@lix-js/sdk 0.6.0-preview.3 → 0.6.0-preview.5
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.
- package/README.md +1 -1
- package/SKILL.md +105 -65
- package/dist/engine-wasm/index.js +4 -4
- package/dist/engine-wasm/wasm/lix_engine.d.ts +30 -6
- package/dist/engine-wasm/wasm/lix_engine.js +187 -117
- package/dist/engine-wasm/wasm/lix_engine.wasm +0 -0
- package/dist/engine-wasm/wasm/lix_engine.wasm.d.ts +14 -8
- package/dist/generated/builtin-schemas.d.ts +69 -69
- package/dist/generated/builtin-schemas.js +94 -94
- package/dist/open-lix.d.ts +42 -28
- package/dist/open-lix.js +49 -10
- package/dist/sqlite/index.js +86 -30
- package/dist-engine-src/README.md +3 -3
- package/dist-engine-src/src/backend/capabilities.rs +67 -0
- package/dist-engine-src/src/backend/conformance/baseline.rs +1127 -0
- package/dist-engine-src/src/backend/conformance/factory.rs +93 -0
- package/dist-engine-src/src/backend/conformance/failure_tests.rs +608 -0
- package/dist-engine-src/src/backend/conformance/fixtures.rs +26 -0
- package/dist-engine-src/src/backend/conformance/mod.rs +75 -0
- package/dist-engine-src/src/backend/conformance/model.rs +28 -0
- package/dist-engine-src/src/backend/conformance/model_based.rs +257 -0
- package/dist-engine-src/src/backend/conformance/persistence.rs +204 -0
- package/dist-engine-src/src/backend/conformance/projection.rs +21 -0
- package/dist-engine-src/src/backend/conformance/pushdown.rs +24 -0
- package/dist-engine-src/src/backend/conformance/runner.rs +90 -0
- package/dist-engine-src/src/backend/conformance/scan.rs +24 -0
- package/dist-engine-src/src/backend/conformance/write.rs +16 -0
- package/dist-engine-src/src/backend/error.rs +94 -0
- package/dist-engine-src/src/backend/in_memory.rs +670 -0
- package/dist-engine-src/src/backend/mod.rs +36 -9
- package/dist-engine-src/src/backend/predicate.rs +80 -0
- package/dist-engine-src/src/backend/traits.rs +260 -0
- package/dist-engine-src/src/backend/types.rs +224 -81
- package/dist-engine-src/src/binary_cas/context.rs +8 -8
- package/dist-engine-src/src/binary_cas/kv.rs +234 -259
- package/dist-engine-src/src/{version → branch}/context.rs +12 -12
- package/dist-engine-src/src/branch/lifecycle.rs +221 -0
- package/dist-engine-src/src/branch/mod.rs +13 -0
- package/dist-engine-src/src/branch/refs.rs +321 -0
- package/dist-engine-src/src/branch/stage_rows.rs +67 -0
- package/dist-engine-src/src/branch/types.rs +21 -0
- package/dist-engine-src/src/catalog/context.rs +18 -18
- package/dist-engine-src/src/catalog/snapshot.rs +8 -8
- package/dist-engine-src/src/changelog/bench_support.rs +785 -0
- package/dist-engine-src/src/changelog/change.rs +1 -0
- package/dist-engine-src/src/changelog/codec.rs +497 -0
- package/dist-engine-src/src/changelog/commit.rs +1 -0
- package/dist-engine-src/src/changelog/context.rs +1614 -0
- package/dist-engine-src/src/changelog/mod.rs +29 -0
- package/dist-engine-src/src/changelog/store.rs +163 -0
- package/dist-engine-src/src/changelog/test_support.rs +54 -0
- package/dist-engine-src/src/changelog/types.rs +213 -0
- package/dist-engine-src/src/commit_graph/context.rs +317 -274
- package/dist-engine-src/src/commit_graph/mod.rs +2 -4
- package/dist-engine-src/src/commit_graph/types.rs +22 -42
- package/dist-engine-src/src/commit_graph/walker.rs +133 -103
- package/dist-engine-src/src/common/error.rs +52 -18
- package/dist-engine-src/src/common/identity.rs +2 -2
- package/dist-engine-src/src/common/mod.rs +1 -1
- package/dist-engine-src/src/domain.rs +42 -46
- package/dist-engine-src/src/engine.rs +74 -96
- package/dist-engine-src/src/{entity_identity.rs → entity_pk.rs} +89 -92
- package/dist-engine-src/src/functions/context.rs +56 -52
- package/dist-engine-src/src/functions/state.rs +51 -52
- package/dist-engine-src/src/init.rs +288 -154
- package/dist-engine-src/src/json_store/context.rs +15 -266
- package/dist-engine-src/src/json_store/mod.rs +26 -0
- package/dist-engine-src/src/json_store/store.rs +103 -718
- package/dist-engine-src/src/json_store/types.rs +4 -9
- package/dist-engine-src/src/lib.rs +49 -19
- package/dist-engine-src/src/live_state/context.rs +654 -790
- package/dist-engine-src/src/live_state/mod.rs +9 -3
- package/dist-engine-src/src/live_state/overlay.rs +4 -4
- package/dist-engine-src/src/live_state/types.rs +30 -21
- package/dist-engine-src/src/live_state/visibility.rs +514 -71
- package/dist-engine-src/src/plugin/install.rs +48 -48
- package/dist-engine-src/src/plugin/manifest.rs +7 -7
- package/dist-engine-src/src/plugin/materializer.rs +0 -275
- package/dist-engine-src/src/plugin/plugin_manifest.json +4 -3
- package/dist-engine-src/src/schema/builtin/lix_binary_blob_ref.json +2 -2
- package/dist-engine-src/src/schema/builtin/lix_branch_descriptor.json +34 -0
- package/dist-engine-src/src/schema/builtin/lix_branch_ref.json +48 -0
- package/dist-engine-src/src/schema/builtin/lix_change.json +3 -3
- package/dist-engine-src/src/schema/builtin/lix_commit.json +1 -1
- package/dist-engine-src/src/schema/builtin/lix_label_assignment.json +6 -6
- package/dist-engine-src/src/schema/builtin/mod.rs +18 -20
- package/dist-engine-src/src/schema/compatibility.rs +11 -11
- package/dist-engine-src/src/schema/definition.json +2 -2
- package/dist-engine-src/src/schema/definition.rs +5 -5
- package/dist-engine-src/src/schema/key.rs +3 -3
- package/dist-engine-src/src/schema/mod.rs +1 -1
- package/dist-engine-src/src/schema/tests.rs +18 -18
- package/dist-engine-src/src/session/context.rs +819 -124
- package/dist-engine-src/src/session/create_branch.rs +94 -0
- package/dist-engine-src/src/session/execute.rs +260 -57
- package/dist-engine-src/src/session/merge/analysis.rs +9 -3
- package/dist-engine-src/src/session/merge/{version.rs → branch.rs} +119 -129
- package/dist-engine-src/src/session/merge/conflicts.rs +2 -2
- package/dist-engine-src/src/session/merge/mod.rs +5 -6
- package/dist-engine-src/src/session/merge/stats.rs +7 -11
- package/dist-engine-src/src/session/mod.rs +19 -16
- package/dist-engine-src/src/session/switch_branch.rs +113 -0
- package/dist-engine-src/src/session/transaction.rs +557 -0
- package/dist-engine-src/src/sql2/bind/classify.rs +102 -0
- package/dist-engine-src/src/sql2/bind/error.rs +5 -0
- package/dist-engine-src/src/sql2/bind/expr.rs +29 -0
- package/dist-engine-src/src/sql2/bind/mod.rs +12 -0
- package/dist-engine-src/src/sql2/{udfs/public_call.rs → bind/public_udf.rs} +98 -3
- package/dist-engine-src/src/sql2/bind/read.rs +65 -0
- package/dist-engine-src/src/sql2/bind/statement.rs +2236 -0
- package/dist-engine-src/src/sql2/bind/table.rs +273 -0
- package/dist-engine-src/src/sql2/bind/write.rs +86 -0
- package/dist-engine-src/src/sql2/branch_scope.rs +436 -0
- package/dist-engine-src/src/sql2/catalog/capability.rs +20 -0
- package/dist-engine-src/src/sql2/catalog/entity_surface.rs +296 -0
- package/dist-engine-src/src/sql2/catalog/mod.rs +15 -0
- package/dist-engine-src/src/sql2/catalog/registry.rs +556 -0
- package/dist-engine-src/src/sql2/catalog/schema.rs +88 -0
- package/dist-engine-src/src/sql2/catalog/surface.rs +41 -0
- package/dist-engine-src/src/sql2/change_materialization.rs +122 -0
- package/dist-engine-src/src/sql2/context.rs +36 -30
- package/dist-engine-src/src/sql2/error.rs +4 -5
- package/dist-engine-src/src/sql2/exec/bound_public_write.rs +1593 -0
- package/dist-engine-src/src/sql2/exec/datafusion.rs +5266 -0
- package/dist-engine-src/src/sql2/exec/fast_write.rs +82 -0
- package/dist-engine-src/src/sql2/exec/mod.rs +24 -0
- package/dist-engine-src/src/sql2/exec/write.rs +661 -0
- package/dist-engine-src/src/sql2/filesystem_planner.rs +72 -77
- package/dist-engine-src/src/sql2/filesystem_visibility.rs +21 -21
- package/dist-engine-src/src/sql2/history_projection.rs +8 -8
- package/dist-engine-src/src/sql2/history_route.rs +35 -31
- package/dist-engine-src/src/sql2/mod.rs +30 -24
- package/dist-engine-src/src/sql2/optimize/datafusion.rs +1 -0
- package/dist-engine-src/src/sql2/optimize/mod.rs +2 -0
- package/dist-engine-src/src/sql2/optimize/simple_write.rs +116 -0
- package/dist-engine-src/src/sql2/parse/mod.rs +69 -0
- package/dist-engine-src/src/sql2/parse/normalize.rs +1 -0
- package/dist-engine-src/src/sql2/plan/branch_scope.rs +24 -0
- package/dist-engine-src/src/sql2/plan/mod.rs +5 -0
- package/dist-engine-src/src/sql2/plan/predicate.rs +22 -0
- package/dist-engine-src/src/sql2/plan/write.rs +147 -0
- package/dist-engine-src/src/sql2/predicate_typecheck.rs +258 -0
- package/dist-engine-src/src/sql2/{version_provider.rs → providers/branch.rs} +218 -214
- package/dist-engine-src/src/sql2/{change_provider.rs → providers/change.rs} +156 -42
- package/dist-engine-src/src/sql2/{directory_provider.rs → providers/directory.rs} +291 -322
- package/dist-engine-src/src/sql2/{directory_history_provider.rs → providers/directory_history.rs} +56 -42
- package/dist-engine-src/src/sql2/providers/entity.rs +1484 -0
- package/dist-engine-src/src/sql2/{entity_history_provider.rs → providers/entity_history.rs} +43 -31
- package/dist-engine-src/src/sql2/{file_provider.rs → providers/file.rs} +323 -316
- package/dist-engine-src/src/sql2/{file_history_provider.rs → providers/file_history.rs} +60 -46
- package/dist-engine-src/src/sql2/{history_provider.rs → providers/history.rs} +46 -32
- package/dist-engine-src/src/sql2/{lix_state_provider.rs → providers/lix_state.rs} +359 -329
- package/dist-engine-src/src/sql2/providers/mod.rs +508 -0
- package/dist-engine-src/src/sql2/read_only.rs +2 -2
- package/dist-engine-src/src/sql2/session.rs +47 -96
- package/dist-engine-src/src/sql2/storage/constraints.rs +1 -0
- package/dist-engine-src/src/sql2/storage/mod.rs +1 -0
- package/dist-engine-src/src/sql2/test_support/differential.rs +712 -0
- package/dist-engine-src/src/sql2/test_support/generators.rs +354 -0
- package/dist-engine-src/src/sql2/test_support/mod.rs +2 -0
- package/dist-engine-src/src/sql2/udfs/{lix_active_version_commit_id.rs → lix_active_branch_commit_id.rs} +7 -7
- package/dist-engine-src/src/sql2/udfs/mod.rs +3 -6
- package/dist-engine-src/src/sql2/write_normalization.rs +45 -22
- package/dist-engine-src/src/storage/conformance.rs +399 -0
- package/dist-engine-src/src/storage/context.rs +552 -288
- package/dist-engine-src/src/storage/mod.rs +48 -10
- package/dist-engine-src/src/storage/point.rs +440 -0
- package/dist-engine-src/src/storage/read_scope.rs +43 -64
- package/dist-engine-src/src/storage/reader.rs +867 -0
- package/dist-engine-src/src/storage/scan.rs +784 -0
- package/dist-engine-src/src/storage/spaces.rs +236 -0
- package/dist-engine-src/src/storage/stats.rs +80 -0
- package/dist-engine-src/src/storage/write_set.rs +962 -0
- package/dist-engine-src/src/storage_bench.rs +136 -4828
- package/dist-engine-src/src/test_support.rs +360 -138
- package/dist-engine-src/src/tracked_state/bench_support.rs +394 -0
- package/dist-engine-src/src/tracked_state/codec.rs +155 -1057
- package/dist-engine-src/src/tracked_state/commit_root_rebuild.rs +358 -0
- package/dist-engine-src/src/tracked_state/context.rs +1927 -993
- package/dist-engine-src/src/tracked_state/diff.rs +1715 -261
- package/dist-engine-src/src/tracked_state/merge.rs +74 -88
- package/dist-engine-src/src/tracked_state/mod.rs +19 -16
- package/dist-engine-src/src/tracked_state/{materialization.rs → row_materialization.rs} +50 -178
- package/dist-engine-src/src/tracked_state/storage.rs +243 -191
- package/dist-engine-src/src/tracked_state/tree.rs +247 -371
- package/dist-engine-src/src/tracked_state/types.rs +49 -42
- package/dist-engine-src/src/transaction/bench_support.rs +407 -0
- package/dist-engine-src/src/transaction/commit.rs +821 -713
- package/dist-engine-src/src/transaction/context.rs +705 -600
- package/dist-engine-src/src/transaction/mod.rs +13 -2
- package/dist-engine-src/src/transaction/normalization.rs +63 -76
- package/dist-engine-src/src/transaction/prep.rs +13 -13
- package/dist-engine-src/src/transaction/schema_resolver.rs +19 -5
- package/dist-engine-src/src/transaction/staging.rs +228 -434
- package/dist-engine-src/src/transaction/types.rs +41 -98
- package/dist-engine-src/src/transaction/validation.rs +382 -446
- package/dist-engine-src/src/untracked_state/codec.rs +337 -29
- package/dist-engine-src/src/untracked_state/context.rs +7 -7
- package/dist-engine-src/src/untracked_state/materialization.rs +2 -2
- package/dist-engine-src/src/untracked_state/mod.rs +1 -1
- package/dist-engine-src/src/untracked_state/storage.rs +659 -157
- package/dist-engine-src/src/untracked_state/types.rs +21 -21
- package/package.json +71 -68
- package/dist-engine-src/src/backend/kv.rs +0 -358
- package/dist-engine-src/src/backend/testing.rs +0 -658
- package/dist-engine-src/src/commit_store/codec.rs +0 -887
- package/dist-engine-src/src/commit_store/context.rs +0 -944
- package/dist-engine-src/src/commit_store/materialization.rs +0 -84
- package/dist-engine-src/src/commit_store/mod.rs +0 -16
- package/dist-engine-src/src/commit_store/storage.rs +0 -600
- package/dist-engine-src/src/commit_store/types.rs +0 -215
- package/dist-engine-src/src/schema/builtin/lix_version_descriptor.json +0 -34
- package/dist-engine-src/src/schema/builtin/lix_version_ref.json +0 -48
- package/dist-engine-src/src/session/create_version.rs +0 -88
- package/dist-engine-src/src/session/merge/apply.rs +0 -23
- package/dist-engine-src/src/session/optimization9_sql2_bench.rs +0 -100
- package/dist-engine-src/src/session/switch_version.rs +0 -109
- package/dist-engine-src/src/sql2/classify.rs +0 -182
- package/dist-engine-src/src/sql2/entity_provider.rs +0 -3211
- package/dist-engine-src/src/sql2/execute.rs +0 -3440
- package/dist-engine-src/src/sql2/public_bind/assignment.rs +0 -46
- package/dist-engine-src/src/sql2/public_bind/capability.rs +0 -41
- package/dist-engine-src/src/sql2/public_bind/dml.rs +0 -166
- package/dist-engine-src/src/sql2/public_bind/mod.rs +0 -25
- package/dist-engine-src/src/sql2/public_bind/table.rs +0 -168
- package/dist-engine-src/src/sql2/version_scope.rs +0 -394
- package/dist-engine-src/src/storage/types.rs +0 -501
- package/dist-engine-src/src/tracked_state/by_file_index.rs +0 -98
- package/dist-engine-src/src/tracked_state/materializer.rs +0 -488
- package/dist-engine-src/src/transaction/live_state_overlay.rs +0 -35
- package/dist-engine-src/src/version/lifecycle.rs +0 -221
- package/dist-engine-src/src/version/mod.rs +0 -13
- package/dist-engine-src/src/version/refs.rs +0 -330
- package/dist-engine-src/src/version/stage_rows.rs +0 -67
- package/dist-engine-src/src/version/types.rs +0 -21
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
use std::ops::Bound;
|
|
2
|
+
|
|
3
|
+
use bytes::Bytes;
|
|
4
|
+
|
|
5
|
+
use crate::backend::{Key, KeyRange, Prefix};
|
|
6
|
+
|
|
7
|
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
8
|
+
pub struct BackendPredicate {
|
|
9
|
+
pub id: PredicateId,
|
|
10
|
+
pub expr: PredicateExpr,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
|
14
|
+
pub struct PredicateId(pub u32);
|
|
15
|
+
|
|
16
|
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
17
|
+
pub enum PredicateExpr {
|
|
18
|
+
Key(KeyPredicate),
|
|
19
|
+
Header(HeaderPredicate),
|
|
20
|
+
Refs(RefsPredicate),
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
24
|
+
pub enum KeyPredicate {
|
|
25
|
+
Eq(Key),
|
|
26
|
+
StartsWith(Prefix),
|
|
27
|
+
Range(KeyRange),
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
31
|
+
pub enum HeaderPredicate {
|
|
32
|
+
FieldEq {
|
|
33
|
+
field: HeaderFieldId,
|
|
34
|
+
value: ScalarValue,
|
|
35
|
+
},
|
|
36
|
+
FieldIn {
|
|
37
|
+
field: HeaderFieldId,
|
|
38
|
+
values: Vec<ScalarValue>,
|
|
39
|
+
},
|
|
40
|
+
FieldRange {
|
|
41
|
+
field: HeaderFieldId,
|
|
42
|
+
lower: Bound<ScalarValue>,
|
|
43
|
+
upper: Bound<ScalarValue>,
|
|
44
|
+
},
|
|
45
|
+
IsDeleted(bool),
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
49
|
+
pub enum RefsPredicate {
|
|
50
|
+
HasRef { kind: RefKind, value: Bytes },
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
|
54
|
+
pub struct HeaderFieldId(pub u16);
|
|
55
|
+
|
|
56
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
|
57
|
+
pub struct RefKind(pub u16);
|
|
58
|
+
|
|
59
|
+
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
|
60
|
+
pub enum ScalarValue {
|
|
61
|
+
Bool(bool),
|
|
62
|
+
U64(u64),
|
|
63
|
+
I64(i64),
|
|
64
|
+
Bytes(Bytes),
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
68
|
+
pub enum Support {
|
|
69
|
+
Exact,
|
|
70
|
+
Inexact,
|
|
71
|
+
Unsupported,
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
|
75
|
+
pub enum PredicateSupportLevel {
|
|
76
|
+
#[default]
|
|
77
|
+
None,
|
|
78
|
+
Inexact,
|
|
79
|
+
Exact,
|
|
80
|
+
}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
use crate::backend::{
|
|
2
|
+
BackendCapabilities, BackendError, CommitResult, GetManyResult, GetOptions, Key, KeyRange,
|
|
3
|
+
KeyRef, ProjectedValue, ProjectedValueRef, PutBatch, ReadEntry, ReadOptions, ScanOptions,
|
|
4
|
+
ScanResult, WriteOptions,
|
|
5
|
+
};
|
|
6
|
+
use std::sync::Arc;
|
|
7
|
+
|
|
8
|
+
/// Process-local write lane for one backend durable target.
|
|
9
|
+
///
|
|
10
|
+
/// This type intentionally hides the async mutex implementation from the
|
|
11
|
+
/// public `Backend` contract while preserving a cloneable handle that backend
|
|
12
|
+
/// implementations can share across cloned or reopened handles.
|
|
13
|
+
#[derive(Clone)]
|
|
14
|
+
pub struct DurableWriteLock {
|
|
15
|
+
inner: Arc<tokio::sync::Mutex<()>>,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
impl std::fmt::Debug for DurableWriteLock {
|
|
19
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
20
|
+
f.debug_struct("DurableWriteLock").finish_non_exhaustive()
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
impl DurableWriteLock {
|
|
25
|
+
pub fn new() -> Self {
|
|
26
|
+
Self {
|
|
27
|
+
inner: Arc::new(tokio::sync::Mutex::new(())),
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
pub async fn lock_owned(&self) -> DurableWriteGuard {
|
|
32
|
+
DurableWriteGuard {
|
|
33
|
+
_guard: Arc::clone(&self.inner).lock_owned().await,
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
pub fn ptr_eq(&self, other: &Self) -> bool {
|
|
38
|
+
Arc::ptr_eq(&self.inner, &other.inner)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
impl Default for DurableWriteLock {
|
|
43
|
+
fn default() -> Self {
|
|
44
|
+
Self::new()
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
pub struct DurableWriteGuard {
|
|
49
|
+
_guard: tokio::sync::OwnedMutexGuard<()>,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
pub trait Backend {
|
|
53
|
+
type Read<'a>: BackendRead + 'a
|
|
54
|
+
where
|
|
55
|
+
Self: 'a;
|
|
56
|
+
|
|
57
|
+
type Write<'a>: BackendWrite + 'a
|
|
58
|
+
where
|
|
59
|
+
Self: 'a;
|
|
60
|
+
|
|
61
|
+
fn capabilities(&self) -> BackendCapabilities;
|
|
62
|
+
|
|
63
|
+
fn begin_read(&self, opts: ReadOptions) -> Result<Self::Read<'_>, BackendError>;
|
|
64
|
+
|
|
65
|
+
fn begin_write(&self, opts: WriteOptions) -> Result<Self::Write<'_>, BackendError>;
|
|
66
|
+
|
|
67
|
+
/// Serializes engine-level durable writes for this backend's durable target.
|
|
68
|
+
///
|
|
69
|
+
/// Clones or independently opened handles for the same durable target must
|
|
70
|
+
/// return the same lock. Handles for independent targets may return
|
|
71
|
+
/// independent locks.
|
|
72
|
+
///
|
|
73
|
+
/// This lock is a process-local write lane, not a durability mechanism.
|
|
74
|
+
/// Crash recovery, fsync policy, and cross-process serialization are backend
|
|
75
|
+
/// responsibilities in the MVP.
|
|
76
|
+
fn durable_write_lock(&self) -> DurableWriteLock;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
pub trait BackendRead {
|
|
80
|
+
type RangeScan<'cursor>: BackendRangeScan;
|
|
81
|
+
|
|
82
|
+
fn visit_keys<V>(
|
|
83
|
+
&self,
|
|
84
|
+
keys: &[Key],
|
|
85
|
+
opts: GetOptions<'_>,
|
|
86
|
+
visitor: &mut V,
|
|
87
|
+
) -> Result<(), BackendError>
|
|
88
|
+
where
|
|
89
|
+
V: PointVisitor + ?Sized;
|
|
90
|
+
|
|
91
|
+
fn with_range_scan<T, F>(
|
|
92
|
+
&self,
|
|
93
|
+
range: KeyRange,
|
|
94
|
+
opts: ScanOptions<'_>,
|
|
95
|
+
f: F,
|
|
96
|
+
) -> Result<T, BackendError>
|
|
97
|
+
where
|
|
98
|
+
F: FnOnce(&mut Self::RangeScan<'_>) -> Result<T, BackendError>;
|
|
99
|
+
|
|
100
|
+
fn close(self) -> Result<(), BackendError>
|
|
101
|
+
where
|
|
102
|
+
Self: Sized,
|
|
103
|
+
{
|
|
104
|
+
Ok(())
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
pub trait ScanVisitor {
|
|
109
|
+
fn visit(&mut self, key: KeyRef<'_>, value: ProjectedValueRef<'_>) -> Result<(), BackendError>;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
pub trait BackendRangeScan {
|
|
113
|
+
fn visit_next<V>(
|
|
114
|
+
&mut self,
|
|
115
|
+
limit_rows: usize,
|
|
116
|
+
visitor: &mut V,
|
|
117
|
+
) -> Result<ScanResult, BackendError>
|
|
118
|
+
where
|
|
119
|
+
V: ScanVisitor + ?Sized;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
#[derive(Clone, Debug, Default)]
|
|
123
|
+
pub struct BufferedRangeScan {
|
|
124
|
+
rows: Vec<ReadEntry>,
|
|
125
|
+
position: usize,
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
impl BufferedRangeScan {
|
|
129
|
+
pub fn new(rows: Vec<ReadEntry>) -> Self {
|
|
130
|
+
Self { rows, position: 0 }
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
impl BackendRangeScan for BufferedRangeScan {
|
|
135
|
+
fn visit_next<V>(
|
|
136
|
+
&mut self,
|
|
137
|
+
limit_rows: usize,
|
|
138
|
+
visitor: &mut V,
|
|
139
|
+
) -> Result<ScanResult, BackendError>
|
|
140
|
+
where
|
|
141
|
+
V: ScanVisitor + ?Sized,
|
|
142
|
+
{
|
|
143
|
+
if limit_rows == 0 {
|
|
144
|
+
return Ok(ScanResult::default());
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
let mut emitted = 0usize;
|
|
148
|
+
while emitted < limit_rows {
|
|
149
|
+
let Some(entry) = self.rows.get(self.position) else {
|
|
150
|
+
break;
|
|
151
|
+
};
|
|
152
|
+
visitor.visit(entry.key.as_ref(), entry.value.as_ref())?;
|
|
153
|
+
self.position += 1;
|
|
154
|
+
emitted += 1;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
Ok(ScanResult {
|
|
158
|
+
emitted,
|
|
159
|
+
has_more: self.position < self.rows.len(),
|
|
160
|
+
})
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
pub trait PointVisitor {
|
|
165
|
+
fn visit(
|
|
166
|
+
&mut self,
|
|
167
|
+
index: usize,
|
|
168
|
+
key: &Key,
|
|
169
|
+
value: Option<ProjectedValueRef<'_>>,
|
|
170
|
+
) -> Result<(), BackendError>;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
pub fn get_many<R>(
|
|
174
|
+
read: &R,
|
|
175
|
+
keys: &[Key],
|
|
176
|
+
opts: GetOptions<'_>,
|
|
177
|
+
) -> Result<GetManyResult, BackendError>
|
|
178
|
+
where
|
|
179
|
+
R: BackendRead + ?Sized,
|
|
180
|
+
{
|
|
181
|
+
struct MaterializingPointVisitor<'a> {
|
|
182
|
+
values: &'a mut [Option<ProjectedValue>],
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
impl PointVisitor for MaterializingPointVisitor<'_> {
|
|
186
|
+
fn visit(
|
|
187
|
+
&mut self,
|
|
188
|
+
index: usize,
|
|
189
|
+
_key: &Key,
|
|
190
|
+
value: Option<ProjectedValueRef<'_>>,
|
|
191
|
+
) -> Result<(), BackendError> {
|
|
192
|
+
if let Some(slot) = self.values.get_mut(index) {
|
|
193
|
+
*slot = value.map(|value| value.to_owned());
|
|
194
|
+
}
|
|
195
|
+
Ok(())
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
let mut values = vec![None::<ProjectedValue>; keys.len()];
|
|
200
|
+
read.visit_keys(
|
|
201
|
+
keys,
|
|
202
|
+
opts,
|
|
203
|
+
&mut MaterializingPointVisitor {
|
|
204
|
+
values: values.as_mut_slice(),
|
|
205
|
+
},
|
|
206
|
+
)?;
|
|
207
|
+
Ok(GetManyResult::new(values))
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
pub fn visit_range<R>(
|
|
211
|
+
read: &R,
|
|
212
|
+
range: KeyRange,
|
|
213
|
+
opts: ScanOptions<'_>,
|
|
214
|
+
visitor: &mut dyn ScanVisitor,
|
|
215
|
+
) -> Result<ScanResult, BackendError>
|
|
216
|
+
where
|
|
217
|
+
R: BackendRead,
|
|
218
|
+
{
|
|
219
|
+
let limit_rows = opts.limit_rows;
|
|
220
|
+
read.with_range_scan(range, opts, |cursor| cursor.visit_next(limit_rows, visitor))
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
impl<F> ScanVisitor for F
|
|
224
|
+
where
|
|
225
|
+
F: for<'a> FnMut(KeyRef<'a>, ProjectedValueRef<'a>) -> Result<(), BackendError>,
|
|
226
|
+
{
|
|
227
|
+
fn visit(&mut self, key: KeyRef<'_>, value: ProjectedValueRef<'_>) -> Result<(), BackendError> {
|
|
228
|
+
self(key, value)
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
impl<F> PointVisitor for F
|
|
233
|
+
where
|
|
234
|
+
F: for<'a> FnMut(usize, &Key, Option<ProjectedValueRef<'a>>) -> Result<(), BackendError>,
|
|
235
|
+
{
|
|
236
|
+
fn visit(
|
|
237
|
+
&mut self,
|
|
238
|
+
index: usize,
|
|
239
|
+
key: &Key,
|
|
240
|
+
value: Option<ProjectedValueRef<'_>>,
|
|
241
|
+
) -> Result<(), BackendError> {
|
|
242
|
+
self(index, key, value)
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
pub trait BackendWrite {
|
|
247
|
+
fn put_many(&mut self, entries: PutBatch) -> Result<(), BackendError>;
|
|
248
|
+
|
|
249
|
+
fn delete_many(&mut self, keys: &[Key]) -> Result<(), BackendError>;
|
|
250
|
+
|
|
251
|
+
fn delete_range(&mut self, range: KeyRange) -> Result<(), BackendError>;
|
|
252
|
+
|
|
253
|
+
fn commit(self) -> Result<CommitResult, BackendError>
|
|
254
|
+
where
|
|
255
|
+
Self: Sized;
|
|
256
|
+
|
|
257
|
+
fn rollback(self) -> Result<(), BackendError>
|
|
258
|
+
where
|
|
259
|
+
Self: Sized;
|
|
260
|
+
}
|
|
@@ -1,96 +1,239 @@
|
|
|
1
|
-
use
|
|
2
|
-
|
|
3
|
-
use
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
#[
|
|
11
|
-
pub
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
1
|
+
use std::ops::Bound;
|
|
2
|
+
|
|
3
|
+
use bytes::Bytes;
|
|
4
|
+
|
|
5
|
+
use crate::backend::BackendError;
|
|
6
|
+
|
|
7
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
|
8
|
+
pub struct SpaceId(pub u32);
|
|
9
|
+
|
|
10
|
+
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
|
11
|
+
pub struct Key(pub Bytes);
|
|
12
|
+
|
|
13
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
|
14
|
+
pub struct KeyRef<'a>(pub &'a [u8]);
|
|
15
|
+
|
|
16
|
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
17
|
+
pub struct Value(pub Bytes);
|
|
18
|
+
|
|
19
|
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
20
|
+
pub struct ReadEntry {
|
|
21
|
+
pub key: Key,
|
|
22
|
+
pub value: ProjectedValue,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
26
|
+
pub struct PutEntry {
|
|
27
|
+
pub key: Key,
|
|
28
|
+
pub value: StoredValue,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
|
32
|
+
pub struct PutBatch {
|
|
33
|
+
pub entries: Vec<PutEntry>,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
37
|
+
pub struct StoredValue {
|
|
38
|
+
pub bytes: Bytes,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
42
|
+
pub struct KeyRange {
|
|
43
|
+
pub lower: Bound<Key>,
|
|
44
|
+
pub upper: Bound<Key>,
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
48
|
+
pub struct Prefix {
|
|
49
|
+
pub bytes: Bytes,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
53
|
+
pub struct GetOptions<'a> {
|
|
54
|
+
pub projection: CoreProjection,
|
|
55
|
+
pub _reserved: std::marker::PhantomData<&'a ()>,
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
59
|
+
pub struct ScanOptions<'a> {
|
|
60
|
+
pub projection: CoreProjection,
|
|
61
|
+
pub limit_rows: usize,
|
|
62
|
+
pub resume_after: Option<&'a Key>,
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
66
|
+
pub struct ScanChunk {
|
|
67
|
+
pub entries: Vec<ReadEntry>,
|
|
68
|
+
pub has_more: bool,
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
|
72
|
+
pub struct ScanResult {
|
|
73
|
+
pub emitted: usize,
|
|
74
|
+
pub has_more: bool,
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
78
|
+
pub struct GetManyResult {
|
|
79
|
+
/// One slot per key passed to `get_many`, in caller order.
|
|
21
80
|
///
|
|
22
|
-
///
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
81
|
+
/// Duplicates are preserved. `None` means the requested key was missing.
|
|
82
|
+
pub values: Vec<Option<ProjectedValue>>,
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
86
|
+
pub enum CoreProjection {
|
|
87
|
+
KeyOnly,
|
|
88
|
+
FullValue,
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
92
|
+
pub enum ProjectedValue {
|
|
93
|
+
KeyOnly,
|
|
94
|
+
FullValue(Bytes),
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
98
|
+
pub enum ProjectedValueRef<'a> {
|
|
99
|
+
KeyOnly,
|
|
100
|
+
FullValue(&'a [u8]),
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
impl ProjectedValueRef<'_> {
|
|
104
|
+
pub fn to_owned(self) -> ProjectedValue {
|
|
105
|
+
match self {
|
|
106
|
+
ProjectedValueRef::KeyOnly => ProjectedValue::KeyOnly,
|
|
107
|
+
ProjectedValueRef::FullValue(value) => {
|
|
108
|
+
ProjectedValue::FullValue(Bytes::copy_from_slice(value))
|
|
109
|
+
}
|
|
110
|
+
}
|
|
29
111
|
}
|
|
112
|
+
}
|
|
30
113
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
/// target.
|
|
48
|
-
async fn destroy(&self) -> Result<(), LixError> {
|
|
49
|
-
Err(LixError {
|
|
50
|
-
code: "LIX_ERROR_UNKNOWN".to_string(),
|
|
51
|
-
message: "destroy is not supported by this backend".to_string(),
|
|
52
|
-
hint: None,
|
|
53
|
-
details: None,
|
|
54
|
-
})
|
|
114
|
+
impl ProjectedValue {
|
|
115
|
+
pub fn as_ref(&self) -> ProjectedValueRef<'_> {
|
|
116
|
+
match self {
|
|
117
|
+
ProjectedValue::KeyOnly => ProjectedValueRef::KeyOnly,
|
|
118
|
+
ProjectedValue::FullValue(value) => ProjectedValueRef::FullValue(value.as_ref()),
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
impl<'a> KeyRef<'a> {
|
|
124
|
+
pub fn as_bytes(self) -> &'a [u8] {
|
|
125
|
+
self.0
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
pub fn to_owned_key(self) -> Key {
|
|
129
|
+
Key(Bytes::copy_from_slice(self.0))
|
|
55
130
|
}
|
|
56
131
|
}
|
|
57
132
|
|
|
58
|
-
|
|
59
|
-
pub
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
) -> Result<BackendKvValueBatch, LixError>;
|
|
133
|
+
impl Key {
|
|
134
|
+
pub fn as_ref(&self) -> KeyRef<'_> {
|
|
135
|
+
KeyRef(self.0.as_ref())
|
|
136
|
+
}
|
|
137
|
+
}
|
|
64
138
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
139
|
+
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
|
140
|
+
pub struct ReadOptions {
|
|
141
|
+
pub snapshot: Option<SnapshotRef>,
|
|
142
|
+
pub consistency: ReadConsistency,
|
|
143
|
+
}
|
|
69
144
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
145
|
+
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
|
146
|
+
pub enum ReadConsistency {
|
|
147
|
+
#[default]
|
|
148
|
+
Snapshot,
|
|
149
|
+
StaleOk,
|
|
150
|
+
Latest,
|
|
151
|
+
}
|
|
74
152
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
153
|
+
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
|
154
|
+
pub struct WriteOptions {
|
|
155
|
+
pub base_snapshot: Option<SnapshotRef>,
|
|
156
|
+
pub durability: Durability,
|
|
157
|
+
pub idempotency_key: Option<Bytes>,
|
|
158
|
+
}
|
|
79
159
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
request: BackendKvScanRequest,
|
|
83
|
-
) -> Result<BackendKvEntryPage, LixError>;
|
|
160
|
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
161
|
+
pub struct SnapshotRef(pub Bytes);
|
|
84
162
|
|
|
85
|
-
|
|
163
|
+
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
|
164
|
+
pub enum Durability {
|
|
165
|
+
#[default]
|
|
166
|
+
Durable,
|
|
86
167
|
}
|
|
87
168
|
|
|
88
|
-
#[
|
|
89
|
-
pub
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
169
|
+
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
|
170
|
+
pub struct WriteStats {
|
|
171
|
+
pub put_entries: u64,
|
|
172
|
+
pub deleted_entries: u64,
|
|
173
|
+
pub deleted_ranges: u64,
|
|
174
|
+
pub written_bytes: u64,
|
|
175
|
+
pub backend_calls: u64,
|
|
176
|
+
}
|
|
94
177
|
|
|
95
|
-
|
|
178
|
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
179
|
+
pub struct CommitResult {
|
|
180
|
+
pub commit_id: Option<Bytes>,
|
|
181
|
+
pub stats: WriteStats,
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
impl Prefix {
|
|
185
|
+
pub fn to_range(&self) -> Result<KeyRange, BackendError> {
|
|
186
|
+
let lower = Key(self.bytes.clone());
|
|
187
|
+
let mut upper = self.bytes.to_vec();
|
|
188
|
+
|
|
189
|
+
while let Some(last) = upper.last_mut() {
|
|
190
|
+
if *last == u8::MAX {
|
|
191
|
+
upper.pop();
|
|
192
|
+
} else {
|
|
193
|
+
*last += 1;
|
|
194
|
+
return Ok(KeyRange {
|
|
195
|
+
lower: Bound::Included(lower),
|
|
196
|
+
upper: Bound::Excluded(Key(Bytes::from(upper))),
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
Ok(KeyRange {
|
|
202
|
+
lower: Bound::Included(lower),
|
|
203
|
+
upper: Bound::Unbounded,
|
|
204
|
+
})
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
impl Default for GetOptions<'_> {
|
|
209
|
+
fn default() -> Self {
|
|
210
|
+
Self {
|
|
211
|
+
projection: CoreProjection::FullValue,
|
|
212
|
+
_reserved: std::marker::PhantomData,
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
impl GetManyResult {
|
|
218
|
+
pub fn new(values: Vec<Option<ProjectedValue>>) -> Self {
|
|
219
|
+
Self { values }
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
pub fn entries_for_requested_keys(&self, keys: &[Key]) -> Vec<ReadEntry> {
|
|
223
|
+
keys.iter()
|
|
224
|
+
.cloned()
|
|
225
|
+
.zip(self.values.iter().cloned())
|
|
226
|
+
.filter_map(|(key, value)| value.map(|value| ReadEntry { key, value }))
|
|
227
|
+
.collect()
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
impl Default for ScanOptions<'_> {
|
|
232
|
+
fn default() -> Self {
|
|
233
|
+
Self {
|
|
234
|
+
projection: CoreProjection::FullValue,
|
|
235
|
+
limit_rows: 1024,
|
|
236
|
+
resume_after: None,
|
|
237
|
+
}
|
|
238
|
+
}
|
|
96
239
|
}
|