serializable-bptree 5.2.0 → 6.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 +27 -18
- package/dist/cjs/index.cjs +508 -185
- package/dist/esm/index.mjs +508 -185
- package/dist/types/BPTreeAsync.d.ts +3 -0
- package/package.json +3 -2
package/dist/esm/index.mjs
CHANGED
|
@@ -33,16 +33,26 @@ var LRUMap = class {
|
|
|
33
33
|
map;
|
|
34
34
|
head = null;
|
|
35
35
|
tail = null;
|
|
36
|
+
/**
|
|
37
|
+
* Creates an instance of LRUMap.
|
|
38
|
+
* @param capacity The maximum number of items the cache can hold.
|
|
39
|
+
*/
|
|
36
40
|
constructor(capacity) {
|
|
37
41
|
this.capacity = capacity;
|
|
38
42
|
this.map = /* @__PURE__ */ new Map();
|
|
39
43
|
}
|
|
40
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Promotes a node to the head of the linked list (marks as most recently used).
|
|
46
|
+
* @param node The node to promote.
|
|
47
|
+
*/
|
|
41
48
|
promote(node) {
|
|
42
49
|
this.extract(node);
|
|
43
50
|
this.prepend(node);
|
|
44
51
|
}
|
|
45
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Disconnects a node from the doubly linked list.
|
|
54
|
+
* @param node The node to extract.
|
|
55
|
+
*/
|
|
46
56
|
extract(node) {
|
|
47
57
|
if (node.prev) node.prev.next = node.next;
|
|
48
58
|
else this.head = node.next;
|
|
@@ -51,7 +61,10 @@ var LRUMap = class {
|
|
|
51
61
|
node.prev = null;
|
|
52
62
|
node.next = null;
|
|
53
63
|
}
|
|
54
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Inserts a node at the head of the doubly linked list.
|
|
66
|
+
* @param node The node to prepend.
|
|
67
|
+
*/
|
|
55
68
|
prepend(node) {
|
|
56
69
|
node.next = this.head;
|
|
57
70
|
if (this.head) this.head.prev = node;
|
|
@@ -59,8 +72,10 @@ var LRUMap = class {
|
|
|
59
72
|
if (!this.tail) this.tail = node;
|
|
60
73
|
}
|
|
61
74
|
/**
|
|
62
|
-
*
|
|
63
|
-
*
|
|
75
|
+
* Stores or updates a value by key.
|
|
76
|
+
* If the capacity is exceeded, the least recently used item (tail) is removed.
|
|
77
|
+
* @param key The key to store.
|
|
78
|
+
* @param value The value to store.
|
|
64
79
|
*/
|
|
65
80
|
set(key, value) {
|
|
66
81
|
const existing = this.map.get(key);
|
|
@@ -78,7 +93,10 @@ var LRUMap = class {
|
|
|
78
93
|
}
|
|
79
94
|
}
|
|
80
95
|
/**
|
|
81
|
-
*
|
|
96
|
+
* Retrieves a value by key.
|
|
97
|
+
* Accessing the item moves it to the "most recently used" position.
|
|
98
|
+
* @param key The key to look for.
|
|
99
|
+
* @returns The value associated with the key, or undefined if not found.
|
|
82
100
|
*/
|
|
83
101
|
get(key) {
|
|
84
102
|
const node = this.map.get(key);
|
|
@@ -87,13 +105,17 @@ var LRUMap = class {
|
|
|
87
105
|
return node.value;
|
|
88
106
|
}
|
|
89
107
|
/**
|
|
90
|
-
*
|
|
108
|
+
* Checks if a key exists in the cache without changing its access order.
|
|
109
|
+
* @param key The key to check.
|
|
110
|
+
* @returns True if the key exists, false otherwise.
|
|
91
111
|
*/
|
|
92
112
|
has(key) {
|
|
93
113
|
return this.map.has(key);
|
|
94
114
|
}
|
|
95
115
|
/**
|
|
96
|
-
*
|
|
116
|
+
* Removes a key and its associated value from the cache.
|
|
117
|
+
* @param key The key to remove.
|
|
118
|
+
* @returns True if the key was found and removed, false otherwise.
|
|
97
119
|
*/
|
|
98
120
|
delete(key) {
|
|
99
121
|
const node = this.map.get(key);
|
|
@@ -103,7 +125,8 @@ var LRUMap = class {
|
|
|
103
125
|
return true;
|
|
104
126
|
}
|
|
105
127
|
/**
|
|
106
|
-
*
|
|
128
|
+
* Returns an iterator of keys in the order of most recently used to least recently used.
|
|
129
|
+
* @returns An iterable iterator of keys.
|
|
107
130
|
*/
|
|
108
131
|
*keys() {
|
|
109
132
|
let current = this.head;
|
|
@@ -113,13 +136,13 @@ var LRUMap = class {
|
|
|
113
136
|
}
|
|
114
137
|
}
|
|
115
138
|
/**
|
|
116
|
-
*
|
|
139
|
+
* Returns the current number of items in the cache.
|
|
117
140
|
*/
|
|
118
141
|
get size() {
|
|
119
142
|
return this.map.size;
|
|
120
143
|
}
|
|
121
144
|
/**
|
|
122
|
-
*
|
|
145
|
+
* Clears all items from the cache.
|
|
123
146
|
*/
|
|
124
147
|
clear() {
|
|
125
148
|
this.map.clear();
|
|
@@ -712,6 +735,9 @@ var BPTreeSync = class extends BPTree {
|
|
|
712
735
|
guess = prevValue;
|
|
713
736
|
}
|
|
714
737
|
}
|
|
738
|
+
if (!pointer) {
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
715
741
|
if (node.values.length + pointer.values.length < this.order) {
|
|
716
742
|
if (!isPredecessor) {
|
|
717
743
|
const pTemp = pointer;
|
|
@@ -856,39 +882,40 @@ var BPTreeSync = class extends BPTree {
|
|
|
856
882
|
return;
|
|
857
883
|
}
|
|
858
884
|
const parentNode = this.getNode(node.parent);
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
if (
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
}
|
|
885
|
+
let insertIndex = 0;
|
|
886
|
+
for (let i = 0; i < parentNode.values.length; i++) {
|
|
887
|
+
if (this.comparator.asc(value, parentNode.values[i]) > 0) {
|
|
888
|
+
insertIndex = i + 1;
|
|
889
|
+
} else {
|
|
890
|
+
break;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
parentNode.values.splice(insertIndex, 0, value);
|
|
894
|
+
parentNode.keys.splice(insertIndex + 1, 0, pointer.id);
|
|
895
|
+
pointer.parent = parentNode.id;
|
|
896
|
+
this.bufferForNodeUpdate(parentNode);
|
|
897
|
+
this.bufferForNodeUpdate(pointer);
|
|
898
|
+
if (parentNode.keys.length > this.order) {
|
|
899
|
+
const parentPointer = this._createNode(false, [], []);
|
|
900
|
+
parentPointer.parent = parentNode.parent;
|
|
901
|
+
const mid = Math.ceil(this.order / 2) - 1;
|
|
902
|
+
parentPointer.values = parentNode.values.slice(mid + 1);
|
|
903
|
+
parentPointer.keys = parentNode.keys.slice(mid + 1);
|
|
904
|
+
const midValue = parentNode.values[mid];
|
|
905
|
+
parentNode.values = parentNode.values.slice(0, mid);
|
|
906
|
+
parentNode.keys = parentNode.keys.slice(0, mid + 1);
|
|
907
|
+
for (const k of parentNode.keys) {
|
|
908
|
+
const node2 = this.getNode(k);
|
|
909
|
+
node2.parent = parentNode.id;
|
|
910
|
+
this.bufferForNodeUpdate(node2);
|
|
911
|
+
}
|
|
912
|
+
for (const k of parentPointer.keys) {
|
|
913
|
+
const node2 = this.getNode(k);
|
|
914
|
+
node2.parent = parentPointer.id;
|
|
915
|
+
this.bufferForNodeUpdate(node2);
|
|
891
916
|
}
|
|
917
|
+
this._insertInParent(parentNode, midValue, parentPointer);
|
|
918
|
+
this.bufferForNodeUpdate(parentNode);
|
|
892
919
|
}
|
|
893
920
|
}
|
|
894
921
|
init() {
|
|
@@ -1133,11 +1160,271 @@ var BPTreeSync = class extends BPTree {
|
|
|
1133
1160
|
}
|
|
1134
1161
|
};
|
|
1135
1162
|
|
|
1163
|
+
// node_modules/ryoiki/dist/esm/index.mjs
|
|
1164
|
+
var Ryoiki = class _Ryoiki {
|
|
1165
|
+
readings;
|
|
1166
|
+
writings;
|
|
1167
|
+
readQueue;
|
|
1168
|
+
writeQueue;
|
|
1169
|
+
static async CatchError(promise) {
|
|
1170
|
+
return await promise.then((v) => [void 0, v]).catch((err) => [err]);
|
|
1171
|
+
}
|
|
1172
|
+
static IsRangeOverlap(a, b) {
|
|
1173
|
+
const [start1, end1] = a;
|
|
1174
|
+
const [start2, end2] = b;
|
|
1175
|
+
if (end1 <= start2 || end2 <= start1) {
|
|
1176
|
+
return false;
|
|
1177
|
+
}
|
|
1178
|
+
return true;
|
|
1179
|
+
}
|
|
1180
|
+
static ERR_ALREADY_EXISTS(lockId) {
|
|
1181
|
+
return new Error(`The '${lockId}' task already existing in queue or running.`);
|
|
1182
|
+
}
|
|
1183
|
+
static ERR_NOT_EXISTS(lockId) {
|
|
1184
|
+
return new Error(`The '${lockId}' task not existing in task queue.`);
|
|
1185
|
+
}
|
|
1186
|
+
static ERR_TIMEOUT(lockId, timeout) {
|
|
1187
|
+
return new Error(`The task with ID '${lockId}' failed to acquire the lock within the timeout(${timeout}ms).`);
|
|
1188
|
+
}
|
|
1189
|
+
/**
|
|
1190
|
+
* Constructs a new instance of the Ryoiki class.
|
|
1191
|
+
*/
|
|
1192
|
+
constructor() {
|
|
1193
|
+
this.readings = /* @__PURE__ */ new Map();
|
|
1194
|
+
this.writings = /* @__PURE__ */ new Map();
|
|
1195
|
+
this.readQueue = /* @__PURE__ */ new Map();
|
|
1196
|
+
this.writeQueue = /* @__PURE__ */ new Map();
|
|
1197
|
+
}
|
|
1198
|
+
/**
|
|
1199
|
+
* Creates a range based on a start value and length.
|
|
1200
|
+
* @param start - The starting value of the range.
|
|
1201
|
+
* @param length - The length of the range.
|
|
1202
|
+
* @returns A range tuple [start, start + length].
|
|
1203
|
+
*/
|
|
1204
|
+
range(start, length) {
|
|
1205
|
+
return [start, start + length];
|
|
1206
|
+
}
|
|
1207
|
+
rangeOverlapping(tasks, range) {
|
|
1208
|
+
return Array.from(tasks.values()).some((t) => _Ryoiki.IsRangeOverlap(t.range, range));
|
|
1209
|
+
}
|
|
1210
|
+
isSameRange(a, b) {
|
|
1211
|
+
const [a1, a2] = a;
|
|
1212
|
+
const [b1, b2] = b;
|
|
1213
|
+
return a1 === b1 && a2 === b2;
|
|
1214
|
+
}
|
|
1215
|
+
fetchUnitAndRun(queue, workspaces) {
|
|
1216
|
+
for (const [id, unit] of queue) {
|
|
1217
|
+
if (!unit.condition()) {
|
|
1218
|
+
continue;
|
|
1219
|
+
}
|
|
1220
|
+
this._alloc(queue, workspaces, id);
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
_handleOverload(args, handlers, argPatterns) {
|
|
1224
|
+
for (const [key, pattern] of Object.entries(argPatterns)) {
|
|
1225
|
+
if (this._matchArgs(args, pattern)) {
|
|
1226
|
+
return handlers[key](...args);
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
throw new Error("Invalid arguments");
|
|
1230
|
+
}
|
|
1231
|
+
_matchArgs(args, pattern) {
|
|
1232
|
+
return args.every((arg, index) => {
|
|
1233
|
+
const expectedType = pattern[index];
|
|
1234
|
+
if (expectedType === void 0) return typeof arg === "undefined";
|
|
1235
|
+
if (expectedType === Function) return typeof arg === "function";
|
|
1236
|
+
if (expectedType === Number) return typeof arg === "number";
|
|
1237
|
+
if (expectedType === Array) return Array.isArray(arg);
|
|
1238
|
+
return false;
|
|
1239
|
+
});
|
|
1240
|
+
}
|
|
1241
|
+
_createRandomId() {
|
|
1242
|
+
const timestamp = Date.now().toString(36);
|
|
1243
|
+
const random = Math.random().toString(36).substring(2);
|
|
1244
|
+
return `${timestamp}${random}`;
|
|
1245
|
+
}
|
|
1246
|
+
_alloc(queue, workspaces, lockId) {
|
|
1247
|
+
const unit = queue.get(lockId);
|
|
1248
|
+
if (!unit) {
|
|
1249
|
+
throw _Ryoiki.ERR_NOT_EXISTS(lockId);
|
|
1250
|
+
}
|
|
1251
|
+
workspaces.set(lockId, unit);
|
|
1252
|
+
queue.delete(lockId);
|
|
1253
|
+
unit.alloc();
|
|
1254
|
+
}
|
|
1255
|
+
_free(workspaces, lockId) {
|
|
1256
|
+
const unit = workspaces.get(lockId);
|
|
1257
|
+
if (!unit) {
|
|
1258
|
+
throw _Ryoiki.ERR_NOT_EXISTS(lockId);
|
|
1259
|
+
}
|
|
1260
|
+
workspaces.delete(lockId);
|
|
1261
|
+
unit.free();
|
|
1262
|
+
}
|
|
1263
|
+
_lock(queue, range, timeout, task, condition) {
|
|
1264
|
+
return new Promise((resolve, reject) => {
|
|
1265
|
+
let timeoutId = null;
|
|
1266
|
+
if (timeout >= 0) {
|
|
1267
|
+
timeoutId = setTimeout(() => {
|
|
1268
|
+
reject(_Ryoiki.ERR_TIMEOUT(id, timeout));
|
|
1269
|
+
}, timeout);
|
|
1270
|
+
}
|
|
1271
|
+
const id = this._createRandomId();
|
|
1272
|
+
const alloc = async () => {
|
|
1273
|
+
if (timeoutId !== null) {
|
|
1274
|
+
clearTimeout(timeoutId);
|
|
1275
|
+
}
|
|
1276
|
+
const [err, v] = await _Ryoiki.CatchError(task(id));
|
|
1277
|
+
if (err) reject(err);
|
|
1278
|
+
else resolve(v);
|
|
1279
|
+
};
|
|
1280
|
+
const fetch = () => {
|
|
1281
|
+
this.fetchUnitAndRun(this.readQueue, this.readings);
|
|
1282
|
+
this.fetchUnitAndRun(this.writeQueue, this.writings);
|
|
1283
|
+
};
|
|
1284
|
+
queue.set(id, { id, range, condition, alloc, free: fetch });
|
|
1285
|
+
fetch();
|
|
1286
|
+
});
|
|
1287
|
+
}
|
|
1288
|
+
_checkWorking(range, workspaces) {
|
|
1289
|
+
let isLocked = false;
|
|
1290
|
+
for (const lock of workspaces.values()) {
|
|
1291
|
+
if (_Ryoiki.IsRangeOverlap(range, lock.range)) {
|
|
1292
|
+
isLocked = true;
|
|
1293
|
+
break;
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
return isLocked;
|
|
1297
|
+
}
|
|
1298
|
+
/**
|
|
1299
|
+
* Checks if there is any active read lock within the specified range.
|
|
1300
|
+
* @param range The range to check for active read locks.
|
|
1301
|
+
* @returns `true` if there is an active read lock within the range, `false` otherwise.
|
|
1302
|
+
*/
|
|
1303
|
+
isReading(range) {
|
|
1304
|
+
return this._checkWorking(range, this.readings);
|
|
1305
|
+
}
|
|
1306
|
+
/**
|
|
1307
|
+
* Checks if there is any active write lock within the specified range.
|
|
1308
|
+
* @param range The range to check for active write locks.
|
|
1309
|
+
* @returns `true` if there is an active write lock within the range, `false` otherwise.
|
|
1310
|
+
*/
|
|
1311
|
+
isWriting(range) {
|
|
1312
|
+
return this._checkWorking(range, this.writings);
|
|
1313
|
+
}
|
|
1314
|
+
/**
|
|
1315
|
+
* Checks if a read lock can be acquired within the specified range.
|
|
1316
|
+
* @param range The range to check for read lock availability.
|
|
1317
|
+
* @returns `true` if a read lock can be acquired, `false` otherwise.
|
|
1318
|
+
*/
|
|
1319
|
+
canRead(range) {
|
|
1320
|
+
const writing = this.isWriting(range);
|
|
1321
|
+
return !writing;
|
|
1322
|
+
}
|
|
1323
|
+
/**
|
|
1324
|
+
* Checks if a write lock can be acquired within the specified range.
|
|
1325
|
+
* @param range The range to check for write lock availability.
|
|
1326
|
+
* @returns `true` if a write lock can be acquired, `false` otherwise.
|
|
1327
|
+
*/
|
|
1328
|
+
canWrite(range) {
|
|
1329
|
+
const reading = this.isReading(range);
|
|
1330
|
+
const writing = this.isWriting(range);
|
|
1331
|
+
return !reading && !writing;
|
|
1332
|
+
}
|
|
1333
|
+
/**
|
|
1334
|
+
* Internal implementation of the read lock. Handles both overloads.
|
|
1335
|
+
* @template T - The return type of the task.
|
|
1336
|
+
* @param arg0 - Either a range or a task callback.
|
|
1337
|
+
* If a range is provided, the task is the second argument.
|
|
1338
|
+
* @param arg1 - The task to execute, required if a range is provided.
|
|
1339
|
+
* @param arg2 - The timeout for acquiring the lock.
|
|
1340
|
+
* If the lock cannot be acquired within this period, an error will be thrown.
|
|
1341
|
+
* If this value is not provided, no timeout will be set.
|
|
1342
|
+
* @returns A promise resolving to the result of the task execution.
|
|
1343
|
+
*/
|
|
1344
|
+
readLock(arg0, arg1, arg2) {
|
|
1345
|
+
const [range, task, timeout] = this._handleOverload(
|
|
1346
|
+
[arg0, arg1, arg2],
|
|
1347
|
+
{
|
|
1348
|
+
rangeTask: (range2, task2) => [range2, task2, -1],
|
|
1349
|
+
rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
|
|
1350
|
+
task: (task2) => [[-Infinity, Infinity], task2, -1],
|
|
1351
|
+
taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
|
|
1352
|
+
},
|
|
1353
|
+
{
|
|
1354
|
+
task: [Function],
|
|
1355
|
+
taskTimeout: [Function, Number],
|
|
1356
|
+
rangeTask: [Array, Function],
|
|
1357
|
+
rangeTaskTimeout: [Array, Function, Number]
|
|
1358
|
+
}
|
|
1359
|
+
);
|
|
1360
|
+
return this._lock(
|
|
1361
|
+
this.readQueue,
|
|
1362
|
+
range,
|
|
1363
|
+
timeout,
|
|
1364
|
+
task,
|
|
1365
|
+
() => !this.rangeOverlapping(this.writings, range)
|
|
1366
|
+
);
|
|
1367
|
+
}
|
|
1368
|
+
/**
|
|
1369
|
+
* Internal implementation of the write lock. Handles both overloads.
|
|
1370
|
+
* @template T - The return type of the task.
|
|
1371
|
+
* @param arg0 - Either a range or a task callback.
|
|
1372
|
+
* If a range is provided, the task is the second argument.
|
|
1373
|
+
* @param arg1 - The task to execute, required if a range is provided.
|
|
1374
|
+
* @param arg2 - The timeout for acquiring the lock.
|
|
1375
|
+
* If the lock cannot be acquired within this period, an error will be thrown.
|
|
1376
|
+
* If this value is not provided, no timeout will be set.
|
|
1377
|
+
* @returns A promise resolving to the result of the task execution.
|
|
1378
|
+
*/
|
|
1379
|
+
writeLock(arg0, arg1, arg2) {
|
|
1380
|
+
const [range, task, timeout] = this._handleOverload(
|
|
1381
|
+
[arg0, arg1, arg2],
|
|
1382
|
+
{
|
|
1383
|
+
rangeTask: (range2, task2) => [range2, task2, -1],
|
|
1384
|
+
rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
|
|
1385
|
+
task: (task2) => [[-Infinity, Infinity], task2, -1],
|
|
1386
|
+
taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
|
|
1387
|
+
},
|
|
1388
|
+
{
|
|
1389
|
+
task: [Function],
|
|
1390
|
+
taskTimeout: [Function, Number],
|
|
1391
|
+
rangeTask: [Array, Function],
|
|
1392
|
+
rangeTaskTimeout: [Array, Function, Number]
|
|
1393
|
+
}
|
|
1394
|
+
);
|
|
1395
|
+
return this._lock(
|
|
1396
|
+
this.writeQueue,
|
|
1397
|
+
range,
|
|
1398
|
+
timeout,
|
|
1399
|
+
task,
|
|
1400
|
+
() => {
|
|
1401
|
+
return !this.rangeOverlapping(this.writings, range) && !this.rangeOverlapping(this.readings, range);
|
|
1402
|
+
}
|
|
1403
|
+
);
|
|
1404
|
+
}
|
|
1405
|
+
/**
|
|
1406
|
+
* Releases a read lock by its lock ID.
|
|
1407
|
+
* @param lockId - The unique identifier for the lock to release.
|
|
1408
|
+
*/
|
|
1409
|
+
readUnlock(lockId) {
|
|
1410
|
+
this._free(this.readings, lockId);
|
|
1411
|
+
}
|
|
1412
|
+
/**
|
|
1413
|
+
* Releases a write lock by its lock ID.
|
|
1414
|
+
* @param lockId - The unique identifier for the lock to release.
|
|
1415
|
+
*/
|
|
1416
|
+
writeUnlock(lockId) {
|
|
1417
|
+
this._free(this.writings, lockId);
|
|
1418
|
+
}
|
|
1419
|
+
};
|
|
1420
|
+
|
|
1136
1421
|
// src/BPTreeAsync.ts
|
|
1137
1422
|
var BPTreeAsync = class extends BPTree {
|
|
1423
|
+
lock;
|
|
1138
1424
|
constructor(strategy, comparator, option) {
|
|
1139
1425
|
super(strategy, comparator, option);
|
|
1140
1426
|
this.nodes = this._createCachedNode();
|
|
1427
|
+
this.lock = new Ryoiki();
|
|
1141
1428
|
}
|
|
1142
1429
|
_createCachedNode() {
|
|
1143
1430
|
return new CacheEntanglementAsync(async (key) => {
|
|
@@ -1146,6 +1433,24 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1146
1433
|
capacity: this.option.capacity ?? 1e3
|
|
1147
1434
|
});
|
|
1148
1435
|
}
|
|
1436
|
+
async readLock(callback) {
|
|
1437
|
+
let lockId;
|
|
1438
|
+
return await this.lock.readLock(async (_lockId) => {
|
|
1439
|
+
lockId = _lockId;
|
|
1440
|
+
return await callback();
|
|
1441
|
+
}).finally(() => {
|
|
1442
|
+
this.lock.readUnlock(lockId);
|
|
1443
|
+
});
|
|
1444
|
+
}
|
|
1445
|
+
async writeLock(callback) {
|
|
1446
|
+
let lockId;
|
|
1447
|
+
return await this.lock.writeLock(async (_lockId) => {
|
|
1448
|
+
lockId = _lockId;
|
|
1449
|
+
return await callback();
|
|
1450
|
+
}).finally(() => {
|
|
1451
|
+
this.lock.writeUnlock(lockId);
|
|
1452
|
+
});
|
|
1453
|
+
}
|
|
1149
1454
|
async getPairsRightToLeft(value, startNode, endNode, comparator) {
|
|
1150
1455
|
const pairs = [];
|
|
1151
1456
|
let node = startNode;
|
|
@@ -1304,6 +1609,9 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1304
1609
|
guess = prevValue;
|
|
1305
1610
|
}
|
|
1306
1611
|
}
|
|
1612
|
+
if (!pointer) {
|
|
1613
|
+
return;
|
|
1614
|
+
}
|
|
1307
1615
|
if (node.values.length + pointer.values.length < this.order) {
|
|
1308
1616
|
if (!isPredecessor) {
|
|
1309
1617
|
const pTemp = pointer;
|
|
@@ -1448,40 +1756,41 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1448
1756
|
return;
|
|
1449
1757
|
}
|
|
1450
1758
|
const parentNode = await this.getNode(node.parent);
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
if (
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
if (parentNode.keys.length > this.order) {
|
|
1458
|
-
const parentPointer = await this._createNode(false, [], []);
|
|
1459
|
-
parentPointer.parent = parentNode.parent;
|
|
1460
|
-
const mid = Math.ceil(this.order / 2) - 1;
|
|
1461
|
-
parentPointer.values = parentNode.values.slice(mid + 1);
|
|
1462
|
-
parentPointer.keys = parentNode.keys.slice(mid + 1);
|
|
1463
|
-
const midValue = parentNode.values[mid];
|
|
1464
|
-
if (mid === 0) {
|
|
1465
|
-
parentNode.values = parentNode.values.slice(0, mid + 1);
|
|
1466
|
-
} else {
|
|
1467
|
-
parentNode.values = parentNode.values.slice(0, mid);
|
|
1468
|
-
}
|
|
1469
|
-
parentNode.keys = parentNode.keys.slice(0, mid + 1);
|
|
1470
|
-
for (const k of parentNode.keys) {
|
|
1471
|
-
const node2 = await this.getNode(k);
|
|
1472
|
-
node2.parent = parentNode.id;
|
|
1473
|
-
this.bufferForNodeUpdate(node2);
|
|
1474
|
-
}
|
|
1475
|
-
for (const k of parentPointer.keys) {
|
|
1476
|
-
const node2 = await this.getNode(k);
|
|
1477
|
-
node2.parent = parentPointer.id;
|
|
1478
|
-
this.bufferForNodeUpdate(node2);
|
|
1479
|
-
}
|
|
1480
|
-
await this._insertInParent(parentNode, midValue, parentPointer);
|
|
1481
|
-
this.bufferForNodeUpdate(parentNode);
|
|
1482
|
-
}
|
|
1759
|
+
let insertIndex = 0;
|
|
1760
|
+
for (let i = 0; i < parentNode.values.length; i++) {
|
|
1761
|
+
if (this.comparator.asc(value, parentNode.values[i]) > 0) {
|
|
1762
|
+
insertIndex = i + 1;
|
|
1763
|
+
} else {
|
|
1764
|
+
break;
|
|
1483
1765
|
}
|
|
1484
1766
|
}
|
|
1767
|
+
parentNode.values.splice(insertIndex, 0, value);
|
|
1768
|
+
parentNode.keys.splice(insertIndex + 1, 0, pointer.id);
|
|
1769
|
+
pointer.parent = parentNode.id;
|
|
1770
|
+
this.bufferForNodeUpdate(parentNode);
|
|
1771
|
+
this.bufferForNodeUpdate(pointer);
|
|
1772
|
+
if (parentNode.keys.length > this.order) {
|
|
1773
|
+
const parentPointer = await this._createNode(false, [], []);
|
|
1774
|
+
parentPointer.parent = parentNode.parent;
|
|
1775
|
+
const mid = Math.ceil(this.order / 2) - 1;
|
|
1776
|
+
parentPointer.values = parentNode.values.slice(mid + 1);
|
|
1777
|
+
parentPointer.keys = parentNode.keys.slice(mid + 1);
|
|
1778
|
+
const midValue = parentNode.values[mid];
|
|
1779
|
+
parentNode.values = parentNode.values.slice(0, mid);
|
|
1780
|
+
parentNode.keys = parentNode.keys.slice(0, mid + 1);
|
|
1781
|
+
for (const k of parentNode.keys) {
|
|
1782
|
+
const node2 = await this.getNode(k);
|
|
1783
|
+
node2.parent = parentNode.id;
|
|
1784
|
+
this.bufferForNodeUpdate(node2);
|
|
1785
|
+
}
|
|
1786
|
+
for (const k of parentPointer.keys) {
|
|
1787
|
+
const node2 = await this.getNode(k);
|
|
1788
|
+
node2.parent = parentPointer.id;
|
|
1789
|
+
this.bufferForNodeUpdate(node2);
|
|
1790
|
+
}
|
|
1791
|
+
await this._insertInParent(parentNode, midValue, parentPointer);
|
|
1792
|
+
this.bufferForNodeUpdate(parentNode);
|
|
1793
|
+
}
|
|
1485
1794
|
}
|
|
1486
1795
|
async init() {
|
|
1487
1796
|
const head = await this.strategy.readHead();
|
|
@@ -1589,139 +1898,153 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1589
1898
|
this._nodeDeleteBuffer.clear();
|
|
1590
1899
|
}
|
|
1591
1900
|
async keys(condition, filterValues) {
|
|
1592
|
-
|
|
1593
|
-
const
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
const
|
|
1606
|
-
|
|
1607
|
-
|
|
1901
|
+
return this.readLock(async () => {
|
|
1902
|
+
for (const k in condition) {
|
|
1903
|
+
const key = k;
|
|
1904
|
+
const value = condition[key];
|
|
1905
|
+
const startNode = await this.verifierStartNode[key](value);
|
|
1906
|
+
const endNode = await this.verifierEndNode[key](value);
|
|
1907
|
+
const direction = this.verifierDirection[key];
|
|
1908
|
+
const comparator = this.verifierMap[key];
|
|
1909
|
+
const pairs = await this.getPairs(value, startNode, endNode, comparator, direction);
|
|
1910
|
+
if (!filterValues) {
|
|
1911
|
+
filterValues = new Set(pairs.keys());
|
|
1912
|
+
} else {
|
|
1913
|
+
const intersections = /* @__PURE__ */ new Set();
|
|
1914
|
+
for (const key2 of filterValues) {
|
|
1915
|
+
const has = pairs.has(key2);
|
|
1916
|
+
if (has) {
|
|
1917
|
+
intersections.add(key2);
|
|
1918
|
+
}
|
|
1608
1919
|
}
|
|
1920
|
+
filterValues = intersections;
|
|
1609
1921
|
}
|
|
1610
|
-
filterValues = intersections;
|
|
1611
1922
|
}
|
|
1612
|
-
|
|
1613
|
-
|
|
1923
|
+
return filterValues ?? /* @__PURE__ */ new Set([]);
|
|
1924
|
+
});
|
|
1614
1925
|
}
|
|
1615
1926
|
async where(condition) {
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
const
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
result
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1927
|
+
return this.readLock(async () => {
|
|
1928
|
+
let result = null;
|
|
1929
|
+
for (const k in condition) {
|
|
1930
|
+
const key = k;
|
|
1931
|
+
const value = condition[key];
|
|
1932
|
+
const startNode = await this.verifierStartNode[key](value);
|
|
1933
|
+
const endNode = await this.verifierEndNode[key](value);
|
|
1934
|
+
const direction = this.verifierDirection[key];
|
|
1935
|
+
const comparator = this.verifierMap[key];
|
|
1936
|
+
const pairs = await this.getPairs(value, startNode, endNode, comparator, direction);
|
|
1937
|
+
if (result === null) {
|
|
1938
|
+
result = pairs;
|
|
1939
|
+
} else {
|
|
1940
|
+
const intersection = /* @__PURE__ */ new Map();
|
|
1941
|
+
for (const [k2, v] of pairs) {
|
|
1942
|
+
if (result.has(k2)) {
|
|
1943
|
+
intersection.set(k2, v);
|
|
1944
|
+
}
|
|
1632
1945
|
}
|
|
1946
|
+
result = intersection;
|
|
1633
1947
|
}
|
|
1634
|
-
result = intersection;
|
|
1635
1948
|
}
|
|
1636
|
-
|
|
1637
|
-
|
|
1949
|
+
return result ?? /* @__PURE__ */ new Map();
|
|
1950
|
+
});
|
|
1638
1951
|
}
|
|
1639
1952
|
async insert(key, value) {
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1953
|
+
return this.writeLock(async () => {
|
|
1954
|
+
const before = await this.insertableNode(value);
|
|
1955
|
+
this._insertAtLeaf(before, key, value);
|
|
1956
|
+
if (before.values.length === this.order) {
|
|
1957
|
+
const after = await this._createNode(
|
|
1958
|
+
true,
|
|
1959
|
+
[],
|
|
1960
|
+
[],
|
|
1961
|
+
true,
|
|
1962
|
+
before.parent,
|
|
1963
|
+
before.next,
|
|
1964
|
+
before.id
|
|
1965
|
+
);
|
|
1966
|
+
const mid = Math.ceil(this.order / 2) - 1;
|
|
1967
|
+
const beforeNext = before.next;
|
|
1968
|
+
after.values = before.values.slice(mid + 1);
|
|
1969
|
+
after.keys = before.keys.slice(mid + 1);
|
|
1970
|
+
before.values = before.values.slice(0, mid + 1);
|
|
1971
|
+
before.keys = before.keys.slice(0, mid + 1);
|
|
1972
|
+
before.next = after.id;
|
|
1973
|
+
if (beforeNext) {
|
|
1974
|
+
const node = await this.getNode(beforeNext);
|
|
1975
|
+
node.prev = after.id;
|
|
1976
|
+
this.bufferForNodeUpdate(node);
|
|
1977
|
+
}
|
|
1978
|
+
await this._insertInParent(before, after.values[0], after);
|
|
1979
|
+
this.bufferForNodeUpdate(before);
|
|
1663
1980
|
}
|
|
1664
|
-
await this.
|
|
1665
|
-
this.
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
await this.commitNodeCreateBuffer();
|
|
1669
|
-
await this.commitNodeUpdateBuffer();
|
|
1981
|
+
await this.commitHeadBuffer();
|
|
1982
|
+
await this.commitNodeCreateBuffer();
|
|
1983
|
+
await this.commitNodeUpdateBuffer();
|
|
1984
|
+
});
|
|
1670
1985
|
}
|
|
1671
1986
|
async delete(key, value) {
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
if (keys.
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
node.
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1987
|
+
return this.writeLock(async () => {
|
|
1988
|
+
const node = await this.insertableNode(value);
|
|
1989
|
+
let i = node.values.length;
|
|
1990
|
+
while (i--) {
|
|
1991
|
+
const nValue = node.values[i];
|
|
1992
|
+
if (this.comparator.isSame(value, nValue)) {
|
|
1993
|
+
const keys = node.keys[i];
|
|
1994
|
+
if (keys.includes(key)) {
|
|
1995
|
+
if (keys.length > 1) {
|
|
1996
|
+
keys.splice(keys.indexOf(key), 1);
|
|
1997
|
+
this.bufferForNodeUpdate(node);
|
|
1998
|
+
} else if (node.id === this.root.id) {
|
|
1999
|
+
node.values.splice(i, 1);
|
|
2000
|
+
node.keys.splice(i, 1);
|
|
2001
|
+
this.bufferForNodeUpdate(node);
|
|
2002
|
+
} else {
|
|
2003
|
+
keys.splice(keys.indexOf(key), 1);
|
|
2004
|
+
node.keys.splice(i, 1);
|
|
2005
|
+
node.values.splice(node.values.indexOf(value), 1);
|
|
2006
|
+
await this._deleteEntry(node, key, value);
|
|
2007
|
+
this.bufferForNodeUpdate(node);
|
|
2008
|
+
}
|
|
1692
2009
|
}
|
|
1693
2010
|
}
|
|
1694
2011
|
}
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
2012
|
+
await this.commitHeadBuffer();
|
|
2013
|
+
await this.commitNodeCreateBuffer();
|
|
2014
|
+
await this.commitNodeUpdateBuffer();
|
|
2015
|
+
await this.commitNodeDeleteBuffer();
|
|
2016
|
+
});
|
|
1700
2017
|
}
|
|
1701
2018
|
async exists(key, value) {
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
2019
|
+
return this.readLock(async () => {
|
|
2020
|
+
const node = await this.insertableNode(value);
|
|
2021
|
+
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
2022
|
+
const nValue = node.values[i];
|
|
2023
|
+
if (this.comparator.isSame(value, nValue)) {
|
|
2024
|
+
const keys = node.keys[i];
|
|
2025
|
+
return keys.includes(key);
|
|
2026
|
+
}
|
|
1708
2027
|
}
|
|
1709
|
-
|
|
1710
|
-
|
|
2028
|
+
return false;
|
|
2029
|
+
});
|
|
1711
2030
|
}
|
|
1712
2031
|
async setHeadData(data) {
|
|
1713
|
-
this.
|
|
1714
|
-
|
|
1715
|
-
|
|
2032
|
+
return this.writeLock(async () => {
|
|
2033
|
+
this.strategy.head.data = data;
|
|
2034
|
+
this._strategyDirty = true;
|
|
2035
|
+
await this.commitHeadBuffer();
|
|
2036
|
+
});
|
|
1716
2037
|
}
|
|
1717
2038
|
async forceUpdate() {
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
2039
|
+
return this.readLock(async () => {
|
|
2040
|
+
const keys = [...this.nodes.keys()];
|
|
2041
|
+
this.nodes.clear();
|
|
2042
|
+
await this.init();
|
|
2043
|
+
for (const key of keys) {
|
|
2044
|
+
await this.getNode(key);
|
|
2045
|
+
}
|
|
2046
|
+
return keys.length;
|
|
2047
|
+
});
|
|
1725
2048
|
}
|
|
1726
2049
|
};
|
|
1727
2050
|
|