Compare commits
7 Commits
main
...
main-tokio
Author | SHA1 | Date | |
---|---|---|---|
5d4cd09497 | |||
b92ee28bef | |||
670f001106 | |||
16c4707d6c | |||
2bb32e75b7 | |||
48a62fc165 | |||
0d6460b01c |
338
Cargo.lock
generated
338
Cargo.lock
generated
@ -1,6 +1,32 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# 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]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
@ -8,6 +34,87 @@ version = "1.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
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]]
|
[[package]]
|
||||||
name = "num"
|
name = "num"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
@ -81,6 +188,15 @@ dependencies = [
|
|||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "object"
|
||||||
|
version = "0.36.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pack"
|
name = "pack"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -89,9 +205,229 @@ dependencies = [
|
|||||||
"num",
|
"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]]
|
[[package]]
|
||||||
name = "storage"
|
name = "storage"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"async-recursion",
|
||||||
"pack",
|
"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"
|
||||||
|
@ -5,4 +5,7 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
||||||
|
tokio = { version = "1.44.1", features = ["full"] }
|
||||||
|
async-recursion = "1.1.1"
|
||||||
|
|
||||||
pack = { git = "https://git.tsukiyo.org/Utility/pack" }
|
pack = { git = "https://git.tsukiyo.org/Utility/pack" }
|
||||||
|
@ -1,22 +1,32 @@
|
|||||||
//use storage::BlockFile;
|
//use storage::BlockFile;
|
||||||
use storage::*;
|
use storage::*;
|
||||||
|
|
||||||
fn main()
|
#[tokio::main]
|
||||||
|
async fn main()
|
||||||
{
|
{
|
||||||
std::fs::create_dir_all("data").ok();
|
std::fs::create_dir_all("data").ok();
|
||||||
|
|
||||||
/*
|
/*let op = 0;
|
||||||
if let Ok(mut bf) = BlockFile::<16>::open("data/cache_data.bin") {
|
if let Ok(mut bf) = BlockFile::<32>::open("data/cache_data.bin").await {
|
||||||
if let Ok(id) = bf.insert("This is a test of the block file system.".as_bytes()) {
|
match op {
|
||||||
let data = String::from_utf8(bf.get(id).unwrap()).unwrap();
|
0 => {
|
||||||
println!("id {} = '{}'", id, data);
|
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 {
|
} else {
|
||||||
println!("Failed to open.");
|
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 [
|
for s in [
|
||||||
"Hello",
|
"Hello",
|
||||||
@ -27,33 +37,35 @@ fn main()
|
|||||||
"Regards",
|
"Regards",
|
||||||
] {
|
] {
|
||||||
println!("# insert {}", s);
|
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);
|
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);
|
println!("found '{}'.", id);
|
||||||
|
|
||||||
if let Ok(key) = tf.key(id) {
|
if let Ok(key) = tf.key(id).await {
|
||||||
println!(" > '{}'", String::from_utf8(key).unwrap());
|
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!(" = '{}'", String::from_utf8(data).unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
println!("");
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in tf.ids().unwrap() {
|
for i in tf.ids().await.unwrap() {
|
||||||
println!("id {}", i);
|
println!("id {}", i);
|
||||||
|
|
||||||
if let Ok(key) = tf.key(i) {
|
if let Ok(key) = tf.key(i).await {
|
||||||
println!(" > '{}'", String::from_utf8(key).unwrap());
|
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!(" = '{}'", String::from_utf8(data).unwrap());
|
||||||
}
|
}
|
||||||
|
println!("");
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
** [Header:16]
|
** [Header:16]
|
||||||
** {AllocTable Head: <Depth:1> <Block:4> } (initial 0, 0)
|
** {AllocTable Head: <Depth:1> <Block:4> } (initial 0, 0)
|
||||||
** {ObjectTable Head: <Depth:1> <Block:4> } (initial 0, 1)
|
** {ObjectTable Head: <Depth:1> <Block:4> } (initial 0, 1)
|
||||||
|
** {NextObject <Id:4>}
|
||||||
**
|
**
|
||||||
** [Object Table]
|
** [Object Table]
|
||||||
** { <Pointer:4> <Length:4> }*
|
** { <Pointer:4> <Length:4> }*
|
||||||
@ -14,10 +15,10 @@
|
|||||||
|
|
||||||
use pack::prelude::*;
|
use pack::prelude::*;
|
||||||
|
|
||||||
use std::{
|
use std::path::Path;
|
||||||
|
use tokio::{
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{Read, Seek, SeekFrom, Write},
|
io::{AsyncReadExt, AsyncSeekExt, SeekFrom, AsyncWriteExt},
|
||||||
path::Path,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const HEADER_SIZE :usize = 16;
|
const HEADER_SIZE :usize = 16;
|
||||||
@ -39,7 +40,7 @@ pub struct BlockFile<const Z:usize> {
|
|||||||
file:File,
|
file:File,
|
||||||
}
|
}
|
||||||
impl<const Z:usize> BlockFile<Z> {
|
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() {
|
if path.as_ref().exists() {
|
||||||
|
|
||||||
@ -47,7 +48,7 @@ impl<const Z:usize> BlockFile<Z> {
|
|||||||
match File::options()
|
match File::options()
|
||||||
.read(true)
|
.read(true)
|
||||||
.write(true)
|
.write(true)
|
||||||
.open(path) {
|
.open(path).await {
|
||||||
Ok(file) => {
|
Ok(file) => {
|
||||||
Ok(Self { file })
|
Ok(Self { file })
|
||||||
}
|
}
|
||||||
@ -60,16 +61,16 @@ impl<const Z:usize> BlockFile<Z> {
|
|||||||
.create_new(true)
|
.create_new(true)
|
||||||
.read(true)
|
.read(true)
|
||||||
.write(true)
|
.write(true)
|
||||||
.open(path) {
|
.open(path).await {
|
||||||
Ok(file) => {
|
Ok(file) => {
|
||||||
Self { file }.init()
|
Self { file }.init().await
|
||||||
}
|
}
|
||||||
Err(error) => Err(error),
|
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.
|
// Write initial headers to the file.
|
||||||
//
|
//
|
||||||
{
|
{
|
||||||
@ -95,24 +96,21 @@ impl<const Z:usize> BlockFile<Z> {
|
|||||||
data[index + 3] = pack_pointer[3];
|
data[index + 3] = pack_pointer[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
self.file.write(&data)?;
|
self.file.write(&data).await?;
|
||||||
Ok(self)
|
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.
|
// Acquire a new object id and write its data to new allocations.
|
||||||
//
|
//
|
||||||
{
|
{
|
||||||
|
|
||||||
// Allocate storage blocks
|
// Allocate storage blocks
|
||||||
let block_count = Self::block_count_from_size(data.len());
|
let block_count = Self::block_count_from_size(data.len());
|
||||||
//println!("block_count {}", block_count);
|
let blocks = self.allocate(block_count.max(1)).await?;
|
||||||
|
|
||||||
let blocks = self.allocate(block_count.max(1))?;
|
|
||||||
//println!("blocks {}", blocks.len());
|
|
||||||
|
|
||||||
// Get object id
|
// 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);
|
//println!("obj_id {}", id);
|
||||||
|
|
||||||
@ -138,37 +136,37 @@ impl<const Z:usize> BlockFile<Z> {
|
|||||||
block_data[Z - 1] = pack_next[3];
|
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)
|
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.
|
// Write new data to an object expanding its existing allocation.
|
||||||
//
|
//
|
||||||
{
|
{
|
||||||
// Get first block and data size
|
// 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 required_blocks = Self::block_count_from_size(data.len());
|
||||||
let mut blocks = Vec::new();
|
let mut blocks = Vec::new();
|
||||||
|
|
||||||
// Count blocks
|
// Count blocks
|
||||||
while block_id != 0 {
|
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);
|
blocks.push(block_id);
|
||||||
block_id = next;
|
block_id = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if blocks.len() > required_blocks {
|
if blocks.len() > required_blocks {
|
||||||
// Free excess blocks
|
// Free excess blocks
|
||||||
self.release(&blocks[required_blocks..])?;
|
self.release(&blocks[required_blocks..]).await?;
|
||||||
blocks.resize(required_blocks, 0);
|
blocks.resize(required_blocks, 0);
|
||||||
|
|
||||||
} else if blocks.len() < required_blocks {
|
} else if blocks.len() < required_blocks {
|
||||||
// Allocate additional 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);
|
blocks.extend_from_slice(&allocated_blocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,32 +192,50 @@ impl<const Z:usize> BlockFile<Z> {
|
|||||||
block_data[Z - 1] = pack_next[3];
|
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(())
|
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.
|
// 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(())
|
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.
|
// Return the object with the specified identifier.
|
||||||
//
|
//
|
||||||
{
|
{
|
||||||
let mut block_data = [0u8; Z];
|
let mut block_data = [0u8; Z];
|
||||||
|
|
||||||
// Get first block and data size
|
// 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();
|
let mut data = Vec::new();
|
||||||
|
|
||||||
// Read blocks until size is full
|
// Read blocks until size is full
|
||||||
while block_id != 0 {
|
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();
|
let next_block = u32::unpack(&block_data, &mut (Z - 4)).unwrap_or_default();
|
||||||
|
|
||||||
//println!("size {} len {}", size, data.len());
|
//println!("size {} len {}", size, data.len());
|
||||||
@ -238,7 +254,7 @@ impl<const Z:usize> BlockFile<Z> {
|
|||||||
Ok(data)
|
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.
|
// Traverses object list and returns allocated ids.
|
||||||
//
|
//
|
||||||
{
|
{
|
||||||
@ -249,7 +265,8 @@ impl<const Z:usize> BlockFile<Z> {
|
|||||||
Ok(output)
|
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.
|
// 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];
|
let mut b32 = [0u8; 4];
|
||||||
|
|
||||||
// Read allocation table root block and depth from file.
|
// Read allocation table root block and depth from file.
|
||||||
self.file.seek(SeekFrom::Start(0))?;
|
self.file.seek(SeekFrom::Start(0)).await?;
|
||||||
self.file.read_exact(&mut b8)?;
|
self.file.read_exact(&mut b8).await?;
|
||||||
self.file.read_exact(&mut b32)?;
|
self.file.read_exact(&mut b32).await?;
|
||||||
|
|
||||||
let root_block = u32::unpack(&b32, &mut 0).unwrap_or_default();
|
let root_block = u32::unpack(&b32, &mut 0).unwrap_or_default();
|
||||||
|
|
||||||
@ -273,12 +290,13 @@ impl<const Z:usize> BlockFile<Z> {
|
|||||||
true,
|
true,
|
||||||
count,
|
count,
|
||||||
&mut blocks,
|
&mut blocks,
|
||||||
)?;
|
).await?;
|
||||||
|
|
||||||
Ok(blocks)
|
Ok(blocks)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allocate_traverse(
|
#[async_recursion::async_recursion]
|
||||||
|
async fn allocate_traverse(
|
||||||
&mut self,
|
&mut self,
|
||||||
block_id:u32,
|
block_id:u32,
|
||||||
depth:u32,
|
depth:u32,
|
||||||
@ -294,7 +312,7 @@ impl<const Z:usize> BlockFile<Z> {
|
|||||||
//println!("allocate_traverse()");
|
//println!("allocate_traverse()");
|
||||||
|
|
||||||
let mut block_data = [0u8; Z];
|
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 write_block = false;
|
||||||
|
|
||||||
let mut operation = Operation::None;
|
let mut operation = Operation::None;
|
||||||
@ -325,7 +343,7 @@ impl<const Z:usize> BlockFile<Z> {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Prepare leaf block.
|
// Prepare leaf block.
|
||||||
let leaf_block = self.end_block()?;
|
let leaf_block = self.end_block().await?;
|
||||||
let mut leaf_data = vec![0u8; Z];
|
let mut leaf_data = vec![0u8; Z];
|
||||||
leaf_data[0] = 1;
|
leaf_data[0] = 1;
|
||||||
|
|
||||||
@ -340,10 +358,10 @@ impl<const Z:usize> BlockFile<Z> {
|
|||||||
table_data.resize(Z, 0);
|
table_data.resize(Z, 0);
|
||||||
|
|
||||||
next_block += 1;
|
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);
|
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 root table allocated last page, generate new root table at greater depth.
|
||||||
if is_root && i == Self::table_size() - 1 {
|
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];
|
let mut table_data = vec![0u8; Z];
|
||||||
|
|
||||||
// Update file header with new root table and depth.
|
// 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(&[
|
self.file.write(&[
|
||||||
(depth as u8).pack(),
|
(depth as u8).pack(),
|
||||||
parent_blocks[0].pack(),
|
parent_blocks[0].pack(),
|
||||||
].concat())?;
|
].concat()).await?;
|
||||||
|
|
||||||
// Add current table to first element of new table.
|
// Add current table to first element of new table.
|
||||||
let packed_id = block_id.pack();
|
let packed_id = block_id.pack();
|
||||||
@ -375,13 +393,13 @@ impl<const Z:usize> BlockFile<Z> {
|
|||||||
table_data[1] = packed_id[1];
|
table_data[1] = packed_id[1];
|
||||||
table_data[2] = packed_id[2];
|
table_data[2] = packed_id[2];
|
||||||
table_data[3] = packed_id[3];
|
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.
|
// 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.
|
// 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);
|
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);
|
//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 => {
|
Operation::SetOccupied => {
|
||||||
write_block = true;
|
write_block = true;
|
||||||
|
|
||||||
@ -450,13 +468,13 @@ impl<const Z:usize> BlockFile<Z> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if write_block {
|
if write_block {
|
||||||
self.write_block(block_id, &block_data)?;
|
self.write_block(block_id, &block_data).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(operation)
|
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.
|
// Mark a set of blocks as unallocated.
|
||||||
//
|
//
|
||||||
{
|
{
|
||||||
@ -464,11 +482,12 @@ impl<const Z:usize> BlockFile<Z> {
|
|||||||
let mut b32 = [0u8; 4];
|
let mut b32 = [0u8; 4];
|
||||||
|
|
||||||
let mut block_data = [0u8; Z];
|
let mut block_data = [0u8; Z];
|
||||||
|
let zero = [0u8; Z];
|
||||||
|
|
||||||
// Read allocation table root block and depth from file.
|
// Read allocation table root block and depth from file.
|
||||||
self.file.seek(SeekFrom::Start(0))?;
|
self.file.seek(SeekFrom::Start(0)).await?;
|
||||||
self.file.read_exact(&mut b8)?;
|
self.file.read_exact(&mut b8).await?;
|
||||||
self.file.read_exact(&mut b32)?;
|
self.file.read_exact(&mut b32).await?;
|
||||||
|
|
||||||
let root_page = u32::unpack(&b32, &mut 0).unwrap_or_default();
|
let root_page = u32::unpack(&b32, &mut 0).unwrap_or_default();
|
||||||
let root_depth = b8[0];
|
let root_depth = b8[0];
|
||||||
@ -480,7 +499,7 @@ impl<const Z:usize> BlockFile<Z> {
|
|||||||
|
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
while depth > 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;
|
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;
|
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;
|
depth -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.read_block(page, &mut block_data)?;
|
self.read_block(page, &mut block_data).await?;
|
||||||
let bit_index = block - offset;
|
let bit_index = block - offset;
|
||||||
let byte = bit_index / 8;
|
let byte = bit_index / 8;
|
||||||
let bit = bit_index % 8;
|
let bit = bit_index % 8;
|
||||||
|
|
||||||
block_data[byte as usize] &= !(1 << bit);
|
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(())
|
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.
|
// Allocate the next available object record.
|
||||||
//
|
//
|
||||||
{
|
{
|
||||||
@ -514,14 +535,14 @@ impl<const Z:usize> BlockFile<Z> {
|
|||||||
let mut b32 = [0u8; 4];
|
let mut b32 = [0u8; 4];
|
||||||
|
|
||||||
// Read allocation table root block and depth from file.
|
// Read allocation table root block and depth from file.
|
||||||
self.file.seek(SeekFrom::Start(5))?;
|
self.file.seek(SeekFrom::Start(5)).await?;
|
||||||
self.file.read_exact(&mut b8)?;
|
self.file.read_exact(&mut b8).await?;
|
||||||
let mut depth = b8[0] as u32;
|
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();
|
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;
|
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];
|
let mut root_data = vec![0u8; Z];
|
||||||
while object_id > range {
|
while object_id > range {
|
||||||
let allocation = self.allocate(1)?;
|
let allocation = self.allocate(1).await?;
|
||||||
|
|
||||||
let packed_id = block_id.pack();
|
let packed_id = block_id.pack();
|
||||||
root_data[0] = packed_id[0];
|
root_data[0] = packed_id[0];
|
||||||
@ -542,7 +563,7 @@ impl<const Z:usize> BlockFile<Z> {
|
|||||||
block_id = allocation[0];
|
block_id = allocation[0];
|
||||||
depth += 1;
|
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;
|
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_depth = [ depth as u8 ];
|
||||||
let pack_pointer = block_id.pack();
|
let pack_pointer = block_id.pack();
|
||||||
|
|
||||||
self.file.seek(SeekFrom::Start(5))?;
|
self.file.seek(SeekFrom::Start(5)).await?;
|
||||||
self.file.write(&pack_depth)?;
|
self.file.write(&pack_depth).await?;
|
||||||
self.file.write(&pack_pointer)?;
|
self.file.write(&pack_pointer).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut basis = 0;
|
let mut basis = 0;
|
||||||
@ -567,7 +588,7 @@ impl<const Z:usize> BlockFile<Z> {
|
|||||||
|
|
||||||
//println!("basis: {}", basis);
|
//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 mut write_block = false;
|
||||||
|
|
||||||
let cell_index = (object_id - basis) / Self::table_offset(depth) as usize;
|
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.
|
// Allocate new page if pointer is zero.
|
||||||
let child_id = if cell_data == 0 {
|
let child_id = if cell_data == 0 {
|
||||||
let allocation = self.allocate(1)?;
|
let allocation = self.allocate(1).await?;
|
||||||
|
|
||||||
// Write new reference to table.
|
// Write new reference to table.
|
||||||
let pack_block = allocation[0].pack();
|
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]
|
allocation[0]
|
||||||
} else {
|
} else {
|
||||||
@ -615,7 +636,7 @@ impl<const Z:usize> BlockFile<Z> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if write_block {
|
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.
|
// Update frame of reference to child table.
|
||||||
@ -627,7 +648,7 @@ impl<const Z:usize> BlockFile<Z> {
|
|||||||
//println!("end basis: {}", basis);
|
//println!("end basis: {}", basis);
|
||||||
|
|
||||||
// Update block and header with object information.
|
// 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_index = (object_id - basis) / Self::table_offset(depth) as usize;
|
||||||
let cell_start = cell_index * 8;
|
let cell_start = cell_index * 8;
|
||||||
@ -650,36 +671,33 @@ impl<const Z:usize> BlockFile<Z> {
|
|||||||
|
|
||||||
// Update header with new pointer.
|
// Update header with new pointer.
|
||||||
let pack_pointer = next_pointer.pack();
|
let pack_pointer = next_pointer.pack();
|
||||||
self.file.seek(SeekFrom::Start(10))?;
|
self.file.seek(SeekFrom::Start(10)).await?;
|
||||||
self.file.write(&pack_pointer)?;
|
self.file.write(&pack_pointer).await?;
|
||||||
|
|
||||||
|
|
||||||
self.write_block(block_id, &block_data)?;
|
self.write_block(block_id, &block_data).await?;
|
||||||
|
|
||||||
Ok(object_id)
|
Ok(object_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_object(&self, id:usize) -> Result<(u32, usize), std::io::Error>
|
async fn free_object(&mut self, id:usize) -> Result<(),std::io::Error>
|
||||||
// Find initial block and data size of an object.
|
|
||||||
//
|
|
||||||
{
|
{
|
||||||
let mut block_data = [0u8; Z];
|
let mut block_data = [0u8; Z];
|
||||||
|
|
||||||
//println!("get_object()");
|
|
||||||
|
|
||||||
let mut file = self.file.try_clone()?;
|
|
||||||
|
|
||||||
let mut b8 = [0u8; 1];
|
let mut b8 = [0u8; 1];
|
||||||
let mut b32 = [0u8; 4];
|
let mut b32 = [0u8; 4];
|
||||||
|
|
||||||
// Read allocation table root block and depth from file.
|
// Read allocation table root block and depth from file.
|
||||||
file.seek(SeekFrom::Start(5))?;
|
self.file.seek(SeekFrom::Start(5)).await?;
|
||||||
file.read_exact(&mut b8)?;
|
self.file.read_exact(&mut b8).await?;
|
||||||
let mut depth = b8[0] as u32;
|
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();
|
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;
|
let mut basis = 0;
|
||||||
|
|
||||||
// Search table for first vacant or unallocated child.
|
// 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.
|
** 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;
|
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.
|
// 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 cell_index = (id - basis) / Self::table_offset(depth) as usize;
|
||||||
let mut cell_start = cell_index * 8;
|
let mut cell_start = cell_index * 8;
|
||||||
@ -718,47 +813,47 @@ impl<const Z:usize> BlockFile<Z> {
|
|||||||
Ok((pointer, length as usize))
|
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.
|
// 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.seek(SeekFrom::Start((HEADER_SIZE + (Z * block_id as usize)) as u64)).await?;
|
||||||
file.read_exact(data)?;
|
file.read_exact(data).await?;
|
||||||
|
|
||||||
Ok(())
|
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.
|
// 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];
|
let mut data = [0u8; 4];
|
||||||
file.seek(SeekFrom::Start((HEADER_SIZE + (Z * block_id as usize) + Self::data_size()) as u64))?;
|
file.seek(SeekFrom::Start((HEADER_SIZE + (Z * block_id as usize) + Self::data_size()) as u64)).await?;
|
||||||
file.read(&mut data)?;
|
file.read(&mut data).await?;
|
||||||
|
|
||||||
Ok(u32::unpack(&data, &mut 0).unwrap())
|
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.
|
// Write a block to file.
|
||||||
//
|
//
|
||||||
{
|
{
|
||||||
self.file.seek(SeekFrom::Start((HEADER_SIZE + (Z * block_id as usize)) as u64))?;
|
self.file.seek(SeekFrom::Start((HEADER_SIZE + (Z * block_id as usize)) as u64)).await?;
|
||||||
self.file.write(&data[0..Z])?;
|
self.file.write(&data[0..Z]).await?;
|
||||||
|
|
||||||
Ok(())
|
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.
|
// Id of the last block in the file.
|
||||||
//
|
//
|
||||||
{
|
{
|
||||||
let mut file = self.file.try_clone()?;
|
let mut file = self.file.try_clone().await?;
|
||||||
let index = file.seek(SeekFrom::End(0))? as usize;
|
let index = file.seek(SeekFrom::End(0)).await? as usize;
|
||||||
Ok((1 + (index - HEADER_SIZE) / Z) as u32)
|
Ok((1 + (index - HEADER_SIZE) / Z) as u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
19
src/database/header.rs
Normal file
19
src/database/header.rs
Normal 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
82
src/database/mod.rs
Normal 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
74
src/database/page.rs
Normal 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
8
src/database/trie.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
pub struct TrieEntry {
|
||||||
|
meta:u8,
|
||||||
|
bytes:[u8; 11],
|
||||||
|
child:u32,
|
||||||
|
lesser:u32,
|
||||||
|
greater:u32,
|
||||||
|
data:u64,
|
||||||
|
}
|
@ -2,3 +2,4 @@
|
|||||||
|
|
||||||
mod blockfile; pub use blockfile::BlockFile;
|
mod blockfile; pub use blockfile::BlockFile;
|
||||||
mod triefile; pub use triefile::TrieFile;
|
mod triefile; pub use triefile::TrieFile;
|
||||||
|
mod database; pub use database::Database;
|
||||||
|
@ -9,12 +9,20 @@
|
|||||||
|
|
||||||
use pack::prelude::Pack;
|
use pack::prelude::Pack;
|
||||||
|
|
||||||
use std::{
|
use std::path::Path;
|
||||||
|
use tokio::{
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{Read, Seek, SeekFrom, Write},
|
io::{AsyncReadExt, AsyncSeekExt, SeekFrom, AsyncWriteExt},
|
||||||
path::Path,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum Traversal {
|
||||||
|
None,
|
||||||
|
Child(u32),
|
||||||
|
Next(u32,u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
const NO_REL :u32 = 0;
|
||||||
|
|
||||||
struct Node<const Z:usize> {
|
struct Node<const Z:usize> {
|
||||||
length:u8,
|
length:u8,
|
||||||
bytes:[u8; 15],
|
bytes:[u8; 15],
|
||||||
@ -91,13 +99,13 @@ pub struct TrieFile<const Z:usize> {
|
|||||||
file:File,
|
file:File,
|
||||||
}
|
}
|
||||||
impl<const Z:usize> TrieFile<Z> {
|
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()
|
match File::options()
|
||||||
.create(true)
|
.create(true)
|
||||||
.read(true)
|
.read(true)
|
||||||
.write(true)
|
.write(true)
|
||||||
.open(path) {
|
.open(path).await {
|
||||||
Ok(file) => {
|
Ok(file) => {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
file,
|
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 = Node::<Z>::new();
|
||||||
|
|
||||||
let mut node_index = 0;
|
let mut node_index = 0;
|
||||||
let mut key_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.
|
// Allocate first chain of nodes if none exist.
|
||||||
if self.block_count()? == 0 {
|
if self.block_count().await? == 0 {
|
||||||
//println!("originate");
|
//println!("originate");
|
||||||
self.trailing_nodes(key, &mut key_index, data, u32::MAX)?;
|
result = self.trailing_nodes(key, &mut key_index, data, u32::MAX).await? as usize;
|
||||||
return Ok(());
|
return Ok(result);
|
||||||
} else {
|
} else {
|
||||||
//println!("traverse");
|
//println!("traverse");
|
||||||
|
|
||||||
// Traverse nodes until key is found.
|
// Traverse nodes until key is found.
|
||||||
while key_index < key.len() {
|
while key_index < key.len() {
|
||||||
//println!("start k {}/{}", 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 shares prefix with key...
|
||||||
if node.bytes[0] == key[key_index] {
|
if node.bytes[0] == key[key_index] {
|
||||||
@ -150,21 +165,22 @@ impl<const Z:usize> TrieFile<Z> {
|
|||||||
if key_index == key.len() {
|
if key_index == key.len() {
|
||||||
//println!(" - found node");
|
//println!(" - found node");
|
||||||
|
|
||||||
node.has_data = true;
|
if overwrite {
|
||||||
node.data = [0; Z];
|
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)?;
|
self.write_node(node_index, &node).await?;
|
||||||
|
result = node_index as usize;
|
||||||
|
} else {
|
||||||
|
return Err(std::io::Error::other("key already exists"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Continue to child node.
|
// Continue to child node.
|
||||||
else {
|
else {
|
||||||
if node.child != 0 {
|
if node.child != NO_REL {
|
||||||
//println!(" - child");
|
//println!(" - child");
|
||||||
parent_index = node_index;
|
traversal = Traversal::Child(node_index);
|
||||||
node_index = node.child;
|
node_index = node.child;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,99 +188,135 @@ impl<const Z:usize> TrieFile<Z> {
|
|||||||
else {
|
else {
|
||||||
//println!(" - new child");
|
//println!(" - new child");
|
||||||
|
|
||||||
node.child = self.trailing_nodes(key, &mut key_index, data, node_index)?;
|
node.child = self.trailing_nodes(key, &mut key_index, data, node_index).await?;
|
||||||
self.write_node(node_index, &node)?;
|
result = node.child as usize;
|
||||||
|
self.write_node(node_index, &node).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
//println!(" - split");
|
//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;
|
key_index += prefix_index;
|
||||||
|
|
||||||
let prefix = node.bytes[0..prefix_index].to_vec();
|
let prefix = node.bytes[0..prefix_index].to_vec();
|
||||||
let suffix = node.bytes[prefix_index..].to_vec();
|
let suffix = node.bytes[prefix_index..].to_vec();
|
||||||
|
|
||||||
node.length = prefix.len() as u8;
|
let new_index = self.allocate().await?;
|
||||||
for i in prefix_index..node.bytes.len() {
|
let mut parent_node = Node::<Z>::new();
|
||||||
node.bytes[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
parent_node.child = node_index;
|
||||||
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];
|
|
||||||
}
|
|
||||||
|
|
||||||
child_node.child = node.child;
|
node.next = NO_REL;
|
||||||
node.child = child_index;
|
|
||||||
|
|
||||||
// Move data to child node.
|
// Set length and text.
|
||||||
child_node.has_data = node.has_data;
|
node.length = suffix.len() as u8;
|
||||||
child_node.data = node.data;
|
Self::copy_to(&mut node.bytes, &suffix);
|
||||||
node.has_data = false;
|
|
||||||
node.data.fill(0);
|
parent_node.length = prefix.len() as u8;
|
||||||
|
Self::copy_to(&mut parent_node.bytes, &prefix);
|
||||||
|
|
||||||
// Write data to trailing nodes.
|
// Write data to trailing nodes.
|
||||||
if key_index < key.len() {
|
if key_index < key.len() {
|
||||||
let new_branch = self.trailing_nodes(key, &mut key_index, data, node_index)?;
|
let new_branch = self.trailing_nodes(key, &mut key_index, data, new_index).await?;
|
||||||
child_node.next = new_branch;
|
result = new_branch as usize;
|
||||||
|
node.next = new_branch;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write data to current node.
|
// Write data to current node.
|
||||||
else {
|
else {
|
||||||
node.has_data = true;
|
parent_node.has_data = true;
|
||||||
for i in 0..Z.min(data.len()) {
|
Self::copy_to(&mut parent_node.data, data);
|
||||||
node.data[i] = data[i];
|
result = new_index as usize;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.write_node(node_index, &node)?;
|
self.write_node(node_index, &node).await?;
|
||||||
self.write_node(child_index, &child_node)?;
|
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...
|
// If node does not share prefix with key...
|
||||||
else {
|
else {
|
||||||
// Move to or create new next node.
|
// Move to or create new next node.
|
||||||
if node.next != 0 {
|
if node.next != NO_REL {
|
||||||
//println!(" - next");
|
//println!(" - next");
|
||||||
|
|
||||||
// Move to next node.
|
// Move to next node.
|
||||||
|
traversal = Traversal::Next(node_index, parent_index);
|
||||||
node_index = node.next;
|
node_index = node.next;
|
||||||
} else {
|
} else {
|
||||||
//println!(" - new next");
|
//println!(" - new next");
|
||||||
|
|
||||||
// Allocate and initialize subsequent nodes until key is resolved.
|
// Allocate and initialize subsequent nodes until key is resolved.
|
||||||
node.next = self.trailing_nodes(key, &mut key_index, data, parent_index)?;
|
node.next = self.trailing_nodes(key, &mut key_index, data, parent_index).await?;
|
||||||
self.write_node(node_index, &node)?;
|
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(())
|
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 = Node::<Z>::new();
|
||||||
|
|
||||||
let mut node_index = 0;
|
let mut node_index = 0;
|
||||||
let mut key_index = 0;
|
let mut key_index = 0;
|
||||||
|
|
||||||
if self.block_count()? != 0 {
|
if self.block_count().await? != 0 {
|
||||||
|
|
||||||
// Traverse nodes until key is found.
|
// Traverse nodes until key is found.
|
||||||
while key_index < key.len() {
|
while key_index < key.len() {
|
||||||
//println!("start k {}/{}", 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 shares prefix with key...
|
||||||
if node.bytes[0] == key[key_index] {
|
if node.bytes[0] == key[key_index] {
|
||||||
@ -292,7 +344,7 @@ impl<const Z:usize> TrieFile<Z> {
|
|||||||
|
|
||||||
// Continue to child node.
|
// Continue to child node.
|
||||||
else {
|
else {
|
||||||
if node.child != 0 {
|
if node.child != NO_REL {
|
||||||
//println!(" - child");
|
//println!(" - child");
|
||||||
|
|
||||||
node_index = node.child;
|
node_index = node.child;
|
||||||
@ -309,7 +361,7 @@ impl<const Z:usize> TrieFile<Z> {
|
|||||||
// If node does not share prefix with key...
|
// If node does not share prefix with key...
|
||||||
else {
|
else {
|
||||||
// Move to or create new next node.
|
// Move to or create new next node.
|
||||||
if node.next != 0 {
|
if node.next != NO_REL {
|
||||||
//println!(" - next");
|
//println!(" - next");
|
||||||
|
|
||||||
// Move to next node.
|
// Move to next node.
|
||||||
@ -324,14 +376,14 @@ impl<const Z:usize> TrieFile<Z> {
|
|||||||
Ok(None)
|
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 node_id = id as u32;
|
||||||
let mut bytes = Vec::new();
|
let mut bytes = Vec::new();
|
||||||
let mut node = Node::<Z>::new();
|
let mut node = Node::<Z>::new();
|
||||||
|
|
||||||
while node_id != u32::MAX {
|
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() {
|
for i in (0..node.length as usize).rev() {
|
||||||
bytes.push(node.bytes[i]);
|
bytes.push(node.bytes[i]);
|
||||||
@ -344,10 +396,10 @@ impl<const Z:usize> TrieFile<Z> {
|
|||||||
Ok(bytes)
|
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();
|
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 {
|
if node.has_data {
|
||||||
Ok(Some(node.data.to_vec()))
|
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 output = Vec::new();
|
||||||
|
|
||||||
let mut node = Node::<Z>::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 {
|
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 {
|
if node.has_data {
|
||||||
output.push(i);
|
output.push(i);
|
||||||
@ -374,14 +426,24 @@ impl<const Z:usize> TrieFile<Z> {
|
|||||||
Ok(output)
|
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 :Node<Z>;
|
||||||
let mut node_index = starting_node;
|
let mut node_index = starting_node;
|
||||||
let mut parent_node = parent;
|
let mut parent_node = parent;
|
||||||
@ -401,56 +463,67 @@ impl<const Z:usize> TrieFile<Z> {
|
|||||||
|
|
||||||
// Allocate child node if key byte remain.
|
// Allocate child node if key byte remain.
|
||||||
if *key_index < key.len() {
|
if *key_index < key.len() {
|
||||||
node.child = self.allocate()?;
|
node.child = self.allocate().await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, write data to node.
|
// Otherwise, write data to node.
|
||||||
else {
|
else {
|
||||||
node.has_data = true;
|
node.has_data = true;
|
||||||
for i in 0..Z.min(data.len()) {
|
Self::copy_to(&mut node.data, data);
|
||||||
node.data[i] = data[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.write_node(node_index, &node)?;
|
self.write_node(node_index, &node).await?;
|
||||||
node_index = node.child;
|
node_index = node.child;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(starting_node)
|
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()];
|
let mut data = vec![0u8; Self::block_size()];
|
||||||
|
|
||||||
file.seek(SeekFrom::Start((Self::block_size() * index as usize) as u64))?;
|
file.seek(SeekFrom::Start((Self::block_size() * index as usize) as u64)).await?;
|
||||||
file.read_exact(&mut data)?;
|
file.read_exact(&mut data).await?;
|
||||||
|
|
||||||
node.decode(&data, &mut 0).map_err(|_| std::io::Error::other("failed to decode node block"))?;
|
node.decode(&data, &mut 0).map_err(|_| std::io::Error::other("failed to decode node block"))?;
|
||||||
|
|
||||||
Ok(())
|
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.seek(SeekFrom::Start((Self::block_size() * index as usize) as u64)).await?;
|
||||||
self.file.write(&node.encode())?;
|
self.file.write(&node.encode()).await?;
|
||||||
Ok(())
|
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;
|
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()])?;
|
self.file.write(&vec![0u8; Self::block_size()]).await?;
|
||||||
Ok(block_id)
|
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()?;
|
let mut file = self.file.try_clone().await?;
|
||||||
Ok(((file.seek(SeekFrom::End(0))? as usize) / Self::block_size()) as u32)
|
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
|
const fn block_size() -> usize
|
||||||
|
Loading…
x
Reference in New Issue
Block a user