@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 +40 -9
- package/dist/src/plugin.d.ts +10 -3
- package/dist/src/plugin.d.ts.map +1 -1
- package/dist/src/plugin.js +2 -0
- package/dist/src/plugin.js.map +1 -1
- package/dist/src/provider.d.ts +77 -21
- package/dist/src/provider.d.ts.map +1 -1
- package/dist/src/provider.js +297 -147
- package/dist/src/provider.js.map +1 -1
- package/dist/src/store.d.ts +47 -7
- package/dist/src/store.d.ts.map +1 -1
- package/dist/src/store.js +70 -25
- package/dist/src/store.js.map +1 -1
- package/package.json +16 -8
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
|
-
- **
|
|
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
|
-
|
|
113
|
-
const
|
|
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'` |
|
|
126
|
-
| `createIfMissing` | boolean | `true` | Create
|
|
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
|
|--------|------|---------|-------------|
|
package/dist/src/plugin.d.ts
CHANGED
|
@@ -10,16 +10,23 @@ import { StoreModule } from '@quereus/store';
|
|
|
10
10
|
*/
|
|
11
11
|
export interface LevelDBPluginConfig {
|
|
12
12
|
/**
|
|
13
|
-
* Base path for
|
|
14
|
-
*
|
|
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
|
|
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'
|
package/dist/src/plugin.d.ts.map
CHANGED
|
@@ -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;;;;;
|
|
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"}
|
package/dist/src/plugin.js
CHANGED
|
@@ -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 })
|
package/dist/src/plugin.js.map
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/src/provider.d.ts
CHANGED
|
@@ -1,45 +1,73 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* LevelDB
|
|
2
|
+
* LevelDB KVStoreProvider — shared-root layout.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
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
|
-
*
|
|
7
|
-
* {
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
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
|
|
19
|
-
*
|
|
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
|
|
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
|
-
|
|
39
|
-
private
|
|
40
|
-
|
|
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,
|
|
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
|
|
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"}
|
package/dist/src/provider.js
CHANGED
|
@@ -1,213 +1,363 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* LevelDB
|
|
2
|
+
* LevelDB KVStoreProvider — shared-root layout.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
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
|
-
*
|
|
7
|
-
* {
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
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
|
|
13
|
-
import
|
|
14
|
-
import {
|
|
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
|
-
*
|
|
28
|
+
* Encode a logical store name into a sublevel-safe name.
|
|
18
29
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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,
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
45
|
-
|
|
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
|
-
|
|
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
|
-
|
|
66
|
-
await this.closeStoreByName(storeName);
|
|
97
|
+
await this.closeStoreByName(buildDataStoreName(schemaName, tableName));
|
|
67
98
|
}
|
|
68
99
|
async closeIndexStore(schemaName, tableName, indexName) {
|
|
69
|
-
|
|
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
|
-
|
|
78
|
-
|
|
79
|
-
this.
|
|
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
|
-
|
|
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
|
|
95
|
-
const
|
|
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
|
-
//
|
|
100
|
-
//
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
-
//
|
|
122
|
-
|
|
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
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
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
|
-
|
|
134
|
-
//
|
|
135
|
-
//
|
|
136
|
-
|
|
137
|
-
|
|
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
|
-
//
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
//
|
|
148
|
-
//
|
|
149
|
-
|
|
150
|
-
|
|
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
|
-
|
|
175
|
-
|
|
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
|
-
|
|
179
|
-
|
|
180
|
-
if (
|
|
181
|
-
|
|
182
|
-
|
|
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.
|
|
186
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
202
|
-
|
|
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
|
-
|
|
210
|
-
|
|
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
|
/**
|
package/dist/src/provider.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/provider.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/provider.ts"],"names":[],"mappings":"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"}
|
package/dist/src/store.d.ts
CHANGED
|
@@ -1,27 +1,67 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* LevelDB-based KVStore implementation for Node.js.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
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 {
|
|
18
|
+
import type { AbstractLevel } from 'abstract-level';
|
|
19
|
+
import type { KVStore, KVEntry, WriteBatch, IterateOptions, KVStoreOptions, WriteOptions } from '@quereus/store';
|
|
7
20
|
/**
|
|
8
|
-
*
|
|
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
|
|
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
|
}
|
package/dist/src/store.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/store.ts"],"names":[],"mappings":"AAAA
|
|
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
|
-
*
|
|
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
|
-
|
|
23
|
+
level;
|
|
12
24
|
closed = false;
|
|
13
|
-
constructor(
|
|
14
|
-
this.
|
|
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
|
-
//
|
|
32
|
-
return await this.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
151
|
+
level;
|
|
107
152
|
ops = [];
|
|
108
|
-
constructor(
|
|
109
|
-
this.
|
|
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.
|
|
164
|
+
await this.level.batch(this.ops);
|
|
120
165
|
this.ops = [];
|
|
121
166
|
}
|
|
122
167
|
}
|
package/dist/src/store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/store.ts"],"names":[],"mappings":"AAAA
|
|
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
|
+
"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": "^
|
|
41
|
-
"@quereus/quereus": "^
|
|
42
|
-
"@quereus/store": "^
|
|
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": "
|
|
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
|
|
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": "^
|
|
92
|
-
"@quereus/store": "^
|
|
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": {
|