mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Bug 1525392 - update rkv (and LMDB) to their latest stable versions r=froydnj
Changes to rkv and LMDB crates: rkv 0.7.0 -> 0.9.1 lmdb-rkv 0.9.0 -> 0.11.2 lmdb-sys 0.8.0 -> lmdb-rkv-sys 0.8.2 Update to the LMDB C library: LMDB 0.9.21 -> 0.9.23 (+ backported patch for Mozilla build issue) Other crate dependency update: lazy_static 1.0.1 -> 1.2.0 This also removes the workaround for bug 1525219 and updates the kvstore in-tree crate (and nsIKeyValueService XPCOM API) for the rkv changes. Differential Revision: https://phabricator.services.mozilla.com/D19094 --HG-- rename : third_party/rust/lmdb-rkv/Cargo.toml => third_party/rust/lmdb-rkv-sys/Cargo.toml rename : third_party/rust/lmdb-sys/build.rs => third_party/rust/lmdb-rkv-sys/build.rs rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/CHANGES => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/CHANGES rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/COPYRIGHT => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/COPYRIGHT rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/Doxyfile => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/Doxyfile rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/LICENSE => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/LICENSE rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/Makefile => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/Makefile rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/intro.doc => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/intro.doc rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/lmdb.h => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/lmdb.h rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/mdb.c => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/mdb.c rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/mdb_copy.1 => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/mdb_copy.1 rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/mdb_copy.c => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/mdb_copy.c rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/mdb_dump.1 => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/mdb_dump.1 rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/mdb_dump.c => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/mdb_dump.c rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/mdb_load.1 => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/mdb_load.1 rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/mdb_load.c => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/mdb_load.c rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/mdb_stat.1 => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/mdb_stat.1 rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/mdb_stat.c => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/mdb_stat.c rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/midl.c => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/midl.c rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/midl.h => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/midl.h rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/mtest.c => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/mtest.c rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/mtest2.c => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/mtest2.c rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/mtest3.c => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/mtest3.c rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/mtest4.c => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/mtest4.c rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/mtest5.c => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/mtest5.c rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/mtest6.c => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/mtest6.c rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/sample-bdb.txt => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/sample-bdb.txt rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/sample-mdb.txt => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/sample-mdb.txt rename : third_party/rust/lmdb-sys/lmdb/libraries/liblmdb/tooltag => third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/tooltag rename : third_party/rust/lmdb-sys/src/constants.rs => third_party/rust/lmdb-rkv-sys/src/constants.rs rename : third_party/rust/lmdb-sys/src/ffi.rs => third_party/rust/lmdb-rkv-sys/src/ffi.rs rename : third_party/rust/lmdb-sys/src/lib.rs => third_party/rust/lmdb-rkv-sys/src/lib.rs extra : moz-landing-system : lando
This commit is contained in:
parent
338f679cf8
commit
3a0aa679dd
@ -22,11 +22,6 @@ git = "https://github.com/glandium/cc-rs"
|
||||
branch = "1.0.23-clang-cl-aarch64"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source."https://github.com/mozilla/lmdb-rs"]
|
||||
git = "https://github.com/mozilla/lmdb-rs"
|
||||
branch = "lmdb-sys-0.8.0-android-fix"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source.vendored-sources]
|
||||
directory = '@top_srcdir@/third_party/rust'
|
||||
|
||||
|
63
Cargo.lock
generated
63
Cargo.lock
generated
@ -5,7 +5,7 @@ name = "Inflector"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -223,7 +223,7 @@ dependencies = [
|
||||
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clang-sys 0.26.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -579,7 +579,7 @@ dependencies = [
|
||||
"arrayvec 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -593,7 +593,7 @@ dependencies = [
|
||||
"arrayvec 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@ -801,7 +801,7 @@ name = "docopt"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (git+https://github.com/servo/serde?branch=deserialize_from_enums9)",
|
||||
@ -833,7 +833,7 @@ name = "dwrote"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (git+https://github.com/servo/serde?branch=deserialize_from_enums9)",
|
||||
@ -1039,7 +1039,7 @@ dependencies = [
|
||||
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hyper 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mozprofile 0.5.0",
|
||||
"mozrunner 0.9.0",
|
||||
@ -1304,7 +1304,7 @@ dependencies = [
|
||||
"cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mozjs_sys 0.0.0",
|
||||
@ -1348,13 +1348,13 @@ dependencies = [
|
||||
"crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lmdb-rkv 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lmdb-rkv 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"moz_task 0.1.0",
|
||||
"nserror 0.1.0",
|
||||
"nsstring 0.1.0",
|
||||
"ordered-float 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rkv 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rkv 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"storage_variant 0.1.0",
|
||||
"xpcom 0.1.0",
|
||||
]
|
||||
@ -1412,7 +1412,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.0.1"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@ -1452,7 +1452,7 @@ dependencies = [
|
||||
name = "libudev-sys"
|
||||
version = "0.1.3"
|
||||
dependencies = [
|
||||
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -1474,18 +1474,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lmdb-rkv"
|
||||
version = "0.9.0"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lmdb-sys 0.8.0 (git+https://github.com/mozilla/lmdb-rs?branch=lmdb-sys-0.8.0-android-fix)",
|
||||
"lmdb-rkv-sys 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lmdb-sys"
|
||||
version = "0.8.0"
|
||||
source = "git+https://github.com/mozilla/lmdb-rs?branch=lmdb-sys-0.8.0-android-fix#1295a0e2c0e3eeff2036ada60cb22d57663d0e74"
|
||||
name = "lmdb-rkv-sys"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.23 (git+https://github.com/glandium/cc-rs?branch=1.0.23-clang-cl-aarch64)",
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2115,7 +2115,7 @@ version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2184,16 +2184,17 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rkv"
|
||||
version = "0.7.0"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"arrayref 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lmdb-rkv 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lmdb-rkv 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ordered-float 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (git+https://github.com/servo/serde?branch=deserialize_from_enums9)",
|
||||
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@ -2463,7 +2464,7 @@ name = "string_cache"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2518,7 +2519,7 @@ dependencies = [
|
||||
"indexmap 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"malloc_size_of 0.0.1",
|
||||
"malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2720,7 +2721,7 @@ name = "thread_local"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -3055,7 +3056,7 @@ dependencies = [
|
||||
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"http 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hyper 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -3092,7 +3093,7 @@ dependencies = [
|
||||
"freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gleam 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -3258,7 +3259,7 @@ dependencies = [
|
||||
name = "xpcom_macros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@ -3414,7 +3415,7 @@ dependencies = [
|
||||
"checksum lalrpop 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f7014afd5642680074fd5dcc624d544f9eabfa281cba2c3ac56c3db6d21ad1b"
|
||||
"checksum lalrpop-snap 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0b85aa455529344133d7ecaaac04c01ed87f459deeaa0fe5422885e2095d8cdc"
|
||||
"checksum lalrpop-util 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2400aeebcd11259370d038c24821b93218dd2f33a53f53e9c8fcccca70be6696"
|
||||
"checksum lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e6412c5e2ad9584b0b8e979393122026cdd6d2a80b933f890dcd694ddbe73739"
|
||||
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
|
||||
"checksum lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce12306c4739d86ee97c23139f3a34ddf0387bbf181bc7929d287025a8c3ef6b"
|
||||
"checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef"
|
||||
"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
|
||||
@ -3422,8 +3423,8 @@ dependencies = [
|
||||
"checksum libudev 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea626d3bdf40a1c5aee3bcd4f40826970cae8d80a8fec934c82a63840094dcfe"
|
||||
"checksum libz-sys 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "3fdd64ef8ee652185674455c1d450b83cbc8ad895625d543b5324d923f82e4d8"
|
||||
"checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e"
|
||||
"checksum lmdb-rkv 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aba42e6d930590ce6625566f2d16300add86ef11335eedba0fcf29f9f4cbd8c5"
|
||||
"checksum lmdb-sys 0.8.0 (git+https://github.com/mozilla/lmdb-rs?branch=lmdb-sys-0.8.0-android-fix)" = "<none>"
|
||||
"checksum lmdb-rkv 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1452294309db7977dc75e1e8135a8c654d9e52e04ff0c0bd06c880897a91defd"
|
||||
"checksum lmdb-rkv-sys 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96846a2e6785ec0fce6577479d18273c8e5b287e6df8a1b398b7f0f7a41cdcbb"
|
||||
"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
|
||||
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
|
||||
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
|
||||
@ -3488,7 +3489,7 @@ dependencies = [
|
||||
"checksum regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75ecf88252dce580404a22444fc7d626c01815debba56a7f4f536772a5ff19d3"
|
||||
"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db"
|
||||
"checksum regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1ac0f60d675cc6cf13a20ec076568254472551051ad5dd050364d70671bf6b"
|
||||
"checksum rkv 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "79504d734e64f3d9391fbcaf15ca247421da461b95b9cdebd9af5679a4cfd8c8"
|
||||
"checksum rkv 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "967f320b7357a64909224619c90c1832f4532c3f19ec24350860bd64c2c7e272"
|
||||
"checksum ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "da06feaa07f69125ab9ddc769b11de29090122170b402547f64b86fe16ebc399"
|
||||
"checksum runloop 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d79b4b604167921892e84afbbaad9d5ad74e091bf6c511d9dbfb0593f09fabd"
|
||||
"checksum rust-ini 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8a654c5bda722c699be6b0fe4c0d90de218928da5b724c3e467fc48865c37263"
|
||||
|
@ -58,7 +58,6 @@ codegen-units = 1
|
||||
|
||||
[patch.crates-io]
|
||||
libudev-sys = { path = "dom/webauthn/libudev-sys" }
|
||||
lmdb-sys = { git = "https://github.com/mozilla/lmdb-rs", branch = "lmdb-sys-0.8.0-android-fix" }
|
||||
serde_derive = { git = "https://github.com/servo/serde", branch = "deserialize_from_enums9" }
|
||||
winapi = { git = "https://github.com/froydnj/winapi-rs", branch = "aarch64" }
|
||||
cc = { git = "https://github.com/glandium/cc-rs", branch = "1.0.23-clang-cl-aarch64" }
|
||||
|
@ -1 +1 @@
|
||||
{"files":{"Cargo.toml":"64e1cd36c70ec172cab7e96c5faa3c670f9313f677c90db977224f9b24a7d468","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0621878e61f0d0fda054bcbe02df75192c28bde1ecc8289cbd86aeba2dd72720","README.md":"7daae430cf5936e151386856293024e1466cddf62f27a9ff7ee3ef1511698514","appveyor.yml":"d17efb6bab4af26aa0048930de8bd3310b8d8a9961946a7962fe9fef31f96720","src/core_lazy.rs":"f20f2fc2bb751cf74622b05ec44675b6a29bfaa67d91a2e55485c665647d2904","src/lazy.rs":"a62cc96b7177a68b25e993592b08a6c706e9020fd565a55afa1fb657efa4052c","src/lib.rs":"75eee349be03ac278c1183cd861ffd0117b7ab7fffd4d46d0a1e21b9c48eab9b","src/nightly_lazy.rs":"7c00b832e907efeee16a01e1739fa536cd01b97a31d71f00d72dcabcf2e4e428","tests/no_std.rs":"2a5236bd3892a253855b4dc192f63138239165fa23b9c3421a9faa5482c780aa","tests/test.rs":"12b100f4790037ca049692d896114d6361373c5321c29e0032c290ee39f1042c"},"package":"e6412c5e2ad9584b0b8e979393122026cdd6d2a80b933f890dcd694ddbe73739"}
|
||||
{"files":{"Cargo.toml":"9501e790a183ddbc845edba899bffa05f573c43fa5f79ef065ead842d056fa85","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0621878e61f0d0fda054bcbe02df75192c28bde1ecc8289cbd86aeba2dd72720","README.md":"f2e94da8b77ac2a097dbc4b93b35912ef41b725624512d83ea968951dd5bdc7d","src/core_lazy.rs":"6b9fb6a4f553058e240756125b6b9ca43a83ed1fb72964343038ea0ea2e1af10","src/inline_lazy.rs":"2ae9a04c5bff40e80194f65b01012f0b42efa527bf717e176c68b4ca5212043c","src/lib.rs":"3defd7a82feced71862161a3c36fcff7cef3e08a51596b2e15d629b9a171a75a","tests/no_std.rs":"d68b149ee51ef5ae2b2906c0c94f5a9812d3b02811b13365c5a35e2ef90d25cf","tests/test.rs":"8e809c0f0332a3a60fca0113128cdab2cdbee92f03db523cdc4e82f4cd4b9f22"},"package":"a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"}
|
9
third_party/rust/lazy_static/Cargo.toml
vendored
9
third_party/rust/lazy_static/Cargo.toml
vendored
@ -12,8 +12,9 @@
|
||||
|
||||
[package]
|
||||
name = "lazy_static"
|
||||
version = "1.0.1"
|
||||
version = "1.2.0"
|
||||
authors = ["Marvin Löbel <loebel.marvin@gmail.com>"]
|
||||
exclude = ["/.travis.yml", "/appveyor.yml"]
|
||||
description = "A macro for declaring lazily evaluated statics in Rust."
|
||||
documentation = "https://docs.rs/lazy_static"
|
||||
readme = "README.md"
|
||||
@ -22,12 +23,14 @@ categories = ["no-std", "rust-patterns", "memory-management"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/rust-lang-nursery/lazy-static.rs"
|
||||
[dependencies.spin]
|
||||
version = "0.4.6"
|
||||
version = "0.4.10"
|
||||
features = ["once"]
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[features]
|
||||
nightly = []
|
||||
spin_no_std = ["nightly", "spin"]
|
||||
spin_no_std = ["spin"]
|
||||
[badges.appveyor]
|
||||
repository = "rust-lang-nursery/lazy-static.rs"
|
||||
|
||||
|
12
third_party/rust/lazy_static/README.md
vendored
12
third_party/rust/lazy_static/README.md
vendored
@ -9,6 +9,16 @@ This includes anything requiring heap allocations, like vectors or hash maps,
|
||||
as well as anything that requires non-const function calls to be computed.
|
||||
|
||||
[![Travis-CI Status](https://travis-ci.org/rust-lang-nursery/lazy-static.rs.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/lazy-static.rs)
|
||||
[![Latest version](https://img.shields.io/crates/v/lazy_static.svg)](https://crates.io/crates/lazy_static)
|
||||
[![Documentation](https://docs.rs/lazy_static/badge.svg)](https://docs.rs/lazy_static)
|
||||
[![License](https://img.shields.io/crates/l/lazy_static.svg)](https://github.com/rust-lang-nursery/lazy-static.rs#license)
|
||||
|
||||
## Minimum supported `rustc`
|
||||
|
||||
`1.24.1+`
|
||||
|
||||
This version is explicitly tested in CI and may only be bumped in new minor versions. Any changes to the supported minimum version will be called out in the release notes.
|
||||
|
||||
|
||||
# Getting Started
|
||||
|
||||
@ -21,7 +31,7 @@ Add the following dependency to your Cargo manifest...
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
lazy_static = "1.0"
|
||||
lazy_static = "1.2.0"
|
||||
```
|
||||
|
||||
...and see the [docs](https://docs.rs/lazy_static) for how to use it.
|
||||
|
61
third_party/rust/lazy_static/appveyor.yml
vendored
61
third_party/rust/lazy_static/appveyor.yml
vendored
@ -1,61 +0,0 @@
|
||||
environment:
|
||||
global:
|
||||
PROJECT_NAME: lazy_static
|
||||
# When this was added there were revocation check failures when using the
|
||||
# libcurl backend as libcurl checks by default, but rustup doesn't provide the
|
||||
# switch to turn this off. Switch to Hyper which looks to not check for
|
||||
# revocation by default like libcurl does.
|
||||
RUSTUP_USE_REQWEST: 1
|
||||
CARGO_HTTP_CHECK_REVOKE: false
|
||||
matrix:
|
||||
# Stable channel
|
||||
- TARGET: i686-pc-windows-gnu
|
||||
CHANNEL: stable
|
||||
- TARGET: i686-pc-windows-msvc
|
||||
CHANNEL: stable
|
||||
- TARGET: x86_64-pc-windows-gnu
|
||||
CHANNEL: stable
|
||||
- TARGET: x86_64-pc-windows-msvc
|
||||
CHANNEL: stable
|
||||
# Beta channel
|
||||
- TARGET: i686-pc-windows-gnu
|
||||
CHANNEL: beta
|
||||
- TARGET: i686-pc-windows-msvc
|
||||
CHANNEL: beta
|
||||
- TARGET: x86_64-pc-windows-gnu
|
||||
CHANNEL: beta
|
||||
- TARGET: x86_64-pc-windows-msvc
|
||||
CHANNEL: beta
|
||||
# Nightly channel
|
||||
- TARGET: i686-pc-windows-gnu
|
||||
CHANNEL: nightly
|
||||
- TARGET: i686-pc-windows-msvc
|
||||
CHANNEL: nightly
|
||||
- TARGET: x86_64-pc-windows-gnu
|
||||
CHANNEL: nightly
|
||||
- TARGET: x86_64-pc-windows-msvc
|
||||
CHANNEL: nightly
|
||||
|
||||
# Install Rust and Cargo
|
||||
# (Based on from https://github.com/rust-lang/libc/blob/master/appveyor.yml)
|
||||
install:
|
||||
- appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
|
||||
- rustup-init.exe -y --default-toolchain %CHANNEL% --default-host %TARGET%
|
||||
- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
|
||||
- if "%TARGET%" == "i686-pc-windows-gnu" set PATH=%PATH%;C:\msys64\mingw32\bin
|
||||
- if "%TARGET%" == "x86_64-pc-windows-gnu" set PATH=%PATH%;C:\msys64\mingw64\bin
|
||||
- rustc -V
|
||||
- cargo -V
|
||||
|
||||
build: false
|
||||
|
||||
test_script:
|
||||
- cargo build --verbose
|
||||
- cargo test
|
||||
- if [%CHANNEL%]==[nightly] (
|
||||
cd compiletest &&
|
||||
cargo clean &&
|
||||
cargo build --verbose &&
|
||||
cargo test &&
|
||||
cd ../
|
||||
)
|
@ -12,10 +12,7 @@ use self::spin::Once;
|
||||
pub struct Lazy<T: Sync>(Once<T>);
|
||||
|
||||
impl<T: Sync> Lazy<T> {
|
||||
#[inline(always)]
|
||||
pub const fn new() -> Self {
|
||||
Lazy(Once::new())
|
||||
}
|
||||
pub const INIT: Self = Lazy(Once::INIT);
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get<F>(&'static self, builder: F) -> &T
|
||||
@ -29,6 +26,6 @@ impl<T: Sync> Lazy<T> {
|
||||
#[doc(hidden)]
|
||||
macro_rules! __lazy_static_create {
|
||||
($NAME:ident, $T:ty) => {
|
||||
static $NAME: $crate::lazy::Lazy<$T> = $crate::lazy::Lazy::new();
|
||||
static $NAME: $crate::lazy::Lazy<$T> = $crate::lazy::Lazy::INIT;
|
||||
}
|
||||
}
|
||||
|
65
third_party/rust/lazy_static/src/inline_lazy.rs
vendored
Normal file
65
third_party/rust/lazy_static/src/inline_lazy.rs
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright 2016 lazy-static.rs Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
|
||||
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
|
||||
// http://opensource.org/licenses/MIT>, at your option. This file may not be
|
||||
// copied, modified, or distributed except according to those terms.
|
||||
|
||||
extern crate core;
|
||||
extern crate std;
|
||||
|
||||
use self::std::prelude::v1::*;
|
||||
use self::std::cell::Cell;
|
||||
use self::std::sync::Once;
|
||||
pub use self::std::sync::ONCE_INIT;
|
||||
|
||||
// FIXME: Replace Option<T> with MaybeInitialized<T>
|
||||
pub struct Lazy<T: Sync>(Cell<Option<T>>, Once);
|
||||
|
||||
impl<T: Sync> Lazy<T> {
|
||||
pub const INIT: Self = Lazy(Cell::new(None), ONCE_INIT);
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get<F>(&'static self, f: F) -> &T
|
||||
where
|
||||
F: FnOnce() -> T,
|
||||
{
|
||||
self.1.call_once(|| {
|
||||
self.0.set(Some(f()));
|
||||
});
|
||||
|
||||
// `self.0` is guaranteed to be `Some` by this point
|
||||
// The `Once` will catch and propegate panics
|
||||
unsafe {
|
||||
match *self.0.as_ptr() {
|
||||
Some(ref x) => x,
|
||||
None => {
|
||||
debug_assert!(false, "attempted to derefence an uninitialized lazy static. This is a bug");
|
||||
|
||||
unreachable_unchecked()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: Sync> Sync for Lazy<T> {}
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! __lazy_static_create {
|
||||
($NAME:ident, $T:ty) => {
|
||||
static $NAME: $crate::lazy::Lazy<$T> = $crate::lazy::Lazy::INIT;
|
||||
};
|
||||
}
|
||||
|
||||
/// Polyfill for std::hint::unreachable_unchecked. There currently exists a
|
||||
/// [crate](https://docs.rs/unreachable) for an equivalent to std::hint::unreachable_unchecked, but
|
||||
/// lazy_static currently doesn't include any runtime dependencies and we've chosen to include this
|
||||
/// short polyfill rather than include a new crate in every consumer's build.
|
||||
///
|
||||
/// This should be replaced by std's version when lazy_static starts to require at least Rust 1.27.
|
||||
unsafe fn unreachable_unchecked() -> ! {
|
||||
enum Void {}
|
||||
match std::mem::uninitialized::<Void>() {}
|
||||
}
|
40
third_party/rust/lazy_static/src/lazy.rs
vendored
40
third_party/rust/lazy_static/src/lazy.rs
vendored
@ -1,40 +0,0 @@
|
||||
// Copyright 2016 lazy-static.rs Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
|
||||
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
|
||||
// http://opensource.org/licenses/MIT>, at your option. This file may not be
|
||||
// copied, modified, or distributed except according to those terms.
|
||||
|
||||
extern crate std;
|
||||
|
||||
use self::std::prelude::v1::*;
|
||||
use self::std::sync::Once;
|
||||
pub use self::std::sync::ONCE_INIT;
|
||||
|
||||
pub struct Lazy<T: Sync>(pub *const T, pub Once);
|
||||
|
||||
impl<T: Sync> Lazy<T> {
|
||||
#[inline(always)]
|
||||
pub fn get<F>(&'static mut self, f: F) -> &T
|
||||
where F: FnOnce() -> T
|
||||
{
|
||||
unsafe {
|
||||
let r = &mut self.0;
|
||||
self.1.call_once(|| {
|
||||
*r = Box::into_raw(Box::new(f()));
|
||||
});
|
||||
|
||||
&*self.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: Sync> Sync for Lazy<T> {}
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! __lazy_static_create {
|
||||
($NAME:ident, $T:ty) => {
|
||||
static mut $NAME: $crate::lazy::Lazy<$T> = $crate::lazy::Lazy(0 as *const $T, $crate::lazy::ONCE_INIT);
|
||||
}
|
||||
}
|
36
third_party/rust/lazy_static/src/lib.rs
vendored
36
third_party/rust/lazy_static/src/lib.rs
vendored
@ -100,22 +100,15 @@ no guarantees can be made about them in regard to SemVer stability.
|
||||
|
||||
*/
|
||||
|
||||
#![cfg_attr(feature="spin_no_std", feature(const_fn))]
|
||||
#![cfg_attr(feature="nightly", feature(unreachable))]
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/lazy_static/1.0.1")]
|
||||
#![doc(html_root_url = "https://docs.rs/lazy_static/1.2.0")]
|
||||
#![no_std]
|
||||
|
||||
#[cfg(not(feature="nightly"))]
|
||||
#[cfg(not(feature = "spin_no_std"))]
|
||||
#[path="inline_lazy.rs"]
|
||||
#[doc(hidden)]
|
||||
pub mod lazy;
|
||||
|
||||
#[cfg(all(feature="nightly", not(feature="spin_no_std")))]
|
||||
#[path="nightly_lazy.rs"]
|
||||
#[doc(hidden)]
|
||||
pub mod lazy;
|
||||
|
||||
#[cfg(all(feature="nightly", feature="spin_no_std"))]
|
||||
#[cfg(feature = "spin_no_std")]
|
||||
#[path="core_lazy.rs"]
|
||||
#[doc(hidden)]
|
||||
pub mod lazy;
|
||||
@ -123,7 +116,7 @@ pub mod lazy;
|
||||
#[doc(hidden)]
|
||||
pub use core::ops::Deref as __Deref;
|
||||
|
||||
#[macro_export]
|
||||
#[macro_export(local_inner_macros)]
|
||||
#[doc(hidden)]
|
||||
macro_rules! __lazy_static_internal {
|
||||
// optional visibility restrictions are wrapped in `()` to allow for
|
||||
@ -136,19 +129,16 @@ macro_rules! __lazy_static_internal {
|
||||
(@TAIL, $N:ident : $T:ty = $e:expr) => {
|
||||
impl $crate::__Deref for $N {
|
||||
type Target = $T;
|
||||
#[allow(unsafe_code)]
|
||||
fn deref(&self) -> &$T {
|
||||
unsafe {
|
||||
#[inline(always)]
|
||||
fn __static_ref_initialize() -> $T { $e }
|
||||
#[inline(always)]
|
||||
fn __static_ref_initialize() -> $T { $e }
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn __stability() -> &'static $T {
|
||||
__lazy_static_create!(LAZY, $T);
|
||||
LAZY.get(__static_ref_initialize)
|
||||
}
|
||||
__stability()
|
||||
#[inline(always)]
|
||||
fn __stability() -> &'static $T {
|
||||
__lazy_static_create!(LAZY, $T);
|
||||
LAZY.get(__static_ref_initialize)
|
||||
}
|
||||
__stability()
|
||||
}
|
||||
}
|
||||
impl $crate::LazyStatic for $N {
|
||||
@ -170,7 +160,7 @@ macro_rules! __lazy_static_internal {
|
||||
() => ()
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! lazy_static {
|
||||
($(#[$attr:meta])* static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
|
||||
// use `()` to explicitly forward the information about private items
|
||||
|
45
third_party/rust/lazy_static/src/nightly_lazy.rs
vendored
45
third_party/rust/lazy_static/src/nightly_lazy.rs
vendored
@ -1,45 +0,0 @@
|
||||
// Copyright 2016 lazy-static.rs Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
|
||||
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
|
||||
// http://opensource.org/licenses/MIT>, at your option. This file may not be
|
||||
// copied, modified, or distributed except according to those terms.
|
||||
|
||||
extern crate std;
|
||||
extern crate core;
|
||||
|
||||
use self::std::prelude::v1::*;
|
||||
use self::std::sync::Once;
|
||||
pub use self::std::sync::ONCE_INIT;
|
||||
|
||||
pub struct Lazy<T: Sync>(pub Option<T>, pub Once);
|
||||
|
||||
impl<T: Sync> Lazy<T> {
|
||||
#[inline(always)]
|
||||
pub fn get<F>(&'static mut self, f: F) -> &T
|
||||
where F: FnOnce() -> T
|
||||
{
|
||||
{
|
||||
let r = &mut self.0;
|
||||
self.1.call_once(|| {
|
||||
*r = Some(f());
|
||||
});
|
||||
}
|
||||
unsafe {
|
||||
match self.0 {
|
||||
Some(ref x) => x,
|
||||
None => core::hint::unreachable_unchecked(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: Sync> Sync for Lazy<T> {}
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! __lazy_static_create {
|
||||
($NAME:ident, $T:ty) => {
|
||||
static mut $NAME: $crate::lazy::Lazy<$T> = $crate::lazy::Lazy(None, $crate::lazy::ONCE_INIT);
|
||||
}
|
||||
}
|
1
third_party/rust/lazy_static/tests/no_std.rs
vendored
1
third_party/rust/lazy_static/tests/no_std.rs
vendored
@ -1,5 +1,4 @@
|
||||
#![cfg(feature="spin_no_std")]
|
||||
#![feature(const_fn)]
|
||||
|
||||
#![no_std]
|
||||
|
||||
|
2
third_party/rust/lazy_static/tests/test.rs
vendored
2
third_party/rust/lazy_static/tests/test.rs
vendored
@ -1,5 +1,3 @@
|
||||
#![cfg_attr(feature="nightly", feature(const_fn))]
|
||||
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
use std::collections::HashMap;
|
||||
|
1
third_party/rust/lmdb-rkv-sys/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/lmdb-rkv-sys/.cargo-checksum.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"files":{"Cargo.toml":"89945728564108bb284dc515a9048ffaae5016b58ea8781d9f6af7e6d4ce9000","build.rs":"4204dd0891e2eca08cb7cbcccfb36d1bdac137651c383f4a36368478fd836402","lmdb/libraries/liblmdb/CHANGES":"12f41155ee12375b7ddeabd2f793399d3216e92bc44f1122d6f305b7637c2fec","lmdb/libraries/liblmdb/COPYRIGHT":"7cf04234accacc7b41b73fe6b3b19759fa49dee1ce705a9fa6533900400e4cca","lmdb/libraries/liblmdb/Doxyfile":"5545f6b049040ce58e6d1a603eaea6b7fb8ae92459f2ab8d3bcbacabcce1014d","lmdb/libraries/liblmdb/LICENSE":"310fe25c858a9515fc8c8d7d1f24a67c9496f84a91e0a0e41ea9975b1371e569","lmdb/libraries/liblmdb/Makefile":"60b5f574e6642602f692a95956da61c588a265ad50b8059960c230b9e6aaf4fd","lmdb/libraries/liblmdb/intro.doc":"9442e0db4fc9c70f058c43545e710476d8d5a80b959d20f4381240fd50c6b843","lmdb/libraries/liblmdb/lmdb.h":"a8194f7a061f4168d99de3c80464de5d279b2c851c24fdd102f1f14dd5828a77","lmdb/libraries/liblmdb/mdb.c":"87d29ea006d0c4dc31a1bc960e37db33c971abe8b3e73de5041813e0333ad8b5","lmdb/libraries/liblmdb/mdb_copy.1":"3a6a8a7a91e1bd42dc4d2a0188ff62d699ff2b3b097a670f30681decf63f22f3","lmdb/libraries/liblmdb/mdb_copy.c":"d3d412a770a5c3afeb88c44b4acdde0f0b985cde22497198e8f38296281cdddd","lmdb/libraries/liblmdb/mdb_dump.1":"9257be883c7fcfcbd61003cc730f7c0900fa8f6feba074c8c1e46634a257b13a","lmdb/libraries/liblmdb/mdb_dump.c":"b046cffcd997254e6daea47a2d7fb74f9d23282174cbb1e3bf9f5fb51a90fe64","lmdb/libraries/liblmdb/mdb_load.1":"ea927473245a4a7777ba687aa26baf7f0951fb620daf82b8d730a090185b2bbc","lmdb/libraries/liblmdb/mdb_load.c":"4f722613c65350315db23060be98584fb572978108885dab271101ba7187dca4","lmdb/libraries/liblmdb/mdb_stat.1":"c0a70d96b4b2d32e73301383d9d5620bc0bbbefb019bfd54f32088dfd4bc921a","lmdb/libraries/liblmdb/mdb_stat.c":"e6405fa191d784ecfa8eb8d1f153a58facc49a8f5a2c891a93802e67acc4861e","lmdb/libraries/liblmdb/midl.c":"92b0933c7736443448018a93f9588e9e26ae2e242f91b19211dea9ed3ab91141","lmdb/libraries/liblmdb/midl.h":"8e01e6c3b1cbd2e93a5a95686a6dd0ca43878b2b8cf0ba53962ccfe355605354","lmdb/libraries/liblmdb/mtest.c":"89ab9ac8bf1e14a9f32a33757c4b3254e4984e0f24e5a302e2d126eb2c86f6db","lmdb/libraries/liblmdb/mtest2.c":"076b00395fe1461dd9577f7bb5567908ce50cf470efbf652787e6fe1dc2fb68c","lmdb/libraries/liblmdb/mtest3.c":"51b9a055e123bd0757ee3082cc6864c836969cf630e646a9cc34e01398c20634","lmdb/libraries/liblmdb/mtest4.c":"b0a725405d80bda6ab95b3ecf410ae330ab8df7a081ca81dd6ea1f8db87642e9","lmdb/libraries/liblmdb/mtest5.c":"7f3b06ca3833315ea4c70d5e91feb1b677f6949f105f4f89d96c3ac35e104f2f","lmdb/libraries/liblmdb/mtest6.c":"e4d7880c36547ebf33bc020046730bf2c075c53aaacd5c876152cc5ae7ab5e6c","lmdb/libraries/liblmdb/sample-bdb.txt":"153d84f8fc49a3abba53ed52d5a41c8d6d4698753a10bbe0689a9e65d3513513","lmdb/libraries/liblmdb/sample-mdb.txt":"1f77385786cffdf72b33da06a91a444fe2827673c3627f89110903a8fe012795","lmdb/libraries/liblmdb/tooltag":"4734c6dc1fa7aec8c2e9646bd04bc5218ef6a03ad83a3b18de2ac4069eb94120","src/constants.rs":"af67740b5acccdc71b2267ec051bb60e5433c4f0313fe16dc0627376a52dcdff","src/ffi.rs":"caa9bbfb3868a7a9e9ad822d775e60ffa8c8c2f2450ac4ed403a93ddb7547899","src/lib.rs":"1d3222feec7b2b4e0902c3b9d7d37d51f5ae5cce8a3ff3dcf0256b7d78f0fecb"},"package":"96846a2e6785ec0fce6577479d18273c8e5b287e6df8a1b398b7f0f7a41cdcbb"}
|
31
third_party/rust/lmdb-rkv-sys/Cargo.toml
vendored
Normal file
31
third_party/rust/lmdb-rkv-sys/Cargo.toml
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "lmdb-rkv-sys"
|
||||
version = "0.8.2"
|
||||
authors = ["Dan Burkert <dan@danburkert.com>"]
|
||||
build = "build.rs"
|
||||
description = "Rust bindings for liblmdb."
|
||||
documentation = "https://docs.rs/lmdb-rkv-sys"
|
||||
readme = "../README.md"
|
||||
keywords = ["LMDB", "database", "storage-engine", "bindings", "library"]
|
||||
categories = ["database", "external-ffi-bindings"]
|
||||
license = "Apache-2.0"
|
||||
repository = "https://github.com/mozilla/lmdb-rs.git"
|
||||
[dependencies.libc]
|
||||
version = "0.2"
|
||||
[build-dependencies.cc]
|
||||
version = "1"
|
||||
|
||||
[build-dependencies.pkg-config]
|
||||
version = "0.3.2"
|
@ -1,5 +1,20 @@
|
||||
LMDB 0.9 Change Log
|
||||
|
||||
LMDB 0.9.23 Release (2018/12/19)
|
||||
ITS#8756 Fix loose pages in dirty list
|
||||
ITS#8831 Fix mdb_load flag init
|
||||
ITS#8844 Fix mdb_env_close in forked process
|
||||
Documentation
|
||||
ITS#8857 mdb_cursor_del doesn't invalidate cursor
|
||||
ITS#8908 GET_MULTIPLE etc don't change passed in key
|
||||
|
||||
LMDB 0.9.22 Release (2018/03/22)
|
||||
Fix MDB_DUPSORT alignment bug (ITS#8819)
|
||||
Fix regression with new db from 0.9.19 (ITS#8760)
|
||||
Fix liblmdb to build on Solaris (ITS#8612)
|
||||
Fix delete behavior with DUPSORT DB (ITS#8622)
|
||||
Fix mdb_cursor_get/mdb_cursor_del behavior (ITS#8722)
|
||||
|
||||
LMDB 0.9.21 Release (2017/06/01)
|
||||
Fix xcursor after cursor_del (ITS#8622)
|
||||
|
@ -1,4 +1,4 @@
|
||||
Copyright 2011-2017 Howard Chu, Symas Corp.
|
||||
Copyright 2011-2018 Howard Chu, Symas Corp.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2017 Howard Chu, Symas Corp.
|
||||
* Copyright 2015-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
@ -135,7 +135,7 @@
|
||||
*
|
||||
* @author Howard Chu, Symas Corporation.
|
||||
*
|
||||
* @copyright Copyright 2011-2017 Howard Chu, Symas Corp. All rights reserved.
|
||||
* @copyright Copyright 2011-2018 Howard Chu, Symas Corp. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
@ -200,7 +200,7 @@ typedef int mdb_filehandle_t;
|
||||
/** Library minor version */
|
||||
#define MDB_VERSION_MINOR 9
|
||||
/** Library patch version */
|
||||
#define MDB_VERSION_PATCH 21
|
||||
#define MDB_VERSION_PATCH 23
|
||||
|
||||
/** Combine args a,b,c into a single integer for easy version comparisons */
|
||||
#define MDB_VERINT(a,b,c) (((a) << 24) | ((b) << 16) | (c))
|
||||
@ -210,7 +210,7 @@ typedef int mdb_filehandle_t;
|
||||
MDB_VERINT(MDB_VERSION_MAJOR,MDB_VERSION_MINOR,MDB_VERSION_PATCH)
|
||||
|
||||
/** The release date of this library version */
|
||||
#define MDB_VERSION_DATE "June 1, 2017"
|
||||
#define MDB_VERSION_DATE "December 19, 2018"
|
||||
|
||||
/** A stringifier for the version info */
|
||||
#define MDB_VERSTR(a,b,c,d) "LMDB " #a "." #b "." #c ": (" d ")"
|
||||
@ -370,7 +370,7 @@ typedef enum MDB_cursor_op {
|
||||
MDB_GET_BOTH, /**< Position at key/data pair. Only for #MDB_DUPSORT */
|
||||
MDB_GET_BOTH_RANGE, /**< position at key, nearest data. Only for #MDB_DUPSORT */
|
||||
MDB_GET_CURRENT, /**< Return key/data at current cursor position */
|
||||
MDB_GET_MULTIPLE, /**< Return key and up to a page of duplicate data items
|
||||
MDB_GET_MULTIPLE, /**< Return up to a page of duplicate data items
|
||||
from current cursor position. Move cursor to prepare
|
||||
for #MDB_NEXT_MULTIPLE. Only for #MDB_DUPFIXED */
|
||||
MDB_LAST, /**< Position at last key/data item */
|
||||
@ -379,7 +379,7 @@ typedef enum MDB_cursor_op {
|
||||
MDB_NEXT, /**< Position at next data item */
|
||||
MDB_NEXT_DUP, /**< Position at next data item of current key.
|
||||
Only for #MDB_DUPSORT */
|
||||
MDB_NEXT_MULTIPLE, /**< Return key and up to a page of duplicate data items
|
||||
MDB_NEXT_MULTIPLE, /**< Return up to a page of duplicate data items
|
||||
from next cursor position. Move cursor to prepare
|
||||
for #MDB_NEXT_MULTIPLE. Only for #MDB_DUPFIXED */
|
||||
MDB_NEXT_NODUP, /**< Position at first data item of next key */
|
||||
@ -390,7 +390,7 @@ typedef enum MDB_cursor_op {
|
||||
MDB_SET, /**< Position at specified key */
|
||||
MDB_SET_KEY, /**< Position at specified key, return key + data */
|
||||
MDB_SET_RANGE, /**< Position at first key greater than or equal to specified key. */
|
||||
MDB_PREV_MULTIPLE /**< Position at previous page and return key and up to
|
||||
MDB_PREV_MULTIPLE /**< Position at previous page and return up to
|
||||
a page of duplicate data items. Only for #MDB_DUPFIXED */
|
||||
} MDB_cursor_op;
|
||||
|
||||
@ -1510,6 +1510,10 @@ int mdb_cursor_put(MDB_cursor *cursor, MDB_val *key, MDB_val *data,
|
||||
/** @brief Delete current key/data pair
|
||||
*
|
||||
* This function deletes the key/data pair to which the cursor refers.
|
||||
* This does not invalidate the cursor, so operations such as MDB_NEXT
|
||||
* can still be used on it.
|
||||
* Both MDB_NEXT and MDB_GET_CURRENT will return the same record after
|
||||
* this operation.
|
||||
* @param[in] cursor A cursor handle returned by #mdb_cursor_open()
|
||||
* @param[in] flags Options for this operation. This parameter
|
||||
* must be set to 0 or one of the values described here.
|
@ -5,7 +5,7 @@
|
||||
* BerkeleyDB API, but much simplified.
|
||||
*/
|
||||
/*
|
||||
* Copyright 2011-2017 Howard Chu, Symas Corp.
|
||||
* Copyright 2011-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -113,6 +113,10 @@ typedef SSIZE_T ssize_t;
|
||||
/* Most platforms have posix_memalign, older may only have memalign */
|
||||
#define HAVE_MEMALIGN 1
|
||||
#include <malloc.h>
|
||||
/* On Solaris, we need the POSIX sigwait function */
|
||||
#if defined (__sun)
|
||||
# define _POSIX_PTHREAD_SEMANTICS 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !(defined(BYTE_ORDER) || defined(__BYTE_ORDER))
|
||||
@ -1222,17 +1226,19 @@ typedef struct MDB_xcursor {
|
||||
unsigned char mx_dbflag;
|
||||
} MDB_xcursor;
|
||||
|
||||
/** Check if there is an inited xcursor, so #XCURSOR_REFRESH() is proper */
|
||||
/** Check if there is an inited xcursor */
|
||||
#define XCURSOR_INITED(mc) \
|
||||
((mc)->mc_xcursor && ((mc)->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED))
|
||||
|
||||
/** Update sub-page pointer, if any, in \b mc->mc_xcursor. Needed
|
||||
/** Update the xcursor's sub-page pointer, if any, in \b mc. Needed
|
||||
* when the node which contains the sub-page may have moved. Called
|
||||
* with \b mp = mc->mc_pg[mc->mc_top], \b ki = mc->mc_ki[mc->mc_top].
|
||||
* with leaf page \b mp = mc->mc_pg[\b top].
|
||||
*/
|
||||
#define XCURSOR_REFRESH(mc, mp, ki) do { \
|
||||
#define XCURSOR_REFRESH(mc, top, mp) do { \
|
||||
MDB_page *xr_pg = (mp); \
|
||||
MDB_node *xr_node = NODEPTR(xr_pg, ki); \
|
||||
MDB_node *xr_node; \
|
||||
if (!XCURSOR_INITED(mc) || (mc)->mc_ki[top] >= NUMKEYS(xr_pg)) break; \
|
||||
xr_node = NODEPTR(xr_pg, (mc)->mc_ki[top]); \
|
||||
if ((xr_node->mn_flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA) \
|
||||
(mc)->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(xr_node); \
|
||||
} while (0)
|
||||
@ -2485,8 +2491,8 @@ done:
|
||||
if (m2 == mc) continue;
|
||||
if (m2->mc_pg[mc->mc_top] == mp) {
|
||||
m2->mc_pg[mc->mc_top] = np;
|
||||
if (XCURSOR_INITED(m2) && IS_LEAF(np))
|
||||
XCURSOR_REFRESH(m2, np, m2->mc_ki[mc->mc_top]);
|
||||
if (IS_LEAF(np))
|
||||
XCURSOR_REFRESH(m2, mc->mc_top, np);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3088,10 +3094,41 @@ mdb_freelist_save(MDB_txn *txn)
|
||||
* we may be unable to return them to me_pghead.
|
||||
*/
|
||||
MDB_page *mp = txn->mt_loose_pgs;
|
||||
MDB_ID2 *dl = txn->mt_u.dirty_list;
|
||||
unsigned x;
|
||||
if ((rc = mdb_midl_need(&txn->mt_free_pgs, txn->mt_loose_count)) != 0)
|
||||
return rc;
|
||||
for (; mp; mp = NEXT_LOOSE_PAGE(mp))
|
||||
for (; mp; mp = NEXT_LOOSE_PAGE(mp)) {
|
||||
mdb_midl_xappend(txn->mt_free_pgs, mp->mp_pgno);
|
||||
/* must also remove from dirty list */
|
||||
if (txn->mt_flags & MDB_TXN_WRITEMAP) {
|
||||
for (x=1; x<=dl[0].mid; x++)
|
||||
if (dl[x].mid == mp->mp_pgno)
|
||||
break;
|
||||
mdb_tassert(txn, x <= dl[0].mid);
|
||||
} else {
|
||||
x = mdb_mid2l_search(dl, mp->mp_pgno);
|
||||
mdb_tassert(txn, dl[x].mid == mp->mp_pgno);
|
||||
}
|
||||
dl[x].mptr = NULL;
|
||||
mdb_dpage_free(env, mp);
|
||||
}
|
||||
{
|
||||
/* squash freed slots out of the dirty list */
|
||||
unsigned y;
|
||||
for (y=1; dl[y].mptr && y <= dl[0].mid; y++);
|
||||
if (y <= dl[0].mid) {
|
||||
for(x=y, y++;;) {
|
||||
while (!dl[y].mptr && y <= dl[0].mid) y++;
|
||||
if (y > dl[0].mid) break;
|
||||
dl[x++] = dl[y++];
|
||||
}
|
||||
dl[0].mid = x-1;
|
||||
} else {
|
||||
/* all slots freed */
|
||||
dl[0].mid = 0;
|
||||
}
|
||||
}
|
||||
txn->mt_loose_pgs = NULL;
|
||||
txn->mt_loose_count = 0;
|
||||
}
|
||||
@ -5057,7 +5094,7 @@ mdb_env_close0(MDB_env *env, int excl)
|
||||
if (env->me_fd != INVALID_HANDLE_VALUE)
|
||||
(void) close(env->me_fd);
|
||||
if (env->me_txns) {
|
||||
MDB_PID_T pid = env->me_pid;
|
||||
MDB_PID_T pid = getpid();
|
||||
/* Clearing readers is done in this function because
|
||||
* me_txkey with its destructor must be disabled first.
|
||||
*
|
||||
@ -6422,6 +6459,11 @@ fetchm:
|
||||
rc = MDB_INCOMPATIBLE;
|
||||
break;
|
||||
}
|
||||
if (mc->mc_ki[mc->mc_top] >= NUMKEYS(mc->mc_pg[mc->mc_top])) {
|
||||
mc->mc_ki[mc->mc_top] = NUMKEYS(mc->mc_pg[mc->mc_top]);
|
||||
rc = MDB_NOTFOUND;
|
||||
break;
|
||||
}
|
||||
{
|
||||
MDB_node *leaf = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
|
||||
if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) {
|
||||
@ -6788,8 +6830,9 @@ prep_subDB:
|
||||
} else {
|
||||
memcpy((char *)mp + mp->mp_upper + PAGEBASE, (char *)fp + fp->mp_upper + PAGEBASE,
|
||||
olddata.mv_size - fp->mp_upper - PAGEBASE);
|
||||
memcpy((char *)(&mp->mp_ptrs), (char *)(&fp->mp_ptrs), NUMKEYS(fp) * sizeof(mp->mp_ptrs[0]));
|
||||
for (i=0; i<NUMKEYS(fp); i++)
|
||||
mp->mp_ptrs[i] = fp->mp_ptrs[i] + offset;
|
||||
mp->mp_ptrs[i] += offset;
|
||||
}
|
||||
}
|
||||
|
||||
@ -6918,8 +6961,7 @@ new_sub:
|
||||
if (m3->mc_ki[i] >= mc->mc_ki[i] && insert_key) {
|
||||
m3->mc_ki[i]++;
|
||||
}
|
||||
if (XCURSOR_INITED(m3))
|
||||
XCURSOR_REFRESH(m3, mp, m3->mc_ki[i]);
|
||||
XCURSOR_REFRESH(m3, i, mp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6961,7 +7003,6 @@ put_sub:
|
||||
MDB_xcursor *mx = mc->mc_xcursor;
|
||||
unsigned i = mc->mc_top;
|
||||
MDB_page *mp = mc->mc_pg[i];
|
||||
int nkeys = NUMKEYS(mp);
|
||||
|
||||
for (m2 = mc->mc_txn->mt_cursors[mc->mc_dbi]; m2; m2=m2->mc_next) {
|
||||
if (m2 == mc || m2->mc_snum < mc->mc_snum) continue;
|
||||
@ -6969,8 +7010,8 @@ put_sub:
|
||||
if (m2->mc_pg[i] == mp) {
|
||||
if (m2->mc_ki[i] == mc->mc_ki[i]) {
|
||||
mdb_xcursor_init2(m2, mx, new_dupdata);
|
||||
} else if (!insert_key && m2->mc_ki[i] < nkeys) {
|
||||
XCURSOR_REFRESH(m2, mp, m2->mc_ki[i]);
|
||||
} else if (!insert_key) {
|
||||
XCURSOR_REFRESH(m2, i, mp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7075,12 +7116,7 @@ mdb_cursor_del(MDB_cursor *mc, unsigned int flags)
|
||||
if (m2 == mc || m2->mc_snum < mc->mc_snum) continue;
|
||||
if (!(m2->mc_flags & C_INITIALIZED)) continue;
|
||||
if (m2->mc_pg[mc->mc_top] == mp) {
|
||||
MDB_node *n2 = leaf;
|
||||
if (m2->mc_ki[mc->mc_top] != mc->mc_ki[mc->mc_top]) {
|
||||
n2 = NODEPTR(mp, m2->mc_ki[mc->mc_top]);
|
||||
if (n2->mn_flags & F_SUBDATA) continue;
|
||||
}
|
||||
m2->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(n2);
|
||||
XCURSOR_REFRESH(m2, mc->mc_top, mp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7926,8 +7962,8 @@ mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst, int fromleft)
|
||||
m3->mc_ki[csrc->mc_top] = cdst->mc_ki[cdst->mc_top];
|
||||
m3->mc_ki[csrc->mc_top-1]++;
|
||||
}
|
||||
if (XCURSOR_INITED(m3) && IS_LEAF(mps))
|
||||
XCURSOR_REFRESH(m3, m3->mc_pg[csrc->mc_top], m3->mc_ki[csrc->mc_top]);
|
||||
if (IS_LEAF(mps))
|
||||
XCURSOR_REFRESH(m3, csrc->mc_top, m3->mc_pg[csrc->mc_top]);
|
||||
}
|
||||
} else
|
||||
/* Adding on the right, bump others down */
|
||||
@ -7948,8 +7984,8 @@ mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst, int fromleft)
|
||||
} else {
|
||||
m3->mc_ki[csrc->mc_top]--;
|
||||
}
|
||||
if (XCURSOR_INITED(m3) && IS_LEAF(mps))
|
||||
XCURSOR_REFRESH(m3, m3->mc_pg[csrc->mc_top], m3->mc_ki[csrc->mc_top]);
|
||||
if (IS_LEAF(mps))
|
||||
XCURSOR_REFRESH(m3, csrc->mc_top, m3->mc_pg[csrc->mc_top]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8150,8 +8186,8 @@ mdb_page_merge(MDB_cursor *csrc, MDB_cursor *cdst)
|
||||
m3->mc_ki[top-1] > csrc->mc_ki[top-1]) {
|
||||
m3->mc_ki[top-1]--;
|
||||
}
|
||||
if (XCURSOR_INITED(m3) && IS_LEAF(psrc))
|
||||
XCURSOR_REFRESH(m3, m3->mc_pg[top], m3->mc_ki[top]);
|
||||
if (IS_LEAF(psrc))
|
||||
XCURSOR_REFRESH(m3, top, m3->mc_pg[top]);
|
||||
}
|
||||
}
|
||||
{
|
||||
@ -8413,8 +8449,7 @@ mdb_cursor_del0(MDB_cursor *mc)
|
||||
} else if (m3->mc_ki[mc->mc_top] > ki) {
|
||||
m3->mc_ki[mc->mc_top]--;
|
||||
}
|
||||
if (XCURSOR_INITED(m3))
|
||||
XCURSOR_REFRESH(m3, m3->mc_pg[mc->mc_top], m3->mc_ki[mc->mc_top]);
|
||||
XCURSOR_REFRESH(m3, mc->mc_top, mp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8461,8 +8496,10 @@ mdb_cursor_del0(MDB_cursor *mc)
|
||||
if (m3->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) {
|
||||
if (!(node->mn_flags & F_SUBDATA))
|
||||
m3->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(node);
|
||||
} else
|
||||
} else {
|
||||
mdb_xcursor_init1(m3, node);
|
||||
m3->mc_xcursor->mx_cursor.mc_flags |= C_DEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8948,8 +8985,8 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno
|
||||
m3->mc_ki[ptop] >= mc->mc_ki[ptop]) {
|
||||
m3->mc_ki[ptop]++;
|
||||
}
|
||||
if (XCURSOR_INITED(m3) && IS_LEAF(mp))
|
||||
XCURSOR_REFRESH(m3, m3->mc_pg[mc->mc_top], m3->mc_ki[mc->mc_top]);
|
||||
if (IS_LEAF(mp))
|
||||
XCURSOR_REFRESH(m3, mc->mc_top, m3->mc_pg[mc->mc_top]);
|
||||
}
|
||||
}
|
||||
DPRINTF(("mp left: %d, rp left: %d", SIZELEFT(mp), SIZELEFT(rp)));
|
||||
@ -9754,8 +9791,11 @@ int mdb_dbi_open(MDB_txn *txn, const char *name, unsigned int flags, MDB_dbi *db
|
||||
MDB_node *node = NODEPTR(mc.mc_pg[mc.mc_top], mc.mc_ki[mc.mc_top]);
|
||||
if ((node->mn_flags & (F_DUPDATA|F_SUBDATA)) != F_SUBDATA)
|
||||
return MDB_INCOMPATIBLE;
|
||||
} else if (! (rc == MDB_NOTFOUND && (flags & MDB_CREATE))) {
|
||||
return rc;
|
||||
} else {
|
||||
if (rc != MDB_NOTFOUND || !(flags & MDB_CREATE))
|
||||
return rc;
|
||||
if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY))
|
||||
return EACCES;
|
||||
}
|
||||
|
||||
/* Done here so we cannot fail after creating a new DB */
|
@ -1,5 +1,5 @@
|
||||
.TH MDB_COPY 1 "2014/07/01" "LMDB 0.9.14"
|
||||
.\" Copyright 2012-2017 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copyright 2012-2018 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.SH NAME
|
||||
mdb_copy \- LMDB environment copy tool
|
@ -1,6 +1,6 @@
|
||||
/* mdb_copy.c - memory-mapped database backup tool */
|
||||
/*
|
||||
* Copyright 2012-2017 Howard Chu, Symas Corp.
|
||||
* Copyright 2012-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
@ -1,5 +1,5 @@
|
||||
.TH MDB_DUMP 1 "2015/09/30" "LMDB 0.9.17"
|
||||
.\" Copyright 2014-2017 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copyright 2014-2018 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.SH NAME
|
||||
mdb_dump \- LMDB environment export tool
|
@ -1,6 +1,6 @@
|
||||
/* mdb_dump.c - memory-mapped database dump tool */
|
||||
/*
|
||||
* Copyright 2011-2017 Howard Chu, Symas Corp.
|
||||
* Copyright 2011-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
@ -1,5 +1,5 @@
|
||||
.TH MDB_LOAD 1 "2015/09/30" "LMDB 0.9.17"
|
||||
.\" Copyright 2014-2017 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copyright 2014-2018 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.SH NAME
|
||||
mdb_load \- LMDB environment import tool
|
@ -1,6 +1,6 @@
|
||||
/* mdb_load.c - memory-mapped database load tool */
|
||||
/*
|
||||
* Copyright 2011-2017 Howard Chu, Symas Corp.
|
||||
* Copyright 2011-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -68,6 +68,7 @@ static void readhdr(void)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
flags = 0;
|
||||
while (fgets(dbuf.mv_data, dbuf.mv_size, stdin) != NULL) {
|
||||
lineno++;
|
||||
if (!strncmp(dbuf.mv_data, "VERSION=", STRLENOF("VERSION="))) {
|
||||
@ -374,7 +375,6 @@ int main(int argc, char *argv[])
|
||||
while(!Eof) {
|
||||
MDB_val key, data;
|
||||
int batch = 0;
|
||||
flags = 0;
|
||||
|
||||
if (!dohdr) {
|
||||
dohdr = 1;
|
@ -1,5 +1,5 @@
|
||||
.TH MDB_STAT 1 "2015/09/30" "LMDB 0.9.17"
|
||||
.\" Copyright 2012-2017 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copyright 2012-2018 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.SH NAME
|
||||
mdb_stat \- LMDB environment status tool
|
@ -1,6 +1,6 @@
|
||||
/* mdb_stat.c - memory-mapped database status tool */
|
||||
/*
|
||||
* Copyright 2011-2017 Howard Chu, Symas Corp.
|
||||
* Copyright 2011-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
@ -3,8 +3,8 @@
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2016 The OpenLDAP Foundation.
|
||||
* Portions Copyright 2001-2017 Howard Chu, Symas Corp.
|
||||
* Copyright 2000-2018 The OpenLDAP Foundation.
|
||||
* Portions Copyright 2001-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
@ -11,8 +11,8 @@
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2016 The OpenLDAP Foundation.
|
||||
* Portions Copyright 2001-2017 Howard Chu, Symas Corp.
|
||||
* Copyright 2000-2018 The OpenLDAP Foundation.
|
||||
* Portions Copyright 2001-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
@ -1,6 +1,6 @@
|
||||
/* mtest.c - memory-mapped database tester/toy */
|
||||
/*
|
||||
* Copyright 2011-2017 Howard Chu, Symas Corp.
|
||||
* Copyright 2011-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
@ -1,6 +1,6 @@
|
||||
/* mtest2.c - memory-mapped database tester/toy */
|
||||
/*
|
||||
* Copyright 2011-2017 Howard Chu, Symas Corp.
|
||||
* Copyright 2011-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
@ -1,6 +1,6 @@
|
||||
/* mtest3.c - memory-mapped database tester/toy */
|
||||
/*
|
||||
* Copyright 2011-2017 Howard Chu, Symas Corp.
|
||||
* Copyright 2011-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
@ -1,6 +1,6 @@
|
||||
/* mtest4.c - memory-mapped database tester/toy */
|
||||
/*
|
||||
* Copyright 2011-2017 Howard Chu, Symas Corp.
|
||||
* Copyright 2011-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
@ -1,6 +1,6 @@
|
||||
/* mtest5.c - memory-mapped database tester/toy */
|
||||
/*
|
||||
* Copyright 2011-2017 Howard Chu, Symas Corp.
|
||||
* Copyright 2011-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
@ -1,6 +1,6 @@
|
||||
/* mtest6.c - memory-mapped database tester/toy */
|
||||
/*
|
||||
* Copyright 2011-2017 Howard Chu, Symas Corp.
|
||||
* Copyright 2011-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
@ -3,7 +3,7 @@
|
||||
* Do a line-by-line comparison of this and sample-mdb.txt
|
||||
*/
|
||||
/*
|
||||
* Copyright 2012-2017 Howard Chu, Symas Corp.
|
||||
* Copyright 2012-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
@ -3,7 +3,7 @@
|
||||
* Do a line-by-line comparison of this and sample-bdb.txt
|
||||
*/
|
||||
/*
|
||||
* Copyright 2012-2017 Howard Chu, Symas Corp.
|
||||
* Copyright 2012-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
@ -1,6 +1,6 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
#![deny(warnings)]
|
||||
#![doc(html_root_url = "https://docs.rs/lmdb-sys/0.8.0")]
|
||||
#![doc(html_root_url = "https://docs.rs/lmdb-rkv-sys/0.8.2")]
|
||||
|
||||
extern crate libc;
|
||||
|
@ -1 +1 @@
|
||||
{"files":{"Cargo.toml":"fec74a5e98cd6a19d96eb3fcb54504199035eed36b999fe50c874f8e12bbf28d","LICENSE":"db6d163be642e3b568c5fb2104013da632316ecd4e75935df1613af8b0b37933","README.md":"97b61d73ff27afb03bde9ae960f12651093558214851303c8ae82f567abfe992","src/cursor.rs":"1cf47e15c55e3df7db5293f81c7538b0139dd2c4414cdc3ee8799f8659a2af0d","src/database.rs":"003a214f53acd632bc70f2f02d01dcb0bc5bf7e777e1781ef1ff19246f0157d0","src/environment.rs":"be682d90b86aef52d68936d96325d9ce9579389c79ce7b3fc640a79a3836c34b","src/error.rs":"0ea99c8bc1619f3789eff7734341efa7f48fcd8732dc9f3141804e0a802f5d71","src/flags.rs":"40fd3d4d72c8db8f9ecb893420300a3585e2ca4c49073065ec9ebf24fe23c064","src/lib.rs":"1e070c161e33eb07ed3e992f827c4b86e6f682ad0a24442346afb4dbc6ab40dd","src/transaction.rs":"e9e9485aafb19cab4688dc8a476eec033c21c8256717a89080cfb77d2dfe235c"},"package":"aba42e6d930590ce6625566f2d16300add86ef11335eedba0fcf29f9f4cbd8c5"}
|
||||
{"files":{"Cargo.toml":"ba319c56424eed8ac65e6add74a59e9610c2a1e30701801b0ede6313020cd596","LICENSE":"db6d163be642e3b568c5fb2104013da632316ecd4e75935df1613af8b0b37933","README.md":"97b61d73ff27afb03bde9ae960f12651093558214851303c8ae82f567abfe992","azure-pipelines-template.yml":"a75d2421df0feefcb2ea17072c12795e58f9ac6322bacfbea90890fbb5e09cb7","azure-pipelines.yml":"c5a206822c22921bd07ea0a469db734875361457400427991319808cfd13ffef","src/cursor.rs":"f51184cbf015d1aef1a45f0cc1a950524114e1d4aadc50bde7bdb712030a839a","src/database.rs":"003a214f53acd632bc70f2f02d01dcb0bc5bf7e777e1781ef1ff19246f0157d0","src/environment.rs":"774241ef807892b0ebede3392113560563dc8b197c87d97756c47811716a8b4c","src/error.rs":"0ea99c8bc1619f3789eff7734341efa7f48fcd8732dc9f3141804e0a802f5d71","src/flags.rs":"40fd3d4d72c8db8f9ecb893420300a3585e2ca4c49073065ec9ebf24fe23c064","src/lib.rs":"e8c93f6501c58f2d325998730e7991c156a8f53459130181005569ede9d2d871","src/transaction.rs":"09ac6501e3dd1a714c635acb46625c4a4d96d9296cd30bcda31d50224e27fd05"},"package":"1452294309db7977dc75e1e8135a8c654d9e52e04ff0c0bd06c880897a91defd"}
|
6
third_party/rust/lmdb-rkv/Cargo.toml
vendored
6
third_party/rust/lmdb-rkv/Cargo.toml
vendored
@ -12,7 +12,7 @@
|
||||
|
||||
[package]
|
||||
name = "lmdb-rkv"
|
||||
version = "0.9.0"
|
||||
version = "0.11.2"
|
||||
authors = ["Dan Burkert <dan@danburkert.com>"]
|
||||
description = "Idiomatic and safe LMDB wrapper."
|
||||
documentation = "https://docs.rs/lmdb-rkv"
|
||||
@ -30,8 +30,8 @@ version = "1"
|
||||
[dependencies.libc]
|
||||
version = "0.2"
|
||||
|
||||
[dependencies.lmdb-sys]
|
||||
version = "0.8.0"
|
||||
[dependencies.lmdb-rkv-sys]
|
||||
version = "0.8.2"
|
||||
[dev-dependencies.byteorder]
|
||||
version = "1.0"
|
||||
|
||||
|
49
third_party/rust/lmdb-rkv/azure-pipelines-template.yml
vendored
Normal file
49
third_party/rust/lmdb-rkv/azure-pipelines-template.yml
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
jobs:
|
||||
- job: ${{ parameters.name }}
|
||||
pool:
|
||||
vmImage: ${{ parameters.vmImage }}
|
||||
strategy:
|
||||
matrix:
|
||||
stable:
|
||||
rustup_toolchain: stable
|
||||
beta:
|
||||
rustup_toolchain: beta
|
||||
nightly:
|
||||
rustup_toolchain: nightly
|
||||
steps:
|
||||
# Linux and macOS.
|
||||
- ${{ if ne(parameters.name, 'Windows') }}:
|
||||
- script: |
|
||||
curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $RUSTUP_TOOLCHAIN
|
||||
echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin"
|
||||
displayName: Install rust
|
||||
# Windows.
|
||||
- ${{ if eq(parameters.name, 'Windows') }}:
|
||||
- script: |
|
||||
curl -sSf -o rustup-init.exe https://win.rustup.rs
|
||||
rustup-init.exe -y --default-toolchain %RUSTUP_TOOLCHAIN%
|
||||
set PATH=%PATH%;%USERPROFILE%\.cargo\bin
|
||||
echo "##vso[task.setvariable variable=PATH;]%PATH%;%USERPROFILE%\.cargo\bin"
|
||||
displayName: Install rust (windows)
|
||||
# All platforms.
|
||||
- script: |
|
||||
rustc -Vv
|
||||
cargo -V
|
||||
displayName: Query rust and cargo versions
|
||||
- script: cargo build
|
||||
displayName: Build
|
||||
# Linux and macOS w/nightly toolchain.
|
||||
# Ideally we'd only run the script for the nightly toolchain, but I can't
|
||||
# figure out how to determine that within the Azure Pipelines conditional.
|
||||
- ${{ if ne(parameters.name, 'Windows') }}:
|
||||
- script: |
|
||||
if [ "$RUSTUP_TOOLCHAIN" = 'nightly' ]
|
||||
then cargo test
|
||||
fi
|
||||
displayName: Test
|
||||
# Windows w/nightly toolchain.
|
||||
# Ideally we'd only run the script for the nightly toolchain, but I can't
|
||||
# figure out how to determine that within the Azure Pipelines conditional.
|
||||
- ${{ if eq(parameters.name, 'Windows') }}:
|
||||
- script: if "%RUSTUP_TOOLCHAIN%" == "nightly" cargo test
|
||||
displayName: Test
|
15
third_party/rust/lmdb-rkv/azure-pipelines.yml
vendored
Normal file
15
third_party/rust/lmdb-rkv/azure-pipelines.yml
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
jobs:
|
||||
- template: azure-pipelines-template.yml
|
||||
parameters:
|
||||
name: macOS
|
||||
vmImage: macOS-10.13
|
||||
|
||||
- template: azure-pipelines-template.yml
|
||||
parameters:
|
||||
name: Linux
|
||||
vmImage: ubuntu-16.04
|
||||
|
||||
- template: azure-pipelines-template.yml
|
||||
parameters:
|
||||
name: Windows
|
||||
vmImage: vs2017-win2016
|
182
third_party/rust/lmdb-rkv/src/cursor.rs
vendored
182
third_party/rust/lmdb-rkv/src/cursor.rs
vendored
@ -60,7 +60,7 @@ pub trait Cursor<'txn> {
|
||||
fn iter_from<K>(&mut self, key: K) -> Iter<'txn> where K: AsRef<[u8]> {
|
||||
match self.get(Some(key.as_ref()), None, ffi::MDB_SET_RANGE) {
|
||||
Ok(_) | Err(Error::NotFound) => (),
|
||||
Err(error) => panic!("mdb_cursor_get returned an unexpected error: {}", error),
|
||||
Err(error) => return Iter::Err(error),
|
||||
};
|
||||
Iter::new(self.cursor(), ffi::MDB_GET_CURRENT, ffi::MDB_NEXT)
|
||||
}
|
||||
@ -80,19 +80,19 @@ pub trait Cursor<'txn> {
|
||||
|
||||
/// Iterate over duplicate items in the database starting from the given
|
||||
/// key. Each item will be returned as an iterator of its duplicates.
|
||||
fn iter_dup_from<K>(&mut self, key: &K) -> IterDup<'txn> where K: AsRef<[u8]> {
|
||||
fn iter_dup_from<K>(&mut self, key: K) -> IterDup<'txn> where K: AsRef<[u8]> {
|
||||
match self.get(Some(key.as_ref()), None, ffi::MDB_SET_RANGE) {
|
||||
Ok(_) | Err(Error::NotFound) => (),
|
||||
Err(error) => panic!("mdb_cursor_get returned an unexpected error: {}", error),
|
||||
Err(error) => return IterDup::Err(error),
|
||||
};
|
||||
IterDup::new(self.cursor(), ffi::MDB_GET_CURRENT)
|
||||
}
|
||||
|
||||
/// Iterate over the duplicates of the item in the database with the given key.
|
||||
fn iter_dup_of<K>(&mut self, key: &K) -> Iter<'txn> where K: AsRef<[u8]> {
|
||||
fn iter_dup_of<K>(&mut self, key: K) -> Iter<'txn> where K: AsRef<[u8]> {
|
||||
match self.get(Some(key.as_ref()), None, ffi::MDB_SET) {
|
||||
Ok(_) | Err(Error::NotFound) => (),
|
||||
Err(error) => panic!("mdb_cursor_get returned an unexpected error: {}", error),
|
||||
Err(error) => return Iter::Err(error),
|
||||
};
|
||||
Iter::new(self.cursor(), ffi::MDB_GET_CURRENT, ffi::MDB_NEXT_DUP)
|
||||
}
|
||||
@ -214,19 +214,39 @@ unsafe fn val_to_slice<'a>(val: ffi::MDB_val) -> &'a [u8] {
|
||||
slice::from_raw_parts(val.mv_data as *const u8, val.mv_size as usize)
|
||||
}
|
||||
|
||||
/// An iterator over the values in an LMDB database.
|
||||
pub struct Iter<'txn> {
|
||||
cursor: *mut ffi::MDB_cursor,
|
||||
op: c_uint,
|
||||
next_op: c_uint,
|
||||
_marker: PhantomData<fn(&'txn ())>,
|
||||
/// An iterator over the key/value pairs in an LMDB database.
|
||||
pub enum Iter<'txn> {
|
||||
/// An iterator that returns an error on every call to Iter.next().
|
||||
/// Cursor.iter*() creates an Iter of this type when LMDB returns an error
|
||||
/// on retrieval of a cursor. Using this variant instead of returning
|
||||
/// an error makes Cursor.iter()* methods infallible, so consumers only
|
||||
/// need to check the result of Iter.next().
|
||||
Err(Error),
|
||||
|
||||
/// An iterator that returns an Item on calls to Iter.next().
|
||||
/// The Item is a Result<(&'txn [u8], &'txn [u8])>, so this variant
|
||||
/// might still return an error, if retrieval of the key/value pair
|
||||
/// fails for some reason.
|
||||
Ok {
|
||||
/// The LMDB cursor with which to iterate.
|
||||
cursor: *mut ffi::MDB_cursor,
|
||||
|
||||
/// The first operation to perform when the consumer calls Iter.next().
|
||||
op: c_uint,
|
||||
|
||||
/// The next and subsequent operations to perform.
|
||||
next_op: c_uint,
|
||||
|
||||
/// A marker to ensure the iterator doesn't outlive the transaction.
|
||||
_marker: PhantomData<fn(&'txn ())>,
|
||||
},
|
||||
}
|
||||
|
||||
impl <'txn> Iter<'txn> {
|
||||
|
||||
/// Creates a new iterator backed by the given cursor.
|
||||
fn new<'t>(cursor: *mut ffi::MDB_cursor, op: c_uint, next_op: c_uint) -> Iter<'t> {
|
||||
Iter { cursor: cursor, op: op, next_op: next_op, _marker: PhantomData }
|
||||
Iter::Ok { cursor: cursor, op: op, next_op: next_op, _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,20 +258,25 @@ impl <'txn> fmt::Debug for Iter<'txn> {
|
||||
|
||||
impl <'txn> Iterator for Iter<'txn> {
|
||||
|
||||
type Item = (&'txn [u8], &'txn [u8]);
|
||||
type Item = Result<(&'txn [u8], &'txn [u8])>;
|
||||
|
||||
fn next(&mut self) -> Option<(&'txn [u8], &'txn [u8])> {
|
||||
let mut key = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
|
||||
let mut data = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
|
||||
let op = mem::replace(&mut self.op, self.next_op);
|
||||
unsafe {
|
||||
match ffi::mdb_cursor_get(self.cursor, &mut key, &mut data, op) {
|
||||
ffi::MDB_SUCCESS => Some((val_to_slice(key), val_to_slice(data))),
|
||||
// EINVAL can occur when the cursor was previously seeked to a non-existent value,
|
||||
// e.g. iter_from with a key greater than all values in the database.
|
||||
ffi::MDB_NOTFOUND | EINVAL => None,
|
||||
error => panic!("mdb_cursor_get returned an unexpected error: {}", error),
|
||||
}
|
||||
fn next(&mut self) -> Option<Result<(&'txn [u8], &'txn [u8])>> {
|
||||
match self {
|
||||
&mut Iter::Ok { cursor, ref mut op, next_op, _marker } => {
|
||||
let mut key = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
|
||||
let mut data = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
|
||||
let op = mem::replace(op, next_op);
|
||||
unsafe {
|
||||
match ffi::mdb_cursor_get(cursor, &mut key, &mut data, op) {
|
||||
ffi::MDB_SUCCESS => Some(Ok((val_to_slice(key), val_to_slice(data)))),
|
||||
// EINVAL can occur when the cursor was previously seeked to a non-existent value,
|
||||
// e.g. iter_from with a key greater than all values in the database.
|
||||
ffi::MDB_NOTFOUND | EINVAL => None,
|
||||
error => Some(Err(Error::from_err_code(error))),
|
||||
}
|
||||
}
|
||||
},
|
||||
&mut Iter::Err(err) => Some(Err(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -260,17 +285,35 @@ impl <'txn> Iterator for Iter<'txn> {
|
||||
///
|
||||
/// The yielded items of the iterator are themselves iterators over the duplicate values for a
|
||||
/// specific key.
|
||||
pub struct IterDup<'txn> {
|
||||
cursor: *mut ffi::MDB_cursor,
|
||||
op: c_uint,
|
||||
_marker: PhantomData<fn(&'txn ())>,
|
||||
pub enum IterDup<'txn> {
|
||||
/// An iterator that returns an error on every call to Iter.next().
|
||||
/// Cursor.iter*() creates an Iter of this type when LMDB returns an error
|
||||
/// on retrieval of a cursor. Using this variant instead of returning
|
||||
/// an error makes Cursor.iter()* methods infallible, so consumers only
|
||||
/// need to check the result of Iter.next().
|
||||
Err(Error),
|
||||
|
||||
/// An iterator that returns an Item on calls to Iter.next().
|
||||
/// The Item is a Result<(&'txn [u8], &'txn [u8])>, so this variant
|
||||
/// might still return an error, if retrieval of the key/value pair
|
||||
/// fails for some reason.
|
||||
Ok {
|
||||
/// The LMDB cursor with which to iterate.
|
||||
cursor: *mut ffi::MDB_cursor,
|
||||
|
||||
/// The first operation to perform when the consumer calls Iter.next().
|
||||
op: c_uint,
|
||||
|
||||
/// A marker to ensure the iterator doesn't outlive the transaction.
|
||||
_marker: PhantomData<fn(&'txn ())>,
|
||||
},
|
||||
}
|
||||
|
||||
impl <'txn> IterDup<'txn> {
|
||||
|
||||
/// Creates a new iterator backed by the given cursor.
|
||||
fn new<'t>(cursor: *mut ffi::MDB_cursor, op: c_uint) -> IterDup<'t> {
|
||||
IterDup { cursor: cursor, op: op, _marker: PhantomData }
|
||||
IterDup::Ok { cursor: cursor, op: op, _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
@ -285,17 +328,22 @@ impl <'txn> Iterator for IterDup<'txn> {
|
||||
type Item = Iter<'txn>;
|
||||
|
||||
fn next(&mut self) -> Option<Iter<'txn>> {
|
||||
let mut key = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
|
||||
let mut data = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
|
||||
let op = mem::replace(&mut self.op, ffi::MDB_NEXT_NODUP);
|
||||
let err_code = unsafe {
|
||||
ffi::mdb_cursor_get(self.cursor, &mut key, &mut data, op)
|
||||
};
|
||||
match self {
|
||||
&mut IterDup::Ok { cursor, ref mut op, _marker } => {
|
||||
let mut key = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
|
||||
let mut data = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
|
||||
let op = mem::replace(op, ffi::MDB_NEXT_NODUP);
|
||||
let err_code = unsafe {
|
||||
ffi::mdb_cursor_get(cursor, &mut key, &mut data, op)
|
||||
};
|
||||
|
||||
if err_code == ffi::MDB_SUCCESS {
|
||||
Some(Iter::new(self.cursor, ffi::MDB_GET_CURRENT, ffi::MDB_NEXT_DUP))
|
||||
} else {
|
||||
None
|
||||
if err_code == ffi::MDB_SUCCESS {
|
||||
Some(Iter::new(cursor, ffi::MDB_GET_CURRENT, ffi::MDB_NEXT_DUP))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
&mut IterDup::Err(err) => Some(Iter::Err(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -433,22 +481,30 @@ mod test {
|
||||
|
||||
let txn = env.begin_ro_txn().unwrap();
|
||||
let mut cursor = txn.open_ro_cursor(db).unwrap();
|
||||
assert_eq!(items, cursor.iter().collect::<Vec<_>>());
|
||||
|
||||
// Because Result implements FromIterator, we can collect the iterator
|
||||
// of items of type Result<_, E> into a Result<Vec<_, E>> by specifying
|
||||
// the collection type via the turbofish syntax.
|
||||
assert_eq!(items, cursor.iter().collect::<Result<Vec<_>>>().unwrap());
|
||||
|
||||
// Alternately, we can collect it into an appropriately typed variable.
|
||||
let retr: Result<Vec<_>> = cursor.iter_start().collect();
|
||||
assert_eq!(items, retr.unwrap());
|
||||
|
||||
cursor.get(Some(b"key2"), None, MDB_SET).unwrap();
|
||||
assert_eq!(items.clone().into_iter().skip(2).collect::<Vec<_>>(),
|
||||
cursor.iter().collect::<Vec<_>>());
|
||||
cursor.iter().collect::<Result<Vec<_>>>().unwrap());
|
||||
|
||||
assert_eq!(items, cursor.iter_start().collect::<Vec<_>>());
|
||||
assert_eq!(items, cursor.iter_start().collect::<Result<Vec<_>>>().unwrap());
|
||||
|
||||
assert_eq!(items.clone().into_iter().skip(1).collect::<Vec<_>>(),
|
||||
cursor.iter_from(b"key2").collect::<Vec<_>>());
|
||||
cursor.iter_from(b"key2").collect::<Result<Vec<_>>>().unwrap());
|
||||
|
||||
assert_eq!(items.clone().into_iter().skip(3).collect::<Vec<_>>(),
|
||||
cursor.iter_from(b"key4").collect::<Vec<_>>());
|
||||
cursor.iter_from(b"key4").collect::<Result<Vec<_>>>().unwrap());
|
||||
|
||||
assert_eq!(vec!().into_iter().collect::<Vec<(&[u8], &[u8])>>(),
|
||||
cursor.iter_from(b"key6").collect::<Vec<_>>());
|
||||
cursor.iter_from(b"key6").collect::<Result<Vec<_>>>().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -510,29 +566,29 @@ mod test {
|
||||
|
||||
let txn = env.begin_ro_txn().unwrap();
|
||||
let mut cursor = txn.open_ro_cursor(db).unwrap();
|
||||
assert_eq!(items, cursor.iter_dup().flat_map(|x| x).collect::<Vec<_>>());
|
||||
assert_eq!(items, cursor.iter_dup().flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap());
|
||||
|
||||
cursor.get(Some(b"b"), None, MDB_SET).unwrap();
|
||||
assert_eq!(items.clone().into_iter().skip(4).collect::<Vec<(&[u8], &[u8])>>(),
|
||||
cursor.iter_dup().flat_map(|x| x).collect::<Vec<_>>());
|
||||
cursor.iter_dup().flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap());
|
||||
|
||||
assert_eq!(items,
|
||||
cursor.iter_dup_start().flat_map(|x| x).collect::<Vec<(&[u8], &[u8])>>());
|
||||
cursor.iter_dup_start().flat_map(|x| x).collect::<Result<Vec<(&[u8], &[u8])>>>().unwrap());
|
||||
|
||||
assert_eq!(items.clone().into_iter().skip(3).collect::<Vec<(&[u8], &[u8])>>(),
|
||||
cursor.iter_dup_from(b"b").flat_map(|x| x).collect::<Vec<_>>());
|
||||
cursor.iter_dup_from(b"b").flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap());
|
||||
|
||||
assert_eq!(items.clone().into_iter().skip(3).collect::<Vec<(&[u8], &[u8])>>(),
|
||||
cursor.iter_dup_from(b"ab").flat_map(|x| x).collect::<Vec<_>>());
|
||||
cursor.iter_dup_from(b"ab").flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap());
|
||||
|
||||
assert_eq!(items.clone().into_iter().skip(9).collect::<Vec<(&[u8], &[u8])>>(),
|
||||
cursor.iter_dup_from(b"d").flat_map(|x| x).collect::<Vec<_>>());
|
||||
cursor.iter_dup_from(b"d").flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap());
|
||||
|
||||
assert_eq!(vec!().into_iter().collect::<Vec<(&[u8], &[u8])>>(),
|
||||
cursor.iter_dup_from(b"f").flat_map(|x| x).collect::<Vec<_>>());
|
||||
cursor.iter_dup_from(b"f").flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap());
|
||||
|
||||
assert_eq!(items.clone().into_iter().skip(3).take(3).collect::<Vec<(&[u8], &[u8])>>(),
|
||||
cursor.iter_dup_of(b"b").collect::<Vec<_>>());
|
||||
cursor.iter_dup_of(b"b").collect::<Result<Vec<_>>>().unwrap());
|
||||
|
||||
assert_eq!(0, cursor.iter_dup_of(b"foo").count());
|
||||
}
|
||||
@ -571,10 +627,26 @@ mod test {
|
||||
let mut i = 0;
|
||||
let mut count = 0u32;
|
||||
|
||||
for (key, data) in cursor.iter() {
|
||||
for (key, data) in cursor.iter().map(Result::unwrap) {
|
||||
i = i + key.len() + data.len();
|
||||
count = count + 1;
|
||||
}
|
||||
for (key, data) in cursor.iter().filter_map(Result::ok) {
|
||||
i = i + key.len() + data.len();
|
||||
count = count + 1;
|
||||
}
|
||||
|
||||
fn iterate<'a>(cursor: &mut RoCursor) -> Result<()> {
|
||||
let mut i = 0;
|
||||
let mut count = 0u32;
|
||||
for result in cursor.iter() {
|
||||
let (key, data) = result?;
|
||||
i = i + key.len() + data.len();
|
||||
count = count + 1;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
iterate(&mut cursor).unwrap();
|
||||
|
||||
black_box(i);
|
||||
assert_eq!(count, n);
|
||||
|
2
third_party/rust/lmdb-rkv/src/environment.rs
vendored
2
third_party/rust/lmdb-rkv/src/environment.rs
vendored
@ -316,7 +316,7 @@ impl EnvironmentBuilder {
|
||||
/// Sets the size of the memory map to use for the environment.
|
||||
///
|
||||
/// The size should be a multiple of the OS page size. The default is
|
||||
/// 10485760 bytes. The size of the memory map is also the maximum size
|
||||
/// 1048576 bytes. The size of the memory map is also the maximum size
|
||||
/// of the database. The value should be chosen as large as possible,
|
||||
/// to accommodate future growth of the database. It may be increased at
|
||||
/// later times.
|
||||
|
4
third_party/rust/lmdb-rkv/src/lib.rs
vendored
4
third_party/rust/lmdb-rkv/src/lib.rs
vendored
@ -3,10 +3,10 @@
|
||||
|
||||
#![cfg_attr(test, feature(test))]
|
||||
#![deny(missing_docs)]
|
||||
#![doc(html_root_url = "https://docs.rs/lmdb-rkv/0.9.0")]
|
||||
#![doc(html_root_url = "https://docs.rs/lmdb-rkv/0.11.2")]
|
||||
|
||||
extern crate libc;
|
||||
extern crate lmdb_sys as ffi;
|
||||
extern crate lmdb_rkv_sys as ffi;
|
||||
|
||||
#[cfg(test)] extern crate rand;
|
||||
#[cfg(test)] extern crate tempdir;
|
||||
|
70
third_party/rust/lmdb-rkv/src/transaction.rs
vendored
70
third_party/rust/lmdb-rkv/src/transaction.rs
vendored
@ -332,12 +332,22 @@ impl <'env> RwTransaction<'env> {
|
||||
let data_val: Option<ffi::MDB_val> =
|
||||
data.map(|data| ffi::MDB_val { mv_size: data.len() as size_t,
|
||||
mv_data: data.as_ptr() as *mut c_void });
|
||||
unsafe {
|
||||
lmdb_result(ffi::mdb_del(self.txn(),
|
||||
database.dbi(),
|
||||
&mut key_val,
|
||||
data_val.map(|mut data_val| &mut data_val as *mut _)
|
||||
.unwrap_or(ptr::null_mut())))
|
||||
|
||||
if let Some(mut d) = data_val {
|
||||
unsafe {
|
||||
lmdb_result(ffi::mdb_del(self.txn(),
|
||||
database.dbi(),
|
||||
&mut key_val,
|
||||
&mut d))
|
||||
|
||||
}
|
||||
} else {
|
||||
unsafe {
|
||||
lmdb_result(ffi::mdb_del(self.txn(),
|
||||
database.dbi(),
|
||||
&mut key_val,
|
||||
ptr::null_mut()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -392,6 +402,7 @@ mod test {
|
||||
use flags::*;
|
||||
use super::*;
|
||||
use test_utils::*;
|
||||
use cursor::Cursor;
|
||||
|
||||
#[test]
|
||||
fn test_put_get_del() {
|
||||
@ -415,6 +426,53 @@ mod test {
|
||||
assert_eq!(txn.get(db, b"key1"), Err(Error::NotFound));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_put_get_del_multi() {
|
||||
let dir = TempDir::new("test").unwrap();
|
||||
let env = Environment::new().open(dir.path()).unwrap();
|
||||
let db = env.create_db(None, DatabaseFlags::DUP_SORT).unwrap();
|
||||
|
||||
let mut txn = env.begin_rw_txn().unwrap();
|
||||
txn.put(db, b"key1", b"val1", WriteFlags::empty()).unwrap();
|
||||
txn.put(db, b"key1", b"val2", WriteFlags::empty()).unwrap();
|
||||
txn.put(db, b"key1", b"val3", WriteFlags::empty()).unwrap();
|
||||
txn.put(db, b"key2", b"val1", WriteFlags::empty()).unwrap();
|
||||
txn.put(db, b"key2", b"val2", WriteFlags::empty()).unwrap();
|
||||
txn.put(db, b"key2", b"val3", WriteFlags::empty()).unwrap();
|
||||
txn.put(db, b"key3", b"val1", WriteFlags::empty()).unwrap();
|
||||
txn.put(db, b"key3", b"val2", WriteFlags::empty()).unwrap();
|
||||
txn.put(db, b"key3", b"val3", WriteFlags::empty()).unwrap();
|
||||
txn.commit().unwrap();
|
||||
|
||||
let txn = env.begin_rw_txn().unwrap();
|
||||
{
|
||||
let mut cur = txn.open_ro_cursor(db).unwrap();
|
||||
let iter = cur.iter_dup_of(b"key1");
|
||||
let vals = iter.map(|x| x.unwrap()).map(|(_,x)| x).collect::<Vec<_>>();
|
||||
assert_eq!(vals, vec![b"val1", b"val2", b"val3"]);
|
||||
|
||||
}
|
||||
txn.commit().unwrap();
|
||||
|
||||
let mut txn = env.begin_rw_txn().unwrap();
|
||||
txn.del(db, b"key1", Some(b"val2")).unwrap();
|
||||
txn.del(db, b"key2", None).unwrap();
|
||||
txn.commit().unwrap();
|
||||
|
||||
let txn = env.begin_rw_txn().unwrap();
|
||||
{
|
||||
let mut cur = txn.open_ro_cursor(db).unwrap();
|
||||
let iter = cur.iter_dup_of(b"key1");
|
||||
let vals = iter.map(|x| x.unwrap()).map(|(_,x)| x).collect::<Vec<_>>();
|
||||
assert_eq!(vals, vec![b"val1", b"val3"]);
|
||||
|
||||
let iter = cur.iter_dup_of(b"key2");
|
||||
assert_eq!(0, iter.count());
|
||||
}
|
||||
txn.commit().unwrap();
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_reserve() {
|
||||
let dir = TempDir::new("test").unwrap();
|
||||
|
@ -1 +0,0 @@
|
||||
{"files":{"Cargo.toml":"6d08d8713cae81e984bb50cbeb309c7746f4eb6b747a8e2affdca9c30230d353","build.rs":"4204dd0891e2eca08cb7cbcccfb36d1bdac137651c383f4a36368478fd836402","lmdb/libraries/liblmdb/.gitignore":"49e1a82819dab072b1c80d4570f817d6e2c6625d574df871f7a065ab44944727","lmdb/libraries/liblmdb/CHANGES":"d58e7fbdac22b7001c141df2f48b9d192770de52c9b4a0348552dcd4056ebbf7","lmdb/libraries/liblmdb/COPYRIGHT":"ce2436e2ab324485500b6fec5764b788ba082ac902ed00290f527d0170d8c90e","lmdb/libraries/liblmdb/Doxyfile":"5545f6b049040ce58e6d1a603eaea6b7fb8ae92459f2ab8d3bcbacabcce1014d","lmdb/libraries/liblmdb/LICENSE":"310fe25c858a9515fc8c8d7d1f24a67c9496f84a91e0a0e41ea9975b1371e569","lmdb/libraries/liblmdb/Makefile":"60b5f574e6642602f692a95956da61c588a265ad50b8059960c230b9e6aaf4fd","lmdb/libraries/liblmdb/intro.doc":"c7c2d970e7c277dc1f45bb3824c054fb73cf8d1666aa826e83c6a9a6a378839d","lmdb/libraries/liblmdb/lmdb.h":"c06ce42284b7544657e7b2d6b1f34cedd85234c193e673167b5d4b86372142ca","lmdb/libraries/liblmdb/mdb.c":"75b99ad8ef4ef747fb6ba93cc54b2d20cd91bef9121450c449cb2dbd77bf6d31","lmdb/libraries/liblmdb/mdb_copy.1":"c01f113a295d3c76b60f432896f24862cb0d2dadb14e26d72c6de9b55a254e2f","lmdb/libraries/liblmdb/mdb_copy.c":"b75a4d9b18aea89b8910bff44938244587a1a5863d1d609134298b1b5f019bfe","lmdb/libraries/liblmdb/mdb_dump.1":"adf51a57167bc6a64e0e6635e28ad2175924754f25eb1e9d89278b543c5e78d3","lmdb/libraries/liblmdb/mdb_dump.c":"7a67fa80539cb976cedd2bf7c56082366c33e07c9eac409e47efabaf4e31b62f","lmdb/libraries/liblmdb/mdb_load.1":"c1f7369d12b84fc92908256d3c1e422fa05576bde378fc84aca272d5aa2f4102","lmdb/libraries/liblmdb/mdb_load.c":"136169ce000cf254149ac00a0d9d4b12e9548649e7cdc9f6d6bd0943c16c11ea","lmdb/libraries/liblmdb/mdb_stat.1":"9c531fa57f1a528fa4bc4da4351b2332bff2e34bbd6f76dd0c1bbd915888cbfd","lmdb/libraries/liblmdb/mdb_stat.c":"235b872ae85aff627dbf27ae495c66cf3ed80eeca2188fe90d27d0486c03d0fa","lmdb/libraries/liblmdb/midl.c":"4877d6421f114a18a7074076b5b56c68567c0ba1a8328018af788cf5bb5c4f87","lmdb/libraries/liblmdb/midl.h":"853fc3115d2b827d6b53afcb03d39e0dcab6be108108955e549990ee5ece5c8a","lmdb/libraries/liblmdb/mtest.c":"4fd58e1ab4e445a73a6c655275f2c84523c128d34afa958a98b128c1d5f7ec24","lmdb/libraries/liblmdb/mtest2.c":"4b5711048ecbc255e3393c2fab589630b78fc3fc423cc98281629c7e45e78b4b","lmdb/libraries/liblmdb/mtest3.c":"b8e895e093a9d5bacbfde677d8f8e0aca9f0b9d8c2f4392bb47ff227b9c6a08d","lmdb/libraries/liblmdb/mtest4.c":"6e1fd62ca1036795dbadd1306fae4e48c34f00576805c0ac1dd73114ec58f85c","lmdb/libraries/liblmdb/mtest5.c":"24906ec930c259be3c2af5250fe1cb06dbb0f40ce3bad3c9f4991f681642e1e9","lmdb/libraries/liblmdb/mtest6.c":"f5c40dc672e5946874fe8a6a2d10fe8da2f509ffe48c73bdd4199b2d6756031c","lmdb/libraries/liblmdb/sample-bdb.txt":"7692f24c5f909328856008ed90e48cf224de1eb466d1f7623ffb7f32148eb3d9","lmdb/libraries/liblmdb/sample-mdb.txt":"40902b2560d72d348d19a23711244c59e3d684871a4262071312cc5a67e5ecae","lmdb/libraries/liblmdb/tooltag":"4734c6dc1fa7aec8c2e9646bd04bc5218ef6a03ad83a3b18de2ac4069eb94120","src/constants.rs":"af67740b5acccdc71b2267ec051bb60e5433c4f0313fe16dc0627376a52dcdff","src/ffi.rs":"caa9bbfb3868a7a9e9ad822d775e60ffa8c8c2f2450ac4ed403a93ddb7547899","src/lib.rs":"93504d2712ee68182bb59d5c6ad440b42892c221ecf014e77c325f2bb5cdddf1"},"package":null}
|
23
third_party/rust/lmdb-sys/Cargo.toml
vendored
23
third_party/rust/lmdb-sys/Cargo.toml
vendored
@ -1,23 +0,0 @@
|
||||
[package]
|
||||
|
||||
name = "lmdb-sys"
|
||||
# NB: When modifying, also modify html_root_url in lib.rs
|
||||
version = "0.8.0"
|
||||
authors = ["Dan Burkert <dan@danburkert.com>"]
|
||||
license = "Apache-2.0"
|
||||
|
||||
description = "Rust bindings for liblmdb."
|
||||
repository = "https://github.com/danburkert/lmdb-rs.git"
|
||||
readme = "../README.md"
|
||||
documentation = "https://docs.rs/lmdb-sys"
|
||||
keywords = ["LMDB", "database", "storage-engine", "bindings", "library"]
|
||||
categories = ["database", "external-ffi-bindings"]
|
||||
|
||||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2"
|
||||
|
||||
[build-dependencies]
|
||||
pkg-config = "0.3"
|
||||
cc = "1"
|
@ -1,23 +0,0 @@
|
||||
mtest
|
||||
mtest[23456]
|
||||
testdb
|
||||
mdb_copy
|
||||
mdb_stat
|
||||
mdb_dump
|
||||
mdb_load
|
||||
*.lo
|
||||
*.[ao]
|
||||
*.so
|
||||
*.exe
|
||||
*[~#]
|
||||
*.bak
|
||||
*.orig
|
||||
*.rej
|
||||
*.gcov
|
||||
*.gcda
|
||||
*.gcno
|
||||
core
|
||||
core.*
|
||||
valgrind.*
|
||||
man/
|
||||
html/
|
2
third_party/rust/rkv/.cargo-checksum.json
vendored
2
third_party/rust/rkv/.cargo-checksum.json
vendored
@ -1 +1 @@
|
||||
{"files":{"Cargo.toml":"a80cc710a906ed055c8d76679319d04e1825cbe95309cde92808a068c15bdca0","LICENSE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","README.md":"9dc24375b49fef42f35dec42e316e21827d7337622f9e7cf36243cd28808797a","examples/README.md":"143767fc145bf167ce269a65138cb3f7086cb715b8bc4f73626da82966e646f4","examples/iterator.rs":"a47bf9e90828e8ae3a1e5146f87efb5c48c7dbbd6e570e4eed4d6f07c8a2583d","examples/simple-store.rs":"f98feda8ec74f4dc6e06dd43d7708d42dc201a773673e10332d257251d536c41","run-all-examples.sh":"7f9d11d01017f77e1c9d26e3e82dfca8c6930deaec85e864458e33a7fa267de0","src/env.rs":"c501be4ea8e38b0127bf6a4706eae48995066ae0be057c08f36384233968455c","src/error.rs":"495112ac06104c4f83e033604a6121cb2e12140cf6450d38d8a7c8d9f5fea874","src/integer.rs":"3cf748279e4b1dd66c35c7e7989c1d3721d067ace097536756d2903683199680","src/lib.rs":"10d9e9fb91421f19667ee5869c64e26b87d2959813758bc081ce69ee0cb351e4","src/manager.rs":"621cbb3eebcb21fa85368122ba0fa8c721dd399334ca66813b795b396899ee81","src/readwrite.rs":"239115092dca693cea756e468879904fccaa7724b7df384eb2ec302ceda8881f","src/value.rs":"30e9784bb98110585fd1f06f263931a305a33bc457594006442c3352eb88f790","tests/manager.rs":"ebc8a9d6e55b1bc0c0699341141de2ce13e1306386ce5677a0eb4eb749f21d54"},"package":"79504d734e64f3d9391fbcaf15ca247421da461b95b9cdebd9af5679a4cfd8c8"}
|
||||
{"files":{"Cargo.toml":"a8e9c69b953f21a7ff7d1b7dec780f9adcde7f5537b7db4e86db45ff382e9132","LICENSE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","README.md":"9dc24375b49fef42f35dec42e316e21827d7337622f9e7cf36243cd28808797a","examples/README.md":"143767fc145bf167ce269a65138cb3f7086cb715b8bc4f73626da82966e646f4","examples/iterator.rs":"ddc3997e394a30ad82d78d2675a48c4617353f88b89bb9a3df5a3804d59b8ef9","examples/simple-store.rs":"9cec5f5a1277edf395775c22a29a27b1d9907ca693a3faa6cbd8e0f0bbff4347","run-all-examples.sh":"7f9d11d01017f77e1c9d26e3e82dfca8c6930deaec85e864458e33a7fa267de0","src/env.rs":"e71264a3ee9d5e87948f56a098099b1394935faa5d77dfcc75aff2c7445634d7","src/error.rs":"46632b8fcb1070a1860247e09a59d39772079ebfba5d3d1bbee03d08e1252275","src/lib.rs":"365cd108bec0e22e8aa010b738a7db2f0da4c6e4cbf1284a1e8ad7e2f1f05736","src/manager.rs":"f06b14ee64f2e58d890a3b37677790b707a02d328242c1af0ce3c74e9028edd8","src/readwrite.rs":"5d5dd64c9b36b7f75b69771e6909c6d48f109ee3725b357f6a9099ddb853e978","src/store.rs":"409d13b1ea0d1254dae947ecbce50e741fb71c3ca118a78803b734336dce6a8f","src/store/integer.rs":"a302c7fb70397b7dca6c116828a309d16c9bc664abe029342d8ebdd730d8b457","src/store/integermulti.rs":"f2c8f9c70d1615757ccb0a56a9642ad6769236fd4c406767f5a71fa84eeeaacf","src/store/multi.rs":"9456f5ff3cec3bf2fc27660b18483e1f0752b5f5f6279b4cfcd1898e236188cb","src/store/single.rs":"09f594b7150cbdad4b8a5dc208d4b0ce4962139b8c856276264dd24c98ac92a4","src/value.rs":"660a8e2fad3d13c3073d15f83f28e16662d9f1a682f6673ee1b885c3c28d44dd","tests/integer-store.rs":"f7e06c71b0dead2323c7c61fc8bcbffbdd3a4796eebf6138db9cce3dbba716a3","tests/manager.rs":"97ec61145dc227f4f5fbcb6449c096bbe5b9a09db4e61ff4491c0443fe9adf26","tests/multi-integer-store.rs":"83295b0135c502321304aa06b05d5a9eeab41b1438ed7ddf2cb1a3613dfef4d9"},"package":"967f320b7357a64909224619c90c1832f4532c3f19ec24350860bd64c2c7e272"}
|
10
third_party/rust/rkv/Cargo.toml
vendored
10
third_party/rust/rkv/Cargo.toml
vendored
@ -11,8 +11,9 @@
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "rkv"
|
||||
version = "0.7.0"
|
||||
version = "0.9.2"
|
||||
authors = ["Richard Newman <rnewman@twinql.com>", "Nan Jiang <najiang@mozilla.com>", "Myk Melez <myk@mykzilla.org>"]
|
||||
description = "a simple, humane, typed Rust interface to LMDB"
|
||||
homepage = "https://github.com/mozilla/rkv"
|
||||
@ -33,10 +34,10 @@ features = ["derive"]
|
||||
default_features = false
|
||||
|
||||
[dependencies.lazy_static]
|
||||
version = "1.0"
|
||||
version = "1.0.2"
|
||||
|
||||
[dependencies.lmdb-rkv]
|
||||
version = "0.9"
|
||||
version = "0.11.2"
|
||||
|
||||
[dependencies.ordered-float]
|
||||
version = "1.0"
|
||||
@ -44,6 +45,9 @@ version = "1.0"
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
|
||||
[dependencies.serde_derive]
|
||||
version = "1.0"
|
||||
|
||||
[dependencies.url]
|
||||
version = "1.7.0"
|
||||
|
||||
|
28
third_party/rust/rkv/examples/iterator.rs
vendored
28
third_party/rust/rkv/examples/iterator.rs
vendored
@ -7,14 +7,12 @@
|
||||
//!
|
||||
//! cargo run --example iterator
|
||||
|
||||
extern crate rkv;
|
||||
extern crate tempfile;
|
||||
|
||||
use rkv::{
|
||||
Manager,
|
||||
Rkv,
|
||||
Store,
|
||||
SingleStore,
|
||||
StoreError,
|
||||
StoreOptions,
|
||||
Value,
|
||||
};
|
||||
use tempfile::Builder;
|
||||
@ -29,7 +27,7 @@ fn main() {
|
||||
|
||||
let created_arc = Manager::singleton().write().unwrap().get_or_create(p, Rkv::new).unwrap();
|
||||
let k = created_arc.read().unwrap();
|
||||
let store = k.open_or_create("store").unwrap();
|
||||
let store = k.open_single("store", StoreOptions::create()).unwrap();
|
||||
|
||||
populate_store(&k, store).unwrap();
|
||||
|
||||
@ -38,29 +36,29 @@ fn main() {
|
||||
println!("Iterating from the beginning...");
|
||||
// Reader::iter_start() iterates from the first item in the store, and
|
||||
// returns the (key, value) tuples in order.
|
||||
let mut iter = reader.iter_start(store).unwrap();
|
||||
while let Some((country, city)) = iter.next() {
|
||||
let mut iter = store.iter_start(&reader).unwrap();
|
||||
while let Some(Ok((country, city))) = iter.next() {
|
||||
println!("{}, {:?}", str::from_utf8(country).unwrap(), city);
|
||||
}
|
||||
|
||||
println!("");
|
||||
println!();
|
||||
println!("Iterating from the given key...");
|
||||
// Reader::iter_from() iterates from the first key equal to or greater
|
||||
// than the given key.
|
||||
let mut iter = reader.iter_from(store, "Japan").unwrap();
|
||||
while let Some((country, city)) = iter.next() {
|
||||
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!("");
|
||||
println!();
|
||||
println!("Iterating from the given prefix...");
|
||||
let mut iter = reader.iter_from(store, "Un").unwrap();
|
||||
while let Some((country, city)) = iter.next() {
|
||||
let mut iter = store.iter_from(&reader, "Un").unwrap();
|
||||
while let Some(Ok((country, city))) = iter.next() {
|
||||
println!("{}, {:?}", str::from_utf8(country).unwrap(), city);
|
||||
}
|
||||
}
|
||||
|
||||
fn populate_store(k: &Rkv, store: Store) -> Result<(), StoreError> {
|
||||
fn populate_store(k: &Rkv, store: SingleStore) -> Result<(), StoreError> {
|
||||
let mut writer = k.write()?;
|
||||
for (country, city) in vec![
|
||||
("Canada", Value::Str("Ottawa")),
|
||||
@ -71,7 +69,7 @@ fn populate_store(k: &Rkv, store: Store) -> Result<(), StoreError> {
|
||||
("United Kingdom", Value::Str("London")),
|
||||
("Japan", Value::Str("Tokyo")),
|
||||
] {
|
||||
writer.put(store, country, &city)?;
|
||||
store.put(&mut writer, country, &city)?;
|
||||
}
|
||||
writer.commit()
|
||||
}
|
||||
|
128
third_party/rust/rkv/examples/simple-store.rs
vendored
128
third_party/rust/rkv/examples/simple-store.rs
vendored
@ -7,18 +7,46 @@
|
||||
//!
|
||||
//! cargo run --example simple-store
|
||||
|
||||
extern crate rkv;
|
||||
extern crate tempfile;
|
||||
|
||||
use rkv::{
|
||||
Manager,
|
||||
MultiStore,
|
||||
Rkv,
|
||||
StoreOptions,
|
||||
Value,
|
||||
Writer,
|
||||
};
|
||||
use tempfile::Builder;
|
||||
|
||||
use std::fs;
|
||||
|
||||
fn getput<'env, 's>(store: MultiStore, writer: &'env mut Writer, ids: &'s mut Vec<String>) {
|
||||
let keys = vec!["str1", "str2", "str3"];
|
||||
// we convert the writer into a cursor so that we can safely read
|
||||
for k in keys.iter() {
|
||||
// this is a multi-valued database, so get returns an iterator
|
||||
let mut iter = store.get(writer, k).unwrap();
|
||||
while let Some(Ok((_key, val))) = iter.next() {
|
||||
if let Value::Str(s) = val.unwrap() {
|
||||
ids.push(s.to_owned());
|
||||
} else {
|
||||
panic!("didn't get a string back!");
|
||||
}
|
||||
}
|
||||
}
|
||||
for id in ids {
|
||||
store.put(writer, &id, &Value::Blob(b"weeeeeee")).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn delete(store: MultiStore, writer: &mut Writer) {
|
||||
let keys = vec!["str1", "str2", "str3"];
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let root = Builder::new().prefix("simple-db").tempdir().unwrap();
|
||||
fs::create_dir_all(root.path()).unwrap();
|
||||
@ -29,61 +57,82 @@ fn main() {
|
||||
let k = created_arc.read().unwrap();
|
||||
|
||||
// Creates a store called "store"
|
||||
let store = k.open_or_create("store").unwrap();
|
||||
let store = k.open_single("store", StoreOptions::create()).unwrap();
|
||||
|
||||
let multistore = k.open_multi("multistore", StoreOptions::create()).unwrap();
|
||||
|
||||
println!("Inserting data...");
|
||||
{
|
||||
// Use a writer to mutate the store
|
||||
let mut writer = k.write().unwrap();
|
||||
writer.put(store, "int", &Value::I64(1234)).unwrap();
|
||||
writer.put(store, "uint", &Value::U64(1234_u64)).unwrap();
|
||||
writer.put(store, "float", &Value::F64(1234.0.into())).unwrap();
|
||||
writer.put(store, "instant", &Value::Instant(1528318073700)).unwrap();
|
||||
writer.put(store, "boolean", &Value::Bool(true)).unwrap();
|
||||
writer.put(store, "string", &Value::Str("héllo, yöu")).unwrap();
|
||||
writer.put(store, "json", &Value::Json(r#"{"foo":"bar", "number": 1}"#)).unwrap();
|
||||
writer.put(store, "blob", &Value::Blob(b"blob")).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();
|
||||
writer.commit().unwrap();
|
||||
}
|
||||
|
||||
println!("Testing getput");
|
||||
{
|
||||
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();
|
||||
getput(multistore, &mut writer, &mut ids);
|
||||
writer.commit().unwrap();
|
||||
let mut writer = k.write().unwrap();
|
||||
delete(multistore, &mut writer);
|
||||
writer.commit().unwrap();
|
||||
}
|
||||
println!("Looking up keys...");
|
||||
{
|
||||
// Use a reader to query the store
|
||||
let reader = k.read().unwrap();
|
||||
println!("Get int {:?}", reader.get(store, "int").unwrap());
|
||||
println!("Get uint {:?}", reader.get(store, "uint").unwrap());
|
||||
println!("Get float {:?}", reader.get(store, "float").unwrap());
|
||||
println!("Get instant {:?}", reader.get(store, "instant").unwrap());
|
||||
println!("Get boolean {:?}", reader.get(store, "boolean").unwrap());
|
||||
println!("Get string {:?}", reader.get(store, "string").unwrap());
|
||||
println!("Get json {:?}", reader.get(store, "json").unwrap());
|
||||
println!("Get blob {:?}", reader.get(store, "blob").unwrap());
|
||||
println!("Get non-existent {:?}", reader.get(store, "non-existent").unwrap());
|
||||
println!("Get int {:?}", store.get(&reader, "int").unwrap());
|
||||
println!("Get uint {:?}", store.get(&reader, "uint").unwrap());
|
||||
println!("Get float {:?}", store.get(&reader, "float").unwrap());
|
||||
println!("Get instant {:?}", store.get(&reader, "instant").unwrap());
|
||||
println!("Get boolean {:?}", store.get(&reader, "boolean").unwrap());
|
||||
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!("Looking up keys via Writer.get()...");
|
||||
{
|
||||
let mut writer = k.write().unwrap();
|
||||
writer.put(store, "foo", &Value::Str("bar")).unwrap();
|
||||
writer.put(store, "bar", &Value::Str("baz")).unwrap();
|
||||
writer.delete(store, "foo").unwrap();
|
||||
println!("It should be None! ({:?})", writer.get(store, "foo").unwrap());
|
||||
println!("Get bar ({:?})", writer.get(store, "bar").unwrap());
|
||||
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!("Get bar ({:?})", store.get(&writer, "bar").unwrap());
|
||||
writer.commit().unwrap();
|
||||
let reader = k.read().expect("reader");
|
||||
println!("It should be None! ({:?})", reader.get(store, "foo").unwrap());
|
||||
println!("Get bar {:?}", reader.get(store, "bar").unwrap());
|
||||
println!("It should be None! ({:?})", store.get(&reader, "foo").unwrap());
|
||||
println!("Get bar {:?}", store.get(&reader, "bar").unwrap());
|
||||
}
|
||||
|
||||
println!("Aborting transaction...");
|
||||
{
|
||||
// Aborting a write transaction rollbacks the change(s)
|
||||
let mut writer = k.write().unwrap();
|
||||
writer.put(store, "foo", &Value::Str("bar")).unwrap();
|
||||
store.put(&mut writer, "foo", &Value::Str("bar")).unwrap();
|
||||
writer.abort();
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
println!("It should be None! ({:?})", reader.get(store, "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.
|
||||
@ -93,27 +142,28 @@ fn main() {
|
||||
{
|
||||
// Deleting a key/value also requires a write transaction
|
||||
let mut writer = k.write().unwrap();
|
||||
writer.put(store, "foo", &Value::Str("bar")).unwrap();
|
||||
writer.delete(store, "foo").unwrap();
|
||||
println!("It should be None! ({:?})", writer.get(store, "foo").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());
|
||||
writer.commit().unwrap();
|
||||
|
||||
// Committing a transaction consumes the writer, preventing you
|
||||
// from reusing it by failing and reporting a compile-time error.
|
||||
// This line would report error[E0382]: use of moved value: `writer`.
|
||||
// writer.put(store, "baz", &Value::Str("buz")).unwrap();
|
||||
// store.put(&mut writer, "baz", &Value::Str("buz")).unwrap();
|
||||
}
|
||||
|
||||
println!("Write and read on multiple stores...");
|
||||
{
|
||||
let another_store = k.open_or_create("another_store").unwrap();
|
||||
let another_store = k.open_single("another_store", StoreOptions::create()).unwrap();
|
||||
let mut writer = k.write().unwrap();
|
||||
writer.put(store, "foo", &Value::Str("bar")).unwrap();
|
||||
writer.put(another_store, "foo", &Value::Str("baz")).unwrap();
|
||||
store.put(&mut writer, "foo", &Value::Str("bar")).unwrap();
|
||||
another_store.put(&mut writer, "foo", &Value::Str("baz")).unwrap();
|
||||
writer.commit().unwrap();
|
||||
|
||||
let reader = k.read().unwrap();
|
||||
println!("Get from store value: {:?}", reader.get(store, "foo").unwrap());
|
||||
println!("Get from another store value: {:?}", reader.get(another_store, "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());
|
||||
}
|
||||
|
693
third_party/rust/rkv/src/env.rs
vendored
693
third_party/rust/rkv/src/env.rs
vendored
File diff suppressed because it is too large
Load Diff
5
third_party/rust/rkv/src/error.rs
vendored
5
third_party/rust/rkv/src/error.rs
vendored
@ -1,4 +1,4 @@
|
||||
// Copyright 2018 Mozilla
|
||||
// Copyright 2018-2019 Mozilla
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
@ -11,9 +11,10 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use bincode;
|
||||
use failure::Fail;
|
||||
use lmdb;
|
||||
|
||||
use value::Type;
|
||||
use crate::value::Type;
|
||||
|
||||
#[derive(Debug, Fail)]
|
||||
pub enum DataError {
|
||||
|
171
third_party/rust/rkv/src/integer.rs
vendored
171
third_party/rust/rkv/src/integer.rs
vendored
@ -1,171 +0,0 @@
|
||||
// Copyright 2018 Mozilla
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// 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.
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use bincode::serialize;
|
||||
|
||||
use serde::Serialize;
|
||||
|
||||
use lmdb::Database;
|
||||
|
||||
use error::{
|
||||
DataError,
|
||||
StoreError,
|
||||
};
|
||||
|
||||
use value::Value;
|
||||
|
||||
use readwrite::{
|
||||
Reader,
|
||||
Store,
|
||||
Writer,
|
||||
};
|
||||
|
||||
pub trait EncodableKey {
|
||||
fn to_bytes(&self) -> Result<Vec<u8>, DataError>;
|
||||
}
|
||||
|
||||
pub trait PrimitiveInt: EncodableKey {}
|
||||
|
||||
impl PrimitiveInt for u32 {}
|
||||
|
||||
impl<T> EncodableKey for T
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
fn to_bytes(&self) -> Result<Vec<u8>, DataError> {
|
||||
serialize(self) // TODO: limited key length.
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Key<K> {
|
||||
bytes: Vec<u8>,
|
||||
phantom: PhantomData<K>,
|
||||
}
|
||||
|
||||
impl<K> AsRef<[u8]> for Key<K>
|
||||
where
|
||||
K: EncodableKey,
|
||||
{
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.bytes.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<K> Key<K>
|
||||
where
|
||||
K: EncodableKey,
|
||||
{
|
||||
fn new(k: K) -> Result<Key<K>, DataError> {
|
||||
Ok(Key {
|
||||
bytes: k.to_bytes()?,
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IntegerReader<'env, K>
|
||||
where
|
||||
K: PrimitiveInt,
|
||||
{
|
||||
inner: Reader<'env, Key<K>>,
|
||||
}
|
||||
|
||||
impl<'env, K> IntegerReader<'env, K>
|
||||
where
|
||||
K: PrimitiveInt,
|
||||
{
|
||||
pub(crate) fn new(reader: Reader<Key<K>>) -> IntegerReader<K> {
|
||||
IntegerReader {
|
||||
inner: reader,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, store: IntegerStore, k: K) -> Result<Option<Value>, StoreError> {
|
||||
self.inner.get(store.0, Key::new(k)?)
|
||||
}
|
||||
|
||||
pub fn abort(self) {
|
||||
self.inner.abort();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IntegerWriter<'env, K>
|
||||
where
|
||||
K: PrimitiveInt,
|
||||
{
|
||||
inner: Writer<'env, Key<K>>,
|
||||
}
|
||||
|
||||
impl<'env, K> IntegerWriter<'env, K>
|
||||
where
|
||||
K: PrimitiveInt,
|
||||
{
|
||||
pub(crate) fn new(writer: Writer<Key<K>>) -> IntegerWriter<K> {
|
||||
IntegerWriter {
|
||||
inner: writer,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, store: IntegerStore, k: K) -> Result<Option<Value>, StoreError> {
|
||||
self.inner.get(store.0, Key::new(k)?)
|
||||
}
|
||||
|
||||
pub fn put(&mut self, store: IntegerStore, k: K, v: &Value) -> Result<(), StoreError> {
|
||||
self.inner.put(store.0, Key::new(k)?, v)
|
||||
}
|
||||
|
||||
fn abort(self) {
|
||||
self.inner.abort();
|
||||
}
|
||||
|
||||
fn commit(self) -> Result<(), StoreError> {
|
||||
self.inner.commit()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct IntegerStore(Store);
|
||||
|
||||
impl IntegerStore {
|
||||
pub fn new(db: Database) -> IntegerStore {
|
||||
IntegerStore(Store::new(db))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
extern crate tempfile;
|
||||
|
||||
use self::tempfile::Builder;
|
||||
use std::fs;
|
||||
|
||||
use super::*;
|
||||
use *;
|
||||
|
||||
#[test]
|
||||
fn test_integer_keys() {
|
||||
let root = Builder::new().prefix("test_integer_keys").tempdir().expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
let k = Rkv::new(root.path()).expect("new succeeded");
|
||||
let s = k.open_or_create_integer("s").expect("open");
|
||||
|
||||
let mut writer = k.write_int::<u32>().expect("writer");
|
||||
|
||||
writer.put(s, 123, &Value::Str("hello!")).expect("write");
|
||||
assert_eq!(writer.get(s, 123).expect("read"), Some(Value::Str("hello!")));
|
||||
writer.commit().expect("committed");
|
||||
|
||||
let reader = k.read_int::<u32>().expect("reader");
|
||||
assert_eq!(reader.get(s, 123).expect("read"), Some(Value::Str("hello!")));
|
||||
}
|
||||
}
|
193
third_party/rust/rkv/src/lib.rs
vendored
193
third_party/rust/rkv/src/lib.rs
vendored
@ -1,4 +1,4 @@
|
||||
// Copyright 2018 Mozilla
|
||||
// Copyright 2018-2019 Mozilla
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
@ -15,17 +15,19 @@
|
||||
//! - Avoid LMDB's sharp edges (e.g., obscure error codes for common situations).
|
||||
//! - Report errors via [failure](https://docs.rs/failure/).
|
||||
//! - Correctly restrict access to one handle per process via a [Manager](struct.Manager.html).
|
||||
//! - Use Rust's type system to make single-typed key stores (including LMDB's own integer-keyed stores) safe and ergonomic.
|
||||
//! - Use Rust's type system to make single-typed key stores (including LMDB's own integer-keyed stores)
|
||||
//! safe and ergonomic.
|
||||
//! - Encode and decode values via [bincode](https://docs.rs/bincode/)/[serde](https://docs.rs/serde/)
|
||||
//! and type tags, achieving platform-independent storage and input/output flexibility.
|
||||
//!
|
||||
//! It exposes these primary abstractions:
|
||||
//!
|
||||
//! - [Manager](struct.Manager.html): a singleton that controls access to LMDB environments
|
||||
//! - [Rkv](struct.Rkv.html): an LMDB environment, which contains a set of key/value databases
|
||||
//! - [Store](struct.Store.html): an LMDB database, which contains a set of key/value pairs
|
||||
//! - [Rkv](struct.Rkv.html): an LMDB environment that contains a set of key/value databases
|
||||
//! - [SingleStore](store/single/struct.SingleStore.html): an LMDB database that contains a set of key/value pairs
|
||||
//!
|
||||
//! Keys can be anything that implements `AsRef<[u8]>` or integers (when accessing an [IntegerStore](struct.IntegerStore.html)).
|
||||
//! Keys can be anything that implements `AsRef<[u8]>` or integers
|
||||
//! (when accessing an [IntegerStore](store/integer/struct.IntegerStore.html)).
|
||||
//! Values can be any of the types defined by the [Value](value/enum.Value.html) enum, including:
|
||||
//!
|
||||
//! - booleans (`Value::Bool`)
|
||||
@ -38,10 +40,7 @@
|
||||
//!
|
||||
//! ## Basic Usage
|
||||
//! ```
|
||||
//! extern crate rkv;
|
||||
//! extern crate tempfile;
|
||||
//!
|
||||
//! use rkv::{Manager, Rkv, Store, Value};
|
||||
//! use rkv::{Manager, Rkv, SingleStore, Value, StoreOptions};
|
||||
//! use std::fs;
|
||||
//! use tempfile::Builder;
|
||||
//!
|
||||
@ -59,34 +58,32 @@
|
||||
//!
|
||||
//! // The Manager enforces that each process opens the same environment
|
||||
//! // at most once by caching a handle to each environment that it opens.
|
||||
//! // Retrieve the handle to an opened environment—or create one if it hasn't
|
||||
//! // already been opened—by calling `Manager.get_or_create()`, passing it
|
||||
//! // an `Rkv` method that opens an environment (`Rkv::new` in this case):
|
||||
//! // Use it to retrieve the handle to an opened environment—or create one
|
||||
//! // if it hasn't already been opened:
|
||||
//! let created_arc = Manager::singleton().write().unwrap().get_or_create(path, Rkv::new).unwrap();
|
||||
//! let env = created_arc.read().unwrap();
|
||||
//!
|
||||
//! // Call `Rkv.open_or_create_default()` to get a handle to the default
|
||||
//! // (unnamed) store for the environment.
|
||||
//! let store: Store = env.open_or_create_default().unwrap();
|
||||
//! // Then you can use the environment handle to get a handle to a datastore:
|
||||
//! let store: SingleStore = env.open_single("mydb", StoreOptions::create()).unwrap();
|
||||
//!
|
||||
//! {
|
||||
//! // Use a write transaction to mutate the store by calling
|
||||
//! // `Rkv.write()` to create a `Writer`. There can be only one
|
||||
//! // writer for a given store; opening a second one will block
|
||||
//! // until the first completes.
|
||||
//! // Use a write transaction to mutate the store via a `Writer`.
|
||||
//! // There can be only one writer for a given environment, so opening
|
||||
//! // a second one will block until the first completes.
|
||||
//! let mut writer = env.write().unwrap();
|
||||
//!
|
||||
//! // Writer takes a `Store` reference as the first argument.
|
||||
//! // Keys are `AsRef<[u8]>`, while values are `Value` enum instances.
|
||||
//! // Use the `Blob` variant to store arbitrary collections of bytes.
|
||||
//! writer.put(store, "int", &Value::I64(1234)).unwrap();
|
||||
//! writer.put(store, "uint", &Value::U64(1234_u64)).unwrap();
|
||||
//! writer.put(store, "float", &Value::F64(1234.0.into())).unwrap();
|
||||
//! writer.put(store, "instant", &Value::Instant(1528318073700)).unwrap();
|
||||
//! writer.put(store, "boolean", &Value::Bool(true)).unwrap();
|
||||
//! writer.put(store, "string", &Value::Str("héllo, yöu")).unwrap();
|
||||
//! writer.put(store, "json", &Value::Json(r#"{"foo":"bar", "number": 1}"#)).unwrap();
|
||||
//! writer.put(store, "blob", &Value::Blob(b"blob")).unwrap();
|
||||
//! // Putting data returns a `Result<(), StoreError>`, where StoreError
|
||||
//! // is an enum identifying the reason for a failure.
|
||||
//! 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(1528318073700)).unwrap();
|
||||
//! store.put(&mut writer, "boolean", &Value::Bool(true)).unwrap();
|
||||
//! store.put(&mut writer, "string", &Value::Str("Héllo, wörld!")).unwrap();
|
||||
//! store.put(&mut writer, "json", &Value::Json(r#"{"foo":"bar", "number": 1}"#)).unwrap();
|
||||
//! store.put(&mut writer, "blob", &Value::Blob(b"blob")).unwrap();
|
||||
//!
|
||||
//! // You must commit a write transaction before the writer goes out
|
||||
//! // of scope, or the transaction will abort and the data won't persist.
|
||||
@ -94,24 +91,23 @@
|
||||
//! }
|
||||
//!
|
||||
//! {
|
||||
//! // Use a read transaction to query the store by calling `Rkv.read()`
|
||||
//! // to create a `Reader`. There can be unlimited concurrent readers
|
||||
//! // for a store, and readers never block on a writer nor other readers.
|
||||
//! // Use a read transaction to query the store via a `Reader`.
|
||||
//! // There can be multiple concurrent readers for a store, and readers
|
||||
//! // never block on a writer nor other readers.
|
||||
//! let reader = env.read().expect("reader");
|
||||
//!
|
||||
//! // To retrieve data, call `Reader.get()`, passing it the target store
|
||||
//! // and the key for the value to retrieve.
|
||||
//! println!("Get int {:?}", reader.get(store, "int").unwrap());
|
||||
//! println!("Get uint {:?}", reader.get(store, "uint").unwrap());
|
||||
//! println!("Get float {:?}", reader.get(store, "float").unwrap());
|
||||
//! println!("Get instant {:?}", reader.get(store, "instant").unwrap());
|
||||
//! println!("Get boolean {:?}", reader.get(store, "boolean").unwrap());
|
||||
//! println!("Get string {:?}", reader.get(store, "string").unwrap());
|
||||
//! println!("Get json {:?}", reader.get(store, "json").unwrap());
|
||||
//! println!("Get blob {:?}", reader.get(store, "blob").unwrap());
|
||||
//! // Keys are `AsRef<u8>`, and the return value is `Result<Option<Value>, StoreError>`.
|
||||
//! println!("Get int {:?}", store.get(&reader, "int").unwrap());
|
||||
//! println!("Get uint {:?}", store.get(&reader, "uint").unwrap());
|
||||
//! println!("Get float {:?}", store.get(&reader, "float").unwrap());
|
||||
//! println!("Get instant {:?}", store.get(&reader, "instant").unwrap());
|
||||
//! println!("Get boolean {:?}", store.get(&reader, "boolean").unwrap());
|
||||
//! println!("Get string {:?}", store.get(&reader, "string").unwrap());
|
||||
//! println!("Get json {:?}", store.get(&reader, "json").unwrap());
|
||||
//! println!("Get blob {:?}", store.get(&reader, "blob").unwrap());
|
||||
//!
|
||||
//! // Retrieving a non-existent value returns `Ok(None)`.
|
||||
//! println!("Get non-existent value {:?}", reader.get(store, "non-existent"));
|
||||
//! println!("Get non-existent value {:?}", store.get(&reader, "non-existent").unwrap());
|
||||
//!
|
||||
//! // A read transaction will automatically close once the reader
|
||||
//! // goes out of scope, so isn't necessary to close it explicitly,
|
||||
@ -121,11 +117,10 @@
|
||||
//! {
|
||||
//! // Aborting a write transaction rolls back the change(s).
|
||||
//! let mut writer = env.write().unwrap();
|
||||
//! writer.put(store, "foo", &Value::Str("bar")).unwrap();
|
||||
//! store.put(&mut writer, "foo", &Value::Str("bar")).unwrap();
|
||||
//! writer.abort();
|
||||
//!
|
||||
//! let reader = env.read().expect("reader");
|
||||
//! println!("It should be None! ({:?})", reader.get(store, "foo").unwrap());
|
||||
//! println!("It should be None! ({:?})", store.get(&reader, "foo").unwrap());
|
||||
//! }
|
||||
//!
|
||||
//! {
|
||||
@ -134,54 +129,52 @@
|
||||
//! // implicitly be aborted once they go out of scope.
|
||||
//! {
|
||||
//! let mut writer = env.write().unwrap();
|
||||
//! writer.put(store, "foo", &Value::Str("bar")).unwrap();
|
||||
//! store.put(&mut writer, "foo", &Value::Str("bar")).unwrap();
|
||||
//! }
|
||||
//! let reader = env.read().expect("reader");
|
||||
//! println!("It should be None! ({:?})", reader.get(store, "foo").unwrap());
|
||||
//! println!("It should be None! ({:?})", store.get(&reader, "foo").unwrap());
|
||||
//! }
|
||||
//!
|
||||
//! {
|
||||
//! // Deleting a key/value pair also requires a write transaction.
|
||||
//! let mut writer = env.write().unwrap();
|
||||
//! writer.put(store, "foo", &Value::Str("bar")).unwrap();
|
||||
//! writer.put(store, "bar", &Value::Str("baz")).unwrap();
|
||||
//! writer.delete(store, "foo").unwrap();
|
||||
//! store.put(&mut writer, "foo", &Value::Str("bar")).unwrap();
|
||||
//! store.put(&mut writer, "bar", &Value::Str("baz")).unwrap();
|
||||
//! store.delete(&mut writer, "foo").unwrap();
|
||||
//!
|
||||
//! // A write transaction also supports reading, the version of the
|
||||
//! // store that it reads includes changes it has made regardless of
|
||||
//! // A write transaction also supports reading, and the version of the
|
||||
//! // store that it reads includes the changes it has made regardless of
|
||||
//! // the commit state of that transaction.
|
||||
|
||||
//! // In the code above, "foo" and "bar" were put into the store,
|
||||
//! // then "foo" was deleted so only "bar" will return a result.
|
||||
//! println!("It should be None! ({:?})", writer.get(store, "foo").unwrap());
|
||||
//! println!("Get bar ({:?})", writer.get(store, "bar").unwrap());
|
||||
//! // then "foo" was deleted so only "bar" will return a result when the
|
||||
//! // database is queried via the writer.
|
||||
//! println!("It should be None! ({:?})", store.get(&writer, "foo").unwrap());
|
||||
//! println!("Get bar ({:?})", store.get(&writer, "bar").unwrap());
|
||||
//!
|
||||
//! // But a reader won't see that change until the write transaction
|
||||
//! // is committed.
|
||||
//! {
|
||||
//! let reader = env.read().expect("reader");
|
||||
//! println!("Get foo {:?}", store.get(&reader, "foo").unwrap());
|
||||
//! println!("Get bar {:?}", store.get(&reader, "bar").unwrap());
|
||||
//! }
|
||||
//! writer.commit().unwrap();
|
||||
//! let reader = env.read().expect("reader");
|
||||
//! println!("It should be None! ({:?})", reader.get(store, "foo").unwrap());
|
||||
//! println!("Get bar {:?}", reader.get(store, "bar").unwrap());
|
||||
//! {
|
||||
//! let reader = env.read().expect("reader");
|
||||
//! println!("It should be None! ({:?})", store.get(&reader, "foo").unwrap());
|
||||
//! println!("Get bar {:?}", store.get(&reader, "bar").unwrap());
|
||||
//! }
|
||||
//!
|
||||
//! // Committing a transaction consumes the writer, preventing you
|
||||
//! // from reusing it by failing at compile time with an error.
|
||||
//! // This line would report error[E0382]: use of moved value: `writer`.
|
||||
//! // writer.put(store, "baz", &Value::Str("buz")).unwrap();
|
||||
//! // This line would report error[E0382]: borrow of moved value: `writer`.
|
||||
//! // store.put(&mut writer, "baz", &Value::Str("buz")).unwrap();
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate arrayref;
|
||||
#[macro_use]
|
||||
extern crate failure;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
extern crate bincode;
|
||||
extern crate lmdb;
|
||||
extern crate ordered_float;
|
||||
extern crate serde; // So we can specify trait bounds. Everything else is bincode.
|
||||
extern crate url;
|
||||
extern crate uuid;
|
||||
|
||||
pub use lmdb::{
|
||||
DatabaseFlags,
|
||||
EnvironmentBuilder,
|
||||
@ -191,34 +184,50 @@ pub use lmdb::{
|
||||
|
||||
mod env;
|
||||
pub mod error;
|
||||
mod integer;
|
||||
mod manager;
|
||||
mod readwrite;
|
||||
pub mod store;
|
||||
pub mod value;
|
||||
|
||||
pub use env::Rkv;
|
||||
pub use lmdb::{
|
||||
Cursor,
|
||||
Database,
|
||||
Iter as LmdbIter,
|
||||
RoCursor,
|
||||
Stat,
|
||||
};
|
||||
|
||||
pub use error::{
|
||||
pub use self::readwrite::{
|
||||
Reader,
|
||||
Writer,
|
||||
};
|
||||
pub use self::store::integer::{
|
||||
IntegerStore,
|
||||
PrimitiveInt,
|
||||
};
|
||||
pub use self::store::integermulti::MultiIntegerStore;
|
||||
pub use self::store::multi::MultiStore;
|
||||
pub use self::store::single::SingleStore;
|
||||
pub use self::store::Options as StoreOptions;
|
||||
|
||||
pub use self::env::Rkv;
|
||||
|
||||
pub use self::error::{
|
||||
DataError,
|
||||
StoreError,
|
||||
};
|
||||
|
||||
pub use integer::{
|
||||
IntegerReader,
|
||||
IntegerStore,
|
||||
IntegerWriter,
|
||||
PrimitiveInt,
|
||||
};
|
||||
pub use self::manager::Manager;
|
||||
|
||||
pub use manager::Manager;
|
||||
|
||||
pub use readwrite::{
|
||||
Reader,
|
||||
Store,
|
||||
Writer,
|
||||
};
|
||||
|
||||
pub use value::{
|
||||
pub use self::value::{
|
||||
OwnedValue,
|
||||
Value,
|
||||
};
|
||||
|
||||
fn read_transform(val: Result<&[u8], lmdb::Error>) -> Result<Option<Value>, StoreError> {
|
||||
match val {
|
||||
Ok(bytes) => Value::from_tagged_slice(bytes).map(Some).map_err(StoreError::DataError),
|
||||
Err(lmdb::Error::NotFound) => Ok(None),
|
||||
Err(e) => Err(StoreError::LmdbError(e)),
|
||||
}
|
||||
}
|
||||
|
11
third_party/rust/rkv/src/manager.rs
vendored
11
third_party/rust/rkv/src/manager.rs
vendored
@ -1,4 +1,4 @@
|
||||
// Copyright 2018 Mozilla
|
||||
// Copyright 2018-2019 Mozilla
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
@ -8,6 +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 lazy_static::lazy_static;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use std::io::{
|
||||
@ -32,9 +33,9 @@ use std::sync::{
|
||||
|
||||
use url::Url;
|
||||
|
||||
use error::StoreError;
|
||||
use crate::error::StoreError;
|
||||
|
||||
use Rkv;
|
||||
use crate::Rkv;
|
||||
|
||||
/// A process is only permitted to have one open handle to each Rkv environment.
|
||||
/// This manager exists to enforce that constraint: don't open environments directly.
|
||||
@ -121,10 +122,8 @@ impl Manager {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
extern crate tempfile;
|
||||
|
||||
use self::tempfile::Builder;
|
||||
use std::fs;
|
||||
use tempfile::Builder;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
193
third_party/rust/rkv/src/readwrite.rs
vendored
193
third_party/rust/rkv/src/readwrite.rs
vendored
@ -1,4 +1,4 @@
|
||||
// Copyright 2018 Mozilla
|
||||
// Copyright 2018-2019 Mozilla
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
@ -8,167 +8,84 @@
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use lmdb;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use lmdb::{
|
||||
Cursor,
|
||||
Database,
|
||||
Iter as LmdbIter,
|
||||
RoCursor,
|
||||
RoTransaction,
|
||||
RwTransaction,
|
||||
Transaction,
|
||||
WriteFlags,
|
||||
};
|
||||
|
||||
use lmdb::WriteFlags;
|
||||
use crate::error::StoreError;
|
||||
use crate::read_transform;
|
||||
use crate::value::Value;
|
||||
|
||||
use error::StoreError;
|
||||
pub struct Reader<'env>(pub RoTransaction<'env>);
|
||||
pub struct Writer<'env>(pub RwTransaction<'env>);
|
||||
|
||||
use value::Value;
|
||||
|
||||
fn read_transform(val: Result<&[u8], lmdb::Error>) -> Result<Option<Value>, StoreError> {
|
||||
match val {
|
||||
Ok(bytes) => Value::from_tagged_slice(bytes).map(Some).map_err(StoreError::DataError),
|
||||
Err(lmdb::Error::NotFound) => Ok(None),
|
||||
Err(e) => Err(StoreError::LmdbError(e)),
|
||||
}
|
||||
pub trait Readable {
|
||||
fn get<K: AsRef<[u8]>>(&self, db: Database, k: &K) -> Result<Option<Value>, StoreError>;
|
||||
fn open_ro_cursor(&self, db: Database) -> Result<RoCursor, StoreError>;
|
||||
}
|
||||
|
||||
pub struct Writer<'env, K>
|
||||
where
|
||||
K: AsRef<[u8]>,
|
||||
{
|
||||
tx: RwTransaction<'env>,
|
||||
phantom: PhantomData<K>,
|
||||
}
|
||||
|
||||
pub struct Reader<'env, K>
|
||||
where
|
||||
K: AsRef<[u8]>,
|
||||
{
|
||||
tx: RoTransaction<'env>,
|
||||
phantom: PhantomData<K>,
|
||||
}
|
||||
|
||||
pub struct Iter<'env> {
|
||||
iter: LmdbIter<'env>,
|
||||
cursor: RoCursor<'env>,
|
||||
}
|
||||
|
||||
impl<'env, K> Writer<'env, K>
|
||||
where
|
||||
K: AsRef<[u8]>,
|
||||
{
|
||||
pub(crate) fn new(txn: RwTransaction) -> Writer<K> {
|
||||
Writer {
|
||||
tx: txn,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, store: Store, k: K) -> Result<Option<Value>, StoreError> {
|
||||
let bytes = self.tx.get(store.0, &k);
|
||||
impl<'env> Readable for Reader<'env> {
|
||||
fn get<K: AsRef<[u8]>>(&self, db: Database, k: &K) -> Result<Option<Value>, StoreError> {
|
||||
let bytes = self.0.get(db, &k);
|
||||
read_transform(bytes)
|
||||
}
|
||||
|
||||
// TODO: flags
|
||||
pub fn put(&mut self, store: Store, k: K, v: &Value) -> Result<(), StoreError> {
|
||||
// TODO: don't allocate twice.
|
||||
let bytes = v.to_bytes()?;
|
||||
self.tx.put(store.0, &k, &bytes, WriteFlags::empty()).map_err(StoreError::LmdbError)
|
||||
fn open_ro_cursor(&self, db: Database) -> Result<RoCursor, StoreError> {
|
||||
self.0.open_ro_cursor(db).map_err(StoreError::LmdbError)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env> Reader<'env> {
|
||||
pub(crate) fn new(txn: RoTransaction) -> Reader {
|
||||
Reader(txn)
|
||||
}
|
||||
|
||||
pub fn delete(&mut self, store: Store, k: K) -> Result<(), StoreError> {
|
||||
self.tx.del(store.0, &k, None).map_err(StoreError::LmdbError)
|
||||
pub fn abort(self) {
|
||||
self.0.abort();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env> Readable for Writer<'env> {
|
||||
fn get<K: AsRef<[u8]>>(&self, db: Database, k: &K) -> Result<Option<Value>, StoreError> {
|
||||
let bytes = self.0.get(db, &k);
|
||||
read_transform(bytes)
|
||||
}
|
||||
|
||||
pub fn delete_value(&mut self, _store: Store, _k: K, _v: &Value) -> Result<(), StoreError> {
|
||||
// Even better would be to make this a method only on a dupsort store —
|
||||
// it would need a little bit of reorganizing of types and traits,
|
||||
// but when I see "If the database does not support sorted duplicate
|
||||
// data items (MDB_DUPSORT) the data parameter is ignored" in the docs,
|
||||
// I see a footgun that we can avoid by using the type system.
|
||||
unimplemented!();
|
||||
fn open_ro_cursor(&self, db: Database) -> Result<RoCursor, StoreError> {
|
||||
self.0.open_ro_cursor(db).map_err(StoreError::LmdbError)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env> Writer<'env> {
|
||||
pub(crate) fn new(txn: RwTransaction) -> Writer {
|
||||
Writer(txn)
|
||||
}
|
||||
|
||||
pub fn commit(self) -> Result<(), StoreError> {
|
||||
self.tx.commit().map_err(StoreError::LmdbError)
|
||||
self.0.commit().map_err(StoreError::LmdbError)
|
||||
}
|
||||
|
||||
pub fn abort(self) {
|
||||
self.tx.abort();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env, K> Reader<'env, K>
|
||||
where
|
||||
K: AsRef<[u8]>,
|
||||
{
|
||||
pub(crate) fn new(txn: RoTransaction) -> Reader<K> {
|
||||
Reader {
|
||||
tx: txn,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, store: Store, k: K) -> Result<Option<Value>, StoreError> {
|
||||
let bytes = self.tx.get(store.0, &k);
|
||||
read_transform(bytes)
|
||||
}
|
||||
|
||||
pub fn abort(self) {
|
||||
self.tx.abort();
|
||||
}
|
||||
|
||||
pub fn iter_start(&self, store: Store) -> Result<Iter, StoreError> {
|
||||
let mut cursor = self.tx.open_ro_cursor(store.0).map_err(StoreError::LmdbError)?;
|
||||
|
||||
// We call Cursor.iter() instead of Cursor.iter_start() because
|
||||
// the latter panics at "called `Result::unwrap()` on an `Err` value:
|
||||
// NotFound" when there are no items in the store, whereas the former
|
||||
// returns an iterator that yields no items.
|
||||
//
|
||||
// And since we create the Cursor and don't change its position, we can
|
||||
// be sure that a call to Cursor.iter() will start at the beginning.
|
||||
//
|
||||
let iter = cursor.iter();
|
||||
|
||||
Ok(Iter {
|
||||
iter,
|
||||
cursor,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn iter_from(&self, store: Store, k: K) -> Result<Iter, StoreError> {
|
||||
let mut cursor = self.tx.open_ro_cursor(store.0).map_err(StoreError::LmdbError)?;
|
||||
let iter = cursor.iter_from(k);
|
||||
Ok(Iter {
|
||||
iter,
|
||||
cursor,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env> Iterator for Iter<'env> {
|
||||
type Item = (&'env [u8], Result<Option<Value<'env>>, StoreError>);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.iter.next() {
|
||||
None => None,
|
||||
Some((key, bytes)) => Some((key, read_transform(Ok(bytes)))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// New type around an `lmdb::Database`. At this time, the underlying LMDB
|
||||
/// handle (within lmdb-rs::Database) is a C integer, so Copy is automatic.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Store(Database);
|
||||
|
||||
impl Store {
|
||||
pub fn new(db: Database) -> Store {
|
||||
Store(db)
|
||||
self.0.abort();
|
||||
}
|
||||
|
||||
pub(crate) fn put<K: AsRef<[u8]>>(
|
||||
&mut self,
|
||||
db: Database,
|
||||
k: &K,
|
||||
v: &Value,
|
||||
flags: WriteFlags,
|
||||
) -> Result<(), StoreError> {
|
||||
// TODO: don't allocate twice.
|
||||
self.0.put(db, &k, &v.to_bytes()?, flags).map_err(StoreError::LmdbError)
|
||||
}
|
||||
|
||||
pub(crate) fn delete<K: AsRef<[u8]>>(&mut self, db: Database, k: &K, v: Option<&[u8]>) -> Result<(), StoreError> {
|
||||
self.0.del(db, &k, v).map_err(StoreError::LmdbError)
|
||||
}
|
||||
}
|
||||
|
21
third_party/rust/rkv/src/store.rs
vendored
Normal file
21
third_party/rust/rkv/src/store.rs
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
pub mod integer;
|
||||
pub mod integermulti;
|
||||
pub mod multi;
|
||||
pub mod single;
|
||||
|
||||
use lmdb::DatabaseFlags;
|
||||
|
||||
#[derive(Default, Debug, Copy, Clone)]
|
||||
pub struct Options {
|
||||
pub create: bool,
|
||||
pub flags: DatabaseFlags,
|
||||
}
|
||||
|
||||
impl Options {
|
||||
pub fn create() -> Options {
|
||||
Options {
|
||||
create: true,
|
||||
flags: DatabaseFlags::empty(),
|
||||
}
|
||||
}
|
||||
}
|
141
third_party/rust/rkv/src/store/integer.rs
vendored
Normal file
141
third_party/rust/rkv/src/store/integer.rs
vendored
Normal file
@ -0,0 +1,141 @@
|
||||
// Copyright 2018-2019 Mozilla
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// 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.
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use bincode::serialize;
|
||||
|
||||
use serde::Serialize;
|
||||
|
||||
use lmdb::Database;
|
||||
|
||||
use crate::error::{
|
||||
DataError,
|
||||
StoreError,
|
||||
};
|
||||
|
||||
use crate::readwrite::{
|
||||
Readable,
|
||||
Writer,
|
||||
};
|
||||
|
||||
use crate::value::Value;
|
||||
|
||||
use crate::store::single::SingleStore;
|
||||
|
||||
pub trait EncodableKey {
|
||||
fn to_bytes(&self) -> Result<Vec<u8>, DataError>;
|
||||
}
|
||||
|
||||
pub trait PrimitiveInt: EncodableKey {}
|
||||
|
||||
impl PrimitiveInt for u32 {}
|
||||
|
||||
impl<T> EncodableKey for T
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
fn to_bytes(&self) -> Result<Vec<u8>, DataError> {
|
||||
serialize(self) // TODO: limited key length.
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Key<K> {
|
||||
bytes: Vec<u8>,
|
||||
phantom: PhantomData<K>,
|
||||
}
|
||||
|
||||
impl<K> AsRef<[u8]> for Key<K>
|
||||
where
|
||||
K: EncodableKey,
|
||||
{
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.bytes.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<K> Key<K>
|
||||
where
|
||||
K: EncodableKey,
|
||||
{
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
pub(crate) fn new(k: &K) -> Result<Key<K>, DataError> {
|
||||
Ok(Key {
|
||||
bytes: k.to_bytes()?,
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IntegerStore<K>
|
||||
where
|
||||
K: PrimitiveInt,
|
||||
{
|
||||
inner: SingleStore,
|
||||
phantom: PhantomData<K>,
|
||||
}
|
||||
|
||||
impl<K> IntegerStore<K>
|
||||
where
|
||||
K: PrimitiveInt,
|
||||
{
|
||||
pub(crate) fn new(db: Database) -> IntegerStore<K> {
|
||||
IntegerStore {
|
||||
inner: SingleStore::new(db),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get<'env, T: Readable>(&self, reader: &'env T, k: K) -> Result<Option<Value<'env>>, StoreError> {
|
||||
self.inner.get(reader, Key::new(&k)?)
|
||||
}
|
||||
|
||||
pub fn put(&self, writer: &mut Writer, k: K, v: &Value) -> Result<(), StoreError> {
|
||||
self.inner.put(writer, Key::new(&k)?, v)
|
||||
}
|
||||
|
||||
pub fn delete(&self, writer: &mut Writer, k: K) -> Result<(), StoreError> {
|
||||
self.inner.delete(writer, Key::new(&k)?)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::fs;
|
||||
use tempfile::Builder;
|
||||
|
||||
use super::*;
|
||||
use crate::*;
|
||||
|
||||
#[test]
|
||||
fn test_integer_keys() {
|
||||
let root = Builder::new().prefix("test_integer_keys").tempdir().expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
let k = Rkv::new(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!")));
|
||||
writer.commit().expect("committed");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
assert_eq!(s.get(&reader, $key).expect("read"), Some(Value::Str("hello!")));
|
||||
}};
|
||||
}
|
||||
|
||||
test_integer_keys!(u32, std::u32::MIN);
|
||||
test_integer_keys!(u32, std::u32::MAX);
|
||||
}
|
||||
}
|
114
third_party/rust/rkv/src/store/integermulti.rs
vendored
Normal file
114
third_party/rust/rkv/src/store/integermulti.rs
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
// Copyright 2018 Mozilla
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// 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.
|
||||
|
||||
use lmdb::{
|
||||
Database,
|
||||
WriteFlags,
|
||||
};
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use crate::error::StoreError;
|
||||
|
||||
use crate::readwrite::{
|
||||
Readable,
|
||||
Writer,
|
||||
};
|
||||
|
||||
use crate::value::Value;
|
||||
|
||||
use crate::store::multi::{
|
||||
Iter,
|
||||
MultiStore,
|
||||
};
|
||||
|
||||
use crate::store::integer::{
|
||||
Key,
|
||||
PrimitiveInt,
|
||||
};
|
||||
|
||||
pub struct MultiIntegerStore<K>
|
||||
where
|
||||
K: PrimitiveInt,
|
||||
{
|
||||
inner: MultiStore,
|
||||
phantom: PhantomData<K>,
|
||||
}
|
||||
|
||||
impl<K> MultiIntegerStore<K>
|
||||
where
|
||||
K: PrimitiveInt,
|
||||
{
|
||||
pub(crate) fn new(db: Database) -> MultiIntegerStore<K> {
|
||||
MultiIntegerStore {
|
||||
inner: MultiStore::new(db),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get<'env, T: Readable>(&self, reader: &'env T, k: K) -> Result<Iter<'env>, StoreError> {
|
||||
self.inner.get(reader, Key::new(&k)?)
|
||||
}
|
||||
|
||||
pub fn get_first<'env, T: Readable>(&self, reader: &'env T, k: K) -> Result<Option<Value<'env>>, StoreError> {
|
||||
self.inner.get_first(reader, Key::new(&k)?)
|
||||
}
|
||||
|
||||
pub fn put(&self, writer: &mut Writer, k: K, v: &Value) -> Result<(), StoreError> {
|
||||
self.inner.put(writer, Key::new(&k)?, v)
|
||||
}
|
||||
|
||||
pub fn put_with_flags(&self, writer: &mut Writer, k: K, v: &Value, flags: WriteFlags) -> Result<(), StoreError> {
|
||||
self.inner.put_with_flags(writer, Key::new(&k)?, v, flags)
|
||||
}
|
||||
|
||||
pub fn delete_all(&self, writer: &mut Writer, k: K) -> Result<(), StoreError> {
|
||||
self.inner.delete_all(writer, Key::new(&k)?)
|
||||
}
|
||||
|
||||
pub fn delete(&self, writer: &mut Writer, k: K, v: &Value) -> Result<(), StoreError> {
|
||||
self.inner.delete(writer, Key::new(&k)?, v)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
extern crate tempfile;
|
||||
|
||||
use self::tempfile::Builder;
|
||||
use std::fs;
|
||||
|
||||
use super::*;
|
||||
use crate::*;
|
||||
|
||||
#[test]
|
||||
fn test_integer_keys() {
|
||||
let root = Builder::new().prefix("test_integer_keys").tempdir().expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
let k = Rkv::new(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!")));
|
||||
writer.commit().expect("committed");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
assert_eq!(s.get_first(&reader, $key).expect("read"), Some(Value::Str("hello!")));
|
||||
}};
|
||||
}
|
||||
|
||||
test_integer_keys!(u32, std::u32::MIN);
|
||||
test_integer_keys!(u32, std::u32::MAX);
|
||||
}
|
||||
}
|
147
third_party/rust/rkv/src/store/multi.rs
vendored
Normal file
147
third_party/rust/rkv/src/store/multi.rs
vendored
Normal file
@ -0,0 +1,147 @@
|
||||
// Copyright 2018 Mozilla
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// 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.
|
||||
|
||||
use crate::{
|
||||
error::StoreError,
|
||||
read_transform,
|
||||
readwrite::{
|
||||
Readable,
|
||||
Writer,
|
||||
},
|
||||
value::Value,
|
||||
};
|
||||
use lmdb::{
|
||||
Cursor,
|
||||
Database,
|
||||
Iter as LmdbIter,
|
||||
// IterDup as LmdbIterDup,
|
||||
RoCursor,
|
||||
WriteFlags,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct MultiStore {
|
||||
db: Database,
|
||||
}
|
||||
|
||||
pub struct Iter<'env> {
|
||||
iter: LmdbIter<'env>,
|
||||
cursor: RoCursor<'env>,
|
||||
}
|
||||
|
||||
impl MultiStore {
|
||||
pub(crate) fn new(db: Database) -> MultiStore {
|
||||
MultiStore {
|
||||
db,
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides a cursor to all of the values for the duplicate entries that match this key
|
||||
pub fn get<T: Readable, K: AsRef<[u8]>>(self, reader: &T, k: K) -> Result<Iter, StoreError> {
|
||||
let mut cursor = reader.open_ro_cursor(self.db)?;
|
||||
let iter = cursor.iter_dup_of(k);
|
||||
Ok(Iter {
|
||||
iter,
|
||||
cursor,
|
||||
})
|
||||
}
|
||||
|
||||
/// Provides the first value that matches this key
|
||||
pub fn get_first<T: Readable, K: AsRef<[u8]>>(self, reader: &T, k: K) -> Result<Option<Value>, StoreError> {
|
||||
reader.get(self.db, &k)
|
||||
}
|
||||
|
||||
/// Insert a value at the specified key.
|
||||
/// This put will allow duplicate entries. If you wish to have duplicate entries
|
||||
/// rejected, use the `put_with_flags` function and specify NO_DUP_DATA
|
||||
pub fn put<K: AsRef<[u8]>>(self, writer: &mut Writer, k: K, v: &Value) -> Result<(), StoreError> {
|
||||
writer.put(self.db, &k, v, WriteFlags::empty())
|
||||
}
|
||||
|
||||
pub fn put_with_flags<K: AsRef<[u8]>>(
|
||||
self,
|
||||
writer: &mut Writer,
|
||||
k: K,
|
||||
v: &Value,
|
||||
flags: WriteFlags,
|
||||
) -> Result<(), StoreError> {
|
||||
writer.put(self.db, &k, v, flags)
|
||||
}
|
||||
|
||||
pub fn delete_all<K: AsRef<[u8]>>(self, writer: &mut Writer, k: K) -> Result<(), StoreError> {
|
||||
writer.delete(self.db, &k, None)
|
||||
}
|
||||
|
||||
pub fn delete<K: AsRef<[u8]>>(self, writer: &mut Writer, k: K, v: &Value) -> Result<(), StoreError> {
|
||||
writer.delete(self.db, &k, Some(&v.to_bytes()?))
|
||||
}
|
||||
|
||||
/* TODO - Figure out how to solve the need to have the cursor stick around when
|
||||
* we are producing iterators from MultiIter
|
||||
/// Provides an iterator starting at the lexographically smallest value in the store
|
||||
pub fn iter_start(&self, store: MultiStore) -> Result<MultiIter, StoreError> {
|
||||
let mut cursor = self.tx.open_ro_cursor(store.0).map_err(StoreError::LmdbError)?;
|
||||
|
||||
// We call Cursor.iter() instead of Cursor.iter_start() because
|
||||
// the latter panics at "called `Result::unwrap()` on an `Err` value:
|
||||
// NotFound" when there are no items in the store, whereas the former
|
||||
// returns an iterator that yields no items.
|
||||
//
|
||||
// And since we create the Cursor and don't change its position, we can
|
||||
// be sure that a call to Cursor.iter() will start at the beginning.
|
||||
//
|
||||
let iter = cursor.iter_dup();
|
||||
|
||||
Ok(MultiIter {
|
||||
iter,
|
||||
cursor,
|
||||
})
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
fn read_transform_owned(val: Result<&[u8], lmdb::Error>) -> Result<Option<OwnedValue>, StoreError> {
|
||||
match val {
|
||||
Ok(bytes) => Value::from_tagged_slice(bytes).map(|v| Some(OwnedValue::from(&v))).map_err(StoreError::DataError),
|
||||
Err(lmdb::Error::NotFound) => Ok(None),
|
||||
Err(e) => Err(StoreError::LmdbError(e)),
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env> Iterator for MultiIter<'env> {
|
||||
type Item = Iter<'env>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.iter.next() {
|
||||
None => None,
|
||||
Some(iter) => Some(Iter {
|
||||
iter,
|
||||
cursor,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
impl<'env> Iterator for Iter<'env> {
|
||||
type Item = Result<(&'env [u8], Option<Value<'env>>), StoreError>;
|
||||
|
||||
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(Err(err)) => Some(Err(StoreError::LmdbError(err))),
|
||||
}
|
||||
}
|
||||
}
|
100
third_party/rust/rkv/src/store/single.rs
vendored
Normal file
100
third_party/rust/rkv/src/store/single.rs
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
// Copyright 2018 Mozilla
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// 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.
|
||||
|
||||
use crate::{
|
||||
error::StoreError,
|
||||
read_transform,
|
||||
readwrite::{
|
||||
Readable,
|
||||
Writer,
|
||||
},
|
||||
value::Value,
|
||||
};
|
||||
use lmdb::{
|
||||
Cursor,
|
||||
Database,
|
||||
Iter as LmdbIter,
|
||||
RoCursor,
|
||||
WriteFlags,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct SingleStore {
|
||||
db: Database,
|
||||
}
|
||||
|
||||
pub struct Iter<'env> {
|
||||
iter: LmdbIter<'env>,
|
||||
cursor: RoCursor<'env>,
|
||||
}
|
||||
|
||||
impl SingleStore {
|
||||
pub(crate) fn new(db: Database) -> SingleStore {
|
||||
SingleStore {
|
||||
db,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get<T: Readable, K: AsRef<[u8]>>(self, reader: &T, k: K) -> Result<Option<Value>, StoreError> {
|
||||
reader.get(self.db, &k)
|
||||
}
|
||||
|
||||
// TODO: flags
|
||||
pub fn put<K: AsRef<[u8]>>(self, writer: &mut Writer, k: K, v: &Value) -> Result<(), StoreError> {
|
||||
writer.put(self.db, &k, v, WriteFlags::empty())
|
||||
}
|
||||
|
||||
pub fn delete<K: AsRef<[u8]>>(self, writer: &mut Writer, k: K) -> Result<(), StoreError> {
|
||||
writer.delete(self.db, &k, None)
|
||||
}
|
||||
|
||||
pub fn iter_start<T: Readable>(self, reader: &T) -> Result<Iter, StoreError> {
|
||||
let mut cursor = reader.open_ro_cursor(self.db)?;
|
||||
|
||||
// We call Cursor.iter() instead of Cursor.iter_start() because
|
||||
// the latter panics at "called `Result::unwrap()` on an `Err` value:
|
||||
// NotFound" when there are no items in the store, whereas the former
|
||||
// returns an iterator that yields no items.
|
||||
//
|
||||
// And since we create the Cursor and don't change its position, we can
|
||||
// be sure that a call to Cursor.iter() will start at the beginning.
|
||||
//
|
||||
let iter = cursor.iter();
|
||||
|
||||
Ok(Iter {
|
||||
iter,
|
||||
cursor,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn iter_from<T: Readable, K: AsRef<[u8]>>(self, reader: &T, k: K) -> Result<Iter, StoreError> {
|
||||
let mut cursor = reader.open_ro_cursor(self.db)?;
|
||||
let iter = cursor.iter_from(k);
|
||||
Ok(Iter {
|
||||
iter,
|
||||
cursor,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env> Iterator for Iter<'env> {
|
||||
type Item = Result<(&'env [u8], Option<Value<'env>>), StoreError>;
|
||||
|
||||
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(Err(err)) => Some(Err(StoreError::LmdbError(err))),
|
||||
}
|
||||
}
|
||||
}
|
17
third_party/rust/rkv/src/value.rs
vendored
17
third_party/rust/rkv/src/value.rs
vendored
@ -1,4 +1,4 @@
|
||||
// Copyright 2018 Mozilla
|
||||
// Copyright 2018-2019 Mozilla
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
@ -8,19 +8,19 @@
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use ordered_float::OrderedFloat;
|
||||
|
||||
use arrayref::array_ref;
|
||||
use bincode::{
|
||||
deserialize,
|
||||
serialize,
|
||||
};
|
||||
use ordered_float::OrderedFloat;
|
||||
|
||||
use uuid::{
|
||||
Bytes,
|
||||
Uuid,
|
||||
};
|
||||
|
||||
use error::DataError;
|
||||
use crate::error::DataError;
|
||||
|
||||
/// We define a set of types, associated with simple integers, to annotate values
|
||||
/// stored in LMDB. This is to avoid an accidental 'cast' from a value of one type
|
||||
@ -46,6 +46,7 @@ impl Type {
|
||||
Type::from_primitive(tag).ok_or_else(|| DataError::UnknownType(tag))
|
||||
}
|
||||
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
pub fn to_tag(self) -> u8 {
|
||||
self as u8
|
||||
}
|
||||
@ -95,7 +96,7 @@ pub enum Value<'s> {
|
||||
Blob(&'s [u8]),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum OwnedValue {
|
||||
Bool(bool),
|
||||
U64(u64),
|
||||
@ -158,7 +159,8 @@ impl<'s> Value<'s> {
|
||||
// Processed above to avoid verbose duplication of error transforms.
|
||||
unreachable!()
|
||||
},
|
||||
}.map_err(|e| DataError::DecodingError {
|
||||
}
|
||||
.map_err(|e| DataError::DecodingError {
|
||||
value_type: t,
|
||||
err: e,
|
||||
})
|
||||
@ -178,7 +180,8 @@ impl<'s> Value<'s> {
|
||||
// Processed above to avoid verbose duplication of error transforms.
|
||||
serialize(&(Type::Uuid.to_tag(), v))
|
||||
},
|
||||
}.map_err(DataError::EncodingError)
|
||||
}
|
||||
.map_err(DataError::EncodingError)
|
||||
}
|
||||
}
|
||||
|
||||
|
77
third_party/rust/rkv/tests/integer-store.rs
vendored
Normal file
77
third_party/rust/rkv/tests/integer-store.rs
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
// Copyright 2018-2019 Mozilla
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// 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.
|
||||
|
||||
use rkv::{
|
||||
PrimitiveInt,
|
||||
Rkv,
|
||||
StoreOptions,
|
||||
Value,
|
||||
};
|
||||
use serde_derive::Serialize;
|
||||
use std::fs;
|
||||
use tempfile::Builder;
|
||||
|
||||
#[test]
|
||||
fn test_integer_keys() {
|
||||
let root = Builder::new().prefix("test_integer_keys").tempdir().expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
let k = Rkv::new(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!")));
|
||||
writer.commit().expect("committed");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
assert_eq!($store.get(&reader, $key).expect("read"), Some(Value::Str("hello!")));
|
||||
}};
|
||||
}
|
||||
|
||||
// The integer module provides only the u32 integer key variant
|
||||
// of IntegerStore, so we can use it without further ado.
|
||||
test_integer_keys!(s, std::u32::MIN);
|
||||
test_integer_keys!(s, std::u32::MAX);
|
||||
|
||||
// If you want to use another integer key variant, you need to implement
|
||||
// a newtype, implement PrimitiveInt, and implement or derive Serialize
|
||||
// for it. Here we do so for the i32 type.
|
||||
|
||||
// DANGER! Doing this enables you to open a store with multiple,
|
||||
// different integer key types, which may result in unexpected behavior.
|
||||
// Make sure you know what you're doing!
|
||||
|
||||
let t = k.open_integer("s", StoreOptions::create()).expect("open");
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct I32(i32);
|
||||
impl PrimitiveInt for I32 {}
|
||||
test_integer_keys!(t, I32(std::i32::MIN));
|
||||
test_integer_keys!(t, I32(std::i32::MAX));
|
||||
|
||||
let u = k.open_integer("s", StoreOptions::create()).expect("open");
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct U16(u16);
|
||||
impl PrimitiveInt for U16 {}
|
||||
test_integer_keys!(u, U16(std::u16::MIN));
|
||||
test_integer_keys!(u, U16(std::u16::MAX));
|
||||
|
||||
let v = k.open_integer("s", StoreOptions::create()).expect("open");
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct U64(u64);
|
||||
impl PrimitiveInt for U64 {}
|
||||
test_integer_keys!(v, U64(std::u64::MIN));
|
||||
test_integer_keys!(v, U64(std::u64::MAX));
|
||||
}
|
16
third_party/rust/rkv/tests/manager.rs
vendored
16
third_party/rust/rkv/tests/manager.rs
vendored
@ -1,4 +1,4 @@
|
||||
// Copyright 2018 Mozilla
|
||||
// Copyright 2018-2019 Mozilla
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
@ -8,19 +8,15 @@
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
extern crate rkv;
|
||||
extern crate tempfile;
|
||||
|
||||
use rkv::{
|
||||
Manager,
|
||||
Rkv,
|
||||
};
|
||||
|
||||
use self::tempfile::Builder;
|
||||
|
||||
use std::fs;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::{
|
||||
fs,
|
||||
sync::Arc,
|
||||
};
|
||||
use tempfile::Builder;
|
||||
|
||||
#[test]
|
||||
// Identical to the same-named unit test, but this one confirms that it works
|
||||
|
91
third_party/rust/rkv/tests/multi-integer-store.rs
vendored
Normal file
91
third_party/rust/rkv/tests/multi-integer-store.rs
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
// Copyright 2018 Mozilla
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// 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.
|
||||
|
||||
use rkv::{
|
||||
PrimitiveInt,
|
||||
Rkv,
|
||||
StoreOptions,
|
||||
Value,
|
||||
};
|
||||
use serde_derive::Serialize;
|
||||
use std::fs;
|
||||
use tempfile::Builder;
|
||||
|
||||
#[test]
|
||||
fn test_multi_integer_keys() {
|
||||
let root = Builder::new().prefix("test_integer_keys").tempdir().expect("tempdir");
|
||||
fs::create_dir_all(root.path()).expect("dir created");
|
||||
let k = Rkv::new(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");
|
||||
let vals = $store
|
||||
.get(&writer, $key)
|
||||
.expect("read")
|
||||
.map(|result| result.expect("ok"))
|
||||
.map(|(_, v)| v.expect("multi read"))
|
||||
.collect::<Vec<Value>>();
|
||||
assert_eq!(vals, vec![Value::Str("hello1"), Value::Str("hello2"), Value::Str("hello3")]);
|
||||
writer.commit().expect("committed");
|
||||
|
||||
let reader = k.read().expect("reader");
|
||||
let vals = $store
|
||||
.get(&reader, $key)
|
||||
.expect("read")
|
||||
.map(|result| result.expect("ok"))
|
||||
.map(|(_, v)| v.expect("multi read"))
|
||||
.collect::<Vec<Value>>();
|
||||
assert_eq!(vals, vec![Value::Str("hello1"), Value::Str("hello2"), Value::Str("hello3")]);
|
||||
}};
|
||||
}
|
||||
|
||||
// The integer module provides only the u32 integer key variant
|
||||
// of IntegerStore, so we can use it without further ado.
|
||||
test_integer_keys!(s, std::u32::MIN);
|
||||
test_integer_keys!(s, std::u32::MAX);
|
||||
|
||||
// If you want to use another integer key variant, you need to implement
|
||||
// a newtype, implement PrimitiveInt, and implement or derive Serialize
|
||||
// for it. Here we do so for the i32 type.
|
||||
|
||||
// DANGER! Doing this enables you to open a store with multiple,
|
||||
// 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");
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct I32(i32);
|
||||
impl PrimitiveInt for I32 {}
|
||||
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");
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct U16(u16);
|
||||
impl PrimitiveInt for U16 {}
|
||||
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");
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct U64(u64);
|
||||
impl PrimitiveInt for U64 {}
|
||||
test_integer_keys!(v, U64(std::u64::MIN));
|
||||
test_integer_keys!(v, U64(std::u64::MAX));
|
||||
}
|
@ -7,13 +7,13 @@ authors = ["Myk Melez <myk@mykzilla.org>"]
|
||||
atomic_refcell = "0.1"
|
||||
crossbeam-utils = "0.6.3"
|
||||
libc = "0.2"
|
||||
lmdb-rkv = "0.9"
|
||||
lmdb-rkv = "0.11.2"
|
||||
log = "0.4"
|
||||
moz_task = { path = "../../../xpcom/rust/moz_task" }
|
||||
nserror = { path = "../../../xpcom/rust/nserror" }
|
||||
nsstring = { path = "../../../xpcom/rust/nsstring" }
|
||||
ordered-float = "1"
|
||||
rkv = "0.7"
|
||||
rkv = "0.9.2"
|
||||
storage_variant = { path = "../../../storage/variant" }
|
||||
xpcom = { path = "../../../xpcom/rust/xpcom" }
|
||||
|
||||
|
@ -34,24 +34,17 @@ interface nsIKeyValueVoidCallback;
|
||||
interface nsIKeyValueService : nsISupports {
|
||||
/**
|
||||
* Get a handle to an existing database or a newly-created one
|
||||
* at the specified path and with the given name. If no name is given,
|
||||
* the default database is returned.
|
||||
* at the specified path and with the given name.
|
||||
*
|
||||
* The service supports multiple named databases at the same path
|
||||
* (i.e. within the same storage file), so you can call this method
|
||||
* multiple times with the same path and different names to retrieve
|
||||
* multiple databases stored in the same location on disk.
|
||||
*
|
||||
* Because the backing storage engine stores information about named
|
||||
* databases in the default database, it's tricky to use both the default
|
||||
* and named databases at the same path. Thus you should generally use
|
||||
* either the default database or named databases, but not both, for a
|
||||
* given path.
|
||||
*/
|
||||
void getOrCreate(
|
||||
in nsIKeyValueDatabaseCallback callback,
|
||||
in AUTF8String path,
|
||||
[optional] in AUTF8String name);
|
||||
in AUTF8String name);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -29,7 +29,7 @@ use moz_task::{create_thread, TaskRunnable};
|
||||
use nserror::{nsresult, NS_ERROR_FAILURE, NS_ERROR_NO_AGGREGATION, NS_OK};
|
||||
use nsstring::{nsACString, nsCString};
|
||||
use owned_value::{owned_to_variant, variant_to_owned, OwnedValue};
|
||||
use rkv::{Rkv, Store};
|
||||
use rkv::{Rkv, SingleStore};
|
||||
use std::{
|
||||
ptr,
|
||||
sync::{Arc, RwLock},
|
||||
@ -44,6 +44,8 @@ use xpcom::{
|
||||
nsIID, RefPtr, ThreadBoundRefPtr,
|
||||
};
|
||||
|
||||
type KeyValuePairResult = Result<(String, OwnedValue), KeyValueError>;
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn nsKeyValueServiceConstructor(
|
||||
outer: *const nsISupports,
|
||||
@ -134,14 +136,14 @@ impl KeyValueService {
|
||||
#[refcnt = "atomic"]
|
||||
pub struct InitKeyValueDatabase {
|
||||
rkv: Arc<RwLock<Rkv>>,
|
||||
store: Store,
|
||||
store: SingleStore,
|
||||
thread: ThreadBoundRefPtr<nsIThread>,
|
||||
}
|
||||
|
||||
impl KeyValueDatabase {
|
||||
fn new(
|
||||
rkv: Arc<RwLock<Rkv>>,
|
||||
store: Store,
|
||||
store: SingleStore,
|
||||
thread: ThreadBoundRefPtr<nsIThread>,
|
||||
) -> RefPtr<KeyValueDatabase> {
|
||||
KeyValueDatabase::allocate(InitKeyValueDatabase { rkv, store, thread })
|
||||
@ -272,21 +274,11 @@ impl KeyValueDatabase {
|
||||
#[xpimplements(nsIKeyValueEnumerator)]
|
||||
#[refcnt = "atomic"]
|
||||
pub struct InitKeyValueEnumerator {
|
||||
iter: AtomicRefCell<
|
||||
IntoIter<(
|
||||
Result<String, KeyValueError>,
|
||||
Result<OwnedValue, KeyValueError>,
|
||||
)>,
|
||||
>,
|
||||
iter: AtomicRefCell<IntoIter<KeyValuePairResult>>,
|
||||
}
|
||||
|
||||
impl KeyValueEnumerator {
|
||||
fn new(
|
||||
pairs: Vec<(
|
||||
Result<String, KeyValueError>,
|
||||
Result<OwnedValue, KeyValueError>,
|
||||
)>,
|
||||
) -> RefPtr<KeyValueEnumerator> {
|
||||
fn new(pairs: Vec<KeyValuePairResult>) -> RefPtr<KeyValueEnumerator> {
|
||||
KeyValueEnumerator::allocate(InitKeyValueEnumerator {
|
||||
iter: AtomicRefCell::new(pairs.into_iter()),
|
||||
})
|
||||
@ -302,13 +294,15 @@ impl KeyValueEnumerator {
|
||||
|
||||
fn get_next(&self) -> Result<RefPtr<nsIKeyValuePair>, KeyValueError> {
|
||||
let mut iter = self.iter.borrow_mut();
|
||||
let (key, value) = iter.next().ok_or(KeyValueError::from(NS_ERROR_FAILURE))?;
|
||||
let (key, value) = iter
|
||||
.next()
|
||||
.ok_or_else(|| KeyValueError::from(NS_ERROR_FAILURE))??;
|
||||
|
||||
// We fail on retrieval of the key/value pair if the key isn't valid
|
||||
// UTF-*, if the value is unexpected, or if we encountered a store error
|
||||
// while retrieving the pair.
|
||||
Ok(RefPtr::new(
|
||||
KeyValuePair::new(key?, value?).coerce::<nsIKeyValuePair>(),
|
||||
KeyValuePair::new(key, value).coerce::<nsIKeyValuePair>(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ pub enum OwnedValue {
|
||||
Str(String),
|
||||
}
|
||||
|
||||
pub fn value_to_owned<'a>(value: Option<Value<'a>>) -> Result<OwnedValue, KeyValueError> {
|
||||
pub fn value_to_owned(value: Option<Value>) -> Result<OwnedValue, KeyValueError> {
|
||||
match value {
|
||||
Some(Value::Bool(val)) => Ok(OwnedValue::Bool(val)),
|
||||
Some(Value::I64(val)) => Ok(OwnedValue::I64(val)),
|
||||
@ -70,8 +70,6 @@ pub fn variant_to_owned(variant: &nsIVariant) -> Result<Option<OwnedValue>, KeyV
|
||||
Ok(Some(OwnedValue::Bool(val)))
|
||||
}
|
||||
DATA_TYPE_EMPTY | DATA_TYPE_VOID => Ok(None),
|
||||
unsupported_type => {
|
||||
return Err(KeyValueError::UnsupportedType(unsupported_type));
|
||||
}
|
||||
unsupported_type => Err(KeyValueError::UnsupportedType(unsupported_type)),
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use moz_task::Task;
|
||||
use nserror::{nsresult, NsresultExt, NS_ERROR_FAILURE};
|
||||
use nsstring::{nsCString, nsString};
|
||||
use owned_value::{value_to_owned, OwnedValue};
|
||||
use rkv::{Manager, Rkv, Store, StoreError, Value};
|
||||
use rkv::{Manager, Rkv, SingleStore, StoreError, StoreOptions, Value};
|
||||
use std::{
|
||||
path::Path,
|
||||
str,
|
||||
@ -22,11 +22,11 @@ use xpcom::{
|
||||
nsIKeyValueDatabaseCallback, nsIKeyValueEnumeratorCallback, nsIKeyValueVariantCallback,
|
||||
nsIKeyValueVoidCallback, nsIThread, nsIVariant,
|
||||
},
|
||||
RefPtr,
|
||||
ThreadBoundRefPtr,
|
||||
RefPtr, ThreadBoundRefPtr,
|
||||
};
|
||||
use KeyValueDatabase;
|
||||
use KeyValueEnumerator;
|
||||
use KeyValuePairResult;
|
||||
|
||||
/// A macro to generate a done() implementation for a Task.
|
||||
/// Takes one argument that specifies the type of the Task's callback function:
|
||||
@ -78,12 +78,19 @@ macro_rules! task_done {
|
||||
};
|
||||
}
|
||||
|
||||
/// A tuple comprising an Arc<RwLock<Rkv>> and a SingleStore, which is
|
||||
/// the result of GetOrCreateTask. We declare this type because otherwise
|
||||
/// Clippy complains "error: very complex type used. Consider factoring
|
||||
/// parts into `type` definitions" (i.e. clippy::type-complexity) when we
|
||||
/// declare the type of `GetOrCreateTask::result`.
|
||||
type RkvStoreTuple = (Arc<RwLock<Rkv>>, SingleStore);
|
||||
|
||||
pub struct GetOrCreateTask {
|
||||
callback: AtomicCell<Option<ThreadBoundRefPtr<nsIKeyValueDatabaseCallback>>>,
|
||||
thread: AtomicCell<Option<ThreadBoundRefPtr<nsIThread>>>,
|
||||
path: nsCString,
|
||||
name: nsCString,
|
||||
result: AtomicCell<Option<Result<(Arc<RwLock<Rkv>>, Store), KeyValueError>>>,
|
||||
result: AtomicCell<Option<Result<RkvStoreTuple, KeyValueError>>>,
|
||||
}
|
||||
|
||||
impl GetOrCreateTask {
|
||||
@ -102,10 +109,7 @@ impl GetOrCreateTask {
|
||||
}
|
||||
}
|
||||
|
||||
fn convert(
|
||||
&self,
|
||||
result: (Arc<RwLock<Rkv>>, Store),
|
||||
) -> Result<RefPtr<KeyValueDatabase>, KeyValueError> {
|
||||
fn convert(&self, result: RkvStoreTuple) -> Result<RefPtr<KeyValueDatabase>, KeyValueError> {
|
||||
let thread = self.thread.swap(None).ok_or(NS_ERROR_FAILURE)?;
|
||||
Ok(KeyValueDatabase::new(result.0, result.1, thread))
|
||||
}
|
||||
@ -115,19 +119,15 @@ impl Task for GetOrCreateTask {
|
||||
fn run(&self) {
|
||||
// We do the work within a closure that returns a Result so we can
|
||||
// use the ? operator to simplify the implementation.
|
||||
self.result.store(Some(
|
||||
|| -> Result<(Arc<RwLock<Rkv>>, Store), KeyValueError> {
|
||||
self.result
|
||||
.store(Some(|| -> Result<RkvStoreTuple, KeyValueError> {
|
||||
let mut writer = Manager::singleton().write()?;
|
||||
let rkv = writer.get_or_create(Path::new(str::from_utf8(&self.path)?), Rkv::new)?;
|
||||
let store = if self.name.is_empty() {
|
||||
rkv.write()?.open_or_create_default()
|
||||
} else {
|
||||
rkv.write()?
|
||||
.open_or_create(Some(str::from_utf8(&self.name)?))
|
||||
}?;
|
||||
let store = rkv
|
||||
.write()?
|
||||
.open_single(str::from_utf8(&self.name)?, StoreOptions::create())?;
|
||||
Ok((rkv, store))
|
||||
}(),
|
||||
));
|
||||
}()));
|
||||
}
|
||||
|
||||
task_done!(value);
|
||||
@ -136,7 +136,7 @@ impl Task for GetOrCreateTask {
|
||||
pub struct PutTask {
|
||||
callback: AtomicCell<Option<ThreadBoundRefPtr<nsIKeyValueVoidCallback>>>,
|
||||
rkv: Arc<RwLock<Rkv>>,
|
||||
store: Store,
|
||||
store: SingleStore,
|
||||
key: nsCString,
|
||||
value: OwnedValue,
|
||||
result: AtomicCell<Option<Result<(), KeyValueError>>>,
|
||||
@ -146,7 +146,7 @@ impl PutTask {
|
||||
pub fn new(
|
||||
callback: RefPtr<nsIKeyValueVoidCallback>,
|
||||
rkv: Arc<RwLock<Rkv>>,
|
||||
store: Store,
|
||||
store: SingleStore,
|
||||
key: nsCString,
|
||||
value: OwnedValue,
|
||||
) -> PutTask {
|
||||
@ -177,7 +177,7 @@ impl Task for PutTask {
|
||||
OwnedValue::Str(ref val) => Value::Str(&val),
|
||||
};
|
||||
|
||||
writer.put(self.store, key, &value)?;
|
||||
self.store.put(&mut writer, key, &value)?;
|
||||
writer.commit()?;
|
||||
|
||||
Ok(())
|
||||
@ -190,7 +190,7 @@ impl Task for PutTask {
|
||||
pub struct GetTask {
|
||||
callback: AtomicCell<Option<ThreadBoundRefPtr<nsIKeyValueVariantCallback>>>,
|
||||
rkv: Arc<RwLock<Rkv>>,
|
||||
store: Store,
|
||||
store: SingleStore,
|
||||
key: nsCString,
|
||||
default_value: Option<OwnedValue>,
|
||||
result: AtomicCell<Option<Result<Option<OwnedValue>, KeyValueError>>>,
|
||||
@ -200,7 +200,7 @@ impl GetTask {
|
||||
pub fn new(
|
||||
callback: RefPtr<nsIKeyValueVariantCallback>,
|
||||
rkv: Arc<RwLock<Rkv>>,
|
||||
store: Store,
|
||||
store: SingleStore,
|
||||
key: nsCString,
|
||||
default_value: Option<OwnedValue>,
|
||||
) -> GetTask {
|
||||
@ -235,7 +235,7 @@ impl Task for GetTask {
|
||||
let key = str::from_utf8(&self.key)?;
|
||||
let env = self.rkv.read()?;
|
||||
let reader = env.read()?;
|
||||
let value = reader.get(self.store, key)?;
|
||||
let value = self.store.get(&reader, key)?;
|
||||
|
||||
// TODO: refactor with value_to_owned in owned_value.rs.
|
||||
Ok(match value {
|
||||
@ -258,7 +258,7 @@ impl Task for GetTask {
|
||||
pub struct HasTask {
|
||||
callback: AtomicCell<Option<ThreadBoundRefPtr<nsIKeyValueVariantCallback>>>,
|
||||
rkv: Arc<RwLock<Rkv>>,
|
||||
store: Store,
|
||||
store: SingleStore,
|
||||
key: nsCString,
|
||||
result: AtomicCell<Option<Result<bool, KeyValueError>>>,
|
||||
}
|
||||
@ -267,7 +267,7 @@ impl HasTask {
|
||||
pub fn new(
|
||||
callback: RefPtr<nsIKeyValueVariantCallback>,
|
||||
rkv: Arc<RwLock<Rkv>>,
|
||||
store: Store,
|
||||
store: SingleStore,
|
||||
key: nsCString,
|
||||
) -> HasTask {
|
||||
HasTask {
|
||||
@ -292,7 +292,7 @@ impl Task for HasTask {
|
||||
let key = str::from_utf8(&self.key)?;
|
||||
let env = self.rkv.read()?;
|
||||
let reader = env.read()?;
|
||||
let value = reader.get(self.store, key)?;
|
||||
let value = self.store.get(&reader, key)?;
|
||||
Ok(value.is_some())
|
||||
}()));
|
||||
}
|
||||
@ -303,7 +303,7 @@ impl Task for HasTask {
|
||||
pub struct DeleteTask {
|
||||
callback: AtomicCell<Option<ThreadBoundRefPtr<nsIKeyValueVoidCallback>>>,
|
||||
rkv: Arc<RwLock<Rkv>>,
|
||||
store: Store,
|
||||
store: SingleStore,
|
||||
key: nsCString,
|
||||
result: AtomicCell<Option<Result<(), KeyValueError>>>,
|
||||
}
|
||||
@ -312,7 +312,7 @@ impl DeleteTask {
|
||||
pub fn new(
|
||||
callback: RefPtr<nsIKeyValueVoidCallback>,
|
||||
rkv: Arc<RwLock<Rkv>>,
|
||||
store: Store,
|
||||
store: SingleStore,
|
||||
key: nsCString,
|
||||
) -> DeleteTask {
|
||||
DeleteTask {
|
||||
@ -334,7 +334,7 @@ impl Task for DeleteTask {
|
||||
let env = self.rkv.read()?;
|
||||
let mut writer = env.write()?;
|
||||
|
||||
match writer.delete(self.store, key) {
|
||||
match self.store.delete(&mut writer, key) {
|
||||
Ok(_) => (),
|
||||
|
||||
// LMDB fails with an error if the key to delete wasn't found,
|
||||
@ -357,17 +357,17 @@ impl Task for DeleteTask {
|
||||
pub struct EnumerateTask {
|
||||
callback: AtomicCell<Option<ThreadBoundRefPtr<nsIKeyValueEnumeratorCallback>>>,
|
||||
rkv: Arc<RwLock<Rkv>>,
|
||||
store: Store,
|
||||
store: SingleStore,
|
||||
from_key: nsCString,
|
||||
to_key: nsCString,
|
||||
result: AtomicCell<Option<Result<Vec<KeyValuePair>, KeyValueError>>>,
|
||||
result: AtomicCell<Option<Result<Vec<KeyValuePairResult>, KeyValueError>>>,
|
||||
}
|
||||
|
||||
impl EnumerateTask {
|
||||
pub fn new(
|
||||
callback: RefPtr<nsIKeyValueEnumeratorCallback>,
|
||||
rkv: Arc<RwLock<Rkv>>,
|
||||
store: Store,
|
||||
store: SingleStore,
|
||||
from_key: nsCString,
|
||||
to_key: nsCString,
|
||||
) -> EnumerateTask {
|
||||
@ -383,32 +383,27 @@ impl EnumerateTask {
|
||||
|
||||
fn convert(
|
||||
&self,
|
||||
result: Vec<KeyValuePair>,
|
||||
result: Vec<KeyValuePairResult>,
|
||||
) -> Result<RefPtr<KeyValueEnumerator>, KeyValueError> {
|
||||
Ok(KeyValueEnumerator::new(result))
|
||||
}
|
||||
}
|
||||
|
||||
type KeyValuePair = (
|
||||
Result<String, KeyValueError>,
|
||||
Result<OwnedValue, KeyValueError>,
|
||||
);
|
||||
|
||||
impl Task for EnumerateTask {
|
||||
fn run(&self) {
|
||||
// We do the work within a closure that returns a Result so we can
|
||||
// use the ? operator to simplify the implementation.
|
||||
self.result
|
||||
.store(Some(|| -> Result<Vec<KeyValuePair>, KeyValueError> {
|
||||
self.result.store(Some(
|
||||
|| -> Result<Vec<KeyValuePairResult>, KeyValueError> {
|
||||
let env = self.rkv.read()?;
|
||||
let reader = env.read()?;
|
||||
let from_key = str::from_utf8(&self.from_key)?;
|
||||
let to_key = str::from_utf8(&self.to_key)?;
|
||||
|
||||
let iterator = if from_key.is_empty() {
|
||||
reader.iter_start(self.store)?
|
||||
self.store.iter_start(&reader)?
|
||||
} else {
|
||||
reader.iter_from(self.store, &from_key)?
|
||||
self.store.iter_from(&reader, &from_key)?
|
||||
};
|
||||
|
||||
// Ideally, we'd enumerate pairs lazily, as the consumer calls
|
||||
@ -421,38 +416,43 @@ impl Task for EnumerateTask {
|
||||
// Our fallback approach is to eagerly collect the iterator
|
||||
// into a collection that KeyValueEnumerator owns. Fixing this so we
|
||||
// enumerate pairs lazily is bug 1499252.
|
||||
let pairs: Vec<KeyValuePair> = iterator
|
||||
let pairs: Vec<KeyValuePairResult> = iterator
|
||||
// Convert the key to a string so we can compare it to the "to" key.
|
||||
// For forward compatibility, we don't fail here if we can't convert
|
||||
// a key to UTF-8. Instead, we store the Err in the collection
|
||||
// and fail lazily in KeyValueEnumerator.get_next().
|
||||
.map(|(key, val)| (str::from_utf8(&key), val))
|
||||
.take_while(|(key, _val)| {
|
||||
if to_key.is_empty() {
|
||||
true
|
||||
} else {
|
||||
match *key {
|
||||
Ok(key) => key < to_key,
|
||||
Err(_err) => true,
|
||||
.map(|result| match result {
|
||||
Ok((key, val)) => Ok((str::from_utf8(&key), val)),
|
||||
Err(err) => Err(err),
|
||||
})
|
||||
// Stop iterating once we reach the to_key, if any.
|
||||
.take_while(|result| match result {
|
||||
Ok((key, _val)) => {
|
||||
if to_key.is_empty() {
|
||||
true
|
||||
} else {
|
||||
match *key {
|
||||
Ok(key) => key < to_key,
|
||||
Err(_err) => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => true,
|
||||
})
|
||||
.map(|(key, val)| {
|
||||
(
|
||||
match key {
|
||||
Ok(key) => Ok(key.to_owned()),
|
||||
Err(err) => Err(err.into()),
|
||||
},
|
||||
match val {
|
||||
Ok(val) => value_to_owned(val),
|
||||
Err(err) => Err(KeyValueError::StoreError(err)),
|
||||
},
|
||||
)
|
||||
// Convert the key/value pair to owned.
|
||||
.map(|result| match result {
|
||||
Ok((key, val)) => match (key, value_to_owned(val)) {
|
||||
(Ok(key), Ok(val)) => Ok((key.to_owned(), val)),
|
||||
(Err(err), _) => Err(err.into()),
|
||||
(_, Err(err)) => Err(err),
|
||||
},
|
||||
Err(err) => Err(KeyValueError::StoreError(err)),
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(pairs)
|
||||
}()));
|
||||
}(),
|
||||
));
|
||||
}
|
||||
|
||||
task_done!(value);
|
||||
|
@ -26,13 +26,13 @@ add_task(async function getService() {
|
||||
|
||||
add_task(async function getOrCreate() {
|
||||
const databaseDir = await makeDatabaseDir("getOrCreate");
|
||||
const defaultDatabase = await KeyValueService.getOrCreate(databaseDir);
|
||||
Assert.ok(defaultDatabase);
|
||||
const database = await KeyValueService.getOrCreate(databaseDir, "db");
|
||||
Assert.ok(database);
|
||||
});
|
||||
|
||||
add_task(async function putGetHasDelete() {
|
||||
const databaseDir = await makeDatabaseDir("putGetHasDelete");
|
||||
const database = await KeyValueService.getOrCreate(databaseDir);
|
||||
const database = await KeyValueService.getOrCreate(databaseDir, "db");
|
||||
|
||||
// Getting key/value pairs that don't exist (yet) returns default values
|
||||
// or null, depending on whether you specify a default value.
|
||||
@ -93,7 +93,7 @@ add_task(async function putGetHasDelete() {
|
||||
|
||||
add_task(async function largeNumbers() {
|
||||
const databaseDir = await makeDatabaseDir("largeNumbers");
|
||||
const database = await KeyValueService.getOrCreate(databaseDir);
|
||||
const database = await KeyValueService.getOrCreate(databaseDir, "db");
|
||||
|
||||
const MAX_INT_VARIANT = Math.pow(2, 31) - 1;
|
||||
const MIN_DOUBLE_VARIANT = Math.pow(2, 31);
|
||||
@ -115,7 +115,7 @@ add_task(async function largeNumbers() {
|
||||
|
||||
add_task(async function extendedCharacterKey() {
|
||||
const databaseDir = await makeDatabaseDir("extendedCharacterKey");
|
||||
const database = await KeyValueService.getOrCreate(databaseDir);
|
||||
const database = await KeyValueService.getOrCreate(databaseDir, "db");
|
||||
|
||||
// Ensure that we can use extended character (i.e. non-ASCII) strings as keys.
|
||||
|
||||
@ -139,42 +139,30 @@ add_task(async function getOrCreateNamedDatabases() {
|
||||
let barDB = await KeyValueService.getOrCreate(databaseDir, "bar");
|
||||
Assert.ok(barDB, "retrieval of second named database works");
|
||||
|
||||
let defaultDB = await KeyValueService.getOrCreate(databaseDir);
|
||||
Assert.ok(defaultDB, "retrieval of default database works");
|
||||
let bazDB = await KeyValueService.getOrCreate(databaseDir, "baz");
|
||||
Assert.ok(bazDB, "retrieval of third named database works");
|
||||
|
||||
// Key/value pairs that are put into a database don't exist in others.
|
||||
await defaultDB.put("key", 1);
|
||||
await bazDB.put("key", 1);
|
||||
Assert.ok(!(await fooDB.has("key")), "the foo DB still doesn't have the key");
|
||||
await fooDB.put("key", 2);
|
||||
Assert.ok(!(await barDB.has("key")), "the bar DB still doesn't have the key");
|
||||
await barDB.put("key", 3);
|
||||
Assert.strictEqual(await defaultDB.get("key", 0), 1, "the default DB has its KV pair");
|
||||
Assert.strictEqual(await bazDB.get("key", 0), 1, "the baz DB has its KV pair");
|
||||
Assert.strictEqual(await fooDB.get("key", 0), 2, "the foo DB has its KV pair");
|
||||
Assert.strictEqual(await barDB.get("key", 0), 3, "the bar DB has its KV pair");
|
||||
|
||||
// Key/value pairs that are deleted from a database still exist in other DBs.
|
||||
await defaultDB.delete("key");
|
||||
await bazDB.delete("key");
|
||||
Assert.strictEqual(await fooDB.get("key", 0), 2, "the foo DB still has its KV pair");
|
||||
await fooDB.delete("key");
|
||||
Assert.strictEqual(await barDB.get("key", 0), 3, "the bar DB still has its KV pair");
|
||||
await barDB.delete("key");
|
||||
|
||||
// LMDB uses the default database to store information about named databases,
|
||||
// so it's tricky to use both in the same directory (i.e. LMDB environment).
|
||||
|
||||
// If you try to put a key into the default database with the same name as
|
||||
// a named database, then the write will fail because LMDB doesn't let you
|
||||
// overwrite the key.
|
||||
await Assert.rejects(defaultDB.put("foo", 5), /LmdbError\(Incompatible\)/);
|
||||
|
||||
// If you try to get a key from the default database for a named database,
|
||||
// then the read will fail because rkv doesn't understand the key's data type.
|
||||
await Assert.rejects(defaultDB.get("foo"), /DataError\(UnknownType\(0\)\)/);
|
||||
});
|
||||
|
||||
add_task(async function enumeration() {
|
||||
const databaseDir = await makeDatabaseDir("enumeration");
|
||||
const database = await KeyValueService.getOrCreate(databaseDir);
|
||||
const database = await KeyValueService.getOrCreate(databaseDir, "db");
|
||||
|
||||
await database.put("int-key", 1234);
|
||||
await database.put("double-key", 56.78);
|
||||
|
@ -77,7 +77,10 @@ pub struct InitTaskRunnable {
|
||||
}
|
||||
|
||||
impl TaskRunnable {
|
||||
pub fn new(name: &'static str, task: Box<dyn Task + Send + Sync>) -> Result<RefPtr<TaskRunnable>, nsresult> {
|
||||
pub fn new(
|
||||
name: &'static str,
|
||||
task: Box<dyn Task + Send + Sync>,
|
||||
) -> Result<RefPtr<TaskRunnable>, nsresult> {
|
||||
assert!(is_main_thread());
|
||||
Ok(TaskRunnable::allocate(InitTaskRunnable {
|
||||
name,
|
||||
@ -94,14 +97,16 @@ impl TaskRunnable {
|
||||
|
||||
xpcom_method!(run => Run());
|
||||
fn run(&self) -> Result<(), nsresult> {
|
||||
match self.has_run.load(Ordering::Acquire) {
|
||||
false => {
|
||||
match self
|
||||
.has_run
|
||||
.compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
|
||||
{
|
||||
Ok(_) => {
|
||||
assert!(!is_main_thread());
|
||||
self.has_run.store(true, Ordering::Release);
|
||||
self.task.run();
|
||||
self.dispatch(get_main_thread()?)
|
||||
}
|
||||
true => {
|
||||
Err(_) => {
|
||||
assert!(is_main_thread());
|
||||
self.task.done()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user