@quereus/plugin-leveldb 3.3.0 → 4.0.0

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 CHANGED
@@ -7,9 +7,34 @@ LevelDB storage plugin for Quereus. Provides persistent storage for Node.js envi
7
7
  - **Fast**: LevelDB offers excellent read/write performance for key-value workloads
8
8
  - **Transaction isolation**: Read-your-own-writes and snapshot isolation by default
9
9
  - **Sorted keys**: Efficient range queries with ordered iteration
10
- - **ACID batches**: Atomic writes across multiple keys
10
+ - **Crash-safe commits**: A whole transaction's data + secondary-index writes commit in one atomic, durable LevelDB batch (see [Storage layout](#storage-layout))
11
11
  - **Compression**: Built-in Snappy compression for reduced disk usage
12
12
 
13
+ ## Storage layout
14
+
15
+ All of a database's stores live inside **one physical LevelDB** at `basePath`,
16
+ each as a [sublevel](https://github.com/Level/abstract-level#sublevel) keyed by
17
+ its store name:
18
+
19
+ | Logical store | Sublevel name |
20
+ |---|---|
21
+ | Table data | `{schema}.{table}` |
22
+ | Secondary index | `{schema}.{table}_idx_{name}` |
23
+ | Unified stats | `__stats__` |
24
+ | Catalog (DDL) | `__catalog__` |
25
+
26
+ Because every sublevel shares one physical store, a single chained batch commits
27
+ across all of a table's sublevels (data + every secondary index) **atomically and
28
+ durably** — closing the crash window where a per-store commit loop could leave a
29
+ table's rows and its indexes divergent on disk. By default each commit is
30
+ `fsync`'d so it survives power loss; see [`syncCommits`](#plugin-settings).
31
+
32
+ > **Hard cutover (no on-disk migration).** This shared-root layout is the only
33
+ > LevelDB layout. Databases written by the older per-directory layout
34
+ > (`{basePath}/{schema}/{table}`, a separate LevelDB per table) are **not** read
35
+ > by this version and must be re-created. Pre-1.0 dev data is expected to be
36
+ > thrown away; there is no migration importer.
37
+
13
38
  ## Installation
14
39
 
15
40
  ```bash
@@ -74,7 +99,10 @@ await db.exec(`
74
99
 
75
100
  ### LevelDBStore
76
101
 
77
- Low-level KVStore implementation:
102
+ Low-level KVStore implementation. `LevelDBStore.open()` opens a **standalone**
103
+ single physical LevelDB database — useful for one-off key-value stores (e.g. sync
104
+ metadata). The multi-table StoreModule backend does not use this directly; it
105
+ opens one shared root and hands out sublevel-backed stores via `LevelDBProvider`.
78
106
 
79
107
  ```typescript
80
108
  import { LevelDBStore } from '@quereus/plugin-leveldb';
@@ -109,11 +137,12 @@ import { createLevelDBProvider } from '@quereus/plugin-leveldb';
109
137
 
110
138
  const provider = createLevelDBProvider({ basePath: './data' });
111
139
 
112
- const userStore = await provider.getStore('main', 'users'); // ./data/main/users
113
- const catalogStore = await provider.getCatalogStore(); // ./data/__catalog__
140
+ // All stores are sublevels of the single LevelDB at ./data
141
+ const userStore = await provider.getStore('main', 'users'); // sublevel main.users
142
+ const catalogStore = await provider.getCatalogStore(); // sublevel __catalog__
114
143
 
115
- await provider.closeStore('main', 'users');
116
- await provider.closeAll();
144
+ await provider.closeStore('main', 'users'); // drops the sublevel handle
145
+ await provider.closeAll(); // closes the shared root
117
146
  ```
118
147
 
119
148
  ## Configuration
@@ -122,11 +151,13 @@ await provider.closeAll();
122
151
 
123
152
  | Setting | Type | Default | Description |
124
153
  |---------|------|---------|-------------|
125
- | `basePath` | string | `'./data'` | Base directory for all stores |
126
- | `createIfMissing` | boolean | `true` | Create directories if they don't exist |
154
+ | `basePath` | string | `'./data'` | Directory of the single shared LevelDB database |
155
+ | `createIfMissing` | boolean | `true` | Create the database if it doesn't exist |
156
+ | `syncCommits` | boolean | `true` | `fsync` each transaction commit so it survives power loss (slower commits when on) |
127
157
  | `moduleName` | string | `'store'` | Name to register the virtual table module under |
158
+ | `isolation` | boolean | `true` | Wrap with the isolation layer (read-your-own-writes, snapshot isolation) |
128
159
 
129
- ### LevelDBStore Options
160
+ ### LevelDBStore Options (standalone `open`)
130
161
 
131
162
  | Option | Type | Default | Description |
132
163
  |--------|------|---------|-------------|
@@ -10,16 +10,23 @@ import { StoreModule } from '@quereus/store';
10
10
  */
11
11
  export interface LevelDBPluginConfig {
12
12
  /**
13
- * Base path for all LevelDB stores.
14
- * Each table gets a subdirectory under this path.
13
+ * Base path for the single shared LevelDB database. Every table, index, the
14
+ * catalog, and stats live as sublevels inside this one physical store.
15
15
  * @default './data'
16
16
  */
17
17
  basePath?: string;
18
18
  /**
19
- * Create directories if they don't exist.
19
+ * Create the database if it doesn't exist.
20
20
  * @default true
21
21
  */
22
22
  createIfMissing?: boolean;
23
+ /**
24
+ * fsync each transaction commit before resolving, so a committed transaction
25
+ * survives power loss. The cost is one fsync per commit; set false to trade
26
+ * durability for lower commit latency.
27
+ * @default true
28
+ */
29
+ syncCommits?: boolean;
23
30
  /**
24
31
  * Module name to register. Tables are created with `USING <moduleName>`.
25
32
  * @default 'store'
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAA6B,MAAM,gBAAgB,CAAC;AAGxE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,QAAQ,CAC/B,GAAG,EAAE,QAAQ,EACb,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAM;;;;;EAwBrC"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAA6B,MAAM,gBAAgB,CAAC;AAGxE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,QAAQ,CAC/B,GAAG,EAAE,QAAQ,EACb,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAM;;;;;EA0BrC"}
@@ -13,9 +13,11 @@ export default function register(_db, config = {}) {
13
13
  const createIfMissing = config.createIfMissing !== false;
14
14
  const moduleName = config.moduleName ?? 'store';
15
15
  const isolation = config.isolation ?? true;
16
+ const syncCommits = config.syncCommits !== false;
16
17
  const provider = new LevelDBProvider({
17
18
  basePath,
18
19
  createIfMissing,
20
+ syncCommits,
19
21
  });
20
22
  const storeModule = isolation
21
23
  ? createIsolatedStoreModule({ provider })
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,WAAW,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAiChD;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,QAAQ,CAC/B,GAAa,EACb,SAAmC,EAAE;IAErC,MAAM,QAAQ,GAAI,MAAM,CAAC,QAAmB,IAAI,QAAQ,CAAC;IACzD,MAAM,eAAe,GAAG,MAAM,CAAC,eAAe,KAAK,KAAK,CAAC;IACzD,MAAM,UAAU,GAAI,MAAM,CAAC,UAAqB,IAAI,OAAO,CAAC;IAC5D,MAAM,SAAS,GAAI,MAAM,CAAC,SAAqB,IAAI,IAAI,CAAC;IAExD,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC;QACpC,QAAQ;QACR,eAAe;KACf,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,SAAS;QAC5B,CAAC,CAAC,yBAAyB,CAAC,EAAE,QAAQ,EAAE,CAAC;QACzC,CAAC,CAAC,IAAI,WAAW,CAAC,QAAQ,CAAC,CAAC;IAE7B,OAAO;QACN,OAAO,EAAE;YACR;gBACC,IAAI,EAAE,UAAU;gBAChB,MAAM,EAAE,WAAW;aACnB;SACD;KACD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,WAAW,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAyChD;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,QAAQ,CAC/B,GAAa,EACb,SAAmC,EAAE;IAErC,MAAM,QAAQ,GAAI,MAAM,CAAC,QAAmB,IAAI,QAAQ,CAAC;IACzD,MAAM,eAAe,GAAG,MAAM,CAAC,eAAe,KAAK,KAAK,CAAC;IACzD,MAAM,UAAU,GAAI,MAAM,CAAC,UAAqB,IAAI,OAAO,CAAC;IAC5D,MAAM,SAAS,GAAI,MAAM,CAAC,SAAqB,IAAI,IAAI,CAAC;IACxD,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,KAAK,KAAK,CAAC;IAEjD,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC;QACpC,QAAQ;QACR,eAAe;QACf,WAAW;KACX,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,SAAS;QAC5B,CAAC,CAAC,yBAAyB,CAAC,EAAE,QAAQ,EAAE,CAAC;QACzC,CAAC,CAAC,IAAI,WAAW,CAAC,QAAQ,CAAC,CAAC;IAE7B,OAAO;QACN,OAAO,EAAE;YACR;gBACC,IAAI,EAAE,UAAU;gBAChB,MAAM,EAAE,WAAW;aACnB;SACD;KACD,CAAC;AACH,CAAC"}
@@ -1,45 +1,73 @@
1
1
  /**
2
- * LevelDB KVStore provider implementation.
2
+ * LevelDB KVStoreProvider — shared-root layout.
3
3
  *
4
- * Manages LevelDB stores for the StoreModule.
4
+ * All of a database's stores live inside ONE physical LevelDB at `basePath`, each
5
+ * as a sublevel keyed by its store name:
5
6
  *
6
- * Storage naming convention:
7
- * {basePath}/{schema}/{table} - Data store (row data)
8
- * {basePath}/{schema}/{table}_idx_{name} - Index store (secondary indexes)
9
- * {basePath}/__stats__ - Unified stats store (row counts for all tables)
10
- * {basePath}/__catalog__ - Catalog store (DDL metadata)
7
+ * {schema}.{table} - table data (buildDataStoreName)
8
+ * {schema}.{table}_idx_{name} - secondary index (buildIndexStoreName)
9
+ * __stats__ - unified stats (STATS_STORE_NAME)
10
+ * __catalog__ - catalog / DDL (CATALOG_STORE_NAME)
11
+ *
12
+ * Because every sublevel shares one physical store, a single chained batch
13
+ * (`root.batch()…write()`) commits across sublevels atomically and durably — see
14
+ * {@link LevelDBProvider.beginAtomicBatch}. This is the crash-safe single commit
15
+ * that the prior per-directory layout (a separate ClassicLevel per table) could
16
+ * not provide: separate physical databases cannot share a write batch.
17
+ *
18
+ * HARD CUTOVER: this is the only LevelDB layout. Databases written by the prior
19
+ * per-directory layout (`{basePath}/{schema}/{table}`) are NOT read here and must
20
+ * be re-created (pre-1.0 dev data). There is no on-disk migration. See README.
11
21
  */
12
- import type { KVStore, KVStoreProvider } from '@quereus/store';
22
+ import type { AtomicBatch, KVStore, KVStoreProvider } from '@quereus/store';
13
23
  /**
14
24
  * Options for creating a LevelDB provider.
15
25
  */
16
26
  export interface LevelDBProviderOptions {
17
27
  /**
18
- * Base path for all LevelDB stores.
19
- * Each table gets a subdirectory under this path.
28
+ * Base path for the single shared LevelDB database. Every table, index, the
29
+ * catalog, and stats live as sublevels inside this one physical store.
20
30
  */
21
31
  basePath: string;
22
32
  /**
23
- * Create directories if they don't exist.
33
+ * Create the database if it doesn't exist.
24
34
  * @default true
25
35
  */
26
36
  createIfMissing?: boolean;
37
+ /**
38
+ * fsync each atomic transaction commit (the chained batch issued by
39
+ * {@link LevelDBProvider.beginAtomicBatch}) before resolving. Default true —
40
+ * a committed transaction then survives power loss, which is the crash-safe
41
+ * guarantee this layout exists to provide. The cost is one fsync per commit;
42
+ * set false to trade durability for lower commit latency.
43
+ * @default true
44
+ */
45
+ syncCommits?: boolean;
27
46
  }
28
47
  /**
29
- * LevelDB implementation of KVStoreProvider.
30
- *
31
- * Creates separate LevelDB databases for each table, stored
32
- * in subdirectories under the configured base path.
48
+ * LevelDB implementation of KVStoreProvider over a single shared root with one
49
+ * sublevel per logical store.
33
50
  */
34
51
  export declare class LevelDBProvider implements KVStoreProvider {
35
52
  private basePath;
36
53
  private createIfMissing;
54
+ private syncCommits;
55
+ /** The shared physical root, once opened. */
56
+ private root;
57
+ /** Memoized in-flight root open so concurrent first-opens share one handle. */
58
+ private rootOpening;
59
+ /** Cached store handles, keyed by store (sublevel) name. */
37
60
  private stores;
38
- private storePaths;
39
- private catalogStore;
40
- private statsStore;
61
+ /** In-flight sublevel opens, keyed by store name, so concurrent callers dedupe. */
62
+ private storeOpening;
63
+ /**
64
+ * Sublevel + ownership proof for every store this provider produced. Used by the
65
+ * atomic batch to map a {@link KVStore} handle back to its sublevel and to reject
66
+ * a foreign handle (a non-LevelDB store, or one from another provider, is absent).
67
+ */
68
+ private sublevelByStore;
41
69
  constructor(options: LevelDBProviderOptions);
42
- getStore(schemaName: string, tableName: string, options?: Record<string, unknown>): Promise<KVStore>;
70
+ getStore(schemaName: string, tableName: string, _options?: Record<string, unknown>): Promise<KVStore>;
43
71
  getIndexStore(schemaName: string, tableName: string, indexName: string): Promise<KVStore>;
44
72
  getStatsStore(_schemaName: string, _tableName: string): Promise<KVStore>;
45
73
  getCatalogStore(): Promise<KVStore>;
@@ -47,10 +75,38 @@ export declare class LevelDBProvider implements KVStoreProvider {
47
75
  closeIndexStore(schemaName: string, tableName: string, indexName: string): Promise<void>;
48
76
  closeAll(): Promise<void>;
49
77
  deleteIndexStore(schemaName: string, tableName: string, indexName: string): Promise<void>;
50
- renameTableStores(schemaName: string, oldName: string, newName: string): Promise<void>;
51
- deleteTableStores(schemaName: string, tableName: string): Promise<void>;
78
+ renameTableStores(schemaName: string, oldName: string, newName: string, indexNames: readonly string[]): Promise<void>;
79
+ deleteTableStores(schemaName: string, tableName: string, indexNames: readonly string[]): Promise<void>;
80
+ /**
81
+ * Open an atomic batch across this provider's sublevels, or undefined when the
82
+ * shared root has not been opened yet (no stores exist → nothing to commit).
83
+ *
84
+ * All sublevels share one physical LevelDB, so a single chained batch
85
+ * (`root.batch()…write()`) with each op targeting its sublevel commits them
86
+ * atomically and durably. The transaction coordinator uses this to commit a
87
+ * table's data + secondary-index stores in one physical batch, closing the
88
+ * crash window where a per-store loop could leave them divergent.
89
+ *
90
+ * In practice the coordinator only calls this once it has pending ops — which
91
+ * means stores (hence the root) were already opened — so the undefined branch
92
+ * is defensive (the coordinator falls back to per-store `batch()`).
93
+ */
94
+ beginAtomicBatch(): AtomicBatch | undefined;
95
+ /**
96
+ * Map a {@link KVStore} handle this provider handed out back to its sublevel.
97
+ * A handle not produced by this provider (wrong type, or from another provider)
98
+ * is absent from the ownership map — a programming error.
99
+ */
100
+ private resolveSublevel;
101
+ /** Open (memoized) the shared physical root database. */
102
+ private getRoot;
103
+ /** Create a sublevel handle over the shared root, with the store's byte encodings. */
104
+ private openSublevel;
52
105
  private getOrCreateStore;
106
+ private openSublevelStore;
53
107
  private closeStoreByName;
108
+ /** Clear a store's keyspace (sublevel.clear) and drop its cached handle. */
109
+ private clearAndDropStore;
54
110
  }
55
111
  /**
56
112
  * Create a LevelDB provider with the given options.
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAI/D;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACtC;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;GAKG;AACH,qBAAa,eAAgB,YAAW,eAAe;IACtD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,eAAe,CAAU;IACjC,OAAO,CAAC,MAAM,CAAmC;IACjD,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,UAAU,CAA6B;gBAEnC,OAAO,EAAE,sBAAsB;IAKrC,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;IAMpG,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAMzF,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAYxE,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAWnC,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKhE,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKxF,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBzB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQzF,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoDtF,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAuC/D,gBAAgB;YAehB,gBAAgB;CAU9B;AAeD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB,GAAG,eAAe,CAEtF"}
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAuC5E;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACtC;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;GAGG;AACH,qBAAa,eAAgB,YAAW,eAAe;IACtD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,eAAe,CAAU;IACjC,OAAO,CAAC,WAAW,CAAU;IAE7B,6CAA6C;IAC7C,OAAO,CAAC,IAAI,CAA0B;IACtC,+EAA+E;IAC/E,OAAO,CAAC,WAAW,CAAmC;IAEtD,4DAA4D;IAC5D,OAAO,CAAC,MAAM,CAAmC;IACjD,mFAAmF;IACnF,OAAO,CAAC,YAAY,CAA4C;IAChE;;;;OAIG;IACH,OAAO,CAAC,eAAe,CAAoC;gBAE/C,OAAO,EAAE,sBAAsB;IAMrC,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;IAOrG,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIzF,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKxE,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAInC,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhE,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxF,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAwBzB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzF,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IA0ErH,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB5G;;;;;;;;;;;;;OAaG;IACH,gBAAgB,IAAI,WAAW,GAAG,SAAS;IAM3C;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAWvB,yDAAyD;YAC3C,OAAO;IAoBrB,sFAAsF;IACtF,OAAO,CAAC,YAAY;YAON,gBAAgB;YA2BhB,iBAAiB;YASjB,gBAAgB;IAU9B,4EAA4E;YAC9D,iBAAiB;CAK/B;AAqDD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB,GAAG,eAAe,CAEtF"}
@@ -1,213 +1,363 @@
1
1
  /**
2
- * LevelDB KVStore provider implementation.
2
+ * LevelDB KVStoreProvider — shared-root layout.
3
3
  *
4
- * Manages LevelDB stores for the StoreModule.
4
+ * All of a database's stores live inside ONE physical LevelDB at `basePath`, each
5
+ * as a sublevel keyed by its store name:
5
6
  *
6
- * Storage naming convention:
7
- * {basePath}/{schema}/{table} - Data store (row data)
8
- * {basePath}/{schema}/{table}_idx_{name} - Index store (secondary indexes)
9
- * {basePath}/__stats__ - Unified stats store (row counts for all tables)
10
- * {basePath}/__catalog__ - Catalog store (DDL metadata)
7
+ * {schema}.{table} - table data (buildDataStoreName)
8
+ * {schema}.{table}_idx_{name} - secondary index (buildIndexStoreName)
9
+ * __stats__ - unified stats (STATS_STORE_NAME)
10
+ * __catalog__ - catalog / DDL (CATALOG_STORE_NAME)
11
+ *
12
+ * Because every sublevel shares one physical store, a single chained batch
13
+ * (`root.batch()…write()`) commits across sublevels atomically and durably — see
14
+ * {@link LevelDBProvider.beginAtomicBatch}. This is the crash-safe single commit
15
+ * that the prior per-directory layout (a separate ClassicLevel per table) could
16
+ * not provide: separate physical databases cannot share a write batch.
17
+ *
18
+ * HARD CUTOVER: this is the only LevelDB layout. Databases written by the prior
19
+ * per-directory layout (`{basePath}/{schema}/{table}`) are NOT read here and must
20
+ * be re-created (pre-1.0 dev data). There is no on-disk migration. See README.
11
21
  */
12
- import path from 'node:path';
13
- import fs from 'node:fs';
14
- import { STORE_SUFFIX, CATALOG_STORE_NAME, STATS_STORE_NAME } from '@quereus/store';
22
+ import { ClassicLevel } from 'classic-level';
23
+ import { buildDataStoreName, buildIndexStoreName, CATALOG_STORE_NAME, STATS_STORE_NAME } from '@quereus/store';
24
+ import { QuereusError, StatusCode } from '@quereus/quereus';
15
25
  import { LevelDBStore } from './store.js';
26
+ const textEncoder = new TextEncoder();
16
27
  /**
17
- * LevelDB implementation of KVStoreProvider.
28
+ * Encode a logical store name into a sublevel-safe name.
18
29
  *
19
- * Creates separate LevelDB databases for each table, stored
20
- * in subdirectories under the configured base path.
30
+ * abstract-level requires every byte of a sublevel name to be in `(separator, 127)`
31
+ * — with the default `!` separator that is 35..126. Logical store names are
32
+ * `{schema}.{table}` identifiers that may contain spaces, punctuation, or non-ASCII
33
+ * (e.g. a quoted table name `"Table With Spaces"`), so any byte outside the safe set
34
+ * is percent-encoded. The mapping is deterministic and injective (distinct logical
35
+ * names → distinct sublevel names), which is all the provider's name-keyed caching
36
+ * and the StoreModule's collision checks require; the sublevel name is never decoded
37
+ * back. Common names (lowercase identifiers, `.`, `_`) pass through unchanged.
38
+ */
39
+ function encodeSublevelName(name) {
40
+ let out = '';
41
+ for (const b of textEncoder.encode(name)) {
42
+ // Safe: printable ASCII in (34, 127) except '%' (0x25), which is reserved as
43
+ // the escape introducer so the encoding stays injective.
44
+ if (b > 34 && b < 127 && b !== 0x25) {
45
+ out += String.fromCharCode(b);
46
+ }
47
+ else {
48
+ out += '%' + b.toString(16).toUpperCase().padStart(2, '0');
49
+ }
50
+ }
51
+ return out;
52
+ }
53
+ /**
54
+ * LevelDB implementation of KVStoreProvider over a single shared root with one
55
+ * sublevel per logical store.
21
56
  */
22
57
  export class LevelDBProvider {
23
58
  basePath;
24
59
  createIfMissing;
60
+ syncCommits;
61
+ /** The shared physical root, once opened. */
62
+ root = null;
63
+ /** Memoized in-flight root open so concurrent first-opens share one handle. */
64
+ rootOpening = null;
65
+ /** Cached store handles, keyed by store (sublevel) name. */
25
66
  stores = new Map();
26
- storePaths = new Map();
27
- catalogStore = null;
28
- statsStore = null;
67
+ /** In-flight sublevel opens, keyed by store name, so concurrent callers dedupe. */
68
+ storeOpening = new Map();
69
+ /**
70
+ * Sublevel + ownership proof for every store this provider produced. Used by the
71
+ * atomic batch to map a {@link KVStore} handle back to its sublevel and to reject
72
+ * a foreign handle (a non-LevelDB store, or one from another provider, is absent).
73
+ */
74
+ sublevelByStore = new WeakMap();
29
75
  constructor(options) {
30
76
  this.basePath = options.basePath;
31
77
  this.createIfMissing = options.createIfMissing ?? true;
78
+ this.syncCommits = options.syncCommits ?? true;
32
79
  }
33
- async getStore(schemaName, tableName, options) {
34
- const storeName = `${schemaName}.${tableName}`.toLowerCase();
35
- const storePath = options?.path || path.join(this.basePath, schemaName, tableName);
36
- return this.getOrCreateStore(storeName, storePath);
80
+ async getStore(schemaName, tableName, _options) {
81
+ // NOTE: the prior per-directory layout honored an `options.path` override to
82
+ // place a table's database elsewhere. With one shared root there is no
83
+ // per-table path, so the override is gone (the engine never passed it).
84
+ return this.getOrCreateStore(buildDataStoreName(schemaName, tableName));
37
85
  }
38
86
  async getIndexStore(schemaName, tableName, indexName) {
39
- const storeName = `${schemaName}.${tableName}${STORE_SUFFIX.INDEX}${indexName}`.toLowerCase();
40
- const storePath = path.join(this.basePath, schemaName, `${tableName}${STORE_SUFFIX.INDEX}${indexName}`);
41
- return this.getOrCreateStore(storeName, storePath);
87
+ return this.getOrCreateStore(buildIndexStoreName(schemaName, tableName, indexName));
42
88
  }
43
89
  async getStatsStore(_schemaName, _tableName) {
44
- // Use the unified __stats__ store for all tables
45
- if (!this.statsStore) {
46
- const statsPath = path.join(this.basePath, STATS_STORE_NAME);
47
- this.statsStore = await LevelDBStore.open({
48
- path: statsPath,
49
- createIfMissing: this.createIfMissing,
50
- });
51
- }
52
- return this.statsStore;
90
+ // Unified __stats__ store for all tables.
91
+ return this.getOrCreateStore(STATS_STORE_NAME);
53
92
  }
54
93
  async getCatalogStore() {
55
- if (!this.catalogStore) {
56
- const catalogPath = path.join(this.basePath, CATALOG_STORE_NAME);
57
- this.catalogStore = await LevelDBStore.open({
58
- path: catalogPath,
59
- createIfMissing: this.createIfMissing,
60
- });
61
- }
62
- return this.catalogStore;
94
+ return this.getOrCreateStore(CATALOG_STORE_NAME);
63
95
  }
64
96
  async closeStore(schemaName, tableName) {
65
- const storeName = `${schemaName}.${tableName}`.toLowerCase();
66
- await this.closeStoreByName(storeName);
97
+ await this.closeStoreByName(buildDataStoreName(schemaName, tableName));
67
98
  }
68
99
  async closeIndexStore(schemaName, tableName, indexName) {
69
- const storeName = `${schemaName}.${tableName}${STORE_SUFFIX.INDEX}${indexName}`.toLowerCase();
70
- await this.closeStoreByName(storeName);
100
+ await this.closeStoreByName(buildIndexStoreName(schemaName, tableName, indexName));
71
101
  }
72
102
  async closeAll() {
103
+ // Await any in-flight opens (stores + root) first so we don't strand a
104
+ // freshly-opened sublevel/root after clearing the caches and closing the root.
105
+ await Promise.allSettled([
106
+ ...this.storeOpening.values(),
107
+ this.rootOpening,
108
+ ].filter(Boolean));
109
+ // Close each cached sublevel handle, then close the root. Closing the root
110
+ // would itself cascade to attached sublevels, but closing handles first
111
+ // marks our store wrappers closed and keeps the close ordering explicit.
73
112
  for (const store of this.stores.values()) {
74
113
  await store.close();
75
114
  }
76
115
  this.stores.clear();
77
- if (this.catalogStore) {
78
- await this.catalogStore.close();
79
- this.catalogStore = null;
80
- }
81
- if (this.statsStore) {
82
- await this.statsStore.close();
83
- this.statsStore = null;
116
+ this.storeOpening.clear();
117
+ if (this.root) {
118
+ await this.root.close();
119
+ this.root = null;
84
120
  }
121
+ this.rootOpening = null;
85
122
  }
86
123
  async deleteIndexStore(schemaName, tableName, indexName) {
87
- const storeName = `${schemaName}.${tableName}${STORE_SUFFIX.INDEX}${indexName}`.toLowerCase();
88
- const storePath = this.storePaths.get(storeName)
89
- ?? path.join(this.basePath, schemaName, `${tableName}${STORE_SUFFIX.INDEX}${indexName}`);
90
- await this.closeStoreByName(storeName);
91
- await removeDir(storePath);
124
+ await this.clearAndDropStore(buildIndexStoreName(schemaName, tableName, indexName));
92
125
  }
93
- async renameTableStores(schemaName, oldName, newName) {
94
- const oldDataStoreName = `${schemaName}.${oldName}`.toLowerCase();
95
- const newDataStoreName = `${schemaName}.${newName}`.toLowerCase();
126
+ async renameTableStores(schemaName, oldName, newName, indexNames) {
127
+ const root = await this.getRoot();
128
+ const oldDataStoreName = buildDataStoreName(schemaName, oldName);
129
+ const newDataStoreName = buildDataStoreName(schemaName, newName);
96
130
  if (this.stores.has(newDataStoreName)) {
97
131
  throw new Error(`Cannot rename '${oldName}' to '${newName}': store already open under the new name`);
98
132
  }
99
- // Close all open handles for the old table (data + indexes) so LevelDB
100
- // releases its file locks before we move the directories.
101
- await this.closeStoreByName(oldDataStoreName);
102
- const oldIndexPrefix = `${schemaName}.${oldName}${STORE_SUFFIX.INDEX}`.toLowerCase();
103
- const indexStoreNames = [];
104
- for (const name of this.stores.keys()) {
105
- if (name.startsWith(oldIndexPrefix))
106
- indexStoreNames.push(name);
107
- }
108
- for (const name of indexStoreNames) {
109
- await this.closeStoreByName(name);
110
- }
111
- // Move data directory, if present.
112
- const schemaDir = path.join(this.basePath, schemaName);
113
- const oldDataPath = path.join(schemaDir, oldName);
114
- const newDataPath = path.join(schemaDir, newName);
115
- if (await pathExists(oldDataPath)) {
116
- if (await pathExists(newDataPath)) {
117
- throw new Error(`Cannot rename '${oldName}' to '${newName}': destination path '${newDataPath}' already exists`);
118
- }
119
- await fs.promises.rename(oldDataPath, newDataPath);
133
+ // (old → new) store-name pairs: data store + each schema index, built
134
+ // exact-by-name via buildIndexStoreName — never a `${oldName}_idx_` prefix
135
+ // scan, which would also match a sibling table literally named
136
+ // `${oldName}_idx_<x>` (its data store) and relocate its keys.
137
+ const pairs = [
138
+ { old: oldDataStoreName, new: newDataStoreName },
139
+ ];
140
+ for (const indexName of indexNames) {
141
+ pairs.push({
142
+ old: buildIndexStoreName(schemaName, oldName, indexName),
143
+ new: buildIndexStoreName(schemaName, newName, indexName),
144
+ });
120
145
  }
121
- // Move each index directory under the new table name.
122
- const oldIndexDirPrefix = `${oldName}${STORE_SUFFIX.INDEX}`;
146
+ // Open destination sublevels and assert each is empty BEFORE moving anything.
147
+ // A non-empty (or already-open) destination is a silent clobber/merge — this
148
+ // is the backstop equivalent of the prior fs "destination already exists"
149
+ // guard (e.g. an index relocating onto a sibling table's data store).
150
+ const destSublevels = new Map();
123
151
  try {
124
- const entries = await fs.promises.readdir(schemaDir);
125
- for (const entry of entries) {
126
- if (!entry.startsWith(oldIndexDirPrefix))
127
- continue;
128
- const indexSuffix = entry.substring(oldIndexDirPrefix.length);
129
- const renamed = `${newName}${STORE_SUFFIX.INDEX}${indexSuffix}`;
130
- await fs.promises.rename(path.join(schemaDir, entry), path.join(schemaDir, renamed));
152
+ for (const pair of pairs) {
153
+ if (this.stores.has(pair.new)) {
154
+ throw new Error(`Cannot rename '${oldName}' to '${newName}': destination store '${pair.new}' already open`);
155
+ }
156
+ const dest = this.openSublevel(root, pair.new);
157
+ await dest.open();
158
+ if (await sublevelHasAnyKey(dest)) {
159
+ throw new Error(`Cannot rename '${oldName}' to '${newName}': destination store '${pair.new}' already exists`);
160
+ }
161
+ destSublevels.set(pair.new, dest);
162
+ }
163
+ // Relocate every pair's keys in ONE chained batch over the shared root:
164
+ // put → new sublevel, del → old sublevel. A single write() is atomic and
165
+ // durable, so the rename is all-or-nothing across data + every index.
166
+ const batch = root.batch();
167
+ for (const pair of pairs) {
168
+ const oldStore = await this.getOrCreateStore(pair.old);
169
+ const oldSublevel = this.sublevelByStore.get(oldStore);
170
+ const dest = destSublevels.get(pair.new);
171
+ for await (const { key, value } of oldStore.iterate()) {
172
+ batch.put(key, value, { sublevel: dest });
173
+ batch.del(key, { sublevel: oldSublevel });
174
+ }
175
+ }
176
+ if (batch.length > 0) {
177
+ await batch.write({ sync: this.syncCommits });
178
+ }
179
+ else {
180
+ await batch.close();
181
+ }
182
+ // Drop old handles so subsequent getStore/getIndexStore open fresh
183
+ // sublevels under the new name (the old keyspaces are now empty).
184
+ for (const pair of pairs) {
185
+ await this.closeStoreByName(pair.old);
131
186
  }
132
187
  }
133
- catch (e) {
134
- // readdir can fail if the schema directory doesn't exist (pre-creation);
135
- // that just means there's nothing to move.
136
- if (e.code !== 'ENOENT')
137
- throw e;
188
+ finally {
189
+ // Close the temporary destination handles; the next getStore(newName)
190
+ // opens and caches a fresh sublevel over the now-populated keyspace.
191
+ for (const dest of destSublevels.values()) {
192
+ await dest.close().catch(() => { });
193
+ }
138
194
  }
139
195
  }
140
- async deleteTableStores(schemaName, tableName) {
141
- // Close and remove data store directory
142
- const dataStoreName = `${schemaName}.${tableName}`.toLowerCase();
143
- const dataStorePath = this.storePaths.get(dataStoreName)
144
- ?? path.join(this.basePath, schemaName, tableName);
145
- await this.closeStoreByName(dataStoreName);
146
- await removeDir(dataStorePath);
147
- // Stats are in the unified __stats__ store, so no need to close a separate store
148
- // The individual stats entry will be removed by the calling code if needed
149
- // Close and remove all index store directories for this table
150
- const indexPrefix = `${schemaName}.${tableName}${STORE_SUFFIX.INDEX}`.toLowerCase();
151
- const indexStoreNames = [];
152
- for (const name of this.stores.keys()) {
153
- if (name.startsWith(indexPrefix))
154
- indexStoreNames.push(name);
155
- }
156
- for (const name of indexStoreNames) {
157
- const indexPath = this.storePaths.get(name);
158
- await this.closeStoreByName(name);
159
- if (indexPath)
160
- await removeDir(indexPath);
161
- }
162
- // Also sweep any on-disk index directories for this table that were never opened
163
- // in this session (e.g. after a process restart followed by a DROP).
164
- const schemaDir = path.join(this.basePath, schemaName);
165
- const indexDirPrefix = `${tableName}${STORE_SUFFIX.INDEX}`;
166
- try {
167
- const entries = await fs.promises.readdir(schemaDir);
168
- for (const entry of entries) {
169
- if (entry.startsWith(indexDirPrefix)) {
170
- await removeDir(path.join(schemaDir, entry));
171
- }
172
- }
196
+ async deleteTableStores(schemaName, tableName, indexNames) {
197
+ // Clear and drop the data store's keyspace.
198
+ await this.clearAndDropStore(buildDataStoreName(schemaName, tableName));
199
+ // Stats live in the unified __stats__ store; the individual stats entry is
200
+ // removed by the calling code (StoreModule), not by clearing a store.
201
+ // Clear exactly the table's index stores (by name). Built via
202
+ // buildIndexStoreName from the authoritative schema index list — never a
203
+ // `${tableName}_idx_` prefix scan, which would also match a sibling table
204
+ // literally named `${tableName}_idx_<x>` and destroy its data.
205
+ for (const indexName of indexNames) {
206
+ await this.clearAndDropStore(buildIndexStoreName(schemaName, tableName, indexName));
173
207
  }
174
- catch {
175
- // Schema directory may not exist; nothing to sweep.
208
+ }
209
+ /**
210
+ * Open an atomic batch across this provider's sublevels, or undefined when the
211
+ * shared root has not been opened yet (no stores exist → nothing to commit).
212
+ *
213
+ * All sublevels share one physical LevelDB, so a single chained batch
214
+ * (`root.batch()…write()`) with each op targeting its sublevel commits them
215
+ * atomically and durably. The transaction coordinator uses this to commit a
216
+ * table's data + secondary-index stores in one physical batch, closing the
217
+ * crash window where a per-store loop could leave them divergent.
218
+ *
219
+ * In practice the coordinator only calls this once it has pending ops — which
220
+ * means stores (hence the root) were already opened — so the undefined branch
221
+ * is defensive (the coordinator falls back to per-store `batch()`).
222
+ */
223
+ beginAtomicBatch() {
224
+ const root = this.root;
225
+ if (!root)
226
+ return undefined;
227
+ return new LevelDBAtomicBatch(root, (store) => this.resolveSublevel(store), this.syncCommits);
228
+ }
229
+ /**
230
+ * Map a {@link KVStore} handle this provider handed out back to its sublevel.
231
+ * A handle not produced by this provider (wrong type, or from another provider)
232
+ * is absent from the ownership map — a programming error.
233
+ */
234
+ resolveSublevel(store) {
235
+ const sublevel = this.sublevelByStore.get(store);
236
+ if (!sublevel) {
237
+ throw new QuereusError('AtomicBatch received a KVStore handle not produced by this provider', StatusCode.MISUSE);
176
238
  }
239
+ return sublevel;
177
240
  }
178
- async getOrCreateStore(storeName, storePath) {
179
- let store = this.stores.get(storeName);
180
- if (!store) {
181
- store = await LevelDBStore.open({
182
- path: storePath,
241
+ /** Open (memoized) the shared physical root database. */
242
+ async getRoot() {
243
+ if (this.root)
244
+ return this.root;
245
+ if (!this.rootOpening) {
246
+ const db = new ClassicLevel(this.basePath, {
247
+ keyEncoding: 'view',
248
+ valueEncoding: 'view',
183
249
  createIfMissing: this.createIfMissing,
184
250
  });
185
- this.stores.set(storeName, store);
186
- this.storePaths.set(storeName, storePath);
251
+ this.rootOpening = db.open().then(() => {
252
+ this.root = db;
253
+ this.rootOpening = null;
254
+ return db;
255
+ }).catch(err => {
256
+ this.rootOpening = null;
257
+ throw err;
258
+ });
259
+ }
260
+ return this.rootOpening;
261
+ }
262
+ /** Create a sublevel handle over the shared root, with the store's byte encodings. */
263
+ openSublevel(root, storeName) {
264
+ return root.sublevel(encodeSublevelName(storeName), {
265
+ keyEncoding: 'view',
266
+ valueEncoding: 'view',
267
+ });
268
+ }
269
+ async getOrCreateStore(storeName) {
270
+ const existing = this.stores.get(storeName);
271
+ if (existing && !existing.isClosed())
272
+ return existing;
273
+ if (existing) {
274
+ // A handle handed out earlier was closed out-of-band (e.g. the StoreTable's
275
+ // releaseIndexStore closes the index handle before dropIndex calls
276
+ // deleteIndexStore). Evict the stale entry and reopen a fresh sublevel.
277
+ this.stores.delete(storeName);
278
+ }
279
+ // Share a single in-flight open across concurrent callers for the same store
280
+ // name so we cache exactly one handle (and one sublevel) per name.
281
+ let opening = this.storeOpening.get(storeName);
282
+ if (!opening) {
283
+ opening = this.openSublevelStore(storeName).then(store => {
284
+ this.stores.set(storeName, store);
285
+ this.storeOpening.delete(storeName);
286
+ return store;
287
+ }).catch(err => {
288
+ this.storeOpening.delete(storeName);
289
+ throw err;
290
+ });
291
+ this.storeOpening.set(storeName, opening);
187
292
  }
293
+ return opening;
294
+ }
295
+ async openSublevelStore(storeName) {
296
+ const root = await this.getRoot();
297
+ const sublevel = this.openSublevel(root, storeName);
298
+ await sublevel.open();
299
+ const store = LevelDBStore.overSublevel(sublevel);
300
+ this.sublevelByStore.set(store, sublevel);
188
301
  return store;
189
302
  }
190
303
  async closeStoreByName(storeName) {
191
304
  const store = this.stores.get(storeName);
192
305
  if (store) {
193
- // Remove from maps before awaiting close, so a concurrent
306
+ // Remove from the map before awaiting close, so a concurrent
194
307
  // getOrCreateStore cannot observe a store that is about to be closed.
195
308
  this.stores.delete(storeName);
196
- this.storePaths.delete(storeName);
197
- await store.close();
309
+ await store.close(); // drops the sublevel handle; the shared root stays open
198
310
  }
199
311
  }
312
+ /** Clear a store's keyspace (sublevel.clear) and drop its cached handle. */
313
+ async clearAndDropStore(storeName) {
314
+ const store = await this.getOrCreateStore(storeName);
315
+ await store.clear();
316
+ await this.closeStoreByName(storeName);
317
+ }
200
318
  }
201
- async function removeDir(dirPath) {
202
- await fs.promises.rm(dirPath, { recursive: true, force: true });
203
- }
204
- async function pathExists(p) {
205
- try {
206
- await fs.promises.access(p);
319
+ /** True if the sublevel has at least one key. */
320
+ async function sublevelHasAnyKey(sublevel) {
321
+ for await (const _key of sublevel.keys({ limit: 1 })) {
207
322
  return true;
208
323
  }
209
- catch {
210
- return false;
324
+ return false;
325
+ }
326
+ /**
327
+ * {@link AtomicBatch} over the shared root's chained batch.
328
+ *
329
+ * Every op targets its store's sublevel via the chained-batch `{ sublevel }`
330
+ * option, so a single `write()` commits across all referenced sublevels in one
331
+ * atomic, durable physical commit. Handles are mapped to sublevels by the
332
+ * provider's `resolveSublevel`.
333
+ */
334
+ class LevelDBAtomicBatch {
335
+ resolveSublevel;
336
+ sync;
337
+ batch;
338
+ constructor(root, resolveSublevel, sync) {
339
+ this.resolveSublevel = resolveSublevel;
340
+ this.sync = sync;
341
+ this.batch = root.batch();
342
+ }
343
+ put(store, key, value) {
344
+ this.batch.put(key, value, { sublevel: this.resolveSublevel(store) });
345
+ }
346
+ delete(store, key) {
347
+ this.batch.del(key, { sublevel: this.resolveSublevel(store) });
348
+ }
349
+ async write() {
350
+ if (this.batch.length === 0) {
351
+ // Free the chained batch's resources without a no-op commit.
352
+ await this.batch.close();
353
+ return;
354
+ }
355
+ // sync=true → fsync the commit so a committed transaction survives power loss
356
+ // (the crash-safe commit this layout exists to provide). One fsync per commit.
357
+ await this.batch.write({ sync: this.sync });
358
+ }
359
+ clear() {
360
+ this.batch.clear();
211
361
  }
212
362
  }
213
363
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/provider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/provider.ts"],"names":[],"mappings":"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"}
@@ -1,27 +1,67 @@
1
1
  /**
2
2
  * LevelDB-based KVStore implementation for Node.js.
3
3
  *
4
- * Uses classic-level for LevelDB bindings.
4
+ * Backed by classic-level. A store operates over an abstract-level handle
5
+ * ({@link ViewLevel}) which is EITHER:
6
+ *
7
+ * - a standalone {@link ClassicLevel} this store owns (via {@link LevelDBStore.open}) —
8
+ * a single physical key-value database used directly (e.g. sync metadata); or
9
+ * - a sublevel of a shared root opened by `LevelDBProvider` (the StoreModule
10
+ * backend), where every table, index, the catalog, and stats share ONE physical
11
+ * LevelDB. See `provider.ts`.
12
+ *
13
+ * `close()` closes the handle. For a standalone store that closes the physical
14
+ * database; for a sublevel it drops the sublevel handle while the shared root
15
+ * stays open (the provider owns the root's lifecycle) — mirroring how
16
+ * `IndexedDBStore.close()` is a per-store handle drop over the shared database.
5
17
  */
6
- import type { KVStore, KVEntry, WriteBatch, IterateOptions, KVStoreOptions } from '@quereus/store';
18
+ import type { AbstractLevel } from 'abstract-level';
19
+ import type { KVStore, KVEntry, WriteBatch, IterateOptions, KVStoreOptions, WriteOptions } from '@quereus/store';
7
20
  /**
8
- * LevelDB implementation of KVStore.
21
+ * Operational handle: the subset of an abstract-level database this store drives.
22
+ * Both a root {@link ClassicLevel} and one of its sublevels satisfy it — both store
23
+ * raw `Uint8Array` keys/values under the `'view'` encoding.
24
+ */
25
+ export type ViewLevel = AbstractLevel<string | Buffer | Uint8Array, Uint8Array, Uint8Array>;
26
+ /**
27
+ * LevelDB implementation of KVStore over an abstract-level handle.
9
28
  */
10
29
  export declare class LevelDBStore implements KVStore {
11
- private db;
30
+ private level;
12
31
  private closed;
13
32
  private constructor();
14
33
  /**
15
- * Open a LevelDB store.
34
+ * Open a standalone LevelDB store as its own physical database at `options.path`.
35
+ *
36
+ * For single-database key-value use (e.g. sync metadata). The multi-table
37
+ * StoreModule backend does NOT use this — it opens one shared root and hands
38
+ * out sublevel-backed stores via `LevelDBProvider`.
16
39
  */
17
40
  static open(options: KVStoreOptions): Promise<LevelDBStore>;
41
+ /**
42
+ * Wrap a sublevel of a shared root as a store. The provider opens the sublevel
43
+ * (off its single root) and owns the root's lifecycle; this store's `close()`
44
+ * only drops the sublevel handle. The sublevel MUST be opened by the caller.
45
+ */
46
+ static overSublevel(sublevel: ViewLevel): LevelDBStore;
18
47
  get(key: Uint8Array): Promise<Uint8Array | undefined>;
19
- put(key: Uint8Array, value: Uint8Array): Promise<void>;
20
- delete(key: Uint8Array): Promise<void>;
48
+ put(key: Uint8Array, value: Uint8Array, options?: WriteOptions): Promise<void>;
49
+ delete(key: Uint8Array, options?: WriteOptions): Promise<void>;
21
50
  has(key: Uint8Array): Promise<boolean>;
22
51
  iterate(options?: IterateOptions): AsyncIterable<KVEntry>;
23
52
  batch(): WriteBatch;
53
+ /**
54
+ * Delete every entry in this store's keyspace. For a sublevel this clears only
55
+ * the sublevel's own prefix range — never a sibling sublevel of the shared root.
56
+ */
57
+ clear(): Promise<void>;
24
58
  close(): Promise<void>;
59
+ /**
60
+ * Whether this handle has been closed. The provider consults this to evict a
61
+ * cached handle that was closed out-of-band by a consumer (e.g. a StoreTable
62
+ * releasing an index store before a drop) and reopen a fresh one.
63
+ */
64
+ isClosed(): boolean;
25
65
  approximateCount(options?: IterateOptions): Promise<number>;
26
66
  private checkOpen;
27
67
  }
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEnG;;GAEG;AACH,qBAAa,YAAa,YAAW,OAAO;IAC1C,OAAO,CAAC,EAAE,CAAuC;IACjD,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO;IAIP;;OAEG;WACU,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC;IAY3D,GAAG,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAMrD,GAAG,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAKtD,MAAM,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAKtC,GAAG,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC;IAOrC,OAAO,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,aAAa,CAAC,OAAO,CAAC;IA0BhE,KAAK,IAAI,UAAU;IAKb,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAOtB,gBAAgB,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC;IAWjE,OAAO,CAAC,SAAS;CAKlB"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,KAAK,EACX,aAAa,EAKb,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEjH;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,GAAG,MAAM,GAAG,UAAU,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;AAa5F;;GAEG;AACH,qBAAa,YAAa,YAAW,OAAO;IAC3C,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO;IAIP;;;;;;OAMG;WACU,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC;IAYjE;;;;OAIG;IACH,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,SAAS,GAAG,YAAY;IAIhD,GAAG,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAMrD,GAAG,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ9E,MAAM,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAM9D,GAAG,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC;IAKrC,OAAO,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,aAAa,CAAC,OAAO,CAAC;IA0BhE,KAAK,IAAI,UAAU;IAKnB;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAS5B;;;;OAIG;IACH,QAAQ,IAAI,OAAO;IAIb,gBAAgB,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC;IAWjE,OAAO,CAAC,SAAS;CAKjB"}
package/dist/src/store.js CHANGED
@@ -1,20 +1,36 @@
1
1
  /**
2
2
  * LevelDB-based KVStore implementation for Node.js.
3
3
  *
4
- * Uses classic-level for LevelDB bindings.
4
+ * Backed by classic-level. A store operates over an abstract-level handle
5
+ * ({@link ViewLevel}) which is EITHER:
6
+ *
7
+ * - a standalone {@link ClassicLevel} this store owns (via {@link LevelDBStore.open}) —
8
+ * a single physical key-value database used directly (e.g. sync metadata); or
9
+ * - a sublevel of a shared root opened by `LevelDBProvider` (the StoreModule
10
+ * backend), where every table, index, the catalog, and stats share ONE physical
11
+ * LevelDB. See `provider.ts`.
12
+ *
13
+ * `close()` closes the handle. For a standalone store that closes the physical
14
+ * database; for a sublevel it drops the sublevel handle while the shared root
15
+ * stays open (the provider owns the root's lifecycle) — mirroring how
16
+ * `IndexedDBStore.close()` is a per-store handle drop over the shared database.
5
17
  */
6
18
  import { ClassicLevel } from 'classic-level';
7
19
  /**
8
- * LevelDB implementation of KVStore.
20
+ * LevelDB implementation of KVStore over an abstract-level handle.
9
21
  */
10
22
  export class LevelDBStore {
11
- db;
23
+ level;
12
24
  closed = false;
13
- constructor(db) {
14
- this.db = db;
25
+ constructor(level) {
26
+ this.level = level;
15
27
  }
16
28
  /**
17
- * Open a LevelDB store.
29
+ * Open a standalone LevelDB store as its own physical database at `options.path`.
30
+ *
31
+ * For single-database key-value use (e.g. sync metadata). The multi-table
32
+ * StoreModule backend does NOT use this — it opens one shared root and hands
33
+ * out sublevel-backed stores via `LevelDBProvider`.
18
34
  */
19
35
  static async open(options) {
20
36
  const db = new ClassicLevel(options.path, {
@@ -26,24 +42,34 @@ export class LevelDBStore {
26
42
  await db.open();
27
43
  return new LevelDBStore(db);
28
44
  }
45
+ /**
46
+ * Wrap a sublevel of a shared root as a store. The provider opens the sublevel
47
+ * (off its single root) and owns the root's lifecycle; this store's `close()`
48
+ * only drops the sublevel handle. The sublevel MUST be opened by the caller.
49
+ */
50
+ static overSublevel(sublevel) {
51
+ return new LevelDBStore(sublevel);
52
+ }
29
53
  async get(key) {
30
54
  this.checkOpen();
31
- // classic-level returns undefined for missing keys (doesn't throw)
32
- return await this.db.get(key);
55
+ // abstract-level returns undefined for missing keys (doesn't throw)
56
+ return await this.level.get(key);
33
57
  }
34
- async put(key, value) {
58
+ async put(key, value, options) {
35
59
  this.checkOpen();
36
- await this.db.put(key, value);
60
+ // classic-level forwards `sync` to the underlying LevelDB write, fsync'ing the
61
+ // log before resolving when requested; sublevels forward it to the root.
62
+ const opts = { sync: options?.sync };
63
+ await this.level.put(key, value, opts);
37
64
  }
38
- async delete(key) {
65
+ async delete(key, options) {
39
66
  this.checkOpen();
40
- await this.db.del(key);
67
+ const opts = { sync: options?.sync };
68
+ await this.level.del(key, opts);
41
69
  }
42
70
  async has(key) {
43
71
  this.checkOpen();
44
- // classic-level returns undefined for missing keys
45
- const value = await this.db.get(key);
46
- return value !== undefined;
72
+ return await this.level.has(key);
47
73
  }
48
74
  async *iterate(options) {
49
75
  this.checkOpen();
@@ -63,7 +89,7 @@ export class LevelDBStore {
63
89
  iteratorOptions.reverse = true;
64
90
  if (options?.limit !== undefined)
65
91
  iteratorOptions.limit = options.limit;
66
- const iterator = this.db.iterator(iteratorOptions);
92
+ const iterator = this.level.iterator(iteratorOptions);
67
93
  try {
68
94
  for await (const [key, value] of iterator) {
69
95
  yield { key, value };
@@ -75,18 +101,36 @@ export class LevelDBStore {
75
101
  }
76
102
  batch() {
77
103
  this.checkOpen();
78
- return new LevelDBWriteBatch(this.db);
104
+ return new LevelDBWriteBatch(this.level);
105
+ }
106
+ /**
107
+ * Delete every entry in this store's keyspace. For a sublevel this clears only
108
+ * the sublevel's own prefix range — never a sibling sublevel of the shared root.
109
+ */
110
+ async clear() {
111
+ this.checkOpen();
112
+ await this.level.clear();
79
113
  }
80
114
  async close() {
81
115
  if (!this.closed) {
82
116
  this.closed = true;
83
- await this.db.close();
117
+ // Standalone: closes the physical database. Sublevel: drops the sublevel
118
+ // handle (detaches from the root); the shared root stays open.
119
+ await this.level.close();
84
120
  }
85
121
  }
122
+ /**
123
+ * Whether this handle has been closed. The provider consults this to evict a
124
+ * cached handle that was closed out-of-band by a consumer (e.g. a StoreTable
125
+ * releasing an index store before a drop) and reopen a fresh one.
126
+ */
127
+ isClosed() {
128
+ return this.closed;
129
+ }
86
130
  async approximateCount(options) {
87
131
  this.checkOpen();
88
- // LevelDB doesn't have a native count, so we iterate and count
89
- // For large datasets, this could be optimized with sampling
132
+ // LevelDB doesn't have a native count, so we iterate and count.
133
+ // For large datasets, this could be optimized with sampling.
90
134
  let count = 0;
91
135
  for await (const _ of this.iterate(options)) {
92
136
  count++;
@@ -100,13 +144,14 @@ export class LevelDBStore {
100
144
  }
101
145
  }
102
146
  /**
103
- * WriteBatch implementation for LevelDB.
147
+ * WriteBatch implementation over a single abstract-level handle (the array-form
148
+ * `batch()`, which commits atomically within that handle).
104
149
  */
105
150
  class LevelDBWriteBatch {
106
- db;
151
+ level;
107
152
  ops = [];
108
- constructor(db) {
109
- this.db = db;
153
+ constructor(level) {
154
+ this.level = level;
110
155
  }
111
156
  put(key, value) {
112
157
  this.ops.push({ type: 'put', key, value });
@@ -116,7 +161,7 @@ class LevelDBWriteBatch {
116
161
  }
117
162
  async write() {
118
163
  if (this.ops.length > 0) {
119
- await this.db.batch(this.ops);
164
+ await this.level.batch(this.ops);
120
165
  this.ops = [];
121
166
  }
122
167
  }
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/store.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quereus/plugin-leveldb",
3
- "version": "3.3.0",
3
+ "version": "4.0.0",
4
4
  "type": "module",
5
5
  "description": "LevelDB storage plugin for Quereus - Node.js persistent storage",
6
6
  "keywords": [
@@ -37,9 +37,9 @@
37
37
  }
38
38
  },
39
39
  "peerDependencies": {
40
- "@quereus/isolation": "^3.3.0",
41
- "@quereus/quereus": "^3.3.0",
42
- "@quereus/store": "^3.3.0"
40
+ "@quereus/isolation": "^4.0.0",
41
+ "@quereus/quereus": "^4.0.0",
42
+ "@quereus/store": "^4.0.0"
43
43
  },
44
44
  "engines": {
45
45
  "quereus": "^0.24.0"
@@ -56,14 +56,21 @@
56
56
  "label": "Base Path",
57
57
  "type": "string",
58
58
  "default": "./data",
59
- "help": "Base directory for all LevelDB stores"
59
+ "help": "Directory of the single shared LevelDB database"
60
60
  },
61
61
  {
62
62
  "key": "createIfMissing",
63
63
  "label": "Create If Missing",
64
64
  "type": "boolean",
65
65
  "default": true,
66
- "help": "Create directories if they don't exist"
66
+ "help": "Create the database if it doesn't exist"
67
+ },
68
+ {
69
+ "key": "syncCommits",
70
+ "label": "Sync Commits",
71
+ "type": "boolean",
72
+ "default": true,
73
+ "help": "fsync each transaction commit so it survives power loss (slower commits when on)"
67
74
  },
68
75
  {
69
76
  "key": "moduleName",
@@ -88,8 +95,9 @@
88
95
  "test": "cd ../.. && node --import ./packages/quereus-plugin-leveldb/register.mjs node_modules/mocha/bin/mocha.js \"packages/quereus-plugin-leveldb/test/**/*.spec.ts\" --reporter min --colors"
89
96
  },
90
97
  "dependencies": {
91
- "@quereus/quereus": "^3.3.0",
92
- "@quereus/store": "^3.3.0",
98
+ "@quereus/quereus": "^4.0.0",
99
+ "@quereus/store": "^4.0.0",
100
+ "abstract-level": "^3.1.0",
93
101
  "classic-level": "^3.0.0"
94
102
  },
95
103
  "devDependencies": {