diff --git a/src/bin/test.rs b/src/bin/test.rs index 5dd073f..c6959ee 100644 --- a/src/bin/test.rs +++ b/src/bin/test.rs @@ -6,17 +6,30 @@ async fn main() { std::fs::create_dir_all("data").ok(); - println!("BLOCKFILE"); + //println!("BLOCKFILE"); - if let Ok(mut bf) = BlockFile::<16>::open("data/cache_data.bin").await { - if let Ok(id) = bf.insert("This is a test of the block file system.".as_bytes()).await { - let data = String::from_utf8(bf.get(id).await.unwrap()).unwrap(); - println!("id {} = '{}'", id, data); + let op = 0; + + if let Ok(mut bf) = BlockFile::<32>::open("data/cache_data.bin").await { + match op { + 0 => { + for i in 0..1 { + if let Ok(id) = bf.insert(format!("{} This is a test of the block file system {}.", i, i).as_bytes()).await { + let data = String::from_utf8(bf.get(id).await.unwrap()).unwrap(); + println!("id {} = '{}'", id, data); + } + } + } + 1 => { + bf.remove(12).await.ok(); + } + _ => { } } } else { println!("Failed to open."); } + /* println!("TRIEFILE"); if let Ok(mut tf) = TrieFile::<8>::open("data/cache_index.bin").await { @@ -62,4 +75,5 @@ async fn main() } else { println!("Failed to open index."); } + */ } diff --git a/src/blockfile/mod.rs b/src/blockfile/mod.rs index 62d691d..88eb755 100644 --- a/src/blockfile/mod.rs +++ b/src/blockfile/mod.rs @@ -4,6 +4,7 @@ ** [Header:16] ** {AllocTable Head: } (initial 0, 0) ** {ObjectTable Head: } (initial 0, 1) +** {NextObject } ** ** [Object Table] ** { }* @@ -106,10 +107,7 @@ impl BlockFile { // Allocate storage blocks let block_count = Self::block_count_from_size(data.len()); - //println!("block_count {}", block_count); - let blocks = self.allocate(block_count.max(1)).await?; - //println!("blocks {}", blocks.len()); // Get object id let id = self.acquire_object(blocks[0], data.len()).await?; @@ -200,10 +198,28 @@ impl BlockFile { Ok(()) } - pub async fn remove(&mut self, _id:usize) -> Result<(), std::io::Error> + pub async fn remove(&mut self, id:usize) -> Result<(), std::io::Error> // Remove the object with the specified identifier and release its allocation. // { + let mut block_data = [0u8; Z]; + + let mut blocks = Vec::new(); + let (mut block_id, _) = self.get_object(id).await?; + + while block_id != 0 { + blocks.push(block_id); + + self.read_block(block_id, &mut block_data).await?; + block_id = u32::unpack(&block_data, &mut (Z - 4)).unwrap_or_default(); + } + + // Remove object listing. + self.free_object(id).await?; + + // Free allocated blocks. + self.release(&blocks).await?; + Ok(()) } @@ -466,6 +482,7 @@ impl BlockFile { let mut b32 = [0u8; 4]; let mut block_data = [0u8; Z]; + let zero = [0u8; Z]; // Read allocation table root block and depth from file. self.file.seek(SeekFrom::Start(0)).await?; @@ -499,6 +516,8 @@ impl BlockFile { block_data[byte as usize] &= !(1 << bit); self.write_block(page, &block_data).await?; + + self.write_block(block, &zero).await.ok(); } Ok(()) @@ -661,6 +680,80 @@ impl BlockFile { Ok(object_id) } + async fn free_object(&mut self, id:usize) -> Result<(),std::io::Error> + { + let mut block_data = [0u8; Z]; + + let mut b8 = [0u8; 1]; + let mut b32 = [0u8; 4]; + + // Read allocation table root block and depth from file. + self.file.seek(SeekFrom::Start(5)).await?; + self.file.read_exact(&mut b8).await?; + let mut depth = b8[0] as u32; + + self.file.read_exact(&mut b32).await?; + let mut block_id = u32::unpack(&b32, &mut 0).unwrap_or_default(); + + self.file.read_exact(&mut b32).await?; + let object_id = u32::unpack(&b32, &mut 0).unwrap_or_default() as usize; + + let mut basis = 0; + + // Search table for first vacant or unallocated child. + while depth > 0 { + /* + ** Select child tables containing object_id until depth is 0. + */ + + self.read_block(block_id, &mut block_data).await?; + + let cell_index = (id - basis) / Self::table_offset(depth) as usize; + + let cell_start = cell_index * 4; + let cell_data = u32::unpack(&block_data, &mut cell_start.clone()).unwrap_or_default(); + + let child_id = if cell_data != 0 { + u32::unpack(&block_data, &mut cell_start.clone()).unwrap_or_default() + } else { + return Err(std::io::Error::new(std::io::ErrorKind::NotFound, "object id not valid")); + }; + + // Update frame of reference to child table. + block_id = child_id; + basis = Self::table_cell_offset(depth, cell_index as u32, basis as u32) as usize; + depth -= 1; + } + + // Get object pointer and length from cell. + self.read_block(block_id, &mut block_data).await?; + + let cell_index = (id - basis) / Self::table_offset(depth) as usize; + let cell_start = cell_index * 8; + + // Set Id + let pack_location = (object_id as u32).pack(); + block_data[cell_start] = pack_location[0]; + block_data[cell_start + 1] = pack_location[1]; + block_data[cell_start + 2] = pack_location[2]; + block_data[cell_start + 3] = pack_location[3]; + + // Set Length + block_data[cell_start + 4] = 0; + block_data[cell_start + 5] = 0; + block_data[cell_start + 6] = 0; + block_data[cell_start + 7] = 0; + + self.write_block(block_id, &block_data).await?; + + // Update header with new pointer. + let pack_pointer = (id as u32).pack(); + self.file.seek(SeekFrom::Start(10)).await?; + self.file.write(&pack_pointer).await?; + + Ok(()) + } + async fn get_object(&self, id:usize) -> Result<(u32, usize), std::io::Error> // Find initial block and data size of an object. //