зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1799442 - Update Glean to v51.8.2, rkv to 0.18 r=janerik,supply-chain-reviewers
Differential Revision: https://phabricator.services.mozilla.com/D162345
This commit is contained in:
Родитель
2ec8b13fae
Коммит
fc358ad992
|
@ -2240,9 +2240,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "glean"
|
||||
version = "51.8.1"
|
||||
version = "51.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d1f6f93391e6a54301b0896347a100f5f742ccc89bf48c9bd4dad06e7282716"
|
||||
checksum = "43db04e51b1b7e796177e3bda4fdbeb3b649d6e429524863b1ecf699fabc7d6c"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"crossbeam-channel",
|
||||
|
@ -2260,9 +2260,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "glean-core"
|
||||
version = "51.8.1"
|
||||
version = "51.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8523726fb4d4aa5098198208d5c6e16e26382652a792f42be62caa966bfcd99b"
|
||||
checksum = "b223c24117a769c9d13e3d9a349187113c364f8ca2831b42651f35d0edba4a5f"
|
||||
dependencies = [
|
||||
"android_logger",
|
||||
"bincode",
|
||||
|
@ -2273,6 +2273,7 @@ dependencies = [
|
|||
"log",
|
||||
"once_cell",
|
||||
"oslog",
|
||||
"remove_dir_all",
|
||||
"rkv",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
@ -4465,9 +4466,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rkv"
|
||||
version = "0.17.1"
|
||||
version = "0.18.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6006704273063c72952370ad236b8d58556dcc4f99a95ced4d9ad40f3e80a69"
|
||||
checksum = "2c3b196786090b5b57c9bb0f4afca6ac6a5bfb6182c0161ef32f1ecade43ac47"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"bincode",
|
||||
|
|
|
@ -36,7 +36,7 @@ allprojects {
|
|||
topsrcdir = gradle.mozconfig.topsrcdir
|
||||
topobjdir = gradle.mozconfig.topobjdir
|
||||
|
||||
gleanVersion = "51.8.1"
|
||||
gleanVersion = "51.8.2"
|
||||
if (gleanVersion != getRustVersionFor("glean")) {
|
||||
throw new StopExecutionException("Mismatched Glean version, expected: ${gleanVersion}," +
|
||||
" found ${getRustVersionFor("glean")}")
|
||||
|
|
|
@ -859,9 +859,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "glean"
|
||||
version = "51.8.1"
|
||||
version = "51.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d1f6f93391e6a54301b0896347a100f5f742ccc89bf48c9bd4dad06e7282716"
|
||||
checksum = "43db04e51b1b7e796177e3bda4fdbeb3b649d6e429524863b1ecf699fabc7d6c"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"crossbeam-channel",
|
||||
|
@ -879,9 +879,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "glean-core"
|
||||
version = "51.8.1"
|
||||
version = "51.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8523726fb4d4aa5098198208d5c6e16e26382652a792f42be62caa966bfcd99b"
|
||||
checksum = "b223c24117a769c9d13e3d9a349187113c364f8ca2831b42651f35d0edba4a5f"
|
||||
dependencies = [
|
||||
"android_logger",
|
||||
"bincode",
|
||||
|
@ -892,6 +892,7 @@ dependencies = [
|
|||
"log",
|
||||
"once_cell",
|
||||
"oslog",
|
||||
"remove_dir_all",
|
||||
"rkv",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
@ -1533,9 +1534,9 @@ checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e"
|
|||
|
||||
[[package]]
|
||||
name = "ordered-float"
|
||||
version = "1.0.2"
|
||||
version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518"
|
||||
checksum = "d84eb1409416d254e4a9c8fa56cc24701755025b458f0fcd8e59e1f5f40c23bf"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
@ -1596,31 +1597,12 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880"
|
||||
dependencies = [
|
||||
"paste-impl",
|
||||
"proc-macro-hack",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc"
|
||||
|
||||
[[package]]
|
||||
name = "paste-impl"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6"
|
||||
dependencies = [
|
||||
"proc-macro-hack",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "peek-poke"
|
||||
version = "0.3.0"
|
||||
|
@ -1715,12 +1697,6 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.36"
|
||||
|
@ -1844,10 +1820,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae"
|
||||
|
||||
[[package]]
|
||||
name = "rkv"
|
||||
version = "0.17.0"
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28e2e15d3fff125cfc4fb3f1b226ff83af057c4715061ded16193b7142beefc9"
|
||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rkv"
|
||||
version = "0.18.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c3b196786090b5b57c9bb0f4afca6ac6a5bfb6182c0161ef32f1ecade43ac47"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"bincode",
|
||||
|
@ -1858,7 +1843,7 @@ dependencies = [
|
|||
"lmdb-rkv",
|
||||
"log",
|
||||
"ordered-float",
|
||||
"paste 0.1.18",
|
||||
"paste",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"thiserror",
|
||||
|
@ -1935,9 +1920,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.137"
|
||||
version = "1.0.147"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
|
||||
checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
@ -1953,9 +1938,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.137"
|
||||
version = "1.0.147"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be"
|
||||
checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -2225,7 +2210,7 @@ dependencies = [
|
|||
"cargo_metadata",
|
||||
"log",
|
||||
"once_cell",
|
||||
"paste 1.0.7",
|
||||
"paste",
|
||||
"static_assertions",
|
||||
"uniffi_macros",
|
||||
]
|
||||
|
@ -2245,7 +2230,7 @@ dependencies = [
|
|||
"goblin",
|
||||
"heck",
|
||||
"once_cell",
|
||||
"paste 1.0.7",
|
||||
"paste",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"toml",
|
||||
|
|
|
@ -14,10 +14,6 @@ packages = [
|
|||
# glsl requires 5.1, and xcursor (required by winit) requires 7.1.
|
||||
# when a version of glsl depending on 7.1 is published we can update.
|
||||
"nom",
|
||||
# Transitive dependency of Glean - see bug 1771743
|
||||
# * v0.1.18 through rkv
|
||||
# * v1.0.7 through UniFFI
|
||||
"paste",
|
||||
"rand_core",
|
||||
# Can be fixed by removing time dependency - see bug 1765324
|
||||
"wasi",
|
||||
|
|
|
@ -51,7 +51,7 @@ svg_fmt = "0.4"
|
|||
tracy-rs = "0.1.2"
|
||||
derive_more = { version = "0.99", default-features = false, features = ["add_assign"] }
|
||||
etagere = "0.2.6"
|
||||
glean = "51.8.1"
|
||||
glean = "51.8.2"
|
||||
fog = { version = "0.1.0", optional = true }
|
||||
swgl = { path = "../swgl", optional = true }
|
||||
topological-sort = "0.1"
|
||||
|
|
|
@ -135,7 +135,7 @@ pth:xpcom/geckoprocesstypes_generator
|
|||
pth:xpcom/idl-parser
|
||||
# glean-sdk may not be installable if a wheel isn't available
|
||||
# and it has to be built from source.
|
||||
pypi-optional:glean-sdk==51.8.1:telemetry will not be collected
|
||||
pypi-optional:glean-sdk==51.8.2:telemetry will not be collected
|
||||
# Mach gracefully handles the case where `psutil` is unavailable.
|
||||
# We aren't (yet) able to pin packages in automation, so we have to
|
||||
# support down to the oldest locally-installed version (5.4.2).
|
||||
|
|
|
@ -12,7 +12,7 @@ log = "0.4"
|
|||
moz_task = { path = "../../../../xpcom/rust/moz_task" }
|
||||
nserror = { path = "../../../../xpcom/rust/nserror" }
|
||||
nsstring = { path = "../../../../xpcom/rust/nsstring" }
|
||||
rkv = { version = "0.17", default-features = false }
|
||||
rkv = { version = "0.18", default-features = false }
|
||||
rust_cascade = "1.4.0"
|
||||
sha2 = "0.10.2"
|
||||
storage_variant = { path = "../../../../storage/variant" }
|
||||
|
|
|
@ -550,6 +550,12 @@ criteria = "safe-to-deploy"
|
|||
version = "51.8.1"
|
||||
notes = "Maintained by the Glean Team at Mozilla"
|
||||
|
||||
[[audits.glean]]
|
||||
who = "Chris H-C <chutten@mozilla.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
version = "51.8.2"
|
||||
notes = "Maintained by the Glean Team at Mozilla."
|
||||
|
||||
[[audits.glean]]
|
||||
who = "Jan-Erik Rediger <jrediger@mozilla.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
|
@ -615,6 +621,12 @@ criteria = "safe-to-deploy"
|
|||
version = "51.8.1"
|
||||
notes = "Maintained by the Glean Team at Mozilla"
|
||||
|
||||
[[audits.glean-core]]
|
||||
who = "Chris H-C <chutten@mozilla.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
version = "51.8.2"
|
||||
notes = "Maintained by the Glean Team at Mozilla."
|
||||
|
||||
[[audits.glean-core]]
|
||||
who = "Jan-Erik Rediger <jrediger@mozilla.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
|
@ -1057,6 +1069,12 @@ who = "Mike Hommey <mh+mozilla@glandium.org>"
|
|||
criteria = "safe-to-deploy"
|
||||
delta = "0.6.26 -> 0.6.27"
|
||||
|
||||
[[audits.rkv]]
|
||||
who = "Chris H-C <chutten@mozilla.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
version = "0.18.2"
|
||||
notes = "Maintained by Jan-Erik and :krosylight."
|
||||
|
||||
[[audits.ron]]
|
||||
who = "Mike Hommey <mh+mozilla@glandium.org>"
|
||||
criteria = "safe-to-deploy"
|
||||
|
|
|
@ -1091,10 +1091,6 @@ criteria = "safe-to-deploy"
|
|||
version = "0.2.8"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.rkv]]
|
||||
version = "0.17.1"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.ron]]
|
||||
version = "0.7.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -12,7 +12,7 @@
|
|||
[package]
|
||||
edition = "2018"
|
||||
name = "glean-core"
|
||||
version = "51.8.1"
|
||||
version = "51.8.2"
|
||||
authors = [
|
||||
"Jan-Erik Rediger <jrediger@mozilla.com>",
|
||||
"The Glean Team <glean-team@mozilla.com>",
|
||||
|
@ -55,8 +55,12 @@ version = "0.4.8"
|
|||
[dependencies.once_cell]
|
||||
version = "1.4.1"
|
||||
|
||||
[dependencies.remove_dir_all]
|
||||
version = "0.5.3"
|
||||
|
||||
[dependencies.rkv]
|
||||
version = "0.17.0"
|
||||
version = "0.18.2"
|
||||
features = ["lmdb"]
|
||||
default-features = false
|
||||
|
||||
[dependencies.serde]
|
||||
|
|
|
@ -300,7 +300,7 @@ impl EventDatabase {
|
|||
|
||||
// safe unwrap, only error case is poisoning
|
||||
let _lock = self.file_lock.write().unwrap();
|
||||
std::fs::remove_dir_all(&self.path)?;
|
||||
remove_dir_all::remove_dir_all(&self.path)?;
|
||||
create_dir_all(&self.path)?;
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -355,7 +355,7 @@ impl PingMaker {
|
|||
pub fn clear_pending_pings(&self, data_path: &Path) -> Result<()> {
|
||||
let pings_dir = self.get_pings_dir(data_path, None)?;
|
||||
|
||||
std::fs::remove_dir_all(&pings_dir)?;
|
||||
remove_dir_all::remove_dir_all(&pings_dir)?;
|
||||
create_dir_all(&pings_dir)?;
|
||||
|
||||
log::debug!("All pending pings deleted");
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"09467d10e79fb01d0e70b45095b16c3c064501920b9f0892cf4903ba405cb2da","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"5bc5b1c46695f628e1023662752272e938a963b535d5686bd1ecc433f9e018c4","src/common_test.rs":"68f6d408cb7b683fa32c8b38a4df1e6c45bfd77c0c90ca35976ea7548bbc4b2f","src/configuration.rs":"37ad5b3e7d4e31dd04a7d6690179168b5f2768d87dd36056dee5d08bdbe20fb2","src/core_metrics.rs":"76ac5350cb6f82d9a193d519b085a08f138dceba77da3514bd0c636bcdefefca","src/lib.rs":"7caacc2b5f389bf5d3829a74e77c100b457a63ddf3a914225f26556e3b8bfb18","src/net/http_uploader.rs":"43812a70d19a38e8d7a093c8076c2b6345372c3c861b0f3511428762700a65e0","src/net/mod.rs":"e05e61860f5828caa529c3ea75a2fff7371bfa3dce057077a74c09baf41a568a","src/private/event.rs":"02bbebf545695812e5055741cc0b5f3c99eda2039e684e26fcdd5f087ed15fe3","src/private/mod.rs":"0364ecf5f0439443a5b209583f4ff2c474b79f7c253c981ab0b7cdc528368698","src/private/ping.rs":"cbdc57f41fc9d46e56b4dfff91ac683753d1f8b3ecd0aa9bc3419e3595b8b81b","src/system.rs":"4e0ec743f6d06a9c83e46c95d0286d5745f4642398c942fce8ae7a1ea5202d37","src/test.rs":"1d9a01fa6befdc04e97caeb58ccebd67c840965ff0417b6b2ba9e53aa108a069","tests/common/mod.rs":"37cd4c48e140c793b852ae09fb3e812da28a4412977295015bcbffd632fcf294","tests/init_fails.rs":"9b78226a4e3220de5b64a205a97b8d5778d1700391b5b71c7819b6cdd120747e","tests/never_init.rs":"1f33b8ce7ca3514b57b48cc16d98408974c85cf8aa7d13257ffc2ad878ebb295","tests/no_time_to_init.rs":"494dcddce49f279c6508f484ee59cf8bb83e7324de07bdbc1142f2a066b7f6a1","tests/overflowing_preinit.rs":"396206d5078b7e6c148bbf2aecb0f963cfaa4d7eff3fc7bf6590125076ee6113","tests/persist_ping_lifetime.rs":"2297d4b208e14188e6dcca2d4806b805cfc7dd824d21bd143a7803b95e0709f4","tests/persist_ping_lifetime_nopanic.rs":"06f1f3ca3b8a6c8b7fc4d6fc48d0e1d2ccffd32139f080db0a95003e9edd507d","tests/schema.rs":"a96089f828928b6be1fad7815e3269f5693af1b773e570312b357a29af28122a","tests/simple.rs":"a1d72af899293390bb955ca379baafb89c29bb746630409f8c51f453d222dbad"},"package":"0d1f6f93391e6a54301b0896347a100f5f742ccc89bf48c9bd4dad06e7282716"}
|
||||
{"files":{"Cargo.toml":"82a921c6455e7365042a426efc5a8d34996c7ced9c71db962327606a6f39c9fb","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"5bc5b1c46695f628e1023662752272e938a963b535d5686bd1ecc433f9e018c4","src/common_test.rs":"68f6d408cb7b683fa32c8b38a4df1e6c45bfd77c0c90ca35976ea7548bbc4b2f","src/configuration.rs":"37ad5b3e7d4e31dd04a7d6690179168b5f2768d87dd36056dee5d08bdbe20fb2","src/core_metrics.rs":"76ac5350cb6f82d9a193d519b085a08f138dceba77da3514bd0c636bcdefefca","src/lib.rs":"7caacc2b5f389bf5d3829a74e77c100b457a63ddf3a914225f26556e3b8bfb18","src/net/http_uploader.rs":"43812a70d19a38e8d7a093c8076c2b6345372c3c861b0f3511428762700a65e0","src/net/mod.rs":"e05e61860f5828caa529c3ea75a2fff7371bfa3dce057077a74c09baf41a568a","src/private/event.rs":"02bbebf545695812e5055741cc0b5f3c99eda2039e684e26fcdd5f087ed15fe3","src/private/mod.rs":"0364ecf5f0439443a5b209583f4ff2c474b79f7c253c981ab0b7cdc528368698","src/private/ping.rs":"cbdc57f41fc9d46e56b4dfff91ac683753d1f8b3ecd0aa9bc3419e3595b8b81b","src/system.rs":"4e0ec743f6d06a9c83e46c95d0286d5745f4642398c942fce8ae7a1ea5202d37","src/test.rs":"1d9a01fa6befdc04e97caeb58ccebd67c840965ff0417b6b2ba9e53aa108a069","tests/common/mod.rs":"37cd4c48e140c793b852ae09fb3e812da28a4412977295015bcbffd632fcf294","tests/init_fails.rs":"9b78226a4e3220de5b64a205a97b8d5778d1700391b5b71c7819b6cdd120747e","tests/never_init.rs":"1f33b8ce7ca3514b57b48cc16d98408974c85cf8aa7d13257ffc2ad878ebb295","tests/no_time_to_init.rs":"494dcddce49f279c6508f484ee59cf8bb83e7324de07bdbc1142f2a066b7f6a1","tests/overflowing_preinit.rs":"396206d5078b7e6c148bbf2aecb0f963cfaa4d7eff3fc7bf6590125076ee6113","tests/persist_ping_lifetime.rs":"2297d4b208e14188e6dcca2d4806b805cfc7dd824d21bd143a7803b95e0709f4","tests/persist_ping_lifetime_nopanic.rs":"06f1f3ca3b8a6c8b7fc4d6fc48d0e1d2ccffd32139f080db0a95003e9edd507d","tests/schema.rs":"a96089f828928b6be1fad7815e3269f5693af1b773e570312b357a29af28122a","tests/simple.rs":"a1d72af899293390bb955ca379baafb89c29bb746630409f8c51f453d222dbad"},"package":"43db04e51b1b7e796177e3bda4fdbeb3b649d6e429524863b1ecf699fabc7d6c"}
|
|
@ -12,7 +12,7 @@
|
|||
[package]
|
||||
edition = "2018"
|
||||
name = "glean"
|
||||
version = "51.8.1"
|
||||
version = "51.8.2"
|
||||
authors = [
|
||||
"Jan-Erik Rediger <jrediger@mozilla.com>",
|
||||
"The Glean Team <glean-team@mozilla.com>",
|
||||
|
@ -41,7 +41,7 @@ features = ["serde"]
|
|||
version = "0.5"
|
||||
|
||||
[dependencies.glean-core]
|
||||
version = "51.8.1"
|
||||
version = "51.8.2"
|
||||
|
||||
[dependencies.inherent]
|
||||
version = "1"
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -37,9 +37,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.73"
|
||||
version = "1.0.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
|
||||
checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
@ -49,20 +49,19 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.7.0"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
|
||||
checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499"
|
||||
dependencies = [
|
||||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.0.1"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
|
||||
checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
|
||||
dependencies = [
|
||||
"matches",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
|
@ -74,11 +73,10 @@ checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005"
|
|||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.2.3"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
|
||||
checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
|
||||
dependencies = [
|
||||
"matches",
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
@ -100,9 +98,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.126"
|
||||
version = "0.2.137"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
||||
checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
|
||||
|
||||
[[package]]
|
||||
name = "lmdb-rkv"
|
||||
|
@ -136,12 +134,6 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.15"
|
||||
|
@ -153,54 +145,54 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ordered-float"
|
||||
version = "3.0.0"
|
||||
version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96bcbab4bfea7a59c2c0fe47211a1ac4e3e96bea6eb446d704f310bc5c732ae2"
|
||||
checksum = "d84eb1409416d254e4a9c8fa56cc24701755025b458f0fcd8e59e1f5f40c23bf"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.7"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc"
|
||||
checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.1.0"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
||||
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.25"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
|
||||
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.39"
|
||||
version = "1.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f"
|
||||
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.18"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
|
||||
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.13"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
|
||||
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
@ -216,7 +208,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rkv"
|
||||
version = "0.17.1"
|
||||
version = "0.18.2"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"bincode",
|
||||
|
@ -238,18 +230,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.137"
|
||||
version = "1.0.147"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
|
||||
checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.137"
|
||||
version = "1.0.147"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be"
|
||||
checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -258,9 +250,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.96"
|
||||
version = "1.0.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf"
|
||||
checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -283,18 +275,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.31"
|
||||
version = "1.0.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
|
||||
checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.31"
|
||||
version = "1.0.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
|
||||
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -324,28 +316,27 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
|
|||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.0"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee"
|
||||
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.19"
|
||||
version = "0.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9"
|
||||
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.2.2"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
|
||||
checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"matches",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
|
|
|
@ -11,8 +11,9 @@
|
|||
|
||||
[package]
|
||||
edition = "2018"
|
||||
rust-version = "1.58"
|
||||
name = "rkv"
|
||||
version = "0.17.1"
|
||||
version = "0.18.2"
|
||||
authors = [
|
||||
"Richard Newman <rnewman@twinql.com>",
|
||||
"Nan Jiang <najiang@mozilla.com>",
|
||||
|
@ -33,6 +34,28 @@ categories = ["database"]
|
|||
license = "Apache-2.0"
|
||||
repository = "https://github.com/mozilla/rkv"
|
||||
|
||||
[[bin]]
|
||||
name = "rand"
|
||||
path = "src/bin/rand.rs"
|
||||
required-features = ["lmdb"]
|
||||
|
||||
[[bin]]
|
||||
name = "dump"
|
||||
path = "src/bin/dump.rs"
|
||||
required-features = ["lmdb"]
|
||||
|
||||
[[test]]
|
||||
name = "env-all"
|
||||
required-features = ["lmdb"]
|
||||
|
||||
[[test]]
|
||||
name = "env-lmdb"
|
||||
required-features = ["lmdb"]
|
||||
|
||||
[[test]]
|
||||
name = "env-migration"
|
||||
required-features = ["lmdb"]
|
||||
|
||||
[dependencies.arrayref]
|
||||
version = "0.3"
|
||||
|
||||
|
@ -40,7 +63,7 @@ version = "0.3"
|
|||
version = "1.0"
|
||||
|
||||
[dependencies.bitflags]
|
||||
version = "1.1"
|
||||
version = "1.2"
|
||||
|
||||
[dependencies.byteorder]
|
||||
version = "1"
|
||||
|
@ -53,6 +76,7 @@ version = "1.1"
|
|||
|
||||
[dependencies.lmdb-rkv]
|
||||
version = "0.14"
|
||||
optional = true
|
||||
|
||||
[dependencies.log]
|
||||
version = "0.4.4"
|
||||
|
@ -64,7 +88,7 @@ version = "3.0.0"
|
|||
version = "1.0.6"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
version = "1.0.144"
|
||||
features = [
|
||||
"derive",
|
||||
"rc",
|
||||
|
@ -95,7 +119,17 @@ default = [
|
|||
"db-dup-sort",
|
||||
"db-int-key",
|
||||
]
|
||||
lmdb = ["lmdb-rkv"]
|
||||
no-canonicalize-path = []
|
||||
with-asan = ["lmdb-rkv/with-asan"]
|
||||
with-fuzzer = ["lmdb-rkv/with-fuzzer"]
|
||||
with-fuzzer-no-link = ["lmdb-rkv/with-fuzzer-no-link"]
|
||||
with-asan = [
|
||||
"lmdb",
|
||||
"lmdb-rkv/with-asan",
|
||||
]
|
||||
with-fuzzer = [
|
||||
"lmdb",
|
||||
"lmdb-rkv/with-fuzzer",
|
||||
]
|
||||
with-fuzzer-no-link = [
|
||||
"lmdb",
|
||||
"lmdb-rkv/with-fuzzer-no-link",
|
||||
]
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
# rkv
|
||||
|
||||
[![Travis CI Build Status](https://travis-ci.org/mozilla/rkv.svg?branch=master)](https://travis-ci.org/mozilla/rkv)
|
||||
[![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/lk936u5y5bi6qafb/branch/master?svg=true)](https://ci.appveyor.com/project/mykmelez/rkv/branch/master)
|
||||
[![CI Build Status](https://github.com/mozilla/rkv/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mozilla/rkv/actions/workflows/ci.yml)
|
||||
[![Documentation](https://docs.rs/rkv/badge.svg)](https://docs.rs/rkv/)
|
||||
[![Crate](https://img.shields.io/crates/v/rkv.svg)](https://crates.io/crates/rkv)
|
||||
|
||||
|
|
|
@ -7,25 +7,13 @@
|
|||
//!
|
||||
//! cargo run --example iterator
|
||||
|
||||
use std::{
|
||||
fs,
|
||||
str,
|
||||
};
|
||||
use std::{fs, str};
|
||||
|
||||
use tempfile::Builder;
|
||||
|
||||
use rkv::{
|
||||
backend::{
|
||||
Lmdb,
|
||||
LmdbDatabase,
|
||||
LmdbEnvironment,
|
||||
},
|
||||
Manager,
|
||||
Rkv,
|
||||
SingleStore,
|
||||
StoreError,
|
||||
StoreOptions,
|
||||
Value,
|
||||
backend::{SafeMode, SafeModeDatabase, SafeModeEnvironment},
|
||||
Manager, Rkv, SingleStore, StoreError, StoreOptions, Value,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
|
@ -33,8 +21,8 @@ fn main() {
|
|||
fs::create_dir_all(root.path()).unwrap();
|
||||
let p = root.path();
|
||||
|
||||
let mut manager = Manager::<LmdbEnvironment>::singleton().write().unwrap();
|
||||
let created_arc = manager.get_or_create(p, Rkv::new::<Lmdb>).unwrap();
|
||||
let mut manager = Manager::<SafeModeEnvironment>::singleton().write().unwrap();
|
||||
let created_arc = manager.get_or_create(p, Rkv::new::<SafeMode>).unwrap();
|
||||
let k = created_arc.read().unwrap();
|
||||
let store = k.open_single("store", StoreOptions::create()).unwrap();
|
||||
|
||||
|
@ -47,7 +35,8 @@ fn main() {
|
|||
// returns the (key, value) tuples in order.
|
||||
let mut iter = store.iter_start(&reader).unwrap();
|
||||
while let Some(Ok((country, city))) = iter.next() {
|
||||
println!("{}, {:?}", str::from_utf8(country).unwrap(), city);
|
||||
let country = str::from_utf8(country).unwrap();
|
||||
println!("{country}, {city:?}");
|
||||
}
|
||||
|
||||
println!();
|
||||
|
@ -56,18 +45,21 @@ fn main() {
|
|||
// than the given key.
|
||||
let mut iter = store.iter_from(&reader, "Japan").unwrap();
|
||||
while let Some(Ok((country, city))) = iter.next() {
|
||||
println!("{}, {:?}", str::from_utf8(country).unwrap(), city);
|
||||
println!("{}, {city:?}", str::from_utf8(country).unwrap());
|
||||
}
|
||||
|
||||
println!();
|
||||
println!("Iterating from the given prefix...");
|
||||
let mut iter = store.iter_from(&reader, "Un").unwrap();
|
||||
while let Some(Ok((country, city))) = iter.next() {
|
||||
println!("{}, {:?}", str::from_utf8(country).unwrap(), city);
|
||||
println!("{}, {city:?}", str::from_utf8(country).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
fn populate_store(k: &Rkv<LmdbEnvironment>, store: SingleStore<LmdbDatabase>) -> Result<(), StoreError> {
|
||||
fn populate_store(
|
||||
k: &Rkv<SafeModeEnvironment>,
|
||||
store: SingleStore<SafeModeDatabase>,
|
||||
) -> Result<(), StoreError> {
|
||||
let mut writer = k.write()?;
|
||||
for (country, city) in vec![
|
||||
("Canada", Value::Str("Ottawa")),
|
||||
|
|
|
@ -12,21 +12,12 @@ use std::fs;
|
|||
use tempfile::Builder;
|
||||
|
||||
use rkv::{
|
||||
backend::{
|
||||
BackendStat,
|
||||
Lmdb,
|
||||
LmdbDatabase,
|
||||
LmdbEnvironment,
|
||||
LmdbRwTransaction,
|
||||
},
|
||||
Manager,
|
||||
Rkv,
|
||||
StoreOptions,
|
||||
Value,
|
||||
backend::{SafeMode, SafeModeDatabase, SafeModeEnvironment, SafeModeRwTransaction},
|
||||
Manager, Rkv, StoreOptions, Value,
|
||||
};
|
||||
|
||||
type MultiStore = rkv::MultiStore<LmdbDatabase>;
|
||||
type Writer<'w> = rkv::Writer<LmdbRwTransaction<'w>>;
|
||||
type MultiStore = rkv::MultiStore<SafeModeDatabase>;
|
||||
type Writer<'w> = rkv::Writer<SafeModeRwTransaction<'w>>;
|
||||
|
||||
fn getput<'w, 's>(store: MultiStore, writer: &'w mut Writer, ids: &'s mut Vec<String>) {
|
||||
let keys = vec!["str1", "str2", "str3"];
|
||||
|
@ -52,7 +43,9 @@ fn delete(store: MultiStore, writer: &mut Writer) {
|
|||
let vals = vec!["string uno", "string quatro", "string siete"];
|
||||
// we convert the writer into a cursor so that we can safely read
|
||||
for i in 0..keys.len() {
|
||||
store.delete(writer, &keys[i], &Value::Str(vals[i])).unwrap();
|
||||
store
|
||||
.delete(writer, &keys[i], &Value::Str(vals[i]))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,8 +55,8 @@ fn main() {
|
|||
let p = root.path();
|
||||
|
||||
// The manager enforces that each process opens the same lmdb environment at most once
|
||||
let mut manager = Manager::<LmdbEnvironment>::singleton().write().unwrap();
|
||||
let created_arc = manager.get_or_create(p, Rkv::new::<Lmdb>).unwrap();
|
||||
let mut manager = Manager::<SafeModeEnvironment>::singleton().write().unwrap();
|
||||
let created_arc = manager.get_or_create(p, Rkv::new::<SafeMode>).unwrap();
|
||||
let k = created_arc.read().unwrap();
|
||||
|
||||
// Creates a store called "store"
|
||||
|
@ -75,13 +68,31 @@ fn main() {
|
|||
// Use a writer to mutate the store
|
||||
let mut writer = k.write().unwrap();
|
||||
store.put(&mut writer, "int", &Value::I64(1234)).unwrap();
|
||||
store.put(&mut writer, "uint", &Value::U64(1234_u64)).unwrap();
|
||||
store.put(&mut writer, "float", &Value::F64(1234.0.into())).unwrap();
|
||||
store.put(&mut writer, "instant", &Value::Instant(1_528_318_073_700)).unwrap();
|
||||
store.put(&mut writer, "boolean", &Value::Bool(true)).unwrap();
|
||||
store.put(&mut writer, "string", &Value::Str("héllo, yöu")).unwrap();
|
||||
store.put(&mut writer, "json", &Value::Json(r#"{"foo":"bar", "number": 1}"#)).unwrap();
|
||||
store.put(&mut writer, "blob", &Value::Blob(b"blob")).unwrap();
|
||||
store
|
||||
.put(&mut writer, "uint", &Value::U64(1234_u64))
|
||||
.unwrap();
|
||||
store
|
||||
.put(&mut writer, "float", &Value::F64(1234.0.into()))
|
||||
.unwrap();
|
||||
store
|
||||
.put(&mut writer, "instant", &Value::Instant(1_528_318_073_700))
|
||||
.unwrap();
|
||||
store
|
||||
.put(&mut writer, "boolean", &Value::Bool(true))
|
||||
.unwrap();
|
||||
store
|
||||
.put(&mut writer, "string", &Value::Str("héllo, yöu"))
|
||||
.unwrap();
|
||||
store
|
||||
.put(
|
||||
&mut writer,
|
||||
"json",
|
||||
&Value::Json(r#"{"foo":"bar", "number": 1}"#),
|
||||
)
|
||||
.unwrap();
|
||||
store
|
||||
.put(&mut writer, "blob", &Value::Blob(b"blob"))
|
||||
.unwrap();
|
||||
writer.commit().unwrap();
|
||||
}
|
||||
|
||||
|
@ -89,15 +100,33 @@ fn main() {
|
|||
{
|
||||
let mut ids = Vec::new();
|
||||
let mut writer = k.write().unwrap();
|
||||
multistore.put(&mut writer, "str1", &Value::Str("string uno")).unwrap();
|
||||
multistore.put(&mut writer, "str1", &Value::Str("string dos")).unwrap();
|
||||
multistore.put(&mut writer, "str1", &Value::Str("string tres")).unwrap();
|
||||
multistore.put(&mut writer, "str2", &Value::Str("string quatro")).unwrap();
|
||||
multistore.put(&mut writer, "str2", &Value::Str("string cinco")).unwrap();
|
||||
multistore.put(&mut writer, "str2", &Value::Str("string seis")).unwrap();
|
||||
multistore.put(&mut writer, "str3", &Value::Str("string siete")).unwrap();
|
||||
multistore.put(&mut writer, "str3", &Value::Str("string ocho")).unwrap();
|
||||
multistore.put(&mut writer, "str3", &Value::Str("string nueve")).unwrap();
|
||||
multistore
|
||||
.put(&mut writer, "str1", &Value::Str("string uno"))
|
||||
.unwrap();
|
||||
multistore
|
||||
.put(&mut writer, "str1", &Value::Str("string dos"))
|
||||
.unwrap();
|
||||
multistore
|
||||
.put(&mut writer, "str1", &Value::Str("string tres"))
|
||||
.unwrap();
|
||||
multistore
|
||||
.put(&mut writer, "str2", &Value::Str("string quatro"))
|
||||
.unwrap();
|
||||
multistore
|
||||
.put(&mut writer, "str2", &Value::Str("string cinco"))
|
||||
.unwrap();
|
||||
multistore
|
||||
.put(&mut writer, "str2", &Value::Str("string seis"))
|
||||
.unwrap();
|
||||
multistore
|
||||
.put(&mut writer, "str3", &Value::Str("string siete"))
|
||||
.unwrap();
|
||||
multistore
|
||||
.put(&mut writer, "str3", &Value::Str("string ocho"))
|
||||
.unwrap();
|
||||
multistore
|
||||
.put(&mut writer, "str3", &Value::Str("string nueve"))
|
||||
.unwrap();
|
||||
getput(multistore, &mut writer, &mut ids);
|
||||
writer.commit().unwrap();
|
||||
let mut writer = k.write().unwrap();
|
||||
|
@ -117,7 +146,10 @@ fn main() {
|
|||
println!("Get string {:?}", store.get(&reader, "string").unwrap());
|
||||
println!("Get json {:?}", store.get(&reader, "json").unwrap());
|
||||
println!("Get blob {:?}", store.get(&reader, "blob").unwrap());
|
||||
println!("Get non-existent {:?}", store.get(&reader, "non-existent").unwrap());
|
||||
println!(
|
||||
"Get non-existent {:?}",
|
||||
store.get(&reader, "non-existent").unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
println!("Looking up keys via Writer.get()...");
|
||||
|
@ -126,11 +158,17 @@ fn main() {
|
|||
store.put(&mut writer, "foo", &Value::Str("bar")).unwrap();
|
||||
store.put(&mut writer, "bar", &Value::Str("baz")).unwrap();
|
||||
store.delete(&mut writer, "foo").unwrap();
|
||||
println!("It should be None! ({:?})", store.get(&writer, "foo").unwrap());
|
||||
println!(
|
||||
"It should be None! ({:?})",
|
||||
store.get(&writer, "foo").unwrap()
|
||||
);
|
||||
println!("Get bar ({:?})", store.get(&writer, "bar").unwrap());
|
||||
writer.commit().unwrap();
|
||||
let reader = k.read().expect("reader");
|
||||
println!("It should be None! ({:?})", store.get(&reader, "foo").unwrap());
|
||||
println!(
|
||||
"It should be None! ({:?})",
|
||||
store.get(&reader, "foo").unwrap()
|
||||
);
|
||||
println!("Get bar {:?}", store.get(&reader, "bar").unwrap());
|
||||
}
|
||||
|
||||
|
@ -142,7 +180,10 @@ fn main() {
|
|||
writer.abort();
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
println!("It should be None! ({:?})", store.get(&reader, "foo").unwrap());
|
||||
println!(
|
||||
"It should be None! ({:?})",
|
||||
store.get(&reader, "foo").unwrap()
|
||||
);
|
||||
// Explicitly aborting a transaction is not required unless an early
|
||||
// abort is desired, since both read and write transactions will
|
||||
// implicitly be aborted once they go out of scope.
|
||||
|
@ -154,7 +195,10 @@ fn main() {
|
|||
let mut writer = k.write().unwrap();
|
||||
store.put(&mut writer, "foo", &Value::Str("bar")).unwrap();
|
||||
store.delete(&mut writer, "foo").unwrap();
|
||||
println!("It should be None! ({:?})", store.get(&writer, "foo").unwrap());
|
||||
println!(
|
||||
"It should be None! ({:?})",
|
||||
store.get(&writer, "foo").unwrap()
|
||||
);
|
||||
writer.commit().unwrap();
|
||||
|
||||
// Committing a transaction consumes the writer, preventing you
|
||||
|
@ -173,22 +217,36 @@ fn main() {
|
|||
writer.commit().unwrap();
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
println!("It should be None! ({:?})", store.get(&reader, "foo").unwrap());
|
||||
println!("It should be None! ({:?})", store.get(&reader, "bar").unwrap());
|
||||
println!(
|
||||
"It should be None! ({:?})",
|
||||
store.get(&reader, "foo").unwrap()
|
||||
);
|
||||
println!(
|
||||
"It should be None! ({:?})",
|
||||
store.get(&reader, "bar").unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
println!("Write and read on multiple stores...");
|
||||
{
|
||||
let another_store = k.open_single("another_store", StoreOptions::create()).unwrap();
|
||||
let another_store = k
|
||||
.open_single("another_store", StoreOptions::create())
|
||||
.unwrap();
|
||||
let mut writer = k.write().unwrap();
|
||||
store.put(&mut writer, "foo", &Value::Str("bar")).unwrap();
|
||||
another_store.put(&mut writer, "foo", &Value::Str("baz")).unwrap();
|
||||
another_store
|
||||
.put(&mut writer, "foo", &Value::Str("baz"))
|
||||
.unwrap();
|
||||
writer.commit().unwrap();
|
||||
|
||||
let reader = k.read().unwrap();
|
||||
println!("Get from store value: {:?}", store.get(&reader, "foo").unwrap());
|
||||
println!("Get from another store value: {:?}", another_store.get(&reader, "foo").unwrap());
|
||||
println!(
|
||||
"Get from store value: {:?}",
|
||||
store.get(&reader, "foo").unwrap()
|
||||
);
|
||||
println!(
|
||||
"Get from another store value: {:?}",
|
||||
another_store.get(&reader, "foo").unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
println!("Environment statistics: btree depth = {}", k.stat().unwrap().depth());
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
mod common;
|
||||
#[cfg(feature = "lmdb")]
|
||||
mod impl_lmdb;
|
||||
mod impl_safe;
|
||||
mod traits;
|
||||
|
@ -16,39 +17,24 @@ mod traits;
|
|||
pub use common::*;
|
||||
pub use traits::*;
|
||||
|
||||
#[cfg(feature = "lmdb")]
|
||||
pub use impl_lmdb::{
|
||||
ArchMigrateError as LmdbArchMigrateError,
|
||||
ArchMigrateResult as LmdbArchMigrateResult,
|
||||
ArchMigrator as LmdbArchMigrator,
|
||||
DatabaseFlagsImpl as LmdbDatabaseFlags,
|
||||
DatabaseImpl as LmdbDatabase,
|
||||
EnvironmentBuilderImpl as Lmdb,
|
||||
EnvironmentFlagsImpl as LmdbEnvironmentFlags,
|
||||
EnvironmentImpl as LmdbEnvironment,
|
||||
ErrorImpl as LmdbError,
|
||||
InfoImpl as LmdbInfo,
|
||||
IterImpl as LmdbIter,
|
||||
RoCursorImpl as LmdbRoCursor,
|
||||
RoTransactionImpl as LmdbRoTransaction,
|
||||
RwCursorImpl as LmdbRwCursor,
|
||||
RwTransactionImpl as LmdbRwTransaction,
|
||||
StatImpl as LmdbStat,
|
||||
ArchMigrateError as LmdbArchMigrateError, ArchMigrateResult as LmdbArchMigrateResult,
|
||||
ArchMigrator as LmdbArchMigrator, DatabaseFlagsImpl as LmdbDatabaseFlags,
|
||||
DatabaseImpl as LmdbDatabase, EnvironmentBuilderImpl as Lmdb,
|
||||
EnvironmentFlagsImpl as LmdbEnvironmentFlags, EnvironmentImpl as LmdbEnvironment,
|
||||
ErrorImpl as LmdbError, InfoImpl as LmdbInfo, IterImpl as LmdbIter,
|
||||
RoCursorImpl as LmdbRoCursor, RoTransactionImpl as LmdbRoTransaction,
|
||||
RwCursorImpl as LmdbRwCursor, RwTransactionImpl as LmdbRwTransaction, StatImpl as LmdbStat,
|
||||
WriteFlagsImpl as LmdbWriteFlags,
|
||||
};
|
||||
|
||||
pub use impl_safe::{
|
||||
DatabaseFlagsImpl as SafeModeDatabaseFlags,
|
||||
DatabaseImpl as SafeModeDatabase,
|
||||
EnvironmentBuilderImpl as SafeMode,
|
||||
EnvironmentFlagsImpl as SafeModeEnvironmentFlags,
|
||||
EnvironmentImpl as SafeModeEnvironment,
|
||||
ErrorImpl as SafeModeError,
|
||||
InfoImpl as SafeModeInfo,
|
||||
IterImpl as SafeModeIter,
|
||||
RoCursorImpl as SafeModeRoCursor,
|
||||
RoTransactionImpl as SafeModeRoTransaction,
|
||||
RwCursorImpl as SafeModeRwCursor,
|
||||
RwTransactionImpl as SafeModeRwTransaction,
|
||||
StatImpl as SafeModeStat,
|
||||
DatabaseFlagsImpl as SafeModeDatabaseFlags, DatabaseImpl as SafeModeDatabase,
|
||||
EnvironmentBuilderImpl as SafeMode, EnvironmentFlagsImpl as SafeModeEnvironmentFlags,
|
||||
EnvironmentImpl as SafeModeEnvironment, ErrorImpl as SafeModeError, InfoImpl as SafeModeInfo,
|
||||
IterImpl as SafeModeIter, RoCursorImpl as SafeModeRoCursor,
|
||||
RoTransactionImpl as SafeModeRoTransaction, RwCursorImpl as SafeModeRwCursor,
|
||||
RwTransactionImpl as SafeModeRwTransaction, StatImpl as SafeModeStat,
|
||||
WriteFlagsImpl as SafeModeWriteFlags,
|
||||
};
|
||||
|
|
|
@ -21,29 +21,14 @@ mod stat;
|
|||
mod transaction;
|
||||
|
||||
pub use arch_migrator::{
|
||||
MigrateError as ArchMigrateError,
|
||||
MigrateResult as ArchMigrateResult,
|
||||
Migrator as ArchMigrator,
|
||||
};
|
||||
pub use cursor::{
|
||||
RoCursorImpl,
|
||||
RwCursorImpl,
|
||||
MigrateError as ArchMigrateError, MigrateResult as ArchMigrateResult, Migrator as ArchMigrator,
|
||||
};
|
||||
pub use cursor::{RoCursorImpl, RwCursorImpl};
|
||||
pub use database::DatabaseImpl;
|
||||
pub use environment::{
|
||||
EnvironmentBuilderImpl,
|
||||
EnvironmentImpl,
|
||||
};
|
||||
pub use environment::{EnvironmentBuilderImpl, EnvironmentImpl};
|
||||
pub use error::ErrorImpl;
|
||||
pub use flags::{
|
||||
DatabaseFlagsImpl,
|
||||
EnvironmentFlagsImpl,
|
||||
WriteFlagsImpl,
|
||||
};
|
||||
pub use flags::{DatabaseFlagsImpl, EnvironmentFlagsImpl, WriteFlagsImpl};
|
||||
pub use info::InfoImpl;
|
||||
pub use iter::IterImpl;
|
||||
pub use stat::StatImpl;
|
||||
pub use transaction::{
|
||||
RoTransactionImpl,
|
||||
RwTransactionImpl,
|
||||
};
|
||||
pub use transaction::{RoTransactionImpl, RwTransactionImpl};
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
#![allow(dead_code)] // TODO: Get rid of unused struct members
|
||||
#![allow(clippy::upper_case_acronyms)] // TODO: Consider renaming things like `BRANCH`
|
||||
|
||||
//! A utility for migrating data from one LMDB environment to another. Notably, this tool
|
||||
//! can migrate data from an enviroment created with a different bit-depth than the
|
||||
|
@ -56,38 +58,18 @@
|
|||
//! variants identify specific kinds of migration failures.
|
||||
|
||||
use std::{
|
||||
collections::{
|
||||
BTreeMap,
|
||||
HashMap,
|
||||
},
|
||||
collections::{BTreeMap, HashMap},
|
||||
convert::TryFrom,
|
||||
fs::File,
|
||||
io::{
|
||||
Cursor,
|
||||
Read,
|
||||
Seek,
|
||||
SeekFrom,
|
||||
Write,
|
||||
},
|
||||
path::{
|
||||
Path,
|
||||
PathBuf,
|
||||
},
|
||||
io::{Cursor, Read, Seek, SeekFrom, Write},
|
||||
path::{Path, PathBuf},
|
||||
rc::Rc,
|
||||
str,
|
||||
};
|
||||
|
||||
use bitflags::bitflags;
|
||||
use byteorder::{
|
||||
LittleEndian,
|
||||
ReadBytesExt,
|
||||
};
|
||||
use lmdb::{
|
||||
DatabaseFlags,
|
||||
Environment,
|
||||
Transaction,
|
||||
WriteFlags,
|
||||
};
|
||||
use byteorder::{LittleEndian, ReadBytesExt};
|
||||
use lmdb::{DatabaseFlags, Environment, Transaction, WriteFlags};
|
||||
|
||||
pub use super::arch_migrator_error::MigrateError;
|
||||
|
||||
|
@ -276,9 +258,7 @@ impl Page {
|
|||
|
||||
match Self::parse_page_header(&mut cursor, bits)? {
|
||||
PageHeader::Regular {
|
||||
mp_flags,
|
||||
pb_lower,
|
||||
..
|
||||
mp_flags, pb_lower, ..
|
||||
} => {
|
||||
if mp_flags.contains(PageFlags::LEAF2) || mp_flags.contains(PageFlags::SUBP) {
|
||||
// We don't yet support DUPFIXED and DUPSORT databases.
|
||||
|
@ -297,22 +277,21 @@ impl Page {
|
|||
} else {
|
||||
Err(MigrateError::UnexpectedPageHeaderVariant)
|
||||
}
|
||||
},
|
||||
PageHeader::Overflow {
|
||||
..
|
||||
} => {
|
||||
}
|
||||
PageHeader::Overflow { .. } => {
|
||||
// There isn't anything to do, nor should we try to instantiate
|
||||
// a page of this type, as we only access them when reading
|
||||
// a value that is too large to fit into a leaf node.
|
||||
Err(MigrateError::UnexpectedPageHeaderVariant)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_page_header(cursor: &mut Cursor<&[u8]>, bits: Bits) -> MigrateResult<PageHeader> {
|
||||
let mp_pgno = cursor.read_uint::<LittleEndian>(bits.size())?;
|
||||
let _mp_pad = cursor.read_u16::<LittleEndian>()?;
|
||||
let mp_flags = PageFlags::from_bits(cursor.read_u16::<LittleEndian>()?).ok_or(MigrateError::InvalidPageBits)?;
|
||||
let mp_flags = PageFlags::from_bits(cursor.read_u16::<LittleEndian>()?)
|
||||
.ok_or(MigrateError::InvalidPageBits)?;
|
||||
|
||||
if mp_flags.contains(PageFlags::OVERFLOW) {
|
||||
let pb_pages = cursor.read_u32::<LittleEndian>()?;
|
||||
|
@ -333,7 +312,7 @@ impl Page {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_meta_data(mut cursor: &mut Cursor<&[u8]>, bits: Bits) -> MigrateResult<MetaData> {
|
||||
fn parse_meta_data(cursor: &mut Cursor<&[u8]>, bits: Bits) -> MigrateResult<MetaData> {
|
||||
cursor.seek(SeekFrom::Start(page_header_size(bits)))?;
|
||||
|
||||
Ok(MetaData {
|
||||
|
@ -342,15 +321,19 @@ impl Page {
|
|||
mm_address: cursor.read_uint::<LittleEndian>(bits.size())?,
|
||||
mm_mapsize: cursor.read_uint::<LittleEndian>(bits.size())?,
|
||||
mm_dbs: Databases {
|
||||
free: Database::new(&mut cursor, bits)?,
|
||||
main: Database::new(&mut cursor, bits)?,
|
||||
free: Database::new(cursor, bits)?,
|
||||
main: Database::new(cursor, bits)?,
|
||||
},
|
||||
mm_last_pg: cursor.read_uint::<LittleEndian>(bits.size())?,
|
||||
mm_txnid: cursor.read_uint::<LittleEndian>(bits.size())?,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_leaf_nodes(cursor: &mut Cursor<&[u8]>, pb_lower: u16, bits: Bits) -> MigrateResult<Vec<LeafNode>> {
|
||||
fn parse_leaf_nodes(
|
||||
cursor: &mut Cursor<&[u8]>,
|
||||
pb_lower: u16,
|
||||
bits: Bits,
|
||||
) -> MigrateResult<Vec<LeafNode>> {
|
||||
cursor.set_position(page_header_size(bits));
|
||||
let num_keys = Self::num_keys(pb_lower, bits);
|
||||
let mp_ptrs = Self::parse_mp_ptrs(cursor, num_keys)?;
|
||||
|
@ -371,7 +354,8 @@ impl Page {
|
|||
let mn_lo = cursor.read_u16::<LittleEndian>()?;
|
||||
let mn_hi = cursor.read_u16::<LittleEndian>()?;
|
||||
|
||||
let mn_flags = NodeFlags::from_bits(cursor.read_u16::<LittleEndian>()?).ok_or(MigrateError::InvalidNodeBits)?;
|
||||
let mn_flags = NodeFlags::from_bits(cursor.read_u16::<LittleEndian>()?)
|
||||
.ok_or(MigrateError::InvalidNodeBits)?;
|
||||
let mn_ksize = cursor.read_u16::<LittleEndian>()?;
|
||||
|
||||
let start = usize::try_from(cursor.position())?;
|
||||
|
@ -428,7 +412,11 @@ impl Page {
|
|||
u32::from(mn_lo) + ((u32::from(mn_hi)) << 16)
|
||||
}
|
||||
|
||||
fn parse_branch_nodes(cursor: &mut Cursor<&[u8]>, pb_lower: u16, bits: Bits) -> MigrateResult<Vec<BranchNode>> {
|
||||
fn parse_branch_nodes(
|
||||
cursor: &mut Cursor<&[u8]>,
|
||||
pb_lower: u16,
|
||||
bits: Bits,
|
||||
) -> MigrateResult<Vec<BranchNode>> {
|
||||
let num_keys = Self::num_keys(pb_lower, bits);
|
||||
let mp_ptrs = Self::parse_mp_ptrs(cursor, num_keys)?;
|
||||
|
||||
|
@ -521,10 +509,7 @@ impl Migrator {
|
|||
}
|
||||
};
|
||||
|
||||
Ok(Migrator {
|
||||
file,
|
||||
bits,
|
||||
})
|
||||
Ok(Migrator { file, bits })
|
||||
}
|
||||
|
||||
/// Dump the data in one of the databases in the LMDB environment. If the `database`
|
||||
|
@ -547,8 +532,9 @@ impl Migrator {
|
|||
let pairs;
|
||||
if let Some(database) = database {
|
||||
let subdbs = self.get_subdbs(root_page)?;
|
||||
let database =
|
||||
subdbs.get(database.as_bytes()).ok_or_else(|| MigrateError::DatabaseNotFound(database.to_string()))?;
|
||||
let database = subdbs
|
||||
.get(database.as_bytes())
|
||||
.ok_or_else(|| MigrateError::DatabaseNotFound(database.to_string()))?;
|
||||
let root_page_num = database.md_root;
|
||||
let root_page = Rc::new(self.get_page(root_page_num)?);
|
||||
pairs = self.get_pairs(root_page)?;
|
||||
|
@ -559,7 +545,7 @@ impl Migrator {
|
|||
out.write_all(b"VERSION=3\n")?;
|
||||
out.write_all(b"format=bytevalue\n")?;
|
||||
if let Some(database) = database {
|
||||
writeln!(out, "database={}", database)?;
|
||||
writeln!(out, "database={database}")?;
|
||||
}
|
||||
out.write_all(b"type=btree\n")?;
|
||||
writeln!(out, "mapsize={}", meta_data.mm_mapsize)?;
|
||||
|
@ -570,12 +556,12 @@ impl Migrator {
|
|||
for (key, value) in pairs {
|
||||
out.write_all(b" ")?;
|
||||
for byte in key {
|
||||
write!(out, "{:02x}", byte)?;
|
||||
write!(out, "{byte:02x}")?;
|
||||
}
|
||||
out.write_all(b"\n")?;
|
||||
out.write_all(b" ")?;
|
||||
for byte in value {
|
||||
write!(out, "{:02x}", byte)?;
|
||||
write!(out, "{byte:02x}")?;
|
||||
}
|
||||
out.write_all(b"\n")?;
|
||||
}
|
||||
|
@ -614,7 +600,7 @@ impl Migrator {
|
|||
// awaiting completion of an existing one.
|
||||
env.create_db(None, meta_data.mm_dbs.main.md_flags)?;
|
||||
for (subdb_name, subdb_info) in &subdbs {
|
||||
env.create_db(Some(str::from_utf8(&subdb_name)?), subdb_info.md_flags)?;
|
||||
env.create_db(Some(str::from_utf8(subdb_name)?), subdb_info.md_flags)?;
|
||||
}
|
||||
|
||||
// Now open the read-write transaction that we'll use to migrate all the data.
|
||||
|
@ -633,7 +619,7 @@ impl Migrator {
|
|||
for (subdb_name, subdb_info) in &subdbs {
|
||||
let root_page = Rc::new(self.get_page(subdb_info.md_root)?);
|
||||
let pairs = self.get_pairs(root_page)?;
|
||||
let db = env.open_db(Some(str::from_utf8(&subdb_name)?))?;
|
||||
let db = env.open_db(Some(str::from_utf8(subdb_name)?))?;
|
||||
for (key, value) in pairs {
|
||||
// If we knew that the target database was empty, we could specify
|
||||
// WriteFlags::APPEND to speed up the migration.
|
||||
|
@ -656,22 +642,17 @@ impl Migrator {
|
|||
for branch in nodes {
|
||||
pages.push(Rc::new(self.get_page(branch.mp_pgno)?));
|
||||
}
|
||||
},
|
||||
}
|
||||
Page::LEAF(nodes) => {
|
||||
for leaf in nodes {
|
||||
if let LeafNode::SubData {
|
||||
key,
|
||||
db,
|
||||
..
|
||||
} = leaf
|
||||
{
|
||||
if let LeafNode::SubData { key, db, .. } = leaf {
|
||||
subdbs.insert(key.to_vec(), db.clone());
|
||||
};
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
return Err(MigrateError::UnexpectedPageVariant);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -688,17 +669,13 @@ impl Migrator {
|
|||
for branch in nodes {
|
||||
pages.push(Rc::new(self.get_page(branch.mp_pgno)?));
|
||||
}
|
||||
},
|
||||
}
|
||||
Page::LEAF(nodes) => {
|
||||
for leaf in nodes {
|
||||
match leaf {
|
||||
LeafNode::Regular {
|
||||
key,
|
||||
value,
|
||||
..
|
||||
} => {
|
||||
LeafNode::Regular { key, value, .. } => {
|
||||
pairs.insert(key.to_vec(), value.to_vec());
|
||||
},
|
||||
}
|
||||
LeafNode::BigData {
|
||||
mv_size,
|
||||
key,
|
||||
|
@ -709,14 +686,13 @@ impl Migrator {
|
|||
// migration by waiting to read big data until it's time
|
||||
// to write it to the new database.
|
||||
let value = self.read_data(
|
||||
*overflow_pgno * u64::from(PAGESIZE) + page_header_size(self.bits),
|
||||
*overflow_pgno * u64::from(PAGESIZE)
|
||||
+ page_header_size(self.bits),
|
||||
*mv_size as usize,
|
||||
)?;
|
||||
pairs.insert(key.to_vec(), value);
|
||||
},
|
||||
LeafNode::SubData {
|
||||
..
|
||||
} => {
|
||||
}
|
||||
LeafNode::SubData { .. } => {
|
||||
// We don't include subdatabase leaves in pairs, since
|
||||
// there's no architecture-neutral representation of them,
|
||||
// and in any case they're meta-data that should get
|
||||
|
@ -726,13 +702,13 @@ impl Migrator {
|
|||
// produced by `mdb_dump`, however, we could allow
|
||||
// consumers to specify that they'd like to include these
|
||||
// records.
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
return Err(MigrateError::UnexpectedPageVariant);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -747,7 +723,10 @@ impl Migrator {
|
|||
}
|
||||
|
||||
fn get_page(&mut self, page_no: u64) -> MigrateResult<Page> {
|
||||
Page::new(self.read_data(page_no * u64::from(PAGESIZE), usize::from(PAGESIZE))?, self.bits)
|
||||
Page::new(
|
||||
self.read_data(page_no * u64::from(PAGESIZE), usize::from(PAGESIZE))?,
|
||||
self.bits,
|
||||
)
|
||||
}
|
||||
|
||||
fn get_meta_data(&mut self) -> MigrateResult<MetaData> {
|
||||
|
@ -767,7 +746,7 @@ impl Migrator {
|
|||
return Err(MigrateError::InvalidDataVersion);
|
||||
}
|
||||
Ok(meta)
|
||||
},
|
||||
}
|
||||
_ => Err(MigrateError::UnexpectedPageVariant),
|
||||
}
|
||||
}
|
||||
|
@ -777,20 +756,10 @@ impl Migrator {
|
|||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use std::{
|
||||
env,
|
||||
fs,
|
||||
mem::size_of,
|
||||
};
|
||||
use std::{env, fs, mem::size_of};
|
||||
|
||||
use lmdb::{
|
||||
Environment,
|
||||
Error as LmdbError,
|
||||
};
|
||||
use tempfile::{
|
||||
tempdir,
|
||||
tempfile,
|
||||
};
|
||||
use lmdb::{Environment, Error as LmdbError};
|
||||
use tempfile::{tempdir, tempfile};
|
||||
|
||||
fn compare_files(ref_file: &mut File, new_file: &mut File) -> MigrateResult<()> {
|
||||
ref_file.seek(SeekFrom::Start(0))?;
|
||||
|
@ -801,17 +770,15 @@ mod tests {
|
|||
|
||||
loop {
|
||||
match ref_file.read(ref_buf) {
|
||||
Err(err) => panic!(err),
|
||||
Ok(ref_len) => {
|
||||
match new_file.read(new_buf) {
|
||||
Err(err) => panic!(err),
|
||||
Ok(new_len) => {
|
||||
assert_eq!(ref_len, new_len);
|
||||
if ref_len == 0 {
|
||||
break;
|
||||
};
|
||||
assert_eq!(ref_buf[0..ref_len], new_buf[0..new_len]);
|
||||
},
|
||||
Err(err) => panic!("{}", err),
|
||||
Ok(ref_len) => match new_file.read(new_buf) {
|
||||
Err(err) => panic!("{}", err),
|
||||
Ok(new_len) => {
|
||||
assert_eq!(ref_len, new_len);
|
||||
if ref_len == 0 {
|
||||
break;
|
||||
};
|
||||
assert_eq!(ref_buf[0..ref_len], new_buf[0..new_len]);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -853,7 +820,9 @@ mod tests {
|
|||
migrator.dump(Some("subdb"), &new_dump_file)?;
|
||||
|
||||
// Open the reference dump file.
|
||||
let ref_dump_file_path: PathBuf = [cwd, "tests", "envs", "ref_dump_subdb.txt"].iter().collect();
|
||||
let ref_dump_file_path: PathBuf = [cwd, "tests", "envs", "ref_dump_subdb.txt"]
|
||||
.iter()
|
||||
.collect();
|
||||
let mut ref_dump_file = File::open(ref_dump_file_path)?;
|
||||
|
||||
// Compare the new dump file to the reference dump file.
|
||||
|
@ -895,7 +864,9 @@ mod tests {
|
|||
migrator.dump(Some("subdb"), &new_dump_file)?;
|
||||
|
||||
// Open the reference dump file.
|
||||
let ref_dump_file_path: PathBuf = [cwd, "tests", "envs", "ref_dump_subdb.txt"].iter().collect();
|
||||
let ref_dump_file_path: PathBuf = [cwd, "tests", "envs", "ref_dump_subdb.txt"]
|
||||
.iter()
|
||||
.collect();
|
||||
let mut ref_dump_file = File::open(ref_dump_file_path)?;
|
||||
|
||||
// Compare the new dump file to the reference dump file.
|
||||
|
@ -916,12 +887,14 @@ mod tests {
|
|||
migrator.migrate(new_env.path())?;
|
||||
|
||||
// Dump data from the new env to a new dump file.
|
||||
let mut migrator = Migrator::new(&new_env.path())?;
|
||||
let mut migrator = Migrator::new(new_env.path())?;
|
||||
let mut new_dump_file = tempfile()?;
|
||||
migrator.dump(Some("subdb"), &new_dump_file)?;
|
||||
|
||||
// Open the reference dump file.
|
||||
let ref_dump_file_path: PathBuf = [cwd, "tests", "envs", "ref_dump_subdb.txt"].iter().collect();
|
||||
let ref_dump_file_path: PathBuf = [cwd, "tests", "envs", "ref_dump_subdb.txt"]
|
||||
.iter()
|
||||
.collect();
|
||||
let mut ref_dump_file = File::open(ref_dump_file_path)?;
|
||||
|
||||
// Compare the new dump file to the reference dump file.
|
||||
|
@ -942,12 +915,14 @@ mod tests {
|
|||
migrator.migrate(new_env.path())?;
|
||||
|
||||
// Dump data from the new env to a new dump file.
|
||||
let mut migrator = Migrator::new(&new_env.path())?;
|
||||
let mut migrator = Migrator::new(new_env.path())?;
|
||||
let mut new_dump_file = tempfile()?;
|
||||
migrator.dump(Some("subdb"), &new_dump_file)?;
|
||||
|
||||
// Open the reference dump file.
|
||||
let ref_dump_file_path: PathBuf = [cwd, "tests", "envs", "ref_dump_subdb.txt"].iter().collect();
|
||||
let ref_dump_file_path: PathBuf = [cwd, "tests", "envs", "ref_dump_subdb.txt"]
|
||||
.iter()
|
||||
.collect();
|
||||
let mut ref_dump_file = File::open(ref_dump_file_path)?;
|
||||
|
||||
// Compare the new dump file to the reference dump file.
|
||||
|
@ -969,12 +944,18 @@ mod tests {
|
|||
let test_env_path: PathBuf = [cwd, "tests", "envs", test_env_name].iter().collect();
|
||||
|
||||
let old_env = tempdir()?;
|
||||
fs::copy(test_env_path.join("data.mdb"), old_env.path().join("data.mdb"))?;
|
||||
fs::copy(test_env_path.join("lock.mdb"), old_env.path().join("lock.mdb"))?;
|
||||
fs::copy(
|
||||
test_env_path.join("data.mdb"),
|
||||
old_env.path().join("data.mdb"),
|
||||
)?;
|
||||
fs::copy(
|
||||
test_env_path.join("lock.mdb"),
|
||||
old_env.path().join("lock.mdb"),
|
||||
)?;
|
||||
|
||||
// Confirm that it isn't possible to open the old environment with LMDB.
|
||||
assert_eq!(
|
||||
match Environment::new().open(&old_env.path()) {
|
||||
match Environment::new().open(old_env.path()) {
|
||||
Err(err) => err,
|
||||
_ => panic!("opening the environment should have failed"),
|
||||
},
|
||||
|
@ -983,16 +964,18 @@ mod tests {
|
|||
|
||||
// Migrate data from the old env to a new one.
|
||||
let new_env = tempdir()?;
|
||||
let mut migrator = Migrator::new(&old_env.path())?;
|
||||
let mut migrator = Migrator::new(old_env.path())?;
|
||||
migrator.migrate(new_env.path())?;
|
||||
|
||||
// Dump data from the new env to a new dump file.
|
||||
let mut migrator = Migrator::new(&new_env.path())?;
|
||||
let mut migrator = Migrator::new(new_env.path())?;
|
||||
let mut new_dump_file = tempfile()?;
|
||||
migrator.dump(Some("subdb"), &new_dump_file)?;
|
||||
|
||||
// Open the reference dump file.
|
||||
let ref_dump_file_path: PathBuf = [cwd, "tests", "envs", "ref_dump_subdb.txt"].iter().collect();
|
||||
let ref_dump_file_path: PathBuf = [cwd, "tests", "envs", "ref_dump_subdb.txt"]
|
||||
.iter()
|
||||
.collect();
|
||||
let mut ref_dump_file = File::open(ref_dump_file_path)?;
|
||||
|
||||
// Compare the new dump file to the reference dump file.
|
||||
|
@ -1000,9 +983,15 @@ mod tests {
|
|||
|
||||
// Overwrite the old env's files with the new env's files and confirm that it's now
|
||||
// possible to open the old env with LMDB.
|
||||
fs::copy(new_env.path().join("data.mdb"), old_env.path().join("data.mdb"))?;
|
||||
fs::copy(new_env.path().join("lock.mdb"), old_env.path().join("lock.mdb"))?;
|
||||
assert!(Environment::new().open(&old_env.path()).is_ok());
|
||||
fs::copy(
|
||||
new_env.path().join("data.mdb"),
|
||||
old_env.path().join("data.mdb"),
|
||||
)?;
|
||||
fs::copy(
|
||||
new_env.path().join("lock.mdb"),
|
||||
old_env.path().join("lock.mdb"),
|
||||
)?;
|
||||
assert!(Environment::new().open(old_env.path()).is_ok());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -8,11 +8,7 @@
|
|||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use std::{
|
||||
io,
|
||||
num,
|
||||
str,
|
||||
};
|
||||
use std::{io, num, str};
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
|
|
|
@ -10,32 +10,18 @@
|
|||
|
||||
use std::{
|
||||
fs,
|
||||
path::{
|
||||
Path,
|
||||
PathBuf,
|
||||
},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use lmdb::Error as LmdbError;
|
||||
|
||||
use super::{
|
||||
DatabaseFlagsImpl,
|
||||
DatabaseImpl,
|
||||
EnvironmentFlagsImpl,
|
||||
ErrorImpl,
|
||||
InfoImpl,
|
||||
RoTransactionImpl,
|
||||
RwTransactionImpl,
|
||||
StatImpl,
|
||||
DatabaseFlagsImpl, DatabaseImpl, EnvironmentFlagsImpl, ErrorImpl, InfoImpl, RoTransactionImpl,
|
||||
RwTransactionImpl, StatImpl,
|
||||
};
|
||||
use crate::backend::traits::{
|
||||
BackendEnvironment,
|
||||
BackendEnvironmentBuilder,
|
||||
BackendInfo,
|
||||
BackendIter,
|
||||
BackendRoCursor,
|
||||
BackendRoCursorTransaction,
|
||||
BackendStat,
|
||||
BackendEnvironment, BackendEnvironmentBuilder, BackendInfo, BackendIter, BackendRoCursor,
|
||||
BackendRoCursorTransaction, BackendStat,
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
|
@ -112,7 +98,7 @@ impl<'b> BackendEnvironmentBuilder<'b> for EnvironmentBuilderImpl {
|
|||
if !path.is_file() {
|
||||
return Err(ErrorImpl::UnsuitableEnvironmentPath(path.into()));
|
||||
}
|
||||
},
|
||||
}
|
||||
EnvironmentPathType::SubDir => {
|
||||
if !path.is_dir() {
|
||||
if !self.make_dir_if_needed {
|
||||
|
@ -120,12 +106,21 @@ impl<'b> BackendEnvironmentBuilder<'b> for EnvironmentBuilderImpl {
|
|||
}
|
||||
fs::create_dir_all(path)?;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
self.builder.open(path).map_err(ErrorImpl::LmdbError).and_then(|lmdbenv| {
|
||||
EnvironmentImpl::new(path, self.env_path_type, self.env_lock_type, self.env_db_type, lmdbenv)
|
||||
})
|
||||
self.builder
|
||||
.open(path)
|
||||
.map_err(ErrorImpl::LmdbError)
|
||||
.and_then(|lmdbenv| {
|
||||
EnvironmentImpl::new(
|
||||
path,
|
||||
self.env_path_type,
|
||||
self.env_lock_type,
|
||||
self.env_db_type,
|
||||
lmdbenv,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,33 +182,54 @@ impl<'e> BackendEnvironment<'e> for EnvironmentImpl {
|
|||
if self.env_db_type == EnvironmentDefaultDbType::SingleDatabase {
|
||||
return Ok(vec![None]);
|
||||
}
|
||||
let db = self.lmdbenv.open_db(None).map(DatabaseImpl).map_err(ErrorImpl::LmdbError)?;
|
||||
let db = self
|
||||
.lmdbenv
|
||||
.open_db(None)
|
||||
.map(DatabaseImpl)
|
||||
.map_err(ErrorImpl::LmdbError)?;
|
||||
let reader = self.begin_ro_txn()?;
|
||||
let cursor = reader.open_ro_cursor(&db)?;
|
||||
let mut iter = cursor.into_iter();
|
||||
let mut store = vec![];
|
||||
while let Some(result) = iter.next() {
|
||||
let (key, _) = result?;
|
||||
let name = String::from_utf8(key.to_owned()).map_err(|_| ErrorImpl::LmdbError(lmdb::Error::Corrupted))?;
|
||||
let name = String::from_utf8(key.to_owned())
|
||||
.map_err(|_| ErrorImpl::LmdbError(lmdb::Error::Corrupted))?;
|
||||
store.push(Some(name));
|
||||
}
|
||||
Ok(store)
|
||||
}
|
||||
|
||||
fn open_db(&self, name: Option<&str>) -> Result<Self::Database, Self::Error> {
|
||||
self.lmdbenv.open_db(name).map(DatabaseImpl).map_err(ErrorImpl::LmdbError)
|
||||
self.lmdbenv
|
||||
.open_db(name)
|
||||
.map(DatabaseImpl)
|
||||
.map_err(ErrorImpl::LmdbError)
|
||||
}
|
||||
|
||||
fn create_db(&self, name: Option<&str>, flags: Self::Flags) -> Result<Self::Database, Self::Error> {
|
||||
self.lmdbenv.create_db(name, flags.0).map(DatabaseImpl).map_err(ErrorImpl::LmdbError)
|
||||
fn create_db(
|
||||
&self,
|
||||
name: Option<&str>,
|
||||
flags: Self::Flags,
|
||||
) -> Result<Self::Database, Self::Error> {
|
||||
self.lmdbenv
|
||||
.create_db(name, flags.0)
|
||||
.map(DatabaseImpl)
|
||||
.map_err(ErrorImpl::LmdbError)
|
||||
}
|
||||
|
||||
fn begin_ro_txn(&'e self) -> Result<Self::RoTransaction, Self::Error> {
|
||||
self.lmdbenv.begin_ro_txn().map(RoTransactionImpl).map_err(ErrorImpl::LmdbError)
|
||||
self.lmdbenv
|
||||
.begin_ro_txn()
|
||||
.map(RoTransactionImpl)
|
||||
.map_err(ErrorImpl::LmdbError)
|
||||
}
|
||||
|
||||
fn begin_rw_txn(&'e self) -> Result<Self::RwTransaction, Self::Error> {
|
||||
self.lmdbenv.begin_rw_txn().map(RwTransactionImpl).map_err(ErrorImpl::LmdbError)
|
||||
self.lmdbenv
|
||||
.begin_rw_txn()
|
||||
.map(RwTransactionImpl)
|
||||
.map_err(ErrorImpl::LmdbError)
|
||||
}
|
||||
|
||||
fn sync(&self, force: bool) -> Result<(), Self::Error> {
|
||||
|
@ -221,11 +237,17 @@ impl<'e> BackendEnvironment<'e> for EnvironmentImpl {
|
|||
}
|
||||
|
||||
fn stat(&self) -> Result<Self::Stat, Self::Error> {
|
||||
self.lmdbenv.stat().map(StatImpl).map_err(ErrorImpl::LmdbError)
|
||||
self.lmdbenv
|
||||
.stat()
|
||||
.map(StatImpl)
|
||||
.map_err(ErrorImpl::LmdbError)
|
||||
}
|
||||
|
||||
fn info(&self) -> Result<Self::Info, Self::Error> {
|
||||
self.lmdbenv.info().map(InfoImpl).map_err(ErrorImpl::LmdbError)
|
||||
self.lmdbenv
|
||||
.info()
|
||||
.map(InfoImpl)
|
||||
.map_err(ErrorImpl::LmdbError)
|
||||
}
|
||||
|
||||
fn freelist(&self) -> Result<usize, Self::Error> {
|
||||
|
@ -247,7 +269,9 @@ impl<'e> BackendEnvironment<'e> for EnvironmentImpl {
|
|||
}
|
||||
|
||||
fn set_map_size(&self, size: usize) -> Result<(), Self::Error> {
|
||||
self.lmdbenv.set_map_size(size).map_err(ErrorImpl::LmdbError)
|
||||
self.lmdbenv
|
||||
.set_map_size(size)
|
||||
.map_err(ErrorImpl::LmdbError)
|
||||
}
|
||||
|
||||
fn get_files_on_disk(&self) -> Vec<PathBuf> {
|
||||
|
|
|
@ -8,16 +8,9 @@
|
|||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use std::{
|
||||
fmt,
|
||||
io,
|
||||
path::PathBuf,
|
||||
};
|
||||
use std::{fmt, io, path::PathBuf};
|
||||
|
||||
use crate::{
|
||||
backend::traits::BackendError,
|
||||
error::StoreError,
|
||||
};
|
||||
use crate::{backend::traits::BackendError, error::StoreError};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ErrorImpl {
|
||||
|
@ -49,7 +42,9 @@ impl Into<StoreError> for ErrorImpl {
|
|||
ErrorImpl::LmdbError(lmdb::Error::DbsFull) => StoreError::DbsFull,
|
||||
ErrorImpl::LmdbError(lmdb::Error::ReadersFull) => StoreError::ReadersFull,
|
||||
ErrorImpl::LmdbError(error) => StoreError::LmdbError(error),
|
||||
ErrorImpl::UnsuitableEnvironmentPath(path) => StoreError::UnsuitableEnvironmentPath(path),
|
||||
ErrorImpl::UnsuitableEnvironmentPath(path) => {
|
||||
StoreError::UnsuitableEnvironmentPath(path)
|
||||
}
|
||||
ErrorImpl::IoError(error) => StoreError::IoError(error),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,17 +9,8 @@
|
|||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use crate::backend::{
|
||||
common::{
|
||||
DatabaseFlags,
|
||||
EnvironmentFlags,
|
||||
WriteFlags,
|
||||
},
|
||||
traits::{
|
||||
BackendDatabaseFlags,
|
||||
BackendEnvironmentFlags,
|
||||
BackendFlags,
|
||||
BackendWriteFlags,
|
||||
},
|
||||
common::{DatabaseFlags, EnvironmentFlags, WriteFlags},
|
||||
traits::{BackendDatabaseFlags, BackendEnvironmentFlags, BackendFlags, BackendWriteFlags},
|
||||
};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]
|
||||
|
|
|
@ -22,12 +22,12 @@ pub struct IterImpl<'i, C> {
|
|||
}
|
||||
|
||||
impl<'i, C> IterImpl<'i, C> {
|
||||
pub(crate) fn new(mut cursor: C, to_iter: impl FnOnce(&mut C) -> lmdb::Iter<'i>) -> IterImpl<'i, C> {
|
||||
pub(crate) fn new(
|
||||
mut cursor: C,
|
||||
to_iter: impl FnOnce(&mut C) -> lmdb::Iter<'i>,
|
||||
) -> IterImpl<'i, C> {
|
||||
let iter = to_iter(&mut cursor);
|
||||
IterImpl {
|
||||
cursor,
|
||||
iter,
|
||||
}
|
||||
IterImpl { cursor, iter }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,16 +10,9 @@
|
|||
|
||||
use lmdb::Transaction;
|
||||
|
||||
use super::{
|
||||
DatabaseImpl,
|
||||
ErrorImpl,
|
||||
RoCursorImpl,
|
||||
WriteFlagsImpl,
|
||||
};
|
||||
use super::{DatabaseImpl, ErrorImpl, RoCursorImpl, WriteFlagsImpl};
|
||||
use crate::backend::traits::{
|
||||
BackendRoCursorTransaction,
|
||||
BackendRoTransaction,
|
||||
BackendRwCursorTransaction,
|
||||
BackendRoCursorTransaction, BackendRoTransaction, BackendRwCursorTransaction,
|
||||
BackendRwTransaction,
|
||||
};
|
||||
|
||||
|
@ -43,7 +36,10 @@ impl<'t> BackendRoCursorTransaction<'t> for RoTransactionImpl<'t> {
|
|||
type RoCursor = RoCursorImpl<'t>;
|
||||
|
||||
fn open_ro_cursor(&'t self, db: &Self::Database) -> Result<Self::RoCursor, Self::Error> {
|
||||
self.0.open_ro_cursor(db.0).map(RoCursorImpl).map_err(ErrorImpl::LmdbError)
|
||||
self.0
|
||||
.open_ro_cursor(db.0)
|
||||
.map(RoCursorImpl)
|
||||
.map_err(ErrorImpl::LmdbError)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,8 +55,16 @@ impl<'t> BackendRwTransaction for RwTransactionImpl<'t> {
|
|||
self.0.get(db.0, &key).map_err(ErrorImpl::LmdbError)
|
||||
}
|
||||
|
||||
fn put(&mut self, db: &Self::Database, key: &[u8], value: &[u8], flags: Self::Flags) -> Result<(), Self::Error> {
|
||||
self.0.put(db.0, &key, &value, flags.0).map_err(ErrorImpl::LmdbError)
|
||||
fn put(
|
||||
&mut self,
|
||||
db: &Self::Database,
|
||||
key: &[u8],
|
||||
value: &[u8],
|
||||
flags: Self::Flags,
|
||||
) -> Result<(), Self::Error> {
|
||||
self.0
|
||||
.put(db.0, &key, &value, flags.0)
|
||||
.map_err(ErrorImpl::LmdbError)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "db-dup-sort"))]
|
||||
|
@ -69,7 +73,12 @@ impl<'t> BackendRwTransaction for RwTransactionImpl<'t> {
|
|||
}
|
||||
|
||||
#[cfg(feature = "db-dup-sort")]
|
||||
fn del(&mut self, db: &Self::Database, key: &[u8], value: Option<&[u8]>) -> Result<(), Self::Error> {
|
||||
fn del(
|
||||
&mut self,
|
||||
db: &Self::Database,
|
||||
key: &[u8],
|
||||
value: Option<&[u8]>,
|
||||
) -> Result<(), Self::Error> {
|
||||
self.0.del(db.0, &key, value).map_err(ErrorImpl::LmdbError)
|
||||
}
|
||||
|
||||
|
@ -90,6 +99,9 @@ impl<'t> BackendRwCursorTransaction<'t> for RwTransactionImpl<'t> {
|
|||
type RoCursor = RoCursorImpl<'t>;
|
||||
|
||||
fn open_ro_cursor(&'t self, db: &Self::Database) -> Result<Self::RoCursor, Self::Error> {
|
||||
self.0.open_ro_cursor(db.0).map(RoCursorImpl).map_err(ErrorImpl::LmdbError)
|
||||
self.0
|
||||
.open_ro_cursor(db.0)
|
||||
.map(RoCursorImpl)
|
||||
.map_err(ErrorImpl::LmdbError)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,25 +19,12 @@ mod snapshot;
|
|||
mod stat;
|
||||
mod transaction;
|
||||
|
||||
pub use cursor::{
|
||||
RoCursorImpl,
|
||||
RwCursorImpl,
|
||||
};
|
||||
pub use cursor::{RoCursorImpl, RwCursorImpl};
|
||||
pub use database::DatabaseImpl;
|
||||
pub use environment::{
|
||||
EnvironmentBuilderImpl,
|
||||
EnvironmentImpl,
|
||||
};
|
||||
pub use environment::{EnvironmentBuilderImpl, EnvironmentImpl};
|
||||
pub use error::ErrorImpl;
|
||||
pub use flags::{
|
||||
DatabaseFlagsImpl,
|
||||
EnvironmentFlagsImpl,
|
||||
WriteFlagsImpl,
|
||||
};
|
||||
pub use flags::{DatabaseFlagsImpl, EnvironmentFlagsImpl, WriteFlagsImpl};
|
||||
pub use info::InfoImpl;
|
||||
pub use iter::IterImpl;
|
||||
pub use stat::StatImpl;
|
||||
pub use transaction::{
|
||||
RoTransactionImpl,
|
||||
RwTransactionImpl,
|
||||
};
|
||||
pub use transaction::{RoTransactionImpl, RwTransactionImpl};
|
||||
|
|
|
@ -8,10 +8,7 @@
|
|||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use super::{
|
||||
snapshot::Snapshot,
|
||||
IterImpl,
|
||||
};
|
||||
use super::{snapshot::Snapshot, IterImpl};
|
||||
use crate::backend::traits::BackendRoCursor;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -29,14 +26,18 @@ impl<'c> BackendRoCursor<'c> for RoCursorImpl<'c> {
|
|||
where
|
||||
K: AsRef<[u8]> + 'c,
|
||||
{
|
||||
IterImpl(Box::new(self.0.iter().skip_while(move |&(k, _)| k < key.as_ref())))
|
||||
IterImpl(Box::new(
|
||||
self.0.iter().skip_while(move |&(k, _)| k < key.as_ref()),
|
||||
))
|
||||
}
|
||||
|
||||
fn into_iter_dup_of<K>(self, key: K) -> Self::Iter
|
||||
where
|
||||
K: AsRef<[u8]> + 'c,
|
||||
{
|
||||
IterImpl(Box::new(self.0.iter().filter(move |&(k, _)| k == key.as_ref())))
|
||||
IterImpl(Box::new(
|
||||
self.0.iter().filter(move |&(k, _)| k == key.as_ref()),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,7 +46,10 @@ impl<'c> BackendRoCursor<'c> for RoCursorImpl<'c> {
|
|||
type Iter = IterImpl<'c>;
|
||||
|
||||
fn into_iter(self) -> Self::Iter {
|
||||
let flattened = self.0.iter().flat_map(|(key, values)| values.map(move |value| (key, value)));
|
||||
let flattened = self
|
||||
.0
|
||||
.iter()
|
||||
.flat_map(|(key, values)| values.map(move |value| (key, value)));
|
||||
IterImpl(Box::new(flattened))
|
||||
}
|
||||
|
||||
|
|
|
@ -9,15 +9,9 @@
|
|||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use id_arena::Id;
|
||||
use serde_derive::{
|
||||
Deserialize,
|
||||
Serialize,
|
||||
};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use super::{
|
||||
snapshot::Snapshot,
|
||||
DatabaseFlagsImpl,
|
||||
};
|
||||
use super::{snapshot::Snapshot, DatabaseFlagsImpl};
|
||||
use crate::backend::traits::BackendDatabase;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
|
||||
|
|
|
@ -13,36 +13,18 @@ use std::{
|
|||
collections::HashMap,
|
||||
fs,
|
||||
ops::DerefMut,
|
||||
path::{
|
||||
Path,
|
||||
PathBuf,
|
||||
},
|
||||
sync::{
|
||||
Arc,
|
||||
RwLock,
|
||||
RwLockReadGuard,
|
||||
RwLockWriteGuard,
|
||||
},
|
||||
path::{Path, PathBuf},
|
||||
sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||
};
|
||||
|
||||
use id_arena::Arena;
|
||||
use log::warn;
|
||||
|
||||
use super::{
|
||||
database::Database,
|
||||
DatabaseFlagsImpl,
|
||||
DatabaseImpl,
|
||||
EnvironmentFlagsImpl,
|
||||
ErrorImpl,
|
||||
InfoImpl,
|
||||
RoTransactionImpl,
|
||||
RwTransactionImpl,
|
||||
StatImpl,
|
||||
};
|
||||
use crate::backend::traits::{
|
||||
BackendEnvironment,
|
||||
BackendEnvironmentBuilder,
|
||||
database::Database, DatabaseFlagsImpl, DatabaseImpl, EnvironmentFlagsImpl, ErrorImpl, InfoImpl,
|
||||
RoTransactionImpl, RwTransactionImpl, StatImpl,
|
||||
};
|
||||
use crate::backend::traits::{BackendEnvironment, BackendEnvironmentBuilder};
|
||||
|
||||
const DEFAULT_DB_FILENAME: &str = "data.safe.bin";
|
||||
|
||||
|
@ -117,7 +99,13 @@ impl<'b> BackendEnvironmentBuilder<'b> for EnvironmentBuilderImpl {
|
|||
}
|
||||
fs::create_dir_all(path)?;
|
||||
}
|
||||
let mut env = EnvironmentImpl::new(path, self.flags, self.max_readers, self.max_dbs, self.map_size)?;
|
||||
let mut env = EnvironmentImpl::new(
|
||||
path,
|
||||
self.flags,
|
||||
self.max_readers,
|
||||
self.max_dbs,
|
||||
self.map_size,
|
||||
)?;
|
||||
env.read_from_disk(self.discard_if_corrupted)?;
|
||||
Ok(env)
|
||||
}
|
||||
|
@ -156,14 +144,21 @@ pub struct EnvironmentImpl {
|
|||
impl EnvironmentImpl {
|
||||
fn serialize(&self) -> Result<Vec<u8>, ErrorImpl> {
|
||||
let dbs = self.dbs.read().map_err(|_| ErrorImpl::EnvPoisonError)?;
|
||||
let data: HashMap<_, _> = dbs.name_map.iter().map(|(name, id)| (name, &dbs.arena[id.0])).collect();
|
||||
let data: HashMap<_, _> = dbs
|
||||
.name_map
|
||||
.iter()
|
||||
.map(|(name, id)| (name, &dbs.arena[id.0]))
|
||||
.collect();
|
||||
Ok(bincode::serialize(&data)?)
|
||||
}
|
||||
|
||||
fn deserialize(bytes: &[u8], discard_if_corrupted: bool) -> Result<(DatabaseArena, DatabaseNameMap), ErrorImpl> {
|
||||
fn deserialize(
|
||||
bytes: &[u8],
|
||||
discard_if_corrupted: bool,
|
||||
) -> Result<(DatabaseArena, DatabaseNameMap), ErrorImpl> {
|
||||
let mut arena = DatabaseArena::new();
|
||||
let mut name_map = HashMap::new();
|
||||
let data: HashMap<_, _> = match bincode::deserialize(&bytes) {
|
||||
let data: HashMap<_, _> = match bincode::deserialize(bytes) {
|
||||
Err(_) if discard_if_corrupted => Ok(HashMap::new()),
|
||||
result => result,
|
||||
}?;
|
||||
|
@ -213,10 +208,7 @@ impl EnvironmentImpl {
|
|||
return Ok(());
|
||||
};
|
||||
let (arena, name_map) = Self::deserialize(&fs::read(&path)?, discard_if_corrupted)?;
|
||||
self.dbs = RwLock::new(EnvironmentDbs {
|
||||
arena,
|
||||
name_map,
|
||||
});
|
||||
self.dbs = RwLock::new(EnvironmentDbs { arena, name_map });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -263,20 +255,26 @@ impl<'e> BackendEnvironment<'e> for EnvironmentImpl {
|
|||
Ok(*db)
|
||||
}
|
||||
|
||||
fn create_db(&self, name: Option<&str>, flags: Self::Flags) -> Result<Self::Database, Self::Error> {
|
||||
fn create_db(
|
||||
&self,
|
||||
name: Option<&str>,
|
||||
flags: Self::Flags,
|
||||
) -> Result<Self::Database, Self::Error> {
|
||||
if Arc::strong_count(&self.ro_txns) > 1 {
|
||||
return Err(ErrorImpl::DbsIllegalOpen);
|
||||
}
|
||||
// TOOD: don't reallocate `name`.
|
||||
let key = name.map(String::from);
|
||||
let mut dbs = self.dbs.write().map_err(|_| ErrorImpl::EnvPoisonError)?;
|
||||
if dbs.name_map.keys().filter_map(|k| k.as_ref()).count() >= self.max_dbs && name != None {
|
||||
if dbs.name_map.keys().filter_map(|k| k.as_ref()).count() >= self.max_dbs && name.is_some() {
|
||||
return Err(ErrorImpl::DbsFull);
|
||||
}
|
||||
let parts = EnvironmentDbsRefMut::from(dbs.deref_mut());
|
||||
let arena = parts.arena;
|
||||
let name_map = parts.name_map;
|
||||
let id = name_map.entry(key).or_insert_with(|| DatabaseImpl(arena.alloc(Database::new(Some(flags), None))));
|
||||
let id = name_map
|
||||
.entry(key)
|
||||
.or_insert_with(|| DatabaseImpl(arena.alloc(Database::new(Some(flags), None))));
|
||||
Ok(*id)
|
||||
}
|
||||
|
||||
|
@ -311,7 +309,10 @@ impl<'e> BackendEnvironment<'e> for EnvironmentImpl {
|
|||
}
|
||||
|
||||
fn set_map_size(&self, size: usize) -> Result<(), Self::Error> {
|
||||
warn!("`set_map_size({})` is ignored by this storage backend.", size);
|
||||
warn!(
|
||||
"`set_map_size({})` is ignored by this storage backend.",
|
||||
size
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -320,6 +321,6 @@ impl<'e> BackendEnvironment<'e> for EnvironmentImpl {
|
|||
// they're both currently unimplemented with this storage backend.
|
||||
let mut db_filename = self.path.clone();
|
||||
db_filename.push(DEFAULT_DB_FILENAME);
|
||||
return vec![db_filename];
|
||||
vec![db_filename]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,18 +8,11 @@
|
|||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use std::{
|
||||
fmt,
|
||||
io,
|
||||
path::PathBuf,
|
||||
};
|
||||
use std::{fmt, io, path::PathBuf};
|
||||
|
||||
use bincode::Error as BincodeError;
|
||||
|
||||
use crate::{
|
||||
backend::traits::BackendError,
|
||||
error::StoreError,
|
||||
};
|
||||
use crate::{backend::traits::BackendError, error::StoreError};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ErrorImpl {
|
||||
|
@ -45,7 +38,9 @@ impl fmt::Display for ErrorImpl {
|
|||
ErrorImpl::DbsIllegalOpen => write!(fmt, "DbIllegalOpen (safe mode)"),
|
||||
ErrorImpl::DbNotFoundError => write!(fmt, "DbNotFoundError (safe mode)"),
|
||||
ErrorImpl::DbIsForeignError => write!(fmt, "DbIsForeignError (safe mode)"),
|
||||
ErrorImpl::UnsuitableEnvironmentPath(_) => write!(fmt, "UnsuitableEnvironmentPath (safe mode)"),
|
||||
ErrorImpl::UnsuitableEnvironmentPath(_) => {
|
||||
write!(fmt, "UnsuitableEnvironmentPath (safe mode)")
|
||||
}
|
||||
ErrorImpl::IoError(e) => e.fmt(fmt),
|
||||
ErrorImpl::BincodeError(e) => e.fmt(fmt),
|
||||
}
|
||||
|
@ -62,7 +57,9 @@ impl Into<StoreError> for ErrorImpl {
|
|||
ErrorImpl::KeyValuePairNotFound => StoreError::KeyValuePairNotFound,
|
||||
ErrorImpl::BincodeError(_) => StoreError::FileInvalid,
|
||||
ErrorImpl::DbsFull => StoreError::DbsFull,
|
||||
ErrorImpl::UnsuitableEnvironmentPath(path) => StoreError::UnsuitableEnvironmentPath(path),
|
||||
ErrorImpl::UnsuitableEnvironmentPath(path) => {
|
||||
StoreError::UnsuitableEnvironmentPath(path)
|
||||
}
|
||||
ErrorImpl::IoError(error) => StoreError::IoError(error),
|
||||
_ => StoreError::SafeModeError(self),
|
||||
}
|
||||
|
|
|
@ -9,23 +9,11 @@
|
|||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use bitflags::bitflags;
|
||||
use serde_derive::{
|
||||
Deserialize,
|
||||
Serialize,
|
||||
};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use crate::backend::{
|
||||
common::{
|
||||
DatabaseFlags,
|
||||
EnvironmentFlags,
|
||||
WriteFlags,
|
||||
},
|
||||
traits::{
|
||||
BackendDatabaseFlags,
|
||||
BackendEnvironmentFlags,
|
||||
BackendFlags,
|
||||
BackendWriteFlags,
|
||||
},
|
||||
common::{DatabaseFlags, EnvironmentFlags, WriteFlags},
|
||||
traits::{BackendDatabaseFlags, BackendEnvironmentFlags, BackendFlags, BackendWriteFlags},
|
||||
};
|
||||
|
||||
bitflags! {
|
||||
|
|
|
@ -9,17 +9,11 @@
|
|||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use std::{
|
||||
collections::{
|
||||
BTreeMap,
|
||||
BTreeSet,
|
||||
},
|
||||
collections::{BTreeMap, BTreeSet},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use serde_derive::{
|
||||
Deserialize,
|
||||
Serialize,
|
||||
};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use super::DatabaseFlagsImpl;
|
||||
|
||||
|
@ -38,7 +32,7 @@ pub struct Snapshot {
|
|||
impl Snapshot {
|
||||
pub(crate) fn new(flags: Option<DatabaseFlagsImpl>) -> Snapshot {
|
||||
Snapshot {
|
||||
flags: flags.unwrap_or_else(DatabaseFlagsImpl::default),
|
||||
flags: flags.unwrap_or_default(),
|
||||
map: Default::default(),
|
||||
}
|
||||
}
|
||||
|
@ -69,14 +63,19 @@ impl Snapshot {
|
|||
}
|
||||
|
||||
pub(crate) fn iter(&self) -> impl Iterator<Item = (&[u8], &[u8])> {
|
||||
self.map.iter().map(|(key, value)| (key.as_ref(), value.as_ref()))
|
||||
self.map
|
||||
.iter()
|
||||
.map(|(key, value)| (key.as_ref(), value.as_ref()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "db-dup-sort")]
|
||||
impl Snapshot {
|
||||
pub(crate) fn get(&self, key: &[u8]) -> Option<&[u8]> {
|
||||
self.map.get(key).and_then(|v| v.iter().next()).map(|v| v.as_ref())
|
||||
self.map
|
||||
.get(key)
|
||||
.and_then(|v| v.iter().next())
|
||||
.map(|v| v.as_ref())
|
||||
}
|
||||
|
||||
pub(crate) fn put(&mut self, key: &[u8], value: &[u8]) {
|
||||
|
@ -86,11 +85,11 @@ impl Snapshot {
|
|||
let mut values = BTreeSet::new();
|
||||
values.insert(Box::from(value));
|
||||
map.insert(Box::from(key), values);
|
||||
},
|
||||
}
|
||||
Some(values) => {
|
||||
values.clear();
|
||||
values.insert(Box::from(value));
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,12 +101,14 @@ impl Snapshot {
|
|||
let was_empty = values.is_empty();
|
||||
values.clear();
|
||||
Some(()).filter(|_| !was_empty)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn iter(&self) -> impl Iterator<Item = (&[u8], impl Iterator<Item = &[u8]>)> {
|
||||
self.map.iter().map(|(key, values)| (key.as_ref(), values.iter().map(|value| value.as_ref())))
|
||||
self.map
|
||||
.iter()
|
||||
.map(|(key, values)| (key.as_ref(), values.iter().map(|value| value.as_ref())))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,10 +121,10 @@ impl Snapshot {
|
|||
let mut values = BTreeSet::new();
|
||||
values.insert(Box::from(value));
|
||||
map.insert(Box::from(key), values);
|
||||
},
|
||||
}
|
||||
Some(values) => {
|
||||
values.insert(Box::from(value));
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,7 +135,7 @@ impl Snapshot {
|
|||
Some(values) => {
|
||||
let was_removed = values.remove(value);
|
||||
Some(()).filter(|_| was_removed)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,24 +7,15 @@
|
|||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
#![allow(dead_code)] // TODO: Get rid of unused struct members
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::Arc,
|
||||
};
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use super::{
|
||||
snapshot::Snapshot,
|
||||
DatabaseImpl,
|
||||
EnvironmentImpl,
|
||||
ErrorImpl,
|
||||
RoCursorImpl,
|
||||
WriteFlagsImpl,
|
||||
snapshot::Snapshot, DatabaseImpl, EnvironmentImpl, ErrorImpl, RoCursorImpl, WriteFlagsImpl,
|
||||
};
|
||||
use crate::backend::traits::{
|
||||
BackendRoCursorTransaction,
|
||||
BackendRoTransaction,
|
||||
BackendRwCursorTransaction,
|
||||
BackendRoCursorTransaction, BackendRoTransaction, BackendRwCursorTransaction,
|
||||
BackendRwTransaction,
|
||||
};
|
||||
|
||||
|
@ -36,8 +27,16 @@ pub struct RoTransactionImpl<'t> {
|
|||
}
|
||||
|
||||
impl<'t> RoTransactionImpl<'t> {
|
||||
pub(crate) fn new(env: &'t EnvironmentImpl, idx: Arc<()>) -> Result<RoTransactionImpl<'t>, ErrorImpl> {
|
||||
let snapshots = env.dbs()?.arena.iter().map(|(id, db)| (DatabaseImpl(id), db.snapshot())).collect();
|
||||
pub(crate) fn new(
|
||||
env: &'t EnvironmentImpl,
|
||||
idx: Arc<()>,
|
||||
) -> Result<RoTransactionImpl<'t>, ErrorImpl> {
|
||||
let snapshots = env
|
||||
.dbs()?
|
||||
.arena
|
||||
.iter()
|
||||
.map(|(id, db)| (DatabaseImpl(id), db.snapshot()))
|
||||
.collect();
|
||||
Ok(RoTransactionImpl {
|
||||
env,
|
||||
snapshots,
|
||||
|
@ -51,8 +50,8 @@ impl<'t> BackendRoTransaction for RoTransactionImpl<'t> {
|
|||
type Error = ErrorImpl;
|
||||
|
||||
fn get(&self, db: &Self::Database, key: &[u8]) -> Result<&[u8], Self::Error> {
|
||||
let snapshot = self.snapshots.get(db).ok_or_else(|| ErrorImpl::DbIsForeignError)?;
|
||||
snapshot.get(key).ok_or_else(|| ErrorImpl::KeyValuePairNotFound)
|
||||
let snapshot = self.snapshots.get(db).ok_or(ErrorImpl::DbIsForeignError)?;
|
||||
snapshot.get(key).ok_or(ErrorImpl::KeyValuePairNotFound)
|
||||
}
|
||||
|
||||
fn abort(self) {
|
||||
|
@ -64,7 +63,7 @@ impl<'t> BackendRoCursorTransaction<'t> for RoTransactionImpl<'t> {
|
|||
type RoCursor = RoCursorImpl<'t>;
|
||||
|
||||
fn open_ro_cursor(&'t self, db: &Self::Database) -> Result<Self::RoCursor, Self::Error> {
|
||||
let snapshot = self.snapshots.get(db).ok_or_else(|| ErrorImpl::DbIsForeignError)?;
|
||||
let snapshot = self.snapshots.get(db).ok_or(ErrorImpl::DbIsForeignError)?;
|
||||
Ok(RoCursorImpl(snapshot))
|
||||
}
|
||||
}
|
||||
|
@ -77,8 +76,16 @@ pub struct RwTransactionImpl<'t> {
|
|||
}
|
||||
|
||||
impl<'t> RwTransactionImpl<'t> {
|
||||
pub(crate) fn new(env: &'t EnvironmentImpl, idx: Arc<()>) -> Result<RwTransactionImpl<'t>, ErrorImpl> {
|
||||
let snapshots = env.dbs()?.arena.iter().map(|(id, db)| (DatabaseImpl(id), db.snapshot())).collect();
|
||||
pub(crate) fn new(
|
||||
env: &'t EnvironmentImpl,
|
||||
idx: Arc<()>,
|
||||
) -> Result<RwTransactionImpl<'t>, ErrorImpl> {
|
||||
let snapshots = env
|
||||
.dbs()?
|
||||
.arena
|
||||
.iter()
|
||||
.map(|(id, db)| (DatabaseImpl(id), db.snapshot()))
|
||||
.collect();
|
||||
Ok(RwTransactionImpl {
|
||||
env,
|
||||
snapshots,
|
||||
|
@ -93,21 +100,39 @@ impl<'t> BackendRwTransaction for RwTransactionImpl<'t> {
|
|||
type Flags = WriteFlagsImpl;
|
||||
|
||||
fn get(&self, db: &Self::Database, key: &[u8]) -> Result<&[u8], Self::Error> {
|
||||
let snapshot = self.snapshots.get(db).ok_or_else(|| ErrorImpl::DbIsForeignError)?;
|
||||
snapshot.get(key).ok_or_else(|| ErrorImpl::KeyValuePairNotFound)
|
||||
let snapshot = self.snapshots.get(db).ok_or(ErrorImpl::DbIsForeignError)?;
|
||||
snapshot.get(key).ok_or(ErrorImpl::KeyValuePairNotFound)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "db-dup-sort"))]
|
||||
fn put(&mut self, db: &Self::Database, key: &[u8], value: &[u8], _flags: Self::Flags) -> Result<(), Self::Error> {
|
||||
let snapshot = self.snapshots.get_mut(db).ok_or_else(|| ErrorImpl::DbIsForeignError)?;
|
||||
fn put(
|
||||
&mut self,
|
||||
db: &Self::Database,
|
||||
key: &[u8],
|
||||
value: &[u8],
|
||||
_flags: Self::Flags,
|
||||
) -> Result<(), Self::Error> {
|
||||
let snapshot = self
|
||||
.snapshots
|
||||
.get_mut(db)
|
||||
.ok_or_else(|| ErrorImpl::DbIsForeignError)?;
|
||||
snapshot.put(key, value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "db-dup-sort")]
|
||||
fn put(&mut self, db: &Self::Database, key: &[u8], value: &[u8], _flags: Self::Flags) -> Result<(), Self::Error> {
|
||||
fn put(
|
||||
&mut self,
|
||||
db: &Self::Database,
|
||||
key: &[u8],
|
||||
value: &[u8],
|
||||
_flags: Self::Flags,
|
||||
) -> Result<(), Self::Error> {
|
||||
use super::DatabaseFlagsImpl;
|
||||
let snapshot = self.snapshots.get_mut(db).ok_or_else(|| ErrorImpl::DbIsForeignError)?;
|
||||
let snapshot = self
|
||||
.snapshots
|
||||
.get_mut(db)
|
||||
.ok_or(ErrorImpl::DbIsForeignError)?;
|
||||
if snapshot.flags().contains(DatabaseFlagsImpl::DUP_SORT) {
|
||||
snapshot.put_dup(key, value);
|
||||
} else {
|
||||
|
@ -118,24 +143,40 @@ impl<'t> BackendRwTransaction for RwTransactionImpl<'t> {
|
|||
|
||||
#[cfg(not(feature = "db-dup-sort"))]
|
||||
fn del(&mut self, db: &Self::Database, key: &[u8]) -> Result<(), Self::Error> {
|
||||
let snapshot = self.snapshots.get_mut(db).ok_or_else(|| ErrorImpl::DbIsForeignError)?;
|
||||
let snapshot = self
|
||||
.snapshots
|
||||
.get_mut(db)
|
||||
.ok_or_else(|| ErrorImpl::DbIsForeignError)?;
|
||||
let deleted = snapshot.del(key);
|
||||
Ok(deleted.ok_or_else(|| ErrorImpl::KeyValuePairNotFound)?)
|
||||
}
|
||||
|
||||
#[cfg(feature = "db-dup-sort")]
|
||||
fn del(&mut self, db: &Self::Database, key: &[u8], value: Option<&[u8]>) -> Result<(), Self::Error> {
|
||||
fn del(
|
||||
&mut self,
|
||||
db: &Self::Database,
|
||||
key: &[u8],
|
||||
value: Option<&[u8]>,
|
||||
) -> Result<(), Self::Error> {
|
||||
use super::DatabaseFlagsImpl;
|
||||
let snapshot = self.snapshots.get_mut(db).ok_or_else(|| ErrorImpl::DbIsForeignError)?;
|
||||
let snapshot = self
|
||||
.snapshots
|
||||
.get_mut(db)
|
||||
.ok_or(ErrorImpl::DbIsForeignError)?;
|
||||
let deleted = match (value, snapshot.flags()) {
|
||||
(Some(value), flags) if flags.contains(DatabaseFlagsImpl::DUP_SORT) => snapshot.del_exact(key, value),
|
||||
(Some(value), flags) if flags.contains(DatabaseFlagsImpl::DUP_SORT) => {
|
||||
snapshot.del_exact(key, value)
|
||||
}
|
||||
_ => snapshot.del(key),
|
||||
};
|
||||
Ok(deleted.ok_or_else(|| ErrorImpl::KeyValuePairNotFound)?)
|
||||
deleted.ok_or(ErrorImpl::KeyValuePairNotFound)
|
||||
}
|
||||
|
||||
fn clear_db(&mut self, db: &Self::Database) -> Result<(), Self::Error> {
|
||||
let snapshot = self.snapshots.get_mut(db).ok_or_else(|| ErrorImpl::DbIsForeignError)?;
|
||||
let snapshot = self
|
||||
.snapshots
|
||||
.get_mut(db)
|
||||
.ok_or(ErrorImpl::DbIsForeignError)?;
|
||||
snapshot.clear();
|
||||
Ok(())
|
||||
}
|
||||
|
@ -144,7 +185,7 @@ impl<'t> BackendRwTransaction for RwTransactionImpl<'t> {
|
|||
let mut dbs = self.env.dbs_mut()?;
|
||||
|
||||
for (id, snapshot) in self.snapshots {
|
||||
let db = dbs.arena.get_mut(id.0).ok_or_else(|| ErrorImpl::DbIsForeignError)?;
|
||||
let db = dbs.arena.get_mut(id.0).ok_or(ErrorImpl::DbIsForeignError)?;
|
||||
db.replace(snapshot);
|
||||
}
|
||||
|
||||
|
@ -161,7 +202,7 @@ impl<'t> BackendRwCursorTransaction<'t> for RwTransactionImpl<'t> {
|
|||
type RoCursor = RoCursorImpl<'t>;
|
||||
|
||||
fn open_ro_cursor(&'t self, db: &Self::Database) -> Result<Self::RoCursor, Self::Error> {
|
||||
let snapshot = self.snapshots.get(db).ok_or_else(|| ErrorImpl::DbIsForeignError)?;
|
||||
let snapshot = self.snapshots.get(db).ok_or(ErrorImpl::DbIsForeignError)?;
|
||||
Ok(RoCursorImpl(snapshot))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,22 +9,12 @@
|
|||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use std::{
|
||||
fmt::{
|
||||
Debug,
|
||||
Display,
|
||||
},
|
||||
path::{
|
||||
Path,
|
||||
PathBuf,
|
||||
},
|
||||
fmt::{Debug, Display},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
backend::common::{
|
||||
DatabaseFlags,
|
||||
EnvironmentFlags,
|
||||
WriteFlags,
|
||||
},
|
||||
backend::common::{DatabaseFlags, EnvironmentFlags, WriteFlags},
|
||||
error::StoreError,
|
||||
};
|
||||
|
||||
|
@ -111,7 +101,11 @@ pub trait BackendEnvironment<'e>: Debug {
|
|||
|
||||
fn open_db(&self, name: Option<&str>) -> Result<Self::Database, Self::Error>;
|
||||
|
||||
fn create_db(&self, name: Option<&str>, flags: Self::Flags) -> Result<Self::Database, Self::Error>;
|
||||
fn create_db(
|
||||
&self,
|
||||
name: Option<&str>,
|
||||
flags: Self::Flags,
|
||||
) -> Result<Self::Database, Self::Error>;
|
||||
|
||||
fn begin_ro_txn(&'e self) -> Result<Self::RoTransaction, Self::Error>;
|
||||
|
||||
|
@ -148,13 +142,24 @@ pub trait BackendRwTransaction: Debug {
|
|||
|
||||
fn get(&self, db: &Self::Database, key: &[u8]) -> Result<&[u8], Self::Error>;
|
||||
|
||||
fn put(&mut self, db: &Self::Database, key: &[u8], value: &[u8], flags: Self::Flags) -> Result<(), Self::Error>;
|
||||
fn put(
|
||||
&mut self,
|
||||
db: &Self::Database,
|
||||
key: &[u8],
|
||||
value: &[u8],
|
||||
flags: Self::Flags,
|
||||
) -> Result<(), Self::Error>;
|
||||
|
||||
#[cfg(not(feature = "db-dup-sort"))]
|
||||
fn del(&mut self, db: &Self::Database, key: &[u8]) -> Result<(), Self::Error>;
|
||||
|
||||
#[cfg(feature = "db-dup-sort")]
|
||||
fn del(&mut self, db: &Self::Database, key: &[u8], value: Option<&[u8]>) -> Result<(), Self::Error>;
|
||||
fn del(
|
||||
&mut self,
|
||||
db: &Self::Database,
|
||||
key: &[u8],
|
||||
value: Option<&[u8]>,
|
||||
) -> Result<(), Self::Error>;
|
||||
|
||||
fn clear_db(&mut self, db: &Self::Database) -> Result<(), Self::Error>;
|
||||
|
||||
|
|
|
@ -8,16 +8,9 @@
|
|||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use std::{
|
||||
env::args,
|
||||
io,
|
||||
path::Path,
|
||||
};
|
||||
use std::{env::args, io, path::Path};
|
||||
|
||||
use rkv::migrator::{
|
||||
LmdbArchMigrateError,
|
||||
LmdbArchMigrator,
|
||||
};
|
||||
use rkv::migrator::{LmdbArchMigrateError, LmdbArchMigrator};
|
||||
|
||||
fn main() -> Result<(), LmdbArchMigrateError> {
|
||||
let mut cli_args = args();
|
||||
|
@ -35,8 +28,8 @@ fn main() -> Result<(), LmdbArchMigrateError> {
|
|||
None => return Err("-s must be followed by database name".into()),
|
||||
Some(str) => Some(str),
|
||||
};
|
||||
},
|
||||
str => return Err(format!("arg -{} not recognized", str).into()),
|
||||
}
|
||||
str => return Err(format!("arg -{str} not recognized").into()),
|
||||
}
|
||||
} else {
|
||||
if env_path.is_some() {
|
||||
|
|
|
@ -14,22 +14,11 @@
|
|||
//! the number of key/value pairs to create via the `-n <number>` flag
|
||||
//! (for which the default value is 50).
|
||||
|
||||
use std::{
|
||||
env::args,
|
||||
fs,
|
||||
fs::File,
|
||||
io::Read,
|
||||
path::Path,
|
||||
};
|
||||
use std::{env::args, fs, fs::File, io::Read, path::Path};
|
||||
|
||||
use rkv::{
|
||||
backend::{
|
||||
BackendEnvironmentBuilder,
|
||||
Lmdb,
|
||||
},
|
||||
Rkv,
|
||||
StoreOptions,
|
||||
Value,
|
||||
backend::{BackendEnvironmentBuilder, Lmdb},
|
||||
Rkv, StoreOptions, Value,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
|
@ -49,13 +38,13 @@ fn main() {
|
|||
None => panic!("-s must be followed by database arg"),
|
||||
Some(str) => Some(str),
|
||||
};
|
||||
},
|
||||
}
|
||||
"n" => {
|
||||
num_pairs = match args.next() {
|
||||
None => panic!("-s must be followed by number of pairs"),
|
||||
Some(str) => str.parse().expect("number"),
|
||||
};
|
||||
},
|
||||
}
|
||||
str => panic!("arg -{} not recognized", str),
|
||||
}
|
||||
} else {
|
||||
|
@ -80,7 +69,9 @@ fn main() {
|
|||
// of the pairs (assuming maximum key and value sizes).
|
||||
builder.set_map_size((511 + 65535) * num_pairs * 2);
|
||||
let rkv = Rkv::from_builder(Path::new(&path), builder).expect("Rkv");
|
||||
let store = rkv.open_single(database.as_deref(), StoreOptions::create()).expect("opened");
|
||||
let store = rkv
|
||||
.open_single(database.as_deref(), StoreOptions::create())
|
||||
.expect("opened");
|
||||
let mut writer = rkv.write().expect("writer");
|
||||
|
||||
// Generate random values for the number of keys and key/value lengths.
|
||||
|
@ -106,7 +97,9 @@ fn main() {
|
|||
let mut value: Vec<u8> = vec![0; value_len];
|
||||
random.read_exact(&mut value[0..value_len]).unwrap();
|
||||
|
||||
store.put(&mut writer, key, &Value::Blob(&value)).expect("wrote");
|
||||
store
|
||||
.put(&mut writer, key, &Value::Blob(&value))
|
||||
.expect("wrote");
|
||||
}
|
||||
|
||||
writer.commit().expect("committed");
|
||||
|
|
|
@ -11,38 +11,19 @@
|
|||
use std::{
|
||||
fs,
|
||||
os::raw::c_uint,
|
||||
path::{
|
||||
Path,
|
||||
PathBuf,
|
||||
},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
#[cfg(any(feature = "db-dup-sort", feature = "db-int-key"))]
|
||||
use crate::backend::{
|
||||
BackendDatabaseFlags,
|
||||
DatabaseFlags,
|
||||
};
|
||||
use crate::backend::{BackendDatabaseFlags, DatabaseFlags};
|
||||
use crate::{
|
||||
backend::{
|
||||
BackendEnvironment,
|
||||
BackendEnvironmentBuilder,
|
||||
BackendRoCursorTransaction,
|
||||
BackendRwCursorTransaction,
|
||||
SafeModeError,
|
||||
},
|
||||
error::{
|
||||
CloseError,
|
||||
StoreError,
|
||||
},
|
||||
readwrite::{
|
||||
Reader,
|
||||
Writer,
|
||||
},
|
||||
store::{
|
||||
single::SingleStore,
|
||||
CloseOptions,
|
||||
Options as StoreOptions,
|
||||
BackendEnvironment, BackendEnvironmentBuilder, BackendRoCursorTransaction,
|
||||
BackendRwCursorTransaction, SafeModeError,
|
||||
},
|
||||
error::{CloseError, StoreError},
|
||||
readwrite::{Reader, Writer},
|
||||
store::{single::SingleStore, CloseOptions, Options as StoreOptions},
|
||||
};
|
||||
|
||||
#[cfg(feature = "db-dup-sort")]
|
||||
|
@ -61,7 +42,7 @@ pub static DEFAULT_MAX_DBS: c_uint = 5;
|
|||
/// Wrapper around an `Environment` (e.g. such as an `LMDB` or `SafeMode` environment).
|
||||
#[derive(Debug)]
|
||||
pub struct Rkv<E> {
|
||||
path: PathBuf,
|
||||
_path: PathBuf,
|
||||
env: E,
|
||||
}
|
||||
|
||||
|
@ -104,7 +85,7 @@ where
|
|||
B: BackendEnvironmentBuilder<'e, Environment = E>,
|
||||
{
|
||||
Ok(Rkv {
|
||||
path: path.into(),
|
||||
_path: path.into(),
|
||||
env: builder.open(path).map_err(|e| e.into())?,
|
||||
})
|
||||
}
|
||||
|
@ -190,20 +171,28 @@ where
|
|||
T: Into<Option<&'s str>>,
|
||||
{
|
||||
if opts.create {
|
||||
self.env.create_db(name.into(), opts.flags).map_err(|e| {
|
||||
match e.into() {
|
||||
StoreError::LmdbError(lmdb::Error::BadRslot) => StoreError::open_during_transaction(),
|
||||
StoreError::SafeModeError(SafeModeError::DbsIllegalOpen) => StoreError::open_during_transaction(),
|
||||
self.env
|
||||
.create_db(name.into(), opts.flags)
|
||||
.map_err(|e| match e.into() {
|
||||
#[cfg(feature = "lmdb")]
|
||||
StoreError::LmdbError(lmdb::Error::BadRslot) => {
|
||||
StoreError::open_during_transaction()
|
||||
}
|
||||
StoreError::SafeModeError(SafeModeError::DbsIllegalOpen) => {
|
||||
StoreError::open_during_transaction()
|
||||
}
|
||||
e => e,
|
||||
}
|
||||
})
|
||||
})
|
||||
} else {
|
||||
self.env.open_db(name.into()).map_err(|e| {
|
||||
match e.into() {
|
||||
StoreError::LmdbError(lmdb::Error::BadRslot) => StoreError::open_during_transaction(),
|
||||
StoreError::SafeModeError(SafeModeError::DbsIllegalOpen) => StoreError::open_during_transaction(),
|
||||
e => e,
|
||||
self.env.open_db(name.into()).map_err(|e| match e.into() {
|
||||
#[cfg(feature = "lmdb")]
|
||||
StoreError::LmdbError(lmdb::Error::BadRslot) => {
|
||||
StoreError::open_during_transaction()
|
||||
}
|
||||
StoreError::SafeModeError(SafeModeError::DbsIllegalOpen) => {
|
||||
StoreError::open_during_transaction()
|
||||
}
|
||||
e => e,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,13 +8,7 @@
|
|||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use std::{
|
||||
io,
|
||||
path::PathBuf,
|
||||
sync,
|
||||
thread,
|
||||
thread::ThreadId,
|
||||
};
|
||||
use std::{io, path::PathBuf, sync, thread, thread::ThreadId};
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
|
@ -27,10 +21,7 @@ pub enum DataError {
|
|||
UnknownType(u8),
|
||||
|
||||
#[error("unexpected type tag: expected {expected}, got {actual}")]
|
||||
UnexpectedType {
|
||||
expected: Type,
|
||||
actual: Type,
|
||||
},
|
||||
UnexpectedType { expected: Type, actual: Type },
|
||||
|
||||
#[error("empty data; expected tag")]
|
||||
Empty,
|
||||
|
@ -83,6 +74,7 @@ pub enum StoreError {
|
|||
#[error("data error: {0:?}")]
|
||||
DataError(#[from] DataError),
|
||||
|
||||
#[cfg(feature = "lmdb")]
|
||||
#[error("lmdb backend error: {0}")]
|
||||
LmdbError(lmdb::Error),
|
||||
|
||||
|
|
|
@ -10,18 +10,12 @@
|
|||
|
||||
use std::{
|
||||
io,
|
||||
path::{
|
||||
Path,
|
||||
PathBuf,
|
||||
},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use url::Url;
|
||||
|
||||
use crate::{
|
||||
error::StoreError,
|
||||
value::Value,
|
||||
};
|
||||
use crate::{error::StoreError, value::Value};
|
||||
|
||||
pub(crate) fn read_transform(value: Result<&[u8], StoreError>) -> Result<Value, StoreError> {
|
||||
match value {
|
||||
|
@ -40,7 +34,9 @@ where
|
|||
|
||||
Ok(if cfg!(target_os = "windows") {
|
||||
let map_err = |_| io::Error::new(io::ErrorKind::Other, "path canonicalization error");
|
||||
Url::from_file_path(&canonical).and_then(|url| url.to_file_path()).map_err(map_err)?
|
||||
Url::from_file_path(&canonical)
|
||||
.and_then(|url| url.to_file_path())
|
||||
.map_err(map_err)?
|
||||
} else {
|
||||
canonical
|
||||
})
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
#![allow(clippy::from_over_into)] // TODO: `Into` implementations in [safe/lmdb]/flags.rs
|
||||
|
||||
//! A simple, humane, typed key-value storage solution. It supports multiple backend
|
||||
//! engines with varying guarantees, such as [LMDB](http://www.lmdb.tech/doc/) for
|
||||
|
@ -45,7 +46,7 @@
|
|||
//! ## Basic Usage
|
||||
//! ```
|
||||
//! use rkv::{Manager, Rkv, SingleStore, Value, StoreOptions};
|
||||
//! use rkv::backend::{Lmdb, LmdbEnvironment};
|
||||
//! use rkv::backend::{SafeMode, SafeModeEnvironment};
|
||||
//! use std::fs;
|
||||
//! use tempfile::Builder;
|
||||
//!
|
||||
|
@ -64,8 +65,8 @@
|
|||
//! // The `Manager` enforces that each process opens the same environment at most once by
|
||||
//! // caching a handle to each environment that it opens. Use it to retrieve the handle
|
||||
//! // to an opened environment—or create one if it hasn't already been opened:
|
||||
//! let mut manager = Manager::<LmdbEnvironment>::singleton().write().unwrap();
|
||||
//! let created_arc = manager.get_or_create(path, Rkv::new::<Lmdb>).unwrap();
|
||||
//! let mut manager = Manager::<SafeModeEnvironment>::singleton().write().unwrap();
|
||||
//! let created_arc = manager.get_or_create(path, Rkv::new::<SafeMode>).unwrap();
|
||||
//! let env = created_arc.read().unwrap();
|
||||
//!
|
||||
//! // Then you can use the environment handle to get a handle to a datastore:
|
||||
|
@ -208,38 +209,20 @@ mod manager;
|
|||
mod readwrite;
|
||||
|
||||
pub mod backend;
|
||||
#[cfg(feature = "lmdb")]
|
||||
pub mod migrator;
|
||||
pub mod store;
|
||||
pub mod value;
|
||||
|
||||
pub use backend::{
|
||||
DatabaseFlags,
|
||||
EnvironmentFlags,
|
||||
WriteFlags,
|
||||
};
|
||||
pub use backend::{DatabaseFlags, EnvironmentFlags, WriteFlags};
|
||||
pub use env::Rkv;
|
||||
pub use error::{
|
||||
DataError,
|
||||
MigrateError,
|
||||
StoreError,
|
||||
};
|
||||
pub use error::{DataError, MigrateError, StoreError};
|
||||
pub use manager::Manager;
|
||||
#[cfg(feature = "lmdb")]
|
||||
pub use migrator::Migrator;
|
||||
pub use readwrite::{
|
||||
Readable,
|
||||
Reader,
|
||||
Writer,
|
||||
};
|
||||
pub use store::{
|
||||
keys::EncodableKey,
|
||||
single::SingleStore,
|
||||
CloseOptions,
|
||||
Options as StoreOptions,
|
||||
};
|
||||
pub use value::{
|
||||
OwnedValue,
|
||||
Value,
|
||||
};
|
||||
pub use readwrite::{Readable, Reader, Writer};
|
||||
pub use store::{keys::EncodableKey, single::SingleStore, CloseOptions, Options as StoreOptions};
|
||||
pub use value::{OwnedValue, Value};
|
||||
|
||||
#[cfg(feature = "db-dup-sort")]
|
||||
pub use store::multi::MultiStore;
|
||||
|
|
|
@ -9,35 +9,20 @@
|
|||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use std::{
|
||||
collections::{
|
||||
btree_map::Entry,
|
||||
BTreeMap,
|
||||
},
|
||||
collections::{btree_map::Entry, BTreeMap},
|
||||
os::raw::c_uint,
|
||||
path::{
|
||||
Path,
|
||||
PathBuf,
|
||||
},
|
||||
path::{Path, PathBuf},
|
||||
result,
|
||||
sync::{
|
||||
Arc,
|
||||
RwLock,
|
||||
},
|
||||
sync::{Arc, RwLock},
|
||||
};
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
#[cfg(feature = "lmdb")]
|
||||
use crate::backend::LmdbEnvironment;
|
||||
use crate::{
|
||||
backend::{
|
||||
BackendEnvironment,
|
||||
BackendEnvironmentBuilder,
|
||||
LmdbEnvironment,
|
||||
SafeModeEnvironment,
|
||||
},
|
||||
error::{
|
||||
CloseError,
|
||||
StoreError,
|
||||
},
|
||||
backend::{BackendEnvironment, BackendEnvironmentBuilder, SafeModeEnvironment},
|
||||
error::{CloseError, StoreError},
|
||||
helpers::canonicalize_path,
|
||||
store::CloseOptions,
|
||||
Rkv,
|
||||
|
@ -47,9 +32,14 @@ type Result<T> = result::Result<T, StoreError>;
|
|||
type CloseResult<T> = result::Result<T, CloseError>;
|
||||
type SharedRkv<E> = Arc<RwLock<Rkv<E>>>;
|
||||
|
||||
#[cfg(feature = "lmdb")]
|
||||
lazy_static! {
|
||||
static ref MANAGER_LMDB: RwLock<Manager<LmdbEnvironment>> = RwLock::new(Manager::new());
|
||||
static ref MANAGER_SAFE_MODE: RwLock<Manager<SafeModeEnvironment>> = RwLock::new(Manager::new());
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref MANAGER_SAFE_MODE: RwLock<Manager<SafeModeEnvironment>> =
|
||||
RwLock::new(Manager::new());
|
||||
}
|
||||
|
||||
/// A process is only permitted to have one open handle to each Rkv environment. This
|
||||
|
@ -106,12 +96,17 @@ where
|
|||
Entry::Vacant(e) => {
|
||||
let k = Arc::new(RwLock::new(f(e.key().as_path())?));
|
||||
e.insert(k).clone()
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Return the open env at `path` with `capacity`, or create it by calling `f`.
|
||||
pub fn get_or_create_with_capacity<'p, F, P>(&mut self, path: P, capacity: c_uint, f: F) -> Result<SharedRkv<E>>
|
||||
pub fn get_or_create_with_capacity<'p, F, P>(
|
||||
&mut self,
|
||||
path: P,
|
||||
capacity: c_uint,
|
||||
f: F,
|
||||
) -> Result<SharedRkv<E>>
|
||||
where
|
||||
F: FnOnce(&Path, c_uint) -> Result<Rkv<E>>,
|
||||
P: Into<&'p Path>,
|
||||
|
@ -126,12 +121,17 @@ where
|
|||
Entry::Vacant(e) => {
|
||||
let k = Arc::new(RwLock::new(f(e.key().as_path(), capacity)?));
|
||||
e.insert(k).clone()
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Return a new Rkv environment from the builder, or create it by calling `f`.
|
||||
pub fn get_or_create_from_builder<'p, F, P, B>(&mut self, path: P, builder: B, f: F) -> Result<SharedRkv<E>>
|
||||
pub fn get_or_create_from_builder<'p, F, P, B>(
|
||||
&mut self,
|
||||
path: P,
|
||||
builder: B,
|
||||
f: F,
|
||||
) -> Result<SharedRkv<E>>
|
||||
where
|
||||
F: FnOnce(&Path, B) -> Result<Rkv<E>>,
|
||||
P: Into<&'p Path>,
|
||||
|
@ -147,7 +147,7 @@ where
|
|||
Entry::Vacant(e) => {
|
||||
let k = Arc::new(RwLock::new(f(e.key().as_path(), builder)?));
|
||||
e.insert(k).clone()
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -164,25 +164,29 @@ where
|
|||
};
|
||||
match self.environments.entry(canonical) {
|
||||
Entry::Vacant(_) => Ok(()),
|
||||
Entry::Occupied(e) if Arc::strong_count(e.get()) > 1 => Err(CloseError::EnvironmentStillOpen),
|
||||
Entry::Occupied(e) if Arc::strong_count(e.get()) > 1 => {
|
||||
Err(CloseError::EnvironmentStillOpen)
|
||||
}
|
||||
Entry::Occupied(e) => {
|
||||
let env = Arc::try_unwrap(e.remove()).map_err(|_| CloseError::UnknownEnvironmentStillOpen)?;
|
||||
let env = Arc::try_unwrap(e.remove())
|
||||
.map_err(|_| CloseError::UnknownEnvironmentStillOpen)?;
|
||||
env.into_inner()?.close(options)?;
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "lmdb")]
|
||||
impl Manager<LmdbEnvironment> {
|
||||
pub fn singleton() -> &'static RwLock<Manager<LmdbEnvironment>> {
|
||||
&*MANAGER_LMDB
|
||||
&MANAGER_LMDB
|
||||
}
|
||||
}
|
||||
|
||||
impl Manager<SafeModeEnvironment> {
|
||||
pub fn singleton() -> &'static RwLock<Manager<SafeModeEnvironment>> {
|
||||
&*MANAGER_SAFE_MODE
|
||||
&MANAGER_SAFE_MODE
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -195,21 +199,31 @@ mod tests {
|
|||
|
||||
use tempfile::Builder;
|
||||
|
||||
#[cfg(feature = "lmdb")]
|
||||
use backend::Lmdb;
|
||||
|
||||
/// Test that one can mutate managed Rkv instances in surprising ways.
|
||||
#[cfg(feature = "lmdb")]
|
||||
#[test]
|
||||
fn test_mutate_managed_rkv() {
|
||||
let mut manager = Manager::<LmdbEnvironment>::new();
|
||||
|
||||
let root1 = Builder::new().prefix("test_mutate_managed_rkv_1").tempdir().expect("tempdir");
|
||||
let root1 = Builder::new()
|
||||
.prefix("test_mutate_managed_rkv_1")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root1.path()).expect("dir created");
|
||||
let path1 = root1.path();
|
||||
let arc = manager.get_or_create(path1, Rkv::new::<Lmdb>).expect("created");
|
||||
let arc = manager
|
||||
.get_or_create(path1, Rkv::new::<Lmdb>)
|
||||
.expect("created");
|
||||
|
||||
// Arc<RwLock<>> has interior mutability, so we can replace arc's Rkv instance with a new
|
||||
// instance that has a different path.
|
||||
let root2 = Builder::new().prefix("test_mutate_managed_rkv_2").tempdir().expect("tempdir");
|
||||
let root2 = Builder::new()
|
||||
.prefix("test_mutate_managed_rkv_2")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root2.path()).expect("dir created");
|
||||
let path2 = root2.path();
|
||||
{
|
||||
|
@ -225,7 +239,9 @@ mod tests {
|
|||
|
||||
// Meanwhile, a new Arc for path2 has a different pointer, even though its Rkv's path is
|
||||
// the same as arc's current path.
|
||||
let path2_arc = manager.get_or_create(path2, Rkv::new::<Lmdb>).expect("success");
|
||||
let path2_arc = manager
|
||||
.get_or_create(path2, Rkv::new::<Lmdb>)
|
||||
.expect("success");
|
||||
assert!(!Arc::ptr_eq(&path2_arc, &arc));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,20 +44,12 @@
|
|||
//! it cannot overwrite nor append data.
|
||||
|
||||
use crate::{
|
||||
backend::{
|
||||
LmdbEnvironment,
|
||||
SafeModeEnvironment,
|
||||
},
|
||||
backend::{LmdbEnvironment, SafeModeEnvironment},
|
||||
error::MigrateError,
|
||||
Rkv,
|
||||
StoreOptions,
|
||||
Rkv, StoreOptions,
|
||||
};
|
||||
|
||||
pub use crate::backend::{
|
||||
LmdbArchMigrateError,
|
||||
LmdbArchMigrateResult,
|
||||
LmdbArchMigrator,
|
||||
};
|
||||
pub use crate::backend::{LmdbArchMigrateError, LmdbArchMigrateResult, LmdbArchMigrator};
|
||||
|
||||
// FIXME: should parametrize this instead.
|
||||
|
||||
|
@ -108,17 +100,15 @@ macro_rules! fn_migrator {
|
|||
F: FnOnce(crate::backend::$builder) -> crate::backend::$builder,
|
||||
D: std::ops::Deref<Target = Rkv<$dst_env>>,
|
||||
{
|
||||
use crate::{
|
||||
backend::*,
|
||||
CloseOptions,
|
||||
};
|
||||
use crate::{backend::*, CloseOptions};
|
||||
|
||||
let mut manager = crate::Manager::<$src_env>::singleton().write()?;
|
||||
let mut builder = Rkv::<$src_env>::environment_builder::<$builder>();
|
||||
builder.set_max_dbs(crate::env::DEFAULT_MAX_DBS);
|
||||
builder = build(builder);
|
||||
|
||||
let src_env = manager.get_or_create_from_builder(path, builder, Rkv::from_builder::<$builder>)?;
|
||||
let src_env =
|
||||
manager.get_or_create_from_builder(path, builder, Rkv::from_builder::<$builder>)?;
|
||||
Migrator::$migrate(src_env.read()?, dst_env)?;
|
||||
|
||||
drop(src_env);
|
||||
|
@ -143,11 +133,15 @@ macro_rules! fn_migrator {
|
|||
match Migrator::$migrate(path, |builder| builder, dst_env) {
|
||||
// Source environment is an invalid file or corrupted database.
|
||||
Err(crate::MigrateError::StoreError(crate::StoreError::FileInvalid)) => Ok(()),
|
||||
Err(crate::MigrateError::StoreError(crate::StoreError::DatabaseCorrupted)) => Ok(()),
|
||||
Err(crate::MigrateError::StoreError(crate::StoreError::DatabaseCorrupted)) => {
|
||||
Ok(())
|
||||
}
|
||||
// Path not accessible.
|
||||
Err(crate::MigrateError::StoreError(crate::StoreError::IoError(_))) => Ok(()),
|
||||
// Path accessible but incompatible for configuration.
|
||||
Err(crate::MigrateError::StoreError(crate::StoreError::UnsuitableEnvironmentPath(_))) => Ok(()),
|
||||
Err(crate::MigrateError::StoreError(
|
||||
crate::StoreError::UnsuitableEnvironmentPath(_),
|
||||
)) => Ok(()),
|
||||
// Couldn't close source environment and delete files on disk (e.g. other stores still open).
|
||||
Err(crate::MigrateError::CloseError(_)) => Ok(()),
|
||||
// Nothing to migrate.
|
||||
|
|
|
@ -10,12 +10,8 @@
|
|||
|
||||
use crate::{
|
||||
backend::{
|
||||
BackendDatabase,
|
||||
BackendRoCursor,
|
||||
BackendRoCursorTransaction,
|
||||
BackendRoTransaction,
|
||||
BackendRwCursorTransaction,
|
||||
BackendRwTransaction,
|
||||
BackendDatabase, BackendRoCursor, BackendRoCursorTransaction, BackendRoTransaction,
|
||||
BackendRwCursorTransaction, BackendRwTransaction,
|
||||
},
|
||||
error::StoreError,
|
||||
helpers::read_transform,
|
||||
|
@ -115,12 +111,20 @@ where
|
|||
self.0.abort();
|
||||
}
|
||||
|
||||
pub(crate) fn put<K>(&mut self, db: &T::Database, k: &K, v: &Value, flags: T::Flags) -> Result<(), StoreError>
|
||||
pub(crate) fn put<K>(
|
||||
&mut self,
|
||||
db: &T::Database,
|
||||
k: &K,
|
||||
v: &Value,
|
||||
flags: T::Flags,
|
||||
) -> Result<(), StoreError>
|
||||
where
|
||||
K: AsRef<[u8]>,
|
||||
{
|
||||
// TODO: don't allocate twice.
|
||||
self.0.put(db, k.as_ref(), &v.to_bytes()?, flags).map_err(|e| e.into())
|
||||
self.0
|
||||
.put(db, k.as_ref(), &v.to_bytes()?, flags)
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "db-dup-sort"))]
|
||||
|
@ -132,7 +136,12 @@ where
|
|||
}
|
||||
|
||||
#[cfg(feature = "db-dup-sort")]
|
||||
pub(crate) fn delete<K>(&mut self, db: &T::Database, k: &K, v: Option<&[u8]>) -> Result<(), StoreError>
|
||||
pub(crate) fn delete<K>(
|
||||
&mut self,
|
||||
db: &T::Database,
|
||||
k: &K,
|
||||
v: Option<&[u8]>,
|
||||
) -> Result<(), StoreError>
|
||||
where
|
||||
K: AsRef<[u8]>,
|
||||
{
|
||||
|
|
|
@ -47,8 +47,6 @@ pub struct CloseOptions {
|
|||
|
||||
impl CloseOptions {
|
||||
pub fn delete_files_on_disk() -> CloseOptions {
|
||||
CloseOptions {
|
||||
delete: true,
|
||||
}
|
||||
CloseOptions { delete: true }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,20 +11,11 @@
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use crate::{
|
||||
backend::{
|
||||
BackendDatabase,
|
||||
BackendRwTransaction,
|
||||
},
|
||||
backend::{BackendDatabase, BackendRwTransaction},
|
||||
error::StoreError,
|
||||
readwrite::{
|
||||
Readable,
|
||||
Writer,
|
||||
},
|
||||
readwrite::{Readable, Writer},
|
||||
store::{
|
||||
keys::{
|
||||
Key,
|
||||
PrimitiveInt,
|
||||
},
|
||||
keys::{Key, PrimitiveInt},
|
||||
single::SingleStore,
|
||||
},
|
||||
value::Value,
|
||||
|
@ -90,22 +81,32 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_integer_keys() {
|
||||
let root = Builder::new().prefix("test_integer_keys").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_integer_keys")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let k = Rkv::new::<backend::Lmdb>(root.path()).expect("new succeeded");
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
let s = k.open_integer("s", StoreOptions::create()).expect("open");
|
||||
|
||||
macro_rules! test_integer_keys {
|
||||
($type:ty, $key:expr) => {{
|
||||
let mut writer = k.write().expect("writer");
|
||||
|
||||
s.put(&mut writer, $key, &Value::Str("hello!")).expect("write");
|
||||
assert_eq!(s.get(&writer, $key).expect("read"), Some(Value::Str("hello!")));
|
||||
s.put(&mut writer, $key, &Value::Str("hello!"))
|
||||
.expect("write");
|
||||
assert_eq!(
|
||||
s.get(&writer, $key).expect("read"),
|
||||
Some(Value::Str("hello!"))
|
||||
);
|
||||
writer.commit().expect("committed");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
assert_eq!(s.get(&reader, $key).expect("read"), Some(Value::Str("hello!")));
|
||||
assert_eq!(
|
||||
s.get(&reader, $key).expect("read"),
|
||||
Some(Value::Str("hello!"))
|
||||
);
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -115,10 +116,13 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_clear() {
|
||||
let root = Builder::new().prefix("test_integer_clear").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_integer_clear")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let k = Rkv::new::<backend::Lmdb>(root.path()).expect("new succeeded");
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
let s = k.open_integer("s", StoreOptions::create()).expect("open");
|
||||
|
||||
{
|
||||
|
@ -146,10 +150,13 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_dup() {
|
||||
let root = Builder::new().prefix("test_integer_dup").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_integer_dup")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let k = Rkv::new::<backend::Lmdb>(root.path()).expect("new succeeded");
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
let s = k.open_integer("s", StoreOptions::create()).expect("open");
|
||||
|
||||
{
|
||||
|
@ -177,10 +184,13 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_del() {
|
||||
let root = Builder::new().prefix("test_integer_del").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_integer_del")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let k = Rkv::new::<backend::Lmdb>(root.path()).expect("new succeeded");
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
let s = k.open_integer("s", StoreOptions::create()).expect("open");
|
||||
|
||||
{
|
||||
|
@ -224,11 +234,14 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_persist() {
|
||||
let root = Builder::new().prefix("test_integer_persist").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_integer_persist")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
{
|
||||
let k = Rkv::new::<backend::Lmdb>(root.path()).expect("new succeeded");
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
let s = k.open_integer("s", StoreOptions::create()).expect("open");
|
||||
|
||||
let mut writer = k.write().expect("writer");
|
||||
|
@ -242,7 +255,7 @@ mod tests {
|
|||
}
|
||||
|
||||
{
|
||||
let k = Rkv::new::<backend::Lmdb>(root.path()).expect("new succeeded");
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
let s = k.open_integer("s", StoreOptions::create()).expect("open");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
|
@ -254,10 +267,13 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_intertwine_read_write() {
|
||||
let root = Builder::new().prefix("test_integer_intertwine_read_write").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_integer_intertwine_read_write")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let k = Rkv::new::<backend::Lmdb>(root.path()).expect("new succeeded");
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
let s = k.open_integer("s", StoreOptions::create()).expect("open");
|
||||
|
||||
{
|
||||
|
@ -279,12 +295,24 @@ mod tests {
|
|||
}
|
||||
|
||||
{
|
||||
s.put(&mut writer, 1, &Value::Str("goodbye!")).expect("write");
|
||||
s.put(&mut writer, 2, &Value::Str("goodbye!")).expect("write");
|
||||
s.put(&mut writer, 3, &Value::Str("goodbye!")).expect("write");
|
||||
assert_eq!(s.get(&writer, 1).expect("read"), Some(Value::Str("goodbye!")));
|
||||
assert_eq!(s.get(&writer, 2).expect("read"), Some(Value::Str("goodbye!")));
|
||||
assert_eq!(s.get(&writer, 3).expect("read"), Some(Value::Str("goodbye!")));
|
||||
s.put(&mut writer, 1, &Value::Str("goodbye!"))
|
||||
.expect("write");
|
||||
s.put(&mut writer, 2, &Value::Str("goodbye!"))
|
||||
.expect("write");
|
||||
s.put(&mut writer, 3, &Value::Str("goodbye!"))
|
||||
.expect("write");
|
||||
assert_eq!(
|
||||
s.get(&writer, 1).expect("read"),
|
||||
Some(Value::Str("goodbye!"))
|
||||
);
|
||||
assert_eq!(
|
||||
s.get(&writer, 2).expect("read"),
|
||||
Some(Value::Str("goodbye!"))
|
||||
);
|
||||
assert_eq!(
|
||||
s.get(&writer, 3).expect("read"),
|
||||
Some(Value::Str("goodbye!"))
|
||||
);
|
||||
writer.commit().expect("committed");
|
||||
}
|
||||
|
||||
|
@ -298,16 +326,28 @@ mod tests {
|
|||
let mut writer = k.write().expect("writer");
|
||||
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
|
||||
assert_eq!(s.get(&writer, 1).expect("read"), Some(Value::Str("hello!")));
|
||||
assert_eq!(s.get(&writer, 2).expect("read"), Some(Value::Str("goodbye!")));
|
||||
assert_eq!(s.get(&writer, 3).expect("read"), Some(Value::Str("goodbye!")));
|
||||
assert_eq!(
|
||||
s.get(&writer, 2).expect("read"),
|
||||
Some(Value::Str("goodbye!"))
|
||||
);
|
||||
assert_eq!(
|
||||
s.get(&writer, 3).expect("read"),
|
||||
Some(Value::Str("goodbye!"))
|
||||
);
|
||||
writer.commit().expect("committed");
|
||||
}
|
||||
|
||||
{
|
||||
let reader = k.write().expect("reader");
|
||||
assert_eq!(s.get(&reader, 1).expect("read"), Some(Value::Str("hello!")));
|
||||
assert_eq!(s.get(&reader, 2).expect("read"), Some(Value::Str("goodbye!")));
|
||||
assert_eq!(s.get(&reader, 3).expect("read"), Some(Value::Str("goodbye!")));
|
||||
assert_eq!(
|
||||
s.get(&reader, 2).expect("read"),
|
||||
Some(Value::Str("goodbye!"))
|
||||
);
|
||||
assert_eq!(
|
||||
s.get(&reader, 3).expect("read"),
|
||||
Some(Value::Str("goodbye!"))
|
||||
);
|
||||
reader.commit().expect("committed");
|
||||
}
|
||||
}
|
||||
|
@ -324,7 +364,10 @@ mod tests_safe {
|
|||
|
||||
#[test]
|
||||
fn test_integer_keys() {
|
||||
let root = Builder::new().prefix("test_integer_keys").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_integer_keys")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
|
@ -334,12 +377,19 @@ mod tests_safe {
|
|||
($type:ty, $key:expr) => {{
|
||||
let mut writer = k.write().expect("writer");
|
||||
|
||||
s.put(&mut writer, $key, &Value::Str("hello!")).expect("write");
|
||||
assert_eq!(s.get(&writer, $key).expect("read"), Some(Value::Str("hello!")));
|
||||
s.put(&mut writer, $key, &Value::Str("hello!"))
|
||||
.expect("write");
|
||||
assert_eq!(
|
||||
s.get(&writer, $key).expect("read"),
|
||||
Some(Value::Str("hello!"))
|
||||
);
|
||||
writer.commit().expect("committed");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
assert_eq!(s.get(&reader, $key).expect("read"), Some(Value::Str("hello!")));
|
||||
assert_eq!(
|
||||
s.get(&reader, $key).expect("read"),
|
||||
Some(Value::Str("hello!"))
|
||||
);
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -349,7 +399,10 @@ mod tests_safe {
|
|||
|
||||
#[test]
|
||||
fn test_clear() {
|
||||
let root = Builder::new().prefix("test_integer_clear").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_integer_clear")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
|
@ -380,7 +433,10 @@ mod tests_safe {
|
|||
|
||||
#[test]
|
||||
fn test_dup() {
|
||||
let root = Builder::new().prefix("test_integer_dup").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_integer_dup")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
|
@ -411,7 +467,10 @@ mod tests_safe {
|
|||
|
||||
#[test]
|
||||
fn test_del() {
|
||||
let root = Builder::new().prefix("test_integer_del").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_integer_del")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
|
@ -458,7 +517,10 @@ mod tests_safe {
|
|||
|
||||
#[test]
|
||||
fn test_persist() {
|
||||
let root = Builder::new().prefix("test_integer_persist").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_integer_persist")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
{
|
||||
|
@ -488,7 +550,10 @@ mod tests_safe {
|
|||
|
||||
#[test]
|
||||
fn test_intertwine_read_write() {
|
||||
let root = Builder::new().prefix("test_integer_intertwine_read_write").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_integer_intertwine_read_write")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
|
@ -513,12 +578,24 @@ mod tests_safe {
|
|||
}
|
||||
|
||||
{
|
||||
s.put(&mut writer, 1, &Value::Str("goodbye!")).expect("write");
|
||||
s.put(&mut writer, 2, &Value::Str("goodbye!")).expect("write");
|
||||
s.put(&mut writer, 3, &Value::Str("goodbye!")).expect("write");
|
||||
assert_eq!(s.get(&writer, 1).expect("read"), Some(Value::Str("goodbye!")));
|
||||
assert_eq!(s.get(&writer, 2).expect("read"), Some(Value::Str("goodbye!")));
|
||||
assert_eq!(s.get(&writer, 3).expect("read"), Some(Value::Str("goodbye!")));
|
||||
s.put(&mut writer, 1, &Value::Str("goodbye!"))
|
||||
.expect("write");
|
||||
s.put(&mut writer, 2, &Value::Str("goodbye!"))
|
||||
.expect("write");
|
||||
s.put(&mut writer, 3, &Value::Str("goodbye!"))
|
||||
.expect("write");
|
||||
assert_eq!(
|
||||
s.get(&writer, 1).expect("read"),
|
||||
Some(Value::Str("goodbye!"))
|
||||
);
|
||||
assert_eq!(
|
||||
s.get(&writer, 2).expect("read"),
|
||||
Some(Value::Str("goodbye!"))
|
||||
);
|
||||
assert_eq!(
|
||||
s.get(&writer, 3).expect("read"),
|
||||
Some(Value::Str("goodbye!"))
|
||||
);
|
||||
writer.commit().expect("committed");
|
||||
}
|
||||
|
||||
|
@ -532,16 +609,28 @@ mod tests_safe {
|
|||
let mut writer = k.write().expect("writer");
|
||||
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
|
||||
assert_eq!(s.get(&writer, 1).expect("read"), Some(Value::Str("hello!")));
|
||||
assert_eq!(s.get(&writer, 2).expect("read"), Some(Value::Str("goodbye!")));
|
||||
assert_eq!(s.get(&writer, 3).expect("read"), Some(Value::Str("goodbye!")));
|
||||
assert_eq!(
|
||||
s.get(&writer, 2).expect("read"),
|
||||
Some(Value::Str("goodbye!"))
|
||||
);
|
||||
assert_eq!(
|
||||
s.get(&writer, 3).expect("read"),
|
||||
Some(Value::Str("goodbye!"))
|
||||
);
|
||||
writer.commit().expect("committed");
|
||||
}
|
||||
|
||||
{
|
||||
let reader = k.write().expect("reader");
|
||||
assert_eq!(s.get(&reader, 1).expect("read"), Some(Value::Str("hello!")));
|
||||
assert_eq!(s.get(&reader, 2).expect("read"), Some(Value::Str("goodbye!")));
|
||||
assert_eq!(s.get(&reader, 3).expect("read"), Some(Value::Str("goodbye!")));
|
||||
assert_eq!(
|
||||
s.get(&reader, 2).expect("read"),
|
||||
Some(Value::Str("goodbye!"))
|
||||
);
|
||||
assert_eq!(
|
||||
s.get(&reader, 3).expect("read"),
|
||||
Some(Value::Str("goodbye!"))
|
||||
);
|
||||
reader.commit().expect("committed");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,26 +11,12 @@
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use crate::{
|
||||
backend::{
|
||||
BackendDatabase,
|
||||
BackendIter,
|
||||
BackendRoCursor,
|
||||
BackendRwTransaction,
|
||||
},
|
||||
backend::{BackendDatabase, BackendIter, BackendRoCursor, BackendRwTransaction},
|
||||
error::StoreError,
|
||||
readwrite::{
|
||||
Readable,
|
||||
Writer,
|
||||
},
|
||||
readwrite::{Readable, Writer},
|
||||
store::{
|
||||
keys::{
|
||||
Key,
|
||||
PrimitiveInt,
|
||||
},
|
||||
multi::{
|
||||
Iter,
|
||||
MultiStore,
|
||||
},
|
||||
keys::{Key, PrimitiveInt},
|
||||
multi::{Iter, MultiStore},
|
||||
},
|
||||
value::Value,
|
||||
};
|
||||
|
@ -79,7 +65,13 @@ where
|
|||
self.inner.put(writer, Key::new(&k)?, v)
|
||||
}
|
||||
|
||||
pub fn put_with_flags<T>(&self, writer: &mut Writer<T>, k: K, v: &Value, flags: T::Flags) -> EmptyResult
|
||||
pub fn put_with_flags<T>(
|
||||
&self,
|
||||
writer: &mut Writer<T>,
|
||||
k: K,
|
||||
v: &Value,
|
||||
flags: T::Flags,
|
||||
) -> EmptyResult
|
||||
where
|
||||
T: BackendRwTransaction<Database = D>,
|
||||
{
|
||||
|
@ -119,22 +111,34 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_integer_keys() {
|
||||
let root = Builder::new().prefix("test_integer_keys").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_integer_keys")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let k = Rkv::new::<backend::Lmdb>(root.path()).expect("new succeeded");
|
||||
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
let s = k
|
||||
.open_multi_integer("s", StoreOptions::create())
|
||||
.expect("open");
|
||||
|
||||
macro_rules! test_integer_keys {
|
||||
($type:ty, $key:expr) => {{
|
||||
let mut writer = k.write().expect("writer");
|
||||
|
||||
s.put(&mut writer, $key, &Value::Str("hello!")).expect("write");
|
||||
assert_eq!(s.get_first(&writer, $key).expect("read"), Some(Value::Str("hello!")));
|
||||
s.put(&mut writer, $key, &Value::Str("hello!"))
|
||||
.expect("write");
|
||||
assert_eq!(
|
||||
s.get_first(&writer, $key).expect("read"),
|
||||
Some(Value::Str("hello!"))
|
||||
);
|
||||
writer.commit().expect("committed");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
assert_eq!(s.get_first(&reader, $key).expect("read"), Some(Value::Str("hello!")));
|
||||
assert_eq!(
|
||||
s.get_first(&reader, $key).expect("read"),
|
||||
Some(Value::Str("hello!"))
|
||||
);
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -144,19 +148,31 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_clear() {
|
||||
let root = Builder::new().prefix("test_multi_integer_clear").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_multi_integer_clear")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let k = Rkv::new::<backend::Lmdb>(root.path()).expect("new succeeded");
|
||||
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
let s = k
|
||||
.open_multi_integer("s", StoreOptions::create())
|
||||
.expect("open");
|
||||
|
||||
{
|
||||
let mut writer = k.write().expect("writer");
|
||||
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
|
||||
s.put(&mut writer, 1, &Value::Str("hello1!")).expect("write");
|
||||
s.put(&mut writer, 1, &Value::Str("hello1!"))
|
||||
.expect("write");
|
||||
s.put(&mut writer, 2, &Value::Str("hello!")).expect("write");
|
||||
assert_eq!(s.get_first(&writer, 1).expect("read"), Some(Value::Str("hello!")));
|
||||
assert_eq!(s.get_first(&writer, 2).expect("read"), Some(Value::Str("hello!")));
|
||||
assert_eq!(
|
||||
s.get_first(&writer, 1).expect("read"),
|
||||
Some(Value::Str("hello!"))
|
||||
);
|
||||
assert_eq!(
|
||||
s.get_first(&writer, 2).expect("read"),
|
||||
Some(Value::Str("hello!"))
|
||||
);
|
||||
assert_eq!(s.get_first(&writer, 3).expect("read"), None);
|
||||
writer.commit().expect("committed");
|
||||
}
|
||||
|
@ -175,18 +191,27 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_dup() {
|
||||
let root = Builder::new().prefix("test_multi_integer_dup").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_multi_integer_dup")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let k = Rkv::new::<backend::Lmdb>(root.path()).expect("new succeeded");
|
||||
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
let s = k
|
||||
.open_multi_integer("s", StoreOptions::create())
|
||||
.expect("open");
|
||||
|
||||
{
|
||||
let mut writer = k.write().expect("writer");
|
||||
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
|
||||
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
|
||||
s.put(&mut writer, 1, &Value::Str("hello1!")).expect("write");
|
||||
assert_eq!(s.get_first(&writer, 1).expect("read"), Some(Value::Str("hello!")));
|
||||
s.put(&mut writer, 1, &Value::Str("hello1!"))
|
||||
.expect("write");
|
||||
assert_eq!(
|
||||
s.get_first(&writer, 1).expect("read"),
|
||||
Some(Value::Str("hello!"))
|
||||
);
|
||||
assert_eq!(s.get_first(&writer, 2).expect("read"), None);
|
||||
assert_eq!(s.get_first(&writer, 3).expect("read"), None);
|
||||
writer.commit().expect("committed");
|
||||
|
@ -206,42 +231,66 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_dup_2() {
|
||||
let root = Builder::new().prefix("test_multi_integer_dup").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_multi_integer_dup")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let k = Rkv::new::<backend::Lmdb>(root.path()).expect("new succeeded");
|
||||
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
let s = k
|
||||
.open_multi_integer("s", StoreOptions::create())
|
||||
.expect("open");
|
||||
|
||||
{
|
||||
let mut writer = k.write().expect("writer");
|
||||
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
|
||||
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
|
||||
s.put(&mut writer, 1, &Value::Str("hello1!")).expect("write");
|
||||
s.put(&mut writer, 1, &Value::Str("hello1!"))
|
||||
.expect("write");
|
||||
|
||||
let mut iter = s.get(&writer, 1).expect("read");
|
||||
assert_eq!(iter.next().expect("first").expect("ok").1, Value::Str("hello!"));
|
||||
assert_eq!(iter.next().expect("second").expect("ok").1, Value::Str("hello1!"));
|
||||
assert_eq!(
|
||||
iter.next().expect("first").expect("ok").1,
|
||||
Value::Str("hello!")
|
||||
);
|
||||
assert_eq!(
|
||||
iter.next().expect("second").expect("ok").1,
|
||||
Value::Str("hello1!")
|
||||
);
|
||||
assert!(iter.next().is_none());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_del() {
|
||||
let root = Builder::new().prefix("test_multi_integer_dup").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_multi_integer_dup")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let k = Rkv::new::<backend::Lmdb>(root.path()).expect("new succeeded");
|
||||
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
let s = k
|
||||
.open_multi_integer("s", StoreOptions::create())
|
||||
.expect("open");
|
||||
|
||||
{
|
||||
let mut writer = k.write().expect("writer");
|
||||
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
|
||||
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
|
||||
s.put(&mut writer, 1, &Value::Str("hello1!")).expect("write");
|
||||
s.put(&mut writer, 1, &Value::Str("hello1!"))
|
||||
.expect("write");
|
||||
{
|
||||
let mut iter = s.get(&writer, 1).expect("read");
|
||||
assert_eq!(iter.next().expect("first").expect("ok").1, Value::Str("hello!"));
|
||||
assert_eq!(iter.next().expect("second").expect("ok").1, Value::Str("hello1!"));
|
||||
assert_eq!(
|
||||
iter.next().expect("first").expect("ok").1,
|
||||
Value::Str("hello!")
|
||||
);
|
||||
assert_eq!(
|
||||
iter.next().expect("second").expect("ok").1,
|
||||
Value::Str("hello1!")
|
||||
);
|
||||
assert!(iter.next().is_none());
|
||||
}
|
||||
writer.commit().expect("committed");
|
||||
|
@ -249,29 +298,38 @@ mod tests {
|
|||
|
||||
{
|
||||
let mut writer = k.write().expect("writer");
|
||||
s.delete(&mut writer, 1, &Value::Str("hello!")).expect("deleted");
|
||||
s.delete(&mut writer, 1, &Value::Str("hello!"))
|
||||
.expect("deleted");
|
||||
writer.commit().expect("committed");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
let mut iter = s.get(&reader, 1).expect("read");
|
||||
assert_eq!(iter.next().expect("first").expect("ok").1, Value::Str("hello1!"));
|
||||
assert_eq!(
|
||||
iter.next().expect("first").expect("ok").1,
|
||||
Value::Str("hello1!")
|
||||
);
|
||||
assert!(iter.next().is_none());
|
||||
}
|
||||
|
||||
{
|
||||
let mut writer = k.write().expect("writer");
|
||||
s.delete(&mut writer, 1, &Value::Str("hello!")).expect_err("deleted");
|
||||
s.delete(&mut writer, 1, &Value::Str("hello!"))
|
||||
.expect_err("deleted");
|
||||
writer.commit().expect("committed");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
let mut iter = s.get(&reader, 1).expect("read");
|
||||
assert_eq!(iter.next().expect("first").expect("ok").1, Value::Str("hello1!"));
|
||||
assert_eq!(
|
||||
iter.next().expect("first").expect("ok").1,
|
||||
Value::Str("hello1!")
|
||||
);
|
||||
assert!(iter.next().is_none());
|
||||
}
|
||||
|
||||
{
|
||||
let mut writer = k.write().expect("writer");
|
||||
s.delete(&mut writer, 1, &Value::Str("hello1!")).expect("deleted");
|
||||
s.delete(&mut writer, 1, &Value::Str("hello1!"))
|
||||
.expect("deleted");
|
||||
writer.commit().expect("committed");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
|
@ -281,7 +339,8 @@ mod tests {
|
|||
|
||||
{
|
||||
let mut writer = k.write().expect("writer");
|
||||
s.delete(&mut writer, 1, &Value::Str("hello1!")).expect_err("deleted");
|
||||
s.delete(&mut writer, 1, &Value::Str("hello1!"))
|
||||
.expect_err("deleted");
|
||||
writer.commit().expect("committed");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
|
@ -292,34 +351,54 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_persist() {
|
||||
let root = Builder::new().prefix("test_multi_integer_persist").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_multi_integer_persist")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
{
|
||||
let k = Rkv::new::<backend::Lmdb>(root.path()).expect("new succeeded");
|
||||
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
let s = k
|
||||
.open_multi_integer("s", StoreOptions::create())
|
||||
.expect("open");
|
||||
|
||||
let mut writer = k.write().expect("writer");
|
||||
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
|
||||
s.put(&mut writer, 1, &Value::Str("hello1!")).expect("write");
|
||||
s.put(&mut writer, 1, &Value::Str("hello1!"))
|
||||
.expect("write");
|
||||
s.put(&mut writer, 2, &Value::Str("hello!")).expect("write");
|
||||
{
|
||||
let mut iter = s.get(&writer, 1).expect("read");
|
||||
assert_eq!(iter.next().expect("first").expect("ok").1, Value::Str("hello!"));
|
||||
assert_eq!(iter.next().expect("second").expect("ok").1, Value::Str("hello1!"));
|
||||
assert_eq!(
|
||||
iter.next().expect("first").expect("ok").1,
|
||||
Value::Str("hello!")
|
||||
);
|
||||
assert_eq!(
|
||||
iter.next().expect("second").expect("ok").1,
|
||||
Value::Str("hello1!")
|
||||
);
|
||||
assert!(iter.next().is_none());
|
||||
}
|
||||
writer.commit().expect("committed");
|
||||
}
|
||||
|
||||
{
|
||||
let k = Rkv::new::<backend::Lmdb>(root.path()).expect("new succeeded");
|
||||
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
let s = k
|
||||
.open_multi_integer("s", StoreOptions::create())
|
||||
.expect("open");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
let mut iter = s.get(&reader, 1).expect("read");
|
||||
assert_eq!(iter.next().expect("first").expect("ok").1, Value::Str("hello!"));
|
||||
assert_eq!(iter.next().expect("second").expect("ok").1, Value::Str("hello1!"));
|
||||
assert_eq!(
|
||||
iter.next().expect("first").expect("ok").1,
|
||||
Value::Str("hello!")
|
||||
);
|
||||
assert_eq!(
|
||||
iter.next().expect("second").expect("ok").1,
|
||||
Value::Str("hello1!")
|
||||
);
|
||||
assert!(iter.next().is_none());
|
||||
}
|
||||
}
|
||||
|
@ -336,22 +415,34 @@ mod tests_safe {
|
|||
|
||||
#[test]
|
||||
fn test_integer_keys() {
|
||||
let root = Builder::new().prefix("test_integer_keys").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_integer_keys")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
|
||||
let s = k
|
||||
.open_multi_integer("s", StoreOptions::create())
|
||||
.expect("open");
|
||||
|
||||
macro_rules! test_integer_keys {
|
||||
($type:ty, $key:expr) => {{
|
||||
let mut writer = k.write().expect("writer");
|
||||
|
||||
s.put(&mut writer, $key, &Value::Str("hello!")).expect("write");
|
||||
assert_eq!(s.get_first(&writer, $key).expect("read"), Some(Value::Str("hello!")));
|
||||
s.put(&mut writer, $key, &Value::Str("hello!"))
|
||||
.expect("write");
|
||||
assert_eq!(
|
||||
s.get_first(&writer, $key).expect("read"),
|
||||
Some(Value::Str("hello!"))
|
||||
);
|
||||
writer.commit().expect("committed");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
assert_eq!(s.get_first(&reader, $key).expect("read"), Some(Value::Str("hello!")));
|
||||
assert_eq!(
|
||||
s.get_first(&reader, $key).expect("read"),
|
||||
Some(Value::Str("hello!"))
|
||||
);
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -361,19 +452,31 @@ mod tests_safe {
|
|||
|
||||
#[test]
|
||||
fn test_clear() {
|
||||
let root = Builder::new().prefix("test_multi_integer_clear").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_multi_integer_clear")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
|
||||
let s = k
|
||||
.open_multi_integer("s", StoreOptions::create())
|
||||
.expect("open");
|
||||
|
||||
{
|
||||
let mut writer = k.write().expect("writer");
|
||||
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
|
||||
s.put(&mut writer, 1, &Value::Str("hello1!")).expect("write");
|
||||
s.put(&mut writer, 1, &Value::Str("hello1!"))
|
||||
.expect("write");
|
||||
s.put(&mut writer, 2, &Value::Str("hello!")).expect("write");
|
||||
assert_eq!(s.get_first(&writer, 1).expect("read"), Some(Value::Str("hello!")));
|
||||
assert_eq!(s.get_first(&writer, 2).expect("read"), Some(Value::Str("hello!")));
|
||||
assert_eq!(
|
||||
s.get_first(&writer, 1).expect("read"),
|
||||
Some(Value::Str("hello!"))
|
||||
);
|
||||
assert_eq!(
|
||||
s.get_first(&writer, 2).expect("read"),
|
||||
Some(Value::Str("hello!"))
|
||||
);
|
||||
assert_eq!(s.get_first(&writer, 3).expect("read"), None);
|
||||
writer.commit().expect("committed");
|
||||
}
|
||||
|
@ -392,18 +495,27 @@ mod tests_safe {
|
|||
|
||||
#[test]
|
||||
fn test_dup() {
|
||||
let root = Builder::new().prefix("test_multi_integer_dup").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_multi_integer_dup")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
|
||||
let s = k
|
||||
.open_multi_integer("s", StoreOptions::create())
|
||||
.expect("open");
|
||||
|
||||
{
|
||||
let mut writer = k.write().expect("writer");
|
||||
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
|
||||
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
|
||||
s.put(&mut writer, 1, &Value::Str("hello1!")).expect("write");
|
||||
assert_eq!(s.get_first(&writer, 1).expect("read"), Some(Value::Str("hello!")));
|
||||
s.put(&mut writer, 1, &Value::Str("hello1!"))
|
||||
.expect("write");
|
||||
assert_eq!(
|
||||
s.get_first(&writer, 1).expect("read"),
|
||||
Some(Value::Str("hello!"))
|
||||
);
|
||||
assert_eq!(s.get_first(&writer, 2).expect("read"), None);
|
||||
assert_eq!(s.get_first(&writer, 3).expect("read"), None);
|
||||
writer.commit().expect("committed");
|
||||
|
@ -423,42 +535,66 @@ mod tests_safe {
|
|||
|
||||
#[test]
|
||||
fn test_dup_2() {
|
||||
let root = Builder::new().prefix("test_multi_integer_dup").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_multi_integer_dup")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
|
||||
let s = k
|
||||
.open_multi_integer("s", StoreOptions::create())
|
||||
.expect("open");
|
||||
|
||||
{
|
||||
let mut writer = k.write().expect("writer");
|
||||
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
|
||||
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
|
||||
s.put(&mut writer, 1, &Value::Str("hello1!")).expect("write");
|
||||
s.put(&mut writer, 1, &Value::Str("hello1!"))
|
||||
.expect("write");
|
||||
|
||||
let mut iter = s.get(&writer, 1).expect("read");
|
||||
assert_eq!(iter.next().expect("first").expect("ok").1, Value::Str("hello!"));
|
||||
assert_eq!(iter.next().expect("second").expect("ok").1, Value::Str("hello1!"));
|
||||
assert_eq!(
|
||||
iter.next().expect("first").expect("ok").1,
|
||||
Value::Str("hello!")
|
||||
);
|
||||
assert_eq!(
|
||||
iter.next().expect("second").expect("ok").1,
|
||||
Value::Str("hello1!")
|
||||
);
|
||||
assert!(iter.next().is_none());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_del() {
|
||||
let root = Builder::new().prefix("test_multi_integer_dup").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_multi_integer_dup")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
|
||||
let s = k
|
||||
.open_multi_integer("s", StoreOptions::create())
|
||||
.expect("open");
|
||||
|
||||
{
|
||||
let mut writer = k.write().expect("writer");
|
||||
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
|
||||
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
|
||||
s.put(&mut writer, 1, &Value::Str("hello1!")).expect("write");
|
||||
s.put(&mut writer, 1, &Value::Str("hello1!"))
|
||||
.expect("write");
|
||||
{
|
||||
let mut iter = s.get(&writer, 1).expect("read");
|
||||
assert_eq!(iter.next().expect("first").expect("ok").1, Value::Str("hello!"));
|
||||
assert_eq!(iter.next().expect("second").expect("ok").1, Value::Str("hello1!"));
|
||||
assert_eq!(
|
||||
iter.next().expect("first").expect("ok").1,
|
||||
Value::Str("hello!")
|
||||
);
|
||||
assert_eq!(
|
||||
iter.next().expect("second").expect("ok").1,
|
||||
Value::Str("hello1!")
|
||||
);
|
||||
assert!(iter.next().is_none());
|
||||
}
|
||||
writer.commit().expect("committed");
|
||||
|
@ -466,29 +602,38 @@ mod tests_safe {
|
|||
|
||||
{
|
||||
let mut writer = k.write().expect("writer");
|
||||
s.delete(&mut writer, 1, &Value::Str("hello!")).expect("deleted");
|
||||
s.delete(&mut writer, 1, &Value::Str("hello!"))
|
||||
.expect("deleted");
|
||||
writer.commit().expect("committed");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
let mut iter = s.get(&reader, 1).expect("read");
|
||||
assert_eq!(iter.next().expect("first").expect("ok").1, Value::Str("hello1!"));
|
||||
assert_eq!(
|
||||
iter.next().expect("first").expect("ok").1,
|
||||
Value::Str("hello1!")
|
||||
);
|
||||
assert!(iter.next().is_none());
|
||||
}
|
||||
|
||||
{
|
||||
let mut writer = k.write().expect("writer");
|
||||
s.delete(&mut writer, 1, &Value::Str("hello!")).expect_err("deleted");
|
||||
s.delete(&mut writer, 1, &Value::Str("hello!"))
|
||||
.expect_err("deleted");
|
||||
writer.commit().expect("committed");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
let mut iter = s.get(&reader, 1).expect("read");
|
||||
assert_eq!(iter.next().expect("first").expect("ok").1, Value::Str("hello1!"));
|
||||
assert_eq!(
|
||||
iter.next().expect("first").expect("ok").1,
|
||||
Value::Str("hello1!")
|
||||
);
|
||||
assert!(iter.next().is_none());
|
||||
}
|
||||
|
||||
{
|
||||
let mut writer = k.write().expect("writer");
|
||||
s.delete(&mut writer, 1, &Value::Str("hello1!")).expect("deleted");
|
||||
s.delete(&mut writer, 1, &Value::Str("hello1!"))
|
||||
.expect("deleted");
|
||||
writer.commit().expect("committed");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
|
@ -498,7 +643,8 @@ mod tests_safe {
|
|||
|
||||
{
|
||||
let mut writer = k.write().expect("writer");
|
||||
s.delete(&mut writer, 1, &Value::Str("hello1!")).expect_err("deleted");
|
||||
s.delete(&mut writer, 1, &Value::Str("hello1!"))
|
||||
.expect_err("deleted");
|
||||
writer.commit().expect("committed");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
|
@ -509,21 +655,33 @@ mod tests_safe {
|
|||
|
||||
#[test]
|
||||
fn test_persist() {
|
||||
let root = Builder::new().prefix("test_multi_integer_persist").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_multi_integer_persist")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
{
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
|
||||
let s = k
|
||||
.open_multi_integer("s", StoreOptions::create())
|
||||
.expect("open");
|
||||
|
||||
let mut writer = k.write().expect("writer");
|
||||
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
|
||||
s.put(&mut writer, 1, &Value::Str("hello1!")).expect("write");
|
||||
s.put(&mut writer, 1, &Value::Str("hello1!"))
|
||||
.expect("write");
|
||||
s.put(&mut writer, 2, &Value::Str("hello!")).expect("write");
|
||||
{
|
||||
let mut iter = s.get(&writer, 1).expect("read");
|
||||
assert_eq!(iter.next().expect("first").expect("ok").1, Value::Str("hello!"));
|
||||
assert_eq!(iter.next().expect("second").expect("ok").1, Value::Str("hello1!"));
|
||||
assert_eq!(
|
||||
iter.next().expect("first").expect("ok").1,
|
||||
Value::Str("hello!")
|
||||
);
|
||||
assert_eq!(
|
||||
iter.next().expect("second").expect("ok").1,
|
||||
Value::Str("hello1!")
|
||||
);
|
||||
assert!(iter.next().is_none());
|
||||
}
|
||||
writer.commit().expect("committed");
|
||||
|
@ -531,12 +689,20 @@ mod tests_safe {
|
|||
|
||||
{
|
||||
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
|
||||
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
|
||||
let s = k
|
||||
.open_multi_integer("s", StoreOptions::create())
|
||||
.expect("open");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
let mut iter = s.get(&reader, 1).expect("read");
|
||||
assert_eq!(iter.next().expect("first").expect("ok").1, Value::Str("hello!"));
|
||||
assert_eq!(iter.next().expect("second").expect("ok").1, Value::Str("hello1!"));
|
||||
assert_eq!(
|
||||
iter.next().expect("first").expect("ok").1,
|
||||
Value::Str("hello!")
|
||||
);
|
||||
assert_eq!(
|
||||
iter.next().expect("second").expect("ok").1,
|
||||
Value::Str("hello1!")
|
||||
);
|
||||
assert!(iter.next().is_none());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,19 +11,10 @@
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use crate::{
|
||||
backend::{
|
||||
BackendDatabase,
|
||||
BackendFlags,
|
||||
BackendIter,
|
||||
BackendRoCursor,
|
||||
BackendRwTransaction,
|
||||
},
|
||||
backend::{BackendDatabase, BackendFlags, BackendIter, BackendRoCursor, BackendRwTransaction},
|
||||
error::StoreError,
|
||||
helpers::read_transform,
|
||||
readwrite::{
|
||||
Readable,
|
||||
Writer,
|
||||
},
|
||||
readwrite::{Readable, Writer},
|
||||
value::Value,
|
||||
};
|
||||
|
||||
|
@ -44,9 +35,7 @@ where
|
|||
D: BackendDatabase,
|
||||
{
|
||||
pub(crate) fn new(db: D) -> MultiStore<D> {
|
||||
MultiStore {
|
||||
db,
|
||||
}
|
||||
MultiStore { db }
|
||||
}
|
||||
|
||||
/// Provides a cursor to all of the values for the duplicate entries that match this
|
||||
|
@ -87,7 +76,13 @@ where
|
|||
writer.put(&self.db, &k, v, T::Flags::empty())
|
||||
}
|
||||
|
||||
pub fn put_with_flags<T, K>(&self, writer: &mut Writer<T>, k: K, v: &Value, flags: T::Flags) -> EmptyResult
|
||||
pub fn put_with_flags<T, K>(
|
||||
&self,
|
||||
writer: &mut Writer<T>,
|
||||
k: K,
|
||||
v: &Value,
|
||||
flags: T::Flags,
|
||||
) -> EmptyResult
|
||||
where
|
||||
T: BackendRwTransaction<Database = D>,
|
||||
K: AsRef<[u8]>,
|
||||
|
@ -128,11 +123,9 @@ where
|
|||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.iter.next() {
|
||||
None => None,
|
||||
Some(Ok((key, bytes))) => {
|
||||
match read_transform(Ok(bytes)) {
|
||||
Ok(val) => Some(Ok((key, val))),
|
||||
Err(err) => Some(Err(err)),
|
||||
}
|
||||
Some(Ok((key, bytes))) => match read_transform(Ok(bytes)) {
|
||||
Ok(val) => Some(Ok((key, val))),
|
||||
Err(err) => Some(Err(err)),
|
||||
},
|
||||
Some(Err(err)) => Some(Err(err.into())),
|
||||
}
|
||||
|
|
|
@ -11,19 +11,10 @@
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use crate::{
|
||||
backend::{
|
||||
BackendDatabase,
|
||||
BackendFlags,
|
||||
BackendIter,
|
||||
BackendRoCursor,
|
||||
BackendRwTransaction,
|
||||
},
|
||||
backend::{BackendDatabase, BackendFlags, BackendIter, BackendRoCursor, BackendRwTransaction},
|
||||
error::StoreError,
|
||||
helpers::read_transform,
|
||||
readwrite::{
|
||||
Readable,
|
||||
Writer,
|
||||
},
|
||||
readwrite::{Readable, Writer},
|
||||
value::Value,
|
||||
};
|
||||
|
||||
|
@ -44,9 +35,7 @@ where
|
|||
D: BackendDatabase,
|
||||
{
|
||||
pub(crate) fn new(db: D) -> SingleStore<D> {
|
||||
SingleStore {
|
||||
db,
|
||||
}
|
||||
SingleStore { db }
|
||||
}
|
||||
|
||||
pub fn get<'r, R, K>(&self, reader: &'r R, k: K) -> Result<Option<Value<'r>>, StoreError>
|
||||
|
@ -133,11 +122,9 @@ where
|
|||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.iter.next() {
|
||||
None => None,
|
||||
Some(Ok((key, bytes))) => {
|
||||
match read_transform(Ok(bytes)) {
|
||||
Ok(val) => Some(Ok((key, val))),
|
||||
Err(err) => Some(Err(err)),
|
||||
}
|
||||
Some(Ok((key, bytes))) => match read_transform(Ok(bytes)) {
|
||||
Ok(val) => Some(Ok((key, val))),
|
||||
Err(err) => Some(Err(err)),
|
||||
},
|
||||
Some(Err(err)) => Some(Err(err.into())),
|
||||
}
|
||||
|
|
|
@ -11,16 +11,9 @@
|
|||
use std::fmt;
|
||||
|
||||
use arrayref::array_ref;
|
||||
use bincode::{
|
||||
deserialize,
|
||||
serialize,
|
||||
serialized_size,
|
||||
};
|
||||
use bincode::{deserialize, serialize, serialized_size};
|
||||
use ordered_float::OrderedFloat;
|
||||
use uuid::{
|
||||
Bytes,
|
||||
Uuid,
|
||||
};
|
||||
use uuid::{Bytes, Uuid};
|
||||
|
||||
use crate::error::DataError;
|
||||
|
||||
|
@ -44,6 +37,7 @@ pub enum Type {
|
|||
/// We use manual tagging, because <https://github.com/serde-rs/serde/issues/610>.
|
||||
impl Type {
|
||||
pub fn from_tag(tag: u8) -> Result<Type, DataError> {
|
||||
#![allow(clippy::unnecessary_lazy_evaluations)]
|
||||
Type::from_primitive(tag).ok_or_else(|| DataError::UnknownType(tag))
|
||||
}
|
||||
|
||||
|
@ -128,11 +122,9 @@ impl<'v> Value<'v> {
|
|||
fn from_type_and_data(t: Type, data: &'v [u8]) -> Result<Value<'v>, DataError> {
|
||||
if t == Type::Uuid {
|
||||
return deserialize(data)
|
||||
.map_err(|e| {
|
||||
DataError::DecodingError {
|
||||
value_type: t,
|
||||
err: e,
|
||||
}
|
||||
.map_err(|e| DataError::DecodingError {
|
||||
value_type: t,
|
||||
err: e,
|
||||
})
|
||||
.map(uuid)?;
|
||||
}
|
||||
|
@ -149,13 +141,11 @@ impl<'v> Value<'v> {
|
|||
Type::Uuid => {
|
||||
// Processed above to avoid verbose duplication of error transforms.
|
||||
unreachable!()
|
||||
},
|
||||
}
|
||||
.map_err(|e| {
|
||||
DataError::DecodingError {
|
||||
value_type: t,
|
||||
err: e,
|
||||
}
|
||||
}
|
||||
.map_err(|e| DataError::DecodingError {
|
||||
value_type: t,
|
||||
err: e,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -240,8 +230,14 @@ mod tests {
|
|||
assert_eq!(Value::I64(-1000).serialized_size().unwrap(), 9);
|
||||
assert_eq!(Value::U64(1000u64).serialized_size().unwrap(), 9);
|
||||
assert_eq!(Value::Bool(true).serialized_size().unwrap(), 2);
|
||||
assert_eq!(Value::Instant(1_558_020_865_224).serialized_size().unwrap(), 9);
|
||||
assert_eq!(Value::F64(OrderedFloat(10000.1)).serialized_size().unwrap(), 9);
|
||||
assert_eq!(
|
||||
Value::Instant(1_558_020_865_224).serialized_size().unwrap(),
|
||||
9
|
||||
);
|
||||
assert_eq!(
|
||||
Value::F64(OrderedFloat(10000.1)).serialized_size().unwrap(),
|
||||
9
|
||||
);
|
||||
assert_eq!(Value::Str("hello!").serialized_size().unwrap(), 15);
|
||||
assert_eq!(Value::Str("¡Hola").serialized_size().unwrap(), 15);
|
||||
assert_eq!(Value::Blob(b"hello!").serialized_size().unwrap(), 15);
|
||||
|
|
|
@ -13,18 +13,16 @@ use std::fs;
|
|||
use tempfile::Builder;
|
||||
|
||||
use rkv::{
|
||||
backend::{
|
||||
Lmdb,
|
||||
SafeMode,
|
||||
},
|
||||
Rkv,
|
||||
StoreOptions,
|
||||
Value,
|
||||
backend::{Lmdb, SafeMode},
|
||||
Rkv, StoreOptions, Value,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_open_safe_same_dir_as_lmdb() {
|
||||
let root = Builder::new().prefix("test_open_safe_same_dir_as_lmdb").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_open_safe_same_dir_as_lmdb")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
// Create database of type A and save to disk.
|
||||
|
@ -33,39 +31,75 @@ fn test_open_safe_same_dir_as_lmdb() {
|
|||
let sk = k.open_single("sk", StoreOptions::create()).expect("opened");
|
||||
|
||||
let mut writer = k.write().expect("writer");
|
||||
sk.put(&mut writer, "foo", &Value::I64(1234)).expect("wrote");
|
||||
sk.put(&mut writer, "bar", &Value::Bool(true)).expect("wrote");
|
||||
sk.put(&mut writer, "baz", &Value::Str("héllo, yöu")).expect("wrote");
|
||||
assert_eq!(sk.get(&writer, "foo").expect("read"), Some(Value::I64(1234)));
|
||||
assert_eq!(sk.get(&writer, "bar").expect("read"), Some(Value::Bool(true)));
|
||||
assert_eq!(sk.get(&writer, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
|
||||
sk.put(&mut writer, "foo", &Value::I64(1234))
|
||||
.expect("wrote");
|
||||
sk.put(&mut writer, "bar", &Value::Bool(true))
|
||||
.expect("wrote");
|
||||
sk.put(&mut writer, "baz", &Value::Str("héllo, yöu"))
|
||||
.expect("wrote");
|
||||
assert_eq!(
|
||||
sk.get(&writer, "foo").expect("read"),
|
||||
Some(Value::I64(1234))
|
||||
);
|
||||
assert_eq!(
|
||||
sk.get(&writer, "bar").expect("read"),
|
||||
Some(Value::Bool(true))
|
||||
);
|
||||
assert_eq!(
|
||||
sk.get(&writer, "baz").expect("read"),
|
||||
Some(Value::Str("héllo, yöu"))
|
||||
);
|
||||
writer.commit().expect("committed");
|
||||
k.sync(true).expect("synced");
|
||||
}
|
||||
// Verify that database of type A was written to disk.
|
||||
{
|
||||
let k = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
|
||||
let sk = k.open_single("sk", StoreOptions::default()).expect("opened");
|
||||
let sk = k
|
||||
.open_single("sk", StoreOptions::default())
|
||||
.expect("opened");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
assert_eq!(sk.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
|
||||
assert_eq!(sk.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
|
||||
assert_eq!(sk.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
|
||||
assert_eq!(
|
||||
sk.get(&reader, "foo").expect("read"),
|
||||
Some(Value::I64(1234))
|
||||
);
|
||||
assert_eq!(
|
||||
sk.get(&reader, "bar").expect("read"),
|
||||
Some(Value::Bool(true))
|
||||
);
|
||||
assert_eq!(
|
||||
sk.get(&reader, "baz").expect("read"),
|
||||
Some(Value::Str("héllo, yöu"))
|
||||
);
|
||||
}
|
||||
// Create database of type B and verify that it is empty.
|
||||
{
|
||||
let k = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
|
||||
let _ = k.open_single("sk", StoreOptions::default()).expect_err("not opened");
|
||||
let _ = k
|
||||
.open_single("sk", StoreOptions::default())
|
||||
.expect_err("not opened");
|
||||
}
|
||||
// Verify that database of type A wasn't changed.
|
||||
{
|
||||
let k = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
|
||||
let sk = k.open_single("sk", StoreOptions::default()).expect("opened");
|
||||
let sk = k
|
||||
.open_single("sk", StoreOptions::default())
|
||||
.expect("opened");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
assert_eq!(sk.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
|
||||
assert_eq!(sk.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
|
||||
assert_eq!(sk.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
|
||||
assert_eq!(
|
||||
sk.get(&reader, "foo").expect("read"),
|
||||
Some(Value::I64(1234))
|
||||
);
|
||||
assert_eq!(
|
||||
sk.get(&reader, "bar").expect("read"),
|
||||
Some(Value::Bool(true))
|
||||
);
|
||||
assert_eq!(
|
||||
sk.get(&reader, "baz").expect("read"),
|
||||
Some(Value::Str("héllo, yöu"))
|
||||
);
|
||||
}
|
||||
// Create database of type B and save to disk (type A exists at the same path).
|
||||
{
|
||||
|
@ -73,40 +107,77 @@ fn test_open_safe_same_dir_as_lmdb() {
|
|||
let sk = k.open_single("sk", StoreOptions::create()).expect("opened");
|
||||
|
||||
let mut writer = k.write().expect("writer");
|
||||
sk.put(&mut writer, "foo1", &Value::I64(5678)).expect("wrote");
|
||||
sk.put(&mut writer, "bar1", &Value::Bool(false)).expect("wrote");
|
||||
sk.put(&mut writer, "baz1", &Value::Str("héllo~ yöu")).expect("wrote");
|
||||
assert_eq!(sk.get(&writer, "foo1").expect("read"), Some(Value::I64(5678)));
|
||||
assert_eq!(sk.get(&writer, "bar1").expect("read"), Some(Value::Bool(false)));
|
||||
assert_eq!(sk.get(&writer, "baz1").expect("read"), Some(Value::Str("héllo~ yöu")));
|
||||
sk.put(&mut writer, "foo1", &Value::I64(5678))
|
||||
.expect("wrote");
|
||||
sk.put(&mut writer, "bar1", &Value::Bool(false))
|
||||
.expect("wrote");
|
||||
sk.put(&mut writer, "baz1", &Value::Str("héllo~ yöu"))
|
||||
.expect("wrote");
|
||||
assert_eq!(
|
||||
sk.get(&writer, "foo1").expect("read"),
|
||||
Some(Value::I64(5678))
|
||||
);
|
||||
assert_eq!(
|
||||
sk.get(&writer, "bar1").expect("read"),
|
||||
Some(Value::Bool(false))
|
||||
);
|
||||
assert_eq!(
|
||||
sk.get(&writer, "baz1").expect("read"),
|
||||
Some(Value::Str("héllo~ yöu"))
|
||||
);
|
||||
writer.commit().expect("committed");
|
||||
k.sync(true).expect("synced");
|
||||
}
|
||||
// Verify that database of type B was written to disk.
|
||||
{
|
||||
let k = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
|
||||
let sk = k.open_single("sk", StoreOptions::default()).expect("opened");
|
||||
let sk = k
|
||||
.open_single("sk", StoreOptions::default())
|
||||
.expect("opened");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
assert_eq!(sk.get(&reader, "foo1").expect("read"), Some(Value::I64(5678)));
|
||||
assert_eq!(sk.get(&reader, "bar1").expect("read"), Some(Value::Bool(false)));
|
||||
assert_eq!(sk.get(&reader, "baz1").expect("read"), Some(Value::Str("héllo~ yöu")));
|
||||
assert_eq!(
|
||||
sk.get(&reader, "foo1").expect("read"),
|
||||
Some(Value::I64(5678))
|
||||
);
|
||||
assert_eq!(
|
||||
sk.get(&reader, "bar1").expect("read"),
|
||||
Some(Value::Bool(false))
|
||||
);
|
||||
assert_eq!(
|
||||
sk.get(&reader, "baz1").expect("read"),
|
||||
Some(Value::Str("héllo~ yöu"))
|
||||
);
|
||||
}
|
||||
// Verify that database of type A still wasn't changed.
|
||||
{
|
||||
let k = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
|
||||
let sk = k.open_single("sk", StoreOptions::default()).expect("opened");
|
||||
let sk = k
|
||||
.open_single("sk", StoreOptions::default())
|
||||
.expect("opened");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
assert_eq!(sk.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
|
||||
assert_eq!(sk.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
|
||||
assert_eq!(sk.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
|
||||
assert_eq!(
|
||||
sk.get(&reader, "foo").expect("read"),
|
||||
Some(Value::I64(1234))
|
||||
);
|
||||
assert_eq!(
|
||||
sk.get(&reader, "bar").expect("read"),
|
||||
Some(Value::Bool(true))
|
||||
);
|
||||
assert_eq!(
|
||||
sk.get(&reader, "baz").expect("read"),
|
||||
Some(Value::Str("héllo, yöu"))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_open_lmdb_same_dir_as_safe() {
|
||||
let root = Builder::new().prefix("test_open_lmdb_same_dir_as_safe").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_open_lmdb_same_dir_as_safe")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
// Create database of type A and save to disk.
|
||||
|
@ -115,39 +186,75 @@ fn test_open_lmdb_same_dir_as_safe() {
|
|||
let sk = k.open_single("sk", StoreOptions::create()).expect("opened");
|
||||
|
||||
let mut writer = k.write().expect("writer");
|
||||
sk.put(&mut writer, "foo", &Value::I64(1234)).expect("wrote");
|
||||
sk.put(&mut writer, "bar", &Value::Bool(true)).expect("wrote");
|
||||
sk.put(&mut writer, "baz", &Value::Str("héllo, yöu")).expect("wrote");
|
||||
assert_eq!(sk.get(&writer, "foo").expect("read"), Some(Value::I64(1234)));
|
||||
assert_eq!(sk.get(&writer, "bar").expect("read"), Some(Value::Bool(true)));
|
||||
assert_eq!(sk.get(&writer, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
|
||||
sk.put(&mut writer, "foo", &Value::I64(1234))
|
||||
.expect("wrote");
|
||||
sk.put(&mut writer, "bar", &Value::Bool(true))
|
||||
.expect("wrote");
|
||||
sk.put(&mut writer, "baz", &Value::Str("héllo, yöu"))
|
||||
.expect("wrote");
|
||||
assert_eq!(
|
||||
sk.get(&writer, "foo").expect("read"),
|
||||
Some(Value::I64(1234))
|
||||
);
|
||||
assert_eq!(
|
||||
sk.get(&writer, "bar").expect("read"),
|
||||
Some(Value::Bool(true))
|
||||
);
|
||||
assert_eq!(
|
||||
sk.get(&writer, "baz").expect("read"),
|
||||
Some(Value::Str("héllo, yöu"))
|
||||
);
|
||||
writer.commit().expect("committed");
|
||||
k.sync(true).expect("synced");
|
||||
}
|
||||
// Verify that database of type A was written to disk.
|
||||
{
|
||||
let k = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
|
||||
let sk = k.open_single("sk", StoreOptions::default()).expect("opened");
|
||||
let sk = k
|
||||
.open_single("sk", StoreOptions::default())
|
||||
.expect("opened");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
assert_eq!(sk.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
|
||||
assert_eq!(sk.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
|
||||
assert_eq!(sk.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
|
||||
assert_eq!(
|
||||
sk.get(&reader, "foo").expect("read"),
|
||||
Some(Value::I64(1234))
|
||||
);
|
||||
assert_eq!(
|
||||
sk.get(&reader, "bar").expect("read"),
|
||||
Some(Value::Bool(true))
|
||||
);
|
||||
assert_eq!(
|
||||
sk.get(&reader, "baz").expect("read"),
|
||||
Some(Value::Str("héllo, yöu"))
|
||||
);
|
||||
}
|
||||
// Create database of type B and verify that it is empty.
|
||||
{
|
||||
let k = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
|
||||
let _ = k.open_single("sk", StoreOptions::default()).expect_err("not opened");
|
||||
let _ = k
|
||||
.open_single("sk", StoreOptions::default())
|
||||
.expect_err("not opened");
|
||||
}
|
||||
// Verify that database of type A wasn't changed.
|
||||
{
|
||||
let k = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
|
||||
let sk = k.open_single("sk", StoreOptions::default()).expect("opened");
|
||||
let sk = k
|
||||
.open_single("sk", StoreOptions::default())
|
||||
.expect("opened");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
assert_eq!(sk.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
|
||||
assert_eq!(sk.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
|
||||
assert_eq!(sk.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
|
||||
assert_eq!(
|
||||
sk.get(&reader, "foo").expect("read"),
|
||||
Some(Value::I64(1234))
|
||||
);
|
||||
assert_eq!(
|
||||
sk.get(&reader, "bar").expect("read"),
|
||||
Some(Value::Bool(true))
|
||||
);
|
||||
assert_eq!(
|
||||
sk.get(&reader, "baz").expect("read"),
|
||||
Some(Value::Str("héllo, yöu"))
|
||||
);
|
||||
}
|
||||
// Create database of type B and save to disk (type A exists at the same path).
|
||||
{
|
||||
|
@ -155,33 +262,67 @@ fn test_open_lmdb_same_dir_as_safe() {
|
|||
let sk = k.open_single("sk", StoreOptions::create()).expect("opened");
|
||||
|
||||
let mut writer = k.write().expect("writer");
|
||||
sk.put(&mut writer, "foo1", &Value::I64(5678)).expect("wrote");
|
||||
sk.put(&mut writer, "bar1", &Value::Bool(false)).expect("wrote");
|
||||
sk.put(&mut writer, "baz1", &Value::Str("héllo~ yöu")).expect("wrote");
|
||||
assert_eq!(sk.get(&writer, "foo1").expect("read"), Some(Value::I64(5678)));
|
||||
assert_eq!(sk.get(&writer, "bar1").expect("read"), Some(Value::Bool(false)));
|
||||
assert_eq!(sk.get(&writer, "baz1").expect("read"), Some(Value::Str("héllo~ yöu")));
|
||||
sk.put(&mut writer, "foo1", &Value::I64(5678))
|
||||
.expect("wrote");
|
||||
sk.put(&mut writer, "bar1", &Value::Bool(false))
|
||||
.expect("wrote");
|
||||
sk.put(&mut writer, "baz1", &Value::Str("héllo~ yöu"))
|
||||
.expect("wrote");
|
||||
assert_eq!(
|
||||
sk.get(&writer, "foo1").expect("read"),
|
||||
Some(Value::I64(5678))
|
||||
);
|
||||
assert_eq!(
|
||||
sk.get(&writer, "bar1").expect("read"),
|
||||
Some(Value::Bool(false))
|
||||
);
|
||||
assert_eq!(
|
||||
sk.get(&writer, "baz1").expect("read"),
|
||||
Some(Value::Str("héllo~ yöu"))
|
||||
);
|
||||
writer.commit().expect("committed");
|
||||
k.sync(true).expect("synced");
|
||||
}
|
||||
// Verify that database of type B was written to disk.
|
||||
{
|
||||
let k = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
|
||||
let sk = k.open_single("sk", StoreOptions::default()).expect("opened");
|
||||
let sk = k
|
||||
.open_single("sk", StoreOptions::default())
|
||||
.expect("opened");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
assert_eq!(sk.get(&reader, "foo1").expect("read"), Some(Value::I64(5678)));
|
||||
assert_eq!(sk.get(&reader, "bar1").expect("read"), Some(Value::Bool(false)));
|
||||
assert_eq!(sk.get(&reader, "baz1").expect("read"), Some(Value::Str("héllo~ yöu")));
|
||||
assert_eq!(
|
||||
sk.get(&reader, "foo1").expect("read"),
|
||||
Some(Value::I64(5678))
|
||||
);
|
||||
assert_eq!(
|
||||
sk.get(&reader, "bar1").expect("read"),
|
||||
Some(Value::Bool(false))
|
||||
);
|
||||
assert_eq!(
|
||||
sk.get(&reader, "baz1").expect("read"),
|
||||
Some(Value::Str("héllo~ yöu"))
|
||||
);
|
||||
}
|
||||
// Verify that database of type A still wasn't changed.
|
||||
{
|
||||
let k = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
|
||||
let sk = k.open_single("sk", StoreOptions::default()).expect("opened");
|
||||
let sk = k
|
||||
.open_single("sk", StoreOptions::default())
|
||||
.expect("opened");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
assert_eq!(sk.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
|
||||
assert_eq!(sk.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
|
||||
assert_eq!(sk.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
|
||||
assert_eq!(
|
||||
sk.get(&reader, "foo").expect("read"),
|
||||
Some(Value::I64(1234))
|
||||
);
|
||||
assert_eq!(
|
||||
sk.get(&reader, "bar").expect("read"),
|
||||
Some(Value::Bool(true))
|
||||
);
|
||||
assert_eq!(
|
||||
sk.get(&reader, "baz").expect("read"),
|
||||
Some(Value::Str("héllo, yöu"))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -8,41 +8,40 @@
|
|||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use std::{
|
||||
fs,
|
||||
path::Path,
|
||||
};
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use tempfile::Builder;
|
||||
|
||||
use rkv::{
|
||||
backend::{
|
||||
Lmdb,
|
||||
LmdbEnvironment,
|
||||
SafeMode,
|
||||
SafeModeEnvironment,
|
||||
},
|
||||
Manager,
|
||||
Migrator,
|
||||
Rkv,
|
||||
StoreOptions,
|
||||
Value,
|
||||
backend::{Lmdb, LmdbEnvironment, SafeMode, SafeModeEnvironment},
|
||||
Manager, Migrator, Rkv, StoreOptions, Value,
|
||||
};
|
||||
|
||||
macro_rules! populate_store {
|
||||
($env:expr) => {
|
||||
let store = $env.open_single("store", StoreOptions::create()).expect("opened");
|
||||
let store = $env
|
||||
.open_single("store", StoreOptions::create())
|
||||
.expect("opened");
|
||||
let mut writer = $env.write().expect("writer");
|
||||
store.put(&mut writer, "foo", &Value::I64(1234)).expect("wrote");
|
||||
store.put(&mut writer, "bar", &Value::Bool(true)).expect("wrote");
|
||||
store.put(&mut writer, "baz", &Value::Str("héllo, yöu")).expect("wrote");
|
||||
store
|
||||
.put(&mut writer, "foo", &Value::I64(1234))
|
||||
.expect("wrote");
|
||||
store
|
||||
.put(&mut writer, "bar", &Value::Bool(true))
|
||||
.expect("wrote");
|
||||
store
|
||||
.put(&mut writer, "baz", &Value::Str("héllo, yöu"))
|
||||
.expect("wrote");
|
||||
writer.commit().expect("committed");
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_open_migrator_lmdb_to_safe() {
|
||||
let root = Builder::new().prefix("test_open_migrator_lmdb_to_safe").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_open_migrator_lmdb_to_safe")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
// Populate source environment and persist to disk.
|
||||
|
@ -63,25 +62,48 @@ fn test_open_migrator_lmdb_to_safe() {
|
|||
// Verify that database was written to disk.
|
||||
{
|
||||
let src_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
|
||||
let store = src_env.open_single("store", StoreOptions::default()).expect("opened");
|
||||
let store = src_env
|
||||
.open_single("store", StoreOptions::default())
|
||||
.expect("opened");
|
||||
let reader = src_env.read().expect("reader");
|
||||
assert_eq!(store.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
|
||||
assert_eq!(store.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
|
||||
assert_eq!(store.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
|
||||
assert_eq!(
|
||||
store.get(&reader, "foo").expect("read"),
|
||||
Some(Value::I64(1234))
|
||||
);
|
||||
assert_eq!(
|
||||
store.get(&reader, "bar").expect("read"),
|
||||
Some(Value::Bool(true))
|
||||
);
|
||||
assert_eq!(
|
||||
store.get(&reader, "baz").expect("read"),
|
||||
Some(Value::Str("héllo, yöu"))
|
||||
);
|
||||
}
|
||||
// Open and migrate.
|
||||
{
|
||||
let dst_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
|
||||
Migrator::open_and_migrate_lmdb_to_safe_mode(root.path(), |builder| builder, &dst_env).expect("migrated");
|
||||
Migrator::open_and_migrate_lmdb_to_safe_mode(root.path(), |builder| builder, &dst_env)
|
||||
.expect("migrated");
|
||||
}
|
||||
// Verify that the database was indeed migrated.
|
||||
{
|
||||
let dst_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
|
||||
let store = dst_env.open_single("store", StoreOptions::default()).expect("opened");
|
||||
let store = dst_env
|
||||
.open_single("store", StoreOptions::default())
|
||||
.expect("opened");
|
||||
let reader = dst_env.read().expect("reader");
|
||||
assert_eq!(store.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
|
||||
assert_eq!(store.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
|
||||
assert_eq!(store.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
|
||||
assert_eq!(
|
||||
store.get(&reader, "foo").expect("read"),
|
||||
Some(Value::I64(1234))
|
||||
);
|
||||
assert_eq!(
|
||||
store.get(&reader, "bar").expect("read"),
|
||||
Some(Value::Bool(true))
|
||||
);
|
||||
assert_eq!(
|
||||
store.get(&reader, "baz").expect("read"),
|
||||
Some(Value::Str("héllo, yöu"))
|
||||
);
|
||||
}
|
||||
// Check if the old files were deleted from disk.
|
||||
{
|
||||
|
@ -96,7 +118,10 @@ fn test_open_migrator_lmdb_to_safe() {
|
|||
|
||||
#[test]
|
||||
fn test_open_migrator_safe_to_lmdb() {
|
||||
let root = Builder::new().prefix("test_open_migrator_safe_to_lmdb").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_open_migrator_safe_to_lmdb")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
// Populate source environment and persist to disk.
|
||||
|
@ -114,25 +139,48 @@ fn test_open_migrator_safe_to_lmdb() {
|
|||
// Verify that database was written to disk.
|
||||
{
|
||||
let src_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
|
||||
let store = src_env.open_single("store", StoreOptions::default()).expect("opened");
|
||||
let store = src_env
|
||||
.open_single("store", StoreOptions::default())
|
||||
.expect("opened");
|
||||
let reader = src_env.read().expect("reader");
|
||||
assert_eq!(store.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
|
||||
assert_eq!(store.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
|
||||
assert_eq!(store.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
|
||||
assert_eq!(
|
||||
store.get(&reader, "foo").expect("read"),
|
||||
Some(Value::I64(1234))
|
||||
);
|
||||
assert_eq!(
|
||||
store.get(&reader, "bar").expect("read"),
|
||||
Some(Value::Bool(true))
|
||||
);
|
||||
assert_eq!(
|
||||
store.get(&reader, "baz").expect("read"),
|
||||
Some(Value::Str("héllo, yöu"))
|
||||
);
|
||||
}
|
||||
// Open and migrate.
|
||||
{
|
||||
let dst_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
|
||||
Migrator::open_and_migrate_safe_mode_to_lmdb(root.path(), |builder| builder, &dst_env).expect("migrated");
|
||||
Migrator::open_and_migrate_safe_mode_to_lmdb(root.path(), |builder| builder, &dst_env)
|
||||
.expect("migrated");
|
||||
}
|
||||
// Verify that the database was indeed migrated.
|
||||
{
|
||||
let dst_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
|
||||
let store = dst_env.open_single("store", StoreOptions::default()).expect("opened");
|
||||
let store = dst_env
|
||||
.open_single("store", StoreOptions::default())
|
||||
.expect("opened");
|
||||
let reader = dst_env.read().expect("reader");
|
||||
assert_eq!(store.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
|
||||
assert_eq!(store.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
|
||||
assert_eq!(store.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
|
||||
assert_eq!(
|
||||
store.get(&reader, "foo").expect("read"),
|
||||
Some(Value::I64(1234))
|
||||
);
|
||||
assert_eq!(
|
||||
store.get(&reader, "bar").expect("read"),
|
||||
Some(Value::Bool(true))
|
||||
);
|
||||
assert_eq!(
|
||||
store.get(&reader, "baz").expect("read"),
|
||||
Some(Value::Str("héllo, yöu"))
|
||||
);
|
||||
}
|
||||
// Check if the old files were deleted from disk.
|
||||
{
|
||||
|
@ -144,7 +192,10 @@ fn test_open_migrator_safe_to_lmdb() {
|
|||
|
||||
#[test]
|
||||
fn test_open_migrator_round_trip() {
|
||||
let root = Builder::new().prefix("test_open_migrator_lmdb_to_safe").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_open_migrator_lmdb_to_safe")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
// Populate source environment and persist to disk.
|
||||
|
@ -156,21 +207,34 @@ fn test_open_migrator_round_trip() {
|
|||
// Open and migrate.
|
||||
{
|
||||
let dst_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
|
||||
Migrator::open_and_migrate_lmdb_to_safe_mode(root.path(), |builder| builder, &dst_env).expect("migrated");
|
||||
Migrator::open_and_migrate_lmdb_to_safe_mode(root.path(), |builder| builder, &dst_env)
|
||||
.expect("migrated");
|
||||
}
|
||||
// Open and migrate back.
|
||||
{
|
||||
let dst_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
|
||||
Migrator::open_and_migrate_safe_mode_to_lmdb(root.path(), |builder| builder, &dst_env).expect("migrated");
|
||||
Migrator::open_and_migrate_safe_mode_to_lmdb(root.path(), |builder| builder, &dst_env)
|
||||
.expect("migrated");
|
||||
}
|
||||
// Verify that the database was indeed migrated twice.
|
||||
{
|
||||
let dst_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
|
||||
let store = dst_env.open_single("store", StoreOptions::default()).expect("opened");
|
||||
let store = dst_env
|
||||
.open_single("store", StoreOptions::default())
|
||||
.expect("opened");
|
||||
let reader = dst_env.read().expect("reader");
|
||||
assert_eq!(store.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
|
||||
assert_eq!(store.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
|
||||
assert_eq!(store.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
|
||||
assert_eq!(
|
||||
store.get(&reader, "foo").expect("read"),
|
||||
Some(Value::I64(1234))
|
||||
);
|
||||
assert_eq!(
|
||||
store.get(&reader, "bar").expect("read"),
|
||||
Some(Value::Bool(true))
|
||||
);
|
||||
assert_eq!(
|
||||
store.get(&reader, "baz").expect("read"),
|
||||
Some(Value::Str("héllo, yöu"))
|
||||
);
|
||||
}
|
||||
// Check if the right files are finally present on disk.
|
||||
{
|
||||
|
@ -188,7 +252,10 @@ fn test_open_migrator_round_trip() {
|
|||
|
||||
#[test]
|
||||
fn test_easy_migrator_no_dir_1() {
|
||||
let root = Builder::new().prefix("test_easy_migrator_no_dir").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_easy_migrator_no_dir")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
// This won't fail with IoError even though the path is a bogus path, because this
|
||||
|
@ -209,7 +276,10 @@ fn test_easy_migrator_no_dir_1() {
|
|||
|
||||
#[test]
|
||||
fn test_easy_migrator_no_dir_2() {
|
||||
let root = Builder::new().prefix("test_easy_migrator_no_dir").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_easy_migrator_no_dir")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
// This won't fail with IoError even though the path is a bogus path, because this
|
||||
|
@ -230,7 +300,10 @@ fn test_easy_migrator_no_dir_2() {
|
|||
|
||||
#[test]
|
||||
fn test_easy_migrator_invalid_1() {
|
||||
let root = Builder::new().prefix("test_easy_migrator_invalid").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_easy_migrator_invalid")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let dbfile = root.path().join("data.mdb");
|
||||
|
@ -254,7 +327,10 @@ fn test_easy_migrator_invalid_1() {
|
|||
|
||||
#[test]
|
||||
fn test_easy_migrator_invalid_2() {
|
||||
let root = Builder::new().prefix("test_easy_migrator_invalid").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_easy_migrator_invalid")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let dbfile = root.path().join("data.safe.bin");
|
||||
|
@ -279,7 +355,10 @@ fn test_easy_migrator_invalid_2() {
|
|||
#[test]
|
||||
#[should_panic(expected = "migrated: SourceEmpty")]
|
||||
fn test_migrator_lmdb_to_safe_1() {
|
||||
let root = Builder::new().prefix("test_migrate_lmdb_to_safe").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_migrate_lmdb_to_safe")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let src_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
|
||||
|
@ -290,7 +369,10 @@ fn test_migrator_lmdb_to_safe_1() {
|
|||
#[test]
|
||||
#[should_panic(expected = "migrated: DestinationNotEmpty")]
|
||||
fn test_migrator_lmdb_to_safe_2() {
|
||||
let root = Builder::new().prefix("test_migrate_lmdb_to_safe").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_migrate_lmdb_to_safe")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let src_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
|
||||
|
@ -302,7 +384,10 @@ fn test_migrator_lmdb_to_safe_2() {
|
|||
|
||||
#[test]
|
||||
fn test_migrator_lmdb_to_safe_3() {
|
||||
let root = Builder::new().prefix("test_migrate_lmdb_to_safe").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_migrate_lmdb_to_safe")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let src_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
|
||||
|
@ -310,17 +395,31 @@ fn test_migrator_lmdb_to_safe_3() {
|
|||
let dst_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
|
||||
Migrator::migrate_lmdb_to_safe_mode(&src_env, &dst_env).expect("migrated");
|
||||
|
||||
let store = dst_env.open_single("store", StoreOptions::default()).expect("opened");
|
||||
let store = dst_env
|
||||
.open_single("store", StoreOptions::default())
|
||||
.expect("opened");
|
||||
let reader = dst_env.read().expect("reader");
|
||||
assert_eq!(store.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
|
||||
assert_eq!(store.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
|
||||
assert_eq!(store.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
|
||||
assert_eq!(
|
||||
store.get(&reader, "foo").expect("read"),
|
||||
Some(Value::I64(1234))
|
||||
);
|
||||
assert_eq!(
|
||||
store.get(&reader, "bar").expect("read"),
|
||||
Some(Value::Bool(true))
|
||||
);
|
||||
assert_eq!(
|
||||
store.get(&reader, "baz").expect("read"),
|
||||
Some(Value::Str("héllo, yöu"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "migrated: SourceEmpty")]
|
||||
fn test_migrator_safe_to_lmdb_1() {
|
||||
let root = Builder::new().prefix("test_migrate_safe_to_lmdb").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_migrate_safe_to_lmdb")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let src_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
|
||||
|
@ -331,7 +430,10 @@ fn test_migrator_safe_to_lmdb_1() {
|
|||
#[test]
|
||||
#[should_panic(expected = "migrated: DestinationNotEmpty")]
|
||||
fn test_migrator_safe_to_lmdb_2() {
|
||||
let root = Builder::new().prefix("test_migrate_safe_to_lmdb").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_migrate_safe_to_lmdb")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let src_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
|
||||
|
@ -343,7 +445,10 @@ fn test_migrator_safe_to_lmdb_2() {
|
|||
|
||||
#[test]
|
||||
fn test_migrator_safe_to_lmdb_3() {
|
||||
let root = Builder::new().prefix("test_migrate_safe_to_lmdb").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_migrate_safe_to_lmdb")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let src_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
|
||||
|
@ -351,16 +456,30 @@ fn test_migrator_safe_to_lmdb_3() {
|
|||
let dst_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
|
||||
Migrator::migrate_safe_mode_to_lmdb(&src_env, &dst_env).expect("migrated");
|
||||
|
||||
let store = dst_env.open_single("store", StoreOptions::default()).expect("opened");
|
||||
let store = dst_env
|
||||
.open_single("store", StoreOptions::default())
|
||||
.expect("opened");
|
||||
let reader = dst_env.read().expect("reader");
|
||||
assert_eq!(store.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
|
||||
assert_eq!(store.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
|
||||
assert_eq!(store.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
|
||||
assert_eq!(
|
||||
store.get(&reader, "foo").expect("read"),
|
||||
Some(Value::I64(1234))
|
||||
);
|
||||
assert_eq!(
|
||||
store.get(&reader, "bar").expect("read"),
|
||||
Some(Value::Bool(true))
|
||||
);
|
||||
assert_eq!(
|
||||
store.get(&reader, "baz").expect("read"),
|
||||
Some(Value::Str("héllo, yöu"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_easy_migrator_failed_migration_1() {
|
||||
let root = Builder::new().prefix("test_easy_migrator_failed_migration_1").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_easy_migrator_failed_migration_1")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let dbfile = root.path().join("data.mdb");
|
||||
|
@ -387,7 +506,10 @@ fn test_easy_migrator_failed_migration_1() {
|
|||
|
||||
#[test]
|
||||
fn test_easy_migrator_failed_migration_2() {
|
||||
let root = Builder::new().prefix("test_easy_migrator_failed_migration_2").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_easy_migrator_failed_migration_2")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let dbfile = root.path().join("data.safe.bin");
|
||||
|
@ -413,19 +535,26 @@ fn test_easy_migrator_failed_migration_2() {
|
|||
}
|
||||
|
||||
fn test_easy_migrator_from_manager_failed_migration_1() {
|
||||
let root = Builder::new().prefix("test_easy_migrator_from_manager_failed_migration_1").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_easy_migrator_from_manager_failed_migration_1")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
{
|
||||
let mut src_manager = Manager::<LmdbEnvironment>::singleton().write().unwrap();
|
||||
let created_src_arc = src_manager.get_or_create(root.path(), Rkv::new::<Lmdb>).unwrap();
|
||||
let created_src_arc = src_manager
|
||||
.get_or_create(root.path(), Rkv::new::<Lmdb>)
|
||||
.unwrap();
|
||||
let src_env = created_src_arc.read().unwrap();
|
||||
populate_store!(&src_env);
|
||||
src_env.sync(true).expect("synced");
|
||||
}
|
||||
{
|
||||
let mut dst_manager = Manager::<SafeModeEnvironment>::singleton().write().unwrap();
|
||||
let created_dst_arc_1 = dst_manager.get_or_create(root.path(), Rkv::new::<SafeMode>).unwrap();
|
||||
let created_dst_arc_1 = dst_manager
|
||||
.get_or_create(root.path(), Rkv::new::<SafeMode>)
|
||||
.unwrap();
|
||||
let dst_env_1 = created_dst_arc_1.read().unwrap();
|
||||
populate_store!(&dst_env_1);
|
||||
dst_env_1.sync(true).expect("synced");
|
||||
|
@ -439,19 +568,26 @@ fn test_easy_migrator_from_manager_failed_migration_1() {
|
|||
}
|
||||
|
||||
fn test_easy_migrator_from_manager_failed_migration_2() {
|
||||
let root = Builder::new().prefix("test_easy_migrator_from_manager_failed_migration_2").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_easy_migrator_from_manager_failed_migration_2")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
{
|
||||
let mut src_manager = Manager::<SafeModeEnvironment>::singleton().write().unwrap();
|
||||
let created_src_arc = src_manager.get_or_create(root.path(), Rkv::new::<SafeMode>).unwrap();
|
||||
let created_src_arc = src_manager
|
||||
.get_or_create(root.path(), Rkv::new::<SafeMode>)
|
||||
.unwrap();
|
||||
let src_env = created_src_arc.read().unwrap();
|
||||
populate_store!(&src_env);
|
||||
src_env.sync(true).expect("synced");
|
||||
}
|
||||
{
|
||||
let mut dst_manager = Manager::<LmdbEnvironment>::singleton().write().unwrap();
|
||||
let created_dst_arc_1 = dst_manager.get_or_create(root.path(), Rkv::new::<Lmdb>).unwrap();
|
||||
let created_dst_arc_1 = dst_manager
|
||||
.get_or_create(root.path(), Rkv::new::<Lmdb>)
|
||||
.unwrap();
|
||||
let dst_env_1 = created_dst_arc_1.read().unwrap();
|
||||
populate_store!(&dst_env_1);
|
||||
dst_env_1.sync(true).expect("synced");
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -15,32 +15,37 @@ use std::fs;
|
|||
use serde_derive::Serialize;
|
||||
use tempfile::Builder;
|
||||
|
||||
use rkv::{
|
||||
backend::Lmdb,
|
||||
PrimitiveInt,
|
||||
Rkv,
|
||||
StoreOptions,
|
||||
Value,
|
||||
};
|
||||
use rkv::{backend::SafeMode, PrimitiveInt, Rkv, StoreOptions, Value};
|
||||
|
||||
#[test]
|
||||
fn test_integer_keys() {
|
||||
let root = Builder::new().prefix("test_integer_keys").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_integer_keys")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let k = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
|
||||
let k = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
|
||||
let s = k.open_integer("s", StoreOptions::create()).expect("open");
|
||||
|
||||
macro_rules! test_integer_keys {
|
||||
($store:expr, $key:expr) => {{
|
||||
let mut writer = k.write().expect("writer");
|
||||
|
||||
$store.put(&mut writer, $key, &Value::Str("hello!")).expect("write");
|
||||
assert_eq!($store.get(&writer, $key).expect("read"), Some(Value::Str("hello!")));
|
||||
$store
|
||||
.put(&mut writer, $key, &Value::Str("hello!"))
|
||||
.expect("write");
|
||||
assert_eq!(
|
||||
$store.get(&writer, $key).expect("read"),
|
||||
Some(Value::Str("hello!"))
|
||||
);
|
||||
writer.commit().expect("committed");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
assert_eq!($store.get(&reader, $key).expect("read"), Some(Value::Str("hello!")));
|
||||
assert_eq!(
|
||||
$store.get(&reader, $key).expect("read"),
|
||||
Some(Value::Str("hello!"))
|
||||
);
|
||||
}};
|
||||
}
|
||||
|
||||
|
|
|
@ -8,34 +8,25 @@
|
|||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use std::{
|
||||
fs,
|
||||
sync::Arc,
|
||||
};
|
||||
use std::{fs, sync::Arc};
|
||||
|
||||
use tempfile::Builder;
|
||||
|
||||
#[cfg(feature = "lmdb")]
|
||||
use rkv::backend::{Lmdb, LmdbEnvironment};
|
||||
use rkv::{
|
||||
backend::{
|
||||
BackendEnvironmentBuilder,
|
||||
Lmdb,
|
||||
LmdbEnvironment,
|
||||
SafeMode,
|
||||
SafeModeEnvironment,
|
||||
},
|
||||
CloseOptions,
|
||||
Rkv,
|
||||
StoreOptions,
|
||||
Value,
|
||||
backend::{BackendEnvironmentBuilder, SafeMode, SafeModeEnvironment},
|
||||
CloseOptions, Rkv, StoreOptions, Value,
|
||||
};
|
||||
|
||||
/// Test that a manager can be created with simple type inference.
|
||||
#[cfg(feature = "lmdb")]
|
||||
#[test]
|
||||
#[allow(clippy::let_underscore_lock)]
|
||||
fn test_simple() {
|
||||
type Manager = rkv::Manager<LmdbEnvironment>;
|
||||
|
||||
let _ = Manager::singleton().write().unwrap();
|
||||
let _unused = Manager::singleton().write().unwrap();
|
||||
}
|
||||
|
||||
/// Test that a manager can be created with simple type inference.
|
||||
|
@ -44,19 +35,25 @@ fn test_simple() {
|
|||
fn test_simple_safe() {
|
||||
type Manager = rkv::Manager<SafeModeEnvironment>;
|
||||
|
||||
let _ = Manager::singleton().write().unwrap();
|
||||
let _unused = Manager::singleton().write().unwrap();
|
||||
}
|
||||
|
||||
/// Test that a shared Rkv instance can be created with simple type inference.
|
||||
#[cfg(feature = "lmdb")]
|
||||
#[test]
|
||||
fn test_simple_2() {
|
||||
type Manager = rkv::Manager<LmdbEnvironment>;
|
||||
|
||||
let root = Builder::new().prefix("test_simple_2").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_simple_2")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let mut manager = Manager::singleton().write().unwrap();
|
||||
let _ = manager.get_or_create(root.path(), Rkv::new::<Lmdb>).unwrap();
|
||||
let _ = manager
|
||||
.get_or_create(root.path(), Rkv::new::<Lmdb>)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// Test that a shared Rkv instance can be created with simple type inference.
|
||||
|
@ -64,26 +61,49 @@ fn test_simple_2() {
|
|||
fn test_simple_safe_2() {
|
||||
type Manager = rkv::Manager<SafeModeEnvironment>;
|
||||
|
||||
let root = Builder::new().prefix("test_simple_safe_2").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_simple_safe_2")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let mut manager = Manager::singleton().write().unwrap();
|
||||
let _ = manager.get_or_create(root.path(), Rkv::new::<SafeMode>).unwrap();
|
||||
let _ = manager
|
||||
.get_or_create(root.path(), Rkv::new::<SafeMode>)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// Test that the manager will return the same Rkv instance each time for each path.
|
||||
#[cfg(feature = "lmdb")]
|
||||
#[test]
|
||||
fn test_same() {
|
||||
type Manager = rkv::Manager<LmdbEnvironment>;
|
||||
|
||||
let root = Builder::new().prefix("test_same").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_same")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let p = root.path();
|
||||
assert!(Manager::singleton().read().unwrap().get(p).expect("success").is_none());
|
||||
assert!(Manager::singleton()
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(p)
|
||||
.expect("success")
|
||||
.is_none());
|
||||
|
||||
let created_arc = Manager::singleton().write().unwrap().get_or_create(p, Rkv::new::<Lmdb>).expect("created");
|
||||
let fetched_arc = Manager::singleton().read().unwrap().get(p).expect("success").expect("existed");
|
||||
let created_arc = Manager::singleton()
|
||||
.write()
|
||||
.unwrap()
|
||||
.get_or_create(p, Rkv::new::<Lmdb>)
|
||||
.expect("created");
|
||||
let fetched_arc = Manager::singleton()
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(p)
|
||||
.expect("success")
|
||||
.expect("existed");
|
||||
assert!(Arc::ptr_eq(&created_arc, &fetched_arc));
|
||||
}
|
||||
|
||||
|
@ -92,23 +112,44 @@ fn test_same() {
|
|||
fn test_same_safe() {
|
||||
type Manager = rkv::Manager<SafeModeEnvironment>;
|
||||
|
||||
let root = Builder::new().prefix("test_same_safe").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_same_safe")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let p = root.path();
|
||||
assert!(Manager::singleton().read().unwrap().get(p).expect("success").is_none());
|
||||
assert!(Manager::singleton()
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(p)
|
||||
.expect("success")
|
||||
.is_none());
|
||||
|
||||
let created_arc = Manager::singleton().write().unwrap().get_or_create(p, Rkv::new::<SafeMode>).expect("created");
|
||||
let fetched_arc = Manager::singleton().read().unwrap().get(p).expect("success").expect("existed");
|
||||
let created_arc = Manager::singleton()
|
||||
.write()
|
||||
.unwrap()
|
||||
.get_or_create(p, Rkv::new::<SafeMode>)
|
||||
.expect("created");
|
||||
let fetched_arc = Manager::singleton()
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(p)
|
||||
.expect("success")
|
||||
.expect("existed");
|
||||
assert!(Arc::ptr_eq(&created_arc, &fetched_arc));
|
||||
}
|
||||
|
||||
/// Test that the manager will return the same Rkv instance each time for each path.
|
||||
#[cfg(feature = "lmdb")]
|
||||
#[test]
|
||||
fn test_same_with_capacity() {
|
||||
type Manager = rkv::Manager<LmdbEnvironment>;
|
||||
|
||||
let root = Builder::new().prefix("test_same_with_capacity").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_same_with_capacity")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let mut manager = Manager::singleton().write().unwrap();
|
||||
|
@ -116,7 +157,9 @@ fn test_same_with_capacity() {
|
|||
let p = root.path();
|
||||
assert!(manager.get(p).expect("success").is_none());
|
||||
|
||||
let created_arc = manager.get_or_create_with_capacity(p, 10, Rkv::with_capacity::<Lmdb>).expect("created");
|
||||
let created_arc = manager
|
||||
.get_or_create_with_capacity(p, 10, Rkv::with_capacity::<Lmdb>)
|
||||
.expect("created");
|
||||
let fetched_arc = manager.get(p).expect("success").expect("existed");
|
||||
assert!(Arc::ptr_eq(&created_arc, &fetched_arc));
|
||||
}
|
||||
|
@ -126,7 +169,10 @@ fn test_same_with_capacity() {
|
|||
fn test_same_with_capacity_safe() {
|
||||
type Manager = rkv::Manager<SafeModeEnvironment>;
|
||||
|
||||
let root = Builder::new().prefix("test_same_with_capacity_safe").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_same_with_capacity_safe")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let mut manager = Manager::singleton().write().unwrap();
|
||||
|
@ -134,7 +180,9 @@ fn test_same_with_capacity_safe() {
|
|||
let p = root.path();
|
||||
assert!(manager.get(p).expect("success").is_none());
|
||||
|
||||
let created_arc = manager.get_or_create_with_capacity(p, 10, Rkv::with_capacity::<SafeMode>).expect("created");
|
||||
let created_arc = manager
|
||||
.get_or_create_with_capacity(p, 10, Rkv::with_capacity::<SafeMode>)
|
||||
.expect("created");
|
||||
let fetched_arc = manager.get(p).expect("success").expect("existed");
|
||||
assert!(Arc::ptr_eq(&created_arc, &fetched_arc));
|
||||
}
|
||||
|
@ -145,20 +193,33 @@ fn test_same_with_capacity_safe() {
|
|||
fn test_safe_mode_corrupt_while_open_1() {
|
||||
type Manager = rkv::Manager<SafeModeEnvironment>;
|
||||
|
||||
let root = Builder::new().prefix("test_safe_mode_corrupt_while_open_1").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_safe_mode_corrupt_while_open_1")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
// Create environment.
|
||||
let mut manager = Manager::singleton().write().unwrap();
|
||||
let shared_env = manager.get_or_create(root.path(), Rkv::new::<SafeMode>).expect("created");
|
||||
let shared_env = manager
|
||||
.get_or_create(root.path(), Rkv::new::<SafeMode>)
|
||||
.expect("created");
|
||||
let env = shared_env.read().unwrap();
|
||||
|
||||
// Write some data.
|
||||
let store = env.open_single("store", StoreOptions::create()).expect("opened");
|
||||
let store = env
|
||||
.open_single("store", StoreOptions::create())
|
||||
.expect("opened");
|
||||
let mut writer = env.write().expect("writer");
|
||||
store.put(&mut writer, "foo", &Value::I64(1234)).expect("wrote");
|
||||
store.put(&mut writer, "bar", &Value::Bool(true)).expect("wrote");
|
||||
store.put(&mut writer, "baz", &Value::Str("héllo, yöu")).expect("wrote");
|
||||
store
|
||||
.put(&mut writer, "foo", &Value::I64(1234))
|
||||
.expect("wrote");
|
||||
store
|
||||
.put(&mut writer, "bar", &Value::Bool(true))
|
||||
.expect("wrote");
|
||||
store
|
||||
.put(&mut writer, "baz", &Value::Str("héllo, yöu"))
|
||||
.expect("wrote");
|
||||
writer.commit().expect("committed");
|
||||
env.sync(true).expect("synced");
|
||||
|
||||
|
@ -173,17 +234,23 @@ fn test_safe_mode_corrupt_while_open_1() {
|
|||
// Close everything.
|
||||
drop(env);
|
||||
drop(shared_env);
|
||||
manager.try_close(root.path(), CloseOptions::default()).expect("closed without deleting");
|
||||
manager
|
||||
.try_close(root.path(), CloseOptions::default())
|
||||
.expect("closed without deleting");
|
||||
assert!(manager.get(root.path()).expect("success").is_none());
|
||||
|
||||
// Recreating environment fails.
|
||||
manager.get_or_create(root.path(), Rkv::new::<SafeMode>).expect_err("not created");
|
||||
manager
|
||||
.get_or_create(root.path(), Rkv::new::<SafeMode>)
|
||||
.expect_err("not created");
|
||||
assert!(manager.get(root.path()).expect("success").is_none());
|
||||
|
||||
// But we can use a builder and pass `discard_if_corrupted` to deal with it.
|
||||
let mut builder = Rkv::environment_builder::<SafeMode>();
|
||||
builder.set_discard_if_corrupted(true);
|
||||
manager.get_or_create_from_builder(root.path(), builder, Rkv::from_builder::<SafeMode>).expect("created");
|
||||
manager
|
||||
.get_or_create_from_builder(root.path(), builder, Rkv::from_builder::<SafeMode>)
|
||||
.expect("created");
|
||||
assert!(manager.get(root.path()).expect("success").is_some());
|
||||
}
|
||||
|
||||
|
@ -193,20 +260,33 @@ fn test_safe_mode_corrupt_while_open_1() {
|
|||
fn test_safe_mode_corrupt_while_open_2() {
|
||||
type Manager = rkv::Manager<SafeModeEnvironment>;
|
||||
|
||||
let root = Builder::new().prefix("test_safe_mode_corrupt_while_open_2").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_safe_mode_corrupt_while_open_2")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
// Create environment.
|
||||
let mut manager = Manager::singleton().write().unwrap();
|
||||
let shared_env = manager.get_or_create(root.path(), Rkv::new::<SafeMode>).expect("created");
|
||||
let shared_env = manager
|
||||
.get_or_create(root.path(), Rkv::new::<SafeMode>)
|
||||
.expect("created");
|
||||
let env = shared_env.read().unwrap();
|
||||
|
||||
// Write some data.
|
||||
let store = env.open_single("store", StoreOptions::create()).expect("opened");
|
||||
let store = env
|
||||
.open_single("store", StoreOptions::create())
|
||||
.expect("opened");
|
||||
let mut writer = env.write().expect("writer");
|
||||
store.put(&mut writer, "foo", &Value::I64(1234)).expect("wrote");
|
||||
store.put(&mut writer, "bar", &Value::Bool(true)).expect("wrote");
|
||||
store.put(&mut writer, "baz", &Value::Str("héllo, yöu")).expect("wrote");
|
||||
store
|
||||
.put(&mut writer, "foo", &Value::I64(1234))
|
||||
.expect("wrote");
|
||||
store
|
||||
.put(&mut writer, "bar", &Value::Bool(true))
|
||||
.expect("wrote");
|
||||
store
|
||||
.put(&mut writer, "baz", &Value::Str("héllo, yöu"))
|
||||
.expect("wrote");
|
||||
writer.commit().expect("committed");
|
||||
env.sync(true).expect("synced");
|
||||
|
||||
|
@ -219,39 +299,82 @@ fn test_safe_mode_corrupt_while_open_2() {
|
|||
fs::write(&safebin, "bogus").expect("dbfile corrupted");
|
||||
|
||||
// Reading still works. Magic.
|
||||
let store = env.open_single("store", StoreOptions::default()).expect("opened");
|
||||
let store = env
|
||||
.open_single("store", StoreOptions::default())
|
||||
.expect("opened");
|
||||
let reader = env.read().expect("reader");
|
||||
assert_eq!(store.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
|
||||
assert_eq!(store.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
|
||||
assert_eq!(store.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
|
||||
assert_eq!(
|
||||
store.get(&reader, "foo").expect("read"),
|
||||
Some(Value::I64(1234))
|
||||
);
|
||||
assert_eq!(
|
||||
store.get(&reader, "bar").expect("read"),
|
||||
Some(Value::Bool(true))
|
||||
);
|
||||
assert_eq!(
|
||||
store.get(&reader, "baz").expect("read"),
|
||||
Some(Value::Str("héllo, yöu"))
|
||||
);
|
||||
reader.abort();
|
||||
|
||||
// Writing still works, dbfile will be un-corrupted.
|
||||
let store = env.open_single("store", StoreOptions::default()).expect("opened");
|
||||
let store = env
|
||||
.open_single("store", StoreOptions::default())
|
||||
.expect("opened");
|
||||
let mut writer = env.write().expect("writer");
|
||||
store.put(&mut writer, "foo2", &Value::I64(5678)).expect("wrote");
|
||||
store.put(&mut writer, "bar2", &Value::Bool(false)).expect("wrote");
|
||||
store.put(&mut writer, "baz2", &Value::Str("byé, yöu")).expect("wrote");
|
||||
store
|
||||
.put(&mut writer, "foo2", &Value::I64(5678))
|
||||
.expect("wrote");
|
||||
store
|
||||
.put(&mut writer, "bar2", &Value::Bool(false))
|
||||
.expect("wrote");
|
||||
store
|
||||
.put(&mut writer, "baz2", &Value::Str("byé, yöu"))
|
||||
.expect("wrote");
|
||||
writer.commit().expect("committed");
|
||||
env.sync(true).expect("synced");
|
||||
|
||||
// Close everything.
|
||||
drop(env);
|
||||
drop(shared_env);
|
||||
manager.try_close(root.path(), CloseOptions::default()).expect("closed without deleting");
|
||||
manager
|
||||
.try_close(root.path(), CloseOptions::default())
|
||||
.expect("closed without deleting");
|
||||
assert!(manager.get(root.path()).expect("success").is_none());
|
||||
|
||||
// Recreate environment.
|
||||
let shared_env = manager.get_or_create(root.path(), Rkv::new::<SafeMode>).expect("created");
|
||||
let shared_env = manager
|
||||
.get_or_create(root.path(), Rkv::new::<SafeMode>)
|
||||
.expect("created");
|
||||
let env = shared_env.read().unwrap();
|
||||
|
||||
// Verify that the dbfile is not corrupted.
|
||||
let store = env.open_single("store", StoreOptions::default()).expect("opened");
|
||||
let store = env
|
||||
.open_single("store", StoreOptions::default())
|
||||
.expect("opened");
|
||||
let reader = env.read().expect("reader");
|
||||
assert_eq!(store.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
|
||||
assert_eq!(store.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
|
||||
assert_eq!(store.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
|
||||
assert_eq!(store.get(&reader, "foo2").expect("read"), Some(Value::I64(5678)));
|
||||
assert_eq!(store.get(&reader, "bar2").expect("read"), Some(Value::Bool(false)));
|
||||
assert_eq!(store.get(&reader, "baz2").expect("read"), Some(Value::Str("byé, yöu")));
|
||||
assert_eq!(
|
||||
store.get(&reader, "foo").expect("read"),
|
||||
Some(Value::I64(1234))
|
||||
);
|
||||
assert_eq!(
|
||||
store.get(&reader, "bar").expect("read"),
|
||||
Some(Value::Bool(true))
|
||||
);
|
||||
assert_eq!(
|
||||
store.get(&reader, "baz").expect("read"),
|
||||
Some(Value::Str("héllo, yöu"))
|
||||
);
|
||||
assert_eq!(
|
||||
store.get(&reader, "foo2").expect("read"),
|
||||
Some(Value::I64(5678))
|
||||
);
|
||||
assert_eq!(
|
||||
store.get(&reader, "bar2").expect("read"),
|
||||
Some(Value::Bool(false))
|
||||
);
|
||||
assert_eq!(
|
||||
store.get(&reader, "baz2").expect("read"),
|
||||
Some(Value::Str("byé, yöu"))
|
||||
);
|
||||
}
|
||||
|
|
|
@ -15,36 +15,48 @@ use std::fs;
|
|||
use serde_derive::Serialize;
|
||||
use tempfile::Builder;
|
||||
|
||||
use rkv::{
|
||||
backend::Lmdb,
|
||||
PrimitiveInt,
|
||||
Rkv,
|
||||
StoreOptions,
|
||||
Value,
|
||||
};
|
||||
use rkv::{backend::SafeMode, PrimitiveInt, Rkv, StoreOptions, Value};
|
||||
|
||||
#[test]
|
||||
fn test_multi_integer_keys() {
|
||||
let root = Builder::new().prefix("test_integer_keys").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_integer_keys")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
|
||||
let k = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
|
||||
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
|
||||
let k = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
|
||||
let s = k
|
||||
.open_multi_integer("s", StoreOptions::create())
|
||||
.expect("open");
|
||||
|
||||
macro_rules! test_integer_keys {
|
||||
($store:expr, $key:expr) => {{
|
||||
let mut writer = k.write().expect("writer");
|
||||
|
||||
$store.put(&mut writer, $key, &Value::Str("hello1")).expect("write");
|
||||
$store.put(&mut writer, $key, &Value::Str("hello2")).expect("write");
|
||||
$store.put(&mut writer, $key, &Value::Str("hello3")).expect("write");
|
||||
$store
|
||||
.put(&mut writer, $key, &Value::Str("hello1"))
|
||||
.expect("write");
|
||||
$store
|
||||
.put(&mut writer, $key, &Value::Str("hello2"))
|
||||
.expect("write");
|
||||
$store
|
||||
.put(&mut writer, $key, &Value::Str("hello3"))
|
||||
.expect("write");
|
||||
let vals = $store
|
||||
.get(&writer, $key)
|
||||
.expect("read")
|
||||
.map(|result| result.expect("ok"))
|
||||
.map(|(_, v)| v)
|
||||
.collect::<Vec<Value>>();
|
||||
assert_eq!(vals, vec![Value::Str("hello1"), Value::Str("hello2"), Value::Str("hello3")]);
|
||||
assert_eq!(
|
||||
vals,
|
||||
vec![
|
||||
Value::Str("hello1"),
|
||||
Value::Str("hello2"),
|
||||
Value::Str("hello3")
|
||||
]
|
||||
);
|
||||
writer.commit().expect("committed");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
|
@ -54,7 +66,14 @@ fn test_multi_integer_keys() {
|
|||
.map(|result| result.expect("ok"))
|
||||
.map(|(_, v)| v)
|
||||
.collect::<Vec<Value>>();
|
||||
assert_eq!(vals, vec![Value::Str("hello1"), Value::Str("hello2"), Value::Str("hello3")]);
|
||||
assert_eq!(
|
||||
vals,
|
||||
vec![
|
||||
Value::Str("hello1"),
|
||||
Value::Str("hello2"),
|
||||
Value::Str("hello3")
|
||||
]
|
||||
);
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -71,7 +90,9 @@ fn test_multi_integer_keys() {
|
|||
// different integer key types, which may result in unexpected behavior.
|
||||
// Make sure you know what you're doing!
|
||||
|
||||
let t = k.open_multi_integer("s", StoreOptions::create()).expect("open");
|
||||
let t = k
|
||||
.open_multi_integer("s", StoreOptions::create())
|
||||
.expect("open");
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct I32(i32);
|
||||
|
@ -79,7 +100,9 @@ fn test_multi_integer_keys() {
|
|||
test_integer_keys!(t, I32(std::i32::MIN));
|
||||
test_integer_keys!(t, I32(std::i32::MAX));
|
||||
|
||||
let u = k.open_multi_integer("s", StoreOptions::create()).expect("open");
|
||||
let u = k
|
||||
.open_multi_integer("s", StoreOptions::create())
|
||||
.expect("open");
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct U16(u16);
|
||||
|
@ -87,7 +110,9 @@ fn test_multi_integer_keys() {
|
|||
test_integer_keys!(u, U16(std::u16::MIN));
|
||||
test_integer_keys!(u, U16(std::u16::MAX));
|
||||
|
||||
let v = k.open_multi_integer("s", StoreOptions::create()).expect("open");
|
||||
let v = k
|
||||
.open_multi_integer("s", StoreOptions::create())
|
||||
.expect("open");
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct U64(u64);
|
||||
|
|
|
@ -14,17 +14,8 @@ use std::fs;
|
|||
use tempfile::Builder;
|
||||
|
||||
use rkv::{
|
||||
backend::{
|
||||
Lmdb,
|
||||
LmdbDatabase,
|
||||
LmdbRoCursor,
|
||||
LmdbRwTransaction,
|
||||
},
|
||||
Readable,
|
||||
Rkv,
|
||||
StoreOptions,
|
||||
Value,
|
||||
Writer,
|
||||
backend::{SafeMode, SafeModeDatabase, SafeModeRoCursor, SafeModeRwTransaction},
|
||||
Readable, Rkv, StoreOptions, Value, Writer,
|
||||
};
|
||||
|
||||
/// Consider a struct like this:
|
||||
|
@ -41,14 +32,17 @@ use rkv::{
|
|||
/// Note that the reader functions take `Readable` because they might run within a Read
|
||||
/// Transaction or a Write Transaction. The test demonstrates fetching values via both.
|
||||
|
||||
type SingleStore = rkv::SingleStore<LmdbDatabase>;
|
||||
type MultiStore = rkv::MultiStore<LmdbDatabase>;
|
||||
type SingleStore = rkv::SingleStore<SafeModeDatabase>;
|
||||
type MultiStore = rkv::MultiStore<SafeModeDatabase>;
|
||||
|
||||
#[test]
|
||||
fn read_many() {
|
||||
let root = Builder::new().prefix("test_txns").tempdir().expect("tempdir");
|
||||
let root = Builder::new()
|
||||
.prefix("test_txns")
|
||||
.tempdir()
|
||||
.expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
let k = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
|
||||
let k = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
|
||||
let samplestore = k.open_single("s", StoreOptions::create()).expect("open");
|
||||
let datestore = k.open_multi("m", StoreOptions::create()).expect("open");
|
||||
let valuestore = k.open_multi("m", StoreOptions::create()).expect("open");
|
||||
|
@ -57,8 +51,8 @@ fn read_many() {
|
|||
let mut writer = k.write().expect("env write lock");
|
||||
|
||||
for id in 0..30_u64 {
|
||||
let value = format!("value{}", id);
|
||||
let date = format!("2019-06-{}", id);
|
||||
let value = format!("value{id}");
|
||||
let date = format!("2019-06-{id}");
|
||||
put_id_field(&mut writer, datestore, &date, id);
|
||||
put_id_field(&mut writer, valuestore, &value, id);
|
||||
put_sample(&mut writer, samplestore, id, &value);
|
||||
|
@ -66,49 +60,47 @@ fn read_many() {
|
|||
|
||||
// now we read in the same transaction
|
||||
for id in 0..30_u64 {
|
||||
let value = format!("value{}", id);
|
||||
let date = format!("2019-06-{}", id);
|
||||
let value = format!("value{id}");
|
||||
let date = format!("2019-06-{id}");
|
||||
let ids = get_ids_by_field(&writer, datestore, &date);
|
||||
let ids2 = get_ids_by_field(&writer, valuestore, &value);
|
||||
let samples = get_samples(&writer, samplestore, &ids);
|
||||
let samples2 = get_samples(&writer, samplestore, &ids2);
|
||||
println!("{:?}, {:?}", samples, samples2);
|
||||
println!("{samples:?}, {samples2:?}");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let reader = k.read().expect("env read lock");
|
||||
for id in 0..30_u64 {
|
||||
let value = format!("value{}", id);
|
||||
let date = format!("2019-06-{}", id);
|
||||
let value = format!("value{id}");
|
||||
let date = format!("2019-06-{id}");
|
||||
let ids = get_ids_by_field(&reader, datestore, &date);
|
||||
let ids2 = get_ids_by_field(&reader, valuestore, &value);
|
||||
let samples = get_samples(&reader, samplestore, &ids);
|
||||
let samples2 = get_samples(&reader, samplestore, &ids2);
|
||||
println!("{:?}, {:?}", samples, samples2);
|
||||
println!("{samples:?}, {samples2:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_ids_by_field<'t, T>(txn: &'t T, store: MultiStore, field: &'t str) -> Vec<u64>
|
||||
where
|
||||
T: Readable<'t, Database = LmdbDatabase, RoCursor = LmdbRoCursor<'t>>,
|
||||
T: Readable<'t, Database = SafeModeDatabase, RoCursor = SafeModeRoCursor<'t>>,
|
||||
{
|
||||
store
|
||||
.get(txn, field)
|
||||
.expect("get iterator")
|
||||
.map(|id| {
|
||||
match id.expect("field") {
|
||||
(_, Value::U64(id)) => id,
|
||||
_ => panic!("getting value in iter"),
|
||||
}
|
||||
.map(|id| match id.expect("field") {
|
||||
(_, Value::U64(id)) => id,
|
||||
_ => panic!("getting value in iter"),
|
||||
})
|
||||
.collect::<Vec<u64>>()
|
||||
}
|
||||
|
||||
fn get_samples<'t, T>(txn: &'t T, samplestore: SingleStore, ids: &[u64]) -> Vec<String>
|
||||
where
|
||||
T: Readable<'t, Database = LmdbDatabase, RoCursor = LmdbRoCursor<'t>>,
|
||||
T: Readable<'t, Database = SafeModeDatabase, RoCursor = SafeModeRoCursor<'t>>,
|
||||
{
|
||||
ids.iter()
|
||||
.map(|id| {
|
||||
|
@ -122,11 +114,18 @@ where
|
|||
.collect::<Vec<String>>()
|
||||
}
|
||||
|
||||
fn put_sample(txn: &mut Writer<LmdbRwTransaction>, samplestore: SingleStore, id: u64, value: &str) {
|
||||
fn put_sample(
|
||||
txn: &mut Writer<SafeModeRwTransaction>,
|
||||
samplestore: SingleStore,
|
||||
id: u64,
|
||||
value: &str,
|
||||
) {
|
||||
let idbytes = id.to_be_bytes();
|
||||
samplestore.put(txn, &idbytes, &Value::Str(value)).expect("put id");
|
||||
samplestore
|
||||
.put(txn, &idbytes, &Value::Str(value))
|
||||
.expect("put id");
|
||||
}
|
||||
|
||||
fn put_id_field(txn: &mut Writer<LmdbRwTransaction>, store: MultiStore, field: &str, id: u64) {
|
||||
fn put_id_field(txn: &mut Writer<SafeModeRwTransaction>, store: MultiStore, field: &str, id: u64) {
|
||||
store.put(txn, field, &Value::U64(id)).expect("put id");
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ edition = "2018"
|
|||
license = "MPL-2.0"
|
||||
|
||||
[dependencies]
|
||||
glean = "51.8.1"
|
||||
glean = "51.8.2"
|
||||
log = "0.4"
|
||||
nserror = { path = "../../../xpcom/rust/nserror" }
|
||||
nsstring = { path = "../../../xpcom/rust/nsstring" }
|
||||
|
|
|
@ -8,7 +8,7 @@ publish = false
|
|||
[dependencies]
|
||||
bincode = "1.0"
|
||||
chrono = "0.4.10"
|
||||
glean = "51.8.1"
|
||||
glean = "51.8.2"
|
||||
inherent = "1.0.0"
|
||||
log = "0.4"
|
||||
nsstring = { path = "../../../../xpcom/rust/nsstring", optional = true }
|
||||
|
|
|
@ -13,7 +13,7 @@ log = "0.4"
|
|||
moz_task = { path = "../../../xpcom/rust/moz_task" }
|
||||
nserror = { path = "../../../xpcom/rust/nserror" }
|
||||
nsstring = { path = "../../../xpcom/rust/nsstring" }
|
||||
rkv = { version = "0.17", default-features = false, features=["no-canonicalize-path"] }
|
||||
rkv = { version = "0.18", default-features = false, features=["no-canonicalize-path"] }
|
||||
storage_variant = { path = "../../../storage/variant" }
|
||||
xpcom = { path = "../../../xpcom/rust/xpcom" }
|
||||
tempfile = "3"
|
||||
|
|
|
@ -13,7 +13,7 @@ moz_task = { path = "../../../xpcom/rust/moz_task" }
|
|||
nsstring = { path = "../../../xpcom/rust/nsstring" }
|
||||
nserror = { path = "../../../xpcom/rust/nserror" }
|
||||
once_cell = "1"
|
||||
rkv = { version = "0.17", default-features = false, features=["no-canonicalize-path"] }
|
||||
rkv = { version = "0.18", default-features = false, features=["no-canonicalize-path"] }
|
||||
serde_json = "1"
|
||||
tempfile = "3"
|
||||
thiserror = "1"
|
||||
|
|
|
@ -7,5 +7,5 @@ authors = ["fuzzing@mozilla.com"]
|
|||
libc = "0.2"
|
||||
tempfile = "3"
|
||||
lazy_static = "1.4.0"
|
||||
rkv = { version = "0.17", features = ["with-fuzzer-no-link"] }
|
||||
rkv = { version = "0.18", features = ["with-fuzzer-no-link"] }
|
||||
lmdb-rkv = { version = "0.14", features = ["with-fuzzer-no-link"] }
|
||||
|
|
Загрузка…
Ссылка в новой задаче