document-dataply 0.0.5 → 0.0.6
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/dist/cjs/index.js +1892 -1600
- package/package.json +2 -2
package/dist/cjs/index.js
CHANGED
|
@@ -71,7 +71,7 @@ var require_cjs = __commonJS({
|
|
|
71
71
|
BPTreeSyncTransaction: () => BPTreeSyncTransaction,
|
|
72
72
|
BitmapPageManager: () => BitmapPageManager,
|
|
73
73
|
CacheEntanglementAsync: () => CacheEntanglementAsync,
|
|
74
|
-
CacheEntanglementSync: () =>
|
|
74
|
+
CacheEntanglementSync: () => CacheEntanglementSync,
|
|
75
75
|
DataPageManager: () => DataPageManager,
|
|
76
76
|
Dataply: () => Dataply,
|
|
77
77
|
DataplyAPI: () => DataplyAPI2,
|
|
@@ -156,6 +156,42 @@ var require_cjs = __commonJS({
|
|
|
156
156
|
};
|
|
157
157
|
var MVCCStrategy = class {
|
|
158
158
|
};
|
|
159
|
+
var LRUMap = class {
|
|
160
|
+
cache = /* @__PURE__ */ new Map();
|
|
161
|
+
capacity;
|
|
162
|
+
constructor(capacity) {
|
|
163
|
+
this.capacity = capacity;
|
|
164
|
+
}
|
|
165
|
+
get(key) {
|
|
166
|
+
if (!this.cache.has(key)) return void 0;
|
|
167
|
+
const value = this.cache.get(key);
|
|
168
|
+
this.cache.delete(key);
|
|
169
|
+
this.cache.set(key, value);
|
|
170
|
+
return value;
|
|
171
|
+
}
|
|
172
|
+
set(key, value) {
|
|
173
|
+
if (this.cache.has(key)) {
|
|
174
|
+
this.cache.delete(key);
|
|
175
|
+
} else if (this.cache.size >= this.capacity) {
|
|
176
|
+
const oldestKey = this.cache.keys().next().value;
|
|
177
|
+
if (oldestKey !== void 0) this.cache.delete(oldestKey);
|
|
178
|
+
}
|
|
179
|
+
this.cache.set(key, value);
|
|
180
|
+
return this;
|
|
181
|
+
}
|
|
182
|
+
has(key) {
|
|
183
|
+
return this.cache.has(key);
|
|
184
|
+
}
|
|
185
|
+
delete(key) {
|
|
186
|
+
return this.cache.delete(key);
|
|
187
|
+
}
|
|
188
|
+
clear() {
|
|
189
|
+
this.cache.clear();
|
|
190
|
+
}
|
|
191
|
+
get size() {
|
|
192
|
+
return this.cache.size;
|
|
193
|
+
}
|
|
194
|
+
};
|
|
159
195
|
var MVCCTransaction = class {
|
|
160
196
|
committed;
|
|
161
197
|
snapshotVersion;
|
|
@@ -163,11 +199,11 @@ var require_cjs = __commonJS({
|
|
|
163
199
|
writeBuffer;
|
|
164
200
|
deleteBuffer;
|
|
165
201
|
createdKeys;
|
|
166
|
-
// create()로 생성된 키 추적
|
|
167
202
|
deletedValues;
|
|
168
203
|
// delete 시 삭제 전 값 저장
|
|
169
204
|
originallyExisted;
|
|
170
205
|
// 트랜잭션 시작 시점에 디스크에 존재했던 키 (deleted 결과 필터링용)
|
|
206
|
+
bufferHistory = /* @__PURE__ */ new Map();
|
|
171
207
|
// Nested Transaction Properties
|
|
172
208
|
parent;
|
|
173
209
|
localVersion;
|
|
@@ -181,7 +217,8 @@ var require_cjs = __commonJS({
|
|
|
181
217
|
versionIndex = /* @__PURE__ */ new Map();
|
|
182
218
|
deletedCache = /* @__PURE__ */ new Map();
|
|
183
219
|
activeTransactions = /* @__PURE__ */ new Set();
|
|
184
|
-
|
|
220
|
+
diskCache;
|
|
221
|
+
constructor(strategy, options, parent, snapshotVersion) {
|
|
185
222
|
this.snapshotVersion = snapshotVersion ?? 0;
|
|
186
223
|
this.writeBuffer = /* @__PURE__ */ new Map();
|
|
187
224
|
this.deleteBuffer = /* @__PURE__ */ new Set();
|
|
@@ -196,6 +233,7 @@ var require_cjs = __commonJS({
|
|
|
196
233
|
this.snapshotLocalVersion = parent.localVersion;
|
|
197
234
|
this.strategy = void 0;
|
|
198
235
|
this.root = parent.root;
|
|
236
|
+
this.diskCache = parent.diskCache;
|
|
199
237
|
} else {
|
|
200
238
|
if (!strategy) throw new Error("Root Transaction must get Strategy");
|
|
201
239
|
this.strategy = strategy;
|
|
@@ -203,8 +241,13 @@ var require_cjs = __commonJS({
|
|
|
203
241
|
this.localVersion = 0;
|
|
204
242
|
this.snapshotLocalVersion = 0;
|
|
205
243
|
this.root = this;
|
|
244
|
+
this.diskCache = new LRUMap(options?.cacheCapacity ?? 1e3);
|
|
206
245
|
}
|
|
207
246
|
}
|
|
247
|
+
/**
|
|
248
|
+
* Checks if the transaction is a root transaction.
|
|
249
|
+
* @returns True if the transaction is a root transaction, false otherwise.
|
|
250
|
+
*/
|
|
208
251
|
isRoot() {
|
|
209
252
|
return !this.parent;
|
|
210
253
|
}
|
|
@@ -221,27 +264,96 @@ var require_cjs = __commonJS({
|
|
|
221
264
|
}
|
|
222
265
|
return false;
|
|
223
266
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
267
|
+
/**
|
|
268
|
+
* Checks if a key was written in this transaction.
|
|
269
|
+
* @param key The key to check.
|
|
270
|
+
* @returns True if the key was written in this transaction, false otherwise.
|
|
271
|
+
*/
|
|
272
|
+
isWrote(key) {
|
|
273
|
+
return this.writeBuffer.has(key);
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Checks if a key was deleted in this transaction.
|
|
277
|
+
* @param key The key to check.
|
|
278
|
+
* @returns True if the key was deleted in this transaction, false otherwise.
|
|
279
|
+
*/
|
|
280
|
+
isDeleted(key) {
|
|
281
|
+
return this.deleteBuffer.has(key);
|
|
282
|
+
}
|
|
283
|
+
_recordHistory(key) {
|
|
284
|
+
const existsInWriteBuffer = this.writeBuffer.has(key);
|
|
285
|
+
const existsInDeleteBuffer = this.deleteBuffer.has(key);
|
|
286
|
+
const currentVer = this.keyVersions.get(key);
|
|
287
|
+
if (currentVer !== void 0) {
|
|
288
|
+
if (!this.bufferHistory.has(key)) this.bufferHistory.set(key, []);
|
|
289
|
+
this.bufferHistory.get(key).push({
|
|
290
|
+
value: existsInWriteBuffer ? this.writeBuffer.get(key) : this.deletedValues.get(key) ?? null,
|
|
291
|
+
exists: existsInWriteBuffer || !existsInDeleteBuffer,
|
|
292
|
+
version: currentVer
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* BINARY SEARCH HELPER: Finds the index of the last element in the array
|
|
298
|
+
* where item[key] <= target. Assumes the array is sorted by 'key' ascending.
|
|
299
|
+
*/
|
|
300
|
+
_findLastLE(array, target, property) {
|
|
301
|
+
let left = 0;
|
|
302
|
+
let right = array.length - 1;
|
|
303
|
+
let result = -1;
|
|
304
|
+
while (left <= right) {
|
|
305
|
+
const mid = left + right >> 1;
|
|
306
|
+
if (array[mid][property] <= target) {
|
|
307
|
+
result = mid;
|
|
308
|
+
left = mid + 1;
|
|
309
|
+
} else {
|
|
310
|
+
right = mid - 1;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return result;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* BINARY SEARCH HELPER: Finds the index of the element in the array
|
|
317
|
+
* where item[key] === target. Assumes the array is sorted by 'key' ascending.
|
|
318
|
+
*/
|
|
319
|
+
_findExact(array, target, property) {
|
|
320
|
+
let left = 0;
|
|
321
|
+
let right = array.length - 1;
|
|
322
|
+
while (left <= right) {
|
|
323
|
+
const mid = left + right >> 1;
|
|
324
|
+
const val = array[mid][property];
|
|
325
|
+
if (val === target) return mid;
|
|
326
|
+
if (val < target) left = mid + 1;
|
|
327
|
+
else right = mid - 1;
|
|
328
|
+
}
|
|
329
|
+
return -1;
|
|
330
|
+
}
|
|
331
|
+
_bufferCreate(key, value, version) {
|
|
332
|
+
if (version === void 0) this.localVersion++;
|
|
333
|
+
const targetVersion = version ?? this.localVersion;
|
|
334
|
+
this._recordHistory(key);
|
|
227
335
|
this.writeBuffer.set(key, value);
|
|
228
336
|
this.createdKeys.add(key);
|
|
229
337
|
this.deleteBuffer.delete(key);
|
|
230
338
|
this.originallyExisted.delete(key);
|
|
231
|
-
this.keyVersions.set(key,
|
|
339
|
+
this.keyVersions.set(key, targetVersion);
|
|
232
340
|
}
|
|
233
|
-
_bufferWrite(key, value) {
|
|
234
|
-
this.localVersion++;
|
|
341
|
+
_bufferWrite(key, value, version) {
|
|
342
|
+
if (version === void 0) this.localVersion++;
|
|
343
|
+
const targetVersion = version ?? this.localVersion;
|
|
344
|
+
this._recordHistory(key);
|
|
235
345
|
this.writeBuffer.set(key, value);
|
|
236
346
|
this.deleteBuffer.delete(key);
|
|
237
|
-
this.keyVersions.set(key,
|
|
347
|
+
this.keyVersions.set(key, targetVersion);
|
|
238
348
|
}
|
|
239
|
-
_bufferDelete(key) {
|
|
240
|
-
this.localVersion++;
|
|
349
|
+
_bufferDelete(key, version) {
|
|
350
|
+
if (version === void 0) this.localVersion++;
|
|
351
|
+
const targetVersion = version ?? this.localVersion;
|
|
352
|
+
this._recordHistory(key);
|
|
241
353
|
this.deleteBuffer.add(key);
|
|
242
354
|
this.writeBuffer.delete(key);
|
|
243
355
|
this.createdKeys.delete(key);
|
|
244
|
-
this.keyVersions.set(key,
|
|
356
|
+
this.keyVersions.set(key, targetVersion);
|
|
245
357
|
}
|
|
246
358
|
/**
|
|
247
359
|
* Returns the entries that will be created, updated, and deleted by this transaction.
|
|
@@ -265,7 +377,11 @@ var require_cjs = __commonJS({
|
|
|
265
377
|
deleted.push({ key, data });
|
|
266
378
|
}
|
|
267
379
|
}
|
|
268
|
-
return {
|
|
380
|
+
return {
|
|
381
|
+
created,
|
|
382
|
+
updated,
|
|
383
|
+
deleted
|
|
384
|
+
};
|
|
269
385
|
}
|
|
270
386
|
/**
|
|
271
387
|
* Rolls back the transaction.
|
|
@@ -283,7 +399,36 @@ var require_cjs = __commonJS({
|
|
|
283
399
|
if (this.root !== this) {
|
|
284
400
|
this.root.activeTransactions.delete(this);
|
|
285
401
|
}
|
|
286
|
-
return {
|
|
402
|
+
return {
|
|
403
|
+
success: true,
|
|
404
|
+
created,
|
|
405
|
+
updated,
|
|
406
|
+
deleted
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Checks for conflicts among multiple transactions.
|
|
411
|
+
* A conflict occurs if two or more transactions modify (write or delete) the same key.
|
|
412
|
+
* @param transactions Array of transactions to check.
|
|
413
|
+
* @returns An array of keys that are in conflict.
|
|
414
|
+
*/
|
|
415
|
+
static CheckConflicts(transactions) {
|
|
416
|
+
const modifiedKeys = /* @__PURE__ */ new Map();
|
|
417
|
+
const conflicts = /* @__PURE__ */ new Set();
|
|
418
|
+
for (const tx of transactions) {
|
|
419
|
+
const txModified = /* @__PURE__ */ new Set([
|
|
420
|
+
...tx.writeBuffer.keys(),
|
|
421
|
+
...tx.deleteBuffer
|
|
422
|
+
]);
|
|
423
|
+
for (const key of txModified) {
|
|
424
|
+
const count = modifiedKeys.get(key) ?? 0;
|
|
425
|
+
if (count > 0) {
|
|
426
|
+
conflicts.add(key);
|
|
427
|
+
}
|
|
428
|
+
modifiedKeys.set(key, count + 1);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return Array.from(conflicts);
|
|
287
432
|
}
|
|
288
433
|
/**
|
|
289
434
|
* Cleans up both deletedCache and versionIndex based on minActiveVersion.
|
|
@@ -318,7 +463,9 @@ var require_cjs = __commonJS({
|
|
|
318
463
|
break;
|
|
319
464
|
}
|
|
320
465
|
}
|
|
321
|
-
if (latestInSnapshotIdx
|
|
466
|
+
if (latestInSnapshotIdx === versions.length - 1) {
|
|
467
|
+
this.versionIndex.delete(key);
|
|
468
|
+
} else if (latestInSnapshotIdx > 0) {
|
|
322
469
|
versions.splice(0, latestInSnapshotIdx);
|
|
323
470
|
}
|
|
324
471
|
}
|
|
@@ -367,7 +514,7 @@ var require_cjs = __commonJS({
|
|
|
367
514
|
createNested() {
|
|
368
515
|
if (this.committed) throw new Error("Transaction already committed");
|
|
369
516
|
const childVersion = this.isRoot() ? this.version : this.snapshotVersion;
|
|
370
|
-
const child = new _SyncMVCCTransaction(void 0, this, childVersion);
|
|
517
|
+
const child = new _SyncMVCCTransaction(void 0, void 0, this, childVersion);
|
|
371
518
|
this.root.activeTransactions.add(child);
|
|
372
519
|
return child;
|
|
373
520
|
}
|
|
@@ -375,32 +522,77 @@ var require_cjs = __commonJS({
|
|
|
375
522
|
if (this.committed) throw new Error("Transaction already committed");
|
|
376
523
|
if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
|
|
377
524
|
if (this.deleteBuffer.has(key)) return null;
|
|
378
|
-
|
|
525
|
+
if (this.parent) {
|
|
526
|
+
return this.parent._readSnapshot(key, this.snapshotVersion, this.snapshotLocalVersion);
|
|
527
|
+
}
|
|
528
|
+
return this._diskRead(key, this.snapshotVersion);
|
|
379
529
|
}
|
|
380
530
|
exists(key) {
|
|
381
531
|
if (this.committed) throw new Error("Transaction already committed");
|
|
382
532
|
if (this.deleteBuffer.has(key)) return false;
|
|
383
533
|
if (this.writeBuffer.has(key)) return true;
|
|
384
|
-
|
|
534
|
+
if (this.parent) {
|
|
535
|
+
return this.parent._existsSnapshot(key, this.snapshotVersion, this.snapshotLocalVersion);
|
|
536
|
+
}
|
|
537
|
+
return this._diskExists(key, this.snapshotVersion);
|
|
385
538
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
539
|
+
_existsSnapshot(key, snapshotVersion, snapshotLocalVersion) {
|
|
540
|
+
let current = this;
|
|
541
|
+
let slVer = snapshotLocalVersion;
|
|
542
|
+
while (current) {
|
|
543
|
+
if (current.writeBuffer.has(key)) {
|
|
544
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
545
|
+
if (slVer === void 0 || keyModVersion <= slVer) return true;
|
|
546
|
+
}
|
|
547
|
+
if (current.deleteBuffer.has(key)) {
|
|
548
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
549
|
+
if (slVer === void 0 || keyModVersion <= slVer) return false;
|
|
550
|
+
}
|
|
551
|
+
const history = current.bufferHistory.get(key);
|
|
552
|
+
if (history && slVer !== void 0) {
|
|
553
|
+
const idx = current._findLastLE(history, slVer, "version");
|
|
554
|
+
if (idx >= 0) return history[idx].exists;
|
|
555
|
+
}
|
|
556
|
+
if (current.parent) {
|
|
557
|
+
slVer = current.snapshotLocalVersion;
|
|
558
|
+
current = current.parent;
|
|
559
|
+
} else {
|
|
560
|
+
return current._diskExists(key, snapshotVersion);
|
|
391
561
|
}
|
|
392
562
|
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
563
|
+
return false;
|
|
564
|
+
}
|
|
565
|
+
_readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
|
|
566
|
+
let current = this;
|
|
567
|
+
let slVer = snapshotLocalVersion;
|
|
568
|
+
while (current) {
|
|
569
|
+
if (current.writeBuffer.has(key)) {
|
|
570
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
571
|
+
if (slVer === void 0 || keyModVersion <= slVer) {
|
|
572
|
+
return current.writeBuffer.get(key);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
if (current.deleteBuffer.has(key)) {
|
|
576
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
577
|
+
if (slVer === void 0 || keyModVersion <= slVer) {
|
|
578
|
+
return null;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
const history = current.bufferHistory.get(key);
|
|
582
|
+
if (history && slVer !== void 0) {
|
|
583
|
+
const idx = current._findLastLE(history, slVer, "version");
|
|
584
|
+
if (idx >= 0) {
|
|
585
|
+
return history[idx].exists ? history[idx].value : null;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
if (current.parent) {
|
|
589
|
+
slVer = current.snapshotLocalVersion;
|
|
590
|
+
current = current.parent;
|
|
591
|
+
} else {
|
|
592
|
+
return current._diskRead(key, snapshotVersion);
|
|
397
593
|
}
|
|
398
594
|
}
|
|
399
|
-
|
|
400
|
-
return this.parent._readSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
|
|
401
|
-
} else {
|
|
402
|
-
return this._diskRead(key, snapshotVersion);
|
|
403
|
-
}
|
|
595
|
+
return null;
|
|
404
596
|
}
|
|
405
597
|
commit(label) {
|
|
406
598
|
const { created, updated, deleted } = this.getResultEntries();
|
|
@@ -460,6 +652,7 @@ var require_cjs = __commonJS({
|
|
|
460
652
|
this.deletedValues.clear();
|
|
461
653
|
this.originallyExisted.clear();
|
|
462
654
|
this.keyVersions.clear();
|
|
655
|
+
this.bufferHistory.clear();
|
|
463
656
|
this.localVersion = 0;
|
|
464
657
|
this.snapshotVersion = this.version;
|
|
465
658
|
}
|
|
@@ -500,32 +693,22 @@ var require_cjs = __commonJS({
|
|
|
500
693
|
};
|
|
501
694
|
}
|
|
502
695
|
}
|
|
503
|
-
const
|
|
504
|
-
for (const key of child.writeBuffer
|
|
505
|
-
|
|
506
|
-
this.
|
|
507
|
-
this.
|
|
508
|
-
if (child.createdKeys.has(key)) {
|
|
509
|
-
this.createdKeys.add(key);
|
|
510
|
-
}
|
|
696
|
+
const mergeVersion = ++this.localVersion;
|
|
697
|
+
for (const [key, value] of child.writeBuffer) {
|
|
698
|
+
const wasCreated = child.createdKeys.has(key);
|
|
699
|
+
if (wasCreated) this._bufferCreate(key, value, mergeVersion);
|
|
700
|
+
else this._bufferWrite(key, value, mergeVersion);
|
|
511
701
|
}
|
|
512
702
|
for (const key of child.deleteBuffer) {
|
|
513
|
-
this.deleteBuffer.add(key);
|
|
514
|
-
this.writeBuffer.delete(key);
|
|
515
|
-
this.createdKeys.delete(key);
|
|
516
|
-
this.keyVersions.set(key, newLocalVersion);
|
|
517
703
|
const deletedValue = child.deletedValues.get(key);
|
|
518
|
-
if (deletedValue !== void 0)
|
|
519
|
-
|
|
520
|
-
}
|
|
521
|
-
if (child.originallyExisted.has(key)) {
|
|
704
|
+
if (deletedValue !== void 0) this.deletedValues.set(key, deletedValue);
|
|
705
|
+
if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
|
|
522
706
|
this.originallyExisted.add(key);
|
|
523
707
|
}
|
|
708
|
+
this._bufferDelete(key, mergeVersion);
|
|
524
709
|
}
|
|
525
|
-
this.localVersion = newLocalVersion;
|
|
526
710
|
this.root.activeTransactions.delete(child);
|
|
527
711
|
} else {
|
|
528
|
-
const newVersion = this.version + 1;
|
|
529
712
|
if (child !== this) {
|
|
530
713
|
const modifiedKeys = /* @__PURE__ */ new Set([...child.writeBuffer.keys(), ...child.deleteBuffer]);
|
|
531
714
|
for (const key of modifiedKeys) {
|
|
@@ -543,50 +726,57 @@ var require_cjs = __commonJS({
|
|
|
543
726
|
};
|
|
544
727
|
}
|
|
545
728
|
}
|
|
729
|
+
const lastModLocalVer = this.keyVersions.get(key);
|
|
730
|
+
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
731
|
+
return {
|
|
732
|
+
error: `Commit conflict: Key '${key}' was modified by a newer transaction in the same session (Local v${lastModLocalVer})`,
|
|
733
|
+
conflict: {
|
|
734
|
+
key,
|
|
735
|
+
parent: this.read(key),
|
|
736
|
+
child: child.read(key)
|
|
737
|
+
}
|
|
738
|
+
};
|
|
739
|
+
}
|
|
546
740
|
}
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
for (const key of child.deleteBuffer) {
|
|
556
|
-
this.deleteBuffer.add(key);
|
|
557
|
-
this.writeBuffer.delete(key);
|
|
558
|
-
this.createdKeys.delete(key);
|
|
559
|
-
const deletedValue = child.deletedValues.get(key);
|
|
560
|
-
if (deletedValue !== void 0) {
|
|
561
|
-
this.deletedValues.set(key, deletedValue);
|
|
741
|
+
const mergeVersion = ++this.localVersion;
|
|
742
|
+
for (const [key, value] of child.writeBuffer) {
|
|
743
|
+
const wasCreated = child.createdKeys.has(key);
|
|
744
|
+
if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
|
|
745
|
+
this.originallyExisted.add(key);
|
|
746
|
+
}
|
|
747
|
+
if (wasCreated) this._bufferCreate(key, value, mergeVersion);
|
|
748
|
+
else this._bufferWrite(key, value, mergeVersion);
|
|
562
749
|
}
|
|
563
|
-
|
|
564
|
-
|
|
750
|
+
for (const key of child.deleteBuffer) {
|
|
751
|
+
const deletedValue = child.deletedValues.get(key);
|
|
752
|
+
if (deletedValue !== void 0) this.deletedValues.set(key, deletedValue);
|
|
753
|
+
if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
|
|
754
|
+
this.originallyExisted.add(key);
|
|
755
|
+
}
|
|
756
|
+
this._bufferDelete(key, mergeVersion);
|
|
565
757
|
}
|
|
758
|
+
this.root.activeTransactions.delete(child);
|
|
759
|
+
} else {
|
|
760
|
+
const newVersion = this.version + 1;
|
|
761
|
+
for (const [key, value] of this.writeBuffer) this._diskWrite(key, value, newVersion);
|
|
762
|
+
for (const key of this.deleteBuffer) this._diskDelete(key, newVersion);
|
|
763
|
+
this.version = newVersion;
|
|
764
|
+
this._cleanupDeletedCache();
|
|
566
765
|
}
|
|
567
|
-
for (const [key, value] of child.writeBuffer) {
|
|
568
|
-
this._diskWrite(key, value, newVersion);
|
|
569
|
-
}
|
|
570
|
-
for (const key of child.deleteBuffer) {
|
|
571
|
-
this._diskDelete(key, newVersion);
|
|
572
|
-
}
|
|
573
|
-
this.version = newVersion;
|
|
574
|
-
this.root.activeTransactions.delete(child);
|
|
575
|
-
this._cleanupDeletedCache();
|
|
576
766
|
}
|
|
577
767
|
return null;
|
|
578
768
|
}
|
|
579
|
-
// --- Internal IO Helpers (Root Only) ---
|
|
580
769
|
_diskWrite(key, value, version) {
|
|
581
770
|
const strategy = this.strategy;
|
|
582
771
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
583
|
-
|
|
584
|
-
|
|
772
|
+
const rootAsAny = this.root;
|
|
773
|
+
if (this._diskExists(key, version)) {
|
|
774
|
+
const currentVal = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : strategy.read(key);
|
|
585
775
|
if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
|
|
586
|
-
this.deletedCache.get(key).push({
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
776
|
+
this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: version });
|
|
777
|
+
rootAsAny.diskCache.set(key, value);
|
|
778
|
+
} else {
|
|
779
|
+
rootAsAny.diskCache.set(key, value);
|
|
590
780
|
}
|
|
591
781
|
strategy.write(key, value);
|
|
592
782
|
if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
|
|
@@ -597,36 +787,44 @@ var require_cjs = __commonJS({
|
|
|
597
787
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
598
788
|
const versions = this.versionIndex.get(key);
|
|
599
789
|
if (!versions) {
|
|
600
|
-
|
|
790
|
+
const rootAsAny = this.root;
|
|
791
|
+
if (this._diskExists(key, snapshotVersion)) {
|
|
792
|
+
const val = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : strategy.read(key);
|
|
793
|
+
rootAsAny.diskCache.set(key, val);
|
|
794
|
+
return val;
|
|
795
|
+
}
|
|
796
|
+
return null;
|
|
601
797
|
}
|
|
602
798
|
let targetVerObj = null;
|
|
603
799
|
let nextVerObj = null;
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
} else {
|
|
608
|
-
nextVerObj = v;
|
|
609
|
-
break;
|
|
610
|
-
}
|
|
611
|
-
}
|
|
800
|
+
const idx = this._findLastLE(versions, snapshotVersion, "version");
|
|
801
|
+
if (idx >= 0) targetVerObj = versions[idx];
|
|
802
|
+
if (idx + 1 < versions.length) nextVerObj = versions[idx + 1];
|
|
612
803
|
if (!targetVerObj) {
|
|
613
804
|
if (nextVerObj) {
|
|
614
805
|
const cached2 = this.deletedCache.get(key);
|
|
615
806
|
if (cached2) {
|
|
616
|
-
const
|
|
617
|
-
if (
|
|
807
|
+
const cIdx = this._findExact(cached2, nextVerObj.version, "deletedAtVersion");
|
|
808
|
+
if (cIdx >= 0) return cached2[cIdx].value;
|
|
618
809
|
}
|
|
619
810
|
}
|
|
620
811
|
return null;
|
|
621
812
|
}
|
|
622
813
|
if (!targetVerObj.exists) return null;
|
|
623
814
|
if (!nextVerObj) {
|
|
624
|
-
return
|
|
815
|
+
if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
|
|
816
|
+
if (this._diskExists(key, snapshotVersion)) {
|
|
817
|
+
const rootAsAny = this.root;
|
|
818
|
+
const val = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : strategy.read(key);
|
|
819
|
+
rootAsAny.diskCache.set(key, val);
|
|
820
|
+
return val;
|
|
821
|
+
}
|
|
822
|
+
return null;
|
|
625
823
|
}
|
|
626
824
|
const cached = this.deletedCache.get(key);
|
|
627
825
|
if (cached) {
|
|
628
|
-
const
|
|
629
|
-
if (
|
|
826
|
+
const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
|
|
827
|
+
if (cIdx >= 0) return cached[cIdx].value;
|
|
630
828
|
}
|
|
631
829
|
return null;
|
|
632
830
|
}
|
|
@@ -635,31 +833,40 @@ var require_cjs = __commonJS({
|
|
|
635
833
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
636
834
|
const versions = this.versionIndex.get(key);
|
|
637
835
|
if (!versions) {
|
|
638
|
-
|
|
836
|
+
const rootAsAny = this.root;
|
|
837
|
+
if (rootAsAny.diskCache.has(key)) return rootAsAny.diskCache.get(key) !== null;
|
|
838
|
+
const exists = strategy.exists(key);
|
|
839
|
+
if (!exists) rootAsAny.diskCache.set(key, null);
|
|
840
|
+
return exists;
|
|
639
841
|
}
|
|
640
842
|
let targetVerObj = null;
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
843
|
+
let nextVerObj = null;
|
|
844
|
+
const idx = this._findLastLE(versions, snapshotVersion, "version");
|
|
845
|
+
if (idx >= 0) targetVerObj = versions[idx];
|
|
846
|
+
if (idx + 1 < versions.length) nextVerObj = versions[idx + 1];
|
|
847
|
+
if (!targetVerObj) {
|
|
848
|
+
if (nextVerObj) {
|
|
849
|
+
const cached = this.deletedCache.get(key);
|
|
850
|
+
if (cached) {
|
|
851
|
+
const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
|
|
852
|
+
if (cIdx >= 0) return true;
|
|
853
|
+
}
|
|
646
854
|
}
|
|
855
|
+
return false;
|
|
647
856
|
}
|
|
648
|
-
if (!targetVerObj) return strategy.exists(key);
|
|
649
857
|
return targetVerObj.exists;
|
|
650
858
|
}
|
|
651
859
|
_diskDelete(key, snapshotVersion) {
|
|
652
860
|
const strategy = this.strategy;
|
|
653
861
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
654
|
-
|
|
655
|
-
|
|
862
|
+
const rootAsAny = this.root;
|
|
863
|
+
if (this._diskExists(key, snapshotVersion)) {
|
|
864
|
+
const currentVal = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : strategy.read(key);
|
|
656
865
|
if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
|
|
657
|
-
this.deletedCache.get(key).push({
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
});
|
|
866
|
+
this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: snapshotVersion });
|
|
867
|
+
strategy.delete(key);
|
|
868
|
+
rootAsAny.diskCache.delete(key);
|
|
661
869
|
}
|
|
662
|
-
strategy.delete(key);
|
|
663
870
|
if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
|
|
664
871
|
this.versionIndex.get(key).push({ version: snapshotVersion, exists: false });
|
|
665
872
|
}
|
|
@@ -972,7 +1179,7 @@ var require_cjs = __commonJS({
|
|
|
972
1179
|
createNested() {
|
|
973
1180
|
if (this.committed) throw new Error("Transaction already committed");
|
|
974
1181
|
const childVersion = this.isRoot() ? this.version : this.snapshotVersion;
|
|
975
|
-
const child = new _AsyncMVCCTransaction(void 0, this, childVersion);
|
|
1182
|
+
const child = new _AsyncMVCCTransaction(void 0, void 0, this, childVersion);
|
|
976
1183
|
this.root.activeTransactions.add(child);
|
|
977
1184
|
return child;
|
|
978
1185
|
}
|
|
@@ -980,32 +1187,77 @@ var require_cjs = __commonJS({
|
|
|
980
1187
|
if (this.committed) throw new Error("Transaction already committed");
|
|
981
1188
|
if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
|
|
982
1189
|
if (this.deleteBuffer.has(key)) return null;
|
|
983
|
-
|
|
1190
|
+
if (this.parent) {
|
|
1191
|
+
return this.parent._readSnapshot(key, this.snapshotVersion, this.snapshotLocalVersion);
|
|
1192
|
+
}
|
|
1193
|
+
return await this._diskRead(key, this.snapshotVersion);
|
|
984
1194
|
}
|
|
985
1195
|
async exists(key) {
|
|
986
1196
|
if (this.committed) throw new Error("Transaction already committed");
|
|
987
1197
|
if (this.deleteBuffer.has(key)) return false;
|
|
988
1198
|
if (this.writeBuffer.has(key)) return true;
|
|
989
|
-
|
|
1199
|
+
if (this.parent) {
|
|
1200
|
+
return this.parent._existsSnapshot(key, this.snapshotVersion, this.snapshotLocalVersion);
|
|
1201
|
+
}
|
|
1202
|
+
return await this._diskExists(key, this.snapshotVersion);
|
|
990
1203
|
}
|
|
991
|
-
async
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
1204
|
+
async _existsSnapshot(key, snapshotVersion, snapshotLocalVersion) {
|
|
1205
|
+
let current = this;
|
|
1206
|
+
let slVer = snapshotLocalVersion;
|
|
1207
|
+
while (current) {
|
|
1208
|
+
if (current.writeBuffer.has(key)) {
|
|
1209
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
1210
|
+
if (slVer === void 0 || keyModVersion <= slVer) return true;
|
|
1211
|
+
}
|
|
1212
|
+
if (current.deleteBuffer.has(key)) {
|
|
1213
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
1214
|
+
if (slVer === void 0 || keyModVersion <= slVer) return false;
|
|
1215
|
+
}
|
|
1216
|
+
const history = current.bufferHistory.get(key);
|
|
1217
|
+
if (history && slVer !== void 0) {
|
|
1218
|
+
const idx = current._findLastLE(history, slVer, "version");
|
|
1219
|
+
if (idx >= 0) return history[idx].exists;
|
|
1220
|
+
}
|
|
1221
|
+
if (current.parent) {
|
|
1222
|
+
slVer = current.snapshotLocalVersion;
|
|
1223
|
+
current = current.parent;
|
|
1224
|
+
} else {
|
|
1225
|
+
return await current._diskExists(key, snapshotVersion);
|
|
996
1226
|
}
|
|
997
1227
|
}
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1228
|
+
return false;
|
|
1229
|
+
}
|
|
1230
|
+
async _readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
|
|
1231
|
+
let current = this;
|
|
1232
|
+
let slVer = snapshotLocalVersion;
|
|
1233
|
+
while (current) {
|
|
1234
|
+
if (current.writeBuffer.has(key)) {
|
|
1235
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
1236
|
+
if (slVer === void 0 || keyModVersion <= slVer) {
|
|
1237
|
+
return current.writeBuffer.get(key);
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
if (current.deleteBuffer.has(key)) {
|
|
1241
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
1242
|
+
if (slVer === void 0 || keyModVersion <= slVer) {
|
|
1243
|
+
return null;
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
const history = current.bufferHistory.get(key);
|
|
1247
|
+
if (history && slVer !== void 0) {
|
|
1248
|
+
const idx = current._findLastLE(history, slVer, "version");
|
|
1249
|
+
if (idx >= 0) {
|
|
1250
|
+
return history[idx].exists ? history[idx].value : null;
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
if (current.parent) {
|
|
1254
|
+
slVer = current.snapshotLocalVersion;
|
|
1255
|
+
current = current.parent;
|
|
1256
|
+
} else {
|
|
1257
|
+
return await current._diskRead(key, snapshotVersion);
|
|
1002
1258
|
}
|
|
1003
1259
|
}
|
|
1004
|
-
|
|
1005
|
-
return this.parent._readSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
|
|
1006
|
-
} else {
|
|
1007
|
-
return this._diskRead(key, snapshotVersion);
|
|
1008
|
-
}
|
|
1260
|
+
return null;
|
|
1009
1261
|
}
|
|
1010
1262
|
async commit(label) {
|
|
1011
1263
|
const { created, updated, deleted } = this.getResultEntries();
|
|
@@ -1065,6 +1317,7 @@ var require_cjs = __commonJS({
|
|
|
1065
1317
|
this.deletedValues.clear();
|
|
1066
1318
|
this.originallyExisted.clear();
|
|
1067
1319
|
this.keyVersions.clear();
|
|
1320
|
+
this.bufferHistory.clear();
|
|
1068
1321
|
this.localVersion = 0;
|
|
1069
1322
|
this.snapshotVersion = this.version;
|
|
1070
1323
|
}
|
|
@@ -1106,33 +1359,23 @@ var require_cjs = __commonJS({
|
|
|
1106
1359
|
};
|
|
1107
1360
|
}
|
|
1108
1361
|
}
|
|
1109
|
-
const
|
|
1110
|
-
for (const key of child.writeBuffer
|
|
1111
|
-
|
|
1112
|
-
this.
|
|
1113
|
-
this.
|
|
1114
|
-
if (child.createdKeys.has(key)) {
|
|
1115
|
-
this.createdKeys.add(key);
|
|
1116
|
-
}
|
|
1362
|
+
const mergeVersion = ++this.localVersion;
|
|
1363
|
+
for (const [key, value] of child.writeBuffer) {
|
|
1364
|
+
const wasCreated = child.createdKeys.has(key);
|
|
1365
|
+
if (wasCreated) this._bufferCreate(key, value, mergeVersion);
|
|
1366
|
+
else this._bufferWrite(key, value, mergeVersion);
|
|
1117
1367
|
}
|
|
1118
1368
|
for (const key of child.deleteBuffer) {
|
|
1119
|
-
this.deleteBuffer.add(key);
|
|
1120
|
-
this.writeBuffer.delete(key);
|
|
1121
|
-
this.createdKeys.delete(key);
|
|
1122
|
-
this.keyVersions.set(key, newLocalVersion);
|
|
1123
1369
|
const deletedValue = child.deletedValues.get(key);
|
|
1124
|
-
if (deletedValue !== void 0)
|
|
1125
|
-
|
|
1126
|
-
}
|
|
1127
|
-
if (child.originallyExisted.has(key)) {
|
|
1370
|
+
if (deletedValue !== void 0) this.deletedValues.set(key, deletedValue);
|
|
1371
|
+
if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
|
|
1128
1372
|
this.originallyExisted.add(key);
|
|
1129
1373
|
}
|
|
1374
|
+
this._bufferDelete(key, mergeVersion);
|
|
1130
1375
|
}
|
|
1131
|
-
this.localVersion = newLocalVersion;
|
|
1132
1376
|
this.root.activeTransactions.delete(child);
|
|
1133
1377
|
return null;
|
|
1134
1378
|
} else {
|
|
1135
|
-
const newVersion = this.version + 1;
|
|
1136
1379
|
if (child !== this) {
|
|
1137
1380
|
const modifiedKeys = /* @__PURE__ */ new Set([...child.writeBuffer.keys(), ...child.deleteBuffer]);
|
|
1138
1381
|
for (const key of modifiedKeys) {
|
|
@@ -1150,51 +1393,58 @@ var require_cjs = __commonJS({
|
|
|
1150
1393
|
};
|
|
1151
1394
|
}
|
|
1152
1395
|
}
|
|
1396
|
+
const lastModLocalVer = this.keyVersions.get(key);
|
|
1397
|
+
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
1398
|
+
return {
|
|
1399
|
+
error: `Commit conflict: Key '${key}' was modified by a newer transaction in the same session (Local v${lastModLocalVer})`,
|
|
1400
|
+
conflict: {
|
|
1401
|
+
key,
|
|
1402
|
+
parent: await this.read(key),
|
|
1403
|
+
child: await child.read(key)
|
|
1404
|
+
}
|
|
1405
|
+
};
|
|
1406
|
+
}
|
|
1153
1407
|
}
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
for (const key of child.deleteBuffer) {
|
|
1163
|
-
this.deleteBuffer.add(key);
|
|
1164
|
-
this.writeBuffer.delete(key);
|
|
1165
|
-
this.createdKeys.delete(key);
|
|
1166
|
-
const deletedValue = child.deletedValues.get(key);
|
|
1167
|
-
if (deletedValue !== void 0) {
|
|
1168
|
-
this.deletedValues.set(key, deletedValue);
|
|
1408
|
+
const mergeVersion = ++this.localVersion;
|
|
1409
|
+
for (const [key, value] of child.writeBuffer) {
|
|
1410
|
+
const wasCreated = child.createdKeys.has(key);
|
|
1411
|
+
if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
|
|
1412
|
+
this.originallyExisted.add(key);
|
|
1413
|
+
}
|
|
1414
|
+
if (wasCreated) this._bufferCreate(key, value, mergeVersion);
|
|
1415
|
+
else this._bufferWrite(key, value, mergeVersion);
|
|
1169
1416
|
}
|
|
1170
|
-
|
|
1171
|
-
|
|
1417
|
+
for (const key of child.deleteBuffer) {
|
|
1418
|
+
const deletedValue = child.deletedValues.get(key);
|
|
1419
|
+
if (deletedValue !== void 0) this.deletedValues.set(key, deletedValue);
|
|
1420
|
+
if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
|
|
1421
|
+
this.originallyExisted.add(key);
|
|
1422
|
+
}
|
|
1423
|
+
this._bufferDelete(key, mergeVersion);
|
|
1172
1424
|
}
|
|
1425
|
+
this.root.activeTransactions.delete(child);
|
|
1426
|
+
} else {
|
|
1427
|
+
const newVersion = this.version + 1;
|
|
1428
|
+
for (const [key, value] of this.writeBuffer) await this._diskWrite(key, value, newVersion);
|
|
1429
|
+
for (const key of this.deleteBuffer) await this._diskDelete(key, newVersion);
|
|
1430
|
+
this.version = newVersion;
|
|
1431
|
+
this._cleanupDeletedCache();
|
|
1173
1432
|
}
|
|
1174
|
-
for (const [key, value] of child.writeBuffer) {
|
|
1175
|
-
await this._diskWrite(key, value, newVersion);
|
|
1176
|
-
}
|
|
1177
|
-
for (const key of child.deleteBuffer) {
|
|
1178
|
-
await this._diskDelete(key, newVersion);
|
|
1179
|
-
}
|
|
1180
|
-
this.version = newVersion;
|
|
1181
|
-
this.root.activeTransactions.delete(child);
|
|
1182
|
-
this._cleanupDeletedCache();
|
|
1183
1433
|
return null;
|
|
1184
1434
|
}
|
|
1185
1435
|
});
|
|
1186
1436
|
}
|
|
1187
|
-
// --- Internal IO Helpers (Root Only) ---
|
|
1188
1437
|
async _diskWrite(key, value, version) {
|
|
1189
1438
|
const strategy = this.strategy;
|
|
1190
1439
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
1191
|
-
|
|
1192
|
-
|
|
1440
|
+
const rootAsAny = this.root;
|
|
1441
|
+
if (await this._diskExists(key, version)) {
|
|
1442
|
+
const currentVal = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : await strategy.read(key);
|
|
1193
1443
|
if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
|
|
1194
|
-
this.deletedCache.get(key).push({
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1444
|
+
this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: version });
|
|
1445
|
+
rootAsAny.diskCache.set(key, value);
|
|
1446
|
+
} else {
|
|
1447
|
+
rootAsAny.diskCache.set(key, value);
|
|
1198
1448
|
}
|
|
1199
1449
|
await strategy.write(key, value);
|
|
1200
1450
|
if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
|
|
@@ -1205,36 +1455,44 @@ var require_cjs = __commonJS({
|
|
|
1205
1455
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
1206
1456
|
const versions = this.versionIndex.get(key);
|
|
1207
1457
|
if (!versions) {
|
|
1208
|
-
|
|
1458
|
+
const rootAsAny = this.root;
|
|
1459
|
+
if (await this._diskExists(key, snapshotVersion)) {
|
|
1460
|
+
const val = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : await strategy.read(key);
|
|
1461
|
+
rootAsAny.diskCache.set(key, val);
|
|
1462
|
+
return val;
|
|
1463
|
+
}
|
|
1464
|
+
return null;
|
|
1209
1465
|
}
|
|
1210
1466
|
let targetVerObj = null;
|
|
1211
1467
|
let nextVerObj = null;
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
} else {
|
|
1216
|
-
nextVerObj = v;
|
|
1217
|
-
break;
|
|
1218
|
-
}
|
|
1219
|
-
}
|
|
1468
|
+
const idx = this._findLastLE(versions, snapshotVersion, "version");
|
|
1469
|
+
if (idx >= 0) targetVerObj = versions[idx];
|
|
1470
|
+
if (idx + 1 < versions.length) nextVerObj = versions[idx + 1];
|
|
1220
1471
|
if (!targetVerObj) {
|
|
1221
1472
|
if (nextVerObj) {
|
|
1222
1473
|
const cached2 = this.deletedCache.get(key);
|
|
1223
1474
|
if (cached2) {
|
|
1224
|
-
const
|
|
1225
|
-
if (
|
|
1475
|
+
const cIdx = this._findExact(cached2, nextVerObj.version, "deletedAtVersion");
|
|
1476
|
+
if (cIdx >= 0) return cached2[cIdx].value;
|
|
1226
1477
|
}
|
|
1227
1478
|
}
|
|
1228
1479
|
return null;
|
|
1229
1480
|
}
|
|
1230
1481
|
if (!targetVerObj.exists) return null;
|
|
1231
1482
|
if (!nextVerObj) {
|
|
1232
|
-
return
|
|
1483
|
+
if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
|
|
1484
|
+
if (await this._diskExists(key, snapshotVersion)) {
|
|
1485
|
+
const rootAsAny = this.root;
|
|
1486
|
+
const val = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : await strategy.read(key);
|
|
1487
|
+
rootAsAny.diskCache.set(key, val);
|
|
1488
|
+
return val;
|
|
1489
|
+
}
|
|
1490
|
+
return null;
|
|
1233
1491
|
}
|
|
1234
1492
|
const cached = this.deletedCache.get(key);
|
|
1235
1493
|
if (cached) {
|
|
1236
|
-
const
|
|
1237
|
-
if (
|
|
1494
|
+
const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
|
|
1495
|
+
if (cIdx >= 0) return cached[cIdx].value;
|
|
1238
1496
|
}
|
|
1239
1497
|
return null;
|
|
1240
1498
|
}
|
|
@@ -1243,359 +1501,47 @@ var require_cjs = __commonJS({
|
|
|
1243
1501
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
1244
1502
|
const versions = this.versionIndex.get(key);
|
|
1245
1503
|
if (!versions) {
|
|
1246
|
-
|
|
1504
|
+
const rootAsAny = this.root;
|
|
1505
|
+
if (rootAsAny.diskCache.has(key)) return rootAsAny.diskCache.get(key) !== null;
|
|
1506
|
+
const exists = await strategy.exists(key);
|
|
1507
|
+
if (!exists) rootAsAny.diskCache.set(key, null);
|
|
1508
|
+
return exists;
|
|
1247
1509
|
}
|
|
1248
1510
|
let targetVerObj = null;
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1511
|
+
let nextVerObj = null;
|
|
1512
|
+
const idx = this._findLastLE(versions, snapshotVersion, "version");
|
|
1513
|
+
if (idx >= 0) targetVerObj = versions[idx];
|
|
1514
|
+
if (idx + 1 < versions.length) nextVerObj = versions[idx + 1];
|
|
1515
|
+
if (!targetVerObj) {
|
|
1516
|
+
if (nextVerObj) {
|
|
1517
|
+
const cached = this.deletedCache.get(key);
|
|
1518
|
+
if (cached) {
|
|
1519
|
+
const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
|
|
1520
|
+
if (cIdx >= 0) return true;
|
|
1521
|
+
}
|
|
1254
1522
|
}
|
|
1523
|
+
return false;
|
|
1255
1524
|
}
|
|
1256
|
-
if (!targetVerObj) return strategy.exists(key);
|
|
1257
1525
|
return targetVerObj.exists;
|
|
1258
1526
|
}
|
|
1259
1527
|
async _diskDelete(key, snapshotVersion) {
|
|
1260
1528
|
const strategy = this.strategy;
|
|
1261
1529
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
1262
|
-
|
|
1263
|
-
|
|
1530
|
+
const rootAsAny = this.root;
|
|
1531
|
+
if (await this._diskExists(key, snapshotVersion)) {
|
|
1532
|
+
const currentVal = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : await strategy.read(key);
|
|
1264
1533
|
if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
|
|
1265
|
-
this.deletedCache.get(key).push({
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
});
|
|
1534
|
+
this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: snapshotVersion });
|
|
1535
|
+
await strategy.delete(key);
|
|
1536
|
+
rootAsAny.diskCache.delete(key);
|
|
1269
1537
|
}
|
|
1270
|
-
await strategy.delete(key);
|
|
1271
1538
|
if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
|
|
1272
1539
|
this.versionIndex.get(key).push({ version: snapshotVersion, exists: false });
|
|
1273
1540
|
}
|
|
1274
1541
|
};
|
|
1275
|
-
var LRUMap = class {
|
|
1276
|
-
capacity;
|
|
1277
|
-
map;
|
|
1278
|
-
head = null;
|
|
1279
|
-
tail = null;
|
|
1280
|
-
/**
|
|
1281
|
-
* Creates an instance of LRUMap.
|
|
1282
|
-
* @param capacity The maximum number of items the cache can hold.
|
|
1283
|
-
*/
|
|
1284
|
-
constructor(capacity) {
|
|
1285
|
-
this.capacity = capacity;
|
|
1286
|
-
this.map = /* @__PURE__ */ new Map();
|
|
1287
|
-
}
|
|
1288
|
-
/**
|
|
1289
|
-
* Promotes a node to the head of the linked list (marks as most recently used).
|
|
1290
|
-
* @param node The node to promote.
|
|
1291
|
-
*/
|
|
1292
|
-
promote(node) {
|
|
1293
|
-
this.extract(node);
|
|
1294
|
-
this.prepend(node);
|
|
1295
|
-
}
|
|
1296
|
-
/**
|
|
1297
|
-
* Disconnects a node from the doubly linked list.
|
|
1298
|
-
* @param node The node to extract.
|
|
1299
|
-
*/
|
|
1300
|
-
extract(node) {
|
|
1301
|
-
if (node.prev) node.prev.next = node.next;
|
|
1302
|
-
else this.head = node.next;
|
|
1303
|
-
if (node.next) node.next.prev = node.prev;
|
|
1304
|
-
else this.tail = node.prev;
|
|
1305
|
-
node.prev = null;
|
|
1306
|
-
node.next = null;
|
|
1307
|
-
}
|
|
1308
|
-
/**
|
|
1309
|
-
* Inserts a node at the head of the doubly linked list.
|
|
1310
|
-
* @param node The node to prepend.
|
|
1311
|
-
*/
|
|
1312
|
-
prepend(node) {
|
|
1313
|
-
node.next = this.head;
|
|
1314
|
-
if (this.head) this.head.prev = node;
|
|
1315
|
-
this.head = node;
|
|
1316
|
-
if (!this.tail) this.tail = node;
|
|
1317
|
-
}
|
|
1318
|
-
/**
|
|
1319
|
-
* Stores or updates a value by key.
|
|
1320
|
-
* If the capacity is exceeded, the least recently used item (tail) is removed.
|
|
1321
|
-
* @param key The key to store.
|
|
1322
|
-
* @param value The value to store.
|
|
1323
|
-
*/
|
|
1324
|
-
set(key, value) {
|
|
1325
|
-
const existing = this.map.get(key);
|
|
1326
|
-
if (existing) {
|
|
1327
|
-
existing.value = value;
|
|
1328
|
-
this.promote(existing);
|
|
1329
|
-
return;
|
|
1330
|
-
}
|
|
1331
|
-
const newNode = { key, value, prev: null, next: null };
|
|
1332
|
-
this.map.set(key, newNode);
|
|
1333
|
-
this.prepend(newNode);
|
|
1334
|
-
if (this.map.size > this.capacity && this.tail) {
|
|
1335
|
-
this.map.delete(this.tail.key);
|
|
1336
|
-
this.extract(this.tail);
|
|
1337
|
-
}
|
|
1338
|
-
}
|
|
1339
|
-
/**
|
|
1340
|
-
* Retrieves a value by key.
|
|
1341
|
-
* Accessing the item moves it to the "most recently used" position.
|
|
1342
|
-
* @param key The key to look for.
|
|
1343
|
-
* @returns The value associated with the key, or undefined if not found.
|
|
1344
|
-
*/
|
|
1345
|
-
get(key) {
|
|
1346
|
-
const node = this.map.get(key);
|
|
1347
|
-
if (!node) return void 0;
|
|
1348
|
-
this.promote(node);
|
|
1349
|
-
return node.value;
|
|
1350
|
-
}
|
|
1351
|
-
/**
|
|
1352
|
-
* Checks if a key exists in the cache without changing its access order.
|
|
1353
|
-
* @param key The key to check.
|
|
1354
|
-
* @returns True if the key exists, false otherwise.
|
|
1355
|
-
*/
|
|
1356
|
-
has(key) {
|
|
1357
|
-
return this.map.has(key);
|
|
1358
|
-
}
|
|
1359
|
-
/**
|
|
1360
|
-
* Removes a key and its associated value from the cache.
|
|
1361
|
-
* @param key The key to remove.
|
|
1362
|
-
* @returns True if the key was found and removed, false otherwise.
|
|
1363
|
-
*/
|
|
1364
|
-
delete(key) {
|
|
1365
|
-
const node = this.map.get(key);
|
|
1366
|
-
if (!node) return false;
|
|
1367
|
-
this.extract(node);
|
|
1368
|
-
this.map.delete(key);
|
|
1369
|
-
return true;
|
|
1370
|
-
}
|
|
1371
|
-
/**
|
|
1372
|
-
* Returns an iterator of keys in the order of most recently used to least recently used.
|
|
1373
|
-
* @returns An iterable iterator of keys.
|
|
1374
|
-
*/
|
|
1375
|
-
*keys() {
|
|
1376
|
-
let current = this.head;
|
|
1377
|
-
while (current) {
|
|
1378
|
-
yield current.key;
|
|
1379
|
-
current = current.next;
|
|
1380
|
-
}
|
|
1381
|
-
}
|
|
1382
|
-
/**
|
|
1383
|
-
* Returns the current number of items in the cache.
|
|
1384
|
-
*/
|
|
1385
|
-
get size() {
|
|
1386
|
-
return this.map.size;
|
|
1387
|
-
}
|
|
1388
|
-
/**
|
|
1389
|
-
* Clears all items from the cache.
|
|
1390
|
-
*/
|
|
1391
|
-
clear() {
|
|
1392
|
-
this.map.clear();
|
|
1393
|
-
this.head = null;
|
|
1394
|
-
this.tail = null;
|
|
1395
|
-
}
|
|
1396
|
-
};
|
|
1397
|
-
var CacheEntanglement = class {
|
|
1398
|
-
creation;
|
|
1399
|
-
beforeUpdateHook;
|
|
1400
|
-
capacity;
|
|
1401
|
-
dependencies;
|
|
1402
|
-
caches;
|
|
1403
|
-
parameters;
|
|
1404
|
-
assignments;
|
|
1405
|
-
dependencyProperties;
|
|
1406
|
-
updateRequirements;
|
|
1407
|
-
constructor(creation, option) {
|
|
1408
|
-
option = option ?? {};
|
|
1409
|
-
const {
|
|
1410
|
-
dependencies,
|
|
1411
|
-
capacity,
|
|
1412
|
-
beforeUpdateHook
|
|
1413
|
-
} = option;
|
|
1414
|
-
this.creation = creation;
|
|
1415
|
-
this.beforeUpdateHook = beforeUpdateHook ?? (() => {
|
|
1416
|
-
});
|
|
1417
|
-
this.capacity = capacity ?? 100;
|
|
1418
|
-
this.assignments = [];
|
|
1419
|
-
this.caches = new LRUMap(this.capacity);
|
|
1420
|
-
this.parameters = /* @__PURE__ */ new Map();
|
|
1421
|
-
this.dependencies = dependencies ?? {};
|
|
1422
|
-
this.dependencyProperties = Object.keys(this.dependencies);
|
|
1423
|
-
this.updateRequirements = /* @__PURE__ */ new Set();
|
|
1424
|
-
for (const name in this.dependencies) {
|
|
1425
|
-
const dependency = this.dependencies[name];
|
|
1426
|
-
if (!dependency.assignments.includes(this)) {
|
|
1427
|
-
dependency.assignments.push(this);
|
|
1428
|
-
}
|
|
1429
|
-
}
|
|
1430
|
-
}
|
|
1431
|
-
bubbleUpdateSignal(key) {
|
|
1432
|
-
this.updateRequirements.add(key);
|
|
1433
|
-
for (let i = 0, len = this.assignments.length; i < len; i++) {
|
|
1434
|
-
const t = this.assignments[i];
|
|
1435
|
-
const instance = t;
|
|
1436
|
-
for (const cacheKey of instance.caches.keys()) {
|
|
1437
|
-
if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
|
|
1438
|
-
instance.bubbleUpdateSignal(cacheKey);
|
|
1439
|
-
}
|
|
1440
|
-
}
|
|
1441
|
-
}
|
|
1442
|
-
}
|
|
1443
|
-
dependencyKey(key) {
|
|
1444
|
-
const i = key.lastIndexOf("/");
|
|
1445
|
-
if (i === -1) {
|
|
1446
|
-
return key;
|
|
1447
|
-
}
|
|
1448
|
-
return key.substring(0, i);
|
|
1449
|
-
}
|
|
1450
|
-
/**
|
|
1451
|
-
* Returns all keys stored in the instance.
|
|
1452
|
-
*/
|
|
1453
|
-
keys() {
|
|
1454
|
-
return this.parameters.keys();
|
|
1455
|
-
}
|
|
1456
|
-
/**
|
|
1457
|
-
* Deletes all cache values stored in the instance.
|
|
1458
|
-
*/
|
|
1459
|
-
clear() {
|
|
1460
|
-
for (const key of this.keys()) {
|
|
1461
|
-
this.delete(key);
|
|
1462
|
-
}
|
|
1463
|
-
}
|
|
1464
|
-
/**
|
|
1465
|
-
* Checks if there is a cache value stored in the key within the instance.
|
|
1466
|
-
* @param key The key to search.
|
|
1467
|
-
*/
|
|
1468
|
-
exists(key) {
|
|
1469
|
-
return this.parameters.has(key);
|
|
1470
|
-
}
|
|
1471
|
-
/**
|
|
1472
|
-
* Checks if there is a cache value stored in the key within the instance.
|
|
1473
|
-
* This method is an alias for `exists`.
|
|
1474
|
-
* @param key The key to search.
|
|
1475
|
-
*/
|
|
1476
|
-
has(key) {
|
|
1477
|
-
return this.exists(key);
|
|
1478
|
-
}
|
|
1479
|
-
/**
|
|
1480
|
-
* Deletes the cache value stored in the key within the instance.
|
|
1481
|
-
* @param key The key to delete.
|
|
1482
|
-
*/
|
|
1483
|
-
delete(key) {
|
|
1484
|
-
this.caches.delete(key);
|
|
1485
|
-
this.parameters.delete(key);
|
|
1486
|
-
this.updateRequirements.delete(key);
|
|
1487
|
-
for (let i = 0, len = this.assignments.length; i < len; i++) {
|
|
1488
|
-
const t = this.assignments[i];
|
|
1489
|
-
const instance = t;
|
|
1490
|
-
for (const cacheKey of instance.keys()) {
|
|
1491
|
-
if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
|
|
1492
|
-
instance.delete(cacheKey);
|
|
1493
|
-
}
|
|
1494
|
-
}
|
|
1495
|
-
}
|
|
1496
|
-
}
|
|
1497
|
-
};
|
|
1498
|
-
var CacheData = class _CacheData {
|
|
1499
|
-
static StructuredClone = globalThis.structuredClone.bind(globalThis);
|
|
1500
|
-
_value;
|
|
1501
|
-
constructor(value) {
|
|
1502
|
-
this._value = value;
|
|
1503
|
-
}
|
|
1504
|
-
/**
|
|
1505
|
-
* This is cached data.
|
|
1506
|
-
* It was generated at the time of caching, so there is a risk of modification if it's an object due to shallow copying.
|
|
1507
|
-
* Therefore, if it's not a primitive type, please avoid using this value directly and use the `clone` method to use a copied version of the data.
|
|
1508
|
-
*/
|
|
1509
|
-
get raw() {
|
|
1510
|
-
return this._value;
|
|
1511
|
-
}
|
|
1512
|
-
/**
|
|
1513
|
-
* The method returns a copied value of the cached data.
|
|
1514
|
-
* You can pass a function as a parameter to copy the value. This parameter function should return the copied value.
|
|
1515
|
-
*
|
|
1516
|
-
* If no parameter is passed, it defaults to using `structuredClone` function to copy the value.
|
|
1517
|
-
* If you prefer shallow copying instead of deep copying,
|
|
1518
|
-
* you can use the default options `array-shallow-copy`, `object-shallow-copy` and `deep-copy`,
|
|
1519
|
-
* which are replaced with functions to shallow copy arrays and objects, respectively. This is a syntactic sugar.
|
|
1520
|
-
* @param strategy The function that returns the copied value.
|
|
1521
|
-
* If you want to perform a shallow copy, simply pass the strings `array-shallow-copy` or `object-shallow-copy` for easy use.
|
|
1522
|
-
* The `array-shallow-copy` strategy performs a shallow copy of an array.
|
|
1523
|
-
* The `object-shallow-copy` strategy performs a shallow copy of an object.
|
|
1524
|
-
* The `deep-copy` strategy performs a deep copy of the value using `structuredClone`.
|
|
1525
|
-
* The default is `deep-copy`.
|
|
1526
|
-
*/
|
|
1527
|
-
clone(strategy = "deep-copy") {
|
|
1528
|
-
if (strategy && typeof strategy !== "string") {
|
|
1529
|
-
return strategy(this.raw);
|
|
1530
|
-
}
|
|
1531
|
-
switch (strategy) {
|
|
1532
|
-
case "array-shallow-copy":
|
|
1533
|
-
return [].concat(this.raw);
|
|
1534
|
-
case "object-shallow-copy":
|
|
1535
|
-
return Object.assign({}, this.raw);
|
|
1536
|
-
case "deep-copy":
|
|
1537
|
-
default:
|
|
1538
|
-
return _CacheData.StructuredClone(this.raw);
|
|
1539
|
-
}
|
|
1540
|
-
}
|
|
1541
|
-
};
|
|
1542
|
-
var CacheEntanglementSync = class extends CacheEntanglement {
|
|
1543
|
-
constructor(creation, option) {
|
|
1544
|
-
super(creation, option);
|
|
1545
|
-
}
|
|
1546
|
-
recache(key) {
|
|
1547
|
-
if (!this.parameters.has(key)) {
|
|
1548
|
-
return;
|
|
1549
|
-
}
|
|
1550
|
-
if (!this.caches.has(key) || this.updateRequirements.has(key)) {
|
|
1551
|
-
this.resolve(key, ...this.parameters.get(key));
|
|
1552
|
-
}
|
|
1553
|
-
return this.caches.get(key);
|
|
1554
|
-
}
|
|
1555
|
-
resolve(key, ...parameter) {
|
|
1556
|
-
const resolved = {};
|
|
1557
|
-
const dependencyKey = this.dependencyKey(key);
|
|
1558
|
-
this.beforeUpdateHook(key, dependencyKey, ...parameter);
|
|
1559
|
-
for (let i = 0, len = this.dependencyProperties.length; i < len; i++) {
|
|
1560
|
-
const name = this.dependencyProperties[i];
|
|
1561
|
-
const dependency = this.dependencies[name];
|
|
1562
|
-
if (!dependency.exists(key) && !dependency.exists(dependencyKey)) {
|
|
1563
|
-
throw new Error(`The key '${key}' or '${dependencyKey}' has not been assigned yet in dependency '${name.toString()}'.`, {
|
|
1564
|
-
cause: {
|
|
1565
|
-
from: this
|
|
1566
|
-
}
|
|
1567
|
-
});
|
|
1568
|
-
}
|
|
1569
|
-
const dependencyValue = dependency.recache(key) ?? dependency.recache(dependencyKey);
|
|
1570
|
-
resolved[name] = dependencyValue;
|
|
1571
|
-
}
|
|
1572
|
-
const value = new CacheData(this.creation(key, resolved, ...parameter));
|
|
1573
|
-
this.updateRequirements.delete(key);
|
|
1574
|
-
this.parameters.set(key, parameter);
|
|
1575
|
-
this.caches.set(key, value);
|
|
1576
|
-
return value;
|
|
1577
|
-
}
|
|
1578
|
-
get(key) {
|
|
1579
|
-
if (!this.parameters.has(key)) {
|
|
1580
|
-
throw new Error(`Cache value not found: ${key}`);
|
|
1581
|
-
}
|
|
1582
|
-
return this.cache(key, ...this.parameters.get(key));
|
|
1583
|
-
}
|
|
1584
|
-
cache(key, ...parameter) {
|
|
1585
|
-
if (!this.caches.has(key) || this.updateRequirements.has(key)) {
|
|
1586
|
-
this.resolve(key, ...parameter);
|
|
1587
|
-
}
|
|
1588
|
-
return this.caches.get(key);
|
|
1589
|
-
}
|
|
1590
|
-
update(key, ...parameter) {
|
|
1591
|
-
this.bubbleUpdateSignal(key);
|
|
1592
|
-
this.resolve(key, ...parameter);
|
|
1593
|
-
return this.caches.get(key);
|
|
1594
|
-
}
|
|
1595
|
-
};
|
|
1596
1542
|
var BPTreeTransaction = class _BPTreeTransaction {
|
|
1597
|
-
_cachedRegexp;
|
|
1598
|
-
nodes;
|
|
1543
|
+
_cachedRegexp = /* @__PURE__ */ new Map();
|
|
1544
|
+
nodes = /* @__PURE__ */ new Map();
|
|
1599
1545
|
deletedNodeBuffer = /* @__PURE__ */ new Map();
|
|
1600
1546
|
rootTx;
|
|
1601
1547
|
mvccRoot;
|
|
@@ -1605,6 +1551,8 @@ var require_cjs = __commonJS({
|
|
|
1605
1551
|
option;
|
|
1606
1552
|
order;
|
|
1607
1553
|
rootId;
|
|
1554
|
+
isInitialized = false;
|
|
1555
|
+
isDestroyed = false;
|
|
1608
1556
|
verifierMap = {
|
|
1609
1557
|
gt: (nv, v) => this.comparator.isHigher(nv, v),
|
|
1610
1558
|
gte: (nv, v) => this.comparator.isHigher(nv, v) || this.comparator.isSame(nv, v),
|
|
@@ -1623,8 +1571,12 @@ var require_cjs = __commonJS({
|
|
|
1623
1571
|
like: (nv, v) => {
|
|
1624
1572
|
const nodeValue = this.comparator.match(nv);
|
|
1625
1573
|
const value = v;
|
|
1626
|
-
|
|
1627
|
-
|
|
1574
|
+
if (!this._cachedRegexp.has(value)) {
|
|
1575
|
+
const pattern = value.replace(/%/g, ".*").replace(/_/g, ".");
|
|
1576
|
+
const regexp2 = new RegExp(`^${pattern}$`, "i");
|
|
1577
|
+
this._cachedRegexp.set(value, regexp2);
|
|
1578
|
+
}
|
|
1579
|
+
const regexp = this._cachedRegexp.get(value);
|
|
1628
1580
|
return regexp.test(nodeValue);
|
|
1629
1581
|
}
|
|
1630
1582
|
};
|
|
@@ -1765,6 +1717,15 @@ var require_cjs = __commonJS({
|
|
|
1765
1717
|
}
|
|
1766
1718
|
return best;
|
|
1767
1719
|
}
|
|
1720
|
+
/**
|
|
1721
|
+
* Checks for conflicts between multiple transactions.
|
|
1722
|
+
*
|
|
1723
|
+
* @param transactions Array of BPTreeTransaction instances to check
|
|
1724
|
+
* @returns An array of keys that are in conflict. Empty array if no conflicts.
|
|
1725
|
+
*/
|
|
1726
|
+
static CheckConflicts(transactions) {
|
|
1727
|
+
return MVCCTransaction.CheckConflicts(transactions.map((tx) => tx.mvcc));
|
|
1728
|
+
}
|
|
1768
1729
|
/**
|
|
1769
1730
|
* Returns the ID of the root node.
|
|
1770
1731
|
* @returns The root node ID.
|
|
@@ -1796,6 +1757,9 @@ var require_cjs = __commonJS({
|
|
|
1796
1757
|
}
|
|
1797
1758
|
return true;
|
|
1798
1759
|
}
|
|
1760
|
+
_cloneNode(node) {
|
|
1761
|
+
return JSON.parse(JSON.stringify(node));
|
|
1762
|
+
}
|
|
1799
1763
|
/**
|
|
1800
1764
|
* Selects the best driver key from a condition object.
|
|
1801
1765
|
* The driver key determines the starting point and traversal direction for queries.
|
|
@@ -1828,17 +1792,6 @@ var require_cjs = __commonJS({
|
|
|
1828
1792
|
this.strategy = strategy;
|
|
1829
1793
|
this.comparator = comparator;
|
|
1830
1794
|
this.option = option ?? {};
|
|
1831
|
-
this.nodes = new LRUMap(this.option.capacity ?? 1e3);
|
|
1832
|
-
this._cachedRegexp = this._createCachedRegexp();
|
|
1833
|
-
}
|
|
1834
|
-
_createCachedRegexp() {
|
|
1835
|
-
return new CacheEntanglementSync((key) => {
|
|
1836
|
-
const pattern = key.replace(/%/g, ".*").replace(/_/g, ".");
|
|
1837
|
-
const regexp = new RegExp(`^${pattern}$`, "i");
|
|
1838
|
-
return regexp;
|
|
1839
|
-
}, {
|
|
1840
|
-
capacity: this.option.capacity ?? 1e3
|
|
1841
|
-
});
|
|
1842
1795
|
}
|
|
1843
1796
|
ensureValues(v) {
|
|
1844
1797
|
if (!Array.isArray(v)) {
|
|
@@ -1869,13 +1822,25 @@ var require_cjs = __commonJS({
|
|
|
1869
1822
|
getResultEntries() {
|
|
1870
1823
|
return this.mvcc.getResultEntries();
|
|
1871
1824
|
}
|
|
1825
|
+
_clearCache() {
|
|
1826
|
+
this._cachedRegexp.clear();
|
|
1827
|
+
}
|
|
1872
1828
|
/**
|
|
1873
1829
|
* Clears all cached nodes.
|
|
1874
1830
|
* This method is useful for freeing up memory when the tree is no longer needed.
|
|
1875
1831
|
*/
|
|
1876
1832
|
clear() {
|
|
1877
|
-
this.
|
|
1878
|
-
|
|
1833
|
+
if (this.rootTx !== this) {
|
|
1834
|
+
throw new Error("Cannot call clear on a nested transaction");
|
|
1835
|
+
}
|
|
1836
|
+
this._clearInternal();
|
|
1837
|
+
}
|
|
1838
|
+
_clearInternal() {
|
|
1839
|
+
if (this.isDestroyed) {
|
|
1840
|
+
throw new Error("Transaction already destroyed");
|
|
1841
|
+
}
|
|
1842
|
+
this._clearCache();
|
|
1843
|
+
this.isDestroyed = true;
|
|
1879
1844
|
}
|
|
1880
1845
|
_binarySearchValues(values, target, usePrimary = false, upperBound = false) {
|
|
1881
1846
|
let low = 0;
|
|
@@ -1909,9 +1874,6 @@ var require_cjs = __commonJS({
|
|
|
1909
1874
|
);
|
|
1910
1875
|
}
|
|
1911
1876
|
getNode(id) {
|
|
1912
|
-
if (this.nodes.has(id)) {
|
|
1913
|
-
return this.nodes.get(id);
|
|
1914
|
-
}
|
|
1915
1877
|
return this.mvcc.read(id);
|
|
1916
1878
|
}
|
|
1917
1879
|
/**
|
|
@@ -1929,23 +1891,22 @@ var require_cjs = __commonJS({
|
|
|
1929
1891
|
prev
|
|
1930
1892
|
};
|
|
1931
1893
|
this.mvcc.create(id, node);
|
|
1932
|
-
this.nodes.set(id, node);
|
|
1933
1894
|
return node;
|
|
1934
1895
|
}
|
|
1935
1896
|
_updateNode(node) {
|
|
1897
|
+
if (this.mvcc.isDeleted(node.id)) {
|
|
1898
|
+
return;
|
|
1899
|
+
}
|
|
1936
1900
|
this.mvcc.write(node.id, node);
|
|
1937
|
-
this.nodes.set(node.id, node);
|
|
1938
1901
|
}
|
|
1939
1902
|
_deleteNode(node) {
|
|
1903
|
+
if (this.mvcc.isDeleted(node.id)) {
|
|
1904
|
+
return;
|
|
1905
|
+
}
|
|
1940
1906
|
this.mvcc.delete(node.id);
|
|
1941
|
-
this.nodes.delete(node.id);
|
|
1942
1907
|
}
|
|
1943
1908
|
_readHead() {
|
|
1944
|
-
|
|
1945
|
-
return this.nodes.get("__HEAD__") ?? null;
|
|
1946
|
-
}
|
|
1947
|
-
const head = this.mvcc.read("__HEAD__");
|
|
1948
|
-
return head ?? null;
|
|
1909
|
+
return this.mvcc.read("__HEAD__");
|
|
1949
1910
|
}
|
|
1950
1911
|
_writeHead(head) {
|
|
1951
1912
|
if (!this.mvcc.exists("__HEAD__")) {
|
|
@@ -1953,49 +1914,56 @@ var require_cjs = __commonJS({
|
|
|
1953
1914
|
} else {
|
|
1954
1915
|
this.mvcc.write("__HEAD__", head);
|
|
1955
1916
|
}
|
|
1956
|
-
this.nodes.set("__HEAD__", head);
|
|
1957
1917
|
this.rootId = head.root;
|
|
1958
1918
|
}
|
|
1959
1919
|
_insertAtLeaf(node, key, value) {
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1920
|
+
let leaf = node;
|
|
1921
|
+
if (leaf.values.length) {
|
|
1922
|
+
for (let i = 0, len = leaf.values.length; i < len; i++) {
|
|
1923
|
+
const nValue = leaf.values[i];
|
|
1963
1924
|
if (this.comparator.isSame(value, nValue)) {
|
|
1964
|
-
const keys =
|
|
1925
|
+
const keys = leaf.keys[i];
|
|
1965
1926
|
if (keys.includes(key)) {
|
|
1966
1927
|
break;
|
|
1967
1928
|
}
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1929
|
+
leaf = this._cloneNode(leaf);
|
|
1930
|
+
leaf.keys[i].push(key);
|
|
1931
|
+
this._updateNode(leaf);
|
|
1932
|
+
return leaf;
|
|
1971
1933
|
} else if (this.comparator.isLower(value, nValue)) {
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1934
|
+
leaf = this._cloneNode(leaf);
|
|
1935
|
+
leaf.values.splice(i, 0, value);
|
|
1936
|
+
leaf.keys.splice(i, 0, [key]);
|
|
1937
|
+
this._updateNode(leaf);
|
|
1938
|
+
return leaf;
|
|
1939
|
+
} else if (i + 1 === leaf.values.length) {
|
|
1940
|
+
leaf = this._cloneNode(leaf);
|
|
1941
|
+
leaf.values.push(value);
|
|
1942
|
+
leaf.keys.push([key]);
|
|
1943
|
+
this._updateNode(leaf);
|
|
1944
|
+
return leaf;
|
|
1981
1945
|
}
|
|
1982
1946
|
}
|
|
1983
1947
|
} else {
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1948
|
+
leaf = this._cloneNode(leaf);
|
|
1949
|
+
leaf.values = [value];
|
|
1950
|
+
leaf.keys = [[key]];
|
|
1951
|
+
this._updateNode(leaf);
|
|
1952
|
+
return leaf;
|
|
1988
1953
|
}
|
|
1954
|
+
return leaf;
|
|
1989
1955
|
}
|
|
1990
|
-
_insertInParent(node, value,
|
|
1956
|
+
_insertInParent(node, value, newSiblingNode) {
|
|
1991
1957
|
if (this.rootId === node.id) {
|
|
1992
|
-
|
|
1958
|
+
node = this._cloneNode(node);
|
|
1959
|
+
newSiblingNode = this._cloneNode(newSiblingNode);
|
|
1960
|
+
const root = this._createNode(false, [node.id, newSiblingNode.id], [value]);
|
|
1993
1961
|
this.rootId = root.id;
|
|
1994
1962
|
node.parent = root.id;
|
|
1995
|
-
|
|
1996
|
-
if (
|
|
1997
|
-
node.next =
|
|
1998
|
-
|
|
1963
|
+
newSiblingNode.parent = root.id;
|
|
1964
|
+
if (newSiblingNode.leaf) {
|
|
1965
|
+
node.next = newSiblingNode.id;
|
|
1966
|
+
newSiblingNode.prev = node.id;
|
|
1999
1967
|
}
|
|
2000
1968
|
this._writeHead({
|
|
2001
1969
|
root: root.id,
|
|
@@ -2003,53 +1971,54 @@ var require_cjs = __commonJS({
|
|
|
2003
1971
|
data: this.strategy.head.data
|
|
2004
1972
|
});
|
|
2005
1973
|
this._updateNode(node);
|
|
2006
|
-
this._updateNode(
|
|
1974
|
+
this._updateNode(newSiblingNode);
|
|
2007
1975
|
return;
|
|
2008
1976
|
}
|
|
2009
|
-
const parentNode = this.getNode(node.parent);
|
|
1977
|
+
const parentNode = this._cloneNode(this.getNode(node.parent));
|
|
2010
1978
|
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
2011
1979
|
if (nodeIndex === -1) {
|
|
2012
1980
|
throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
|
|
2013
1981
|
}
|
|
2014
1982
|
parentNode.values.splice(nodeIndex, 0, value);
|
|
2015
|
-
parentNode.keys.splice(nodeIndex + 1, 0,
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
1983
|
+
parentNode.keys.splice(nodeIndex + 1, 0, newSiblingNode.id);
|
|
1984
|
+
newSiblingNode = this._cloneNode(newSiblingNode);
|
|
1985
|
+
newSiblingNode.parent = parentNode.id;
|
|
1986
|
+
if (newSiblingNode.leaf) {
|
|
1987
|
+
const leftSibling = this._cloneNode(node);
|
|
2019
1988
|
const oldNextId = leftSibling.next;
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
leftSibling.next =
|
|
1989
|
+
newSiblingNode.prev = leftSibling.id;
|
|
1990
|
+
newSiblingNode.next = oldNextId;
|
|
1991
|
+
leftSibling.next = newSiblingNode.id;
|
|
2023
1992
|
this._updateNode(leftSibling);
|
|
2024
1993
|
if (oldNextId) {
|
|
2025
|
-
const oldNext = this.getNode(oldNextId);
|
|
2026
|
-
oldNext.prev =
|
|
1994
|
+
const oldNext = this._cloneNode(this.getNode(oldNextId));
|
|
1995
|
+
oldNext.prev = newSiblingNode.id;
|
|
2027
1996
|
this._updateNode(oldNext);
|
|
2028
1997
|
}
|
|
2029
1998
|
}
|
|
2030
1999
|
this._updateNode(parentNode);
|
|
2031
|
-
this._updateNode(
|
|
2000
|
+
this._updateNode(newSiblingNode);
|
|
2032
2001
|
if (parentNode.keys.length > this.order) {
|
|
2033
|
-
const
|
|
2034
|
-
|
|
2002
|
+
const newSiblingNodeRecursive = this._createNode(false, [], []);
|
|
2003
|
+
newSiblingNodeRecursive.parent = parentNode.parent;
|
|
2035
2004
|
const mid = Math.ceil(this.order / 2) - 1;
|
|
2036
|
-
|
|
2037
|
-
|
|
2005
|
+
newSiblingNodeRecursive.values = parentNode.values.slice(mid + 1);
|
|
2006
|
+
newSiblingNodeRecursive.keys = parentNode.keys.slice(mid + 1);
|
|
2038
2007
|
const midValue = parentNode.values[mid];
|
|
2039
2008
|
parentNode.values = parentNode.values.slice(0, mid);
|
|
2040
2009
|
parentNode.keys = parentNode.keys.slice(0, mid + 1);
|
|
2041
2010
|
for (const k of parentNode.keys) {
|
|
2042
|
-
const n = this.getNode(k);
|
|
2011
|
+
const n = this._cloneNode(this.getNode(k));
|
|
2043
2012
|
n.parent = parentNode.id;
|
|
2044
2013
|
this._updateNode(n);
|
|
2045
2014
|
}
|
|
2046
|
-
for (const k of
|
|
2047
|
-
const n = this.getNode(k);
|
|
2048
|
-
n.parent =
|
|
2015
|
+
for (const k of newSiblingNodeRecursive.keys) {
|
|
2016
|
+
const n = this._cloneNode(this.getNode(k));
|
|
2017
|
+
n.parent = newSiblingNodeRecursive.id;
|
|
2049
2018
|
this._updateNode(n);
|
|
2050
2019
|
}
|
|
2051
2020
|
this._updateNode(parentNode);
|
|
2052
|
-
this._insertInParent(parentNode, midValue,
|
|
2021
|
+
this._insertInParent(parentNode, midValue, newSiblingNodeRecursive);
|
|
2053
2022
|
}
|
|
2054
2023
|
}
|
|
2055
2024
|
insertableNode(value) {
|
|
@@ -2179,28 +2148,42 @@ var require_cjs = __commonJS({
|
|
|
2179
2148
|
}
|
|
2180
2149
|
}
|
|
2181
2150
|
init() {
|
|
2182
|
-
this.
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
const { root, order } = head;
|
|
2194
|
-
this.strategy.head = head;
|
|
2195
|
-
this.order = order;
|
|
2196
|
-
this._writeHead({
|
|
2197
|
-
root,
|
|
2198
|
-
order: this.order,
|
|
2199
|
-
data: this.strategy.head.data
|
|
2200
|
-
});
|
|
2151
|
+
if (this.rootTx !== this) {
|
|
2152
|
+
throw new Error("Cannot call init on a nested transaction");
|
|
2153
|
+
}
|
|
2154
|
+
this._initInternal();
|
|
2155
|
+
}
|
|
2156
|
+
_initInternal() {
|
|
2157
|
+
if (this.isInitialized) {
|
|
2158
|
+
throw new Error("Transaction already initialized");
|
|
2159
|
+
}
|
|
2160
|
+
if (this.isDestroyed) {
|
|
2161
|
+
throw new Error("Transaction already destroyed");
|
|
2201
2162
|
}
|
|
2202
|
-
|
|
2203
|
-
|
|
2163
|
+
this.isInitialized = true;
|
|
2164
|
+
try {
|
|
2165
|
+
this._clearCache();
|
|
2166
|
+
const head = this._readHead();
|
|
2167
|
+
if (head === null) {
|
|
2168
|
+
this.order = this.strategy.order;
|
|
2169
|
+
const root = this._createNode(true, [], []);
|
|
2170
|
+
this._writeHead({
|
|
2171
|
+
root: root.id,
|
|
2172
|
+
order: this.order,
|
|
2173
|
+
data: this.strategy.head.data
|
|
2174
|
+
});
|
|
2175
|
+
} else {
|
|
2176
|
+
const { root, order } = head;
|
|
2177
|
+
this.strategy.head = head;
|
|
2178
|
+
this.order = order;
|
|
2179
|
+
this.rootId = root;
|
|
2180
|
+
}
|
|
2181
|
+
if (this.order < 3) {
|
|
2182
|
+
throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
|
|
2183
|
+
}
|
|
2184
|
+
} catch (e) {
|
|
2185
|
+
this.isInitialized = false;
|
|
2186
|
+
throw e;
|
|
2204
2187
|
}
|
|
2205
2188
|
}
|
|
2206
2189
|
exists(key, value) {
|
|
@@ -2214,21 +2197,6 @@ var require_cjs = __commonJS({
|
|
|
2214
2197
|
}
|
|
2215
2198
|
return false;
|
|
2216
2199
|
}
|
|
2217
|
-
forceUpdate(id) {
|
|
2218
|
-
if (id) {
|
|
2219
|
-
this.nodes.delete(id);
|
|
2220
|
-
this.getNode(id);
|
|
2221
|
-
return 1;
|
|
2222
|
-
}
|
|
2223
|
-
const keys = Array.from(this.nodes.keys());
|
|
2224
|
-
for (const key of keys) {
|
|
2225
|
-
this.nodes.delete(key);
|
|
2226
|
-
}
|
|
2227
|
-
for (const key of keys) {
|
|
2228
|
-
this.getNode(key);
|
|
2229
|
-
}
|
|
2230
|
-
return keys.length;
|
|
2231
|
-
}
|
|
2232
2200
|
get(key) {
|
|
2233
2201
|
let node = this.leftestNode();
|
|
2234
2202
|
while (true) {
|
|
@@ -2314,10 +2282,10 @@ var require_cjs = __commonJS({
|
|
|
2314
2282
|
return map;
|
|
2315
2283
|
}
|
|
2316
2284
|
insert(key, value) {
|
|
2317
|
-
|
|
2318
|
-
this._insertAtLeaf(before, key, value);
|
|
2285
|
+
let before = this.insertableNode(value);
|
|
2286
|
+
before = this._insertAtLeaf(before, key, value);
|
|
2319
2287
|
if (before.values.length === this.order) {
|
|
2320
|
-
|
|
2288
|
+
let after = this._createNode(
|
|
2321
2289
|
true,
|
|
2322
2290
|
[],
|
|
2323
2291
|
[],
|
|
@@ -2326,10 +2294,13 @@ var require_cjs = __commonJS({
|
|
|
2326
2294
|
null
|
|
2327
2295
|
);
|
|
2328
2296
|
const mid = Math.ceil(this.order / 2) - 1;
|
|
2297
|
+
after = this._cloneNode(after);
|
|
2329
2298
|
after.values = before.values.slice(mid + 1);
|
|
2330
2299
|
after.keys = before.keys.slice(mid + 1);
|
|
2331
2300
|
before.values = before.values.slice(0, mid + 1);
|
|
2332
2301
|
before.keys = before.keys.slice(0, mid + 1);
|
|
2302
|
+
this._updateNode(before);
|
|
2303
|
+
this._updateNode(after);
|
|
2333
2304
|
this._insertInParent(before, after.values[0], after);
|
|
2334
2305
|
}
|
|
2335
2306
|
}
|
|
@@ -2343,6 +2314,7 @@ var require_cjs = __commonJS({
|
|
|
2343
2314
|
}
|
|
2344
2315
|
}
|
|
2345
2316
|
if (keyIndex !== -1) {
|
|
2317
|
+
node = this._cloneNode(node);
|
|
2346
2318
|
node.keys.splice(keyIndex, 1);
|
|
2347
2319
|
const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
|
|
2348
2320
|
node.values.splice(valueIndex, 1);
|
|
@@ -2352,7 +2324,7 @@ var require_cjs = __commonJS({
|
|
|
2352
2324
|
if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
|
|
2353
2325
|
const keys = node.keys;
|
|
2354
2326
|
this._deleteNode(node);
|
|
2355
|
-
const newRoot = this.getNode(keys[0]);
|
|
2327
|
+
const newRoot = this._cloneNode(this.getNode(keys[0]));
|
|
2356
2328
|
newRoot.parent = null;
|
|
2357
2329
|
this._updateNode(newRoot);
|
|
2358
2330
|
this._writeHead({
|
|
@@ -2360,17 +2332,17 @@ var require_cjs = __commonJS({
|
|
|
2360
2332
|
order: this.order,
|
|
2361
2333
|
data: this.strategy.head.data
|
|
2362
2334
|
});
|
|
2363
|
-
return;
|
|
2335
|
+
return node;
|
|
2364
2336
|
} else if (this.rootId === node.id) {
|
|
2365
2337
|
this._writeHead({
|
|
2366
2338
|
root: node.id,
|
|
2367
2339
|
order: this.order,
|
|
2368
2340
|
data: this.strategy.head.data
|
|
2369
2341
|
});
|
|
2370
|
-
return;
|
|
2342
|
+
return node;
|
|
2371
2343
|
} else if (node.keys.length < Math.ceil(this.order / 2) && !node.leaf || node.values.length < Math.ceil((this.order - 1) / 2) && node.leaf) {
|
|
2372
2344
|
if (node.parent === null) {
|
|
2373
|
-
return;
|
|
2345
|
+
return node;
|
|
2374
2346
|
}
|
|
2375
2347
|
let isPredecessor = false;
|
|
2376
2348
|
let parentNode = this.getNode(node.parent);
|
|
@@ -2391,78 +2363,80 @@ var require_cjs = __commonJS({
|
|
|
2391
2363
|
}
|
|
2392
2364
|
}
|
|
2393
2365
|
}
|
|
2394
|
-
let
|
|
2366
|
+
let siblingNode;
|
|
2395
2367
|
let guess;
|
|
2396
2368
|
if (prevNode === null) {
|
|
2397
|
-
|
|
2369
|
+
siblingNode = nextNode;
|
|
2398
2370
|
guess = postValue;
|
|
2399
2371
|
} else if (nextNode === null) {
|
|
2400
2372
|
isPredecessor = true;
|
|
2401
|
-
|
|
2373
|
+
siblingNode = prevNode;
|
|
2402
2374
|
guess = prevValue;
|
|
2403
2375
|
} else {
|
|
2404
2376
|
if (node.values.length + nextNode.values.length < this.order) {
|
|
2405
|
-
|
|
2377
|
+
siblingNode = nextNode;
|
|
2406
2378
|
guess = postValue;
|
|
2407
2379
|
} else {
|
|
2408
2380
|
isPredecessor = true;
|
|
2409
|
-
|
|
2381
|
+
siblingNode = prevNode;
|
|
2410
2382
|
guess = prevValue;
|
|
2411
2383
|
}
|
|
2412
2384
|
}
|
|
2413
|
-
if (!
|
|
2414
|
-
return;
|
|
2385
|
+
if (!siblingNode) {
|
|
2386
|
+
return node;
|
|
2415
2387
|
}
|
|
2416
|
-
|
|
2388
|
+
node = this._cloneNode(node);
|
|
2389
|
+
siblingNode = this._cloneNode(siblingNode);
|
|
2390
|
+
if (node.values.length + siblingNode.values.length < this.order) {
|
|
2417
2391
|
if (!isPredecessor) {
|
|
2418
|
-
const pTemp =
|
|
2419
|
-
|
|
2392
|
+
const pTemp = siblingNode;
|
|
2393
|
+
siblingNode = node;
|
|
2420
2394
|
node = pTemp;
|
|
2421
2395
|
}
|
|
2422
|
-
|
|
2396
|
+
siblingNode.keys.push(...node.keys);
|
|
2423
2397
|
if (!node.leaf) {
|
|
2424
|
-
|
|
2398
|
+
siblingNode.values.push(guess);
|
|
2425
2399
|
} else {
|
|
2426
|
-
|
|
2427
|
-
if (
|
|
2428
|
-
const n = this.getNode(
|
|
2429
|
-
n.prev =
|
|
2400
|
+
siblingNode.next = node.next;
|
|
2401
|
+
if (siblingNode.next) {
|
|
2402
|
+
const n = this._cloneNode(this.getNode(siblingNode.next));
|
|
2403
|
+
n.prev = siblingNode.id;
|
|
2430
2404
|
this._updateNode(n);
|
|
2431
2405
|
}
|
|
2432
2406
|
}
|
|
2433
|
-
|
|
2434
|
-
if (!
|
|
2435
|
-
const keys =
|
|
2407
|
+
siblingNode.values.push(...node.values);
|
|
2408
|
+
if (!siblingNode.leaf) {
|
|
2409
|
+
const keys = siblingNode.keys;
|
|
2436
2410
|
for (const key2 of keys) {
|
|
2437
|
-
const node2 = this.getNode(key2);
|
|
2438
|
-
node2.parent =
|
|
2411
|
+
const node2 = this._cloneNode(this.getNode(key2));
|
|
2412
|
+
node2.parent = siblingNode.id;
|
|
2439
2413
|
this._updateNode(node2);
|
|
2440
2414
|
}
|
|
2441
2415
|
}
|
|
2442
2416
|
this._deleteNode(node);
|
|
2443
|
-
this._updateNode(
|
|
2417
|
+
this._updateNode(siblingNode);
|
|
2444
2418
|
this._deleteEntry(this.getNode(node.parent), node.id);
|
|
2445
2419
|
} else {
|
|
2446
2420
|
if (isPredecessor) {
|
|
2447
2421
|
let pointerPm;
|
|
2448
2422
|
let pointerKm;
|
|
2449
2423
|
if (!node.leaf) {
|
|
2450
|
-
pointerPm =
|
|
2451
|
-
pointerKm =
|
|
2424
|
+
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
2425
|
+
pointerKm = siblingNode.values.splice(-1)[0];
|
|
2452
2426
|
node.keys = [pointerPm, ...node.keys];
|
|
2453
2427
|
node.values = [guess, ...node.values];
|
|
2454
|
-
parentNode = this.getNode(node.parent);
|
|
2428
|
+
parentNode = this._cloneNode(this.getNode(node.parent));
|
|
2455
2429
|
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
2456
2430
|
if (nodeIndex > 0) {
|
|
2457
2431
|
parentNode.values[nodeIndex - 1] = pointerKm;
|
|
2458
2432
|
this._updateNode(parentNode);
|
|
2459
2433
|
}
|
|
2460
2434
|
} else {
|
|
2461
|
-
pointerPm =
|
|
2462
|
-
pointerKm =
|
|
2435
|
+
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
2436
|
+
pointerKm = siblingNode.values.splice(-1)[0];
|
|
2463
2437
|
node.keys = [pointerPm, ...node.keys];
|
|
2464
2438
|
node.values = [pointerKm, ...node.values];
|
|
2465
|
-
parentNode = this.getNode(node.parent);
|
|
2439
|
+
parentNode = this._cloneNode(this.getNode(node.parent));
|
|
2466
2440
|
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
2467
2441
|
if (nodeIndex > 0) {
|
|
2468
2442
|
parentNode.values[nodeIndex - 1] = pointerKm;
|
|
@@ -2470,63 +2444,70 @@ var require_cjs = __commonJS({
|
|
|
2470
2444
|
}
|
|
2471
2445
|
}
|
|
2472
2446
|
this._updateNode(node);
|
|
2473
|
-
this._updateNode(
|
|
2447
|
+
this._updateNode(siblingNode);
|
|
2474
2448
|
} else {
|
|
2475
2449
|
let pointerP0;
|
|
2476
2450
|
let pointerK0;
|
|
2477
2451
|
if (!node.leaf) {
|
|
2478
|
-
pointerP0 =
|
|
2479
|
-
pointerK0 =
|
|
2452
|
+
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
2453
|
+
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
2480
2454
|
node.keys = [...node.keys, pointerP0];
|
|
2481
2455
|
node.values = [...node.values, guess];
|
|
2482
|
-
parentNode = this.getNode(node.parent);
|
|
2483
|
-
const pointerIndex = parentNode.keys.indexOf(
|
|
2456
|
+
parentNode = this._cloneNode(this.getNode(node.parent));
|
|
2457
|
+
const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
|
|
2484
2458
|
if (pointerIndex > 0) {
|
|
2485
2459
|
parentNode.values[pointerIndex - 1] = pointerK0;
|
|
2486
2460
|
this._updateNode(parentNode);
|
|
2487
2461
|
}
|
|
2488
2462
|
} else {
|
|
2489
|
-
pointerP0 =
|
|
2490
|
-
pointerK0 =
|
|
2463
|
+
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
2464
|
+
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
2491
2465
|
node.keys = [...node.keys, pointerP0];
|
|
2492
2466
|
node.values = [...node.values, pointerK0];
|
|
2493
|
-
parentNode = this.getNode(node.parent);
|
|
2494
|
-
const pointerIndex = parentNode.keys.indexOf(
|
|
2467
|
+
parentNode = this._cloneNode(this.getNode(node.parent));
|
|
2468
|
+
const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
|
|
2495
2469
|
if (pointerIndex > 0) {
|
|
2496
|
-
parentNode.values[pointerIndex - 1] =
|
|
2470
|
+
parentNode.values[pointerIndex - 1] = siblingNode.values[0];
|
|
2497
2471
|
this._updateNode(parentNode);
|
|
2498
2472
|
}
|
|
2499
2473
|
}
|
|
2500
2474
|
this._updateNode(node);
|
|
2501
|
-
this._updateNode(
|
|
2475
|
+
this._updateNode(siblingNode);
|
|
2502
2476
|
}
|
|
2503
|
-
if (!
|
|
2504
|
-
for (const key2 of
|
|
2505
|
-
const n = this.getNode(key2);
|
|
2506
|
-
n.parent =
|
|
2477
|
+
if (!siblingNode.leaf) {
|
|
2478
|
+
for (const key2 of siblingNode.keys) {
|
|
2479
|
+
const n = this._cloneNode(this.getNode(key2));
|
|
2480
|
+
n.parent = siblingNode.id;
|
|
2507
2481
|
this._updateNode(n);
|
|
2508
2482
|
}
|
|
2509
2483
|
}
|
|
2510
2484
|
if (!node.leaf) {
|
|
2511
2485
|
for (const key2 of node.keys) {
|
|
2512
|
-
const n = this.getNode(key2);
|
|
2486
|
+
const n = this._cloneNode(this.getNode(key2));
|
|
2513
2487
|
n.parent = node.id;
|
|
2514
2488
|
this._updateNode(n);
|
|
2515
2489
|
}
|
|
2516
2490
|
}
|
|
2517
2491
|
if (!parentNode.leaf) {
|
|
2518
2492
|
for (const key2 of parentNode.keys) {
|
|
2519
|
-
const n = this.getNode(key2);
|
|
2493
|
+
const n = this._cloneNode(this.getNode(key2));
|
|
2520
2494
|
n.parent = parentNode.id;
|
|
2521
2495
|
this._updateNode(n);
|
|
2522
2496
|
}
|
|
2523
2497
|
}
|
|
2524
2498
|
}
|
|
2525
2499
|
} else {
|
|
2526
|
-
this._updateNode(node);
|
|
2500
|
+
this._updateNode(this._cloneNode(node));
|
|
2527
2501
|
}
|
|
2502
|
+
return node;
|
|
2528
2503
|
}
|
|
2529
2504
|
delete(key, value) {
|
|
2505
|
+
if (value === void 0) {
|
|
2506
|
+
value = this.get(key);
|
|
2507
|
+
}
|
|
2508
|
+
if (value === void 0) {
|
|
2509
|
+
return;
|
|
2510
|
+
}
|
|
2530
2511
|
let node = this.insertableNodeByPrimary(value);
|
|
2531
2512
|
let found = false;
|
|
2532
2513
|
while (true) {
|
|
@@ -2537,13 +2518,15 @@ var require_cjs = __commonJS({
|
|
|
2537
2518
|
const keys = node.keys[i];
|
|
2538
2519
|
const keyIndex = keys.indexOf(key);
|
|
2539
2520
|
if (keyIndex !== -1) {
|
|
2540
|
-
|
|
2541
|
-
|
|
2521
|
+
node = this._cloneNode(node);
|
|
2522
|
+
const freshKeys = node.keys[i];
|
|
2523
|
+
freshKeys.splice(keyIndex, 1);
|
|
2524
|
+
if (freshKeys.length === 0) {
|
|
2542
2525
|
node.keys.splice(i, 1);
|
|
2543
2526
|
node.values.splice(i, 1);
|
|
2544
2527
|
}
|
|
2545
2528
|
this._updateNode(node);
|
|
2546
|
-
this._deleteEntry(node, key);
|
|
2529
|
+
node = this._deleteEntry(node, key);
|
|
2547
2530
|
found = true;
|
|
2548
2531
|
break;
|
|
2549
2532
|
}
|
|
@@ -2578,110 +2561,359 @@ var require_cjs = __commonJS({
|
|
|
2578
2561
|
commit(label) {
|
|
2579
2562
|
let result = this.mvcc.commit(label);
|
|
2580
2563
|
if (result.success) {
|
|
2581
|
-
|
|
2582
|
-
if (
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
for (const r of result.created) {
|
|
2587
|
-
this.nodes.set(r.key, r.data);
|
|
2588
|
-
}
|
|
2589
|
-
for (const r of result.updated) {
|
|
2590
|
-
this.nodes.set(r.key, r.data);
|
|
2564
|
+
const isRootTx = this.rootTx === this;
|
|
2565
|
+
if (!isRootTx) {
|
|
2566
|
+
result = this.rootTx.commit(label);
|
|
2567
|
+
if (result.success) {
|
|
2568
|
+
this.rootTx.rootId = this.rootId;
|
|
2591
2569
|
}
|
|
2592
|
-
|
|
2593
|
-
|
|
2570
|
+
}
|
|
2571
|
+
}
|
|
2572
|
+
return result;
|
|
2573
|
+
}
|
|
2574
|
+
rollback() {
|
|
2575
|
+
return this.mvcc.rollback();
|
|
2576
|
+
}
|
|
2577
|
+
};
|
|
2578
|
+
var BPTreeMVCCStrategySync = class extends SyncMVCCStrategy {
|
|
2579
|
+
constructor(strategy) {
|
|
2580
|
+
super();
|
|
2581
|
+
this.strategy = strategy;
|
|
2582
|
+
}
|
|
2583
|
+
read(key) {
|
|
2584
|
+
if (key === "__HEAD__") {
|
|
2585
|
+
return this.strategy.readHead();
|
|
2586
|
+
}
|
|
2587
|
+
return this.strategy.read(key);
|
|
2588
|
+
}
|
|
2589
|
+
write(key, value) {
|
|
2590
|
+
if (key === "__HEAD__") {
|
|
2591
|
+
this.strategy.writeHead(value);
|
|
2592
|
+
} else {
|
|
2593
|
+
this.strategy.write(key, value);
|
|
2594
|
+
}
|
|
2595
|
+
}
|
|
2596
|
+
delete(key) {
|
|
2597
|
+
this.strategy.delete(key);
|
|
2598
|
+
}
|
|
2599
|
+
exists(key) {
|
|
2600
|
+
if (key === "__HEAD__") {
|
|
2601
|
+
return this.strategy.readHead() !== null;
|
|
2602
|
+
}
|
|
2603
|
+
try {
|
|
2604
|
+
const node = this.strategy.read(key);
|
|
2605
|
+
return node !== null && node !== void 0;
|
|
2606
|
+
} catch {
|
|
2607
|
+
return false;
|
|
2608
|
+
}
|
|
2609
|
+
}
|
|
2610
|
+
};
|
|
2611
|
+
var BPTreeSync = class extends BPTreeSyncTransaction {
|
|
2612
|
+
constructor(strategy, comparator, option) {
|
|
2613
|
+
const mvccRoot = new SyncMVCCTransaction(new BPTreeMVCCStrategySync(strategy), {
|
|
2614
|
+
cacheCapacity: option?.capacity ?? void 0
|
|
2615
|
+
});
|
|
2616
|
+
super(
|
|
2617
|
+
null,
|
|
2618
|
+
mvccRoot,
|
|
2619
|
+
mvccRoot,
|
|
2620
|
+
strategy,
|
|
2621
|
+
comparator,
|
|
2622
|
+
option
|
|
2623
|
+
);
|
|
2624
|
+
}
|
|
2625
|
+
/**
|
|
2626
|
+
* Creates a new synchronous transaction.
|
|
2627
|
+
* @returns A new BPTreeSyncTransaction.
|
|
2628
|
+
*/
|
|
2629
|
+
createTransaction() {
|
|
2630
|
+
const nestedTx = this.mvcc.createNested();
|
|
2631
|
+
const tx = new BPTreeSyncTransaction(
|
|
2632
|
+
this,
|
|
2633
|
+
this.mvcc,
|
|
2634
|
+
nestedTx,
|
|
2635
|
+
this.strategy,
|
|
2636
|
+
this.comparator,
|
|
2637
|
+
this.option
|
|
2638
|
+
);
|
|
2639
|
+
tx._initInternal();
|
|
2640
|
+
return tx;
|
|
2641
|
+
}
|
|
2642
|
+
insert(key, value) {
|
|
2643
|
+
const tx = this.createTransaction();
|
|
2644
|
+
tx.insert(key, value);
|
|
2645
|
+
const result = tx.commit();
|
|
2646
|
+
if (!result.success) {
|
|
2647
|
+
throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
|
|
2648
|
+
}
|
|
2649
|
+
}
|
|
2650
|
+
delete(key, value) {
|
|
2651
|
+
const tx = this.createTransaction();
|
|
2652
|
+
tx.delete(key, value);
|
|
2653
|
+
const result = tx.commit();
|
|
2654
|
+
if (!result.success) {
|
|
2655
|
+
throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
|
|
2656
|
+
}
|
|
2657
|
+
}
|
|
2658
|
+
};
|
|
2659
|
+
var Ryoiki22 = class _Ryoiki2 {
|
|
2660
|
+
readings;
|
|
2661
|
+
writings;
|
|
2662
|
+
readQueue;
|
|
2663
|
+
writeQueue;
|
|
2664
|
+
static async CatchError(promise) {
|
|
2665
|
+
return await promise.then((v) => [void 0, v]).catch((err) => [err]);
|
|
2666
|
+
}
|
|
2667
|
+
static IsRangeOverlap(a, b) {
|
|
2668
|
+
const [start1, end1] = a;
|
|
2669
|
+
const [start2, end2] = b;
|
|
2670
|
+
if (end1 <= start2 || end2 <= start1) {
|
|
2671
|
+
return false;
|
|
2672
|
+
}
|
|
2673
|
+
return true;
|
|
2674
|
+
}
|
|
2675
|
+
static ERR_ALREADY_EXISTS(lockId) {
|
|
2676
|
+
return new Error(`The '${lockId}' task already existing in queue or running.`);
|
|
2677
|
+
}
|
|
2678
|
+
static ERR_NOT_EXISTS(lockId) {
|
|
2679
|
+
return new Error(`The '${lockId}' task not existing in task queue.`);
|
|
2680
|
+
}
|
|
2681
|
+
static ERR_TIMEOUT(lockId, timeout) {
|
|
2682
|
+
return new Error(`The task with ID '${lockId}' failed to acquire the lock within the timeout(${timeout}ms).`);
|
|
2683
|
+
}
|
|
2684
|
+
/**
|
|
2685
|
+
* Constructs a new instance of the Ryoiki class.
|
|
2686
|
+
*/
|
|
2687
|
+
constructor() {
|
|
2688
|
+
this.readings = /* @__PURE__ */ new Map();
|
|
2689
|
+
this.writings = /* @__PURE__ */ new Map();
|
|
2690
|
+
this.readQueue = /* @__PURE__ */ new Map();
|
|
2691
|
+
this.writeQueue = /* @__PURE__ */ new Map();
|
|
2692
|
+
}
|
|
2693
|
+
/**
|
|
2694
|
+
* Creates a range based on a start value and length.
|
|
2695
|
+
* @param start - The starting value of the range.
|
|
2696
|
+
* @param length - The length of the range.
|
|
2697
|
+
* @returns A range tuple [start, start + length].
|
|
2698
|
+
*/
|
|
2699
|
+
range(start, length) {
|
|
2700
|
+
return [start, start + length];
|
|
2701
|
+
}
|
|
2702
|
+
rangeOverlapping(tasks, range) {
|
|
2703
|
+
return Array.from(tasks.values()).some((t) => _Ryoiki2.IsRangeOverlap(t.range, range));
|
|
2704
|
+
}
|
|
2705
|
+
isSameRange(a, b) {
|
|
2706
|
+
const [a1, a2] = a;
|
|
2707
|
+
const [b1, b2] = b;
|
|
2708
|
+
return a1 === b1 && a2 === b2;
|
|
2709
|
+
}
|
|
2710
|
+
fetchUnitAndRun(queue, workspaces) {
|
|
2711
|
+
for (const [id, unit] of queue) {
|
|
2712
|
+
if (!unit.condition()) {
|
|
2713
|
+
continue;
|
|
2714
|
+
}
|
|
2715
|
+
this._alloc(queue, workspaces, id);
|
|
2716
|
+
}
|
|
2717
|
+
}
|
|
2718
|
+
_handleOverload(args, handlers, argPatterns) {
|
|
2719
|
+
for (const [key, pattern] of Object.entries(argPatterns)) {
|
|
2720
|
+
if (this._matchArgs(args, pattern)) {
|
|
2721
|
+
return handlers[key](...args);
|
|
2722
|
+
}
|
|
2723
|
+
}
|
|
2724
|
+
throw new Error("Invalid arguments");
|
|
2725
|
+
}
|
|
2726
|
+
_matchArgs(args, pattern) {
|
|
2727
|
+
return args.every((arg, index) => {
|
|
2728
|
+
const expectedType = pattern[index];
|
|
2729
|
+
if (expectedType === void 0) return typeof arg === "undefined";
|
|
2730
|
+
if (expectedType === Function) return typeof arg === "function";
|
|
2731
|
+
if (expectedType === Number) return typeof arg === "number";
|
|
2732
|
+
if (expectedType === Array) return Array.isArray(arg);
|
|
2733
|
+
return false;
|
|
2734
|
+
});
|
|
2735
|
+
}
|
|
2736
|
+
_createRandomId() {
|
|
2737
|
+
const timestamp = Date.now().toString(36);
|
|
2738
|
+
const random = Math.random().toString(36).substring(2);
|
|
2739
|
+
return `${timestamp}${random}`;
|
|
2740
|
+
}
|
|
2741
|
+
_alloc(queue, workspaces, lockId) {
|
|
2742
|
+
const unit = queue.get(lockId);
|
|
2743
|
+
if (!unit) {
|
|
2744
|
+
throw _Ryoiki2.ERR_NOT_EXISTS(lockId);
|
|
2745
|
+
}
|
|
2746
|
+
workspaces.set(lockId, unit);
|
|
2747
|
+
queue.delete(lockId);
|
|
2748
|
+
unit.alloc();
|
|
2749
|
+
}
|
|
2750
|
+
_free(workspaces, lockId) {
|
|
2751
|
+
const unit = workspaces.get(lockId);
|
|
2752
|
+
if (!unit) {
|
|
2753
|
+
throw _Ryoiki2.ERR_NOT_EXISTS(lockId);
|
|
2754
|
+
}
|
|
2755
|
+
workspaces.delete(lockId);
|
|
2756
|
+
unit.free();
|
|
2757
|
+
}
|
|
2758
|
+
_lock(queue, range, timeout, task, condition) {
|
|
2759
|
+
return new Promise((resolve, reject) => {
|
|
2760
|
+
let timeoutId = null;
|
|
2761
|
+
if (timeout >= 0) {
|
|
2762
|
+
timeoutId = setTimeout(() => {
|
|
2763
|
+
reject(_Ryoiki2.ERR_TIMEOUT(id, timeout));
|
|
2764
|
+
}, timeout);
|
|
2765
|
+
}
|
|
2766
|
+
const id = this._createRandomId();
|
|
2767
|
+
const alloc = async () => {
|
|
2768
|
+
if (timeoutId !== null) {
|
|
2769
|
+
clearTimeout(timeoutId);
|
|
2594
2770
|
}
|
|
2771
|
+
const [err, v] = await _Ryoiki2.CatchError(task(id));
|
|
2772
|
+
if (err) reject(err);
|
|
2773
|
+
else resolve(v);
|
|
2774
|
+
};
|
|
2775
|
+
const fetch = () => {
|
|
2776
|
+
this.fetchUnitAndRun(this.readQueue, this.readings);
|
|
2777
|
+
this.fetchUnitAndRun(this.writeQueue, this.writings);
|
|
2778
|
+
};
|
|
2779
|
+
queue.set(id, { id, range, condition, alloc, free: fetch });
|
|
2780
|
+
fetch();
|
|
2781
|
+
});
|
|
2782
|
+
}
|
|
2783
|
+
_checkWorking(range, workspaces) {
|
|
2784
|
+
let isLocked = false;
|
|
2785
|
+
for (const lock of workspaces.values()) {
|
|
2786
|
+
if (_Ryoiki2.IsRangeOverlap(range, lock.range)) {
|
|
2787
|
+
isLocked = true;
|
|
2788
|
+
break;
|
|
2595
2789
|
}
|
|
2596
2790
|
}
|
|
2597
|
-
return
|
|
2598
|
-
}
|
|
2599
|
-
rollback() {
|
|
2600
|
-
return this.mvcc.rollback();
|
|
2601
|
-
}
|
|
2602
|
-
};
|
|
2603
|
-
var BPTreeMVCCStrategySync = class extends SyncMVCCStrategy {
|
|
2604
|
-
constructor(strategy) {
|
|
2605
|
-
super();
|
|
2606
|
-
this.strategy = strategy;
|
|
2791
|
+
return isLocked;
|
|
2607
2792
|
}
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2793
|
+
/**
|
|
2794
|
+
* Checks if there is any active read lock within the specified range.
|
|
2795
|
+
* @param range The range to check for active read locks.
|
|
2796
|
+
* @returns `true` if there is an active read lock within the range, `false` otherwise.
|
|
2797
|
+
*/
|
|
2798
|
+
isReading(range) {
|
|
2799
|
+
return this._checkWorking(range, this.readings);
|
|
2613
2800
|
}
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2801
|
+
/**
|
|
2802
|
+
* Checks if there is any active write lock within the specified range.
|
|
2803
|
+
* @param range The range to check for active write locks.
|
|
2804
|
+
* @returns `true` if there is an active write lock within the range, `false` otherwise.
|
|
2805
|
+
*/
|
|
2806
|
+
isWriting(range) {
|
|
2807
|
+
return this._checkWorking(range, this.writings);
|
|
2620
2808
|
}
|
|
2621
|
-
|
|
2622
|
-
|
|
2809
|
+
/**
|
|
2810
|
+
* Checks if a read lock can be acquired within the specified range.
|
|
2811
|
+
* @param range The range to check for read lock availability.
|
|
2812
|
+
* @returns `true` if a read lock can be acquired, `false` otherwise.
|
|
2813
|
+
*/
|
|
2814
|
+
canRead(range) {
|
|
2815
|
+
const writing = this.isWriting(range);
|
|
2816
|
+
return !writing;
|
|
2623
2817
|
}
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
}
|
|
2818
|
+
/**
|
|
2819
|
+
* Checks if a write lock can be acquired within the specified range.
|
|
2820
|
+
* @param range The range to check for write lock availability.
|
|
2821
|
+
* @returns `true` if a write lock can be acquired, `false` otherwise.
|
|
2822
|
+
*/
|
|
2823
|
+
canWrite(range) {
|
|
2824
|
+
const reading = this.isReading(range);
|
|
2825
|
+
const writing = this.isWriting(range);
|
|
2826
|
+
return !reading && !writing;
|
|
2634
2827
|
}
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2828
|
+
/**
|
|
2829
|
+
* Internal implementation of the read lock. Handles both overloads.
|
|
2830
|
+
* @template T - The return type of the task.
|
|
2831
|
+
* @param arg0 - Either a range or a task callback.
|
|
2832
|
+
* If a range is provided, the task is the second argument.
|
|
2833
|
+
* @param arg1 - The task to execute, required if a range is provided.
|
|
2834
|
+
* @param arg2 - The timeout for acquiring the lock.
|
|
2835
|
+
* If the lock cannot be acquired within this period, an error will be thrown.
|
|
2836
|
+
* If this value is not provided, no timeout will be set.
|
|
2837
|
+
* @returns A promise resolving to the result of the task execution.
|
|
2838
|
+
*/
|
|
2839
|
+
readLock(arg0, arg1, arg2) {
|
|
2840
|
+
const [range, task, timeout] = this._handleOverload(
|
|
2841
|
+
[arg0, arg1, arg2],
|
|
2842
|
+
{
|
|
2843
|
+
rangeTask: (range2, task2) => [range2, task2, -1],
|
|
2844
|
+
rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
|
|
2845
|
+
task: (task2) => [[-Infinity, Infinity], task2, -1],
|
|
2846
|
+
taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
|
|
2847
|
+
},
|
|
2848
|
+
{
|
|
2849
|
+
task: [Function],
|
|
2850
|
+
taskTimeout: [Function, Number],
|
|
2851
|
+
rangeTask: [Array, Function],
|
|
2852
|
+
rangeTaskTimeout: [Array, Function, Number]
|
|
2853
|
+
}
|
|
2854
|
+
);
|
|
2855
|
+
return this._lock(
|
|
2856
|
+
this.readQueue,
|
|
2857
|
+
range,
|
|
2858
|
+
timeout,
|
|
2859
|
+
task,
|
|
2860
|
+
() => !this.rangeOverlapping(this.writings, range)
|
|
2646
2861
|
);
|
|
2647
2862
|
}
|
|
2648
2863
|
/**
|
|
2649
|
-
*
|
|
2650
|
-
* @
|
|
2864
|
+
* Internal implementation of the write lock. Handles both overloads.
|
|
2865
|
+
* @template T - The return type of the task.
|
|
2866
|
+
* @param arg0 - Either a range or a task callback.
|
|
2867
|
+
* If a range is provided, the task is the second argument.
|
|
2868
|
+
* @param arg1 - The task to execute, required if a range is provided.
|
|
2869
|
+
* @param arg2 - The timeout for acquiring the lock.
|
|
2870
|
+
* If the lock cannot be acquired within this period, an error will be thrown.
|
|
2871
|
+
* If this value is not provided, no timeout will be set.
|
|
2872
|
+
* @returns A promise resolving to the result of the task execution.
|
|
2651
2873
|
*/
|
|
2652
|
-
|
|
2653
|
-
const
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2874
|
+
writeLock(arg0, arg1, arg2) {
|
|
2875
|
+
const [range, task, timeout] = this._handleOverload(
|
|
2876
|
+
[arg0, arg1, arg2],
|
|
2877
|
+
{
|
|
2878
|
+
rangeTask: (range2, task2) => [range2, task2, -1],
|
|
2879
|
+
rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
|
|
2880
|
+
task: (task2) => [[-Infinity, Infinity], task2, -1],
|
|
2881
|
+
taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
|
|
2882
|
+
},
|
|
2883
|
+
{
|
|
2884
|
+
task: [Function],
|
|
2885
|
+
taskTimeout: [Function, Number],
|
|
2886
|
+
rangeTask: [Array, Function],
|
|
2887
|
+
rangeTaskTimeout: [Array, Function, Number]
|
|
2888
|
+
}
|
|
2889
|
+
);
|
|
2890
|
+
return this._lock(
|
|
2891
|
+
this.writeQueue,
|
|
2892
|
+
range,
|
|
2893
|
+
timeout,
|
|
2894
|
+
task,
|
|
2895
|
+
() => {
|
|
2896
|
+
return !this.rangeOverlapping(this.writings, range) && !this.rangeOverlapping(this.readings, range);
|
|
2897
|
+
}
|
|
2661
2898
|
);
|
|
2662
|
-
tx.init();
|
|
2663
|
-
return tx;
|
|
2664
2899
|
}
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
}
|
|
2672
|
-
this.rootId = tx.getRootId();
|
|
2900
|
+
/**
|
|
2901
|
+
* Releases a read lock by its lock ID.
|
|
2902
|
+
* @param lockId - The unique identifier for the lock to release.
|
|
2903
|
+
*/
|
|
2904
|
+
readUnlock(lockId) {
|
|
2905
|
+
this._free(this.readings, lockId);
|
|
2673
2906
|
}
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
}
|
|
2681
|
-
this.rootId = tx.getRootId();
|
|
2907
|
+
/**
|
|
2908
|
+
* Releases a write lock by its lock ID.
|
|
2909
|
+
* @param lockId - The unique identifier for the lock to release.
|
|
2910
|
+
*/
|
|
2911
|
+
writeUnlock(lockId) {
|
|
2912
|
+
this._free(this.writings, lockId);
|
|
2682
2913
|
}
|
|
2683
2914
|
};
|
|
2684
2915
|
var BPTreeAsyncTransaction2 = class extends BPTreeTransaction {
|
|
2916
|
+
lock;
|
|
2685
2917
|
constructor(rootTx, mvccRoot, mvcc, strategy, comparator, option) {
|
|
2686
2918
|
super(
|
|
2687
2919
|
rootTx,
|
|
@@ -2691,11 +2923,18 @@ var require_cjs = __commonJS({
|
|
|
2691
2923
|
comparator,
|
|
2692
2924
|
option
|
|
2693
2925
|
);
|
|
2926
|
+
this.lock = new Ryoiki22();
|
|
2927
|
+
}
|
|
2928
|
+
async writeLock(id, fn) {
|
|
2929
|
+
let lockId;
|
|
2930
|
+
return this.lock.writeLock([id, id + 0.1], async (_lockId) => {
|
|
2931
|
+
lockId = _lockId;
|
|
2932
|
+
return fn();
|
|
2933
|
+
}).finally(() => {
|
|
2934
|
+
this.lock.writeUnlock(lockId);
|
|
2935
|
+
});
|
|
2694
2936
|
}
|
|
2695
2937
|
async getNode(id) {
|
|
2696
|
-
if (this.nodes.has(id)) {
|
|
2697
|
-
return this.nodes.get(id);
|
|
2698
|
-
}
|
|
2699
2938
|
return await this.mvcc.read(id);
|
|
2700
2939
|
}
|
|
2701
2940
|
/**
|
|
@@ -2713,23 +2952,22 @@ var require_cjs = __commonJS({
|
|
|
2713
2952
|
prev
|
|
2714
2953
|
};
|
|
2715
2954
|
await this.mvcc.create(id, node);
|
|
2716
|
-
this.nodes.set(id, node);
|
|
2717
2955
|
return node;
|
|
2718
2956
|
}
|
|
2719
2957
|
async _updateNode(node) {
|
|
2958
|
+
if (this.mvcc.isDeleted(node.id)) {
|
|
2959
|
+
return;
|
|
2960
|
+
}
|
|
2720
2961
|
await this.mvcc.write(node.id, node);
|
|
2721
|
-
this.nodes.set(node.id, node);
|
|
2722
2962
|
}
|
|
2723
2963
|
async _deleteNode(node) {
|
|
2964
|
+
if (this.mvcc.isDeleted(node.id)) {
|
|
2965
|
+
return;
|
|
2966
|
+
}
|
|
2724
2967
|
await this.mvcc.delete(node.id);
|
|
2725
|
-
this.nodes.delete(node.id);
|
|
2726
2968
|
}
|
|
2727
2969
|
async _readHead() {
|
|
2728
|
-
|
|
2729
|
-
return this.nodes.get("__HEAD__") ?? null;
|
|
2730
|
-
}
|
|
2731
|
-
const head = await this.mvcc.read("__HEAD__");
|
|
2732
|
-
return head ?? null;
|
|
2970
|
+
return await this.mvcc.read("__HEAD__");
|
|
2733
2971
|
}
|
|
2734
2972
|
async _writeHead(head) {
|
|
2735
2973
|
if (!await this.mvcc.exists("__HEAD__")) {
|
|
@@ -2737,49 +2975,56 @@ var require_cjs = __commonJS({
|
|
|
2737
2975
|
} else {
|
|
2738
2976
|
await this.mvcc.write("__HEAD__", head);
|
|
2739
2977
|
}
|
|
2740
|
-
this.nodes.set("__HEAD__", head);
|
|
2741
2978
|
this.rootId = head.root;
|
|
2742
2979
|
}
|
|
2743
2980
|
async _insertAtLeaf(node, key, value) {
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2981
|
+
let leaf = node;
|
|
2982
|
+
if (leaf.values.length) {
|
|
2983
|
+
for (let i = 0, len = leaf.values.length; i < len; i++) {
|
|
2984
|
+
const nValue = leaf.values[i];
|
|
2747
2985
|
if (this.comparator.isSame(value, nValue)) {
|
|
2748
|
-
const keys =
|
|
2986
|
+
const keys = leaf.keys[i];
|
|
2749
2987
|
if (keys.includes(key)) {
|
|
2750
2988
|
break;
|
|
2751
2989
|
}
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2990
|
+
leaf = this._cloneNode(leaf);
|
|
2991
|
+
leaf.keys[i].push(key);
|
|
2992
|
+
await this._updateNode(leaf);
|
|
2993
|
+
return leaf;
|
|
2755
2994
|
} else if (this.comparator.isLower(value, nValue)) {
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2995
|
+
leaf = this._cloneNode(leaf);
|
|
2996
|
+
leaf.values.splice(i, 0, value);
|
|
2997
|
+
leaf.keys.splice(i, 0, [key]);
|
|
2998
|
+
await this._updateNode(leaf);
|
|
2999
|
+
return leaf;
|
|
3000
|
+
} else if (i + 1 === leaf.values.length) {
|
|
3001
|
+
leaf = this._cloneNode(leaf);
|
|
3002
|
+
leaf.values.push(value);
|
|
3003
|
+
leaf.keys.push([key]);
|
|
3004
|
+
await this._updateNode(leaf);
|
|
3005
|
+
return leaf;
|
|
2765
3006
|
}
|
|
2766
3007
|
}
|
|
2767
3008
|
} else {
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
3009
|
+
leaf = this._cloneNode(leaf);
|
|
3010
|
+
leaf.values = [value];
|
|
3011
|
+
leaf.keys = [[key]];
|
|
3012
|
+
await this._updateNode(leaf);
|
|
3013
|
+
return leaf;
|
|
2772
3014
|
}
|
|
3015
|
+
return leaf;
|
|
2773
3016
|
}
|
|
2774
|
-
async _insertInParent(node, value,
|
|
3017
|
+
async _insertInParent(node, value, newSiblingNode) {
|
|
2775
3018
|
if (this.rootId === node.id) {
|
|
2776
|
-
|
|
3019
|
+
node = this._cloneNode(node);
|
|
3020
|
+
newSiblingNode = this._cloneNode(newSiblingNode);
|
|
3021
|
+
const root = await this._createNode(false, [node.id, newSiblingNode.id], [value]);
|
|
2777
3022
|
this.rootId = root.id;
|
|
2778
3023
|
node.parent = root.id;
|
|
2779
|
-
|
|
2780
|
-
if (
|
|
2781
|
-
node.next =
|
|
2782
|
-
|
|
3024
|
+
newSiblingNode.parent = root.id;
|
|
3025
|
+
if (newSiblingNode.leaf) {
|
|
3026
|
+
node.next = newSiblingNode.id;
|
|
3027
|
+
newSiblingNode.prev = node.id;
|
|
2783
3028
|
}
|
|
2784
3029
|
await this._writeHead({
|
|
2785
3030
|
root: root.id,
|
|
@@ -2787,53 +3032,54 @@ var require_cjs = __commonJS({
|
|
|
2787
3032
|
data: this.strategy.head.data
|
|
2788
3033
|
});
|
|
2789
3034
|
await this._updateNode(node);
|
|
2790
|
-
await this._updateNode(
|
|
3035
|
+
await this._updateNode(newSiblingNode);
|
|
2791
3036
|
return;
|
|
2792
3037
|
}
|
|
2793
|
-
const parentNode = await this.getNode(node.parent);
|
|
3038
|
+
const parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
2794
3039
|
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
2795
3040
|
if (nodeIndex === -1) {
|
|
2796
3041
|
throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
|
|
2797
3042
|
}
|
|
2798
3043
|
parentNode.values.splice(nodeIndex, 0, value);
|
|
2799
|
-
parentNode.keys.splice(nodeIndex + 1, 0,
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
3044
|
+
parentNode.keys.splice(nodeIndex + 1, 0, newSiblingNode.id);
|
|
3045
|
+
newSiblingNode = this._cloneNode(newSiblingNode);
|
|
3046
|
+
newSiblingNode.parent = parentNode.id;
|
|
3047
|
+
if (newSiblingNode.leaf) {
|
|
3048
|
+
const leftSibling = this._cloneNode(node);
|
|
2803
3049
|
const oldNextId = leftSibling.next;
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
leftSibling.next =
|
|
3050
|
+
newSiblingNode.prev = leftSibling.id;
|
|
3051
|
+
newSiblingNode.next = oldNextId;
|
|
3052
|
+
leftSibling.next = newSiblingNode.id;
|
|
2807
3053
|
await this._updateNode(leftSibling);
|
|
2808
3054
|
if (oldNextId) {
|
|
2809
|
-
const oldNext = await this.getNode(oldNextId);
|
|
2810
|
-
oldNext.prev =
|
|
3055
|
+
const oldNext = this._cloneNode(await this.getNode(oldNextId));
|
|
3056
|
+
oldNext.prev = newSiblingNode.id;
|
|
2811
3057
|
await this._updateNode(oldNext);
|
|
2812
3058
|
}
|
|
2813
3059
|
}
|
|
2814
3060
|
await this._updateNode(parentNode);
|
|
2815
|
-
await this._updateNode(
|
|
3061
|
+
await this._updateNode(newSiblingNode);
|
|
2816
3062
|
if (parentNode.keys.length > this.order) {
|
|
2817
|
-
const
|
|
2818
|
-
|
|
3063
|
+
const newSiblingNodeRecursive = await this._createNode(false, [], []);
|
|
3064
|
+
newSiblingNodeRecursive.parent = parentNode.parent;
|
|
2819
3065
|
const mid = Math.ceil(this.order / 2) - 1;
|
|
2820
|
-
|
|
2821
|
-
|
|
3066
|
+
newSiblingNodeRecursive.values = parentNode.values.slice(mid + 1);
|
|
3067
|
+
newSiblingNodeRecursive.keys = parentNode.keys.slice(mid + 1);
|
|
2822
3068
|
const midValue = parentNode.values[mid];
|
|
2823
3069
|
parentNode.values = parentNode.values.slice(0, mid);
|
|
2824
3070
|
parentNode.keys = parentNode.keys.slice(0, mid + 1);
|
|
2825
3071
|
for (const k of parentNode.keys) {
|
|
2826
|
-
const n = await this.getNode(k);
|
|
3072
|
+
const n = this._cloneNode(await this.getNode(k));
|
|
2827
3073
|
n.parent = parentNode.id;
|
|
2828
3074
|
await this._updateNode(n);
|
|
2829
3075
|
}
|
|
2830
|
-
for (const k of
|
|
2831
|
-
const n = await this.getNode(k);
|
|
2832
|
-
n.parent =
|
|
3076
|
+
for (const k of newSiblingNodeRecursive.keys) {
|
|
3077
|
+
const n = this._cloneNode(await this.getNode(k));
|
|
3078
|
+
n.parent = newSiblingNodeRecursive.id;
|
|
2833
3079
|
await this._updateNode(n);
|
|
2834
3080
|
}
|
|
2835
3081
|
await this._updateNode(parentNode);
|
|
2836
|
-
await this._insertInParent(parentNode, midValue,
|
|
3082
|
+
await this._insertInParent(parentNode, midValue, newSiblingNodeRecursive);
|
|
2837
3083
|
}
|
|
2838
3084
|
}
|
|
2839
3085
|
async insertableNode(value) {
|
|
@@ -2969,28 +3215,42 @@ var require_cjs = __commonJS({
|
|
|
2969
3215
|
}
|
|
2970
3216
|
}
|
|
2971
3217
|
async init() {
|
|
2972
|
-
this.
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
const { root, order } = head;
|
|
2984
|
-
this.strategy.head = head;
|
|
2985
|
-
this.order = order;
|
|
2986
|
-
await this._writeHead({
|
|
2987
|
-
root,
|
|
2988
|
-
order: this.order,
|
|
2989
|
-
data: this.strategy.head.data
|
|
2990
|
-
});
|
|
3218
|
+
if (this.rootTx !== this) {
|
|
3219
|
+
throw new Error("Cannot call init on a nested transaction");
|
|
3220
|
+
}
|
|
3221
|
+
return await this._initInternal();
|
|
3222
|
+
}
|
|
3223
|
+
async _initInternal() {
|
|
3224
|
+
if (this.isInitialized) {
|
|
3225
|
+
throw new Error("Transaction already initialized");
|
|
3226
|
+
}
|
|
3227
|
+
if (this.isDestroyed) {
|
|
3228
|
+
throw new Error("Transaction already destroyed");
|
|
2991
3229
|
}
|
|
2992
|
-
|
|
2993
|
-
|
|
3230
|
+
this.isInitialized = true;
|
|
3231
|
+
try {
|
|
3232
|
+
this._clearCache();
|
|
3233
|
+
const head = await this._readHead();
|
|
3234
|
+
if (head === null) {
|
|
3235
|
+
this.order = this.strategy.order;
|
|
3236
|
+
const root = await this._createNode(true, [], []);
|
|
3237
|
+
await this._writeHead({
|
|
3238
|
+
root: root.id,
|
|
3239
|
+
order: this.order,
|
|
3240
|
+
data: this.strategy.head.data
|
|
3241
|
+
});
|
|
3242
|
+
} else {
|
|
3243
|
+
const { root, order } = head;
|
|
3244
|
+
this.strategy.head = head;
|
|
3245
|
+
this.order = order;
|
|
3246
|
+
this.rootId = root;
|
|
3247
|
+
}
|
|
3248
|
+
if (this.order < 3) {
|
|
3249
|
+
throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
|
|
3250
|
+
}
|
|
3251
|
+
} catch (e) {
|
|
3252
|
+
this.isInitialized = false;
|
|
3253
|
+
throw e;
|
|
2994
3254
|
}
|
|
2995
3255
|
}
|
|
2996
3256
|
async exists(key, value) {
|
|
@@ -3004,21 +3264,6 @@ var require_cjs = __commonJS({
|
|
|
3004
3264
|
}
|
|
3005
3265
|
return false;
|
|
3006
3266
|
}
|
|
3007
|
-
async forceUpdate(id) {
|
|
3008
|
-
if (id) {
|
|
3009
|
-
this.nodes.delete(id);
|
|
3010
|
-
await this.getNode(id);
|
|
3011
|
-
return 1;
|
|
3012
|
-
}
|
|
3013
|
-
const keys = Array.from(this.nodes.keys());
|
|
3014
|
-
for (const key of keys) {
|
|
3015
|
-
this.nodes.delete(key);
|
|
3016
|
-
}
|
|
3017
|
-
for (const key of keys) {
|
|
3018
|
-
await this.getNode(key);
|
|
3019
|
-
}
|
|
3020
|
-
return keys.length;
|
|
3021
|
-
}
|
|
3022
3267
|
async get(key) {
|
|
3023
3268
|
let node = await this.leftestNode();
|
|
3024
3269
|
while (true) {
|
|
@@ -3099,29 +3344,34 @@ var require_cjs = __commonJS({
|
|
|
3099
3344
|
async where(condition, order = "asc") {
|
|
3100
3345
|
const map = /* @__PURE__ */ new Map();
|
|
3101
3346
|
for await (const [key, value] of this.whereStream(condition, void 0, order)) {
|
|
3102
|
-
map.set(key, value);
|
|
3103
|
-
}
|
|
3104
|
-
return map;
|
|
3105
|
-
}
|
|
3106
|
-
async insert(key, value) {
|
|
3107
|
-
const before = await this.insertableNode(value);
|
|
3108
|
-
await this._insertAtLeaf(before, key, value);
|
|
3109
|
-
if (before.values.length === this.order) {
|
|
3110
|
-
const after = await this._createNode(
|
|
3111
|
-
true,
|
|
3112
|
-
[],
|
|
3113
|
-
[],
|
|
3114
|
-
before.parent,
|
|
3115
|
-
null,
|
|
3116
|
-
null
|
|
3117
|
-
);
|
|
3118
|
-
const mid = Math.ceil(this.order / 2) - 1;
|
|
3119
|
-
after.values = before.values.slice(mid + 1);
|
|
3120
|
-
after.keys = before.keys.slice(mid + 1);
|
|
3121
|
-
before.values = before.values.slice(0, mid + 1);
|
|
3122
|
-
before.keys = before.keys.slice(0, mid + 1);
|
|
3123
|
-
await this._insertInParent(before, after.values[0], after);
|
|
3347
|
+
map.set(key, value);
|
|
3124
3348
|
}
|
|
3349
|
+
return map;
|
|
3350
|
+
}
|
|
3351
|
+
async insert(key, value) {
|
|
3352
|
+
return this.writeLock(0, async () => {
|
|
3353
|
+
let before = await this.insertableNode(value);
|
|
3354
|
+
before = await this._insertAtLeaf(before, key, value);
|
|
3355
|
+
if (before.values.length === this.order) {
|
|
3356
|
+
let after = await this._createNode(
|
|
3357
|
+
true,
|
|
3358
|
+
[],
|
|
3359
|
+
[],
|
|
3360
|
+
before.parent,
|
|
3361
|
+
null,
|
|
3362
|
+
null
|
|
3363
|
+
);
|
|
3364
|
+
const mid = Math.ceil(this.order / 2) - 1;
|
|
3365
|
+
after = this._cloneNode(after);
|
|
3366
|
+
after.values = before.values.slice(mid + 1);
|
|
3367
|
+
after.keys = before.keys.slice(mid + 1);
|
|
3368
|
+
before.values = before.values.slice(0, mid + 1);
|
|
3369
|
+
before.keys = before.keys.slice(0, mid + 1);
|
|
3370
|
+
await this._updateNode(before);
|
|
3371
|
+
await this._updateNode(after);
|
|
3372
|
+
await this._insertInParent(before, after.values[0], after);
|
|
3373
|
+
}
|
|
3374
|
+
});
|
|
3125
3375
|
}
|
|
3126
3376
|
async _deleteEntry(node, key) {
|
|
3127
3377
|
if (!node.leaf) {
|
|
@@ -3133,6 +3383,7 @@ var require_cjs = __commonJS({
|
|
|
3133
3383
|
}
|
|
3134
3384
|
}
|
|
3135
3385
|
if (keyIndex !== -1) {
|
|
3386
|
+
node = this._cloneNode(node);
|
|
3136
3387
|
node.keys.splice(keyIndex, 1);
|
|
3137
3388
|
const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
|
|
3138
3389
|
node.values.splice(valueIndex, 1);
|
|
@@ -3142,7 +3393,7 @@ var require_cjs = __commonJS({
|
|
|
3142
3393
|
if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
|
|
3143
3394
|
const keys = node.keys;
|
|
3144
3395
|
this._deleteNode(node);
|
|
3145
|
-
const newRoot = await this.getNode(keys[0]);
|
|
3396
|
+
const newRoot = this._cloneNode(await this.getNode(keys[0]));
|
|
3146
3397
|
newRoot.parent = null;
|
|
3147
3398
|
await this._updateNode(newRoot);
|
|
3148
3399
|
await this._writeHead({
|
|
@@ -3150,14 +3401,17 @@ var require_cjs = __commonJS({
|
|
|
3150
3401
|
order: this.order,
|
|
3151
3402
|
data: this.strategy.head.data
|
|
3152
3403
|
});
|
|
3153
|
-
return;
|
|
3404
|
+
return node;
|
|
3154
3405
|
} else if (this.rootId === node.id) {
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3406
|
+
await this._writeHead({
|
|
3407
|
+
root: node.id,
|
|
3408
|
+
order: this.order,
|
|
3409
|
+
data: this.strategy.head.data
|
|
3410
|
+
});
|
|
3411
|
+
return node;
|
|
3158
3412
|
} else if (node.keys.length < Math.ceil(this.order / 2) && !node.leaf || node.values.length < Math.ceil((this.order - 1) / 2) && node.leaf) {
|
|
3159
3413
|
if (node.parent === null) {
|
|
3160
|
-
return;
|
|
3414
|
+
return node;
|
|
3161
3415
|
}
|
|
3162
3416
|
let isPredecessor = false;
|
|
3163
3417
|
let parentNode = await this.getNode(node.parent);
|
|
@@ -3178,78 +3432,80 @@ var require_cjs = __commonJS({
|
|
|
3178
3432
|
}
|
|
3179
3433
|
}
|
|
3180
3434
|
}
|
|
3181
|
-
let
|
|
3435
|
+
let siblingNode;
|
|
3182
3436
|
let guess;
|
|
3183
3437
|
if (prevNode === null) {
|
|
3184
|
-
|
|
3438
|
+
siblingNode = nextNode;
|
|
3185
3439
|
guess = postValue;
|
|
3186
3440
|
} else if (nextNode === null) {
|
|
3187
3441
|
isPredecessor = true;
|
|
3188
|
-
|
|
3442
|
+
siblingNode = prevNode;
|
|
3189
3443
|
guess = prevValue;
|
|
3190
3444
|
} else {
|
|
3191
3445
|
if (node.values.length + nextNode.values.length < this.order) {
|
|
3192
|
-
|
|
3446
|
+
siblingNode = nextNode;
|
|
3193
3447
|
guess = postValue;
|
|
3194
3448
|
} else {
|
|
3195
3449
|
isPredecessor = true;
|
|
3196
|
-
|
|
3450
|
+
siblingNode = prevNode;
|
|
3197
3451
|
guess = prevValue;
|
|
3198
3452
|
}
|
|
3199
3453
|
}
|
|
3200
|
-
if (!
|
|
3201
|
-
return;
|
|
3454
|
+
if (!siblingNode) {
|
|
3455
|
+
return node;
|
|
3202
3456
|
}
|
|
3203
|
-
|
|
3457
|
+
node = this._cloneNode(node);
|
|
3458
|
+
siblingNode = this._cloneNode(siblingNode);
|
|
3459
|
+
if (node.values.length + siblingNode.values.length < this.order) {
|
|
3204
3460
|
if (!isPredecessor) {
|
|
3205
|
-
const pTemp =
|
|
3206
|
-
|
|
3461
|
+
const pTemp = siblingNode;
|
|
3462
|
+
siblingNode = node;
|
|
3207
3463
|
node = pTemp;
|
|
3208
3464
|
}
|
|
3209
|
-
|
|
3465
|
+
siblingNode.keys.push(...node.keys);
|
|
3210
3466
|
if (!node.leaf) {
|
|
3211
|
-
|
|
3467
|
+
siblingNode.values.push(guess);
|
|
3212
3468
|
} else {
|
|
3213
|
-
|
|
3214
|
-
if (
|
|
3215
|
-
const n = await this.getNode(
|
|
3216
|
-
n.prev =
|
|
3469
|
+
siblingNode.next = node.next;
|
|
3470
|
+
if (siblingNode.next) {
|
|
3471
|
+
const n = this._cloneNode(await this.getNode(siblingNode.next));
|
|
3472
|
+
n.prev = siblingNode.id;
|
|
3217
3473
|
await this._updateNode(n);
|
|
3218
3474
|
}
|
|
3219
3475
|
}
|
|
3220
|
-
|
|
3221
|
-
if (!
|
|
3222
|
-
const keys =
|
|
3476
|
+
siblingNode.values.push(...node.values);
|
|
3477
|
+
if (!siblingNode.leaf) {
|
|
3478
|
+
const keys = siblingNode.keys;
|
|
3223
3479
|
for (const key2 of keys) {
|
|
3224
|
-
const node2 = await this.getNode(key2);
|
|
3225
|
-
node2.parent =
|
|
3480
|
+
const node2 = this._cloneNode(await this.getNode(key2));
|
|
3481
|
+
node2.parent = siblingNode.id;
|
|
3226
3482
|
await this._updateNode(node2);
|
|
3227
3483
|
}
|
|
3228
3484
|
}
|
|
3229
3485
|
this._deleteNode(node);
|
|
3230
|
-
await this._updateNode(
|
|
3486
|
+
await this._updateNode(siblingNode);
|
|
3231
3487
|
await this._deleteEntry(await this.getNode(node.parent), node.id);
|
|
3232
3488
|
} else {
|
|
3233
3489
|
if (isPredecessor) {
|
|
3234
3490
|
let pointerPm;
|
|
3235
3491
|
let pointerKm;
|
|
3236
3492
|
if (!node.leaf) {
|
|
3237
|
-
pointerPm =
|
|
3238
|
-
pointerKm =
|
|
3493
|
+
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
3494
|
+
pointerKm = siblingNode.values.splice(-1)[0];
|
|
3239
3495
|
node.keys = [pointerPm, ...node.keys];
|
|
3240
3496
|
node.values = [guess, ...node.values];
|
|
3241
|
-
parentNode = await this.getNode(node.parent);
|
|
3497
|
+
parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
3242
3498
|
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
3243
3499
|
if (nodeIndex > 0) {
|
|
3244
3500
|
parentNode.values[nodeIndex - 1] = pointerKm;
|
|
3245
3501
|
await this._updateNode(parentNode);
|
|
3246
3502
|
}
|
|
3247
3503
|
} else {
|
|
3248
|
-
pointerPm =
|
|
3249
|
-
pointerKm =
|
|
3504
|
+
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
3505
|
+
pointerKm = siblingNode.values.splice(-1)[0];
|
|
3250
3506
|
node.keys = [pointerPm, ...node.keys];
|
|
3251
3507
|
node.values = [pointerKm, ...node.values];
|
|
3252
|
-
parentNode = await this.getNode(node.parent);
|
|
3508
|
+
parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
3253
3509
|
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
3254
3510
|
if (nodeIndex > 0) {
|
|
3255
3511
|
parentNode.values[nodeIndex - 1] = pointerKm;
|
|
@@ -3257,92 +3513,103 @@ var require_cjs = __commonJS({
|
|
|
3257
3513
|
}
|
|
3258
3514
|
}
|
|
3259
3515
|
await this._updateNode(node);
|
|
3260
|
-
await this._updateNode(
|
|
3516
|
+
await this._updateNode(siblingNode);
|
|
3261
3517
|
} else {
|
|
3262
3518
|
let pointerP0;
|
|
3263
3519
|
let pointerK0;
|
|
3264
3520
|
if (!node.leaf) {
|
|
3265
|
-
pointerP0 =
|
|
3266
|
-
pointerK0 =
|
|
3521
|
+
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
3522
|
+
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
3267
3523
|
node.keys = [...node.keys, pointerP0];
|
|
3268
3524
|
node.values = [...node.values, guess];
|
|
3269
|
-
parentNode = await this.getNode(node.parent);
|
|
3270
|
-
const pointerIndex = parentNode.keys.indexOf(
|
|
3525
|
+
parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
3526
|
+
const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
|
|
3271
3527
|
if (pointerIndex > 0) {
|
|
3272
3528
|
parentNode.values[pointerIndex - 1] = pointerK0;
|
|
3273
3529
|
await this._updateNode(parentNode);
|
|
3274
3530
|
}
|
|
3275
3531
|
} else {
|
|
3276
|
-
pointerP0 =
|
|
3277
|
-
pointerK0 =
|
|
3532
|
+
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
3533
|
+
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
3278
3534
|
node.keys = [...node.keys, pointerP0];
|
|
3279
3535
|
node.values = [...node.values, pointerK0];
|
|
3280
|
-
parentNode = await this.getNode(node.parent);
|
|
3281
|
-
const pointerIndex = parentNode.keys.indexOf(
|
|
3536
|
+
parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
3537
|
+
const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
|
|
3282
3538
|
if (pointerIndex > 0) {
|
|
3283
|
-
parentNode.values[pointerIndex - 1] =
|
|
3539
|
+
parentNode.values[pointerIndex - 1] = siblingNode.values[0];
|
|
3284
3540
|
await this._updateNode(parentNode);
|
|
3285
3541
|
}
|
|
3286
3542
|
}
|
|
3287
3543
|
await this._updateNode(node);
|
|
3288
|
-
await this._updateNode(
|
|
3544
|
+
await this._updateNode(siblingNode);
|
|
3289
3545
|
}
|
|
3290
|
-
if (!
|
|
3291
|
-
for (const key2 of
|
|
3292
|
-
const n = await this.getNode(key2);
|
|
3293
|
-
n.parent =
|
|
3546
|
+
if (!siblingNode.leaf) {
|
|
3547
|
+
for (const key2 of siblingNode.keys) {
|
|
3548
|
+
const n = this._cloneNode(await this.getNode(key2));
|
|
3549
|
+
n.parent = siblingNode.id;
|
|
3294
3550
|
await this._updateNode(n);
|
|
3295
3551
|
}
|
|
3296
3552
|
}
|
|
3297
3553
|
if (!node.leaf) {
|
|
3298
3554
|
for (const key2 of node.keys) {
|
|
3299
|
-
const n = await this.getNode(key2);
|
|
3555
|
+
const n = this._cloneNode(await this.getNode(key2));
|
|
3300
3556
|
n.parent = node.id;
|
|
3301
3557
|
await this._updateNode(n);
|
|
3302
3558
|
}
|
|
3303
3559
|
}
|
|
3304
3560
|
if (!parentNode.leaf) {
|
|
3305
3561
|
for (const key2 of parentNode.keys) {
|
|
3306
|
-
const n = await this.getNode(key2);
|
|
3562
|
+
const n = this._cloneNode(await this.getNode(key2));
|
|
3307
3563
|
n.parent = parentNode.id;
|
|
3308
3564
|
await this._updateNode(n);
|
|
3309
3565
|
}
|
|
3310
3566
|
}
|
|
3311
3567
|
}
|
|
3312
3568
|
} else {
|
|
3313
|
-
await this._updateNode(node);
|
|
3569
|
+
await this._updateNode(this._cloneNode(node));
|
|
3314
3570
|
}
|
|
3571
|
+
return node;
|
|
3315
3572
|
}
|
|
3316
3573
|
async delete(key, value) {
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3574
|
+
return this.writeLock(0, async () => {
|
|
3575
|
+
if (value === void 0) {
|
|
3576
|
+
value = await this.get(key);
|
|
3577
|
+
}
|
|
3578
|
+
if (value === void 0) {
|
|
3579
|
+
return;
|
|
3580
|
+
}
|
|
3581
|
+
let node = await this.insertableNodeByPrimary(value);
|
|
3582
|
+
let found = false;
|
|
3583
|
+
while (true) {
|
|
3584
|
+
let i = node.values.length;
|
|
3585
|
+
while (i--) {
|
|
3586
|
+
const nValue = node.values[i];
|
|
3587
|
+
if (this.comparator.isSame(value, nValue)) {
|
|
3588
|
+
const keys = node.keys[i];
|
|
3589
|
+
const keyIndex = keys.indexOf(key);
|
|
3590
|
+
if (keyIndex !== -1) {
|
|
3591
|
+
node = this._cloneNode(node);
|
|
3592
|
+
const freshKeys = node.keys[i];
|
|
3593
|
+
freshKeys.splice(keyIndex, 1);
|
|
3594
|
+
if (freshKeys.length === 0) {
|
|
3595
|
+
node.keys.splice(i, 1);
|
|
3596
|
+
node.values.splice(i, 1);
|
|
3597
|
+
}
|
|
3598
|
+
await this._updateNode(node);
|
|
3599
|
+
node = await this._deleteEntry(node, key);
|
|
3600
|
+
found = true;
|
|
3601
|
+
break;
|
|
3331
3602
|
}
|
|
3332
|
-
await this._updateNode(node);
|
|
3333
|
-
await this._deleteEntry(node, key);
|
|
3334
|
-
found = true;
|
|
3335
|
-
break;
|
|
3336
3603
|
}
|
|
3337
3604
|
}
|
|
3605
|
+
if (found) break;
|
|
3606
|
+
if (node.next) {
|
|
3607
|
+
node = await this.getNode(node.next);
|
|
3608
|
+
continue;
|
|
3609
|
+
}
|
|
3610
|
+
break;
|
|
3338
3611
|
}
|
|
3339
|
-
|
|
3340
|
-
if (node.next) {
|
|
3341
|
-
node = await this.getNode(node.next);
|
|
3342
|
-
continue;
|
|
3343
|
-
}
|
|
3344
|
-
break;
|
|
3345
|
-
}
|
|
3612
|
+
});
|
|
3346
3613
|
}
|
|
3347
3614
|
async getHeadData() {
|
|
3348
3615
|
const head = await this._readHead();
|
|
@@ -3362,428 +3629,168 @@ var require_cjs = __commonJS({
|
|
|
3362
3629
|
data
|
|
3363
3630
|
});
|
|
3364
3631
|
}
|
|
3365
|
-
async commit(label) {
|
|
3366
|
-
let result = await this.mvcc.commit(label);
|
|
3367
|
-
if (result.success) {
|
|
3368
|
-
|
|
3369
|
-
if (
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
this.nodes.set(r.key, r.data);
|
|
3375
|
-
}
|
|
3376
|
-
for (const r of result.updated) {
|
|
3377
|
-
this.nodes.set(r.key, r.data);
|
|
3378
|
-
}
|
|
3379
|
-
for (const r of result.deleted) {
|
|
3380
|
-
this.nodes.delete(r.key);
|
|
3381
|
-
}
|
|
3382
|
-
}
|
|
3383
|
-
}
|
|
3384
|
-
return result;
|
|
3385
|
-
}
|
|
3386
|
-
rollback() {
|
|
3387
|
-
return this.mvcc.rollback();
|
|
3388
|
-
}
|
|
3389
|
-
};
|
|
3390
|
-
var BPTreeMVCCStrategyAsync = class extends AsyncMVCCStrategy {
|
|
3391
|
-
constructor(strategy) {
|
|
3392
|
-
super();
|
|
3393
|
-
this.strategy = strategy;
|
|
3394
|
-
}
|
|
3395
|
-
async read(key) {
|
|
3396
|
-
if (key === "__HEAD__") {
|
|
3397
|
-
return await this.strategy.readHead();
|
|
3398
|
-
}
|
|
3399
|
-
return await this.strategy.read(key);
|
|
3400
|
-
}
|
|
3401
|
-
async write(key, value) {
|
|
3402
|
-
if (key === "__HEAD__") {
|
|
3403
|
-
await this.strategy.writeHead(value);
|
|
3404
|
-
} else {
|
|
3405
|
-
await this.strategy.write(key, value);
|
|
3406
|
-
}
|
|
3407
|
-
}
|
|
3408
|
-
async delete(key) {
|
|
3409
|
-
await this.strategy.delete(key);
|
|
3410
|
-
}
|
|
3411
|
-
async exists(key) {
|
|
3412
|
-
if (key === "__HEAD__") {
|
|
3413
|
-
return await this.strategy.readHead() !== null;
|
|
3414
|
-
}
|
|
3415
|
-
try {
|
|
3416
|
-
const node = await this.strategy.read(key);
|
|
3417
|
-
return node !== null && node !== void 0;
|
|
3418
|
-
} catch {
|
|
3419
|
-
return false;
|
|
3420
|
-
}
|
|
3421
|
-
}
|
|
3422
|
-
};
|
|
3423
|
-
var BPTreeAsync2 = class extends BPTreeAsyncTransaction2 {
|
|
3424
|
-
constructor(strategy, comparator, option) {
|
|
3425
|
-
const mvccRoot = new AsyncMVCCTransaction(new BPTreeMVCCStrategyAsync(strategy));
|
|
3426
|
-
super(
|
|
3427
|
-
null,
|
|
3428
|
-
mvccRoot,
|
|
3429
|
-
mvccRoot,
|
|
3430
|
-
strategy,
|
|
3431
|
-
comparator,
|
|
3432
|
-
option
|
|
3433
|
-
);
|
|
3434
|
-
}
|
|
3435
|
-
/**
|
|
3436
|
-
* Creates a new asynchronous transaction.
|
|
3437
|
-
* @returns A new BPTreeAsyncTransaction.
|
|
3438
|
-
*/
|
|
3439
|
-
async createTransaction() {
|
|
3440
|
-
const nestedTx = await this.mvcc.createNested();
|
|
3441
|
-
const tx = new BPTreeAsyncTransaction2(
|
|
3442
|
-
this,
|
|
3443
|
-
this.mvcc,
|
|
3444
|
-
nestedTx,
|
|
3445
|
-
this.strategy,
|
|
3446
|
-
this.comparator,
|
|
3447
|
-
this.option
|
|
3448
|
-
);
|
|
3449
|
-
await tx.init();
|
|
3450
|
-
return tx;
|
|
3451
|
-
}
|
|
3452
|
-
async insert(key, value) {
|
|
3453
|
-
const tx = await this.createTransaction();
|
|
3454
|
-
await tx.insert(key, value);
|
|
3455
|
-
const result = await tx.commit();
|
|
3456
|
-
if (!result.success) {
|
|
3457
|
-
throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
|
|
3458
|
-
}
|
|
3459
|
-
this.rootId = tx.getRootId();
|
|
3460
|
-
}
|
|
3461
|
-
async delete(key, value) {
|
|
3462
|
-
const tx = await this.createTransaction();
|
|
3463
|
-
await tx.delete(key, value);
|
|
3464
|
-
const result = await tx.commit();
|
|
3465
|
-
if (!result.success) {
|
|
3466
|
-
throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
|
|
3467
|
-
}
|
|
3468
|
-
this.rootId = tx.getRootId();
|
|
3469
|
-
}
|
|
3470
|
-
};
|
|
3471
|
-
var SerializeStrategy = class {
|
|
3472
|
-
order;
|
|
3473
|
-
head;
|
|
3474
|
-
constructor(order) {
|
|
3475
|
-
this.order = order;
|
|
3476
|
-
this.head = {
|
|
3477
|
-
order,
|
|
3478
|
-
root: null,
|
|
3479
|
-
data: {}
|
|
3480
|
-
};
|
|
3481
|
-
}
|
|
3482
|
-
};
|
|
3483
|
-
var SerializeStrategySync = class extends SerializeStrategy {
|
|
3484
|
-
getHeadData(key, defaultValue) {
|
|
3485
|
-
if (!Object.hasOwn(this.head.data, key)) {
|
|
3486
|
-
this.setHeadData(key, defaultValue);
|
|
3487
|
-
}
|
|
3488
|
-
return this.head.data[key];
|
|
3489
|
-
}
|
|
3490
|
-
setHeadData(key, data) {
|
|
3491
|
-
this.head.data[key] = data;
|
|
3492
|
-
this.writeHead(this.head);
|
|
3493
|
-
}
|
|
3494
|
-
autoIncrement(key, defaultValue) {
|
|
3495
|
-
const current = this.getHeadData(key, defaultValue);
|
|
3496
|
-
const next = current + 1;
|
|
3497
|
-
this.setHeadData(key, next);
|
|
3498
|
-
return current;
|
|
3499
|
-
}
|
|
3500
|
-
};
|
|
3501
|
-
var InMemoryStoreStrategySync = class extends SerializeStrategySync {
|
|
3502
|
-
node;
|
|
3503
|
-
constructor(order) {
|
|
3504
|
-
super(order);
|
|
3505
|
-
this.node = {};
|
|
3506
|
-
}
|
|
3507
|
-
id(isLeaf) {
|
|
3508
|
-
return this.autoIncrement("index", 1).toString();
|
|
3509
|
-
}
|
|
3510
|
-
read(id) {
|
|
3511
|
-
if (!Object.hasOwn(this.node, id)) {
|
|
3512
|
-
throw new Error(`The tree attempted to reference node '${id}', but couldn't find the corresponding node.`);
|
|
3513
|
-
}
|
|
3514
|
-
const node = this.node[id];
|
|
3515
|
-
return JSON.parse(JSON.stringify(node));
|
|
3516
|
-
}
|
|
3517
|
-
write(id, node) {
|
|
3518
|
-
this.node[id] = node;
|
|
3519
|
-
}
|
|
3520
|
-
delete(id) {
|
|
3521
|
-
delete this.node[id];
|
|
3522
|
-
}
|
|
3523
|
-
readHead() {
|
|
3524
|
-
if (this.head.root === null) {
|
|
3525
|
-
return null;
|
|
3526
|
-
}
|
|
3527
|
-
return this.head;
|
|
3528
|
-
}
|
|
3529
|
-
writeHead(head) {
|
|
3530
|
-
this.head = head;
|
|
3531
|
-
}
|
|
3532
|
-
};
|
|
3533
|
-
var Ryoiki22 = class _Ryoiki2 {
|
|
3534
|
-
readings;
|
|
3535
|
-
writings;
|
|
3536
|
-
readQueue;
|
|
3537
|
-
writeQueue;
|
|
3538
|
-
static async CatchError(promise) {
|
|
3539
|
-
return await promise.then((v) => [void 0, v]).catch((err) => [err]);
|
|
3540
|
-
}
|
|
3541
|
-
static IsRangeOverlap(a, b) {
|
|
3542
|
-
const [start1, end1] = a;
|
|
3543
|
-
const [start2, end2] = b;
|
|
3544
|
-
if (end1 <= start2 || end2 <= start1) {
|
|
3545
|
-
return false;
|
|
3546
|
-
}
|
|
3547
|
-
return true;
|
|
3548
|
-
}
|
|
3549
|
-
static ERR_ALREADY_EXISTS(lockId) {
|
|
3550
|
-
return new Error(`The '${lockId}' task already existing in queue or running.`);
|
|
3551
|
-
}
|
|
3552
|
-
static ERR_NOT_EXISTS(lockId) {
|
|
3553
|
-
return new Error(`The '${lockId}' task not existing in task queue.`);
|
|
3554
|
-
}
|
|
3555
|
-
static ERR_TIMEOUT(lockId, timeout) {
|
|
3556
|
-
return new Error(`The task with ID '${lockId}' failed to acquire the lock within the timeout(${timeout}ms).`);
|
|
3557
|
-
}
|
|
3558
|
-
/**
|
|
3559
|
-
* Constructs a new instance of the Ryoiki class.
|
|
3560
|
-
*/
|
|
3561
|
-
constructor() {
|
|
3562
|
-
this.readings = /* @__PURE__ */ new Map();
|
|
3563
|
-
this.writings = /* @__PURE__ */ new Map();
|
|
3564
|
-
this.readQueue = /* @__PURE__ */ new Map();
|
|
3565
|
-
this.writeQueue = /* @__PURE__ */ new Map();
|
|
3566
|
-
}
|
|
3567
|
-
/**
|
|
3568
|
-
* Creates a range based on a start value and length.
|
|
3569
|
-
* @param start - The starting value of the range.
|
|
3570
|
-
* @param length - The length of the range.
|
|
3571
|
-
* @returns A range tuple [start, start + length].
|
|
3572
|
-
*/
|
|
3573
|
-
range(start, length) {
|
|
3574
|
-
return [start, start + length];
|
|
3575
|
-
}
|
|
3576
|
-
rangeOverlapping(tasks, range) {
|
|
3577
|
-
return Array.from(tasks.values()).some((t) => _Ryoiki2.IsRangeOverlap(t.range, range));
|
|
3578
|
-
}
|
|
3579
|
-
isSameRange(a, b) {
|
|
3580
|
-
const [a1, a2] = a;
|
|
3581
|
-
const [b1, b2] = b;
|
|
3582
|
-
return a1 === b1 && a2 === b2;
|
|
3583
|
-
}
|
|
3584
|
-
fetchUnitAndRun(queue, workspaces) {
|
|
3585
|
-
for (const [id, unit] of queue) {
|
|
3586
|
-
if (!unit.condition()) {
|
|
3587
|
-
continue;
|
|
3588
|
-
}
|
|
3589
|
-
this._alloc(queue, workspaces, id);
|
|
3590
|
-
}
|
|
3591
|
-
}
|
|
3592
|
-
_handleOverload(args, handlers, argPatterns) {
|
|
3593
|
-
for (const [key, pattern] of Object.entries(argPatterns)) {
|
|
3594
|
-
if (this._matchArgs(args, pattern)) {
|
|
3595
|
-
return handlers[key](...args);
|
|
3632
|
+
async commit(label) {
|
|
3633
|
+
let result = await this.mvcc.commit(label);
|
|
3634
|
+
if (result.success) {
|
|
3635
|
+
const isRootTx = this.rootTx === this;
|
|
3636
|
+
if (!isRootTx) {
|
|
3637
|
+
result = await this.rootTx.commit(label);
|
|
3638
|
+
if (result.success) {
|
|
3639
|
+
this.rootTx.rootId = this.rootId;
|
|
3640
|
+
}
|
|
3596
3641
|
}
|
|
3597
3642
|
}
|
|
3598
|
-
|
|
3643
|
+
return result;
|
|
3599
3644
|
}
|
|
3600
|
-
|
|
3601
|
-
return
|
|
3602
|
-
const expectedType = pattern[index];
|
|
3603
|
-
if (expectedType === void 0) return typeof arg === "undefined";
|
|
3604
|
-
if (expectedType === Function) return typeof arg === "function";
|
|
3605
|
-
if (expectedType === Number) return typeof arg === "number";
|
|
3606
|
-
if (expectedType === Array) return Array.isArray(arg);
|
|
3607
|
-
return false;
|
|
3608
|
-
});
|
|
3645
|
+
async rollback() {
|
|
3646
|
+
return this.mvcc.rollback();
|
|
3609
3647
|
}
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3648
|
+
};
|
|
3649
|
+
var BPTreeMVCCStrategyAsync = class extends AsyncMVCCStrategy {
|
|
3650
|
+
constructor(strategy) {
|
|
3651
|
+
super();
|
|
3652
|
+
this.strategy = strategy;
|
|
3614
3653
|
}
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
throw _Ryoiki2.ERR_NOT_EXISTS(lockId);
|
|
3654
|
+
async read(key) {
|
|
3655
|
+
if (key === "__HEAD__") {
|
|
3656
|
+
return await this.strategy.readHead();
|
|
3619
3657
|
}
|
|
3620
|
-
|
|
3621
|
-
queue.delete(lockId);
|
|
3622
|
-
unit.alloc();
|
|
3658
|
+
return await this.strategy.read(key);
|
|
3623
3659
|
}
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3660
|
+
async write(key, value) {
|
|
3661
|
+
if (key === "__HEAD__") {
|
|
3662
|
+
await this.strategy.writeHead(value);
|
|
3663
|
+
} else {
|
|
3664
|
+
await this.strategy.write(key, value);
|
|
3628
3665
|
}
|
|
3629
|
-
workspaces.delete(lockId);
|
|
3630
|
-
unit.free();
|
|
3631
3666
|
}
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
let timeoutId = null;
|
|
3635
|
-
if (timeout >= 0) {
|
|
3636
|
-
timeoutId = setTimeout(() => {
|
|
3637
|
-
reject(_Ryoiki2.ERR_TIMEOUT(id, timeout));
|
|
3638
|
-
}, timeout);
|
|
3639
|
-
}
|
|
3640
|
-
const id = this._createRandomId();
|
|
3641
|
-
const alloc = async () => {
|
|
3642
|
-
if (timeoutId !== null) {
|
|
3643
|
-
clearTimeout(timeoutId);
|
|
3644
|
-
}
|
|
3645
|
-
const [err, v] = await _Ryoiki2.CatchError(task(id));
|
|
3646
|
-
if (err) reject(err);
|
|
3647
|
-
else resolve(v);
|
|
3648
|
-
};
|
|
3649
|
-
const fetch = () => {
|
|
3650
|
-
this.fetchUnitAndRun(this.readQueue, this.readings);
|
|
3651
|
-
this.fetchUnitAndRun(this.writeQueue, this.writings);
|
|
3652
|
-
};
|
|
3653
|
-
queue.set(id, { id, range, condition, alloc, free: fetch });
|
|
3654
|
-
fetch();
|
|
3655
|
-
});
|
|
3667
|
+
async delete(key) {
|
|
3668
|
+
await this.strategy.delete(key);
|
|
3656
3669
|
}
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3670
|
+
async exists(key) {
|
|
3671
|
+
if (key === "__HEAD__") {
|
|
3672
|
+
return await this.strategy.readHead() !== null;
|
|
3673
|
+
}
|
|
3674
|
+
try {
|
|
3675
|
+
const node = await this.strategy.read(key);
|
|
3676
|
+
return node !== null && node !== void 0;
|
|
3677
|
+
} catch {
|
|
3678
|
+
return false;
|
|
3664
3679
|
}
|
|
3665
|
-
return isLocked;
|
|
3666
|
-
}
|
|
3667
|
-
/**
|
|
3668
|
-
* Checks if there is any active read lock within the specified range.
|
|
3669
|
-
* @param range The range to check for active read locks.
|
|
3670
|
-
* @returns `true` if there is an active read lock within the range, `false` otherwise.
|
|
3671
|
-
*/
|
|
3672
|
-
isReading(range) {
|
|
3673
|
-
return this._checkWorking(range, this.readings);
|
|
3674
|
-
}
|
|
3675
|
-
/**
|
|
3676
|
-
* Checks if there is any active write lock within the specified range.
|
|
3677
|
-
* @param range The range to check for active write locks.
|
|
3678
|
-
* @returns `true` if there is an active write lock within the range, `false` otherwise.
|
|
3679
|
-
*/
|
|
3680
|
-
isWriting(range) {
|
|
3681
|
-
return this._checkWorking(range, this.writings);
|
|
3682
|
-
}
|
|
3683
|
-
/**
|
|
3684
|
-
* Checks if a read lock can be acquired within the specified range.
|
|
3685
|
-
* @param range The range to check for read lock availability.
|
|
3686
|
-
* @returns `true` if a read lock can be acquired, `false` otherwise.
|
|
3687
|
-
*/
|
|
3688
|
-
canRead(range) {
|
|
3689
|
-
const writing = this.isWriting(range);
|
|
3690
|
-
return !writing;
|
|
3691
3680
|
}
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3681
|
+
};
|
|
3682
|
+
var BPTreeAsync2 = class extends BPTreeAsyncTransaction2 {
|
|
3683
|
+
constructor(strategy, comparator, option) {
|
|
3684
|
+
const mvccRoot = new AsyncMVCCTransaction(new BPTreeMVCCStrategyAsync(strategy), {
|
|
3685
|
+
cacheCapacity: option?.capacity ?? void 0
|
|
3686
|
+
});
|
|
3687
|
+
super(
|
|
3688
|
+
null,
|
|
3689
|
+
mvccRoot,
|
|
3690
|
+
mvccRoot,
|
|
3691
|
+
strategy,
|
|
3692
|
+
comparator,
|
|
3693
|
+
option
|
|
3694
|
+
);
|
|
3701
3695
|
}
|
|
3702
3696
|
/**
|
|
3703
|
-
*
|
|
3704
|
-
* @
|
|
3705
|
-
* @param arg0 - Either a range or a task callback.
|
|
3706
|
-
* If a range is provided, the task is the second argument.
|
|
3707
|
-
* @param arg1 - The task to execute, required if a range is provided.
|
|
3708
|
-
* @param arg2 - The timeout for acquiring the lock.
|
|
3709
|
-
* If the lock cannot be acquired within this period, an error will be thrown.
|
|
3710
|
-
* If this value is not provided, no timeout will be set.
|
|
3711
|
-
* @returns A promise resolving to the result of the task execution.
|
|
3697
|
+
* Creates a new asynchronous transaction.
|
|
3698
|
+
* @returns A new BPTreeAsyncTransaction.
|
|
3712
3699
|
*/
|
|
3713
|
-
|
|
3714
|
-
const
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
{
|
|
3723
|
-
task: [Function],
|
|
3724
|
-
taskTimeout: [Function, Number],
|
|
3725
|
-
rangeTask: [Array, Function],
|
|
3726
|
-
rangeTaskTimeout: [Array, Function, Number]
|
|
3727
|
-
}
|
|
3728
|
-
);
|
|
3729
|
-
return this._lock(
|
|
3730
|
-
this.readQueue,
|
|
3731
|
-
range,
|
|
3732
|
-
timeout,
|
|
3733
|
-
task,
|
|
3734
|
-
() => !this.rangeOverlapping(this.writings, range)
|
|
3700
|
+
async createTransaction() {
|
|
3701
|
+
const nestedTx = this.mvcc.createNested();
|
|
3702
|
+
const tx = new BPTreeAsyncTransaction2(
|
|
3703
|
+
this,
|
|
3704
|
+
this.mvcc,
|
|
3705
|
+
nestedTx,
|
|
3706
|
+
this.strategy,
|
|
3707
|
+
this.comparator,
|
|
3708
|
+
this.option
|
|
3735
3709
|
);
|
|
3710
|
+
await tx._initInternal();
|
|
3711
|
+
return tx;
|
|
3736
3712
|
}
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
* If the lock cannot be acquired within this period, an error will be thrown.
|
|
3745
|
-
* If this value is not provided, no timeout will be set.
|
|
3746
|
-
* @returns A promise resolving to the result of the task execution.
|
|
3747
|
-
*/
|
|
3748
|
-
writeLock(arg0, arg1, arg2) {
|
|
3749
|
-
const [range, task, timeout] = this._handleOverload(
|
|
3750
|
-
[arg0, arg1, arg2],
|
|
3751
|
-
{
|
|
3752
|
-
rangeTask: (range2, task2) => [range2, task2, -1],
|
|
3753
|
-
rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
|
|
3754
|
-
task: (task2) => [[-Infinity, Infinity], task2, -1],
|
|
3755
|
-
taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
|
|
3756
|
-
},
|
|
3757
|
-
{
|
|
3758
|
-
task: [Function],
|
|
3759
|
-
taskTimeout: [Function, Number],
|
|
3760
|
-
rangeTask: [Array, Function],
|
|
3761
|
-
rangeTaskTimeout: [Array, Function, Number]
|
|
3713
|
+
async insert(key, value) {
|
|
3714
|
+
return this.writeLock(1, async () => {
|
|
3715
|
+
const tx = await this.createTransaction();
|
|
3716
|
+
await tx.insert(key, value);
|
|
3717
|
+
const result = await tx.commit();
|
|
3718
|
+
if (!result.success) {
|
|
3719
|
+
throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
|
|
3762
3720
|
}
|
|
3763
|
-
);
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
()
|
|
3770
|
-
|
|
3721
|
+
});
|
|
3722
|
+
}
|
|
3723
|
+
async delete(key, value) {
|
|
3724
|
+
return this.writeLock(1, async () => {
|
|
3725
|
+
const tx = await this.createTransaction();
|
|
3726
|
+
await tx.delete(key, value);
|
|
3727
|
+
const result = await tx.commit();
|
|
3728
|
+
if (!result.success) {
|
|
3729
|
+
throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
|
|
3771
3730
|
}
|
|
3772
|
-
);
|
|
3731
|
+
});
|
|
3732
|
+
}
|
|
3733
|
+
};
|
|
3734
|
+
var SerializeStrategy = class {
|
|
3735
|
+
order;
|
|
3736
|
+
head;
|
|
3737
|
+
constructor(order) {
|
|
3738
|
+
this.order = order;
|
|
3739
|
+
this.head = {
|
|
3740
|
+
order,
|
|
3741
|
+
root: null,
|
|
3742
|
+
data: {}
|
|
3743
|
+
};
|
|
3744
|
+
}
|
|
3745
|
+
};
|
|
3746
|
+
var SerializeStrategySync = class extends SerializeStrategy {
|
|
3747
|
+
getHeadData(key, defaultValue) {
|
|
3748
|
+
if (!Object.hasOwn(this.head.data, key)) {
|
|
3749
|
+
this.setHeadData(key, defaultValue);
|
|
3750
|
+
}
|
|
3751
|
+
return this.head.data[key];
|
|
3752
|
+
}
|
|
3753
|
+
setHeadData(key, data) {
|
|
3754
|
+
this.head.data[key] = data;
|
|
3755
|
+
this.writeHead(this.head);
|
|
3756
|
+
}
|
|
3757
|
+
autoIncrement(key, defaultValue) {
|
|
3758
|
+
const current = this.getHeadData(key, defaultValue);
|
|
3759
|
+
const next = current + 1;
|
|
3760
|
+
this.setHeadData(key, next);
|
|
3761
|
+
return current;
|
|
3762
|
+
}
|
|
3763
|
+
};
|
|
3764
|
+
var InMemoryStoreStrategySync = class extends SerializeStrategySync {
|
|
3765
|
+
node;
|
|
3766
|
+
constructor(order) {
|
|
3767
|
+
super(order);
|
|
3768
|
+
this.node = {};
|
|
3773
3769
|
}
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
* @param lockId - The unique identifier for the lock to release.
|
|
3777
|
-
*/
|
|
3778
|
-
readUnlock(lockId) {
|
|
3779
|
-
this._free(this.readings, lockId);
|
|
3770
|
+
id(isLeaf) {
|
|
3771
|
+
return this.autoIncrement("index", 1).toString();
|
|
3780
3772
|
}
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3773
|
+
read(id) {
|
|
3774
|
+
if (!Object.hasOwn(this.node, id)) {
|
|
3775
|
+
throw new Error(`The tree attempted to reference node '${id}', but couldn't find the corresponding node.`);
|
|
3776
|
+
}
|
|
3777
|
+
const node = this.node[id];
|
|
3778
|
+
return JSON.parse(JSON.stringify(node));
|
|
3779
|
+
}
|
|
3780
|
+
write(id, node) {
|
|
3781
|
+
this.node[id] = node;
|
|
3782
|
+
}
|
|
3783
|
+
delete(id) {
|
|
3784
|
+
delete this.node[id];
|
|
3785
|
+
}
|
|
3786
|
+
readHead() {
|
|
3787
|
+
if (this.head.root === null) {
|
|
3788
|
+
return null;
|
|
3789
|
+
}
|
|
3790
|
+
return this.head;
|
|
3791
|
+
}
|
|
3792
|
+
writeHead(head) {
|
|
3793
|
+
this.head = head;
|
|
3787
3794
|
}
|
|
3788
3795
|
};
|
|
3789
3796
|
var SerializeStrategyAsync2 = class extends SerializeStrategy {
|
|
@@ -4224,7 +4231,7 @@ var require_cjs = __commonJS({
|
|
|
4224
4231
|
this.tail = null;
|
|
4225
4232
|
}
|
|
4226
4233
|
};
|
|
4227
|
-
var
|
|
4234
|
+
var CacheEntanglement = class {
|
|
4228
4235
|
creation;
|
|
4229
4236
|
beforeUpdateHook;
|
|
4230
4237
|
capacity;
|
|
@@ -4325,7 +4332,7 @@ var require_cjs = __commonJS({
|
|
|
4325
4332
|
}
|
|
4326
4333
|
}
|
|
4327
4334
|
};
|
|
4328
|
-
var
|
|
4335
|
+
var CacheData = class _CacheData {
|
|
4329
4336
|
static StructuredClone = globalThis.structuredClone.bind(globalThis);
|
|
4330
4337
|
_value;
|
|
4331
4338
|
constructor(value) {
|
|
@@ -4365,11 +4372,11 @@ var require_cjs = __commonJS({
|
|
|
4365
4372
|
return Object.assign({}, this.raw);
|
|
4366
4373
|
case "deep-copy":
|
|
4367
4374
|
default:
|
|
4368
|
-
return
|
|
4375
|
+
return _CacheData.StructuredClone(this.raw);
|
|
4369
4376
|
}
|
|
4370
4377
|
}
|
|
4371
4378
|
};
|
|
4372
|
-
var
|
|
4379
|
+
var CacheEntanglementSync = class extends CacheEntanglement {
|
|
4373
4380
|
constructor(creation, option) {
|
|
4374
4381
|
super(creation, option);
|
|
4375
4382
|
}
|
|
@@ -4399,7 +4406,7 @@ var require_cjs = __commonJS({
|
|
|
4399
4406
|
const dependencyValue = dependency.recache(key) ?? dependency.recache(dependencyKey);
|
|
4400
4407
|
resolved[name] = dependencyValue;
|
|
4401
4408
|
}
|
|
4402
|
-
const value = new
|
|
4409
|
+
const value = new CacheData(this.creation(key, resolved, ...parameter));
|
|
4403
4410
|
this.updateRequirements.delete(key);
|
|
4404
4411
|
this.parameters.set(key, parameter);
|
|
4405
4412
|
this.caches.set(key, value);
|
|
@@ -4423,7 +4430,7 @@ var require_cjs = __commonJS({
|
|
|
4423
4430
|
return this.caches.get(key);
|
|
4424
4431
|
}
|
|
4425
4432
|
};
|
|
4426
|
-
var CacheEntanglementAsync = class extends
|
|
4433
|
+
var CacheEntanglementAsync = class extends CacheEntanglement {
|
|
4427
4434
|
constructor(creation, option) {
|
|
4428
4435
|
super(creation, option);
|
|
4429
4436
|
}
|
|
@@ -4453,7 +4460,7 @@ var require_cjs = __commonJS({
|
|
|
4453
4460
|
const dependencyValue = await dependency.recache(key) ?? await dependency.recache(dependencyKey);
|
|
4454
4461
|
resolved[name] = dependencyValue;
|
|
4455
4462
|
}
|
|
4456
|
-
const value = new
|
|
4463
|
+
const value = new CacheData(await this.creation(key, resolved, ...parameter));
|
|
4457
4464
|
this.updateRequirements.delete(key);
|
|
4458
4465
|
this.parameters.set(key, parameter);
|
|
4459
4466
|
this.caches.set(key, value);
|
|
@@ -4556,6 +4563,42 @@ var require_cjs = __commonJS({
|
|
|
4556
4563
|
};
|
|
4557
4564
|
var MVCCStrategy2 = class {
|
|
4558
4565
|
};
|
|
4566
|
+
var LRUMap3 = class {
|
|
4567
|
+
cache = /* @__PURE__ */ new Map();
|
|
4568
|
+
capacity;
|
|
4569
|
+
constructor(capacity) {
|
|
4570
|
+
this.capacity = capacity;
|
|
4571
|
+
}
|
|
4572
|
+
get(key) {
|
|
4573
|
+
if (!this.cache.has(key)) return void 0;
|
|
4574
|
+
const value = this.cache.get(key);
|
|
4575
|
+
this.cache.delete(key);
|
|
4576
|
+
this.cache.set(key, value);
|
|
4577
|
+
return value;
|
|
4578
|
+
}
|
|
4579
|
+
set(key, value) {
|
|
4580
|
+
if (this.cache.has(key)) {
|
|
4581
|
+
this.cache.delete(key);
|
|
4582
|
+
} else if (this.cache.size >= this.capacity) {
|
|
4583
|
+
const oldestKey = this.cache.keys().next().value;
|
|
4584
|
+
if (oldestKey !== void 0) this.cache.delete(oldestKey);
|
|
4585
|
+
}
|
|
4586
|
+
this.cache.set(key, value);
|
|
4587
|
+
return this;
|
|
4588
|
+
}
|
|
4589
|
+
has(key) {
|
|
4590
|
+
return this.cache.has(key);
|
|
4591
|
+
}
|
|
4592
|
+
delete(key) {
|
|
4593
|
+
return this.cache.delete(key);
|
|
4594
|
+
}
|
|
4595
|
+
clear() {
|
|
4596
|
+
this.cache.clear();
|
|
4597
|
+
}
|
|
4598
|
+
get size() {
|
|
4599
|
+
return this.cache.size;
|
|
4600
|
+
}
|
|
4601
|
+
};
|
|
4559
4602
|
var MVCCTransaction2 = class {
|
|
4560
4603
|
committed;
|
|
4561
4604
|
snapshotVersion;
|
|
@@ -4563,11 +4606,11 @@ var require_cjs = __commonJS({
|
|
|
4563
4606
|
writeBuffer;
|
|
4564
4607
|
deleteBuffer;
|
|
4565
4608
|
createdKeys;
|
|
4566
|
-
// create()로 생성된 키 추적
|
|
4567
4609
|
deletedValues;
|
|
4568
4610
|
// delete 시 삭제 전 값 저장
|
|
4569
4611
|
originallyExisted;
|
|
4570
4612
|
// 트랜잭션 시작 시점에 디스크에 존재했던 키 (deleted 결과 필터링용)
|
|
4613
|
+
bufferHistory = /* @__PURE__ */ new Map();
|
|
4571
4614
|
// Nested Transaction Properties
|
|
4572
4615
|
parent;
|
|
4573
4616
|
localVersion;
|
|
@@ -4581,7 +4624,8 @@ var require_cjs = __commonJS({
|
|
|
4581
4624
|
versionIndex = /* @__PURE__ */ new Map();
|
|
4582
4625
|
deletedCache = /* @__PURE__ */ new Map();
|
|
4583
4626
|
activeTransactions = /* @__PURE__ */ new Set();
|
|
4584
|
-
|
|
4627
|
+
diskCache;
|
|
4628
|
+
constructor(strategy, options, parent, snapshotVersion) {
|
|
4585
4629
|
this.snapshotVersion = snapshotVersion ?? 0;
|
|
4586
4630
|
this.writeBuffer = /* @__PURE__ */ new Map();
|
|
4587
4631
|
this.deleteBuffer = /* @__PURE__ */ new Set();
|
|
@@ -4596,6 +4640,7 @@ var require_cjs = __commonJS({
|
|
|
4596
4640
|
this.snapshotLocalVersion = parent.localVersion;
|
|
4597
4641
|
this.strategy = void 0;
|
|
4598
4642
|
this.root = parent.root;
|
|
4643
|
+
this.diskCache = parent.diskCache;
|
|
4599
4644
|
} else {
|
|
4600
4645
|
if (!strategy) throw new Error("Root Transaction must get Strategy");
|
|
4601
4646
|
this.strategy = strategy;
|
|
@@ -4603,8 +4648,13 @@ var require_cjs = __commonJS({
|
|
|
4603
4648
|
this.localVersion = 0;
|
|
4604
4649
|
this.snapshotLocalVersion = 0;
|
|
4605
4650
|
this.root = this;
|
|
4651
|
+
this.diskCache = new LRUMap3(options?.cacheCapacity ?? 1e3);
|
|
4606
4652
|
}
|
|
4607
4653
|
}
|
|
4654
|
+
/**
|
|
4655
|
+
* Checks if the transaction is a root transaction.
|
|
4656
|
+
* @returns True if the transaction is a root transaction, false otherwise.
|
|
4657
|
+
*/
|
|
4608
4658
|
isRoot() {
|
|
4609
4659
|
return !this.parent;
|
|
4610
4660
|
}
|
|
@@ -4621,27 +4671,96 @@ var require_cjs = __commonJS({
|
|
|
4621
4671
|
}
|
|
4622
4672
|
return false;
|
|
4623
4673
|
}
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4674
|
+
/**
|
|
4675
|
+
* Checks if a key was written in this transaction.
|
|
4676
|
+
* @param key The key to check.
|
|
4677
|
+
* @returns True if the key was written in this transaction, false otherwise.
|
|
4678
|
+
*/
|
|
4679
|
+
isWrote(key) {
|
|
4680
|
+
return this.writeBuffer.has(key);
|
|
4681
|
+
}
|
|
4682
|
+
/**
|
|
4683
|
+
* Checks if a key was deleted in this transaction.
|
|
4684
|
+
* @param key The key to check.
|
|
4685
|
+
* @returns True if the key was deleted in this transaction, false otherwise.
|
|
4686
|
+
*/
|
|
4687
|
+
isDeleted(key) {
|
|
4688
|
+
return this.deleteBuffer.has(key);
|
|
4689
|
+
}
|
|
4690
|
+
_recordHistory(key) {
|
|
4691
|
+
const existsInWriteBuffer = this.writeBuffer.has(key);
|
|
4692
|
+
const existsInDeleteBuffer = this.deleteBuffer.has(key);
|
|
4693
|
+
const currentVer = this.keyVersions.get(key);
|
|
4694
|
+
if (currentVer !== void 0) {
|
|
4695
|
+
if (!this.bufferHistory.has(key)) this.bufferHistory.set(key, []);
|
|
4696
|
+
this.bufferHistory.get(key).push({
|
|
4697
|
+
value: existsInWriteBuffer ? this.writeBuffer.get(key) : this.deletedValues.get(key) ?? null,
|
|
4698
|
+
exists: existsInWriteBuffer || !existsInDeleteBuffer,
|
|
4699
|
+
version: currentVer
|
|
4700
|
+
});
|
|
4701
|
+
}
|
|
4702
|
+
}
|
|
4703
|
+
/**
|
|
4704
|
+
* BINARY SEARCH HELPER: Finds the index of the last element in the array
|
|
4705
|
+
* where item[key] <= target. Assumes the array is sorted by 'key' ascending.
|
|
4706
|
+
*/
|
|
4707
|
+
_findLastLE(array, target, property) {
|
|
4708
|
+
let left = 0;
|
|
4709
|
+
let right = array.length - 1;
|
|
4710
|
+
let result = -1;
|
|
4711
|
+
while (left <= right) {
|
|
4712
|
+
const mid = left + right >> 1;
|
|
4713
|
+
if (array[mid][property] <= target) {
|
|
4714
|
+
result = mid;
|
|
4715
|
+
left = mid + 1;
|
|
4716
|
+
} else {
|
|
4717
|
+
right = mid - 1;
|
|
4718
|
+
}
|
|
4719
|
+
}
|
|
4720
|
+
return result;
|
|
4721
|
+
}
|
|
4722
|
+
/**
|
|
4723
|
+
* BINARY SEARCH HELPER: Finds the index of the element in the array
|
|
4724
|
+
* where item[key] === target. Assumes the array is sorted by 'key' ascending.
|
|
4725
|
+
*/
|
|
4726
|
+
_findExact(array, target, property) {
|
|
4727
|
+
let left = 0;
|
|
4728
|
+
let right = array.length - 1;
|
|
4729
|
+
while (left <= right) {
|
|
4730
|
+
const mid = left + right >> 1;
|
|
4731
|
+
const val = array[mid][property];
|
|
4732
|
+
if (val === target) return mid;
|
|
4733
|
+
if (val < target) left = mid + 1;
|
|
4734
|
+
else right = mid - 1;
|
|
4735
|
+
}
|
|
4736
|
+
return -1;
|
|
4737
|
+
}
|
|
4738
|
+
_bufferCreate(key, value, version) {
|
|
4739
|
+
if (version === void 0) this.localVersion++;
|
|
4740
|
+
const targetVersion = version ?? this.localVersion;
|
|
4741
|
+
this._recordHistory(key);
|
|
4627
4742
|
this.writeBuffer.set(key, value);
|
|
4628
4743
|
this.createdKeys.add(key);
|
|
4629
4744
|
this.deleteBuffer.delete(key);
|
|
4630
4745
|
this.originallyExisted.delete(key);
|
|
4631
|
-
this.keyVersions.set(key,
|
|
4746
|
+
this.keyVersions.set(key, targetVersion);
|
|
4632
4747
|
}
|
|
4633
|
-
_bufferWrite(key, value) {
|
|
4634
|
-
this.localVersion++;
|
|
4748
|
+
_bufferWrite(key, value, version) {
|
|
4749
|
+
if (version === void 0) this.localVersion++;
|
|
4750
|
+
const targetVersion = version ?? this.localVersion;
|
|
4751
|
+
this._recordHistory(key);
|
|
4635
4752
|
this.writeBuffer.set(key, value);
|
|
4636
4753
|
this.deleteBuffer.delete(key);
|
|
4637
|
-
this.keyVersions.set(key,
|
|
4754
|
+
this.keyVersions.set(key, targetVersion);
|
|
4638
4755
|
}
|
|
4639
|
-
_bufferDelete(key) {
|
|
4640
|
-
this.localVersion++;
|
|
4756
|
+
_bufferDelete(key, version) {
|
|
4757
|
+
if (version === void 0) this.localVersion++;
|
|
4758
|
+
const targetVersion = version ?? this.localVersion;
|
|
4759
|
+
this._recordHistory(key);
|
|
4641
4760
|
this.deleteBuffer.add(key);
|
|
4642
4761
|
this.writeBuffer.delete(key);
|
|
4643
4762
|
this.createdKeys.delete(key);
|
|
4644
|
-
this.keyVersions.set(key,
|
|
4763
|
+
this.keyVersions.set(key, targetVersion);
|
|
4645
4764
|
}
|
|
4646
4765
|
/**
|
|
4647
4766
|
* Returns the entries that will be created, updated, and deleted by this transaction.
|
|
@@ -4665,7 +4784,11 @@ var require_cjs = __commonJS({
|
|
|
4665
4784
|
deleted.push({ key, data });
|
|
4666
4785
|
}
|
|
4667
4786
|
}
|
|
4668
|
-
return {
|
|
4787
|
+
return {
|
|
4788
|
+
created,
|
|
4789
|
+
updated,
|
|
4790
|
+
deleted
|
|
4791
|
+
};
|
|
4669
4792
|
}
|
|
4670
4793
|
/**
|
|
4671
4794
|
* Rolls back the transaction.
|
|
@@ -4683,7 +4806,36 @@ var require_cjs = __commonJS({
|
|
|
4683
4806
|
if (this.root !== this) {
|
|
4684
4807
|
this.root.activeTransactions.delete(this);
|
|
4685
4808
|
}
|
|
4686
|
-
return {
|
|
4809
|
+
return {
|
|
4810
|
+
success: true,
|
|
4811
|
+
created,
|
|
4812
|
+
updated,
|
|
4813
|
+
deleted
|
|
4814
|
+
};
|
|
4815
|
+
}
|
|
4816
|
+
/**
|
|
4817
|
+
* Checks for conflicts among multiple transactions.
|
|
4818
|
+
* A conflict occurs if two or more transactions modify (write or delete) the same key.
|
|
4819
|
+
* @param transactions Array of transactions to check.
|
|
4820
|
+
* @returns An array of keys that are in conflict.
|
|
4821
|
+
*/
|
|
4822
|
+
static CheckConflicts(transactions) {
|
|
4823
|
+
const modifiedKeys = /* @__PURE__ */ new Map();
|
|
4824
|
+
const conflicts = /* @__PURE__ */ new Set();
|
|
4825
|
+
for (const tx of transactions) {
|
|
4826
|
+
const txModified = /* @__PURE__ */ new Set([
|
|
4827
|
+
...tx.writeBuffer.keys(),
|
|
4828
|
+
...tx.deleteBuffer
|
|
4829
|
+
]);
|
|
4830
|
+
for (const key of txModified) {
|
|
4831
|
+
const count = modifiedKeys.get(key) ?? 0;
|
|
4832
|
+
if (count > 0) {
|
|
4833
|
+
conflicts.add(key);
|
|
4834
|
+
}
|
|
4835
|
+
modifiedKeys.set(key, count + 1);
|
|
4836
|
+
}
|
|
4837
|
+
}
|
|
4838
|
+
return Array.from(conflicts);
|
|
4687
4839
|
}
|
|
4688
4840
|
/**
|
|
4689
4841
|
* Cleans up both deletedCache and versionIndex based on minActiveVersion.
|
|
@@ -4718,7 +4870,9 @@ var require_cjs = __commonJS({
|
|
|
4718
4870
|
break;
|
|
4719
4871
|
}
|
|
4720
4872
|
}
|
|
4721
|
-
if (latestInSnapshotIdx
|
|
4873
|
+
if (latestInSnapshotIdx === versions.length - 1) {
|
|
4874
|
+
this.versionIndex.delete(key);
|
|
4875
|
+
} else if (latestInSnapshotIdx > 0) {
|
|
4722
4876
|
versions.splice(0, latestInSnapshotIdx);
|
|
4723
4877
|
}
|
|
4724
4878
|
}
|
|
@@ -4767,7 +4921,7 @@ var require_cjs = __commonJS({
|
|
|
4767
4921
|
createNested() {
|
|
4768
4922
|
if (this.committed) throw new Error("Transaction already committed");
|
|
4769
4923
|
const childVersion = this.isRoot() ? this.version : this.snapshotVersion;
|
|
4770
|
-
const child = new _SyncMVCCTransaction2(void 0, this, childVersion);
|
|
4924
|
+
const child = new _SyncMVCCTransaction2(void 0, void 0, this, childVersion);
|
|
4771
4925
|
this.root.activeTransactions.add(child);
|
|
4772
4926
|
return child;
|
|
4773
4927
|
}
|
|
@@ -4775,32 +4929,77 @@ var require_cjs = __commonJS({
|
|
|
4775
4929
|
if (this.committed) throw new Error("Transaction already committed");
|
|
4776
4930
|
if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
|
|
4777
4931
|
if (this.deleteBuffer.has(key)) return null;
|
|
4778
|
-
|
|
4932
|
+
if (this.parent) {
|
|
4933
|
+
return this.parent._readSnapshot(key, this.snapshotVersion, this.snapshotLocalVersion);
|
|
4934
|
+
}
|
|
4935
|
+
return this._diskRead(key, this.snapshotVersion);
|
|
4779
4936
|
}
|
|
4780
4937
|
exists(key) {
|
|
4781
4938
|
if (this.committed) throw new Error("Transaction already committed");
|
|
4782
4939
|
if (this.deleteBuffer.has(key)) return false;
|
|
4783
4940
|
if (this.writeBuffer.has(key)) return true;
|
|
4784
|
-
|
|
4941
|
+
if (this.parent) {
|
|
4942
|
+
return this.parent._existsSnapshot(key, this.snapshotVersion, this.snapshotLocalVersion);
|
|
4943
|
+
}
|
|
4944
|
+
return this._diskExists(key, this.snapshotVersion);
|
|
4785
4945
|
}
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4946
|
+
_existsSnapshot(key, snapshotVersion, snapshotLocalVersion) {
|
|
4947
|
+
let current = this;
|
|
4948
|
+
let slVer = snapshotLocalVersion;
|
|
4949
|
+
while (current) {
|
|
4950
|
+
if (current.writeBuffer.has(key)) {
|
|
4951
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
4952
|
+
if (slVer === void 0 || keyModVersion <= slVer) return true;
|
|
4953
|
+
}
|
|
4954
|
+
if (current.deleteBuffer.has(key)) {
|
|
4955
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
4956
|
+
if (slVer === void 0 || keyModVersion <= slVer) return false;
|
|
4957
|
+
}
|
|
4958
|
+
const history = current.bufferHistory.get(key);
|
|
4959
|
+
if (history && slVer !== void 0) {
|
|
4960
|
+
const idx = current._findLastLE(history, slVer, "version");
|
|
4961
|
+
if (idx >= 0) return history[idx].exists;
|
|
4962
|
+
}
|
|
4963
|
+
if (current.parent) {
|
|
4964
|
+
slVer = current.snapshotLocalVersion;
|
|
4965
|
+
current = current.parent;
|
|
4966
|
+
} else {
|
|
4967
|
+
return current._diskExists(key, snapshotVersion);
|
|
4791
4968
|
}
|
|
4792
4969
|
}
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
4970
|
+
return false;
|
|
4971
|
+
}
|
|
4972
|
+
_readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
|
|
4973
|
+
let current = this;
|
|
4974
|
+
let slVer = snapshotLocalVersion;
|
|
4975
|
+
while (current) {
|
|
4976
|
+
if (current.writeBuffer.has(key)) {
|
|
4977
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
4978
|
+
if (slVer === void 0 || keyModVersion <= slVer) {
|
|
4979
|
+
return current.writeBuffer.get(key);
|
|
4980
|
+
}
|
|
4981
|
+
}
|
|
4982
|
+
if (current.deleteBuffer.has(key)) {
|
|
4983
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
4984
|
+
if (slVer === void 0 || keyModVersion <= slVer) {
|
|
4985
|
+
return null;
|
|
4986
|
+
}
|
|
4987
|
+
}
|
|
4988
|
+
const history = current.bufferHistory.get(key);
|
|
4989
|
+
if (history && slVer !== void 0) {
|
|
4990
|
+
const idx = current._findLastLE(history, slVer, "version");
|
|
4991
|
+
if (idx >= 0) {
|
|
4992
|
+
return history[idx].exists ? history[idx].value : null;
|
|
4993
|
+
}
|
|
4994
|
+
}
|
|
4995
|
+
if (current.parent) {
|
|
4996
|
+
slVer = current.snapshotLocalVersion;
|
|
4997
|
+
current = current.parent;
|
|
4998
|
+
} else {
|
|
4999
|
+
return current._diskRead(key, snapshotVersion);
|
|
4797
5000
|
}
|
|
4798
5001
|
}
|
|
4799
|
-
|
|
4800
|
-
return this.parent._readSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
|
|
4801
|
-
} else {
|
|
4802
|
-
return this._diskRead(key, snapshotVersion);
|
|
4803
|
-
}
|
|
5002
|
+
return null;
|
|
4804
5003
|
}
|
|
4805
5004
|
commit(label) {
|
|
4806
5005
|
const { created, updated, deleted } = this.getResultEntries();
|
|
@@ -4860,6 +5059,7 @@ var require_cjs = __commonJS({
|
|
|
4860
5059
|
this.deletedValues.clear();
|
|
4861
5060
|
this.originallyExisted.clear();
|
|
4862
5061
|
this.keyVersions.clear();
|
|
5062
|
+
this.bufferHistory.clear();
|
|
4863
5063
|
this.localVersion = 0;
|
|
4864
5064
|
this.snapshotVersion = this.version;
|
|
4865
5065
|
}
|
|
@@ -4900,32 +5100,22 @@ var require_cjs = __commonJS({
|
|
|
4900
5100
|
};
|
|
4901
5101
|
}
|
|
4902
5102
|
}
|
|
4903
|
-
const
|
|
4904
|
-
for (const key of child.writeBuffer
|
|
4905
|
-
|
|
4906
|
-
this.
|
|
4907
|
-
this.
|
|
4908
|
-
if (child.createdKeys.has(key)) {
|
|
4909
|
-
this.createdKeys.add(key);
|
|
4910
|
-
}
|
|
5103
|
+
const mergeVersion = ++this.localVersion;
|
|
5104
|
+
for (const [key, value] of child.writeBuffer) {
|
|
5105
|
+
const wasCreated = child.createdKeys.has(key);
|
|
5106
|
+
if (wasCreated) this._bufferCreate(key, value, mergeVersion);
|
|
5107
|
+
else this._bufferWrite(key, value, mergeVersion);
|
|
4911
5108
|
}
|
|
4912
5109
|
for (const key of child.deleteBuffer) {
|
|
4913
|
-
this.deleteBuffer.add(key);
|
|
4914
|
-
this.writeBuffer.delete(key);
|
|
4915
|
-
this.createdKeys.delete(key);
|
|
4916
|
-
this.keyVersions.set(key, newLocalVersion);
|
|
4917
5110
|
const deletedValue = child.deletedValues.get(key);
|
|
4918
|
-
if (deletedValue !== void 0)
|
|
4919
|
-
|
|
4920
|
-
}
|
|
4921
|
-
if (child.originallyExisted.has(key)) {
|
|
5111
|
+
if (deletedValue !== void 0) this.deletedValues.set(key, deletedValue);
|
|
5112
|
+
if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
|
|
4922
5113
|
this.originallyExisted.add(key);
|
|
4923
5114
|
}
|
|
5115
|
+
this._bufferDelete(key, mergeVersion);
|
|
4924
5116
|
}
|
|
4925
|
-
this.localVersion = newLocalVersion;
|
|
4926
5117
|
this.root.activeTransactions.delete(child);
|
|
4927
5118
|
} else {
|
|
4928
|
-
const newVersion = this.version + 1;
|
|
4929
5119
|
if (child !== this) {
|
|
4930
5120
|
const modifiedKeys = /* @__PURE__ */ new Set([...child.writeBuffer.keys(), ...child.deleteBuffer]);
|
|
4931
5121
|
for (const key of modifiedKeys) {
|
|
@@ -4943,50 +5133,57 @@ var require_cjs = __commonJS({
|
|
|
4943
5133
|
};
|
|
4944
5134
|
}
|
|
4945
5135
|
}
|
|
5136
|
+
const lastModLocalVer = this.keyVersions.get(key);
|
|
5137
|
+
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
5138
|
+
return {
|
|
5139
|
+
error: `Commit conflict: Key '${key}' was modified by a newer transaction in the same session (Local v${lastModLocalVer})`,
|
|
5140
|
+
conflict: {
|
|
5141
|
+
key,
|
|
5142
|
+
parent: this.read(key),
|
|
5143
|
+
child: child.read(key)
|
|
5144
|
+
}
|
|
5145
|
+
};
|
|
5146
|
+
}
|
|
4946
5147
|
}
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
for (const key of child.deleteBuffer) {
|
|
4956
|
-
this.deleteBuffer.add(key);
|
|
4957
|
-
this.writeBuffer.delete(key);
|
|
4958
|
-
this.createdKeys.delete(key);
|
|
4959
|
-
const deletedValue = child.deletedValues.get(key);
|
|
4960
|
-
if (deletedValue !== void 0) {
|
|
4961
|
-
this.deletedValues.set(key, deletedValue);
|
|
5148
|
+
const mergeVersion = ++this.localVersion;
|
|
5149
|
+
for (const [key, value] of child.writeBuffer) {
|
|
5150
|
+
const wasCreated = child.createdKeys.has(key);
|
|
5151
|
+
if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
|
|
5152
|
+
this.originallyExisted.add(key);
|
|
5153
|
+
}
|
|
5154
|
+
if (wasCreated) this._bufferCreate(key, value, mergeVersion);
|
|
5155
|
+
else this._bufferWrite(key, value, mergeVersion);
|
|
4962
5156
|
}
|
|
4963
|
-
|
|
4964
|
-
|
|
5157
|
+
for (const key of child.deleteBuffer) {
|
|
5158
|
+
const deletedValue = child.deletedValues.get(key);
|
|
5159
|
+
if (deletedValue !== void 0) this.deletedValues.set(key, deletedValue);
|
|
5160
|
+
if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
|
|
5161
|
+
this.originallyExisted.add(key);
|
|
5162
|
+
}
|
|
5163
|
+
this._bufferDelete(key, mergeVersion);
|
|
4965
5164
|
}
|
|
5165
|
+
this.root.activeTransactions.delete(child);
|
|
5166
|
+
} else {
|
|
5167
|
+
const newVersion = this.version + 1;
|
|
5168
|
+
for (const [key, value] of this.writeBuffer) this._diskWrite(key, value, newVersion);
|
|
5169
|
+
for (const key of this.deleteBuffer) this._diskDelete(key, newVersion);
|
|
5170
|
+
this.version = newVersion;
|
|
5171
|
+
this._cleanupDeletedCache();
|
|
4966
5172
|
}
|
|
4967
|
-
for (const [key, value] of child.writeBuffer) {
|
|
4968
|
-
this._diskWrite(key, value, newVersion);
|
|
4969
|
-
}
|
|
4970
|
-
for (const key of child.deleteBuffer) {
|
|
4971
|
-
this._diskDelete(key, newVersion);
|
|
4972
|
-
}
|
|
4973
|
-
this.version = newVersion;
|
|
4974
|
-
this.root.activeTransactions.delete(child);
|
|
4975
|
-
this._cleanupDeletedCache();
|
|
4976
5173
|
}
|
|
4977
5174
|
return null;
|
|
4978
5175
|
}
|
|
4979
|
-
// --- Internal IO Helpers (Root Only) ---
|
|
4980
5176
|
_diskWrite(key, value, version) {
|
|
4981
5177
|
const strategy = this.strategy;
|
|
4982
5178
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
4983
|
-
|
|
4984
|
-
|
|
5179
|
+
const rootAsAny = this.root;
|
|
5180
|
+
if (this._diskExists(key, version)) {
|
|
5181
|
+
const currentVal = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : strategy.read(key);
|
|
4985
5182
|
if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
|
|
4986
|
-
this.deletedCache.get(key).push({
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
5183
|
+
this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: version });
|
|
5184
|
+
rootAsAny.diskCache.set(key, value);
|
|
5185
|
+
} else {
|
|
5186
|
+
rootAsAny.diskCache.set(key, value);
|
|
4990
5187
|
}
|
|
4991
5188
|
strategy.write(key, value);
|
|
4992
5189
|
if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
|
|
@@ -4997,36 +5194,44 @@ var require_cjs = __commonJS({
|
|
|
4997
5194
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
4998
5195
|
const versions = this.versionIndex.get(key);
|
|
4999
5196
|
if (!versions) {
|
|
5000
|
-
|
|
5197
|
+
const rootAsAny = this.root;
|
|
5198
|
+
if (this._diskExists(key, snapshotVersion)) {
|
|
5199
|
+
const val = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : strategy.read(key);
|
|
5200
|
+
rootAsAny.diskCache.set(key, val);
|
|
5201
|
+
return val;
|
|
5202
|
+
}
|
|
5203
|
+
return null;
|
|
5001
5204
|
}
|
|
5002
5205
|
let targetVerObj = null;
|
|
5003
5206
|
let nextVerObj = null;
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
} else {
|
|
5008
|
-
nextVerObj = v;
|
|
5009
|
-
break;
|
|
5010
|
-
}
|
|
5011
|
-
}
|
|
5207
|
+
const idx = this._findLastLE(versions, snapshotVersion, "version");
|
|
5208
|
+
if (idx >= 0) targetVerObj = versions[idx];
|
|
5209
|
+
if (idx + 1 < versions.length) nextVerObj = versions[idx + 1];
|
|
5012
5210
|
if (!targetVerObj) {
|
|
5013
5211
|
if (nextVerObj) {
|
|
5014
5212
|
const cached2 = this.deletedCache.get(key);
|
|
5015
5213
|
if (cached2) {
|
|
5016
|
-
const
|
|
5017
|
-
if (
|
|
5214
|
+
const cIdx = this._findExact(cached2, nextVerObj.version, "deletedAtVersion");
|
|
5215
|
+
if (cIdx >= 0) return cached2[cIdx].value;
|
|
5018
5216
|
}
|
|
5019
5217
|
}
|
|
5020
5218
|
return null;
|
|
5021
5219
|
}
|
|
5022
5220
|
if (!targetVerObj.exists) return null;
|
|
5023
5221
|
if (!nextVerObj) {
|
|
5024
|
-
return
|
|
5222
|
+
if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
|
|
5223
|
+
if (this._diskExists(key, snapshotVersion)) {
|
|
5224
|
+
const rootAsAny = this.root;
|
|
5225
|
+
const val = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : strategy.read(key);
|
|
5226
|
+
rootAsAny.diskCache.set(key, val);
|
|
5227
|
+
return val;
|
|
5228
|
+
}
|
|
5229
|
+
return null;
|
|
5025
5230
|
}
|
|
5026
5231
|
const cached = this.deletedCache.get(key);
|
|
5027
5232
|
if (cached) {
|
|
5028
|
-
const
|
|
5029
|
-
if (
|
|
5233
|
+
const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
|
|
5234
|
+
if (cIdx >= 0) return cached[cIdx].value;
|
|
5030
5235
|
}
|
|
5031
5236
|
return null;
|
|
5032
5237
|
}
|
|
@@ -5035,31 +5240,40 @@ var require_cjs = __commonJS({
|
|
|
5035
5240
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
5036
5241
|
const versions = this.versionIndex.get(key);
|
|
5037
5242
|
if (!versions) {
|
|
5038
|
-
|
|
5243
|
+
const rootAsAny = this.root;
|
|
5244
|
+
if (rootAsAny.diskCache.has(key)) return rootAsAny.diskCache.get(key) !== null;
|
|
5245
|
+
const exists = strategy.exists(key);
|
|
5246
|
+
if (!exists) rootAsAny.diskCache.set(key, null);
|
|
5247
|
+
return exists;
|
|
5039
5248
|
}
|
|
5040
5249
|
let targetVerObj = null;
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5250
|
+
let nextVerObj = null;
|
|
5251
|
+
const idx = this._findLastLE(versions, snapshotVersion, "version");
|
|
5252
|
+
if (idx >= 0) targetVerObj = versions[idx];
|
|
5253
|
+
if (idx + 1 < versions.length) nextVerObj = versions[idx + 1];
|
|
5254
|
+
if (!targetVerObj) {
|
|
5255
|
+
if (nextVerObj) {
|
|
5256
|
+
const cached = this.deletedCache.get(key);
|
|
5257
|
+
if (cached) {
|
|
5258
|
+
const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
|
|
5259
|
+
if (cIdx >= 0) return true;
|
|
5260
|
+
}
|
|
5046
5261
|
}
|
|
5262
|
+
return false;
|
|
5047
5263
|
}
|
|
5048
|
-
if (!targetVerObj) return strategy.exists(key);
|
|
5049
5264
|
return targetVerObj.exists;
|
|
5050
5265
|
}
|
|
5051
5266
|
_diskDelete(key, snapshotVersion) {
|
|
5052
5267
|
const strategy = this.strategy;
|
|
5053
5268
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
5054
|
-
|
|
5055
|
-
|
|
5269
|
+
const rootAsAny = this.root;
|
|
5270
|
+
if (this._diskExists(key, snapshotVersion)) {
|
|
5271
|
+
const currentVal = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : strategy.read(key);
|
|
5056
5272
|
if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
|
|
5057
|
-
this.deletedCache.get(key).push({
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
});
|
|
5273
|
+
this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: snapshotVersion });
|
|
5274
|
+
strategy.delete(key);
|
|
5275
|
+
rootAsAny.diskCache.delete(key);
|
|
5061
5276
|
}
|
|
5062
|
-
strategy.delete(key);
|
|
5063
5277
|
if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
|
|
5064
5278
|
this.versionIndex.get(key).push({ version: snapshotVersion, exists: false });
|
|
5065
5279
|
}
|
|
@@ -5372,7 +5586,7 @@ var require_cjs = __commonJS({
|
|
|
5372
5586
|
createNested() {
|
|
5373
5587
|
if (this.committed) throw new Error("Transaction already committed");
|
|
5374
5588
|
const childVersion = this.isRoot() ? this.version : this.snapshotVersion;
|
|
5375
|
-
const child = new _AsyncMVCCTransaction2(void 0, this, childVersion);
|
|
5589
|
+
const child = new _AsyncMVCCTransaction2(void 0, void 0, this, childVersion);
|
|
5376
5590
|
this.root.activeTransactions.add(child);
|
|
5377
5591
|
return child;
|
|
5378
5592
|
}
|
|
@@ -5380,32 +5594,77 @@ var require_cjs = __commonJS({
|
|
|
5380
5594
|
if (this.committed) throw new Error("Transaction already committed");
|
|
5381
5595
|
if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
|
|
5382
5596
|
if (this.deleteBuffer.has(key)) return null;
|
|
5383
|
-
|
|
5597
|
+
if (this.parent) {
|
|
5598
|
+
return this.parent._readSnapshot(key, this.snapshotVersion, this.snapshotLocalVersion);
|
|
5599
|
+
}
|
|
5600
|
+
return await this._diskRead(key, this.snapshotVersion);
|
|
5384
5601
|
}
|
|
5385
5602
|
async exists(key) {
|
|
5386
5603
|
if (this.committed) throw new Error("Transaction already committed");
|
|
5387
5604
|
if (this.deleteBuffer.has(key)) return false;
|
|
5388
5605
|
if (this.writeBuffer.has(key)) return true;
|
|
5389
|
-
|
|
5606
|
+
if (this.parent) {
|
|
5607
|
+
return this.parent._existsSnapshot(key, this.snapshotVersion, this.snapshotLocalVersion);
|
|
5608
|
+
}
|
|
5609
|
+
return await this._diskExists(key, this.snapshotVersion);
|
|
5390
5610
|
}
|
|
5391
|
-
async
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5611
|
+
async _existsSnapshot(key, snapshotVersion, snapshotLocalVersion) {
|
|
5612
|
+
let current = this;
|
|
5613
|
+
let slVer = snapshotLocalVersion;
|
|
5614
|
+
while (current) {
|
|
5615
|
+
if (current.writeBuffer.has(key)) {
|
|
5616
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
5617
|
+
if (slVer === void 0 || keyModVersion <= slVer) return true;
|
|
5618
|
+
}
|
|
5619
|
+
if (current.deleteBuffer.has(key)) {
|
|
5620
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
5621
|
+
if (slVer === void 0 || keyModVersion <= slVer) return false;
|
|
5622
|
+
}
|
|
5623
|
+
const history = current.bufferHistory.get(key);
|
|
5624
|
+
if (history && slVer !== void 0) {
|
|
5625
|
+
const idx = current._findLastLE(history, slVer, "version");
|
|
5626
|
+
if (idx >= 0) return history[idx].exists;
|
|
5627
|
+
}
|
|
5628
|
+
if (current.parent) {
|
|
5629
|
+
slVer = current.snapshotLocalVersion;
|
|
5630
|
+
current = current.parent;
|
|
5631
|
+
} else {
|
|
5632
|
+
return await current._diskExists(key, snapshotVersion);
|
|
5396
5633
|
}
|
|
5397
5634
|
}
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5635
|
+
return false;
|
|
5636
|
+
}
|
|
5637
|
+
async _readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
|
|
5638
|
+
let current = this;
|
|
5639
|
+
let slVer = snapshotLocalVersion;
|
|
5640
|
+
while (current) {
|
|
5641
|
+
if (current.writeBuffer.has(key)) {
|
|
5642
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
5643
|
+
if (slVer === void 0 || keyModVersion <= slVer) {
|
|
5644
|
+
return current.writeBuffer.get(key);
|
|
5645
|
+
}
|
|
5646
|
+
}
|
|
5647
|
+
if (current.deleteBuffer.has(key)) {
|
|
5648
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
5649
|
+
if (slVer === void 0 || keyModVersion <= slVer) {
|
|
5650
|
+
return null;
|
|
5651
|
+
}
|
|
5652
|
+
}
|
|
5653
|
+
const history = current.bufferHistory.get(key);
|
|
5654
|
+
if (history && slVer !== void 0) {
|
|
5655
|
+
const idx = current._findLastLE(history, slVer, "version");
|
|
5656
|
+
if (idx >= 0) {
|
|
5657
|
+
return history[idx].exists ? history[idx].value : null;
|
|
5658
|
+
}
|
|
5659
|
+
}
|
|
5660
|
+
if (current.parent) {
|
|
5661
|
+
slVer = current.snapshotLocalVersion;
|
|
5662
|
+
current = current.parent;
|
|
5663
|
+
} else {
|
|
5664
|
+
return await current._diskRead(key, snapshotVersion);
|
|
5402
5665
|
}
|
|
5403
5666
|
}
|
|
5404
|
-
|
|
5405
|
-
return this.parent._readSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
|
|
5406
|
-
} else {
|
|
5407
|
-
return this._diskRead(key, snapshotVersion);
|
|
5408
|
-
}
|
|
5667
|
+
return null;
|
|
5409
5668
|
}
|
|
5410
5669
|
async commit(label) {
|
|
5411
5670
|
const { created, updated, deleted } = this.getResultEntries();
|
|
@@ -5465,6 +5724,7 @@ var require_cjs = __commonJS({
|
|
|
5465
5724
|
this.deletedValues.clear();
|
|
5466
5725
|
this.originallyExisted.clear();
|
|
5467
5726
|
this.keyVersions.clear();
|
|
5727
|
+
this.bufferHistory.clear();
|
|
5468
5728
|
this.localVersion = 0;
|
|
5469
5729
|
this.snapshotVersion = this.version;
|
|
5470
5730
|
}
|
|
@@ -5506,33 +5766,23 @@ var require_cjs = __commonJS({
|
|
|
5506
5766
|
};
|
|
5507
5767
|
}
|
|
5508
5768
|
}
|
|
5509
|
-
const
|
|
5510
|
-
for (const key of child.writeBuffer
|
|
5511
|
-
|
|
5512
|
-
this.
|
|
5513
|
-
this.
|
|
5514
|
-
if (child.createdKeys.has(key)) {
|
|
5515
|
-
this.createdKeys.add(key);
|
|
5516
|
-
}
|
|
5769
|
+
const mergeVersion = ++this.localVersion;
|
|
5770
|
+
for (const [key, value] of child.writeBuffer) {
|
|
5771
|
+
const wasCreated = child.createdKeys.has(key);
|
|
5772
|
+
if (wasCreated) this._bufferCreate(key, value, mergeVersion);
|
|
5773
|
+
else this._bufferWrite(key, value, mergeVersion);
|
|
5517
5774
|
}
|
|
5518
5775
|
for (const key of child.deleteBuffer) {
|
|
5519
|
-
this.deleteBuffer.add(key);
|
|
5520
|
-
this.writeBuffer.delete(key);
|
|
5521
|
-
this.createdKeys.delete(key);
|
|
5522
|
-
this.keyVersions.set(key, newLocalVersion);
|
|
5523
5776
|
const deletedValue = child.deletedValues.get(key);
|
|
5524
|
-
if (deletedValue !== void 0)
|
|
5525
|
-
|
|
5526
|
-
}
|
|
5527
|
-
if (child.originallyExisted.has(key)) {
|
|
5777
|
+
if (deletedValue !== void 0) this.deletedValues.set(key, deletedValue);
|
|
5778
|
+
if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
|
|
5528
5779
|
this.originallyExisted.add(key);
|
|
5529
5780
|
}
|
|
5781
|
+
this._bufferDelete(key, mergeVersion);
|
|
5530
5782
|
}
|
|
5531
|
-
this.localVersion = newLocalVersion;
|
|
5532
5783
|
this.root.activeTransactions.delete(child);
|
|
5533
5784
|
return null;
|
|
5534
5785
|
} else {
|
|
5535
|
-
const newVersion = this.version + 1;
|
|
5536
5786
|
if (child !== this) {
|
|
5537
5787
|
const modifiedKeys = /* @__PURE__ */ new Set([...child.writeBuffer.keys(), ...child.deleteBuffer]);
|
|
5538
5788
|
for (const key of modifiedKeys) {
|
|
@@ -5550,51 +5800,58 @@ var require_cjs = __commonJS({
|
|
|
5550
5800
|
};
|
|
5551
5801
|
}
|
|
5552
5802
|
}
|
|
5803
|
+
const lastModLocalVer = this.keyVersions.get(key);
|
|
5804
|
+
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
5805
|
+
return {
|
|
5806
|
+
error: `Commit conflict: Key '${key}' was modified by a newer transaction in the same session (Local v${lastModLocalVer})`,
|
|
5807
|
+
conflict: {
|
|
5808
|
+
key,
|
|
5809
|
+
parent: await this.read(key),
|
|
5810
|
+
child: await child.read(key)
|
|
5811
|
+
}
|
|
5812
|
+
};
|
|
5813
|
+
}
|
|
5553
5814
|
}
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
for (const key of child.deleteBuffer) {
|
|
5563
|
-
this.deleteBuffer.add(key);
|
|
5564
|
-
this.writeBuffer.delete(key);
|
|
5565
|
-
this.createdKeys.delete(key);
|
|
5566
|
-
const deletedValue = child.deletedValues.get(key);
|
|
5567
|
-
if (deletedValue !== void 0) {
|
|
5568
|
-
this.deletedValues.set(key, deletedValue);
|
|
5815
|
+
const mergeVersion = ++this.localVersion;
|
|
5816
|
+
for (const [key, value] of child.writeBuffer) {
|
|
5817
|
+
const wasCreated = child.createdKeys.has(key);
|
|
5818
|
+
if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
|
|
5819
|
+
this.originallyExisted.add(key);
|
|
5820
|
+
}
|
|
5821
|
+
if (wasCreated) this._bufferCreate(key, value, mergeVersion);
|
|
5822
|
+
else this._bufferWrite(key, value, mergeVersion);
|
|
5569
5823
|
}
|
|
5570
|
-
|
|
5571
|
-
|
|
5824
|
+
for (const key of child.deleteBuffer) {
|
|
5825
|
+
const deletedValue = child.deletedValues.get(key);
|
|
5826
|
+
if (deletedValue !== void 0) this.deletedValues.set(key, deletedValue);
|
|
5827
|
+
if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
|
|
5828
|
+
this.originallyExisted.add(key);
|
|
5829
|
+
}
|
|
5830
|
+
this._bufferDelete(key, mergeVersion);
|
|
5572
5831
|
}
|
|
5832
|
+
this.root.activeTransactions.delete(child);
|
|
5833
|
+
} else {
|
|
5834
|
+
const newVersion = this.version + 1;
|
|
5835
|
+
for (const [key, value] of this.writeBuffer) await this._diskWrite(key, value, newVersion);
|
|
5836
|
+
for (const key of this.deleteBuffer) await this._diskDelete(key, newVersion);
|
|
5837
|
+
this.version = newVersion;
|
|
5838
|
+
this._cleanupDeletedCache();
|
|
5573
5839
|
}
|
|
5574
|
-
for (const [key, value] of child.writeBuffer) {
|
|
5575
|
-
await this._diskWrite(key, value, newVersion);
|
|
5576
|
-
}
|
|
5577
|
-
for (const key of child.deleteBuffer) {
|
|
5578
|
-
await this._diskDelete(key, newVersion);
|
|
5579
|
-
}
|
|
5580
|
-
this.version = newVersion;
|
|
5581
|
-
this.root.activeTransactions.delete(child);
|
|
5582
|
-
this._cleanupDeletedCache();
|
|
5583
5840
|
return null;
|
|
5584
5841
|
}
|
|
5585
5842
|
});
|
|
5586
5843
|
}
|
|
5587
|
-
// --- Internal IO Helpers (Root Only) ---
|
|
5588
5844
|
async _diskWrite(key, value, version) {
|
|
5589
5845
|
const strategy = this.strategy;
|
|
5590
5846
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
5591
|
-
|
|
5592
|
-
|
|
5847
|
+
const rootAsAny = this.root;
|
|
5848
|
+
if (await this._diskExists(key, version)) {
|
|
5849
|
+
const currentVal = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : await strategy.read(key);
|
|
5593
5850
|
if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
|
|
5594
|
-
this.deletedCache.get(key).push({
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5851
|
+
this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: version });
|
|
5852
|
+
rootAsAny.diskCache.set(key, value);
|
|
5853
|
+
} else {
|
|
5854
|
+
rootAsAny.diskCache.set(key, value);
|
|
5598
5855
|
}
|
|
5599
5856
|
await strategy.write(key, value);
|
|
5600
5857
|
if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
|
|
@@ -5605,36 +5862,44 @@ var require_cjs = __commonJS({
|
|
|
5605
5862
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
5606
5863
|
const versions = this.versionIndex.get(key);
|
|
5607
5864
|
if (!versions) {
|
|
5608
|
-
|
|
5865
|
+
const rootAsAny = this.root;
|
|
5866
|
+
if (await this._diskExists(key, snapshotVersion)) {
|
|
5867
|
+
const val = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : await strategy.read(key);
|
|
5868
|
+
rootAsAny.diskCache.set(key, val);
|
|
5869
|
+
return val;
|
|
5870
|
+
}
|
|
5871
|
+
return null;
|
|
5609
5872
|
}
|
|
5610
5873
|
let targetVerObj = null;
|
|
5611
5874
|
let nextVerObj = null;
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
} else {
|
|
5616
|
-
nextVerObj = v;
|
|
5617
|
-
break;
|
|
5618
|
-
}
|
|
5619
|
-
}
|
|
5875
|
+
const idx = this._findLastLE(versions, snapshotVersion, "version");
|
|
5876
|
+
if (idx >= 0) targetVerObj = versions[idx];
|
|
5877
|
+
if (idx + 1 < versions.length) nextVerObj = versions[idx + 1];
|
|
5620
5878
|
if (!targetVerObj) {
|
|
5621
5879
|
if (nextVerObj) {
|
|
5622
5880
|
const cached2 = this.deletedCache.get(key);
|
|
5623
5881
|
if (cached2) {
|
|
5624
|
-
const
|
|
5625
|
-
if (
|
|
5882
|
+
const cIdx = this._findExact(cached2, nextVerObj.version, "deletedAtVersion");
|
|
5883
|
+
if (cIdx >= 0) return cached2[cIdx].value;
|
|
5626
5884
|
}
|
|
5627
5885
|
}
|
|
5628
5886
|
return null;
|
|
5629
5887
|
}
|
|
5630
5888
|
if (!targetVerObj.exists) return null;
|
|
5631
5889
|
if (!nextVerObj) {
|
|
5632
|
-
return
|
|
5890
|
+
if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
|
|
5891
|
+
if (await this._diskExists(key, snapshotVersion)) {
|
|
5892
|
+
const rootAsAny = this.root;
|
|
5893
|
+
const val = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : await strategy.read(key);
|
|
5894
|
+
rootAsAny.diskCache.set(key, val);
|
|
5895
|
+
return val;
|
|
5896
|
+
}
|
|
5897
|
+
return null;
|
|
5633
5898
|
}
|
|
5634
5899
|
const cached = this.deletedCache.get(key);
|
|
5635
5900
|
if (cached) {
|
|
5636
|
-
const
|
|
5637
|
-
if (
|
|
5901
|
+
const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
|
|
5902
|
+
if (cIdx >= 0) return cached[cIdx].value;
|
|
5638
5903
|
}
|
|
5639
5904
|
return null;
|
|
5640
5905
|
}
|
|
@@ -5643,31 +5908,40 @@ var require_cjs = __commonJS({
|
|
|
5643
5908
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
5644
5909
|
const versions = this.versionIndex.get(key);
|
|
5645
5910
|
if (!versions) {
|
|
5646
|
-
|
|
5911
|
+
const rootAsAny = this.root;
|
|
5912
|
+
if (rootAsAny.diskCache.has(key)) return rootAsAny.diskCache.get(key) !== null;
|
|
5913
|
+
const exists = await strategy.exists(key);
|
|
5914
|
+
if (!exists) rootAsAny.diskCache.set(key, null);
|
|
5915
|
+
return exists;
|
|
5647
5916
|
}
|
|
5648
5917
|
let targetVerObj = null;
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5918
|
+
let nextVerObj = null;
|
|
5919
|
+
const idx = this._findLastLE(versions, snapshotVersion, "version");
|
|
5920
|
+
if (idx >= 0) targetVerObj = versions[idx];
|
|
5921
|
+
if (idx + 1 < versions.length) nextVerObj = versions[idx + 1];
|
|
5922
|
+
if (!targetVerObj) {
|
|
5923
|
+
if (nextVerObj) {
|
|
5924
|
+
const cached = this.deletedCache.get(key);
|
|
5925
|
+
if (cached) {
|
|
5926
|
+
const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
|
|
5927
|
+
if (cIdx >= 0) return true;
|
|
5928
|
+
}
|
|
5654
5929
|
}
|
|
5930
|
+
return false;
|
|
5655
5931
|
}
|
|
5656
|
-
if (!targetVerObj) return strategy.exists(key);
|
|
5657
5932
|
return targetVerObj.exists;
|
|
5658
5933
|
}
|
|
5659
5934
|
async _diskDelete(key, snapshotVersion) {
|
|
5660
5935
|
const strategy = this.strategy;
|
|
5661
5936
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
5662
|
-
|
|
5663
|
-
|
|
5937
|
+
const rootAsAny = this.root;
|
|
5938
|
+
if (await this._diskExists(key, snapshotVersion)) {
|
|
5939
|
+
const currentVal = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : await strategy.read(key);
|
|
5664
5940
|
if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
|
|
5665
|
-
this.deletedCache.get(key).push({
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
});
|
|
5941
|
+
this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: snapshotVersion });
|
|
5942
|
+
await strategy.delete(key);
|
|
5943
|
+
rootAsAny.diskCache.delete(key);
|
|
5669
5944
|
}
|
|
5670
|
-
await strategy.delete(key);
|
|
5671
5945
|
if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
|
|
5672
5946
|
this.versionIndex.get(key).push({ version: snapshotVersion, exists: false });
|
|
5673
5947
|
}
|
|
@@ -7537,9 +7811,8 @@ var require_cjs = __commonJS({
|
|
|
7537
7811
|
}
|
|
7538
7812
|
};
|
|
7539
7813
|
var import_node_fs2 = __toESM2(require("node:fs"));
|
|
7540
|
-
var PageMVCCStrategy = class
|
|
7814
|
+
var PageMVCCStrategy = class {
|
|
7541
7815
|
constructor(fileHandle, pageSize, cacheCapacity) {
|
|
7542
|
-
super();
|
|
7543
7816
|
this.fileHandle = fileHandle;
|
|
7544
7817
|
this.pageSize = pageSize;
|
|
7545
7818
|
this.cache = new LRUMap2(cacheCapacity);
|
|
@@ -8336,7 +8609,6 @@ var require_cjs = __commonJS({
|
|
|
8336
8609
|
if (!btx) return;
|
|
8337
8610
|
const result = await btx.commit();
|
|
8338
8611
|
if (result.success) {
|
|
8339
|
-
await this.bptree.init();
|
|
8340
8612
|
for (const entry of result.deleted) {
|
|
8341
8613
|
await this.strategy.delete(entry.key);
|
|
8342
8614
|
}
|
|
@@ -9813,6 +10085,7 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
9813
10085
|
return 0;
|
|
9814
10086
|
}
|
|
9815
10087
|
const fieldTxMap = {};
|
|
10088
|
+
const fieldMap = /* @__PURE__ */ new Map();
|
|
9816
10089
|
for (const field of backfillTargets) {
|
|
9817
10090
|
const tree = this.trees.get(field);
|
|
9818
10091
|
if (tree && field !== "_id") {
|
|
@@ -9838,16 +10111,35 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
|
|
|
9838
10111
|
}
|
|
9839
10112
|
const v = flatDoc[field];
|
|
9840
10113
|
const btx = fieldTxMap[field];
|
|
9841
|
-
|
|
10114
|
+
const entry = { k, v };
|
|
10115
|
+
await btx.insert(k, entry);
|
|
10116
|
+
if (!fieldMap.has(btx)) {
|
|
10117
|
+
fieldMap.set(btx, []);
|
|
10118
|
+
}
|
|
10119
|
+
fieldMap.get(btx).push(entry);
|
|
9842
10120
|
}
|
|
9843
10121
|
backfilledCount++;
|
|
9844
10122
|
}
|
|
9845
|
-
const
|
|
9846
|
-
|
|
9847
|
-
|
|
9848
|
-
|
|
10123
|
+
const btxs = Object.values(fieldTxMap);
|
|
10124
|
+
const success = [];
|
|
10125
|
+
try {
|
|
10126
|
+
for (const btx of btxs) {
|
|
10127
|
+
await btx.commit();
|
|
10128
|
+
success.push(btx);
|
|
10129
|
+
}
|
|
10130
|
+
} catch (err) {
|
|
10131
|
+
for (const btx of btxs) {
|
|
10132
|
+
await btx.rollback();
|
|
10133
|
+
}
|
|
10134
|
+
for (const btx of success) {
|
|
10135
|
+
const entries = fieldMap.get(btx);
|
|
10136
|
+
if (!entries) continue;
|
|
10137
|
+
for (const entry of entries) {
|
|
10138
|
+
await btx.delete(entry.k, entry);
|
|
10139
|
+
}
|
|
10140
|
+
}
|
|
9849
10141
|
throw err;
|
|
9850
|
-
}
|
|
10142
|
+
}
|
|
9851
10143
|
this.pendingBackfillFields = [];
|
|
9852
10144
|
return backfilledCount;
|
|
9853
10145
|
}, tx);
|