covalence 0.1.0.dev2__tar.gz → 0.1.0.dev3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/Cargo.lock +19 -19
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/Cargo.toml +17 -17
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/PKG-INFO +21 -9
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/README.md +20 -8
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/cas/kv/src/lib.rs +28 -10
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/cas/kv/tests/kv.rs +59 -6
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/cas/trait/src/lib.rs +8 -4
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/kv/memory/src/lib.rs +35 -2
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/kv/memory/tests/memory.rs +30 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/kv/s3/src/lib.rs +36 -2
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/kv/s3/src/write.rs +83 -34
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/kv/s3/tests/kv.rs +79 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/kv/trait/src/lib.rs +40 -0
- covalence-0.1.0.dev3/crates/kv/trait/tests/atomic.rs +52 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/python/README.md +20 -8
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/python/src/lib.rs +145 -2
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/python/tests/test_api.py +172 -4
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/python/covalence/THIRD-PARTY-LICENSES.md +17 -17
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/python/covalence/_native.pyi +27 -2
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/LICENSE-APACHE +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/LICENSE-CC0 +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/LICENSE-MIT +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/blob/trait/Cargo.toml +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/blob/trait/LICENSE-APACHE +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/blob/trait/LICENSE-CC0 +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/blob/trait/LICENSE-MIT +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/blob/trait/README.md +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/blob/trait/src/lib.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/blob/trait/tests/blob.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/blob/trait/tests/common/mod.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/blob/trait/tests/fact.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/cas/kv/Cargo.toml +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/cas/kv/LICENSE-APACHE +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/cas/kv/LICENSE-CC0 +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/cas/kv/LICENSE-MIT +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/cas/memory/Cargo.toml +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/cas/memory/LICENSE-APACHE +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/cas/memory/LICENSE-CC0 +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/cas/memory/LICENSE-MIT +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/cas/memory/src/lib.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/cas/memory/tests/memory.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/cas/sqlite/Cargo.toml +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/cas/sqlite/LICENSE-APACHE +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/cas/sqlite/LICENSE-CC0 +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/cas/sqlite/LICENSE-MIT +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/cas/sqlite/src/lib.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/cas/sqlite/tests/sqlite.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/cas/trait/Cargo.toml +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/cas/trait/LICENSE-APACHE +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/cas/trait/LICENSE-CC0 +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/cas/trait/LICENSE-MIT +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/cas/trait/tests/trait.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/kv/memory/Cargo.toml +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/kv/memory/LICENSE-APACHE +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/kv/memory/LICENSE-CC0 +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/kv/memory/LICENSE-MIT +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/kv/s3/Cargo.toml +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/kv/s3/LICENSE-APACHE +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/kv/s3/LICENSE-CC0 +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/kv/s3/LICENSE-MIT +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/kv/s3/src/read.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/kv/s3/tests/aws.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/kv/trait/Cargo.toml +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/kv/trait/LICENSE-APACHE +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/kv/trait/LICENSE-CC0 +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/kv/trait/LICENSE-MIT +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/cid/Cargo.toml +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/cid/LICENSE-APACHE +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/cid/LICENSE-CC0 +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/cid/LICENSE-MIT +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/cid/README.md +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/cid/src/dasl.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/cid/src/fact.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/cid/src/git.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/cid/src/lib.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/cid/src/multicodec.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/cid/src/o256.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/cid/src/storage.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/cid/tests/cid.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/cid/tests/fact.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/cid/tests/git.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/cid/tests/o256.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/cid/tests/shattered/1.bin +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/cid/tests/shattered/2.bin +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/cid/tests/shattered/README.md +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/Cargo.toml +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/LICENSE-APACHE +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/LICENSE-CC0 +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/LICENSE-MIT +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/README.md +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/src/drisl.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/src/event.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/src/json.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/src/lib.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/tests/codec.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/tests/events.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/tests/fact.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/tests/fixtures/LICENSE +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/tests/fixtures/README.md +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/tests/fixtures/cid.json +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/tests/fixtures/concat.json +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/tests/fixtures/floats.json +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/tests/fixtures/indefinite.json +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/tests/fixtures/integer_range.json +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/tests/fixtures/map_keys.json +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/tests/fixtures/numeric_reduction.json +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/tests/fixtures/short_form.json +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/tests/fixtures/simple.json +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/tests/fixtures/tags.json +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/tests/fixtures/utf8.json +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/tests/fixtures.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/tests/json.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/tests/vectors/README.md +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/tests/vectors/cid-vectors.jsonl +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/tests/vectors/dasl-vectors.jsonl +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/dasl/tests/vectors.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/data/Cargo.toml +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/data/LICENSE-APACHE +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/data/LICENSE-CC0 +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/data/LICENSE-MIT +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/data/src/lib.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/error/Cargo.toml +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/error/LICENSE-APACHE +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/error/LICENSE-CC0 +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/error/LICENSE-MIT +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/error/src/lib.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/python/Cargo.toml +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/python/LICENSE-APACHE +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/python/LICENSE-CC0 +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/python/LICENSE-MIT +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/python/src/lib.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/rand/Cargo.toml +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/rand/LICENSE-APACHE +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/rand/LICENSE-CC0 +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/rand/LICENSE-MIT +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/rand/src/lib.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/serde/Cargo.toml +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/serde/LICENSE-APACHE +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/serde/LICENSE-CC0 +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/serde/LICENSE-MIT +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/serde/src/lib.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/sqlite/Cargo.toml +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/sqlite/LICENSE-APACHE +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/sqlite/LICENSE-CC0 +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/sqlite/LICENSE-MIT +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/lib/sqlite/src/lib.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/python/Cargo.toml +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/python/LICENSE-APACHE +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/python/LICENSE-CC0 +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/python/LICENSE-MIT +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/python/about.md.hbs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/python/about.toml +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/python/src/errors.rs +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/python/tests/test_docs.py +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/python/tests/test_package.py +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/python/tests/test_stubs.py +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/crates/python/tests/typed_usage.py +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/pyproject.toml +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/python/covalence/__init__.py +0 -0
- {covalence-0.1.0.dev2 → covalence-0.1.0.dev3}/python/covalence/py.typed +0 -0
|
@@ -779,7 +779,7 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
|
|
779
779
|
|
|
780
780
|
[[package]]
|
|
781
781
|
name = "covalence-blob-trait"
|
|
782
|
-
version = "0.1.0-dev.
|
|
782
|
+
version = "0.1.0-dev.3"
|
|
783
783
|
dependencies = [
|
|
784
784
|
"covalence-lib-cid",
|
|
785
785
|
"covalence-lib-data",
|
|
@@ -788,7 +788,7 @@ dependencies = [
|
|
|
788
788
|
|
|
789
789
|
[[package]]
|
|
790
790
|
name = "covalence-cas-kv"
|
|
791
|
-
version = "0.1.0-dev.
|
|
791
|
+
version = "0.1.0-dev.3"
|
|
792
792
|
dependencies = [
|
|
793
793
|
"blake3",
|
|
794
794
|
"covalence-cas-trait",
|
|
@@ -810,7 +810,7 @@ dependencies = [
|
|
|
810
810
|
|
|
811
811
|
[[package]]
|
|
812
812
|
name = "covalence-cas-memory"
|
|
813
|
-
version = "0.1.0-dev.
|
|
813
|
+
version = "0.1.0-dev.3"
|
|
814
814
|
dependencies = [
|
|
815
815
|
"covalence-cas-trait",
|
|
816
816
|
"covalence-lib-cid",
|
|
@@ -821,7 +821,7 @@ dependencies = [
|
|
|
821
821
|
|
|
822
822
|
[[package]]
|
|
823
823
|
name = "covalence-cas-sqlite"
|
|
824
|
-
version = "0.1.0-dev.
|
|
824
|
+
version = "0.1.0-dev.3"
|
|
825
825
|
dependencies = [
|
|
826
826
|
"covalence-cas-trait",
|
|
827
827
|
"covalence-lib-cid",
|
|
@@ -836,7 +836,7 @@ dependencies = [
|
|
|
836
836
|
|
|
837
837
|
[[package]]
|
|
838
838
|
name = "covalence-cas-trait"
|
|
839
|
-
version = "0.1.0-dev.
|
|
839
|
+
version = "0.1.0-dev.3"
|
|
840
840
|
dependencies = [
|
|
841
841
|
"covalence-lib-cid",
|
|
842
842
|
"covalence-lib-dasl",
|
|
@@ -847,7 +847,7 @@ dependencies = [
|
|
|
847
847
|
|
|
848
848
|
[[package]]
|
|
849
849
|
name = "covalence-kv-memory"
|
|
850
|
-
version = "0.1.0-dev.
|
|
850
|
+
version = "0.1.0-dev.3"
|
|
851
851
|
dependencies = [
|
|
852
852
|
"covalence-kv-trait",
|
|
853
853
|
"covalence-lib-dasl",
|
|
@@ -857,7 +857,7 @@ dependencies = [
|
|
|
857
857
|
|
|
858
858
|
[[package]]
|
|
859
859
|
name = "covalence-kv-s3"
|
|
860
|
-
version = "0.1.0-dev.
|
|
860
|
+
version = "0.1.0-dev.3"
|
|
861
861
|
dependencies = [
|
|
862
862
|
"aws-config",
|
|
863
863
|
"aws-credential-types",
|
|
@@ -881,7 +881,7 @@ dependencies = [
|
|
|
881
881
|
|
|
882
882
|
[[package]]
|
|
883
883
|
name = "covalence-kv-trait"
|
|
884
|
-
version = "0.1.0-dev.
|
|
884
|
+
version = "0.1.0-dev.3"
|
|
885
885
|
dependencies = [
|
|
886
886
|
"covalence-lib-dasl",
|
|
887
887
|
"covalence-lib-data",
|
|
@@ -890,7 +890,7 @@ dependencies = [
|
|
|
890
890
|
|
|
891
891
|
[[package]]
|
|
892
892
|
name = "covalence-lib-cid"
|
|
893
|
-
version = "0.1.0-dev.
|
|
893
|
+
version = "0.1.0-dev.3"
|
|
894
894
|
dependencies = [
|
|
895
895
|
"blake3",
|
|
896
896
|
"covalence-lib-data",
|
|
@@ -905,14 +905,14 @@ dependencies = [
|
|
|
905
905
|
|
|
906
906
|
[[package]]
|
|
907
907
|
name = "covalence-lib-cli"
|
|
908
|
-
version = "0.1.0-dev.
|
|
908
|
+
version = "0.1.0-dev.3"
|
|
909
909
|
dependencies = [
|
|
910
910
|
"clap",
|
|
911
911
|
]
|
|
912
912
|
|
|
913
913
|
[[package]]
|
|
914
914
|
name = "covalence-lib-dasl"
|
|
915
|
-
version = "0.1.0-dev.
|
|
915
|
+
version = "0.1.0-dev.3"
|
|
916
916
|
dependencies = [
|
|
917
917
|
"blake3",
|
|
918
918
|
"covalence-lib-cid",
|
|
@@ -927,7 +927,7 @@ dependencies = [
|
|
|
927
927
|
|
|
928
928
|
[[package]]
|
|
929
929
|
name = "covalence-lib-data"
|
|
930
|
-
version = "0.1.0-dev.
|
|
930
|
+
version = "0.1.0-dev.3"
|
|
931
931
|
dependencies = [
|
|
932
932
|
"arrayvec",
|
|
933
933
|
"bytes",
|
|
@@ -939,7 +939,7 @@ dependencies = [
|
|
|
939
939
|
|
|
940
940
|
[[package]]
|
|
941
941
|
name = "covalence-lib-error"
|
|
942
|
-
version = "0.1.0-dev.
|
|
942
|
+
version = "0.1.0-dev.3"
|
|
943
943
|
dependencies = [
|
|
944
944
|
"miette",
|
|
945
945
|
"snafu",
|
|
@@ -947,14 +947,14 @@ dependencies = [
|
|
|
947
947
|
|
|
948
948
|
[[package]]
|
|
949
949
|
name = "covalence-lib-python"
|
|
950
|
-
version = "0.1.0-dev.
|
|
950
|
+
version = "0.1.0-dev.3"
|
|
951
951
|
dependencies = [
|
|
952
952
|
"pyo3",
|
|
953
953
|
]
|
|
954
954
|
|
|
955
955
|
[[package]]
|
|
956
956
|
name = "covalence-lib-rand"
|
|
957
|
-
version = "0.1.0-dev.
|
|
957
|
+
version = "0.1.0-dev.3"
|
|
958
958
|
dependencies = [
|
|
959
959
|
"getrandom 0.3.4",
|
|
960
960
|
"rand",
|
|
@@ -962,21 +962,21 @@ dependencies = [
|
|
|
962
962
|
|
|
963
963
|
[[package]]
|
|
964
964
|
name = "covalence-lib-serde"
|
|
965
|
-
version = "0.1.0-dev.
|
|
965
|
+
version = "0.1.0-dev.3"
|
|
966
966
|
dependencies = [
|
|
967
967
|
"serde",
|
|
968
968
|
]
|
|
969
969
|
|
|
970
970
|
[[package]]
|
|
971
971
|
name = "covalence-lib-sqlite"
|
|
972
|
-
version = "0.1.0-dev.
|
|
972
|
+
version = "0.1.0-dev.3"
|
|
973
973
|
dependencies = [
|
|
974
974
|
"rusqlite",
|
|
975
975
|
]
|
|
976
976
|
|
|
977
977
|
[[package]]
|
|
978
978
|
name = "covalence-python"
|
|
979
|
-
version = "0.1.0-dev.
|
|
979
|
+
version = "0.1.0-dev.3"
|
|
980
980
|
dependencies = [
|
|
981
981
|
"blake3",
|
|
982
982
|
"covalence-blob-trait",
|
|
@@ -997,7 +997,7 @@ dependencies = [
|
|
|
997
997
|
|
|
998
998
|
[[package]]
|
|
999
999
|
name = "covalence-tools-glu"
|
|
1000
|
-
version = "0.1.0-dev.
|
|
1000
|
+
version = "0.1.0-dev.3"
|
|
1001
1001
|
dependencies = [
|
|
1002
1002
|
"covalence-lib-cli",
|
|
1003
1003
|
"covalence-lib-error",
|
|
@@ -3,7 +3,7 @@ members = ["crates/lib/error", "crates/lib/serde", "crates/lib/data", "crates/li
|
|
|
3
3
|
resolver = "3"
|
|
4
4
|
|
|
5
5
|
[workspace.package]
|
|
6
|
-
version = "0.1.0-dev.
|
|
6
|
+
version = "0.1.0-dev.3"
|
|
7
7
|
edition = "2024"
|
|
8
8
|
rust-version = "1.98"
|
|
9
9
|
license = "CC0-1.0 OR MIT OR Apache-2.0"
|
|
@@ -17,22 +17,22 @@ miette = "7.6.0"
|
|
|
17
17
|
sha2 = "0.11.0"
|
|
18
18
|
snafu = "0.9.2"
|
|
19
19
|
# Published crates, at the workspace version so the set moves together.
|
|
20
|
-
covalence-blob-trait = { path = "crates/blob/trait", version = "=0.1.0-dev.
|
|
21
|
-
covalence-cas-kv = { path = "crates/cas/kv", version = "=0.1.0-dev.
|
|
22
|
-
covalence-cas-memory = { path = "crates/cas/memory", version = "=0.1.0-dev.
|
|
23
|
-
covalence-cas-sqlite = { path = "crates/cas/sqlite", version = "=0.1.0-dev.
|
|
24
|
-
covalence-cas-trait = { path = "crates/cas/trait", version = "=0.1.0-dev.
|
|
25
|
-
covalence-kv-memory = { path = "crates/kv/memory", version = "=0.1.0-dev.
|
|
26
|
-
covalence-kv-s3 = { path = "crates/kv/s3", version = "=0.1.0-dev.
|
|
27
|
-
covalence-kv-trait = { path = "crates/kv/trait", version = "=0.1.0-dev.
|
|
28
|
-
covalence-lib-cid = { path = "crates/lib/cid", version = "=0.1.0-dev.
|
|
29
|
-
covalence-lib-cli = { path = "crates/lib/cli", version = "=0.1.0-dev.
|
|
30
|
-
covalence-lib-dasl = { path = "crates/lib/dasl", version = "=0.1.0-dev.
|
|
31
|
-
covalence-lib-data = { path = "crates/lib/data", version = "=0.1.0-dev.
|
|
32
|
-
covalence-lib-error = { path = "crates/lib/error", version = "=0.1.0-dev.
|
|
33
|
-
covalence-lib-rand = { path = "crates/lib/rand", version = "=0.1.0-dev.
|
|
34
|
-
covalence-lib-serde = { path = "crates/lib/serde", version = "=0.1.0-dev.
|
|
35
|
-
covalence-lib-sqlite = { path = "crates/lib/sqlite", version = "=0.1.0-dev.
|
|
20
|
+
covalence-blob-trait = { path = "crates/blob/trait", version = "=0.1.0-dev.3" }
|
|
21
|
+
covalence-cas-kv = { path = "crates/cas/kv", version = "=0.1.0-dev.3" }
|
|
22
|
+
covalence-cas-memory = { path = "crates/cas/memory", version = "=0.1.0-dev.3" }
|
|
23
|
+
covalence-cas-sqlite = { path = "crates/cas/sqlite", version = "=0.1.0-dev.3" }
|
|
24
|
+
covalence-cas-trait = { path = "crates/cas/trait", version = "=0.1.0-dev.3" }
|
|
25
|
+
covalence-kv-memory = { path = "crates/kv/memory", version = "=0.1.0-dev.3" }
|
|
26
|
+
covalence-kv-s3 = { path = "crates/kv/s3", version = "=0.1.0-dev.3" }
|
|
27
|
+
covalence-kv-trait = { path = "crates/kv/trait", version = "=0.1.0-dev.3" }
|
|
28
|
+
covalence-lib-cid = { path = "crates/lib/cid", version = "=0.1.0-dev.3" }
|
|
29
|
+
covalence-lib-cli = { path = "crates/lib/cli", version = "=0.1.0-dev.3" }
|
|
30
|
+
covalence-lib-dasl = { path = "crates/lib/dasl", version = "=0.1.0-dev.3" }
|
|
31
|
+
covalence-lib-data = { path = "crates/lib/data", version = "=0.1.0-dev.3" }
|
|
32
|
+
covalence-lib-error = { path = "crates/lib/error", version = "=0.1.0-dev.3" }
|
|
33
|
+
covalence-lib-rand = { path = "crates/lib/rand", version = "=0.1.0-dev.3" }
|
|
34
|
+
covalence-lib-serde = { path = "crates/lib/serde", version = "=0.1.0-dev.3" }
|
|
35
|
+
covalence-lib-sqlite = { path = "crates/lib/sqlite", version = "=0.1.0-dev.3" }
|
|
36
36
|
|
|
37
37
|
[workspace.lints.rust]
|
|
38
38
|
unsafe_code = "forbid"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: covalence
|
|
3
|
-
Version: 0.1.0.
|
|
3
|
+
Version: 0.1.0.dev3
|
|
4
4
|
License-File: LICENSE-APACHE
|
|
5
5
|
License-File: LICENSE-CC0
|
|
6
6
|
License-File: LICENSE-MIT
|
|
@@ -35,7 +35,7 @@ True
|
|
|
35
35
|
## Install
|
|
36
36
|
|
|
37
37
|
```sh
|
|
38
|
-
pip install covalence==0.1.0.
|
|
38
|
+
pip install covalence==0.1.0.dev3
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
- Pre-releases need an exact pin like this one, or `pip install --pre`.
|
|
@@ -138,6 +138,9 @@ pip install covalence==0.1.0.dev2
|
|
|
138
138
|
`prefix/blake3/<digest>/bytes`.
|
|
139
139
|
- `put` returns the raw BLAKE3 `Cid`, after checking that the store kept the
|
|
140
140
|
data under it.
|
|
141
|
+
- `Cas.kv` never replaces a block its `Kv` already holds: on `Kv.s3` each
|
|
142
|
+
write is conditional (`If-None-Match: *`), so concurrent writers of one
|
|
143
|
+
block race safely and the first one's bytes stay.
|
|
141
144
|
- `put_value(value)` stores the DRISL encoding of a `Value` (or what
|
|
142
145
|
`Value(...)` takes) and returns its DRISL CID, which is `value.cid()`.
|
|
143
146
|
- `get` returns the bytes and `get_fact` a `BlobFact`, both checked against
|
|
@@ -156,16 +159,25 @@ pip install covalence==0.1.0.dev2
|
|
|
156
159
|
- Ranges are clipped at the end.
|
|
157
160
|
- Stores without native ranges fetch the whole value and slice it.
|
|
158
161
|
|
|
159
|
-
### Files
|
|
162
|
+
### Files and streams
|
|
160
163
|
|
|
161
164
|
- `Cas.put_file(path)` stores a file and returns its raw BLAKE3 `Cid`, as
|
|
162
165
|
`put` does.
|
|
166
|
+
- `Cas.put_from(cid, chunks, length)` stores a block from an iterable of
|
|
167
|
+
bytes, such as a request body, and returns its raw BLAKE3 `Cid`. Before a
|
|
168
|
+
new block is stored, its bytes must match `length` and the BLAKE3 `cid`,
|
|
169
|
+
and `chunks` must end there. A store may return an existing block without
|
|
170
|
+
consuming all the input; unread bytes and source errors are not checked.
|
|
171
|
+
While consuming input, a hash mismatch (`IntegrityError`), too few or too
|
|
172
|
+
many bytes (`ValueError`), or a source exception publish no new block.
|
|
173
|
+
Source exceptions propagate unchanged unless cleanup also fails, in which
|
|
174
|
+
case `StoreError` reports that failure with the source as its `__cause__`.
|
|
163
175
|
- `Cas.get_file(cid, path)` writes the block to a file and returns its
|
|
164
176
|
length, or `None` if missing.
|
|
165
|
-
- `put_file` and `get_file` stream on `Cas.kv` over `Kv.s3`,
|
|
166
|
-
16 parts of 8 MiB (128 MiB) at a time
|
|
167
|
-
parts. Other stores, including `Cas.kv(Kv.memory())`, hold
|
|
168
|
-
memory.
|
|
177
|
+
- `put_file`, `put_from` and `get_file` stream on `Cas.kv` over `Kv.s3`,
|
|
178
|
+
holding up to 16 parts of 8 MiB (128 MiB) at a time, or as many as
|
|
179
|
+
`Kv.s3(..., concurrency=n)` says; blocks over 78 GiB go up in larger parts. Other stores, including `Cas.kv(Kv.memory())`, hold
|
|
180
|
+
the block in memory.
|
|
169
181
|
- `put_file` reads the file twice, to hash it and to store it, and stores the
|
|
170
182
|
bytes it hashed. If they changed in between it raises `IntegrityError`,
|
|
171
183
|
and if the file got shorter `OSError`, storing nothing either way. Bytes
|
|
@@ -254,9 +266,9 @@ workflow artifacts. A release tag must match the workspace version, such as
|
|
|
254
266
|
`.github/workflows/crates.yml` publishes the crates to crates.io.
|
|
255
267
|
- `python-v<version>` only attaches them to the GitHub release.
|
|
256
268
|
|
|
257
|
-
To publish `0.1.0-dev.
|
|
269
|
+
To publish `0.1.0-dev.3`:
|
|
258
270
|
|
|
259
271
|
```sh
|
|
260
|
-
git tag v0.1.0-dev.
|
|
272
|
+
git tag v0.1.0-dev.3 && git push origin v0.1.0-dev.3
|
|
261
273
|
```
|
|
262
274
|
|
|
@@ -21,7 +21,7 @@ True
|
|
|
21
21
|
## Install
|
|
22
22
|
|
|
23
23
|
```sh
|
|
24
|
-
pip install covalence==0.1.0.
|
|
24
|
+
pip install covalence==0.1.0.dev3
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
- Pre-releases need an exact pin like this one, or `pip install --pre`.
|
|
@@ -124,6 +124,9 @@ pip install covalence==0.1.0.dev2
|
|
|
124
124
|
`prefix/blake3/<digest>/bytes`.
|
|
125
125
|
- `put` returns the raw BLAKE3 `Cid`, after checking that the store kept the
|
|
126
126
|
data under it.
|
|
127
|
+
- `Cas.kv` never replaces a block its `Kv` already holds: on `Kv.s3` each
|
|
128
|
+
write is conditional (`If-None-Match: *`), so concurrent writers of one
|
|
129
|
+
block race safely and the first one's bytes stay.
|
|
127
130
|
- `put_value(value)` stores the DRISL encoding of a `Value` (or what
|
|
128
131
|
`Value(...)` takes) and returns its DRISL CID, which is `value.cid()`.
|
|
129
132
|
- `get` returns the bytes and `get_fact` a `BlobFact`, both checked against
|
|
@@ -142,16 +145,25 @@ pip install covalence==0.1.0.dev2
|
|
|
142
145
|
- Ranges are clipped at the end.
|
|
143
146
|
- Stores without native ranges fetch the whole value and slice it.
|
|
144
147
|
|
|
145
|
-
### Files
|
|
148
|
+
### Files and streams
|
|
146
149
|
|
|
147
150
|
- `Cas.put_file(path)` stores a file and returns its raw BLAKE3 `Cid`, as
|
|
148
151
|
`put` does.
|
|
152
|
+
- `Cas.put_from(cid, chunks, length)` stores a block from an iterable of
|
|
153
|
+
bytes, such as a request body, and returns its raw BLAKE3 `Cid`. Before a
|
|
154
|
+
new block is stored, its bytes must match `length` and the BLAKE3 `cid`,
|
|
155
|
+
and `chunks` must end there. A store may return an existing block without
|
|
156
|
+
consuming all the input; unread bytes and source errors are not checked.
|
|
157
|
+
While consuming input, a hash mismatch (`IntegrityError`), too few or too
|
|
158
|
+
many bytes (`ValueError`), or a source exception publish no new block.
|
|
159
|
+
Source exceptions propagate unchanged unless cleanup also fails, in which
|
|
160
|
+
case `StoreError` reports that failure with the source as its `__cause__`.
|
|
149
161
|
- `Cas.get_file(cid, path)` writes the block to a file and returns its
|
|
150
162
|
length, or `None` if missing.
|
|
151
|
-
- `put_file` and `get_file` stream on `Cas.kv` over `Kv.s3`,
|
|
152
|
-
16 parts of 8 MiB (128 MiB) at a time
|
|
153
|
-
parts. Other stores, including `Cas.kv(Kv.memory())`, hold
|
|
154
|
-
memory.
|
|
163
|
+
- `put_file`, `put_from` and `get_file` stream on `Cas.kv` over `Kv.s3`,
|
|
164
|
+
holding up to 16 parts of 8 MiB (128 MiB) at a time, or as many as
|
|
165
|
+
`Kv.s3(..., concurrency=n)` says; blocks over 78 GiB go up in larger parts. Other stores, including `Cas.kv(Kv.memory())`, hold
|
|
166
|
+
the block in memory.
|
|
155
167
|
- `put_file` reads the file twice, to hash it and to store it, and stores the
|
|
156
168
|
bytes it hashed. If they changed in between it raises `IntegrityError`,
|
|
157
169
|
and if the file got shorter `OSError`, storing nothing either way. Bytes
|
|
@@ -240,8 +252,8 @@ workflow artifacts. A release tag must match the workspace version, such as
|
|
|
240
252
|
`.github/workflows/crates.yml` publishes the crates to crates.io.
|
|
241
253
|
- `python-v<version>` only attaches them to the GitHub release.
|
|
242
254
|
|
|
243
|
-
To publish `0.1.0-dev.
|
|
255
|
+
To publish `0.1.0-dev.3`:
|
|
244
256
|
|
|
245
257
|
```sh
|
|
246
|
-
git tag v0.1.0-dev.
|
|
258
|
+
git tag v0.1.0-dev.3 && git push origin v0.1.0-dev.3
|
|
247
259
|
```
|
|
@@ -46,13 +46,16 @@ use data_encoding::BASE32_NOPAD;
|
|
|
46
46
|
/// `get_fact` and `aget_fact` check the bytes against the CID and fail with
|
|
47
47
|
/// [`Error::Check`] if they do not match. `get_unchecked`, sizes and ranges
|
|
48
48
|
/// are not checked.
|
|
49
|
-
/// - `has` asks the key-value store whether the key exists
|
|
50
|
-
///
|
|
51
|
-
/// - `put`
|
|
52
|
-
///
|
|
53
|
-
///
|
|
49
|
+
/// - `has` asks the key-value store whether the key exists, without reading
|
|
50
|
+
/// the bytes.
|
|
51
|
+
/// - `put`, `aput` and `put_from` never replace a block: they store through
|
|
52
|
+
/// the key-value store's [`Kv::put_new`], [`Kv::aput_new`] and
|
|
53
|
+
/// [`Kv::put_new_from`], so concurrent writers of one block race safely.
|
|
54
|
+
/// Writes fail if the backend does not implement atomic create-only writes.
|
|
54
55
|
/// - `put_from` and `get_to` stream through the key-value store's own
|
|
55
|
-
/// `
|
|
56
|
+
/// `put_new_from` and `get_to`, hashing the bytes as they pass.
|
|
57
|
+
/// If the backend skips an existing block, `put_from` returns without
|
|
58
|
+
/// consuming or checking any remaining input.
|
|
56
59
|
/// - If the bytes `put_from` reads do not hash to the CID, the read that would
|
|
57
60
|
/// hand over the last byte fails instead. The key-value store's `put_from`
|
|
58
61
|
/// then fails as [`Kv::put_from`] says, storing nothing, and `put_from`
|
|
@@ -60,6 +63,18 @@ use data_encoding::BASE32_NOPAD;
|
|
|
60
63
|
/// store reports a further failure, such as failing to clean up.
|
|
61
64
|
/// - [`Cas::info`] is `{"name": "kv", "prefix": <prefix>, "kv": <the
|
|
62
65
|
/// key-value store's info>}`; [`Cas::stats`] is the key-value store's.
|
|
66
|
+
///
|
|
67
|
+
/// # S3
|
|
68
|
+
///
|
|
69
|
+
/// Writes use conditional requests to preserve existing blocks. They do not
|
|
70
|
+
/// make a preliminary HEAD request, so they need only write access.
|
|
71
|
+
///
|
|
72
|
+
/// `has` uses a HEAD request. S3 answers a HEAD for a missing key with 403 to
|
|
73
|
+
/// a client that may not list the bucket.
|
|
74
|
+
///
|
|
75
|
+
/// S3 may consume the source before discovering that a block already exists.
|
|
76
|
+
/// Once the backend skips insertion, `put_from` leaves any remaining input
|
|
77
|
+
/// unread.
|
|
63
78
|
pub struct KvCas {
|
|
64
79
|
kv: Arc<dyn Kv>,
|
|
65
80
|
prefix: String,
|
|
@@ -277,7 +292,7 @@ impl Put<Blake3> for KvCas {
|
|
|
277
292
|
fn put(&self, bytes: Bytes) -> Result<Blake3, Error> {
|
|
278
293
|
let cid = Blake3::of(&bytes);
|
|
279
294
|
self.kv
|
|
280
|
-
.
|
|
295
|
+
.put_new(self.key(&cid).as_bytes(), bytes)
|
|
281
296
|
.map_err(backend)?;
|
|
282
297
|
Ok(cid)
|
|
283
298
|
}
|
|
@@ -294,7 +309,10 @@ impl AsyncPut for KvCas {
|
|
|
294
309
|
Box::pin(async move {
|
|
295
310
|
let cid = Blake3::of(&bytes);
|
|
296
311
|
let key = self.key(&cid);
|
|
297
|
-
self.kv
|
|
312
|
+
self.kv
|
|
313
|
+
.aput_new(key.as_bytes(), bytes)
|
|
314
|
+
.await
|
|
315
|
+
.map_err(backend)?;
|
|
298
316
|
Ok(cid.into())
|
|
299
317
|
})
|
|
300
318
|
}
|
|
@@ -334,8 +352,8 @@ impl Cas for KvCas {
|
|
|
334
352
|
mismatch: false,
|
|
335
353
|
};
|
|
336
354
|
let key = self.key(&cid);
|
|
337
|
-
match self.kv.
|
|
338
|
-
Ok(
|
|
355
|
+
match self.kv.put_new_from(key.as_bytes(), &mut checked, len) {
|
|
356
|
+
Ok(_) => Ok(cid.into()),
|
|
339
357
|
// The store failed as asked; a store error beyond that, such as a
|
|
340
358
|
// failed cleanup, is the one to report.
|
|
341
359
|
Err(covalence_kv_trait::Error::Io { .. }) if checked.mismatch => {
|
|
@@ -25,7 +25,7 @@ use tokio::sync::oneshot;
|
|
|
25
25
|
const HELLO: &str = "blake3/5khrmpntq2bjexseshc6ldklwnig56gbj23yvbxjbdcwestheahq/bytes";
|
|
26
26
|
|
|
27
27
|
/// Store "hello" and check reads, then `corrupt` it and check that checked
|
|
28
|
-
/// reads notice, and that `put`
|
|
28
|
+
/// reads notice, and that `put` leaves the block it finds: it never replaces.
|
|
29
29
|
fn check(store: &KvCas, corrupt: impl FnOnce()) {
|
|
30
30
|
let cid: Cid = store.put("hello".into()).unwrap();
|
|
31
31
|
assert_eq!(cid, Blake3::of(b"hello").into());
|
|
@@ -59,7 +59,12 @@ fn check(store: &KvCas, corrupt: impl FnOnce()) {
|
|
|
59
59
|
));
|
|
60
60
|
assert!(matches!(store.get_fact(&cid), Err(Error::Check { .. })));
|
|
61
61
|
let _: Cid = store.put("hello".into()).unwrap();
|
|
62
|
-
assert_eq!(store.
|
|
62
|
+
assert_eq!(store.get_unchecked(&cid).unwrap().unwrap(), "wrong");
|
|
63
|
+
let _ = block_on(store.aput("hello".into())).unwrap();
|
|
64
|
+
assert_eq!(store.get_unchecked(&cid).unwrap().unwrap(), "wrong");
|
|
65
|
+
let put_from = store.put_from(Blake3::of(b"hello"), &mut &b"hello"[..], 5);
|
|
66
|
+
assert_eq!(put_from.unwrap(), cid);
|
|
67
|
+
assert_eq!(store.get_unchecked(&cid).unwrap().unwrap(), "wrong");
|
|
63
68
|
}
|
|
64
69
|
|
|
65
70
|
#[test]
|
|
@@ -72,7 +77,7 @@ fn memory() {
|
|
|
72
77
|
}
|
|
73
78
|
|
|
74
79
|
/// A key-value store that cannot read values, only whether they exist.
|
|
75
|
-
struct Blind(MemoryKv);
|
|
80
|
+
struct Blind(MemoryKv, usize);
|
|
76
81
|
|
|
77
82
|
impl Kv for Blind {
|
|
78
83
|
fn get(&self, _: &[u8]) -> Result<Option<Bytes>, covalence_kv_trait::Error> {
|
|
@@ -90,13 +95,61 @@ impl Kv for Blind {
|
|
|
90
95
|
fn exists(&self, key: &[u8]) -> Result<bool, covalence_kv_trait::Error> {
|
|
91
96
|
self.0.exists(key)
|
|
92
97
|
}
|
|
98
|
+
fn put_new(&self, key: &[u8], value: Bytes) -> Result<bool, covalence_kv_trait::Error> {
|
|
99
|
+
self.0.put_new(key, value)
|
|
100
|
+
}
|
|
101
|
+
fn aput_new<'a>(&'a self, key: &'a [u8], value: Bytes) -> KvFuture<'a, bool> {
|
|
102
|
+
self.0.aput_new(key, value)
|
|
103
|
+
}
|
|
104
|
+
fn put_new_from(
|
|
105
|
+
&self,
|
|
106
|
+
key: &[u8],
|
|
107
|
+
reader: &mut dyn std::io::Read,
|
|
108
|
+
len: u64,
|
|
109
|
+
) -> Result<bool, covalence_kv_trait::Error> {
|
|
110
|
+
if self.0.exists(key)? {
|
|
111
|
+
reader
|
|
112
|
+
.read_exact(&mut vec![0; self.1])
|
|
113
|
+
.map_err(|source| covalence_kv_trait::Error::Io { source })?;
|
|
114
|
+
return Ok(false);
|
|
115
|
+
}
|
|
116
|
+
self.0.put_new_from(key, reader, len)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/// An existing block may succeed with invalid or failing input left unread.
|
|
121
|
+
#[test]
|
|
122
|
+
fn existing_blocks_leave_unused_stream_bytes_unchecked() {
|
|
123
|
+
for consumed in [0, 2] {
|
|
124
|
+
// A backend may skip immediately or after reading part of the source.
|
|
125
|
+
let store = KvCas::new(Blind(MemoryKv::default(), consumed).into_dyn());
|
|
126
|
+
let cid: Cid = store.put("hello".into()).unwrap();
|
|
127
|
+
let claim = Blake3::of(b"hello");
|
|
128
|
+
for data in [&b"wrong"[..], &b"bad"[..]] {
|
|
129
|
+
let mut source = std::io::Cursor::new(data);
|
|
130
|
+
assert_eq!(store.put_from(claim, &mut source, 5).unwrap(), cid);
|
|
131
|
+
assert_eq!(source.position(), consumed as u64);
|
|
132
|
+
}
|
|
133
|
+
// An error beyond the consumed prefix must not be observed either.
|
|
134
|
+
let mut source = std::io::Read::chain(std::io::Cursor::new(b"he"), FailingReader);
|
|
135
|
+
assert_eq!(store.put_from(claim, &mut source, 5).unwrap(), cid);
|
|
136
|
+
assert_eq!(source.get_ref().0.position(), consumed as u64);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
struct FailingReader;
|
|
141
|
+
|
|
142
|
+
impl std::io::Read for FailingReader {
|
|
143
|
+
fn read(&mut self, _: &mut [u8]) -> std::io::Result<usize> {
|
|
144
|
+
Err(std::io::Error::other("source failed"))
|
|
145
|
+
}
|
|
93
146
|
}
|
|
94
147
|
|
|
95
148
|
/// `has` and `missing` ask whether keys exist rather than reading values,
|
|
96
149
|
/// through `Arc<dyn Cas>` too.
|
|
97
150
|
#[test]
|
|
98
151
|
fn existence_without_reads() {
|
|
99
|
-
let store = KvCas::new(Blind(MemoryKv::default()).into_dyn()).into_dyn();
|
|
152
|
+
let store = KvCas::new(Blind(MemoryKv::default(), 0).into_dyn()).into_dyn();
|
|
100
153
|
let cid = store.put("hello".into()).unwrap();
|
|
101
154
|
assert_eq!(store.put("hello".into()).unwrap(), cid);
|
|
102
155
|
let missing: Cid = Blake3::of(b"missing").into();
|
|
@@ -352,12 +405,12 @@ impl Kv for Leaky {
|
|
|
352
405
|
fn put(&self, _: &[u8], _: Bytes) -> Result<(), covalence_kv_trait::Error> {
|
|
353
406
|
Ok(())
|
|
354
407
|
}
|
|
355
|
-
fn
|
|
408
|
+
fn put_new_from(
|
|
356
409
|
&self,
|
|
357
410
|
_: &[u8],
|
|
358
411
|
reader: &mut dyn std::io::Read,
|
|
359
412
|
_: u64,
|
|
360
|
-
) -> Result<
|
|
413
|
+
) -> Result<bool, covalence_kv_trait::Error> {
|
|
361
414
|
let _ = reader.read_to_end(&mut Vec::new());
|
|
362
415
|
Err(covalence_kv_trait::Error::Backend {
|
|
363
416
|
source: "abort failed".into(),
|
|
@@ -350,10 +350,14 @@ pub trait Cas: Get + Put + AsyncGet + AsyncPut {
|
|
|
350
350
|
}
|
|
351
351
|
|
|
352
352
|
/// Store the next `len` bytes of `reader`, whose raw BLAKE3 CID is `cid`,
|
|
353
|
-
/// and return the key [`Put::put_fact`] would.
|
|
354
|
-
///
|
|
355
|
-
///
|
|
356
|
-
///
|
|
353
|
+
/// and return the key [`Put::put_fact`] would.
|
|
354
|
+
///
|
|
355
|
+
/// - A store may return an existing block without consuming all of
|
|
356
|
+
/// `reader`; unread bytes are not checked.
|
|
357
|
+
/// - Otherwise, reads exactly `len` bytes and no further. Stores nothing
|
|
358
|
+
/// and fails with [`Error::Check`] if the bytes have another CID, or
|
|
359
|
+
/// with [`Error::Io`] if `reader` fails or ends early.
|
|
360
|
+
/// - Reads into memory by default; stores that can stream override it.
|
|
357
361
|
fn put_from(&self, cid: Blake3, reader: &mut dyn Read, len: u64) -> Result<Cid, Error> {
|
|
358
362
|
let mut bytes = Vec::new();
|
|
359
363
|
let read = reader
|
|
@@ -17,13 +17,17 @@
|
|
|
17
17
|
//! ```
|
|
18
18
|
#![deny(missing_docs)]
|
|
19
19
|
|
|
20
|
-
use std::{
|
|
20
|
+
use std::{
|
|
21
|
+
collections::BTreeMap,
|
|
22
|
+
io::{self, Read},
|
|
23
|
+
sync::RwLock,
|
|
24
|
+
};
|
|
21
25
|
|
|
22
26
|
use covalence_kv_trait::{Error, Kv, KvFuture, ready};
|
|
23
27
|
use covalence_lib_dasl::Value;
|
|
24
28
|
use covalence_lib_data::Bytes;
|
|
25
29
|
|
|
26
|
-
/// An in-memory store. It accepts every key.
|
|
30
|
+
/// An in-memory store. It accepts every key, and [`Kv::put_new`] is atomic.
|
|
27
31
|
///
|
|
28
32
|
/// [`Kv::info`] is `{"name": "memory"}`, and [`Kv::stats`] counts `keys` and
|
|
29
33
|
/// the `bytes` of their values.
|
|
@@ -48,6 +52,35 @@ impl Kv for MemoryKv {
|
|
|
48
52
|
ready(self.put(key, value))
|
|
49
53
|
}
|
|
50
54
|
|
|
55
|
+
fn put_new(&self, key: &[u8], value: Bytes) -> Result<bool, Error> {
|
|
56
|
+
let mut map = self.0.write().unwrap();
|
|
57
|
+
if map.contains_key(key) {
|
|
58
|
+
return Ok(false);
|
|
59
|
+
}
|
|
60
|
+
map.insert(key.into(), value);
|
|
61
|
+
Ok(true)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/// Reads the value into memory first, so the store is locked only to
|
|
65
|
+
/// insert it.
|
|
66
|
+
fn put_new_from(&self, key: &[u8], reader: &mut dyn Read, len: u64) -> Result<bool, Error> {
|
|
67
|
+
let mut value = Vec::new();
|
|
68
|
+
let read = reader
|
|
69
|
+
.take(len)
|
|
70
|
+
.read_to_end(&mut value)
|
|
71
|
+
.map_err(|source| Error::Io { source })?;
|
|
72
|
+
if (read as u64) < len {
|
|
73
|
+
return Err(Error::Io {
|
|
74
|
+
source: io::ErrorKind::UnexpectedEof.into(),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
self.put_new(key, value.into())
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
fn aput_new<'a>(&'a self, key: &'a [u8], value: Bytes) -> KvFuture<'a, bool> {
|
|
81
|
+
ready(self.put_new(key, value))
|
|
82
|
+
}
|
|
83
|
+
|
|
51
84
|
fn exists(&self, key: &[u8]) -> Result<bool, Error> {
|
|
52
85
|
Ok(self.0.read().unwrap().contains_key(key))
|
|
53
86
|
}
|
|
@@ -27,6 +27,36 @@ fn put_and_get() -> Result<(), Error> {
|
|
|
27
27
|
Ok(())
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
/// A new value goes only under a free key, also through `Arc<dyn Kv>`, and
|
|
31
|
+
/// racing writers of one key store once.
|
|
32
|
+
#[test]
|
|
33
|
+
fn new_values_never_replace() -> Result<(), Error> {
|
|
34
|
+
let store = store();
|
|
35
|
+
assert!(store.put_new(b"a", "one".into())?);
|
|
36
|
+
assert!(!store.put_new(b"a", "two".into())?);
|
|
37
|
+
assert!(!block_on(store.aput_new(b"a", "two".into()))?);
|
|
38
|
+
assert!(!store.put_new_from(b"a", &mut &b"two"[..], 3)?);
|
|
39
|
+
assert_eq!(store.get(b"a")?.unwrap(), "one");
|
|
40
|
+
assert!(store.put_new_from(b"b", &mut &b"two!"[..], 3)?);
|
|
41
|
+
assert_eq!(store.get(b"b")?.unwrap(), "two");
|
|
42
|
+
let error = store.put_new_from(b"c", &mut &b"ab"[..], 3).unwrap_err();
|
|
43
|
+
assert!(matches!(error, Error::Io { .. }), "{error}");
|
|
44
|
+
assert!(!store.exists(b"c")?);
|
|
45
|
+
let stored = std::thread::scope(|scope| {
|
|
46
|
+
let store = &store;
|
|
47
|
+
let racers: Vec<_> = (0..8u8)
|
|
48
|
+
.map(|i| scope.spawn(move || store.put_new(b"race", vec![i].into()).unwrap()))
|
|
49
|
+
.collect();
|
|
50
|
+
racers
|
|
51
|
+
.into_iter()
|
|
52
|
+
.map(|racer| racer.join().unwrap())
|
|
53
|
+
.filter(|&stored| stored)
|
|
54
|
+
.count()
|
|
55
|
+
});
|
|
56
|
+
assert_eq!(stored, 1);
|
|
57
|
+
Ok(())
|
|
58
|
+
}
|
|
59
|
+
|
|
30
60
|
#[test]
|
|
31
61
|
fn async_matches_sync() -> Result<(), Error> {
|
|
32
62
|
let store = store();
|