serializable-bptree 8.1.0 → 8.1.2
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 +10 -11
- package/dist/cjs/index.cjs +98 -142
- package/dist/esm/index.mjs +98 -142
- package/dist/types/base/BPTreeTransaction.d.ts +4 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -134,7 +134,7 @@ Explore the detailed guides and concepts of `serializable-bptree`:
|
|
|
134
134
|
- [Best Practices](./docs/BEST_PRACTICES.md): Tips for bulk insertion and performance optimization.
|
|
135
135
|
- [Duplicate Value Handling](./docs/DUPLICATE_VALUES.md): Strategies for managing large amounts of duplicate data.
|
|
136
136
|
- [Concurrency & Synchronization](./docs/CONCURRENCY.md): Multi-instance usage and locking mechanisms.
|
|
137
|
-
- [Query Optimization Guide](./docs/QUERY.md#performance--optimization): How to use `ChooseDriver
|
|
137
|
+
- [Query Optimization Guide](./docs/QUERY.md#performance--optimization): How to use `ChooseDriver` and `keys()` for complex queries.
|
|
138
138
|
|
|
139
139
|
## Quick Example: Query Optimization
|
|
140
140
|
|
|
@@ -144,19 +144,20 @@ When you have multiple indexes (e.g., an index for `id` and another for `age`),
|
|
|
144
144
|
const query = { id: { equal: 100 }, age: { gt: 20 } }
|
|
145
145
|
|
|
146
146
|
// 1. Select the best index based on condition priority
|
|
147
|
-
const
|
|
147
|
+
const candidates = [
|
|
148
148
|
{ tree: idxId, condition: query.id },
|
|
149
149
|
{ tree: idxAge, condition: query.age }
|
|
150
|
-
]
|
|
150
|
+
]
|
|
151
|
+
const driver = BPTreeSync.ChooseDriver(candidates)
|
|
152
|
+
const others = candidates.filter((c) => driver.tree !== c.tree)
|
|
151
153
|
|
|
152
154
|
// 2. Execute query using the selected driver
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
if (age !== undefined && idxAge.verify(age, query.age)) {
|
|
157
|
-
console.log(`Match found! PK: ${pk}`)
|
|
158
|
-
}
|
|
155
|
+
let keys = driver.tree.keys(driver.condition)
|
|
156
|
+
for (const { tree, condition } of others) {
|
|
157
|
+
keys = tree.keys(condition, keys)
|
|
159
158
|
}
|
|
159
|
+
|
|
160
|
+
console.log('Found: ', keys)
|
|
160
161
|
```
|
|
161
162
|
|
|
162
163
|
## Migration
|
|
@@ -165,6 +166,4 @@ Instructions for migrating between major versions (e.g., v8.0.0, v6.0.0) can be
|
|
|
165
166
|
|
|
166
167
|
## LICENSE
|
|
167
168
|
|
|
168
|
-
## LICENSE
|
|
169
|
-
|
|
170
169
|
MIT LICENSE
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -222,6 +222,45 @@ var MVCCTransaction = class {
|
|
|
222
222
|
}
|
|
223
223
|
return { success: true, created, updated, deleted };
|
|
224
224
|
}
|
|
225
|
+
/**
|
|
226
|
+
* Cleans up both deletedCache and versionIndex based on minActiveVersion.
|
|
227
|
+
* Root transactions call this after commit to reclaim memory.
|
|
228
|
+
*/
|
|
229
|
+
_cleanupDeletedCache() {
|
|
230
|
+
if (this.deletedCache.size === 0 && this.versionIndex.size === 0) return;
|
|
231
|
+
let minActiveVersion = this.version;
|
|
232
|
+
if (this.activeTransactions.size > 0) {
|
|
233
|
+
for (const tx of this.activeTransactions) {
|
|
234
|
+
if (!tx.committed && tx.snapshotVersion < minActiveVersion) {
|
|
235
|
+
minActiveVersion = tx.snapshotVersion;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
if (this.deletedCache.size > 0) {
|
|
240
|
+
for (const [key, cachedList] of this.deletedCache) {
|
|
241
|
+
const remaining = cachedList.filter((item) => item.deletedAtVersion > minActiveVersion);
|
|
242
|
+
if (remaining.length === 0) {
|
|
243
|
+
this.deletedCache.delete(key);
|
|
244
|
+
} else {
|
|
245
|
+
this.deletedCache.set(key, remaining);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
if (this.versionIndex.size > 0) {
|
|
250
|
+
for (const [key, versions] of this.versionIndex) {
|
|
251
|
+
let latestInSnapshotIdx = -1;
|
|
252
|
+
for (let i = versions.length - 1; i >= 0; i--) {
|
|
253
|
+
if (versions[i].version <= minActiveVersion) {
|
|
254
|
+
latestInSnapshotIdx = i;
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (latestInSnapshotIdx > 0) {
|
|
259
|
+
versions.splice(0, latestInSnapshotIdx);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
225
264
|
};
|
|
226
265
|
var SyncMVCCStrategy = class extends MVCCStrategy {
|
|
227
266
|
};
|
|
@@ -561,25 +600,6 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
561
600
|
if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
|
|
562
601
|
this.versionIndex.get(key).push({ version: snapshotVersion, exists: false });
|
|
563
602
|
}
|
|
564
|
-
_cleanupDeletedCache() {
|
|
565
|
-
if (this.deletedCache.size === 0) return;
|
|
566
|
-
let minActiveVersion = this.version;
|
|
567
|
-
if (this.activeTransactions.size > 0) {
|
|
568
|
-
for (const tx of this.activeTransactions) {
|
|
569
|
-
if (!tx.committed && tx.snapshotVersion < minActiveVersion) {
|
|
570
|
-
minActiveVersion = tx.snapshotVersion;
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
for (const [key, cachedList] of this.deletedCache) {
|
|
575
|
-
const remaining = cachedList.filter((item) => item.deletedAtVersion > minActiveVersion);
|
|
576
|
-
if (remaining.length === 0) {
|
|
577
|
-
this.deletedCache.delete(key);
|
|
578
|
-
} else {
|
|
579
|
-
this.deletedCache.set(key, remaining);
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
603
|
};
|
|
584
604
|
var AsyncMVCCStrategy = class extends MVCCStrategy {
|
|
585
605
|
};
|
|
@@ -1188,25 +1208,6 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
1188
1208
|
if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
|
|
1189
1209
|
this.versionIndex.get(key).push({ version: snapshotVersion, exists: false });
|
|
1190
1210
|
}
|
|
1191
|
-
_cleanupDeletedCache() {
|
|
1192
|
-
if (this.deletedCache.size === 0) return;
|
|
1193
|
-
let minActiveVersion = this.version;
|
|
1194
|
-
if (this.activeTransactions.size > 0) {
|
|
1195
|
-
for (const tx of this.activeTransactions) {
|
|
1196
|
-
if (!tx.committed && tx.snapshotVersion < minActiveVersion) {
|
|
1197
|
-
minActiveVersion = tx.snapshotVersion;
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
}
|
|
1201
|
-
for (const [key, cachedList] of this.deletedCache) {
|
|
1202
|
-
const remaining = cachedList.filter((item) => item.deletedAtVersion > minActiveVersion);
|
|
1203
|
-
if (remaining.length === 0) {
|
|
1204
|
-
this.deletedCache.delete(key);
|
|
1205
|
-
} else {
|
|
1206
|
-
this.deletedCache.set(key, remaining);
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
}
|
|
1210
1211
|
};
|
|
1211
1212
|
|
|
1212
1213
|
// node_modules/cache-entanglement/dist/esm/index.mjs
|
|
@@ -1817,6 +1818,25 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1817
1818
|
this._cachedRegexp.clear();
|
|
1818
1819
|
this.nodes.clear();
|
|
1819
1820
|
}
|
|
1821
|
+
_binarySearchValues(values, target, usePrimary = false, upperBound = false) {
|
|
1822
|
+
let low = 0;
|
|
1823
|
+
let high = values.length;
|
|
1824
|
+
let found = false;
|
|
1825
|
+
while (low < high) {
|
|
1826
|
+
const mid = low + high >>> 1;
|
|
1827
|
+
const cmp = usePrimary ? this.comparator.primaryAsc(target, values[mid]) : this.comparator.asc(target, values[mid]);
|
|
1828
|
+
if (cmp === 0) {
|
|
1829
|
+
found = true;
|
|
1830
|
+
if (upperBound) low = mid + 1;
|
|
1831
|
+
else high = mid;
|
|
1832
|
+
} else if (cmp < 0) {
|
|
1833
|
+
high = mid;
|
|
1834
|
+
} else {
|
|
1835
|
+
low = mid + 1;
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
return { index: low, found };
|
|
1839
|
+
}
|
|
1820
1840
|
};
|
|
1821
1841
|
|
|
1822
1842
|
// src/transaction/BPTreeSyncTransaction.ts
|
|
@@ -1978,58 +1998,24 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
1978
1998
|
insertableNode(value) {
|
|
1979
1999
|
let node = this.getNode(this.rootId);
|
|
1980
2000
|
while (!node.leaf) {
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
const k = node.keys;
|
|
1984
|
-
if (this.comparator.isSame(value, nValue)) {
|
|
1985
|
-
node = this.getNode(k[i + 1]);
|
|
1986
|
-
break;
|
|
1987
|
-
} else if (this.comparator.isLower(value, nValue)) {
|
|
1988
|
-
node = this.getNode(k[i]);
|
|
1989
|
-
break;
|
|
1990
|
-
} else if (i + 1 === node.values.length) {
|
|
1991
|
-
node = this.getNode(k[i + 1]);
|
|
1992
|
-
break;
|
|
1993
|
-
}
|
|
1994
|
-
}
|
|
2001
|
+
const { index } = this._binarySearchValues(node.values, value, false, true);
|
|
2002
|
+
node = this.getNode(node.keys[index]);
|
|
1995
2003
|
}
|
|
1996
2004
|
return node;
|
|
1997
2005
|
}
|
|
1998
2006
|
insertableNodeByPrimary(value) {
|
|
1999
2007
|
let node = this.getNode(this.rootId);
|
|
2000
2008
|
while (!node.leaf) {
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
const k = node.keys;
|
|
2004
|
-
if (this.comparator.isPrimarySame(value, nValue)) {
|
|
2005
|
-
node = this.getNode(k[i]);
|
|
2006
|
-
break;
|
|
2007
|
-
} else if (this.comparator.isPrimaryLower(value, nValue)) {
|
|
2008
|
-
node = this.getNode(k[i]);
|
|
2009
|
-
break;
|
|
2010
|
-
} else if (i + 1 === node.values.length) {
|
|
2011
|
-
node = this.getNode(k[i + 1]);
|
|
2012
|
-
break;
|
|
2013
|
-
}
|
|
2014
|
-
}
|
|
2009
|
+
const { index } = this._binarySearchValues(node.values, value, true, false);
|
|
2010
|
+
node = this.getNode(node.keys[index]);
|
|
2015
2011
|
}
|
|
2016
2012
|
return node;
|
|
2017
2013
|
}
|
|
2018
2014
|
insertableRightestNodeByPrimary(value) {
|
|
2019
2015
|
let node = this.getNode(this.rootId);
|
|
2020
2016
|
while (!node.leaf) {
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
const k = node.keys;
|
|
2024
|
-
if (this.comparator.isPrimaryLower(value, nValue)) {
|
|
2025
|
-
node = this.getNode(k[i]);
|
|
2026
|
-
break;
|
|
2027
|
-
}
|
|
2028
|
-
if (i + 1 === node.values.length) {
|
|
2029
|
-
node = this.getNode(k[i + 1]);
|
|
2030
|
-
break;
|
|
2031
|
-
}
|
|
2032
|
-
}
|
|
2017
|
+
const { index } = this._binarySearchValues(node.values, value, true, true);
|
|
2018
|
+
node = this.getNode(node.keys[index]);
|
|
2033
2019
|
}
|
|
2034
2020
|
return node;
|
|
2035
2021
|
}
|
|
@@ -2162,12 +2148,11 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2162
2148
|
}
|
|
2163
2149
|
exists(key, value) {
|
|
2164
2150
|
const node = this.insertableNode(value);
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
}
|
|
2151
|
+
const { index, found } = this._binarySearchValues(node.values, value);
|
|
2152
|
+
if (found) {
|
|
2153
|
+
const keys = node.keys[index];
|
|
2154
|
+
if (keys.includes(key)) {
|
|
2155
|
+
return true;
|
|
2171
2156
|
}
|
|
2172
2157
|
}
|
|
2173
2158
|
return false;
|
|
@@ -2803,58 +2788,24 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
2803
2788
|
async insertableNode(value) {
|
|
2804
2789
|
let node = await this.getNode(this.rootId);
|
|
2805
2790
|
while (!node.leaf) {
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
const k = node.keys;
|
|
2809
|
-
if (this.comparator.isSame(value, nValue)) {
|
|
2810
|
-
node = await this.getNode(k[i + 1]);
|
|
2811
|
-
break;
|
|
2812
|
-
} else if (this.comparator.isLower(value, nValue)) {
|
|
2813
|
-
node = await this.getNode(k[i]);
|
|
2814
|
-
break;
|
|
2815
|
-
} else if (i + 1 === node.values.length) {
|
|
2816
|
-
node = await this.getNode(k[i + 1]);
|
|
2817
|
-
break;
|
|
2818
|
-
}
|
|
2819
|
-
}
|
|
2791
|
+
const { index } = this._binarySearchValues(node.values, value, false, true);
|
|
2792
|
+
node = await this.getNode(node.keys[index]);
|
|
2820
2793
|
}
|
|
2821
2794
|
return node;
|
|
2822
2795
|
}
|
|
2823
2796
|
async insertableNodeByPrimary(value) {
|
|
2824
2797
|
let node = await this.getNode(this.rootId);
|
|
2825
2798
|
while (!node.leaf) {
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
const k = node.keys;
|
|
2829
|
-
if (this.comparator.isPrimarySame(value, nValue)) {
|
|
2830
|
-
node = await this.getNode(k[i]);
|
|
2831
|
-
break;
|
|
2832
|
-
} else if (this.comparator.isPrimaryLower(value, nValue)) {
|
|
2833
|
-
node = await this.getNode(k[i]);
|
|
2834
|
-
break;
|
|
2835
|
-
} else if (i + 1 === node.values.length) {
|
|
2836
|
-
node = await this.getNode(k[i + 1]);
|
|
2837
|
-
break;
|
|
2838
|
-
}
|
|
2839
|
-
}
|
|
2799
|
+
const { index } = this._binarySearchValues(node.values, value, true, false);
|
|
2800
|
+
node = await this.getNode(node.keys[index]);
|
|
2840
2801
|
}
|
|
2841
2802
|
return node;
|
|
2842
2803
|
}
|
|
2843
2804
|
async insertableRightestNodeByPrimary(value) {
|
|
2844
2805
|
let node = await this.getNode(this.rootId);
|
|
2845
2806
|
while (!node.leaf) {
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
const k = node.keys;
|
|
2849
|
-
if (this.comparator.isPrimaryLower(value, nValue)) {
|
|
2850
|
-
node = await this.getNode(k[i]);
|
|
2851
|
-
break;
|
|
2852
|
-
}
|
|
2853
|
-
if (i + 1 === node.values.length) {
|
|
2854
|
-
node = await this.getNode(k[i + 1]);
|
|
2855
|
-
break;
|
|
2856
|
-
}
|
|
2857
|
-
}
|
|
2807
|
+
const { index } = this._binarySearchValues(node.values, value, true, true);
|
|
2808
|
+
node = await this.getNode(node.keys[index]);
|
|
2858
2809
|
}
|
|
2859
2810
|
return node;
|
|
2860
2811
|
}
|
|
@@ -2907,11 +2858,21 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
2907
2858
|
let node = startNode;
|
|
2908
2859
|
let done = false;
|
|
2909
2860
|
let hasMatched = false;
|
|
2861
|
+
let nextNodePromise = null;
|
|
2910
2862
|
while (!done) {
|
|
2911
2863
|
if (endNode && node.id === endNode.id) {
|
|
2912
2864
|
done = true;
|
|
2913
2865
|
break;
|
|
2914
2866
|
}
|
|
2867
|
+
if (direction === 1) {
|
|
2868
|
+
if (node.next && !done) {
|
|
2869
|
+
nextNodePromise = this.getNode(node.next);
|
|
2870
|
+
}
|
|
2871
|
+
} else {
|
|
2872
|
+
if (node.prev && !done) {
|
|
2873
|
+
nextNodePromise = this.getNode(node.prev);
|
|
2874
|
+
}
|
|
2875
|
+
}
|
|
2915
2876
|
const len = node.values.length;
|
|
2916
2877
|
if (direction === 1) {
|
|
2917
2878
|
for (let i = 0; i < len; i++) {
|
|
@@ -2944,19 +2905,15 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
2944
2905
|
}
|
|
2945
2906
|
}
|
|
2946
2907
|
}
|
|
2947
|
-
if (done)
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2908
|
+
if (done) {
|
|
2909
|
+
if (nextNodePromise) await nextNodePromise;
|
|
2910
|
+
break;
|
|
2911
|
+
}
|
|
2912
|
+
if (nextNodePromise) {
|
|
2913
|
+
node = await nextNodePromise;
|
|
2914
|
+
nextNodePromise = null;
|
|
2954
2915
|
} else {
|
|
2955
|
-
|
|
2956
|
-
done = true;
|
|
2957
|
-
break;
|
|
2958
|
-
}
|
|
2959
|
-
node = await this.getNode(node.prev);
|
|
2916
|
+
done = true;
|
|
2960
2917
|
}
|
|
2961
2918
|
}
|
|
2962
2919
|
}
|
|
@@ -2987,12 +2944,11 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
2987
2944
|
}
|
|
2988
2945
|
async exists(key, value) {
|
|
2989
2946
|
const node = await this.insertableNode(value);
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
}
|
|
2947
|
+
const { index, found } = this._binarySearchValues(node.values, value);
|
|
2948
|
+
if (found) {
|
|
2949
|
+
const keys = node.keys[index];
|
|
2950
|
+
if (keys.includes(key)) {
|
|
2951
|
+
return true;
|
|
2996
2952
|
}
|
|
2997
2953
|
}
|
|
2998
2954
|
return false;
|
package/dist/esm/index.mjs
CHANGED
|
@@ -186,6 +186,45 @@ var MVCCTransaction = class {
|
|
|
186
186
|
}
|
|
187
187
|
return { success: true, created, updated, deleted };
|
|
188
188
|
}
|
|
189
|
+
/**
|
|
190
|
+
* Cleans up both deletedCache and versionIndex based on minActiveVersion.
|
|
191
|
+
* Root transactions call this after commit to reclaim memory.
|
|
192
|
+
*/
|
|
193
|
+
_cleanupDeletedCache() {
|
|
194
|
+
if (this.deletedCache.size === 0 && this.versionIndex.size === 0) return;
|
|
195
|
+
let minActiveVersion = this.version;
|
|
196
|
+
if (this.activeTransactions.size > 0) {
|
|
197
|
+
for (const tx of this.activeTransactions) {
|
|
198
|
+
if (!tx.committed && tx.snapshotVersion < minActiveVersion) {
|
|
199
|
+
minActiveVersion = tx.snapshotVersion;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
if (this.deletedCache.size > 0) {
|
|
204
|
+
for (const [key, cachedList] of this.deletedCache) {
|
|
205
|
+
const remaining = cachedList.filter((item) => item.deletedAtVersion > minActiveVersion);
|
|
206
|
+
if (remaining.length === 0) {
|
|
207
|
+
this.deletedCache.delete(key);
|
|
208
|
+
} else {
|
|
209
|
+
this.deletedCache.set(key, remaining);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (this.versionIndex.size > 0) {
|
|
214
|
+
for (const [key, versions] of this.versionIndex) {
|
|
215
|
+
let latestInSnapshotIdx = -1;
|
|
216
|
+
for (let i = versions.length - 1; i >= 0; i--) {
|
|
217
|
+
if (versions[i].version <= minActiveVersion) {
|
|
218
|
+
latestInSnapshotIdx = i;
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if (latestInSnapshotIdx > 0) {
|
|
223
|
+
versions.splice(0, latestInSnapshotIdx);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
189
228
|
};
|
|
190
229
|
var SyncMVCCStrategy = class extends MVCCStrategy {
|
|
191
230
|
};
|
|
@@ -525,25 +564,6 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
525
564
|
if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
|
|
526
565
|
this.versionIndex.get(key).push({ version: snapshotVersion, exists: false });
|
|
527
566
|
}
|
|
528
|
-
_cleanupDeletedCache() {
|
|
529
|
-
if (this.deletedCache.size === 0) return;
|
|
530
|
-
let minActiveVersion = this.version;
|
|
531
|
-
if (this.activeTransactions.size > 0) {
|
|
532
|
-
for (const tx of this.activeTransactions) {
|
|
533
|
-
if (!tx.committed && tx.snapshotVersion < minActiveVersion) {
|
|
534
|
-
minActiveVersion = tx.snapshotVersion;
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
for (const [key, cachedList] of this.deletedCache) {
|
|
539
|
-
const remaining = cachedList.filter((item) => item.deletedAtVersion > minActiveVersion);
|
|
540
|
-
if (remaining.length === 0) {
|
|
541
|
-
this.deletedCache.delete(key);
|
|
542
|
-
} else {
|
|
543
|
-
this.deletedCache.set(key, remaining);
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
567
|
};
|
|
548
568
|
var AsyncMVCCStrategy = class extends MVCCStrategy {
|
|
549
569
|
};
|
|
@@ -1152,25 +1172,6 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
1152
1172
|
if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
|
|
1153
1173
|
this.versionIndex.get(key).push({ version: snapshotVersion, exists: false });
|
|
1154
1174
|
}
|
|
1155
|
-
_cleanupDeletedCache() {
|
|
1156
|
-
if (this.deletedCache.size === 0) return;
|
|
1157
|
-
let minActiveVersion = this.version;
|
|
1158
|
-
if (this.activeTransactions.size > 0) {
|
|
1159
|
-
for (const tx of this.activeTransactions) {
|
|
1160
|
-
if (!tx.committed && tx.snapshotVersion < minActiveVersion) {
|
|
1161
|
-
minActiveVersion = tx.snapshotVersion;
|
|
1162
|
-
}
|
|
1163
|
-
}
|
|
1164
|
-
}
|
|
1165
|
-
for (const [key, cachedList] of this.deletedCache) {
|
|
1166
|
-
const remaining = cachedList.filter((item) => item.deletedAtVersion > minActiveVersion);
|
|
1167
|
-
if (remaining.length === 0) {
|
|
1168
|
-
this.deletedCache.delete(key);
|
|
1169
|
-
} else {
|
|
1170
|
-
this.deletedCache.set(key, remaining);
|
|
1171
|
-
}
|
|
1172
|
-
}
|
|
1173
|
-
}
|
|
1174
1175
|
};
|
|
1175
1176
|
|
|
1176
1177
|
// node_modules/cache-entanglement/dist/esm/index.mjs
|
|
@@ -1781,6 +1782,25 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1781
1782
|
this._cachedRegexp.clear();
|
|
1782
1783
|
this.nodes.clear();
|
|
1783
1784
|
}
|
|
1785
|
+
_binarySearchValues(values, target, usePrimary = false, upperBound = false) {
|
|
1786
|
+
let low = 0;
|
|
1787
|
+
let high = values.length;
|
|
1788
|
+
let found = false;
|
|
1789
|
+
while (low < high) {
|
|
1790
|
+
const mid = low + high >>> 1;
|
|
1791
|
+
const cmp = usePrimary ? this.comparator.primaryAsc(target, values[mid]) : this.comparator.asc(target, values[mid]);
|
|
1792
|
+
if (cmp === 0) {
|
|
1793
|
+
found = true;
|
|
1794
|
+
if (upperBound) low = mid + 1;
|
|
1795
|
+
else high = mid;
|
|
1796
|
+
} else if (cmp < 0) {
|
|
1797
|
+
high = mid;
|
|
1798
|
+
} else {
|
|
1799
|
+
low = mid + 1;
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
return { index: low, found };
|
|
1803
|
+
}
|
|
1784
1804
|
};
|
|
1785
1805
|
|
|
1786
1806
|
// src/transaction/BPTreeSyncTransaction.ts
|
|
@@ -1942,58 +1962,24 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
1942
1962
|
insertableNode(value) {
|
|
1943
1963
|
let node = this.getNode(this.rootId);
|
|
1944
1964
|
while (!node.leaf) {
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
const k = node.keys;
|
|
1948
|
-
if (this.comparator.isSame(value, nValue)) {
|
|
1949
|
-
node = this.getNode(k[i + 1]);
|
|
1950
|
-
break;
|
|
1951
|
-
} else if (this.comparator.isLower(value, nValue)) {
|
|
1952
|
-
node = this.getNode(k[i]);
|
|
1953
|
-
break;
|
|
1954
|
-
} else if (i + 1 === node.values.length) {
|
|
1955
|
-
node = this.getNode(k[i + 1]);
|
|
1956
|
-
break;
|
|
1957
|
-
}
|
|
1958
|
-
}
|
|
1965
|
+
const { index } = this._binarySearchValues(node.values, value, false, true);
|
|
1966
|
+
node = this.getNode(node.keys[index]);
|
|
1959
1967
|
}
|
|
1960
1968
|
return node;
|
|
1961
1969
|
}
|
|
1962
1970
|
insertableNodeByPrimary(value) {
|
|
1963
1971
|
let node = this.getNode(this.rootId);
|
|
1964
1972
|
while (!node.leaf) {
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
const k = node.keys;
|
|
1968
|
-
if (this.comparator.isPrimarySame(value, nValue)) {
|
|
1969
|
-
node = this.getNode(k[i]);
|
|
1970
|
-
break;
|
|
1971
|
-
} else if (this.comparator.isPrimaryLower(value, nValue)) {
|
|
1972
|
-
node = this.getNode(k[i]);
|
|
1973
|
-
break;
|
|
1974
|
-
} else if (i + 1 === node.values.length) {
|
|
1975
|
-
node = this.getNode(k[i + 1]);
|
|
1976
|
-
break;
|
|
1977
|
-
}
|
|
1978
|
-
}
|
|
1973
|
+
const { index } = this._binarySearchValues(node.values, value, true, false);
|
|
1974
|
+
node = this.getNode(node.keys[index]);
|
|
1979
1975
|
}
|
|
1980
1976
|
return node;
|
|
1981
1977
|
}
|
|
1982
1978
|
insertableRightestNodeByPrimary(value) {
|
|
1983
1979
|
let node = this.getNode(this.rootId);
|
|
1984
1980
|
while (!node.leaf) {
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
const k = node.keys;
|
|
1988
|
-
if (this.comparator.isPrimaryLower(value, nValue)) {
|
|
1989
|
-
node = this.getNode(k[i]);
|
|
1990
|
-
break;
|
|
1991
|
-
}
|
|
1992
|
-
if (i + 1 === node.values.length) {
|
|
1993
|
-
node = this.getNode(k[i + 1]);
|
|
1994
|
-
break;
|
|
1995
|
-
}
|
|
1996
|
-
}
|
|
1981
|
+
const { index } = this._binarySearchValues(node.values, value, true, true);
|
|
1982
|
+
node = this.getNode(node.keys[index]);
|
|
1997
1983
|
}
|
|
1998
1984
|
return node;
|
|
1999
1985
|
}
|
|
@@ -2126,12 +2112,11 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2126
2112
|
}
|
|
2127
2113
|
exists(key, value) {
|
|
2128
2114
|
const node = this.insertableNode(value);
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
}
|
|
2115
|
+
const { index, found } = this._binarySearchValues(node.values, value);
|
|
2116
|
+
if (found) {
|
|
2117
|
+
const keys = node.keys[index];
|
|
2118
|
+
if (keys.includes(key)) {
|
|
2119
|
+
return true;
|
|
2135
2120
|
}
|
|
2136
2121
|
}
|
|
2137
2122
|
return false;
|
|
@@ -2767,58 +2752,24 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
2767
2752
|
async insertableNode(value) {
|
|
2768
2753
|
let node = await this.getNode(this.rootId);
|
|
2769
2754
|
while (!node.leaf) {
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
const k = node.keys;
|
|
2773
|
-
if (this.comparator.isSame(value, nValue)) {
|
|
2774
|
-
node = await this.getNode(k[i + 1]);
|
|
2775
|
-
break;
|
|
2776
|
-
} else if (this.comparator.isLower(value, nValue)) {
|
|
2777
|
-
node = await this.getNode(k[i]);
|
|
2778
|
-
break;
|
|
2779
|
-
} else if (i + 1 === node.values.length) {
|
|
2780
|
-
node = await this.getNode(k[i + 1]);
|
|
2781
|
-
break;
|
|
2782
|
-
}
|
|
2783
|
-
}
|
|
2755
|
+
const { index } = this._binarySearchValues(node.values, value, false, true);
|
|
2756
|
+
node = await this.getNode(node.keys[index]);
|
|
2784
2757
|
}
|
|
2785
2758
|
return node;
|
|
2786
2759
|
}
|
|
2787
2760
|
async insertableNodeByPrimary(value) {
|
|
2788
2761
|
let node = await this.getNode(this.rootId);
|
|
2789
2762
|
while (!node.leaf) {
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
const k = node.keys;
|
|
2793
|
-
if (this.comparator.isPrimarySame(value, nValue)) {
|
|
2794
|
-
node = await this.getNode(k[i]);
|
|
2795
|
-
break;
|
|
2796
|
-
} else if (this.comparator.isPrimaryLower(value, nValue)) {
|
|
2797
|
-
node = await this.getNode(k[i]);
|
|
2798
|
-
break;
|
|
2799
|
-
} else if (i + 1 === node.values.length) {
|
|
2800
|
-
node = await this.getNode(k[i + 1]);
|
|
2801
|
-
break;
|
|
2802
|
-
}
|
|
2803
|
-
}
|
|
2763
|
+
const { index } = this._binarySearchValues(node.values, value, true, false);
|
|
2764
|
+
node = await this.getNode(node.keys[index]);
|
|
2804
2765
|
}
|
|
2805
2766
|
return node;
|
|
2806
2767
|
}
|
|
2807
2768
|
async insertableRightestNodeByPrimary(value) {
|
|
2808
2769
|
let node = await this.getNode(this.rootId);
|
|
2809
2770
|
while (!node.leaf) {
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
const k = node.keys;
|
|
2813
|
-
if (this.comparator.isPrimaryLower(value, nValue)) {
|
|
2814
|
-
node = await this.getNode(k[i]);
|
|
2815
|
-
break;
|
|
2816
|
-
}
|
|
2817
|
-
if (i + 1 === node.values.length) {
|
|
2818
|
-
node = await this.getNode(k[i + 1]);
|
|
2819
|
-
break;
|
|
2820
|
-
}
|
|
2821
|
-
}
|
|
2771
|
+
const { index } = this._binarySearchValues(node.values, value, true, true);
|
|
2772
|
+
node = await this.getNode(node.keys[index]);
|
|
2822
2773
|
}
|
|
2823
2774
|
return node;
|
|
2824
2775
|
}
|
|
@@ -2871,11 +2822,21 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
2871
2822
|
let node = startNode;
|
|
2872
2823
|
let done = false;
|
|
2873
2824
|
let hasMatched = false;
|
|
2825
|
+
let nextNodePromise = null;
|
|
2874
2826
|
while (!done) {
|
|
2875
2827
|
if (endNode && node.id === endNode.id) {
|
|
2876
2828
|
done = true;
|
|
2877
2829
|
break;
|
|
2878
2830
|
}
|
|
2831
|
+
if (direction === 1) {
|
|
2832
|
+
if (node.next && !done) {
|
|
2833
|
+
nextNodePromise = this.getNode(node.next);
|
|
2834
|
+
}
|
|
2835
|
+
} else {
|
|
2836
|
+
if (node.prev && !done) {
|
|
2837
|
+
nextNodePromise = this.getNode(node.prev);
|
|
2838
|
+
}
|
|
2839
|
+
}
|
|
2879
2840
|
const len = node.values.length;
|
|
2880
2841
|
if (direction === 1) {
|
|
2881
2842
|
for (let i = 0; i < len; i++) {
|
|
@@ -2908,19 +2869,15 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
2908
2869
|
}
|
|
2909
2870
|
}
|
|
2910
2871
|
}
|
|
2911
|
-
if (done)
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2872
|
+
if (done) {
|
|
2873
|
+
if (nextNodePromise) await nextNodePromise;
|
|
2874
|
+
break;
|
|
2875
|
+
}
|
|
2876
|
+
if (nextNodePromise) {
|
|
2877
|
+
node = await nextNodePromise;
|
|
2878
|
+
nextNodePromise = null;
|
|
2918
2879
|
} else {
|
|
2919
|
-
|
|
2920
|
-
done = true;
|
|
2921
|
-
break;
|
|
2922
|
-
}
|
|
2923
|
-
node = await this.getNode(node.prev);
|
|
2880
|
+
done = true;
|
|
2924
2881
|
}
|
|
2925
2882
|
}
|
|
2926
2883
|
}
|
|
@@ -2951,12 +2908,11 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
2951
2908
|
}
|
|
2952
2909
|
async exists(key, value) {
|
|
2953
2910
|
const node = await this.insertableNode(value);
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
}
|
|
2911
|
+
const { index, found } = this._binarySearchValues(node.values, value);
|
|
2912
|
+
if (found) {
|
|
2913
|
+
const keys = node.keys[index];
|
|
2914
|
+
if (keys.includes(key)) {
|
|
2915
|
+
return true;
|
|
2960
2916
|
}
|
|
2961
2917
|
}
|
|
2962
2918
|
return false;
|
|
@@ -182,4 +182,8 @@ export declare abstract class BPTreeTransaction<K, V> {
|
|
|
182
182
|
* This method is useful for freeing up memory when the tree is no longer needed.
|
|
183
183
|
*/
|
|
184
184
|
clear(): void;
|
|
185
|
+
protected _binarySearchValues(values: V[], target: V, usePrimary?: boolean, upperBound?: boolean): {
|
|
186
|
+
index: number;
|
|
187
|
+
found: boolean;
|
|
188
|
+
};
|
|
185
189
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "serializable-bptree",
|
|
3
|
-
"version": "8.1.
|
|
3
|
+
"version": "8.1.2",
|
|
4
4
|
"description": "Store the B+tree flexibly, not only in-memory.",
|
|
5
5
|
"types": "./dist/types/index.d.ts",
|
|
6
6
|
"main": "./dist/cjs/index.cjs",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"cache-entanglement": "^1.7.1",
|
|
47
|
-
"mvcc-api": "^1.2.
|
|
47
|
+
"mvcc-api": "^1.2.11",
|
|
48
48
|
"ryoiki": "^1.2.0"
|
|
49
49
|
}
|
|
50
50
|
}
|