Compare commits

..

7 Commits

10 changed files with 904 additions and 201 deletions

338
Cargo.lock generated
View File

@ -1,6 +1,32 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4
[[package]]
name = "addr2line"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
dependencies = [
"gimli",
]
[[package]]
name = "adler2"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
[[package]]
name = "async-recursion"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "autocfg"
@ -8,6 +34,87 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "backtrace"
version = "0.3.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
dependencies = [
"addr2line",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
"windows-targets",
]
[[package]]
name = "bitflags"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
[[package]]
name = "bytes"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "gimli"
version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]]
name = "libc"
version = "0.2.171"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
[[package]]
name = "lock_api"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "miniz_oxide"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
dependencies = [
"adler2",
]
[[package]]
name = "mio"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
dependencies = [
"libc",
"wasi",
"windows-sys",
]
[[package]]
name = "num"
version = "0.4.3"
@ -81,6 +188,15 @@ dependencies = [
"autocfg",
]
[[package]]
name = "object"
version = "0.36.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
dependencies = [
"memchr",
]
[[package]]
name = "pack"
version = "0.1.0"
@ -89,9 +205,229 @@ dependencies = [
"num",
]
[[package]]
name = "parking_lot"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-targets",
]
[[package]]
name = "pin-project-lite"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
[[package]]
name = "proc-macro2"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3"
dependencies = [
"bitflags",
]
[[package]]
name = "rustc-demangle"
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "signal-hook-registry"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
dependencies = [
"libc",
]
[[package]]
name = "smallvec"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
[[package]]
name = "socket2"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "storage"
version = "0.1.0"
dependencies = [
"async-recursion",
"pack",
"tokio",
]
[[package]]
name = "syn"
version = "2.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tokio"
version = "1.44.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
dependencies = [
"backtrace",
"bytes",
"libc",
"mio",
"parking_lot",
"pin-project-lite",
"signal-hook-registry",
"socket2",
"tokio-macros",
"windows-sys",
]
[[package]]
name = "tokio-macros"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

View File

@ -5,4 +5,7 @@ edition = "2021"
[dependencies]
tokio = { version = "1.44.1", features = ["full"] }
async-recursion = "1.1.1"
pack = { git = "https://git.tsukiyo.org/Utility/pack" }

View File

