@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
|
@@ -1,14 +1,52 @@
|
|
|
1
|
+
//! Primary storage adapter.
|
|
2
|
+
//!
|
|
3
|
+
//! This module is the Lix-neutral layer between domain stores and
|
|
4
|
+
//! `backend`. Domain stores own schemas and key layouts; storage owns
|
|
5
|
+
//! shared scopes, batching, lowering, cursors, and adapter stats.
|
|
6
|
+
//!
|
|
7
|
+
//! Storage is intentionally below the session transaction lifecycle. Direct
|
|
8
|
+
//! users of `StorageContext` or `StorageWriteSet` bypass session close/commit
|
|
9
|
+
//! accounting and must serialize durable writes themselves.
|
|
10
|
+
|
|
1
11
|
mod context;
|
|
12
|
+
mod point;
|
|
2
13
|
mod read_scope;
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
14
|
+
#[cfg(test)]
|
|
15
|
+
mod reader;
|
|
16
|
+
mod scan;
|
|
17
|
+
mod spaces;
|
|
18
|
+
mod stats;
|
|
19
|
+
mod write_set;
|
|
20
|
+
|
|
21
|
+
#[cfg(test)]
|
|
22
|
+
mod conformance;
|
|
23
|
+
|
|
24
|
+
pub trait StorageBackend: crate::backend::Backend {}
|
|
25
|
+
impl<T> StorageBackend for T where T: crate::backend::Backend {}
|
|
26
|
+
pub trait StorageBackendRead: crate::backend::BackendRead {}
|
|
27
|
+
impl<T> StorageBackendRead for T where T: crate::backend::BackendRead {}
|
|
28
|
+
pub type StorageBackendReadOf<'a, B> = <B as crate::backend::Backend>::Read<'a>;
|
|
29
|
+
|
|
30
|
+
pub use crate::backend::{
|
|
31
|
+
BackendError as StorageBackendError, CoreProjection as StorageCoreProjection,
|
|
32
|
+
DurableWriteGuard, DurableWriteLock, GetOptions as StorageGetOptions,
|
|
33
|
+
InMemoryBackend as InMemoryStorageBackend, InMemoryRead as InMemoryStorageRead,
|
|
34
|
+
InMemoryWrite as InMemoryStorageWrite, Key as StorageKey, KeyRange as StorageKeyRange,
|
|
35
|
+
Prefix as StoragePrefix, ProjectedValue as StorageProjectedValue,
|
|
36
|
+
ReadOptions as StorageReadOptions, ScanOptions as StorageScanOptions,
|
|
37
|
+
SpaceId as StorageSpaceId, StoredValue as StorageValue, WriteOptions as StorageWriteOptions,
|
|
11
38
|
};
|
|
12
39
|
|
|
13
|
-
|
|
14
|
-
pub
|
|
40
|
+
pub use context::StorageContext;
|
|
41
|
+
pub use point::{
|
|
42
|
+
PointReadBuffer, PointReadPlan, PointValues, PointValuesRef, RequestedToUnique,
|
|
43
|
+
RequestedToUniqueRef,
|
|
44
|
+
};
|
|
45
|
+
pub use read_scope::{StorageRead, StorageReadScope};
|
|
46
|
+
pub use scan::{ScanBuffer, ScanChunkRef, ScanCursor, ScanPlan};
|
|
47
|
+
pub(crate) use spaces::decode_logical_key_ref;
|
|
48
|
+
pub use spaces::StorageSpace;
|
|
49
|
+
pub use stats::{
|
|
50
|
+
StorageReadResult, StorageReadStats, StorageReadStatsCollector, StorageWriteSetStats,
|
|
51
|
+
};
|
|
52
|
+
pub use write_set::{StorageWriteSet, StorageWriteSetError};
|
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
|
|
3
|
+
use ahash::RandomState;
|
|
4
|
+
|
|
5
|
+
use crate::backend::{
|
|
6
|
+
BackendError, BackendRead, GetOptions, Key, PointVisitor, ProjectedValue, ProjectedValueRef,
|
|
7
|
+
};
|
|
8
|
+
use crate::storage::{StorageRead, StorageReadResult, StorageReadStats, StorageSpace};
|
|
9
|
+
|
|
10
|
+
type FastHashBuilder = RandomState;
|
|
11
|
+
|
|
12
|
+
#[derive(Clone, Debug)]
|
|
13
|
+
pub struct PointReadPlan {
|
|
14
|
+
pub logical_unique_keys: Vec<Key>,
|
|
15
|
+
pub physical_unique_keys: Vec<Key>,
|
|
16
|
+
pub requested_to_unique: RequestedToUnique,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
#[derive(Debug, PartialEq, Eq)]
|
|
20
|
+
pub struct PointValues<'plan> {
|
|
21
|
+
pub unique_values: Vec<Option<ProjectedValue>>,
|
|
22
|
+
pub requested_to_unique: RequestedToUniqueRef<'plan>,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
#[derive(Debug, Default)]
|
|
26
|
+
pub struct PointReadBuffer {
|
|
27
|
+
unique_values: Vec<Option<ProjectedValue>>,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#[derive(Debug, PartialEq, Eq)]
|
|
31
|
+
pub struct PointValuesRef<'plan, 'buf> {
|
|
32
|
+
pub unique_values: &'buf [Option<ProjectedValue>],
|
|
33
|
+
pub requested_to_unique: RequestedToUniqueRef<'plan>,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
37
|
+
pub enum RequestedToUnique {
|
|
38
|
+
Identity { len: usize },
|
|
39
|
+
Indexes(Vec<usize>),
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
43
|
+
pub enum RequestedToUniqueRef<'a> {
|
|
44
|
+
Identity { len: usize },
|
|
45
|
+
Indexes(&'a [usize]),
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
impl PointReadPlan {
|
|
49
|
+
pub fn new(space: StorageSpace, keys: &[Key]) -> Self {
|
|
50
|
+
let mut unique_index_by_key =
|
|
51
|
+
HashMap::<Key, usize, FastHashBuilder>::with_capacity_and_hasher(
|
|
52
|
+
keys.len(),
|
|
53
|
+
FastHashBuilder::with_seeds(0, 0, 0, 0),
|
|
54
|
+
);
|
|
55
|
+
let mut logical_unique_keys = Vec::with_capacity(keys.len());
|
|
56
|
+
let mut requested_to_unique = Vec::with_capacity(keys.len());
|
|
57
|
+
for key in keys {
|
|
58
|
+
if let Some(&unique_index) = unique_index_by_key.get(key) {
|
|
59
|
+
requested_to_unique.push(unique_index);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
let unique_index = logical_unique_keys.len();
|
|
64
|
+
unique_index_by_key.insert(key.clone(), unique_index);
|
|
65
|
+
logical_unique_keys.push(key.clone());
|
|
66
|
+
requested_to_unique.push(unique_index);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
Self::from_parts(
|
|
70
|
+
space,
|
|
71
|
+
logical_unique_keys,
|
|
72
|
+
requested_to_unique_mapping(requested_to_unique, keys.len()),
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
pub fn from_unique_keys(space: StorageSpace, unique_keys: Vec<Key>) -> Self {
|
|
77
|
+
debug_assert!(
|
|
78
|
+
keys_are_unique(&unique_keys),
|
|
79
|
+
"PointReadPlan::from_unique_keys requires unique keys"
|
|
80
|
+
);
|
|
81
|
+
let len = unique_keys.len();
|
|
82
|
+
Self::from_parts(space, unique_keys, RequestedToUnique::Identity { len })
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
pub fn len(&self) -> usize {
|
|
86
|
+
self.requested_to_unique.len()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
pub fn is_empty(&self) -> bool {
|
|
90
|
+
self.requested_to_unique.is_empty()
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
pub fn requested_to_unique(&self) -> RequestedToUniqueRef<'_> {
|
|
94
|
+
self.requested_to_unique.as_ref()
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
pub fn collect<R>(
|
|
98
|
+
&self,
|
|
99
|
+
read: &R,
|
|
100
|
+
opts: GetOptions<'_>,
|
|
101
|
+
) -> Result<StorageReadResult<PointValues<'_>>, BackendError>
|
|
102
|
+
where
|
|
103
|
+
R: StorageRead + ?Sized,
|
|
104
|
+
{
|
|
105
|
+
let unique_values =
|
|
106
|
+
collect_physical_unique_values(read.backend_read(), &self.physical_unique_keys, opts)?;
|
|
107
|
+
Ok(StorageReadResult::new(
|
|
108
|
+
PointValues {
|
|
109
|
+
unique_values,
|
|
110
|
+
requested_to_unique: self.requested_to_unique.as_ref(),
|
|
111
|
+
},
|
|
112
|
+
self.stats(),
|
|
113
|
+
))
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
pub fn materialize<R>(
|
|
117
|
+
&self,
|
|
118
|
+
read: &R,
|
|
119
|
+
opts: GetOptions<'_>,
|
|
120
|
+
) -> Result<StorageReadResult<Vec<Option<ProjectedValue>>>, BackendError>
|
|
121
|
+
where
|
|
122
|
+
R: StorageRead + ?Sized,
|
|
123
|
+
{
|
|
124
|
+
let result = self.collect(read, opts)?;
|
|
125
|
+
Ok(StorageReadResult::new(
|
|
126
|
+
result.value.materialize_caller_order(),
|
|
127
|
+
result.stats,
|
|
128
|
+
))
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
pub fn collect_into<'plan, 'buf, R>(
|
|
132
|
+
&'plan self,
|
|
133
|
+
read: &R,
|
|
134
|
+
opts: GetOptions<'_>,
|
|
135
|
+
buffer: &'buf mut PointReadBuffer,
|
|
136
|
+
) -> Result<StorageReadResult<PointValuesRef<'plan, 'buf>>, BackendError>
|
|
137
|
+
where
|
|
138
|
+
R: StorageRead + ?Sized,
|
|
139
|
+
{
|
|
140
|
+
collect_physical_unique_values_into(
|
|
141
|
+
read.backend_read(),
|
|
142
|
+
&self.physical_unique_keys,
|
|
143
|
+
opts,
|
|
144
|
+
buffer,
|
|
145
|
+
)?;
|
|
146
|
+
|
|
147
|
+
Ok(StorageReadResult::new(
|
|
148
|
+
PointValuesRef {
|
|
149
|
+
unique_values: buffer.unique_values.as_slice(),
|
|
150
|
+
requested_to_unique: self.requested_to_unique.as_ref(),
|
|
151
|
+
},
|
|
152
|
+
self.stats(),
|
|
153
|
+
))
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
pub fn visit<R, V>(
|
|
157
|
+
&self,
|
|
158
|
+
read: &R,
|
|
159
|
+
opts: GetOptions<'_>,
|
|
160
|
+
visitor: &mut V,
|
|
161
|
+
) -> Result<StorageReadStats, BackendError>
|
|
162
|
+
where
|
|
163
|
+
R: StorageRead + ?Sized,
|
|
164
|
+
V: PointVisitor + ?Sized,
|
|
165
|
+
{
|
|
166
|
+
struct LogicalPointVisitor<'a, V: ?Sized> {
|
|
167
|
+
logical_keys: &'a [Key],
|
|
168
|
+
inner: &'a mut V,
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
impl<V> PointVisitor for LogicalPointVisitor<'_, V>
|
|
172
|
+
where
|
|
173
|
+
V: PointVisitor + ?Sized,
|
|
174
|
+
{
|
|
175
|
+
fn visit(
|
|
176
|
+
&mut self,
|
|
177
|
+
index: usize,
|
|
178
|
+
_key: &Key,
|
|
179
|
+
value: Option<ProjectedValueRef<'_>>,
|
|
180
|
+
) -> Result<(), BackendError> {
|
|
181
|
+
let Some(logical_key) = self.logical_keys.get(index) else {
|
|
182
|
+
return Ok(());
|
|
183
|
+
};
|
|
184
|
+
self.inner.visit(index, logical_key, value)
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
read.backend_read().visit_keys(
|
|
189
|
+
&self.physical_unique_keys,
|
|
190
|
+
opts,
|
|
191
|
+
&mut LogicalPointVisitor {
|
|
192
|
+
logical_keys: &self.logical_unique_keys,
|
|
193
|
+
inner: visitor,
|
|
194
|
+
},
|
|
195
|
+
)?;
|
|
196
|
+
Ok(self.stats())
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
fn from_parts(
|
|
200
|
+
space: StorageSpace,
|
|
201
|
+
logical_unique_keys: Vec<Key>,
|
|
202
|
+
requested_to_unique: RequestedToUnique,
|
|
203
|
+
) -> Self {
|
|
204
|
+
let physical_unique_keys = logical_unique_keys
|
|
205
|
+
.iter()
|
|
206
|
+
.map(|key| space.encode_key(key))
|
|
207
|
+
.collect();
|
|
208
|
+
Self {
|
|
209
|
+
logical_unique_keys,
|
|
210
|
+
physical_unique_keys,
|
|
211
|
+
requested_to_unique,
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
fn stats(&self) -> StorageReadStats {
|
|
216
|
+
StorageReadStats {
|
|
217
|
+
requested_keys: self.requested_to_unique.len() as u64,
|
|
218
|
+
unique_backend_keys: self.logical_unique_keys.len() as u64,
|
|
219
|
+
backend_calls: 1,
|
|
220
|
+
prefix_lowered: 0,
|
|
221
|
+
..StorageReadStats::default()
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
impl RequestedToUnique {
|
|
227
|
+
pub fn len(&self) -> usize {
|
|
228
|
+
match self {
|
|
229
|
+
Self::Identity { len } => *len,
|
|
230
|
+
Self::Indexes(indexes) => indexes.len(),
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
pub fn is_empty(&self) -> bool {
|
|
235
|
+
self.len() == 0
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
pub fn unique_index(&self, requested_index: usize) -> Option<usize> {
|
|
239
|
+
match self {
|
|
240
|
+
Self::Identity { len } => (requested_index < *len).then_some(requested_index),
|
|
241
|
+
Self::Indexes(indexes) => indexes.get(requested_index).copied(),
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
pub fn as_ref(&self) -> RequestedToUniqueRef<'_> {
|
|
246
|
+
match self {
|
|
247
|
+
Self::Identity { len } => RequestedToUniqueRef::Identity { len: *len },
|
|
248
|
+
Self::Indexes(indexes) => RequestedToUniqueRef::Indexes(indexes),
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
pub fn to_vec(&self) -> Vec<usize> {
|
|
253
|
+
match self {
|
|
254
|
+
Self::Identity { len } => (0..*len).collect(),
|
|
255
|
+
Self::Indexes(indexes) => indexes.clone(),
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
impl<'a> RequestedToUniqueRef<'a> {
|
|
261
|
+
pub fn len(&self) -> usize {
|
|
262
|
+
match self {
|
|
263
|
+
Self::Identity { len } => *len,
|
|
264
|
+
Self::Indexes(indexes) => indexes.len(),
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
pub fn is_empty(&self) -> bool {
|
|
269
|
+
self.len() == 0
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
pub fn unique_index(&self, requested_index: usize) -> Option<usize> {
|
|
273
|
+
match self {
|
|
274
|
+
Self::Identity { len } => (requested_index < *len).then_some(requested_index),
|
|
275
|
+
Self::Indexes(indexes) => indexes.get(requested_index).copied(),
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
pub fn to_vec(self) -> Vec<usize> {
|
|
280
|
+
match self {
|
|
281
|
+
Self::Identity { len } => (0..len).collect(),
|
|
282
|
+
Self::Indexes(indexes) => indexes.to_vec(),
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
impl<'plan> PointValues<'plan> {
|
|
288
|
+
pub fn len(&self) -> usize {
|
|
289
|
+
self.requested_to_unique.len()
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
pub fn is_empty(&self) -> bool {
|
|
293
|
+
self.requested_to_unique.is_empty()
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
pub fn value_at(&self, requested_index: usize) -> Option<&ProjectedValue> {
|
|
297
|
+
let unique_index = self.requested_to_unique.unique_index(requested_index)?;
|
|
298
|
+
self.unique_values.get(unique_index)?.as_ref()
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
pub fn materialize_caller_order(self) -> Vec<Option<ProjectedValue>> {
|
|
302
|
+
materialize_caller_order(self.unique_values, self.requested_to_unique)
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
impl PointReadBuffer {
|
|
307
|
+
pub fn new() -> Self {
|
|
308
|
+
Self::default()
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
pub fn capacity(&self) -> usize {
|
|
312
|
+
self.unique_values.capacity()
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
pub fn clear(&mut self) {
|
|
316
|
+
self.unique_values.clear();
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
fn reset_for_len(&mut self, len: usize) {
|
|
320
|
+
self.unique_values.clear();
|
|
321
|
+
self.unique_values.resize_with(len, || None);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
impl<'plan, 'buf> PointValuesRef<'plan, 'buf> {
|
|
326
|
+
pub fn len(&self) -> usize {
|
|
327
|
+
self.requested_to_unique.len()
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
pub fn is_empty(&self) -> bool {
|
|
331
|
+
self.requested_to_unique.is_empty()
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
pub fn value_at(&self, requested_index: usize) -> Option<&ProjectedValue> {
|
|
335
|
+
let unique_index = self.requested_to_unique.unique_index(requested_index)?;
|
|
336
|
+
self.unique_values.get(unique_index)?.as_ref()
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
fn collect_physical_unique_values<R>(
|
|
341
|
+
read: &R,
|
|
342
|
+
physical_unique_keys: &[Key],
|
|
343
|
+
opts: GetOptions<'_>,
|
|
344
|
+
) -> Result<Vec<Option<ProjectedValue>>, BackendError>
|
|
345
|
+
where
|
|
346
|
+
R: BackendRead,
|
|
347
|
+
{
|
|
348
|
+
let mut values = vec![None; physical_unique_keys.len()];
|
|
349
|
+
collect_physical_unique_values_into_slice(
|
|
350
|
+
read,
|
|
351
|
+
physical_unique_keys,
|
|
352
|
+
opts,
|
|
353
|
+
values.as_mut_slice(),
|
|
354
|
+
)?;
|
|
355
|
+
Ok(values)
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
fn collect_physical_unique_values_into<R>(
|
|
359
|
+
read: &R,
|
|
360
|
+
physical_unique_keys: &[Key],
|
|
361
|
+
opts: GetOptions<'_>,
|
|
362
|
+
buffer: &mut PointReadBuffer,
|
|
363
|
+
) -> Result<(), BackendError>
|
|
364
|
+
where
|
|
365
|
+
R: BackendRead,
|
|
366
|
+
{
|
|
367
|
+
buffer.reset_for_len(physical_unique_keys.len());
|
|
368
|
+
collect_physical_unique_values_into_slice(
|
|
369
|
+
read,
|
|
370
|
+
physical_unique_keys,
|
|
371
|
+
opts,
|
|
372
|
+
buffer.unique_values.as_mut_slice(),
|
|
373
|
+
)
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
fn collect_physical_unique_values_into_slice<R>(
|
|
377
|
+
read: &R,
|
|
378
|
+
physical_unique_keys: &[Key],
|
|
379
|
+
opts: GetOptions<'_>,
|
|
380
|
+
values: &mut [Option<ProjectedValue>],
|
|
381
|
+
) -> Result<(), BackendError>
|
|
382
|
+
where
|
|
383
|
+
R: BackendRead,
|
|
384
|
+
{
|
|
385
|
+
struct Collector<'a> {
|
|
386
|
+
values: &'a mut [Option<ProjectedValue>],
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
impl PointVisitor for Collector<'_> {
|
|
390
|
+
fn visit(
|
|
391
|
+
&mut self,
|
|
392
|
+
index: usize,
|
|
393
|
+
_key: &Key,
|
|
394
|
+
value: Option<ProjectedValueRef<'_>>,
|
|
395
|
+
) -> Result<(), BackendError> {
|
|
396
|
+
if let Some(slot) = self.values.get_mut(index) {
|
|
397
|
+
*slot = value.map(|value| value.to_owned());
|
|
398
|
+
}
|
|
399
|
+
Ok(())
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
read.visit_keys(physical_unique_keys, opts, &mut Collector { values })
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
fn keys_are_unique(keys: &[Key]) -> bool {
|
|
407
|
+
let mut seen = HashMap::<&Key, (), FastHashBuilder>::with_capacity_and_hasher(
|
|
408
|
+
keys.len(),
|
|
409
|
+
FastHashBuilder::with_seeds(0, 0, 0, 0),
|
|
410
|
+
);
|
|
411
|
+
keys.iter().all(|key| seen.insert(key, ()).is_none())
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
fn requested_to_unique_mapping(indexes: Vec<usize>, requested_len: usize) -> RequestedToUnique {
|
|
415
|
+
if indexes.len() == requested_len
|
|
416
|
+
&& indexes
|
|
417
|
+
.iter()
|
|
418
|
+
.copied()
|
|
419
|
+
.enumerate()
|
|
420
|
+
.all(|(requested_index, unique_index)| requested_index == unique_index)
|
|
421
|
+
{
|
|
422
|
+
RequestedToUnique::Identity { len: requested_len }
|
|
423
|
+
} else {
|
|
424
|
+
RequestedToUnique::Indexes(indexes)
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
fn materialize_caller_order(
|
|
429
|
+
unique_values: Vec<Option<ProjectedValue>>,
|
|
430
|
+
requested_to_unique: RequestedToUniqueRef<'_>,
|
|
431
|
+
) -> Vec<Option<ProjectedValue>> {
|
|
432
|
+
let mut values = Vec::with_capacity(requested_to_unique.len());
|
|
433
|
+
for requested_index in 0..requested_to_unique.len() {
|
|
434
|
+
let unique_index = requested_to_unique
|
|
435
|
+
.unique_index(requested_index)
|
|
436
|
+
.expect("requested index is inside requested_to_unique");
|
|
437
|
+
values.push(unique_values[unique_index].clone());
|
|
438
|
+
}
|
|
439
|
+
values
|
|
440
|
+
}
|
|
@@ -1,88 +1,67 @@
|
|
|
1
|
-
use
|
|
1
|
+
use crate::backend::{BackendError, BackendRead};
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
StorageReadTransaction, StorageReader,
|
|
6
|
-
};
|
|
7
|
-
use crate::LixError;
|
|
8
|
-
use tokio::sync::Mutex;
|
|
3
|
+
pub trait StorageRead {
|
|
4
|
+
type BackendRead: BackendRead;
|
|
9
5
|
|
|
10
|
-
|
|
11
|
-
///
|
|
12
|
-
/// This lets multiple subsystem readers share the same transaction/backend view
|
|
13
|
-
/// even when the underlying handle itself is not cloneable.
|
|
14
|
-
pub(crate) struct StorageReadScope<S> {
|
|
15
|
-
store: Arc<Mutex<S>>,
|
|
6
|
+
fn backend_read(&self) -> &Self::BackendRead;
|
|
16
7
|
}
|
|
17
8
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
9
|
+
#[derive(Clone)]
|
|
10
|
+
pub struct StorageReadScope<R> {
|
|
11
|
+
read: R,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
impl<R> StorageReadScope<R> {
|
|
15
|
+
pub fn new(read: R) -> Self {
|
|
16
|
+
Self { read }
|
|
26
17
|
}
|
|
27
18
|
|
|
28
|
-
pub
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
19
|
+
pub fn store(&self) -> Self
|
|
20
|
+
where
|
|
21
|
+
R: Clone,
|
|
22
|
+
{
|
|
23
|
+
self.clone()
|
|
32
24
|
}
|
|
33
25
|
}
|
|
34
26
|
|
|
35
|
-
impl StorageReadScope<
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
)
|
|
42
|
-
})?;
|
|
43
|
-
store.into_inner().rollback().await
|
|
27
|
+
impl<R> StorageReadScope<R>
|
|
28
|
+
where
|
|
29
|
+
R: BackendRead,
|
|
30
|
+
{
|
|
31
|
+
pub fn close(self) -> Result<(), BackendError> {
|
|
32
|
+
self.read.close()
|
|
44
33
|
}
|
|
45
34
|
}
|
|
46
35
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
36
|
+
impl<R> StorageRead for StorageReadScope<R>
|
|
37
|
+
where
|
|
38
|
+
R: BackendRead,
|
|
39
|
+
{
|
|
40
|
+
type BackendRead = R;
|
|
50
41
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
Self {
|
|
54
|
-
store: Arc::clone(&self.store),
|
|
55
|
-
}
|
|
42
|
+
fn backend_read(&self) -> &Self::BackendRead {
|
|
43
|
+
&self.read
|
|
56
44
|
}
|
|
57
45
|
}
|
|
58
46
|
|
|
59
|
-
|
|
60
|
-
impl<S> StorageReader for ScopedStorageReader<S>
|
|
47
|
+
impl<T> StorageRead for &T
|
|
61
48
|
where
|
|
62
|
-
|
|
49
|
+
T: StorageRead + ?Sized,
|
|
63
50
|
{
|
|
64
|
-
|
|
65
|
-
let mut store = self.store.lock().await;
|
|
66
|
-
store.get_values(request).await
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
async fn exists_many(&mut self, request: KvGetRequest) -> Result<KvExistsBatch, LixError> {
|
|
70
|
-
let mut store = self.store.lock().await;
|
|
71
|
-
store.exists_many(request).await
|
|
72
|
-
}
|
|
51
|
+
type BackendRead = T::BackendRead;
|
|
73
52
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
store.scan_keys(request).await
|
|
53
|
+
fn backend_read(&self) -> &Self::BackendRead {
|
|
54
|
+
(*self).backend_read()
|
|
77
55
|
}
|
|
56
|
+
}
|
|
78
57
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
58
|
+
impl<T> StorageRead for &mut T
|
|
59
|
+
where
|
|
60
|
+
T: StorageRead + ?Sized,
|
|
61
|
+
{
|
|
62
|
+
type BackendRead = T::BackendRead;
|
|
83
63
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
store.scan_entries(request).await
|
|
64
|
+
fn backend_read(&self) -> &Self::BackendRead {
|
|
65
|
+
(**self).backend_read()
|
|
87
66
|
}
|
|
88
67
|
}
|