serializable-bptree 3.4.0-alpha.1 → 4.0.1
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 +52 -42
- package/dist/cjs/index.cjs +49 -16
- package/dist/esm/index.mjs +49 -16
- package/dist/typings/BPTreeAsync.d.ts +3 -3
- package/dist/typings/BPTreeSync.d.ts +3 -3
- package/dist/typings/SerializeStrategyAsync.d.ts +9 -9
- package/dist/typings/SerializeStrategySync.d.ts +9 -9
- package/dist/typings/base/BPTree.d.ts +15 -14
- package/dist/typings/base/SerializeStrategy.d.ts +6 -7
- package/dist/typings/utils/InvertedWeakMap.d.ts +12 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
This is a B+tree that's totally okay with duplicate values. If you need to keep track of the B+ tree's state, don't just leave it in memory - make sure you write it down.
|
|
7
7
|
|
|
8
8
|
```typescript
|
|
9
|
-
import { readFileSync, writeFileSync, existsSync } from 'fs'
|
|
9
|
+
import { readFileSync, writeFileSync, unlinkSync, existsSync } from 'fs'
|
|
10
10
|
import {
|
|
11
11
|
BPTreeSync,
|
|
12
12
|
SerializeStrategySync,
|
|
@@ -14,18 +14,22 @@ import {
|
|
|
14
14
|
} from 'serializable-bptree'
|
|
15
15
|
|
|
16
16
|
class FileStoreStrategySync extends SerializeStrategySync<K, V> {
|
|
17
|
-
id():
|
|
18
|
-
return this.autoIncrement('index', 1)
|
|
17
|
+
id(): string {
|
|
18
|
+
return this.autoIncrement('index', 1).toString()
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
read(id:
|
|
22
|
-
const raw = readFileSync(id
|
|
21
|
+
read(id: string): BPTreeNode<K, V> {
|
|
22
|
+
const raw = readFileSync(id, 'utf8')
|
|
23
23
|
return JSON.parse(raw)
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
write(id:
|
|
26
|
+
write(id: string, node: BPTreeNode<K, V>): void {
|
|
27
27
|
const stringify = JSON.stringify(node)
|
|
28
|
-
writeFileSync(id
|
|
28
|
+
writeFileSync(id, stringify, 'utf8')
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
delete(id: string): void {
|
|
32
|
+
unlinkSync(id)
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
readHead(): SerializeStrategyHead|null {
|
|
@@ -98,7 +102,7 @@ import {
|
|
|
98
102
|
ValueComparator,
|
|
99
103
|
NumericComparator,
|
|
100
104
|
StringComparator
|
|
101
|
-
} from 'https://cdn.jsdelivr.net/npm/serializable-bptree@
|
|
105
|
+
} from 'https://cdn.jsdelivr.net/npm/serializable-bptree@4.x.x/dist/esm/index.min.js'
|
|
102
106
|
</script>
|
|
103
107
|
```
|
|
104
108
|
|
|
@@ -177,9 +181,10 @@ You need to construct a logic for input/output from the file by inheriting the S
|
|
|
177
181
|
import { SerializeStrategySync } from 'serializable-bptree'
|
|
178
182
|
|
|
179
183
|
class MyFileIOStrategySync extends SerializeStrategySync {
|
|
180
|
-
id():
|
|
181
|
-
read(id:
|
|
182
|
-
write(id:
|
|
184
|
+
id(): string
|
|
185
|
+
read(id: string): BPTreeNode<K, V>
|
|
186
|
+
write(id: string, node: BPTreeNode<K, V>): void
|
|
187
|
+
delete(id: string): void
|
|
183
188
|
readHead(): SerializeStrategyHead|null
|
|
184
189
|
writeHead(head: SerializeStrategyHead): void
|
|
185
190
|
}
|
|
@@ -187,49 +192,39 @@ class MyFileIOStrategySync extends SerializeStrategySync {
|
|
|
187
192
|
|
|
188
193
|
What does this method mean? And why do we need to construct such a method?
|
|
189
194
|
|
|
190
|
-
#### id(isLeaf: `boolean`): `
|
|
191
|
-
|
|
192
|
-
When a node is created in the B+tree, the node needs a unique value to represent itself. This is the **node.id** attribute, and you can specify this attribute yourself. For example, it could be implemented like this.
|
|
193
|
-
|
|
194
|
-
```typescript
|
|
195
|
-
id(isLeaf: boolean): number {
|
|
196
|
-
const current = before + 1
|
|
197
|
-
before = current
|
|
198
|
-
return current
|
|
199
|
-
}
|
|
200
|
-
```
|
|
195
|
+
#### id(isLeaf: `boolean`): `string`
|
|
201
196
|
|
|
202
|
-
|
|
197
|
+
When a node is created in the B+tree, the node needs a unique value to represent itself. This is the **node.id** attribute, and you can specify this attribute yourself.
|
|
203
198
|
|
|
204
199
|
Typically, such an **id** value increases sequentially, and it would be beneficial to store such a value separately within the tree. For that purpose, the **setHeadData** and **getHeadData** methods are available. These methods are responsible for storing arbitrary data in the tree's header or retrieving stored data. Below is an example of usage:
|
|
205
200
|
|
|
206
201
|
```typescript
|
|
207
|
-
id(isLeaf: boolean):
|
|
202
|
+
id(isLeaf: boolean): string {
|
|
208
203
|
const current = this.getHeadData('index', 1) as number
|
|
209
204
|
this.setHeadData('index', current+1)
|
|
210
|
-
return current
|
|
205
|
+
return current.toString()
|
|
211
206
|
}
|
|
212
207
|
```
|
|
213
208
|
|
|
214
|
-
Additionally, there is a more
|
|
209
|
+
Additionally, there is a more dev-friendly usage of this code.
|
|
215
210
|
|
|
216
211
|
```typescript
|
|
217
|
-
id(isLeaf: boolean):
|
|
218
|
-
return this.autoIncrement('index', 1)
|
|
212
|
+
id(isLeaf: boolean): string {
|
|
213
|
+
return this.autoIncrement('index', 1).toString()
|
|
219
214
|
}
|
|
220
215
|
```
|
|
221
216
|
|
|
222
217
|
The **id** method is called before a node is created in the tree. Therefore, it can also be used to allocate space for storing the node.
|
|
223
218
|
|
|
224
|
-
#### read(id: `
|
|
219
|
+
#### read(id: `string`): `BPTreeNode<K, V>`
|
|
225
220
|
|
|
226
221
|
This is a method to load the saved value as a tree instance. If you have previously saved the node as a file, you should use this method to convert it back to JavaScript JSON format and return it.
|
|
227
222
|
|
|
228
223
|
Please refer to the example below:
|
|
229
224
|
|
|
230
225
|
```typescript
|
|
231
|
-
read(id:
|
|
232
|
-
const filePath = `./my-store/${id
|
|
226
|
+
read(id: string): BPTreeNode<K, V> {
|
|
227
|
+
const filePath = `./my-store/${id}`
|
|
233
228
|
const raw = fs.readFileSync(filePath, 'utf8')
|
|
234
229
|
return JSON.parse(raw)
|
|
235
230
|
}
|
|
@@ -237,7 +232,7 @@ read(id: number): BPTreeNode<K, V> {
|
|
|
237
232
|
|
|
238
233
|
This method is called only once when loading a node from a tree instance. The loaded node is loaded into memory, and subsequently, when the tree references the node, it operates based on the values in memory **without** re-invoking this method.
|
|
239
234
|
|
|
240
|
-
#### write(id: `
|
|
235
|
+
#### write(id: `string`, node: `BPTreeNode<K, V>`): `void`
|
|
241
236
|
|
|
242
237
|
This method is called when there are changes in the internal nodes due to the insert or delete operations of the tree instance. In other words, it's a necessary method for synchronizing the in-memory nodes into a file.
|
|
243
238
|
|
|
@@ -247,17 +242,17 @@ Please refer to the example below:
|
|
|
247
242
|
|
|
248
243
|
```typescript
|
|
249
244
|
let queue = 0
|
|
250
|
-
function writeBack(id:
|
|
245
|
+
function writeBack(id: string, node: BPTreeNode<K, V>, timer: number) {
|
|
251
246
|
clearTimeout(queue)
|
|
252
247
|
queue = setTimeout(() => {
|
|
253
|
-
const filePath = `./my-store/${id
|
|
248
|
+
const filePath = `./my-store/${id}`
|
|
254
249
|
const stringify = JSON.stringify(node)
|
|
255
250
|
writeFileSync(filePath, stringify, 'utf8')
|
|
256
251
|
}, timer)
|
|
257
252
|
}
|
|
258
253
|
|
|
259
254
|
...
|
|
260
|
-
write(id:
|
|
255
|
+
write(id: string, node: BPTreeNode<K, V>): void {
|
|
261
256
|
const writeBackInterval = 10
|
|
262
257
|
writeBack(id, node, writeBackInterval)
|
|
263
258
|
}
|
|
@@ -265,6 +260,17 @@ write(id: number, node: BPTreeNode<K, V>): void {
|
|
|
265
260
|
|
|
266
261
|
This kind of delay writing should ideally occur within a few milliseconds. If this is not feasible, consider other approaches.
|
|
267
262
|
|
|
263
|
+
#### delete(id: `string`): `void`
|
|
264
|
+
|
|
265
|
+
This method is called when previously created nodes become no longer needed due to deletion or other processes. It can be used to free up space by deleting existing stored nodes.
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
delete(id: string): void {
|
|
269
|
+
const filePath = `./my-store/${id}`
|
|
270
|
+
fs.unlinkSync(filePath)
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
268
274
|
#### readHead(): `SerializeStrategyHead`|`null`
|
|
269
275
|
|
|
270
276
|
This method is called only once when the tree is created. It's a method to restore the saved tree information. If it is the initial creation and there is no stored root node, it should return **null**.
|
|
@@ -357,7 +363,7 @@ Support for asynchronous trees has been available since version 3.0.0. Asynchron
|
|
|
357
363
|
|
|
358
364
|
```typescript
|
|
359
365
|
import { existsSync } from 'fs'
|
|
360
|
-
import { readFile, writeFile } from 'fs/promises'
|
|
366
|
+
import { readFile, writeFile, unlink } from 'fs/promises'
|
|
361
367
|
import {
|
|
362
368
|
BPTreeAsync,
|
|
363
369
|
SerializeStrategyAsync,
|
|
@@ -366,18 +372,22 @@ import {
|
|
|
366
372
|
} from 'serializable-bptree'
|
|
367
373
|
|
|
368
374
|
class FileStoreStrategyAsync extends SerializeStrategyAsync<K, V> {
|
|
369
|
-
async id(isLeaf: boolean): Promise<
|
|
370
|
-
return await this.autoIncrement('index', 1)
|
|
375
|
+
async id(isLeaf: boolean): Promise<string> {
|
|
376
|
+
return await this.autoIncrement('index', 1).toString()
|
|
371
377
|
}
|
|
372
378
|
|
|
373
|
-
async read(id:
|
|
374
|
-
const raw = await readFile(id
|
|
379
|
+
async read(id: string): Promise<BPTreeNode<K, V>> {
|
|
380
|
+
const raw = await readFile(id, 'utf8')
|
|
375
381
|
return JSON.parse(raw)
|
|
376
382
|
}
|
|
377
383
|
|
|
378
|
-
async write(id:
|
|
384
|
+
async write(id: string, node: BPTreeNode<K, V>): Promise<void> {
|
|
379
385
|
const stringify = JSON.stringify(node)
|
|
380
|
-
await writeFile(id
|
|
386
|
+
await writeFile(id, stringify, 'utf8')
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
async delete(id: string): Promise<void> {
|
|
390
|
+
await unlink(id)
|
|
381
391
|
}
|
|
382
392
|
|
|
383
393
|
async readHead(): Promise<SerializeStrategyHead|null> {
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -426,6 +426,39 @@ var CacheBranchSync = class _CacheBranchSync extends CacheBranch {
|
|
|
426
426
|
}
|
|
427
427
|
};
|
|
428
428
|
|
|
429
|
+
// src/utils/InvertedWeakMap.ts
|
|
430
|
+
var InvertedWeakMap = class {
|
|
431
|
+
_map;
|
|
432
|
+
_registry;
|
|
433
|
+
constructor() {
|
|
434
|
+
this._map = /* @__PURE__ */ new Map();
|
|
435
|
+
this._registry = new FinalizationRegistry((key) => this._map.delete(key));
|
|
436
|
+
}
|
|
437
|
+
clear() {
|
|
438
|
+
return this._map.clear();
|
|
439
|
+
}
|
|
440
|
+
delete(key) {
|
|
441
|
+
return this._map.delete(key);
|
|
442
|
+
}
|
|
443
|
+
get(key) {
|
|
444
|
+
return this._map.get(key)?.deref();
|
|
445
|
+
}
|
|
446
|
+
has(key) {
|
|
447
|
+
return this._map.has(key) && this.get(key) !== void 0;
|
|
448
|
+
}
|
|
449
|
+
set(key, value) {
|
|
450
|
+
this._map.set(key, new WeakRef(value));
|
|
451
|
+
this._registry.register(value, key);
|
|
452
|
+
return this;
|
|
453
|
+
}
|
|
454
|
+
get size() {
|
|
455
|
+
return this._map.size;
|
|
456
|
+
}
|
|
457
|
+
keys() {
|
|
458
|
+
return this._map.keys();
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
|
|
429
462
|
// src/base/BPTree.ts
|
|
430
463
|
var BPTree = class {
|
|
431
464
|
_cachedRegexp;
|
|
@@ -486,7 +519,7 @@ var BPTree = class {
|
|
|
486
519
|
this._nodeCreateBuffer = /* @__PURE__ */ new Map();
|
|
487
520
|
this._nodeUpdateBuffer = /* @__PURE__ */ new Map();
|
|
488
521
|
this._nodeDeleteBuffer = /* @__PURE__ */ new Map();
|
|
489
|
-
this.nodes =
|
|
522
|
+
this.nodes = new InvertedWeakMap();
|
|
490
523
|
this.strategy = strategy;
|
|
491
524
|
this.comparator = comparator;
|
|
492
525
|
}
|
|
@@ -609,12 +642,12 @@ var BPTreeSync = class extends BPTree {
|
|
|
609
642
|
}
|
|
610
643
|
_createNodeId(isLeaf) {
|
|
611
644
|
const id = this.strategy.id(isLeaf);
|
|
612
|
-
if (id ===
|
|
613
|
-
throw new Error(`The node's id should never be
|
|
645
|
+
if (id === null) {
|
|
646
|
+
throw new Error(`The node's id should never be null.`);
|
|
614
647
|
}
|
|
615
648
|
return id;
|
|
616
649
|
}
|
|
617
|
-
_createNode(isLeaf, keys2, values, leaf = false, parent =
|
|
650
|
+
_createNode(isLeaf, keys2, values, leaf = false, parent = null, next = null, prev = null) {
|
|
618
651
|
const id = this._createNodeId(isLeaf);
|
|
619
652
|
const node = {
|
|
620
653
|
id,
|
|
@@ -651,7 +684,7 @@ var BPTreeSync = class extends BPTree {
|
|
|
651
684
|
const keys2 = node.keys;
|
|
652
685
|
this.bufferForNodeDelete(this.root);
|
|
653
686
|
this.root = this.getNode(keys2[0]);
|
|
654
|
-
this.root.parent =
|
|
687
|
+
this.root.parent = null;
|
|
655
688
|
this.strategy.head.root = this.root.id;
|
|
656
689
|
this.bufferForNodeUpdate(this.root);
|
|
657
690
|
return;
|
|
@@ -719,7 +752,7 @@ var BPTreeSync = class extends BPTree {
|
|
|
719
752
|
this.bufferForNodeUpdate(n);
|
|
720
753
|
}
|
|
721
754
|
if (isPredecessor) {
|
|
722
|
-
pointer.prev =
|
|
755
|
+
pointer.prev = null;
|
|
723
756
|
}
|
|
724
757
|
}
|
|
725
758
|
pointer.values.push(...node.values);
|
|
@@ -1160,12 +1193,12 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1160
1193
|
}
|
|
1161
1194
|
async _createNodeId(isLeaf) {
|
|
1162
1195
|
const id = await this.strategy.id(isLeaf);
|
|
1163
|
-
if (id ===
|
|
1164
|
-
throw new Error(`The node's id should never be
|
|
1196
|
+
if (id === null) {
|
|
1197
|
+
throw new Error(`The node's id should never be null.`);
|
|
1165
1198
|
}
|
|
1166
1199
|
return id;
|
|
1167
1200
|
}
|
|
1168
|
-
async _createNode(isLeaf, keys2, values, leaf = false, parent =
|
|
1201
|
+
async _createNode(isLeaf, keys2, values, leaf = false, parent = null, next = null, prev = null) {
|
|
1169
1202
|
const id = await this._createNodeId(isLeaf);
|
|
1170
1203
|
const node = {
|
|
1171
1204
|
id,
|
|
@@ -1202,7 +1235,7 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1202
1235
|
const keys2 = node.keys;
|
|
1203
1236
|
this.bufferForNodeDelete(this.root);
|
|
1204
1237
|
this.root = await this.getNode(keys2[0]);
|
|
1205
|
-
this.root.parent =
|
|
1238
|
+
this.root.parent = null;
|
|
1206
1239
|
this.strategy.head.root = this.root.id;
|
|
1207
1240
|
this.bufferForNodeUpdate(this.root);
|
|
1208
1241
|
return;
|
|
@@ -1270,7 +1303,7 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1270
1303
|
this.bufferForNodeUpdate(n);
|
|
1271
1304
|
}
|
|
1272
1305
|
if (isPredecessor) {
|
|
1273
|
-
pointer.prev =
|
|
1306
|
+
pointer.prev = null;
|
|
1274
1307
|
}
|
|
1275
1308
|
}
|
|
1276
1309
|
pointer.values.push(...node.values);
|
|
@@ -1646,7 +1679,7 @@ var SerializeStrategy = class {
|
|
|
1646
1679
|
this.order = order;
|
|
1647
1680
|
this.head = {
|
|
1648
1681
|
order,
|
|
1649
|
-
root:
|
|
1682
|
+
root: null,
|
|
1650
1683
|
data: {}
|
|
1651
1684
|
};
|
|
1652
1685
|
}
|
|
@@ -1678,7 +1711,7 @@ var InMemoryStoreStrategySync = class extends SerializeStrategySync {
|
|
|
1678
1711
|
this.node = {};
|
|
1679
1712
|
}
|
|
1680
1713
|
id(isLeaf) {
|
|
1681
|
-
return this.autoIncrement("index", 1);
|
|
1714
|
+
return this.autoIncrement("index", 1).toString();
|
|
1682
1715
|
}
|
|
1683
1716
|
read(id) {
|
|
1684
1717
|
if (!Object.hasOwn(this.node, id)) {
|
|
@@ -1693,7 +1726,7 @@ var InMemoryStoreStrategySync = class extends SerializeStrategySync {
|
|
|
1693
1726
|
delete this.node[id];
|
|
1694
1727
|
}
|
|
1695
1728
|
readHead() {
|
|
1696
|
-
if (this.head.root ===
|
|
1729
|
+
if (this.head.root === null) {
|
|
1697
1730
|
return null;
|
|
1698
1731
|
}
|
|
1699
1732
|
return this.head;
|
|
@@ -1729,7 +1762,7 @@ var InMemoryStoreStrategyAsync = class extends SerializeStrategyAsync {
|
|
|
1729
1762
|
this.node = {};
|
|
1730
1763
|
}
|
|
1731
1764
|
async id(isLeaf) {
|
|
1732
|
-
return await this.autoIncrement("index", 1);
|
|
1765
|
+
return (await this.autoIncrement("index", 1)).toString();
|
|
1733
1766
|
}
|
|
1734
1767
|
async read(id) {
|
|
1735
1768
|
if (!Object.hasOwn(this.node, id)) {
|
|
@@ -1744,7 +1777,7 @@ var InMemoryStoreStrategyAsync = class extends SerializeStrategyAsync {
|
|
|
1744
1777
|
delete this.node[id];
|
|
1745
1778
|
}
|
|
1746
1779
|
async readHead() {
|
|
1747
|
-
if (this.head.root ===
|
|
1780
|
+
if (this.head.root === null) {
|
|
1748
1781
|
return null;
|
|
1749
1782
|
}
|
|
1750
1783
|
return this.head;
|
package/dist/esm/index.mjs
CHANGED
|
@@ -392,6 +392,39 @@ var CacheBranchSync = class _CacheBranchSync extends CacheBranch {
|
|
|
392
392
|
}
|
|
393
393
|
};
|
|
394
394
|
|
|
395
|
+
// src/utils/InvertedWeakMap.ts
|
|
396
|
+
var InvertedWeakMap = class {
|
|
397
|
+
_map;
|
|
398
|
+
_registry;
|
|
399
|
+
constructor() {
|
|
400
|
+
this._map = /* @__PURE__ */ new Map();
|
|
401
|
+
this._registry = new FinalizationRegistry((key) => this._map.delete(key));
|
|
402
|
+
}
|
|
403
|
+
clear() {
|
|
404
|
+
return this._map.clear();
|
|
405
|
+
}
|
|
406
|
+
delete(key) {
|
|
407
|
+
return this._map.delete(key);
|
|
408
|
+
}
|
|
409
|
+
get(key) {
|
|
410
|
+
return this._map.get(key)?.deref();
|
|
411
|
+
}
|
|
412
|
+
has(key) {
|
|
413
|
+
return this._map.has(key) && this.get(key) !== void 0;
|
|
414
|
+
}
|
|
415
|
+
set(key, value) {
|
|
416
|
+
this._map.set(key, new WeakRef(value));
|
|
417
|
+
this._registry.register(value, key);
|
|
418
|
+
return this;
|
|
419
|
+
}
|
|
420
|
+
get size() {
|
|
421
|
+
return this._map.size;
|
|
422
|
+
}
|
|
423
|
+
keys() {
|
|
424
|
+
return this._map.keys();
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
|
|
395
428
|
// src/base/BPTree.ts
|
|
396
429
|
var BPTree = class {
|
|
397
430
|
_cachedRegexp;
|
|
@@ -452,7 +485,7 @@ var BPTree = class {
|
|
|
452
485
|
this._nodeCreateBuffer = /* @__PURE__ */ new Map();
|
|
453
486
|
this._nodeUpdateBuffer = /* @__PURE__ */ new Map();
|
|
454
487
|
this._nodeDeleteBuffer = /* @__PURE__ */ new Map();
|
|
455
|
-
this.nodes =
|
|
488
|
+
this.nodes = new InvertedWeakMap();
|
|
456
489
|
this.strategy = strategy;
|
|
457
490
|
this.comparator = comparator;
|
|
458
491
|
}
|
|
@@ -575,12 +608,12 @@ var BPTreeSync = class extends BPTree {
|
|
|
575
608
|
}
|
|
576
609
|
_createNodeId(isLeaf) {
|
|
577
610
|
const id = this.strategy.id(isLeaf);
|
|
578
|
-
if (id ===
|
|
579
|
-
throw new Error(`The node's id should never be
|
|
611
|
+
if (id === null) {
|
|
612
|
+
throw new Error(`The node's id should never be null.`);
|
|
580
613
|
}
|
|
581
614
|
return id;
|
|
582
615
|
}
|
|
583
|
-
_createNode(isLeaf, keys2, values, leaf = false, parent =
|
|
616
|
+
_createNode(isLeaf, keys2, values, leaf = false, parent = null, next = null, prev = null) {
|
|
584
617
|
const id = this._createNodeId(isLeaf);
|
|
585
618
|
const node = {
|
|
586
619
|
id,
|
|
@@ -617,7 +650,7 @@ var BPTreeSync = class extends BPTree {
|
|
|
617
650
|
const keys2 = node.keys;
|
|
618
651
|
this.bufferForNodeDelete(this.root);
|
|
619
652
|
this.root = this.getNode(keys2[0]);
|
|
620
|
-
this.root.parent =
|
|
653
|
+
this.root.parent = null;
|
|
621
654
|
this.strategy.head.root = this.root.id;
|
|
622
655
|
this.bufferForNodeUpdate(this.root);
|
|
623
656
|
return;
|
|
@@ -685,7 +718,7 @@ var BPTreeSync = class extends BPTree {
|
|
|
685
718
|
this.bufferForNodeUpdate(n);
|
|
686
719
|
}
|
|
687
720
|
if (isPredecessor) {
|
|
688
|
-
pointer.prev =
|
|
721
|
+
pointer.prev = null;
|
|
689
722
|
}
|
|
690
723
|
}
|
|
691
724
|
pointer.values.push(...node.values);
|
|
@@ -1126,12 +1159,12 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1126
1159
|
}
|
|
1127
1160
|
async _createNodeId(isLeaf) {
|
|
1128
1161
|
const id = await this.strategy.id(isLeaf);
|
|
1129
|
-
if (id ===
|
|
1130
|
-
throw new Error(`The node's id should never be
|
|
1162
|
+
if (id === null) {
|
|
1163
|
+
throw new Error(`The node's id should never be null.`);
|
|
1131
1164
|
}
|
|
1132
1165
|
return id;
|
|
1133
1166
|
}
|
|
1134
|
-
async _createNode(isLeaf, keys2, values, leaf = false, parent =
|
|
1167
|
+
async _createNode(isLeaf, keys2, values, leaf = false, parent = null, next = null, prev = null) {
|
|
1135
1168
|
const id = await this._createNodeId(isLeaf);
|
|
1136
1169
|
const node = {
|
|
1137
1170
|
id,
|
|
@@ -1168,7 +1201,7 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1168
1201
|
const keys2 = node.keys;
|
|
1169
1202
|
this.bufferForNodeDelete(this.root);
|
|
1170
1203
|
this.root = await this.getNode(keys2[0]);
|
|
1171
|
-
this.root.parent =
|
|
1204
|
+
this.root.parent = null;
|
|
1172
1205
|
this.strategy.head.root = this.root.id;
|
|
1173
1206
|
this.bufferForNodeUpdate(this.root);
|
|
1174
1207
|
return;
|
|
@@ -1236,7 +1269,7 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1236
1269
|
this.bufferForNodeUpdate(n);
|
|
1237
1270
|
}
|
|
1238
1271
|
if (isPredecessor) {
|
|
1239
|
-
pointer.prev =
|
|
1272
|
+
pointer.prev = null;
|
|
1240
1273
|
}
|
|
1241
1274
|
}
|
|
1242
1275
|
pointer.values.push(...node.values);
|
|
@@ -1612,7 +1645,7 @@ var SerializeStrategy = class {
|
|
|
1612
1645
|
this.order = order;
|
|
1613
1646
|
this.head = {
|
|
1614
1647
|
order,
|
|
1615
|
-
root:
|
|
1648
|
+
root: null,
|
|
1616
1649
|
data: {}
|
|
1617
1650
|
};
|
|
1618
1651
|
}
|
|
@@ -1644,7 +1677,7 @@ var InMemoryStoreStrategySync = class extends SerializeStrategySync {
|
|
|
1644
1677
|
this.node = {};
|
|
1645
1678
|
}
|
|
1646
1679
|
id(isLeaf) {
|
|
1647
|
-
return this.autoIncrement("index", 1);
|
|
1680
|
+
return this.autoIncrement("index", 1).toString();
|
|
1648
1681
|
}
|
|
1649
1682
|
read(id) {
|
|
1650
1683
|
if (!Object.hasOwn(this.node, id)) {
|
|
@@ -1659,7 +1692,7 @@ var InMemoryStoreStrategySync = class extends SerializeStrategySync {
|
|
|
1659
1692
|
delete this.node[id];
|
|
1660
1693
|
}
|
|
1661
1694
|
readHead() {
|
|
1662
|
-
if (this.head.root ===
|
|
1695
|
+
if (this.head.root === null) {
|
|
1663
1696
|
return null;
|
|
1664
1697
|
}
|
|
1665
1698
|
return this.head;
|
|
@@ -1695,7 +1728,7 @@ var InMemoryStoreStrategyAsync = class extends SerializeStrategyAsync {
|
|
|
1695
1728
|
this.node = {};
|
|
1696
1729
|
}
|
|
1697
1730
|
async id(isLeaf) {
|
|
1698
|
-
return await this.autoIncrement("index", 1);
|
|
1731
|
+
return (await this.autoIncrement("index", 1)).toString();
|
|
1699
1732
|
}
|
|
1700
1733
|
async read(id) {
|
|
1701
1734
|
if (!Object.hasOwn(this.node, id)) {
|
|
@@ -1710,7 +1743,7 @@ var InMemoryStoreStrategyAsync = class extends SerializeStrategyAsync {
|
|
|
1710
1743
|
delete this.node[id];
|
|
1711
1744
|
}
|
|
1712
1745
|
async readHead() {
|
|
1713
|
-
if (this.head.root ===
|
|
1746
|
+
if (this.head.root === null) {
|
|
1714
1747
|
return null;
|
|
1715
1748
|
}
|
|
1716
1749
|
return this.head;
|
|
@@ -8,12 +8,12 @@ export declare class BPTreeAsync<K, V> extends BPTree<K, V> {
|
|
|
8
8
|
protected _getPairsRightToLeft(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean): Promise<BPTreePair<K, V>[]>;
|
|
9
9
|
protected _getPairsLeftToRight(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean): Promise<BPTreePair<K, V>[]>;
|
|
10
10
|
protected getPairs(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean, direction: 1 | -1): Promise<BPTreePair<K, V>[]>;
|
|
11
|
-
protected _createNodeId(isLeaf: boolean): Promise<
|
|
12
|
-
protected _createNode(isLeaf: boolean, keys:
|
|
11
|
+
protected _createNodeId(isLeaf: boolean): Promise<string>;
|
|
12
|
+
protected _createNode(isLeaf: boolean, keys: string[] | K[][], values: V[], leaf?: boolean, parent?: string | null, next?: string | null, prev?: string | null): Promise<BPTreeUnknownNode<K, V>>;
|
|
13
13
|
protected _deleteEntry(node: BPTreeUnknownNode<K, V>, key: BPTreeNodeKey<K>, value: V): Promise<void>;
|
|
14
14
|
protected _insertInParent(node: BPTreeUnknownNode<K, V>, value: V, pointer: BPTreeUnknownNode<K, V>): Promise<void>;
|
|
15
15
|
init(): Promise<void>;
|
|
16
|
-
protected getNode(id:
|
|
16
|
+
protected getNode(id: string): Promise<BPTreeUnknownNode<K, V>>;
|
|
17
17
|
protected insertableNode(value: V): Promise<BPTreeLeafNode<K, V>>;
|
|
18
18
|
protected leftestNode(): Promise<BPTreeLeafNode<K, V>>;
|
|
19
19
|
protected commitHeadBuffer(): Promise<void>;
|
|
@@ -8,12 +8,12 @@ export declare class BPTreeSync<K, V> extends BPTree<K, V> {
|
|
|
8
8
|
protected _getPairsRightToLeft(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean): BPTreePair<K, V>[];
|
|
9
9
|
protected _getPairsLeftToRight(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean): BPTreePair<K, V>[];
|
|
10
10
|
protected getPairs(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean, direction: 1 | -1): BPTreePair<K, V>[];
|
|
11
|
-
protected _createNodeId(isLeaf: boolean):
|
|
12
|
-
protected _createNode(isLeaf: boolean, keys:
|
|
11
|
+
protected _createNodeId(isLeaf: boolean): string;
|
|
12
|
+
protected _createNode(isLeaf: boolean, keys: string[] | K[][], values: V[], leaf?: boolean, parent?: string | null, next?: string | null, prev?: string | null): BPTreeUnknownNode<K, V>;
|
|
13
13
|
protected _deleteEntry(node: BPTreeUnknownNode<K, V>, key: BPTreeNodeKey<K>, value: V): void;
|
|
14
14
|
protected _insertInParent(node: BPTreeUnknownNode<K, V>, value: V, pointer: BPTreeUnknownNode<K, V>): void;
|
|
15
15
|
init(): void;
|
|
16
|
-
protected getNode(id:
|
|
16
|
+
protected getNode(id: string): BPTreeUnknownNode<K, V>;
|
|
17
17
|
protected insertableNode(value: V): BPTreeLeafNode<K, V>;
|
|
18
18
|
protected leftestNode(): BPTreeLeafNode<K, V>;
|
|
19
19
|
protected commitHeadBuffer(): void;
|
|
@@ -2,10 +2,10 @@ import { BPTreeNode } from './base/BPTree';
|
|
|
2
2
|
import { SerializeStrategy, SerializeStrategyHead } from './base/SerializeStrategy';
|
|
3
3
|
import { Json } from './utils/types';
|
|
4
4
|
export declare abstract class SerializeStrategyAsync<K, V> extends SerializeStrategy<K, V> {
|
|
5
|
-
abstract id(isLeaf: boolean): Promise<
|
|
6
|
-
abstract read(id:
|
|
7
|
-
abstract write(id:
|
|
8
|
-
abstract delete(id:
|
|
5
|
+
abstract id(isLeaf: boolean): Promise<string>;
|
|
6
|
+
abstract read(id: string): Promise<BPTreeNode<K, V>>;
|
|
7
|
+
abstract write(id: string, node: BPTreeNode<K, V>): Promise<void>;
|
|
8
|
+
abstract delete(id: string): Promise<void>;
|
|
9
9
|
abstract readHead(): Promise<SerializeStrategyHead | null>;
|
|
10
10
|
abstract writeHead(head: SerializeStrategyHead): Promise<void>;
|
|
11
11
|
getHeadData(key: string, defaultValue: Json): Promise<Json>;
|
|
@@ -13,12 +13,12 @@ export declare abstract class SerializeStrategyAsync<K, V> extends SerializeStra
|
|
|
13
13
|
autoIncrement(key: string, defaultValue: number): Promise<number>;
|
|
14
14
|
}
|
|
15
15
|
export declare class InMemoryStoreStrategyAsync<K, V> extends SerializeStrategyAsync<K, V> {
|
|
16
|
-
protected readonly node: Record<
|
|
16
|
+
protected readonly node: Record<string, BPTreeNode<K, V>>;
|
|
17
17
|
constructor(order: number);
|
|
18
|
-
id(isLeaf: boolean): Promise<
|
|
19
|
-
read(id:
|
|
20
|
-
write(id:
|
|
21
|
-
delete(id:
|
|
18
|
+
id(isLeaf: boolean): Promise<string>;
|
|
19
|
+
read(id: string): Promise<BPTreeNode<K, V>>;
|
|
20
|
+
write(id: string, node: BPTreeNode<K, V>): Promise<void>;
|
|
21
|
+
delete(id: string): Promise<void>;
|
|
22
22
|
readHead(): Promise<SerializeStrategyHead | null>;
|
|
23
23
|
writeHead(head: SerializeStrategyHead): Promise<void>;
|
|
24
24
|
}
|
|
@@ -2,10 +2,10 @@ import { BPTreeNode } from './base/BPTree';
|
|
|
2
2
|
import { SerializeStrategy, SerializeStrategyHead } from './base/SerializeStrategy';
|
|
3
3
|
import { Json } from './utils/types';
|
|
4
4
|
export declare abstract class SerializeStrategySync<K, V> extends SerializeStrategy<K, V> {
|
|
5
|
-
abstract id(isLeaf: boolean):
|
|
6
|
-
abstract read(id:
|
|
7
|
-
abstract write(id:
|
|
8
|
-
abstract delete(id:
|
|
5
|
+
abstract id(isLeaf: boolean): string;
|
|
6
|
+
abstract read(id: string): BPTreeNode<K, V>;
|
|
7
|
+
abstract write(id: string, node: BPTreeNode<K, V>): void;
|
|
8
|
+
abstract delete(id: string): void;
|
|
9
9
|
abstract readHead(): SerializeStrategyHead | null;
|
|
10
10
|
abstract writeHead(head: SerializeStrategyHead): void;
|
|
11
11
|
getHeadData(key: string, defaultValue: Json): Json;
|
|
@@ -13,12 +13,12 @@ export declare abstract class SerializeStrategySync<K, V> extends SerializeStrat
|
|
|
13
13
|
autoIncrement(key: string, defaultValue: number): number;
|
|
14
14
|
}
|
|
15
15
|
export declare class InMemoryStoreStrategySync<K, V> extends SerializeStrategySync<K, V> {
|
|
16
|
-
protected readonly node: Record<
|
|
16
|
+
protected readonly node: Record<string, BPTreeNode<K, V>>;
|
|
17
17
|
constructor(order: number);
|
|
18
|
-
id(isLeaf: boolean):
|
|
19
|
-
read(id:
|
|
20
|
-
write(id:
|
|
21
|
-
delete(id:
|
|
18
|
+
id(isLeaf: boolean): string;
|
|
19
|
+
read(id: string): BPTreeNode<K, V>;
|
|
20
|
+
write(id: string, node: BPTreeNode<K, V>): void;
|
|
21
|
+
delete(id: string): void;
|
|
22
22
|
readHead(): SerializeStrategyHead | null;
|
|
23
23
|
writeHead(head: SerializeStrategyHead): void;
|
|
24
24
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { ValueComparator } from './ValueComparator';
|
|
2
2
|
import { SerializableData, SerializeStrategy } from './SerializeStrategy';
|
|
3
|
+
import { InvertedWeakMap } from '../utils/InvertedWeakMap';
|
|
3
4
|
type Sync<T> = T;
|
|
4
5
|
type Async<T> = Promise<T>;
|
|
5
6
|
type Deferred<T> = Sync<T> | Async<T>;
|
|
6
|
-
export type BPTreeNodeKey<K> =
|
|
7
|
+
export type BPTreeNodeKey<K> = string | K;
|
|
7
8
|
export type BPTreeCondition<V> = Partial<{
|
|
8
9
|
/** Searches for pairs greater than the given value. */
|
|
9
10
|
gt: Partial<V>;
|
|
@@ -26,17 +27,17 @@ export type BPTreePair<K, V> = {
|
|
|
26
27
|
};
|
|
27
28
|
export type BPTreeUnknownNode<K, V> = BPTreeInternalNode<K, V> | BPTreeLeafNode<K, V>;
|
|
28
29
|
export interface BPTreeNode<K, V> {
|
|
29
|
-
id:
|
|
30
|
-
keys:
|
|
30
|
+
id: string;
|
|
31
|
+
keys: string[] | K[][];
|
|
31
32
|
values: V[];
|
|
32
33
|
leaf: boolean;
|
|
33
|
-
parent:
|
|
34
|
-
next:
|
|
35
|
-
prev:
|
|
34
|
+
parent: string | null;
|
|
35
|
+
next: string | null;
|
|
36
|
+
prev: string | null;
|
|
36
37
|
}
|
|
37
38
|
export interface BPTreeInternalNode<K, V> extends BPTreeNode<K, V> {
|
|
38
39
|
leaf: false;
|
|
39
|
-
keys:
|
|
40
|
+
keys: string[];
|
|
40
41
|
}
|
|
41
42
|
export interface BPTreeLeafNode<K, V> extends BPTreeNode<K, V> {
|
|
42
43
|
leaf: true;
|
|
@@ -46,12 +47,12 @@ export declare abstract class BPTree<K, V> {
|
|
|
46
47
|
private readonly _cachedRegexp;
|
|
47
48
|
protected readonly strategy: SerializeStrategy<K, V>;
|
|
48
49
|
protected readonly comparator: ValueComparator<V>;
|
|
49
|
-
protected readonly nodes:
|
|
50
|
+
protected readonly nodes: InvertedWeakMap<string, BPTreeUnknownNode<K, V>>;
|
|
50
51
|
protected order: number;
|
|
51
52
|
protected root: BPTreeUnknownNode<K, V>;
|
|
52
|
-
protected readonly _nodeCreateBuffer: Map<
|
|
53
|
-
protected readonly _nodeUpdateBuffer: Map<
|
|
54
|
-
protected readonly _nodeDeleteBuffer: Map<
|
|
53
|
+
protected readonly _nodeCreateBuffer: Map<string, BPTreeUnknownNode<K, V>>;
|
|
54
|
+
protected readonly _nodeUpdateBuffer: Map<string, BPTreeUnknownNode<K, V>>;
|
|
55
|
+
protected readonly _nodeDeleteBuffer: Map<string, BPTreeUnknownNode<K, V>>;
|
|
55
56
|
protected readonly verifierMap: Record<keyof BPTreeCondition<V>, (nodeValue: V, value: V) => boolean>;
|
|
56
57
|
protected readonly verifierStartNode: Record<keyof BPTreeCondition<V>, (value: V) => Deferred<BPTreeLeafNode<K, V>>>;
|
|
57
58
|
protected readonly verifierDirection: Record<keyof BPTreeCondition<V>, -1 | 1>;
|
|
@@ -60,11 +61,11 @@ export declare abstract class BPTree<K, V> {
|
|
|
60
61
|
protected abstract _getPairsRightToLeft(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean): Deferred<BPTreePair<K, V>[]>;
|
|
61
62
|
protected abstract _getPairsLeftToRight(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean): Deferred<BPTreePair<K, V>[]>;
|
|
62
63
|
protected abstract getPairs(value: V, startNode: BPTreeLeafNode<K, V>, fullScan: boolean, comparator: (nodeValue: V, value: V) => boolean, direction: -1 | 1): Deferred<BPTreePair<K, V>[]>;
|
|
63
|
-
protected abstract _createNodeId(isLeaf: boolean): Deferred<
|
|
64
|
-
protected abstract _createNode(isLeaf: boolean, keys:
|
|
64
|
+
protected abstract _createNodeId(isLeaf: boolean): Deferred<string>;
|
|
65
|
+
protected abstract _createNode(isLeaf: boolean, keys: string[] | K[][], values: V[], leaf?: boolean, parent?: string | null, next?: string | null, prev?: string | null): Deferred<BPTreeUnknownNode<K, V>>;
|
|
65
66
|
protected abstract _deleteEntry(node: BPTreeUnknownNode<K, V>, key: BPTreeNodeKey<K>, value: V): Deferred<void>;
|
|
66
67
|
protected abstract _insertInParent(node: BPTreeUnknownNode<K, V>, value: V, pointer: BPTreeUnknownNode<K, V>): Deferred<void>;
|
|
67
|
-
protected abstract getNode(id:
|
|
68
|
+
protected abstract getNode(id: string): Deferred<BPTreeUnknownNode<K, V>>;
|
|
68
69
|
protected abstract insertableNode(value: V): Deferred<BPTreeLeafNode<K, V>>;
|
|
69
70
|
protected abstract leftestNode(): Deferred<BPTreeLeafNode<K, V>>;
|
|
70
71
|
protected abstract commitHeadBuffer(): Deferred<void>;
|
|
@@ -2,7 +2,7 @@ import { BPTreeNode } from './BPTree';
|
|
|
2
2
|
import type { Json } from '../utils/types';
|
|
3
3
|
export type SerializableData = Record<string, Json>;
|
|
4
4
|
export interface SerializeStrategyHead {
|
|
5
|
-
root:
|
|
5
|
+
root: string | null;
|
|
6
6
|
order: number;
|
|
7
7
|
data: SerializableData;
|
|
8
8
|
}
|
|
@@ -14,29 +14,28 @@ export declare abstract class SerializeStrategy<K, V> {
|
|
|
14
14
|
* The rule for generating node IDs is set.
|
|
15
15
|
* When a new node is created within the tree, the value returned by this method becomes the node's ID.
|
|
16
16
|
*
|
|
17
|
-
* **WARNING!** The return value should never be `0`.
|
|
18
17
|
* @param isLeaf This is a flag that indicates whether the node is a leaf node or not.
|
|
19
18
|
*/
|
|
20
|
-
abstract id(isLeaf: boolean):
|
|
19
|
+
abstract id(isLeaf: boolean): string | Promise<string>;
|
|
21
20
|
/**
|
|
22
21
|
* Read the stored node from the ID.
|
|
23
22
|
* The JSON object of the read node should be returned.
|
|
24
23
|
* @param id This is the ID of the node to be read.
|
|
25
24
|
*/
|
|
26
|
-
abstract read(id:
|
|
25
|
+
abstract read(id: string): BPTreeNode<K, V> | Promise<BPTreeNode<K, V>>;
|
|
27
26
|
/**
|
|
28
27
|
* It is called when a node is created or updated and needs to be stored.
|
|
29
28
|
* The node ID and the node JSON object are passed as parameters. Use this to store the data.
|
|
30
29
|
* @param id This is the ID of the node to be stored.
|
|
31
30
|
* @param node This is the JSON object of the node to be stored.
|
|
32
31
|
*/
|
|
33
|
-
abstract write(id:
|
|
32
|
+
abstract write(id: string, node: BPTreeNode<K, V>): void | Promise<void>;
|
|
34
33
|
/**
|
|
35
34
|
* This method is called when previously created nodes become no longer needed due to deletion or other processes.
|
|
36
35
|
* It can be used to free up space by deleting existing stored nodes.
|
|
37
36
|
* @param id This is the ID of the node to be deleted.
|
|
38
37
|
*/
|
|
39
|
-
abstract delete(id:
|
|
38
|
+
abstract delete(id: string): void | Promise<void>;
|
|
40
39
|
/**
|
|
41
40
|
* It is called when the `init` method of the tree instance is called.
|
|
42
41
|
* This method should return the information needed to initialize the tree. This information refers to the values stored in the `writeHead` method.
|
|
@@ -53,7 +52,7 @@ export declare abstract class SerializeStrategy<K, V> {
|
|
|
53
52
|
abstract writeHead(head: SerializeStrategyHead): void | Promise<void>;
|
|
54
53
|
/**
|
|
55
54
|
* Retrieves the data stored in the tree.
|
|
56
|
-
* If
|
|
55
|
+
* If no value is stored in the tree, it stores a `defaultValue` and then returns that value.
|
|
57
56
|
* @param key The key of the data stored in the tree.
|
|
58
57
|
*/
|
|
59
58
|
abstract getHeadData(key: string, defaultValue: Json): Json | Promise<Json>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare class InvertedWeakMap<K extends string | number | symbol, V extends WeakKey> {
|
|
2
|
+
private readonly _map;
|
|
3
|
+
private readonly _registry;
|
|
4
|
+
constructor();
|
|
5
|
+
clear(): void;
|
|
6
|
+
delete(key: K): boolean;
|
|
7
|
+
get(key: K): V | undefined;
|
|
8
|
+
has(key: K): boolean;
|
|
9
|
+
set(key: K, value: V): this;
|
|
10
|
+
get size(): number;
|
|
11
|
+
keys(): IterableIterator<K>;
|
|
12
|
+
}
|