@ -1,22 +1,32 @@
//use storage::BlockFile;
use storage::*;
fn main()
#[tokio::main]
async fn main()
{
std::fs::create_dir_all("data").ok();
/*
if let Ok(mut bf) = BlockFile::<16>::open("data/cache_data.bin") {
if let Ok(id) = bf.insert("This is a test of the block file system.".as_bytes()) {
let data = String::from_utf8(bf.get(id).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.");
}
*/
}*/
if let Ok(mut tf) = TrieFile::<8>::open("data/cache_index.bin") {
if let Ok(mut tf) = TrieFile::<8>::open("data/cache_index.bin").await {
for s in [
"Hello",
@ -27,33 +37,35 @@ fn main()
"Regards",
] {
println!("# insert {}", s);
if tf.set(s.as_bytes(), s.as_bytes()).is_err() {
if tf.set(s.as_bytes(), s.as_bytes()).await.is_err() {
println!("Failed to insert '{}'.", s);
}
if let Ok(Some(id)) = tf.find(s.as_bytes()) {
if let Ok(Some(id)) = tf.find(s.as_bytes()).await {
println!("found '{}'.", id);
if let Ok(key) = tf.key(id) {
if let Ok(key) = tf.key(id).await {
println!(" > '{}'", String::from_utf8(key).unwrap());
}
if let Ok(Some(data)) = tf.get(id) {
if let Ok(Some(data)) = tf.get(id).await {
println!(" = '{}'", String::from_utf8(data).unwrap());
}
}
println!("");
}
for i in tf.ids().unwrap() {
for i in tf.ids().await.unwrap() {
println!("id {}", i);
if let Ok(key) = tf.key(i) {
if let Ok(key) = tf.key(i).await {
println!(" > '{}'", String::from_utf8(key).unwrap());
}
if let Ok(Some(data)) = tf.get(i) {
if let Ok(Some(data)) = tf.get(i).await {
println!(" = '{}'", String::from_utf8(data).unwrap());
}
println!("");
}
} else {

View File

@ -4,6 +4,7 @@
** [Header:16]
** {AllocTable Head: <Depth:1> <Block:4> } (initial 0, 0)
** {ObjectTable Head: <Depth:1> <Block:4> } (initial 0, 1)
** {NextObject <Id:4>}
**
** [Object Table]
** { <Pointer:4> <Length:4> }*
@ -14,10 +15,10 @@
use pack::prelude::*;
use std::{
use std::path::Path;
use tokio::{
fs::File,
io::{Read, Seek, SeekFrom, Write},
path::Path,
io::{AsyncReadExt, AsyncSeekExt, SeekFrom, AsyncWriteExt},
};
const HEADER_SIZE :usize = 16;
@ -39,7 +40,7 @@ pub struct BlockFile<const Z:usize> {
file:File,
}
impl<const Z:usize> BlockFile<Z> {
pub fn open<P:AsRef<Path>>(path:P) -> Result<Self, std::io::Error>
pub async fn open<P:AsRef<Path>>(path:P) -> Result<Self, std::io::Error>
{
if path.as_ref().exists() {
@ -47,7 +48,7 @@ impl<const Z:usize> BlockFile<Z> {
match File::options()
.read(true)
.write(true)
.open(path) {
.open(path).await {
Ok(file) => {
Ok(Self { file })
}
@ -60,16 +61,16 @@ impl<const Z:usize> BlockFile<Z> {
.create_new(true)
.read(true)
.write(true)
.open(path) {
.open(path).await {
Ok(file) => {
Self { file }.init()
Self { file }.init().await
}
Err(error) => Err(error),
}
}
}
fn init(mut self) -> Result<Self, std::io::Error>
async fn init(mut self) -> Result<Self, std::io::Error>
// Write initial headers to the file.
//
{
@ -95,24 +96,21 @@ impl<const Z:usize> BlockFile<Z> {
data[index + 3] = pack_pointer[3];
}
self.file.write(&data)?;
self.file.write(&data).await?;
Ok(self)
}
pub fn insert(&mut self, data:&[u8]) -> Result<usize, std::io::Error>
pub async fn insert(&mut self, data:&[u8]) -> Result<usize, std::io::Error>
// Acquire a new object id and write its data to new allocations.
//
{
// 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))?;
//println!("blocks {}", blocks.len());
let blocks = self.allocate(block_count.max(1)).await?;
// Get object id
let id = self.acquire_object(blocks[0], data.len())?;
let id = self.acquire_object(blocks[0], data.len()).await?;
//println!("obj_id {}", id);
@ -138,37 +136,37 @@ impl<const Z:usize> BlockFile<Z> {
block_data[Z - 1] = pack_next[3];
}
self.write_block(blocks[block_index], &block_data)?;
self.write_block(blocks[block_index], &block_data).await?;
}
Ok(id)
}
pub fn update(&mut self, id:usize, data:&[u8]) -> Result<(), std::io::Error>
pub async fn update(&mut self, id:usize, data:&[u8]) -> Result<(), std::io::Error>
// Write new data to an object expanding its existing allocation.
//
{
// Get first block and data size
let (mut block_id, _) = self.get_object(id)?;
let (mut block_id, _) = self.get_object(id).await?;
let required_blocks = Self::block_count_from_size(data.len());
let mut blocks = Vec::new();
// Count blocks
while block_id != 0 {
let next = self.read_block_pointer(block_id)?;
let next = self.read_block_pointer(block_id).await?;
blocks.push(block_id);
block_id = next;
}
if blocks.len() > required_blocks {
// Free excess blocks
self.release(&blocks[required_blocks..])?;
self.release(&blocks[required_blocks..]).await?;
blocks.resize(required_blocks, 0);
} else if blocks.len() < required_blocks {
// Allocate additional blocks
let allocated_blocks = self.allocate(required_blocks - blocks.len())?;
let allocated_blocks = self.allocate(required_blocks - blocks.len()).await?;
blocks.extend_from_slice(&allocated_blocks);
}
@ -194,32 +192,50 @@ impl<const Z:usize> BlockFile<Z> {
block_data[Z - 1] = pack_next[3];
}
self.write_block(blocks[block_index], &block_data)?;
self.write_block(blocks[block_index], &block_data).await?;
}
Ok(())
}
pub 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(())
}
pub fn get(&self, id:usize) -> Result<Vec<u8>, std::io::Error>
pub async fn get(&self, id:usize) -> Result<Vec<u8>, std::io::Error>
// Return the object with the specified identifier.
//
{
let mut block_data = [0u8; Z];
// Get first block and data size
let (mut block_id, size) = self.get_object(id)?;
let (mut block_id, size) = self.get_object(id).await?;
let mut data = Vec::new();
// Read blocks until size is full
while block_id != 0 {
self.read_block(block_id, &mut block_data)?;
self.read_block(block_id, &mut block_data).await?;
let next_block = u32::unpack(&block_data, &mut (Z - 4)).unwrap_or_default();
//println!("size {} len {}", size, data.len());
@ -238,7 +254,7 @@ impl<const Z:usize> BlockFile<Z> {
Ok(data)
}
pub fn ids(&self) -> Result<Vec<usize>, std::io::Error>
pub async fn ids(&self) -> Result<Vec<usize>, std::io::Error>
// Traverses object list and returns allocated ids.
//
{
@ -249,7 +265,8 @@ impl<const Z:usize> BlockFile<Z> {
Ok(output)
}
fn allocate(&mut self, count:usize) -> Result<Vec<u32>, std::io::Error>
#[async_recursion::async_recursion]
async fn allocate(&mut self, count:usize) -> Result<Vec<u32>, std::io::Error>
// Mark as allocated and return the next available N blocks.
//
{
@ -257,9 +274,9 @@ impl<const Z:usize> BlockFile<Z> {
let mut b32 = [0u8; 4];
// Read allocation table root block and depth from file.
self.file.seek(SeekFrom::Start(0))?;
self.file.read_exact(&mut b8)?;
self.file.read_exact(&mut b32)?;
self.file.seek(SeekFrom::Start(0)).await?;
self.file.read_exact(&mut b8).await?;
self.file.read_exact(&mut b32).await?;
let root_block = u32::unpack(&b32, &mut 0).unwrap_or_default();
@ -273,12 +290,13 @@ impl<const Z:usize> BlockFile<Z> {
true,
count,
&mut blocks,
)?;
).await?;
Ok(blocks)
}
fn allocate_traverse(
#[async_recursion::async_recursion]
async fn allocate_traverse(
&mut self,
block_id:u32,
depth:u32,
@ -294,7 +312,7 @@ impl<const Z:usize> BlockFile<Z> {
//println!("allocate_traverse()");
let mut block_data = [0u8; Z];
self.read_block(block_id, &mut block_data)?;
self.read_block(block_id, &mut block_data).await?;
let mut write_block = false;
let mut operation = Operation::None;
@ -325,7 +343,7 @@ impl<const Z:usize> BlockFile<Z> {
}
} else {
// Prepare leaf block.
let leaf_block = self.end_block()?;
let leaf_block = self.end_block().await?;
let mut leaf_data = vec![0u8; Z];
leaf_data[0] = 1;
@ -340,10 +358,10 @@ impl<const Z:usize> BlockFile<Z> {
table_data.resize(Z, 0);
next_block += 1;
self.write_block(next_block, &table_data)?;
self.write_block(next_block, &table_data).await?;
}
self.write_block(leaf_block, &leaf_data)?;
self.write_block(leaf_block, &leaf_data).await?;
next_block_id = Some(next_block);
@ -358,15 +376,15 @@ impl<const Z:usize> BlockFile<Z> {
// If root table allocated last page, generate new root table at greater depth.
if is_root && i == Self::table_size() - 1 {
let parent_blocks = self.allocate(1)?;
let parent_blocks = self.allocate(1).await?;
let mut table_data = vec![0u8; Z];
// Update file header with new root table and depth.
self.file.seek(SeekFrom::Start(0))?;
self.file.seek(SeekFrom::Start(0)).await?;
self.file.write(&[
(depth as u8).pack(),
parent_blocks[0].pack(),
].concat())?;
].concat()).await?;
// Add current table to first element of new table.
let packed_id = block_id.pack();
@ -375,13 +393,13 @@ impl<const Z:usize> BlockFile<Z> {
table_data[1] = packed_id[1];
table_data[2] = packed_id[2];
table_data[3] = packed_id[3];
self.write_block(parent_blocks[0], &table_data)?;
self.write_block(parent_blocks[0], &table_data).await?;
// Update current table before restarting recursion.
self.write_block(block_id, &block_data)?;
self.write_block(block_id, &block_data).await?;
// Restart recursion with new root.
self.allocate_traverse(parent_blocks[0], depth + 1, 0, true, count, blocks)?;
self.allocate_traverse(parent_blocks[0], depth + 1, 0, true, count, blocks).await?;
return Ok(Operation::None);
}
}
@ -392,7 +410,7 @@ impl<const Z:usize> BlockFile<Z> {
//println!("@next basis {} from d {} c {} b {}", next_basis, depth, cell_index, basis);
match self.allocate_traverse(next_block_id, depth - 1, next_basis, false, count, blocks)? {
match self.allocate_traverse(next_block_id, depth - 1, next_basis, false, count, blocks).await? {
Operation::SetOccupied => {
write_block = true;
@ -450,13 +468,13 @@ impl<const Z:usize> BlockFile<Z> {
}
if write_block {
self.write_block(block_id, &block_data)?;
self.write_block(block_id, &block_data).await?;
}
Ok(operation)
}
fn release(&mut self, blocks:&[u32]) -> Result<(),std::io::Error>
async fn release(&mut self, blocks:&[u32]) -> Result<(),std::io::Error>
// Mark a set of blocks as unallocated.
//
{
@ -464,11 +482,12 @@ impl<const Z:usize> BlockFile<Z> {
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))?;
self.file.read_exact(&mut b8)?;
self.file.read_exact(&mut b32)?;
self.file.seek(SeekFrom::Start(0)).await?;
self.file.read_exact(&mut b8).await?;
self.file.read_exact(&mut b32).await?;
let root_page = u32::unpack(&b32, &mut 0).unwrap_or_default();
let root_depth = b8[0];
@ -480,7 +499,7 @@ impl<const Z:usize> BlockFile<Z> {
let mut offset = 0;
while depth > 0 {
self.read_block(page, &mut block_data)?;
self.read_block(page, &mut block_data).await?;
let index = (block - offset) / Self::pool_size().pow(depth as u32) as u32;
offset = Self::table_cell_offset(depth - 1, index as u32, offset) * Self::pool_size() as u32;
@ -490,19 +509,21 @@ impl<const Z:usize> BlockFile<Z> {
depth -= 1;
}
self.read_block(page, &mut block_data)?;
self.read_block(page, &mut block_data).await?;
let bit_index = block - offset;
let byte = bit_index / 8;
let bit = bit_index % 8;
block_data[byte as usize] &= !(1 << bit);
self.write_block(page, &block_data)?;
self.write_block(page, &block_data).await?;
self.write_block(block, &zero).await.ok();
}
Ok(())
}
fn acquire_object(&mut self, data_id:u32, length:usize) -> Result<usize, std::io::Error>
async fn acquire_object(&mut self, data_id:u32, length:usize) -> Result<usize, std::io::Error>
// Allocate the next available object record.
//
{
@ -514,14 +535,14 @@ impl<const Z:usize> BlockFile<Z> {
let mut b32 = [0u8; 4];
// Read allocation table root block and depth from file.
self.file.seek(SeekFrom::Start(5))?;
self.file.read_exact(&mut b8)?;
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)?;
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)?;
self.file.read_exact(&mut b32).await?;
let object_id = u32::unpack(&b32, &mut 0).unwrap_or_default() as usize;
@ -531,7 +552,7 @@ impl<const Z:usize> BlockFile<Z> {
let mut root_data = vec![0u8; Z];
while object_id > range {
let allocation = self.allocate(1)?;
let allocation = self.allocate(1).await?;
let packed_id = block_id.pack();
root_data[0] = packed_id[0];
@ -542,7 +563,7 @@ impl<const Z:usize> BlockFile<Z> {
block_id = allocation[0];
depth += 1;
self.write_block(block_id, &root_data)?;
self.write_block(block_id, &root_data).await?;
range = Self::table_offset(depth + 1) as usize;
}
@ -552,9 +573,9 @@ impl<const Z:usize> BlockFile<Z> {
let pack_depth = [ depth as u8 ];
let pack_pointer = block_id.pack();
self.file.seek(SeekFrom::Start(5))?;
self.file.write(&pack_depth)?;
self.file.write(&pack_pointer)?;
self.file.seek(SeekFrom::Start(5)).await?;
self.file.write(&pack_depth).await?;
self.file.write(&pack_pointer).await?;
}
let mut basis = 0;
@ -567,7 +588,7 @@ impl<const Z:usize> BlockFile<Z> {
//println!("basis: {}", basis);
self.read_block(block_id, &mut block_data)?;
self.read_block(block_id, &mut block_data).await?;
let mut write_block = false;
let cell_index = (object_id - basis) / Self::table_offset(depth) as usize;
@ -578,7 +599,7 @@ impl<const Z:usize> BlockFile<Z> {
// Allocate new page if pointer is zero.
let child_id = if cell_data == 0 {
let allocation = self.allocate(1)?;
let allocation = self.allocate(1).await?;
// Write new reference to table.
let pack_block = allocation[0].pack();
@ -607,7 +628,7 @@ impl<const Z:usize> BlockFile<Z> {
}
}
self.write_block(allocation[0], &table_data)?;
self.write_block(allocation[0], &table_data).await?;
allocation[0]
} else {
@ -615,7 +636,7 @@ impl<const Z:usize> BlockFile<Z> {
};
if write_block {
self.write_block(block_id, &block_data)?;
self.write_block(block_id, &block_data).await?;
}
// Update frame of reference to child table.
@ -627,7 +648,7 @@ impl<const Z:usize> BlockFile<Z> {
//println!("end basis: {}", basis);
// Update block and header with object information.
self.read_block(block_id, &mut block_data)?;
self.read_block(block_id, &mut block_data).await?;
let cell_index = (object_id - basis) / Self::table_offset(depth) as usize;
let cell_start = cell_index * 8;
@ -650,36 +671,33 @@ impl<const Z:usize> BlockFile<Z> {
// Update header with new pointer.
let pack_pointer = next_pointer.pack();
self.file.seek(SeekFrom::Start(10))?;
self.file.write(&pack_pointer)?;
self.file.seek(SeekFrom::Start(10)).await?;
self.file.write(&pack_pointer).await?;
self.write_block(block_id, &block_data)?;
self.write_block(block_id, &block_data).await?;
Ok(object_id)
}
fn get_object(&self, id:usize) -> Result<(u32, usize), std::io::Error>
// Find initial block and data size of an object.
//
async fn free_object(&mut self, id:usize) -> Result<(),std::io::Error>
{
let mut block_data = [0u8; Z];
//println!("get_object()");
let mut file = self.file.try_clone()?;
let mut b8 = [0u8; 1];
let mut b32 = [0u8; 4];
// Read allocation table root block and depth from file.
file.seek(SeekFrom::Start(5))?;
file.read_exact(&mut b8)?;
self.file.seek(SeekFrom::Start(5)).await?;
self.file.read_exact(&mut b8).await?;
let mut depth = b8[0] as u32;
file.read_exact(&mut b32)?;
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.
@ -688,7 +706,7 @@ impl<const Z:usize> BlockFile<Z> {
** Select child tables containing object_id until depth is 0.
*/
self.read_block(block_id, &mut block_data)?;
self.read_block(block_id, &mut block_data).await?;
let cell_index = (id - basis) / Self::table_offset(depth) as usize;
@ -708,7 +726,84 @@ impl<const Z:usize> BlockFile<Z> {
}
// Get object pointer and length from cell.
self.read_block(block_id, &mut block_data)?;
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.
//
{
let mut block_data = [0u8; Z];
//println!("get_object()");
let mut file = self.file.try_clone().await?;
let mut b8 = [0u8; 1];
let mut b32 = [0u8; 4];
// Read allocation table root block and depth from file.
file.seek(SeekFrom::Start(5)).await?;
file.read_exact(&mut b8).await?;
let mut depth = b8[0] as u32;
file.read_exact(&mut b32).await?;
let mut block_id = u32::unpack(&b32, &mut 0).unwrap_or_default();
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 mut cell_start = cell_index * 8;
@ -718,47 +813,47 @@ impl<const Z:usize> BlockFile<Z> {
Ok((pointer, length as usize))
}
fn read_block(&self, block_id:u32, data:&mut [u8;Z]) -> Result<(),std::io::Error>
async fn read_block(&self, block_id:u32, data:&mut [u8;Z]) -> Result<(),std::io::Error>
// Read a block from file.
//
{
let mut file = self.file.try_clone()?;
let mut file = self.file.try_clone().await?;
file.seek(SeekFrom::Start((HEADER_SIZE + (Z * block_id as usize)) as u64))?;
file.read_exact(data)?;
file.seek(SeekFrom::Start((HEADER_SIZE + (Z * block_id as usize)) as u64)).await?;
file.read_exact(data).await?;
Ok(())
}
fn read_block_pointer(&self, block_id:u32) -> Result<u32,std::io::Error>
async fn read_block_pointer(&self, block_id:u32) -> Result<u32,std::io::Error>
// Read the pointer element of a data block.
//
{
let mut file = self.file.try_clone()?;
let mut file = self.file.try_clone().await?;
let mut data = [0u8; 4];
file.seek(SeekFrom::Start((HEADER_SIZE + (Z * block_id as usize) + Self::data_size()) as u64))?;
file.read(&mut data)?;
file.seek(SeekFrom::Start((HEADER_SIZE + (Z * block_id as usize) + Self::data_size()) as u64)).await?;
file.read(&mut data).await?;
Ok(u32::unpack(&data, &mut 0).unwrap())
}
fn write_block(&mut self, block_id:u32, data:&[u8]) -> Result<(), std::io::Error>
async fn write_block(&mut self, block_id:u32, data:&[u8]) -> Result<(), std::io::Error>
// Write a block to file.
//
{
self.file.seek(SeekFrom::Start((HEADER_SIZE + (Z * block_id as usize)) as u64))?;
self.file.write(&data[0..Z])?;
self.file.seek(SeekFrom::Start((HEADER_SIZE + (Z * block_id as usize)) as u64)).await?;
self.file.write(&data[0..Z]).await?;
Ok(())
}
fn end_block(&self) -> Result<u32, std::io::Error>
async fn end_block(&self) -> Result<u32, std::io::Error>
// Id of the last block in the file.
//
{
let mut file = self.file.try_clone()?;
let index = file.seek(SeekFrom::End(0))? as usize;
let mut file = self.file.try_clone().await?;
let index = file.seek(SeekFrom::End(0)).await? as usize;
Ok((1 + (index - HEADER_SIZE) / Z) as u32)
}

19
src/database/header.rs Normal file
View File

@ -0,0 +1,19 @@
pub struct Header {
pub depth:u8,
pub root:u32,
}
impl Header {
pub fn serialize(&self) -> [u8;16]
{
[0; 16]
}
}
impl Default for Header {
fn default() -> Self
{
Self {
depth:1,
root:1,
}
}
}

82
src/database/mod.rs Normal file
View File

@ -0,0 +1,82 @@
use tokio::{
fs::File,
io::{
Error, SeekFrom,
AsyncWriteExt, AsyncSeekExt
},
};
use std::collections::BTreeSet;
mod header;
mod page;
mod trie;
const PAGE_SIZE :u64 = 4096;
enum Path {
Index(usize),
Key(&u8),
}
pub struct Database {
file:File,
temp:BTreeSet<u64>,
}
impl Database {
async fn init(&mut self) -> Result<(),Error>
{
let mut header = header::Header::default();
header.depth = 1;
header.root = 2;
let buffered = header.serialize();
self.file.set_len(PAGE_SIZE * 3).await?;
self.file.seek(SeekFrom::Start(0)).await?;
self.file.write(&buffered).await?;
self.file.seek(SeekFrom::Start(PAGE_SIZE)).await?;
self.file.write(&buffered).await?;
Ok(())
}
}
impl From<File> for Database {
fn from(value: File) -> Self
{
Self {
file:value,
temp:BTreeSet::new(),
}
}
}
/* Object
** Meta [16]
** [0:3] Type
**
** 00 Blob
** [3:3] Size
**
** 01 List
** []
**
** 10 Trie
**
** Addr [48]
*/
/* Page Table Entry
** <>
*/
/* Allocation Table Entry
** <>
**
*/
/* Header
** <>
**
*/

74
src/database/page.rs Normal file
View File

@ -0,0 +1,74 @@
pub enum Usage {
Blob = 0b00,
List = 0b01,
Trie = 0b10,
Table = 0b11,
}
pub struct Entry {
addr:u64,
res:u64,
}
impl Entry {
pub fn new() -> Self
{
Self {
addr:0,
res:0,
}
}
pub fn blob(address:u64, size:u8) -> Self
{
let addr = address & ((1 << 48) - 1);
let size = (size as u64) << 48;
Self {
addr: size|addr,
res: 0,
}
}
pub fn serialize(&self) -> [u8;16]
{
[
(self.addr & 0xFF) as u8,
((self.addr >> 8) & 0xFF) as u8,
((self.addr >> 16) & 0xFF) as u8,
((self.addr >> 24) & 0xFF) as u8,
((self.addr >> 32) & 0xFF) as u8,
((self.addr >> 40) & 0xFF) as u8,
((self.addr >> 48) & 0xFF) as u8,
((self.addr >> 56) & 0xFF) as u8,
(self.res & 0xFF) as u8,
((self.res >> 8) & 0xFF) as u8,
((self.res >> 16) & 0xFF) as u8,
((self.res >> 24) & 0xFF) as u8,
((self.res >> 32) & 0xFF) as u8,
((self.res >> 40) & 0xFF) as u8,
((self.res >> 48) & 0xFF) as u8,
((self.res >> 56) & 0xFF) as u8,
]
}
pub fn deserialize(&mut self, data:[u8;16])
{
self.addr = data[0] as u64
|(data[1] << 8) as u64
|(data[2] << 16) as u64
|(data[3] << 24) as u64
|(data[4] << 32) as u64
|(data[5] << 40) as u64
|(data[6] << 48) as u64
|(data[7] << 56) as u64;
self.res = data[8] as u64
|(data[9] << 8) as u64
|(data[10] << 16) as u64
|(data[11] << 24) as u64
|(data[12] << 32) as u64
|(data[13] << 40) as u64
|(data[14] << 48) as u64
|(data[15] << 56) as u64;
}
}

8
src/database/trie.rs Normal file
View File

@ -0,0 +1,8 @@
pub struct TrieEntry {
meta:u8,
bytes:[u8; 11],
child:u32,
lesser:u32,
greater:u32,
data:u64,
}

View File

@ -2,3 +2,4 @@
mod blockfile; pub use blockfile::BlockFile;
mod triefile; pub use triefile::TrieFile;
mod database; pub use database::Database;

View File

@ -9,12 +9,20 @@
use pack::prelude::Pack;
use std::{
use std::path::Path;
use tokio::{
fs::File,
io::{Read, Seek, SeekFrom, Write},
path::Path,
io::{AsyncReadExt, AsyncSeekExt, SeekFrom, AsyncWriteExt},
};
enum Traversal {
None,
Child(u32),
Next(u32,u32),
}
const NO_REL :u32 = 0;
struct Node<const Z:usize> {
length:u8,
bytes:[u8; 15],
@ -91,13 +99,13 @@ pub struct TrieFile<const Z:usize> {
file:File,
}
impl<const Z:usize> TrieFile<Z> {
pub fn open<P:AsRef<Path>>(path:P) -> Result<Self, std::io::Error>
pub async fn open<P:AsRef<Path>>(path:P) -> Result<Self, std::io::Error>
{
match File::options()
.create(true)
.read(true)
.write(true)
.open(path) {
.open(path).await {
Ok(file) => {
Ok(Self {
file,
@ -107,27 +115,34 @@ impl<const Z:usize> TrieFile<Z> {
}
}
pub fn set(&mut self, key:&[u8], data:&[u8]) -> Result<(),std::io::Error>
async fn set_data(&mut self, key:&[u8], data:&[u8], overwrite:bool) -> Result<usize,std::io::Error>
{
let mut node = Node::<Z>::new();
let mut node_index = 0;
let mut key_index = 0;
let mut parent_index = u32::MAX;
let mut traversal = Traversal::None;
let mut result = 0;
// Allocate first chain of nodes if none exist.
if self.block_count()? == 0 {
if self.block_count().await? == 0 {
//println!("originate");
self.trailing_nodes(key, &mut key_index, data, u32::MAX)?;
return Ok(());
result = self.trailing_nodes(key, &mut key_index, data, u32::MAX).await? as usize;
return Ok(result);
} else {
//println!("traverse");
// Traverse nodes until key is found.
while key_index < key.len() {
//println!("start k {}/{}", key_index, key.len());
let parent_index = match traversal {
Traversal::None => u32::MAX,
Traversal::Child(id) => id,
Traversal::Next(_, id) => id,
};
self.read_node(node_index, &mut node)?;
self.read_node(node_index, &mut node).await?;
// If node shares prefix with key...
if node.bytes[0] == key[key_index] {
@ -150,21 +165,22 @@ impl<const Z:usize> TrieFile<Z> {
if key_index == key.len() {
//println!(" - found node");
node.has_data = true;
node.data = [0; Z];
if overwrite {
node.has_data = true;
Self::copy_to(&mut node.data, data);
for i in 0..Z.min(data.len()) {
node.data[i] = data[i];
self.write_node(node_index, &node).await?;
result = node_index as usize;
} else {
return Err(std::io::Error::other("key already exists"));
}
self.write_node(node_index, &node)?;
}
// Continue to child node.
else {
if node.child != 0 {
if node.child != NO_REL {
//println!(" - child");
parent_index = node_index;
traversal = Traversal::Child(node_index);
node_index = node.child;
}
@ -172,99 +188,135 @@ impl<const Z:usize> TrieFile<Z> {
else {
//println!(" - new child");
node.child = self.trailing_nodes(key, &mut key_index, data, node_index)?;
self.write_node(node_index, &node)?;
node.child = self.trailing_nodes(key, &mut key_index, data, node_index).await?;
result = node.child as usize;
self.write_node(node_index, &node).await?;
}
}
} else {
//println!(" - split");
// Split node into one parent and two children, preserving parent block id.
// Split node into one parent and two children, preserving sequence/id mapping.
key_index += prefix_index;
let prefix = node.bytes[0..prefix_index].to_vec();
let suffix = node.bytes[prefix_index..].to_vec();
node.length = prefix.len() as u8;
for i in prefix_index..node.bytes.len() {
node.bytes[i] = 0;
}
let new_index = self.allocate().await?;
let mut parent_node = Node::<Z>::new();
let child_index = self.allocate()?;
// Set parent/child/next (original parent updated later).
parent_node.parent = node.parent;
node.parent = new_index;
let mut child_node = Node::<Z>::new();
child_node.parent = node_index;
child_node.length = suffix.len() as u8;
for i in 0..15.min(suffix.len()) {
child_node.bytes[i] = suffix[i];
}
parent_node.child = node_index;
child_node.child = node.child;
node.child = child_index;
node.next = NO_REL;
// Move data to child node.
child_node.has_data = node.has_data;
child_node.data = node.data;
node.has_data = false;
node.data.fill(0);
// Set length and text.
node.length = suffix.len() as u8;
Self::copy_to(&mut node.bytes, &suffix);
parent_node.length = prefix.len() as u8;
Self::copy_to(&mut parent_node.bytes, &prefix);
// Write data to trailing nodes.
if key_index < key.len() {
let new_branch = self.trailing_nodes(key, &mut key_index, data, node_index)?;
child_node.next = new_branch;
let new_branch = self.trailing_nodes(key, &mut key_index, data, new_index).await?;
result = new_branch as usize;
node.next = new_branch;
}
// Write data to current node.
else {
node.has_data = true;
for i in 0..Z.min(data.len()) {
node.data[i] = data[i];
}
parent_node.has_data = true;
Self::copy_to(&mut parent_node.data, data);
result = new_index as usize;
}
self.write_node(node_index, &node)?;
self.write_node(child_index, &child_node)?;
self.write_node(node_index, &node).await?;
self.write_node(new_index, &parent_node).await?;
// Update original parent node to new node.
match traversal {
Traversal::None => { }
Traversal::Child(id) => {
self.read_node(id, &mut parent_node).await?;
parent_node.child = new_index;
self.write_node(id, &mut parent_node).await?;
}
Traversal::Next(id, _) => {
self.read_node(id, &mut parent_node).await?;
parent_node.next = new_index;
self.write_node(id, &mut parent_node).await?;
}
};
}
}
// If node does not share prefix with key...
else {
// Move to or create new next node.
if node.next != 0 {
if node.next != NO_REL {
//println!(" - next");
// Move to next node.
traversal = Traversal::Next(node_index, parent_index);
node_index = node.next;
} else {
//println!(" - new next");
// Allocate and initialize subsequent nodes until key is resolved.
node.next = self.trailing_nodes(key, &mut key_index, data, parent_index)?;
self.write_node(node_index, &node)?;
node.next = self.trailing_nodes(key, &mut key_index, data, parent_index).await?;
result = node.next as usize;
self.write_node(node_index, &node).await?;
}
}
}
}
Ok(result)
}
pub async fn set(&mut self, key:&[u8], data:&[u8]) -> Result<usize,std::io::Error>
{
self.set_data(key, data, true).await
}
pub async fn insert(&mut self, key:&[u8], data:&[u8]) -> Result<usize,std::io::Error>
{
self.set_data(key, data, false).await
}
pub async fn update(&mut self, id:usize, data:&[u8]) -> Result<(),std::io::Error>
{
let mut node = Node::<Z>::new();
self.read_node(id as u32, &mut node).await?;
node.has_data = true;
Self::copy_to(&mut node.data, data);
self.write_node(id as u32, &node).await?;
Ok(())
}
pub fn find(&self, key:&[u8]) -> Result<Option<usize>, std::io::Error>
pub async fn find(&self, key:&[u8]) -> Result<Option<usize>, std::io::Error>
{
let mut node = Node::<Z>::new();
let mut node_index = 0;
let mut key_index = 0;
if self.block_count()? != 0 {
if self.block_count().await? != 0 {
// Traverse nodes until key is found.
while key_index < key.len() {
//println!("start k {}/{}", key_index, key.len());
self.read_node(node_index, &mut node)?;
self.read_node(node_index, &mut node).await?;
// If node shares prefix with key...
if node.bytes[0] == key[key_index] {
@ -292,7 +344,7 @@ impl<const Z:usize> TrieFile<Z> {
// Continue to child node.
else {
if node.child != 0 {
if node.child != NO_REL {
//println!(" - child");
node_index = node.child;
@ -309,7 +361,7 @@ impl<const Z:usize> TrieFile<Z> {
// If node does not share prefix with key...
else {
// Move to or create new next node.
if node.next != 0 {
if node.next != NO_REL {
//println!(" - next");
// Move to next node.
@ -324,14 +376,14 @@ impl<const Z:usize> TrieFile<Z> {
Ok(None)
}
pub fn key(&self, id:usize) -> Result<Vec<u8>, std::io::Error>
pub async fn key(&self, id:usize) -> Result<Vec<u8>, std::io::Error>
{
let mut node_id = id as u32;
let mut bytes = Vec::new();
let mut node = Node::<Z>::new();
while node_id != u32::MAX {
self.read_node(node_id, &mut node)?;
self.read_node(node_id, &mut node).await?;
for i in (0..node.length as usize).rev() {
bytes.push(node.bytes[i]);
@ -344,10 +396,10 @@ impl<const Z:usize> TrieFile<Z> {
Ok(bytes)
}
pub fn get(&self, id:usize) -> Result<Option<Vec<u8>>, std::io::Error>
pub async fn get(&self, id:usize) -> Result<Option<Vec<u8>>, std::io::Error>
{
let mut node = Node::<Z>::new();
self.read_node(id as u32, &mut node)?;
self.read_node(id as u32, &mut node).await?;
if node.has_data {
Ok(Some(node.data.to_vec()))
@ -356,15 +408,15 @@ impl<const Z:usize> TrieFile<Z> {
}
}
pub fn ids(&self) -> Result<Vec<usize>, std::io::Error>
pub async fn ids(&self) -> Result<Vec<usize>, std::io::Error>
{
let mut output = Vec::new();
let mut node = Node::<Z>::new();
let length = self.block_count()? as usize;
let length = self.block_count().await? as usize;
for i in 0..length {
self.read_node(i as u32, &mut node)?;
self.read_node(i as u32, &mut node).await?;
if node.has_data {
output.push(i);
@ -374,14 +426,24 @@ impl<const Z:usize> TrieFile<Z> {
Ok(output)
}
/*pub fn unset(&self, _key:&[u8]) -> Result<(), std::io::Error>
pub async fn unset(&mut self, id:usize) -> Result<(), std::io::Error>
{
Ok(())
}*/
let mut node = Node::<Z>::new();
if id < self.block_count().await? as usize {
self.read_node(id as u32, &mut node).await?;
node.has_data = false;
node.data = [0; Z];
self.write_node(id as u32, &node).await?;
fn trailing_nodes(&mut self, key:&[u8], key_index:&mut usize, data:&[u8], parent:u32) -> Result<u32, std::io::Error>
Ok(())
} else {
Err(std::io::Error::other("id out of bounds"))
}
}
async fn trailing_nodes(&mut self, key:&[u8], key_index:&mut usize, data:&[u8], parent:u32) -> Result<u32, std::io::Error>
{
let starting_node = self.allocate()?;
let starting_node = self.allocate().await?;
let mut node :Node<Z>;
let mut node_index = starting_node;
let mut parent_node = parent;
@ -401,56 +463,67 @@ impl<const Z:usize> TrieFile<Z> {
// Allocate child node if key byte remain.
if *key_index < key.len() {
node.child = self.allocate()?;
node.child = self.allocate().await?;
}
// Otherwise, write data to node.
else {
node.has_data = true;
for i in 0..Z.min(data.len()) {
node.data[i] = data[i];
}
Self::copy_to(&mut node.data, data);
}
self.write_node(node_index, &node)?;
self.write_node(node_index, &node).await?;
node_index = node.child;
}
Ok(starting_node)
}
fn read_node(&self, index:u32, node:&mut Node<Z>) -> Result<(), std::io::Error>
async fn read_node(&self, index:u32, node:&mut Node<Z>) -> Result<(), std::io::Error>
{
let mut file = self.file.try_clone()?;
let mut file = self.file.try_clone().await?;
let mut data = vec![0u8; Self::block_size()];
file.seek(SeekFrom::Start((Self::block_size() * index as usize) as u64))?;
file.read_exact(&mut data)?;
file.seek(SeekFrom::Start((Self::block_size() * index as usize) as u64)).await?;
file.read_exact(&mut data).await?;
node.decode(&data, &mut 0).map_err(|_| std::io::Error::other("failed to decode node block"))?;
Ok(())
}
fn write_node(&mut self, index:u32, node:&Node<Z>) -> Result<(), std::io::Error>
async fn write_node(&mut self, index:u32, node:&Node<Z>) -> Result<(), std::io::Error>
{
self.file.seek(SeekFrom::Start((Self::block_size() * index as usize) as u64))?;
self.file.write(&node.encode())?;
self.file.seek(SeekFrom::Start((Self::block_size() * index as usize) as u64)).await?;
self.file.write(&node.encode()).await?;
Ok(())
}
fn allocate(&mut self) -> Result<u32, std::io::Error>
async fn allocate(&mut self) -> Result<u32, std::io::Error>
{
let block_id = ((self.file.seek(SeekFrom::End(0))? as usize) / Self::block_size()) as u32;
self.file.write(&vec![0u8; Self::block_size()])?;
let block_id = ((self.file.seek(SeekFrom::End(0)).await? as usize) / Self::block_size()) as u32;
self.file.write(&vec![0u8; Self::block_size()]).await?;
Ok(block_id)
}
fn block_count(&self) -> Result<u32, std::io::Error>
async fn block_count(&self) -> Result<u32, std::io::Error>
{
let mut file = self.file.try_clone()?;
Ok(((file.seek(SeekFrom::End(0))? as usize) / Self::block_size()) as u32)
let mut file = self.file.try_clone().await?;
Ok(((file.seek(SeekFrom::End(0)).await? as usize) / Self::block_size()) as u32)
}
fn copy_to(dst:&mut [u8], src:&[u8])
{
let mut index = 0;
while index < dst.len() && index < src.len() {
dst[index] = src[index];
index += 1;
}
while index < dst.len() {
dst[index] = 0;
index += 1;
}
}
const fn block_size() -> usize