@quereus/plugin-leveldb 3.3.0 → 4.1.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 +197 -166
- 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 +19 -11
package/README.md
CHANGED
|
@@ -1,166 +1,197 @@
|
|
|
1
|
-
# @quereus/plugin-leveldb
|
|
2
|
-
|
|
3
|
-
LevelDB storage plugin for Quereus. Provides persistent storage for Node.js environments using the [`@quereus/store`](../quereus-store/) module.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- **Fast**: LevelDB offers excellent read/write performance for key-value workloads
|
|
8
|
-
- **Transaction isolation**: Read-your-own-writes and snapshot isolation by default
|
|
9
|
-
- **Sorted keys**: Efficient range queries with ordered iteration
|
|
10
|
-
- **
|
|
11
|
-
- **Compression**: Built-in Snappy compression for reduced disk usage
|
|
12
|
-
|
|
13
|
-
##
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
//
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
```typescript
|
|
108
|
-
import {
|
|
109
|
-
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
await
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
1
|
+
# @quereus/plugin-leveldb
|
|
2
|
+
|
|
3
|
+
LevelDB storage plugin for Quereus. Provides persistent storage for Node.js environments using the [`@quereus/store`](../quereus-store/) module.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Fast**: LevelDB offers excellent read/write performance for key-value workloads
|
|
8
|
+
- **Transaction isolation**: Read-your-own-writes and snapshot isolation by default
|
|
9
|
+
- **Sorted keys**: Efficient range queries with ordered iteration
|
|
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
|
+
- **Compression**: Built-in Snappy compression for reduced disk usage
|
|
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
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm install @quereus/plugin-leveldb @quereus/store @quereus/isolation
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Quick Start
|
|
45
|
+
|
|
46
|
+
### With registerPlugin (Recommended)
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import { Database, registerPlugin } from '@quereus/quereus';
|
|
50
|
+
import leveldbPlugin from '@quereus/plugin-leveldb/plugin';
|
|
51
|
+
|
|
52
|
+
const db = new Database();
|
|
53
|
+
await registerPlugin(db, leveldbPlugin, { basePath: './data' });
|
|
54
|
+
|
|
55
|
+
await db.exec(`
|
|
56
|
+
create table users (id integer primary key, name text)
|
|
57
|
+
using store
|
|
58
|
+
`);
|
|
59
|
+
|
|
60
|
+
// Full transaction isolation enabled by default
|
|
61
|
+
await db.exec('BEGIN');
|
|
62
|
+
await db.exec(`INSERT INTO users VALUES (1, 'Alice')`);
|
|
63
|
+
const user = await db.get('SELECT * FROM users WHERE id = 1'); // Sees uncommitted insert
|
|
64
|
+
await db.exec('COMMIT');
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Disabling Isolation
|
|
68
|
+
|
|
69
|
+
If you need maximum performance and don't require read-your-own-writes within transactions:
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
await registerPlugin(db, leveldbPlugin, {
|
|
73
|
+
basePath: './data',
|
|
74
|
+
isolation: false // Disable isolation layer
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Direct Usage with Provider
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import { Database } from '@quereus/quereus';
|
|
82
|
+
import { createLevelDBProvider } from '@quereus/plugin-leveldb';
|
|
83
|
+
import { createIsolatedStoreModule } from '@quereus/store';
|
|
84
|
+
|
|
85
|
+
const db = new Database();
|
|
86
|
+
const provider = createLevelDBProvider({ basePath: './data' });
|
|
87
|
+
|
|
88
|
+
// With isolation (recommended)
|
|
89
|
+
const storeModule = createIsolatedStoreModule({ provider });
|
|
90
|
+
db.registerModule('store', storeModule);
|
|
91
|
+
|
|
92
|
+
await db.exec(`
|
|
93
|
+
create table users (id integer primary key, name text)
|
|
94
|
+
using store
|
|
95
|
+
`);
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## API
|
|
99
|
+
|
|
100
|
+
### LevelDBStore
|
|
101
|
+
|
|
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`.
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
import { LevelDBStore } from '@quereus/plugin-leveldb';
|
|
109
|
+
|
|
110
|
+
const store = await LevelDBStore.open({ path: './data/mystore' });
|
|
111
|
+
|
|
112
|
+
await store.put(key, value);
|
|
113
|
+
const data = await store.get(key);
|
|
114
|
+
await store.delete(key);
|
|
115
|
+
|
|
116
|
+
// Range iteration
|
|
117
|
+
for await (const { key, value } of store.iterate({ gte: startKey, lt: endKey })) {
|
|
118
|
+
console.log(key, value);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Batch writes
|
|
122
|
+
const batch = store.batch();
|
|
123
|
+
batch.put(key1, value1);
|
|
124
|
+
batch.put(key2, value2);
|
|
125
|
+
batch.delete(key3);
|
|
126
|
+
await batch.write();
|
|
127
|
+
|
|
128
|
+
await store.close();
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### LevelDBProvider
|
|
132
|
+
|
|
133
|
+
Factory for managing multiple stores:
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
import { createLevelDBProvider } from '@quereus/plugin-leveldb';
|
|
137
|
+
|
|
138
|
+
const provider = createLevelDBProvider({ basePath: './data' });
|
|
139
|
+
|
|
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__
|
|
143
|
+
|
|
144
|
+
await provider.closeStore('main', 'users'); // drops the sublevel handle
|
|
145
|
+
await provider.closeAll(); // closes the shared root
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Configuration
|
|
149
|
+
|
|
150
|
+
### Plugin Settings
|
|
151
|
+
|
|
152
|
+
| Setting | Type | Default | Description |
|
|
153
|
+
|---------|------|---------|-------------|
|
|
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) |
|
|
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) |
|
|
159
|
+
|
|
160
|
+
### LevelDBStore Options (standalone `open`)
|
|
161
|
+
|
|
162
|
+
| Option | Type | Default | Description |
|
|
163
|
+
|--------|------|---------|-------------|
|
|
164
|
+
| `path` | string | required | Directory path for the database |
|
|
165
|
+
| `createIfMissing` | boolean | `true` | Create database if it doesn't exist |
|
|
166
|
+
|
|
167
|
+
## Example with Transactions
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import { Database, registerPlugin } from '@quereus/quereus';
|
|
171
|
+
import leveldbPlugin from '@quereus/plugin-leveldb/plugin';
|
|
172
|
+
|
|
173
|
+
const db = new Database();
|
|
174
|
+
await registerPlugin(db, leveldbPlugin, { basePath: './data' });
|
|
175
|
+
|
|
176
|
+
await db.exec(`create table accounts (id integer primary key, balance real) using store`);
|
|
177
|
+
|
|
178
|
+
await db.exec('begin');
|
|
179
|
+
try {
|
|
180
|
+
await db.exec(`update accounts set balance = balance - 100 where id = 1`);
|
|
181
|
+
await db.exec(`update accounts set balance = balance + 100 where id = 2`);
|
|
182
|
+
await db.exec('commit');
|
|
183
|
+
} catch (e) {
|
|
184
|
+
await db.exec('rollback');
|
|
185
|
+
throw e;
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Related Packages
|
|
190
|
+
|
|
191
|
+
- [`@quereus/store`](../quereus-store/) - Core storage module (StoreModule, StoreTable)
|
|
192
|
+
- [`@quereus/plugin-indexeddb`](../quereus-plugin-indexeddb/) - IndexedDB plugin for browsers
|
|
193
|
+
|
|
194
|
+
## License
|
|
195
|
+
|
|
196
|
+
MIT
|
|
197
|
+
|
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"}
|