dataply 0.0.22-alpha.0 → 0.0.22-alpha.3
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 +1137 -984
- package/package.json +3 -3
package/dist/cjs/index.js
CHANGED
|
@@ -38,7 +38,7 @@ __export(src_exports, {
|
|
|
38
38
|
BPTreeSyncTransaction: () => BPTreeSyncTransaction,
|
|
39
39
|
BitmapPageManager: () => BitmapPageManager,
|
|
40
40
|
CacheEntanglementAsync: () => CacheEntanglementAsync,
|
|
41
|
-
CacheEntanglementSync: () =>
|
|
41
|
+
CacheEntanglementSync: () => CacheEntanglementSync,
|
|
42
42
|
DataPageManager: () => DataPageManager,
|
|
43
43
|
Dataply: () => Dataply,
|
|
44
44
|
DataplyAPI: () => DataplyAPI,
|
|
@@ -125,6 +125,42 @@ var StringComparator = class extends ValueComparator {
|
|
|
125
125
|
};
|
|
126
126
|
var MVCCStrategy = class {
|
|
127
127
|
};
|
|
128
|
+
var LRUMap = class {
|
|
129
|
+
cache = /* @__PURE__ */ new Map();
|
|
130
|
+
capacity;
|
|
131
|
+
constructor(capacity) {
|
|
132
|
+
this.capacity = capacity;
|
|
133
|
+
}
|
|
134
|
+
get(key) {
|
|
135
|
+
if (!this.cache.has(key)) return void 0;
|
|
136
|
+
const value = this.cache.get(key);
|
|
137
|
+
this.cache.delete(key);
|
|
138
|
+
this.cache.set(key, value);
|
|
139
|
+
return value;
|
|
140
|
+
}
|
|
141
|
+
set(key, value) {
|
|
142
|
+
if (this.cache.has(key)) {
|
|
143
|
+
this.cache.delete(key);
|
|
144
|
+
} else if (this.cache.size >= this.capacity) {
|
|
145
|
+
const oldestKey = this.cache.keys().next().value;
|
|
146
|
+
if (oldestKey !== void 0) this.cache.delete(oldestKey);
|
|
147
|
+
}
|
|
148
|
+
this.cache.set(key, value);
|
|
149
|
+
return this;
|
|
150
|
+
}
|
|
151
|
+
has(key) {
|
|
152
|
+
return this.cache.has(key);
|
|
153
|
+
}
|
|
154
|
+
delete(key) {
|
|
155
|
+
return this.cache.delete(key);
|
|
156
|
+
}
|
|
157
|
+
clear() {
|
|
158
|
+
this.cache.clear();
|
|
159
|
+
}
|
|
160
|
+
get size() {
|
|
161
|
+
return this.cache.size;
|
|
162
|
+
}
|
|
163
|
+
};
|
|
128
164
|
var MVCCTransaction = class {
|
|
129
165
|
committed;
|
|
130
166
|
snapshotVersion;
|
|
@@ -132,7 +168,6 @@ var MVCCTransaction = class {
|
|
|
132
168
|
writeBuffer;
|
|
133
169
|
deleteBuffer;
|
|
134
170
|
createdKeys;
|
|
135
|
-
// create()로 생성된 키 추적
|
|
136
171
|
deletedValues;
|
|
137
172
|
// delete 시 삭제 전 값 저장
|
|
138
173
|
originallyExisted;
|
|
@@ -151,7 +186,8 @@ var MVCCTransaction = class {
|
|
|
151
186
|
versionIndex = /* @__PURE__ */ new Map();
|
|
152
187
|
deletedCache = /* @__PURE__ */ new Map();
|
|
153
188
|
activeTransactions = /* @__PURE__ */ new Set();
|
|
154
|
-
|
|
189
|
+
diskCache;
|
|
190
|
+
constructor(strategy, options, parent, snapshotVersion) {
|
|
155
191
|
this.snapshotVersion = snapshotVersion ?? 0;
|
|
156
192
|
this.writeBuffer = /* @__PURE__ */ new Map();
|
|
157
193
|
this.deleteBuffer = /* @__PURE__ */ new Set();
|
|
@@ -166,6 +202,7 @@ var MVCCTransaction = class {
|
|
|
166
202
|
this.snapshotLocalVersion = parent.localVersion;
|
|
167
203
|
this.strategy = void 0;
|
|
168
204
|
this.root = parent.root;
|
|
205
|
+
this.diskCache = parent.diskCache;
|
|
169
206
|
} else {
|
|
170
207
|
if (!strategy) throw new Error("Root Transaction must get Strategy");
|
|
171
208
|
this.strategy = strategy;
|
|
@@ -173,8 +210,13 @@ var MVCCTransaction = class {
|
|
|
173
210
|
this.localVersion = 0;
|
|
174
211
|
this.snapshotLocalVersion = 0;
|
|
175
212
|
this.root = this;
|
|
213
|
+
this.diskCache = new LRUMap(options?.cacheCapacity ?? 1e3);
|
|
176
214
|
}
|
|
177
215
|
}
|
|
216
|
+
/**
|
|
217
|
+
* Checks if the transaction is a root transaction.
|
|
218
|
+
* @returns True if the transaction is a root transaction, false otherwise.
|
|
219
|
+
*/
|
|
178
220
|
isRoot() {
|
|
179
221
|
return !this.parent;
|
|
180
222
|
}
|
|
@@ -191,7 +233,22 @@ var MVCCTransaction = class {
|
|
|
191
233
|
}
|
|
192
234
|
return false;
|
|
193
235
|
}
|
|
194
|
-
|
|
236
|
+
/**
|
|
237
|
+
* Checks if a key was written in this transaction.
|
|
238
|
+
* @param key The key to check.
|
|
239
|
+
* @returns True if the key was written in this transaction, false otherwise.
|
|
240
|
+
*/
|
|
241
|
+
isWrote(key) {
|
|
242
|
+
return this.writeBuffer.has(key);
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Checks if a key was deleted in this transaction.
|
|
246
|
+
* @param key The key to check.
|
|
247
|
+
* @returns True if the key was deleted in this transaction, false otherwise.
|
|
248
|
+
*/
|
|
249
|
+
isDeleted(key) {
|
|
250
|
+
return this.deleteBuffer.has(key);
|
|
251
|
+
}
|
|
195
252
|
_recordHistory(key) {
|
|
196
253
|
const existsInWriteBuffer = this.writeBuffer.has(key);
|
|
197
254
|
const existsInDeleteBuffer = this.deleteBuffer.has(key);
|
|
@@ -205,6 +262,41 @@ var MVCCTransaction = class {
|
|
|
205
262
|
});
|
|
206
263
|
}
|
|
207
264
|
}
|
|
265
|
+
/**
|
|
266
|
+
* BINARY SEARCH HELPER: Finds the index of the last element in the array
|
|
267
|
+
* where item[key] <= target. Assumes the array is sorted by 'key' ascending.
|
|
268
|
+
*/
|
|
269
|
+
_findLastLE(array, target, property) {
|
|
270
|
+
let left = 0;
|
|
271
|
+
let right = array.length - 1;
|
|
272
|
+
let result = -1;
|
|
273
|
+
while (left <= right) {
|
|
274
|
+
const mid = left + right >> 1;
|
|
275
|
+
if (array[mid][property] <= target) {
|
|
276
|
+
result = mid;
|
|
277
|
+
left = mid + 1;
|
|
278
|
+
} else {
|
|
279
|
+
right = mid - 1;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return result;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* BINARY SEARCH HELPER: Finds the index of the element in the array
|
|
286
|
+
* where item[key] === target. Assumes the array is sorted by 'key' ascending.
|
|
287
|
+
*/
|
|
288
|
+
_findExact(array, target, property) {
|
|
289
|
+
let left = 0;
|
|
290
|
+
let right = array.length - 1;
|
|
291
|
+
while (left <= right) {
|
|
292
|
+
const mid = left + right >> 1;
|
|
293
|
+
const val = array[mid][property];
|
|
294
|
+
if (val === target) return mid;
|
|
295
|
+
if (val < target) left = mid + 1;
|
|
296
|
+
else right = mid - 1;
|
|
297
|
+
}
|
|
298
|
+
return -1;
|
|
299
|
+
}
|
|
208
300
|
_bufferCreate(key, value, version) {
|
|
209
301
|
if (version === void 0) this.localVersion++;
|
|
210
302
|
const targetVersion = version ?? this.localVersion;
|
|
@@ -254,7 +346,11 @@ var MVCCTransaction = class {
|
|
|
254
346
|
deleted.push({ key, data });
|
|
255
347
|
}
|
|
256
348
|
}
|
|
257
|
-
return {
|
|
349
|
+
return {
|
|
350
|
+
created,
|
|
351
|
+
updated,
|
|
352
|
+
deleted
|
|
353
|
+
};
|
|
258
354
|
}
|
|
259
355
|
/**
|
|
260
356
|
* Rolls back the transaction.
|
|
@@ -272,7 +368,12 @@ var MVCCTransaction = class {
|
|
|
272
368
|
if (this.root !== this) {
|
|
273
369
|
this.root.activeTransactions.delete(this);
|
|
274
370
|
}
|
|
275
|
-
return {
|
|
371
|
+
return {
|
|
372
|
+
success: true,
|
|
373
|
+
created,
|
|
374
|
+
updated,
|
|
375
|
+
deleted
|
|
376
|
+
};
|
|
276
377
|
}
|
|
277
378
|
/**
|
|
278
379
|
* Cleans up both deletedCache and versionIndex based on minActiveVersion.
|
|
@@ -358,7 +459,7 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
358
459
|
createNested() {
|
|
359
460
|
if (this.committed) throw new Error("Transaction already committed");
|
|
360
461
|
const childVersion = this.isRoot() ? this.version : this.snapshotVersion;
|
|
361
|
-
const child = new _SyncMVCCTransaction(void 0, this, childVersion);
|
|
462
|
+
const child = new _SyncMVCCTransaction(void 0, void 0, this, childVersion);
|
|
362
463
|
this.root.activeTransactions.add(child);
|
|
363
464
|
return child;
|
|
364
465
|
}
|
|
@@ -381,78 +482,114 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
381
482
|
return this._diskExists(key, this.snapshotVersion);
|
|
382
483
|
}
|
|
383
484
|
_existsSnapshot(key, snapshotVersion, snapshotLocalVersion) {
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
return false;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
485
|
+
let current = this;
|
|
486
|
+
let slVer = snapshotLocalVersion;
|
|
487
|
+
while (current) {
|
|
488
|
+
if (current.writeBuffer.has(key)) {
|
|
489
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
490
|
+
if (slVer === void 0 || keyModVersion <= slVer) return true;
|
|
491
|
+
}
|
|
492
|
+
if (current.deleteBuffer.has(key)) {
|
|
493
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
494
|
+
if (slVer === void 0 || keyModVersion <= slVer) return false;
|
|
495
|
+
}
|
|
496
|
+
const history = current.bufferHistory.get(key);
|
|
497
|
+
if (history && slVer !== void 0) {
|
|
498
|
+
const idx = current._findLastLE(history, slVer, "version");
|
|
499
|
+
if (idx >= 0) return history[idx].exists;
|
|
500
|
+
}
|
|
501
|
+
if (current.parent) {
|
|
502
|
+
slVer = current.snapshotLocalVersion;
|
|
503
|
+
current = current.parent;
|
|
504
|
+
} else {
|
|
505
|
+
return current._diskExists(key, snapshotVersion);
|
|
402
506
|
}
|
|
403
507
|
}
|
|
404
|
-
|
|
405
|
-
return this.parent._existsSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
|
|
406
|
-
} else {
|
|
407
|
-
return this._diskExists(key, snapshotVersion);
|
|
408
|
-
}
|
|
508
|
+
return false;
|
|
409
509
|
}
|
|
410
510
|
_readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
511
|
+
let current = this;
|
|
512
|
+
let slVer = snapshotLocalVersion;
|
|
513
|
+
while (current) {
|
|
514
|
+
if (current.writeBuffer.has(key)) {
|
|
515
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
516
|
+
if (slVer === void 0 || keyModVersion <= slVer) {
|
|
517
|
+
return current.writeBuffer.get(key);
|
|
518
|
+
}
|
|
415
519
|
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
520
|
+
if (current.deleteBuffer.has(key)) {
|
|
521
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
522
|
+
if (slVer === void 0 || keyModVersion <= slVer) {
|
|
523
|
+
return null;
|
|
524
|
+
}
|
|
421
525
|
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
return history[i].exists ? history[i].value : null;
|
|
526
|
+
const history = current.bufferHistory.get(key);
|
|
527
|
+
if (history && slVer !== void 0) {
|
|
528
|
+
const idx = current._findLastLE(history, slVer, "version");
|
|
529
|
+
if (idx >= 0) {
|
|
530
|
+
return history[idx].exists ? history[idx].value : null;
|
|
428
531
|
}
|
|
429
532
|
}
|
|
533
|
+
if (current.parent) {
|
|
534
|
+
slVer = current.snapshotLocalVersion;
|
|
535
|
+
current = current.parent;
|
|
536
|
+
} else {
|
|
537
|
+
return current._diskRead(key, snapshotVersion);
|
|
538
|
+
}
|
|
430
539
|
}
|
|
431
|
-
|
|
432
|
-
return this.parent._readSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
|
|
433
|
-
} else {
|
|
434
|
-
return this._diskRead(key, snapshotVersion);
|
|
435
|
-
}
|
|
540
|
+
return null;
|
|
436
541
|
}
|
|
437
542
|
commit(label) {
|
|
438
543
|
const { created, updated, deleted } = this.getResultEntries();
|
|
439
544
|
if (this.committed) {
|
|
440
|
-
return {
|
|
545
|
+
return {
|
|
546
|
+
label,
|
|
547
|
+
success: false,
|
|
548
|
+
error: "Transaction already committed",
|
|
549
|
+
conflict: void 0,
|
|
550
|
+
created,
|
|
551
|
+
updated,
|
|
552
|
+
deleted
|
|
553
|
+
};
|
|
441
554
|
}
|
|
442
555
|
if (this.hasCommittedAncestor()) {
|
|
443
|
-
return {
|
|
556
|
+
return {
|
|
557
|
+
label,
|
|
558
|
+
success: false,
|
|
559
|
+
error: "Ancestor transaction already committed",
|
|
560
|
+
conflict: void 0,
|
|
561
|
+
created,
|
|
562
|
+
updated,
|
|
563
|
+
deleted
|
|
564
|
+
};
|
|
444
565
|
}
|
|
445
566
|
if (this.parent) {
|
|
446
567
|
const failure = this.parent._merge(this);
|
|
447
568
|
if (failure) {
|
|
448
|
-
return {
|
|
569
|
+
return {
|
|
570
|
+
label,
|
|
571
|
+
success: false,
|
|
572
|
+
error: failure.error,
|
|
573
|
+
conflict: failure.conflict,
|
|
574
|
+
created,
|
|
575
|
+
updated,
|
|
576
|
+
deleted
|
|
577
|
+
};
|
|
449
578
|
}
|
|
450
579
|
this.committed = true;
|
|
451
580
|
} else {
|
|
452
581
|
if (this.writeBuffer.size > 0 || this.deleteBuffer.size > 0) {
|
|
453
582
|
const failure = this._merge(this);
|
|
454
583
|
if (failure) {
|
|
455
|
-
return {
|
|
584
|
+
return {
|
|
585
|
+
label,
|
|
586
|
+
success: false,
|
|
587
|
+
error: failure.error,
|
|
588
|
+
conflict: failure.conflict,
|
|
589
|
+
created: [],
|
|
590
|
+
updated: [],
|
|
591
|
+
deleted: []
|
|
592
|
+
};
|
|
456
593
|
}
|
|
457
594
|
this.writeBuffer.clear();
|
|
458
595
|
this.deleteBuffer.clear();
|
|
@@ -465,7 +602,13 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
465
602
|
this.snapshotVersion = this.version;
|
|
466
603
|
}
|
|
467
604
|
}
|
|
468
|
-
return {
|
|
605
|
+
return {
|
|
606
|
+
label,
|
|
607
|
+
success: true,
|
|
608
|
+
created,
|
|
609
|
+
updated,
|
|
610
|
+
deleted
|
|
611
|
+
};
|
|
469
612
|
}
|
|
470
613
|
_merge(child) {
|
|
471
614
|
if (this.parent) {
|
|
@@ -474,7 +617,11 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
474
617
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
475
618
|
return {
|
|
476
619
|
error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
|
|
477
|
-
conflict: {
|
|
620
|
+
conflict: {
|
|
621
|
+
key,
|
|
622
|
+
parent: this.read(key),
|
|
623
|
+
child: child.read(key)
|
|
624
|
+
}
|
|
478
625
|
};
|
|
479
626
|
}
|
|
480
627
|
}
|
|
@@ -483,7 +630,11 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
483
630
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
484
631
|
return {
|
|
485
632
|
error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
|
|
486
|
-
conflict: {
|
|
633
|
+
conflict: {
|
|
634
|
+
key,
|
|
635
|
+
parent: this.read(key),
|
|
636
|
+
child: child.read(key)
|
|
637
|
+
}
|
|
487
638
|
};
|
|
488
639
|
}
|
|
489
640
|
}
|
|
@@ -512,7 +663,11 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
512
663
|
if (lastVer > child.snapshotVersion) {
|
|
513
664
|
return {
|
|
514
665
|
error: `Commit conflict: Key '${key}' was modified by a newer transaction (v${lastVer})`,
|
|
515
|
-
conflict: {
|
|
666
|
+
conflict: {
|
|
667
|
+
key,
|
|
668
|
+
parent: this.read(key),
|
|
669
|
+
child: child.read(key)
|
|
670
|
+
}
|
|
516
671
|
};
|
|
517
672
|
}
|
|
518
673
|
}
|
|
@@ -520,7 +675,11 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
520
675
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
521
676
|
return {
|
|
522
677
|
error: `Commit conflict: Key '${key}' was modified by a newer transaction in the same session (Local v${lastModLocalVer})`,
|
|
523
|
-
conflict: {
|
|
678
|
+
conflict: {
|
|
679
|
+
key,
|
|
680
|
+
parent: this.read(key),
|
|
681
|
+
child: child.read(key)
|
|
682
|
+
}
|
|
524
683
|
};
|
|
525
684
|
}
|
|
526
685
|
}
|
|
@@ -555,10 +714,14 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
555
714
|
_diskWrite(key, value, version) {
|
|
556
715
|
const strategy = this.strategy;
|
|
557
716
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
558
|
-
|
|
559
|
-
|
|
717
|
+
const rootAsAny = this.root;
|
|
718
|
+
if (this._diskExists(key, version)) {
|
|
719
|
+
const currentVal = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : strategy.read(key);
|
|
560
720
|
if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
|
|
561
721
|
this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: version });
|
|
722
|
+
rootAsAny.diskCache.set(key, value);
|
|
723
|
+
} else {
|
|
724
|
+
rootAsAny.diskCache.set(key, value);
|
|
562
725
|
}
|
|
563
726
|
strategy.write(key, value);
|
|
564
727
|
if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
|
|
@@ -569,23 +732,25 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
569
732
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
570
733
|
const versions = this.versionIndex.get(key);
|
|
571
734
|
if (!versions) {
|
|
572
|
-
|
|
735
|
+
const rootAsAny = this.root;
|
|
736
|
+
if (this._diskExists(key, snapshotVersion)) {
|
|
737
|
+
const val = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : strategy.read(key);
|
|
738
|
+
rootAsAny.diskCache.set(key, val);
|
|
739
|
+
return val;
|
|
740
|
+
}
|
|
741
|
+
return null;
|
|
573
742
|
}
|
|
574
743
|
let targetVerObj = null;
|
|
575
744
|
let nextVerObj = null;
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
nextVerObj = v;
|
|
580
|
-
break;
|
|
581
|
-
}
|
|
582
|
-
}
|
|
745
|
+
const idx = this._findLastLE(versions, snapshotVersion, "version");
|
|
746
|
+
if (idx >= 0) targetVerObj = versions[idx];
|
|
747
|
+
if (idx + 1 < versions.length) nextVerObj = versions[idx + 1];
|
|
583
748
|
if (!targetVerObj) {
|
|
584
749
|
if (nextVerObj) {
|
|
585
750
|
const cached2 = this.deletedCache.get(key);
|
|
586
751
|
if (cached2) {
|
|
587
|
-
const
|
|
588
|
-
if (
|
|
752
|
+
const cIdx = this._findExact(cached2, nextVerObj.version, "deletedAtVersion");
|
|
753
|
+
if (cIdx >= 0) return cached2[cIdx].value;
|
|
589
754
|
}
|
|
590
755
|
}
|
|
591
756
|
return null;
|
|
@@ -593,12 +758,18 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
593
758
|
if (!targetVerObj.exists) return null;
|
|
594
759
|
if (!nextVerObj) {
|
|
595
760
|
if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
|
|
596
|
-
|
|
761
|
+
if (this._diskExists(key, snapshotVersion)) {
|
|
762
|
+
const rootAsAny = this.root;
|
|
763
|
+
const val = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : strategy.read(key);
|
|
764
|
+
rootAsAny.diskCache.set(key, val);
|
|
765
|
+
return val;
|
|
766
|
+
}
|
|
767
|
+
return null;
|
|
597
768
|
}
|
|
598
769
|
const cached = this.deletedCache.get(key);
|
|
599
770
|
if (cached) {
|
|
600
|
-
const
|
|
601
|
-
if (
|
|
771
|
+
const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
|
|
772
|
+
if (cIdx >= 0) return cached[cIdx].value;
|
|
602
773
|
}
|
|
603
774
|
return null;
|
|
604
775
|
}
|
|
@@ -607,23 +778,23 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
607
778
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
608
779
|
const versions = this.versionIndex.get(key);
|
|
609
780
|
if (!versions) {
|
|
610
|
-
|
|
781
|
+
const rootAsAny = this.root;
|
|
782
|
+
if (rootAsAny.diskCache.has(key)) return rootAsAny.diskCache.get(key) !== null;
|
|
783
|
+
const exists = strategy.exists(key);
|
|
784
|
+
if (!exists) rootAsAny.diskCache.set(key, null);
|
|
785
|
+
return exists;
|
|
611
786
|
}
|
|
612
787
|
let targetVerObj = null;
|
|
613
788
|
let nextVerObj = null;
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
nextVerObj = v;
|
|
618
|
-
break;
|
|
619
|
-
}
|
|
620
|
-
}
|
|
789
|
+
const idx = this._findLastLE(versions, snapshotVersion, "version");
|
|
790
|
+
if (idx >= 0) targetVerObj = versions[idx];
|
|
791
|
+
if (idx + 1 < versions.length) nextVerObj = versions[idx + 1];
|
|
621
792
|
if (!targetVerObj) {
|
|
622
793
|
if (nextVerObj) {
|
|
623
794
|
const cached = this.deletedCache.get(key);
|
|
624
795
|
if (cached) {
|
|
625
|
-
const
|
|
626
|
-
if (
|
|
796
|
+
const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
|
|
797
|
+
if (cIdx >= 0) return true;
|
|
627
798
|
}
|
|
628
799
|
}
|
|
629
800
|
return false;
|
|
@@ -633,11 +804,13 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
633
804
|
_diskDelete(key, snapshotVersion) {
|
|
634
805
|
const strategy = this.strategy;
|
|
635
806
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
636
|
-
|
|
637
|
-
|
|
807
|
+
const rootAsAny = this.root;
|
|
808
|
+
if (this._diskExists(key, snapshotVersion)) {
|
|
809
|
+
const currentVal = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : strategy.read(key);
|
|
638
810
|
if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
|
|
639
811
|
this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: snapshotVersion });
|
|
640
812
|
strategy.delete(key);
|
|
813
|
+
rootAsAny.diskCache.delete(key);
|
|
641
814
|
}
|
|
642
815
|
if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
|
|
643
816
|
this.versionIndex.get(key).push({ version: snapshotVersion, exists: false });
|
|
@@ -951,7 +1124,7 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
951
1124
|
createNested() {
|
|
952
1125
|
if (this.committed) throw new Error("Transaction already committed");
|
|
953
1126
|
const childVersion = this.isRoot() ? this.version : this.snapshotVersion;
|
|
954
|
-
const child = new _AsyncMVCCTransaction(void 0, this, childVersion);
|
|
1127
|
+
const child = new _AsyncMVCCTransaction(void 0, void 0, this, childVersion);
|
|
955
1128
|
this.root.activeTransactions.add(child);
|
|
956
1129
|
return child;
|
|
957
1130
|
}
|
|
@@ -974,78 +1147,114 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
974
1147
|
return await this._diskExists(key, this.snapshotVersion);
|
|
975
1148
|
}
|
|
976
1149
|
async _existsSnapshot(key, snapshotVersion, snapshotLocalVersion) {
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
return false;
|
|
987
|
-
}
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
1150
|
+
let current = this;
|
|
1151
|
+
let slVer = snapshotLocalVersion;
|
|
1152
|
+
while (current) {
|
|
1153
|
+
if (current.writeBuffer.has(key)) {
|
|
1154
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
1155
|
+
if (slVer === void 0 || keyModVersion <= slVer) return true;
|
|
1156
|
+
}
|
|
1157
|
+
if (current.deleteBuffer.has(key)) {
|
|
1158
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
1159
|
+
if (slVer === void 0 || keyModVersion <= slVer) return false;
|
|
1160
|
+
}
|
|
1161
|
+
const history = current.bufferHistory.get(key);
|
|
1162
|
+
if (history && slVer !== void 0) {
|
|
1163
|
+
const idx = current._findLastLE(history, slVer, "version");
|
|
1164
|
+
if (idx >= 0) return history[idx].exists;
|
|
1165
|
+
}
|
|
1166
|
+
if (current.parent) {
|
|
1167
|
+
slVer = current.snapshotLocalVersion;
|
|
1168
|
+
current = current.parent;
|
|
1169
|
+
} else {
|
|
1170
|
+
return await current._diskExists(key, snapshotVersion);
|
|
995
1171
|
}
|
|
996
1172
|
}
|
|
997
|
-
|
|
998
|
-
return this.parent._existsSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
|
|
999
|
-
} else {
|
|
1000
|
-
return await this._diskExists(key, snapshotVersion);
|
|
1001
|
-
}
|
|
1173
|
+
return false;
|
|
1002
1174
|
}
|
|
1003
1175
|
async _readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1176
|
+
let current = this;
|
|
1177
|
+
let slVer = snapshotLocalVersion;
|
|
1178
|
+
while (current) {
|
|
1179
|
+
if (current.writeBuffer.has(key)) {
|
|
1180
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
1181
|
+
if (slVer === void 0 || keyModVersion <= slVer) {
|
|
1182
|
+
return current.writeBuffer.get(key);
|
|
1183
|
+
}
|
|
1008
1184
|
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1185
|
+
if (current.deleteBuffer.has(key)) {
|
|
1186
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
1187
|
+
if (slVer === void 0 || keyModVersion <= slVer) {
|
|
1188
|
+
return null;
|
|
1189
|
+
}
|
|
1014
1190
|
}
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
return history[i].exists ? history[i].value : null;
|
|
1191
|
+
const history = current.bufferHistory.get(key);
|
|
1192
|
+
if (history && slVer !== void 0) {
|
|
1193
|
+
const idx = current._findLastLE(history, slVer, "version");
|
|
1194
|
+
if (idx >= 0) {
|
|
1195
|
+
return history[idx].exists ? history[idx].value : null;
|
|
1021
1196
|
}
|
|
1022
1197
|
}
|
|
1198
|
+
if (current.parent) {
|
|
1199
|
+
slVer = current.snapshotLocalVersion;
|
|
1200
|
+
current = current.parent;
|
|
1201
|
+
} else {
|
|
1202
|
+
return await current._diskRead(key, snapshotVersion);
|
|
1203
|
+
}
|
|
1023
1204
|
}
|
|
1024
|
-
|
|
1025
|
-
return this.parent._readSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
|
|
1026
|
-
} else {
|
|
1027
|
-
return await this._diskRead(key, snapshotVersion);
|
|
1028
|
-
}
|
|
1205
|
+
return null;
|
|
1029
1206
|
}
|
|
1030
1207
|
async commit(label) {
|
|
1031
1208
|
const { created, updated, deleted } = this.getResultEntries();
|
|
1032
1209
|
if (this.committed) {
|
|
1033
|
-
return {
|
|
1210
|
+
return {
|
|
1211
|
+
label,
|
|
1212
|
+
success: false,
|
|
1213
|
+
error: "Transaction already committed",
|
|
1214
|
+
conflict: void 0,
|
|
1215
|
+
created,
|
|
1216
|
+
updated,
|
|
1217
|
+
deleted
|
|
1218
|
+
};
|
|
1034
1219
|
}
|
|
1035
1220
|
if (this.hasCommittedAncestor()) {
|
|
1036
|
-
return {
|
|
1221
|
+
return {
|
|
1222
|
+
label,
|
|
1223
|
+
success: false,
|
|
1224
|
+
error: "Ancestor transaction already committed",
|
|
1225
|
+
conflict: void 0,
|
|
1226
|
+
created,
|
|
1227
|
+
updated,
|
|
1228
|
+
deleted
|
|
1229
|
+
};
|
|
1037
1230
|
}
|
|
1038
1231
|
if (this.parent) {
|
|
1039
1232
|
const failure = await this.parent._merge(this);
|
|
1040
1233
|
if (failure) {
|
|
1041
|
-
return {
|
|
1234
|
+
return {
|
|
1235
|
+
label,
|
|
1236
|
+
success: false,
|
|
1237
|
+
error: failure.error,
|
|
1238
|
+
conflict: failure.conflict,
|
|
1239
|
+
created,
|
|
1240
|
+
updated,
|
|
1241
|
+
deleted
|
|
1242
|
+
};
|
|
1042
1243
|
}
|
|
1043
1244
|
this.committed = true;
|
|
1044
1245
|
} else {
|
|
1045
1246
|
if (this.writeBuffer.size > 0 || this.deleteBuffer.size > 0) {
|
|
1046
1247
|
const failure = await this._merge(this);
|
|
1047
1248
|
if (failure) {
|
|
1048
|
-
return {
|
|
1249
|
+
return {
|
|
1250
|
+
label,
|
|
1251
|
+
success: false,
|
|
1252
|
+
error: failure.error,
|
|
1253
|
+
conflict: failure.conflict,
|
|
1254
|
+
created: [],
|
|
1255
|
+
updated: [],
|
|
1256
|
+
deleted: []
|
|
1257
|
+
};
|
|
1049
1258
|
}
|
|
1050
1259
|
this.writeBuffer.clear();
|
|
1051
1260
|
this.deleteBuffer.clear();
|
|
@@ -1058,7 +1267,13 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
1058
1267
|
this.snapshotVersion = this.version;
|
|
1059
1268
|
}
|
|
1060
1269
|
}
|
|
1061
|
-
return {
|
|
1270
|
+
return {
|
|
1271
|
+
label,
|
|
1272
|
+
success: true,
|
|
1273
|
+
created,
|
|
1274
|
+
updated,
|
|
1275
|
+
deleted
|
|
1276
|
+
};
|
|
1062
1277
|
}
|
|
1063
1278
|
async _merge(child) {
|
|
1064
1279
|
return this.writeLock(async () => {
|
|
@@ -1068,7 +1283,11 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
1068
1283
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
1069
1284
|
return {
|
|
1070
1285
|
error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
|
|
1071
|
-
conflict: {
|
|
1286
|
+
conflict: {
|
|
1287
|
+
key,
|
|
1288
|
+
parent: await this.read(key),
|
|
1289
|
+
child: await child.read(key)
|
|
1290
|
+
}
|
|
1072
1291
|
};
|
|
1073
1292
|
}
|
|
1074
1293
|
}
|
|
@@ -1077,7 +1296,11 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
1077
1296
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
1078
1297
|
return {
|
|
1079
1298
|
error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
|
|
1080
|
-
conflict: {
|
|
1299
|
+
conflict: {
|
|
1300
|
+
key,
|
|
1301
|
+
parent: await this.read(key),
|
|
1302
|
+
child: await child.read(key)
|
|
1303
|
+
}
|
|
1081
1304
|
};
|
|
1082
1305
|
}
|
|
1083
1306
|
}
|
|
@@ -1107,7 +1330,11 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
1107
1330
|
if (lastVer > child.snapshotVersion) {
|
|
1108
1331
|
return {
|
|
1109
1332
|
error: `Commit conflict: Key '${key}' was modified by a newer transaction (v${lastVer})`,
|
|
1110
|
-
conflict: {
|
|
1333
|
+
conflict: {
|
|
1334
|
+
key,
|
|
1335
|
+
parent: await this.read(key),
|
|
1336
|
+
child: await child.read(key)
|
|
1337
|
+
}
|
|
1111
1338
|
};
|
|
1112
1339
|
}
|
|
1113
1340
|
}
|
|
@@ -1115,7 +1342,11 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
1115
1342
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
1116
1343
|
return {
|
|
1117
1344
|
error: `Commit conflict: Key '${key}' was modified by a newer transaction in the same session (Local v${lastModLocalVer})`,
|
|
1118
|
-
conflict: {
|
|
1345
|
+
conflict: {
|
|
1346
|
+
key,
|
|
1347
|
+
parent: await this.read(key),
|
|
1348
|
+
child: await child.read(key)
|
|
1349
|
+
}
|
|
1119
1350
|
};
|
|
1120
1351
|
}
|
|
1121
1352
|
}
|
|
@@ -1151,10 +1382,14 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
1151
1382
|
async _diskWrite(key, value, version) {
|
|
1152
1383
|
const strategy = this.strategy;
|
|
1153
1384
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
1154
|
-
|
|
1155
|
-
|
|
1385
|
+
const rootAsAny = this.root;
|
|
1386
|
+
if (await this._diskExists(key, version)) {
|
|
1387
|
+
const currentVal = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : await strategy.read(key);
|
|
1156
1388
|
if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
|
|
1157
1389
|
this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: version });
|
|
1390
|
+
rootAsAny.diskCache.set(key, value);
|
|
1391
|
+
} else {
|
|
1392
|
+
rootAsAny.diskCache.set(key, value);
|
|
1158
1393
|
}
|
|
1159
1394
|
await strategy.write(key, value);
|
|
1160
1395
|
if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
|
|
@@ -1165,23 +1400,25 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
1165
1400
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
1166
1401
|
const versions = this.versionIndex.get(key);
|
|
1167
1402
|
if (!versions) {
|
|
1168
|
-
|
|
1403
|
+
const rootAsAny = this.root;
|
|
1404
|
+
if (await this._diskExists(key, snapshotVersion)) {
|
|
1405
|
+
const val = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : await strategy.read(key);
|
|
1406
|
+
rootAsAny.diskCache.set(key, val);
|
|
1407
|
+
return val;
|
|
1408
|
+
}
|
|
1409
|
+
return null;
|
|
1169
1410
|
}
|
|
1170
1411
|
let targetVerObj = null;
|
|
1171
1412
|
let nextVerObj = null;
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
nextVerObj = v;
|
|
1176
|
-
break;
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1413
|
+
const idx = this._findLastLE(versions, snapshotVersion, "version");
|
|
1414
|
+
if (idx >= 0) targetVerObj = versions[idx];
|
|
1415
|
+
if (idx + 1 < versions.length) nextVerObj = versions[idx + 1];
|
|
1179
1416
|
if (!targetVerObj) {
|
|
1180
1417
|
if (nextVerObj) {
|
|
1181
1418
|
const cached2 = this.deletedCache.get(key);
|
|
1182
1419
|
if (cached2) {
|
|
1183
|
-
const
|
|
1184
|
-
if (
|
|
1420
|
+
const cIdx = this._findExact(cached2, nextVerObj.version, "deletedAtVersion");
|
|
1421
|
+
if (cIdx >= 0) return cached2[cIdx].value;
|
|
1185
1422
|
}
|
|
1186
1423
|
}
|
|
1187
1424
|
return null;
|
|
@@ -1189,12 +1426,18 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
1189
1426
|
if (!targetVerObj.exists) return null;
|
|
1190
1427
|
if (!nextVerObj) {
|
|
1191
1428
|
if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
|
|
1192
|
-
|
|
1429
|
+
if (await this._diskExists(key, snapshotVersion)) {
|
|
1430
|
+
const rootAsAny = this.root;
|
|
1431
|
+
const val = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : await strategy.read(key);
|
|
1432
|
+
rootAsAny.diskCache.set(key, val);
|
|
1433
|
+
return val;
|
|
1434
|
+
}
|
|
1435
|
+
return null;
|
|
1193
1436
|
}
|
|
1194
1437
|
const cached = this.deletedCache.get(key);
|
|
1195
1438
|
if (cached) {
|
|
1196
|
-
const
|
|
1197
|
-
if (
|
|
1439
|
+
const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
|
|
1440
|
+
if (cIdx >= 0) return cached[cIdx].value;
|
|
1198
1441
|
}
|
|
1199
1442
|
return null;
|
|
1200
1443
|
}
|
|
@@ -1202,367 +1445,48 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
1202
1445
|
const strategy = this.strategy;
|
|
1203
1446
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
1204
1447
|
const versions = this.versionIndex.get(key);
|
|
1205
|
-
if (!versions) {
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
if (v.version <= snapshotVersion) targetVerObj = v;
|
|
1212
|
-
else {
|
|
1213
|
-
nextVerObj = v;
|
|
1214
|
-
break;
|
|
1215
|
-
}
|
|
1216
|
-
}
|
|
1217
|
-
if (!targetVerObj) {
|
|
1218
|
-
if (nextVerObj) {
|
|
1219
|
-
const cached = this.deletedCache.get(key);
|
|
1220
|
-
if (cached) {
|
|
1221
|
-
const match = cached.find((c) => c.deletedAtVersion === nextVerObj.version);
|
|
1222
|
-
if (match) return true;
|
|
1223
|
-
}
|
|
1224
|
-
}
|
|
1225
|
-
return false;
|
|
1226
|
-
}
|
|
1227
|
-
return targetVerObj.exists;
|
|
1228
|
-
}
|
|
1229
|
-
async _diskDelete(key, snapshotVersion) {
|
|
1230
|
-
const strategy = this.strategy;
|
|
1231
|
-
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
1232
|
-
if (await strategy.exists(key)) {
|
|
1233
|
-
const currentVal = await strategy.read(key);
|
|
1234
|
-
if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
|
|
1235
|
-
this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: snapshotVersion });
|
|
1236
|
-
await strategy.delete(key);
|
|
1237
|
-
}
|
|
1238
|
-
if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
|
|
1239
|
-
this.versionIndex.get(key).push({ version: snapshotVersion, exists: false });
|
|
1240
|
-
}
|
|
1241
|
-
};
|
|
1242
|
-
var LRUMap = class {
|
|
1243
|
-
capacity;
|
|
1244
|
-
map;
|
|
1245
|
-
head = null;
|
|
1246
|
-
tail = null;
|
|
1247
|
-
/**
|
|
1248
|
-
* Creates an instance of LRUMap.
|
|
1249
|
-
* @param capacity The maximum number of items the cache can hold.
|
|
1250
|
-
*/
|
|
1251
|
-
constructor(capacity) {
|
|
1252
|
-
this.capacity = capacity;
|
|
1253
|
-
this.map = /* @__PURE__ */ new Map();
|
|
1254
|
-
}
|
|
1255
|
-
/**
|
|
1256
|
-
* Promotes a node to the head of the linked list (marks as most recently used).
|
|
1257
|
-
* @param node The node to promote.
|
|
1258
|
-
*/
|
|
1259
|
-
promote(node) {
|
|
1260
|
-
this.extract(node);
|
|
1261
|
-
this.prepend(node);
|
|
1262
|
-
}
|
|
1263
|
-
/**
|
|
1264
|
-
* Disconnects a node from the doubly linked list.
|
|
1265
|
-
* @param node The node to extract.
|
|
1266
|
-
*/
|
|
1267
|
-
extract(node) {
|
|
1268
|
-
if (node.prev) node.prev.next = node.next;
|
|
1269
|
-
else this.head = node.next;
|
|
1270
|
-
if (node.next) node.next.prev = node.prev;
|
|
1271
|
-
else this.tail = node.prev;
|
|
1272
|
-
node.prev = null;
|
|
1273
|
-
node.next = null;
|
|
1274
|
-
}
|
|
1275
|
-
/**
|
|
1276
|
-
* Inserts a node at the head of the doubly linked list.
|
|
1277
|
-
* @param node The node to prepend.
|
|
1278
|
-
*/
|
|
1279
|
-
prepend(node) {
|
|
1280
|
-
node.next = this.head;
|
|
1281
|
-
if (this.head) this.head.prev = node;
|
|
1282
|
-
this.head = node;
|
|
1283
|
-
if (!this.tail) this.tail = node;
|
|
1284
|
-
}
|
|
1285
|
-
/**
|
|
1286
|
-
* Stores or updates a value by key.
|
|
1287
|
-
* If the capacity is exceeded, the least recently used item (tail) is removed.
|
|
1288
|
-
* @param key The key to store.
|
|
1289
|
-
* @param value The value to store.
|
|
1290
|
-
*/
|
|
1291
|
-
set(key, value) {
|
|
1292
|
-
const existing = this.map.get(key);
|
|
1293
|
-
if (existing) {
|
|
1294
|
-
existing.value = value;
|
|
1295
|
-
this.promote(existing);
|
|
1296
|
-
return;
|
|
1297
|
-
}
|
|
1298
|
-
const newNode = { key, value, prev: null, next: null };
|
|
1299
|
-
this.map.set(key, newNode);
|
|
1300
|
-
this.prepend(newNode);
|
|
1301
|
-
if (this.map.size > this.capacity && this.tail) {
|
|
1302
|
-
this.map.delete(this.tail.key);
|
|
1303
|
-
this.extract(this.tail);
|
|
1304
|
-
}
|
|
1305
|
-
}
|
|
1306
|
-
/**
|
|
1307
|
-
* Retrieves a value by key.
|
|
1308
|
-
* Accessing the item moves it to the "most recently used" position.
|
|
1309
|
-
* @param key The key to look for.
|
|
1310
|
-
* @returns The value associated with the key, or undefined if not found.
|
|
1311
|
-
*/
|
|
1312
|
-
get(key) {
|
|
1313
|
-
const node = this.map.get(key);
|
|
1314
|
-
if (!node) return void 0;
|
|
1315
|
-
this.promote(node);
|
|
1316
|
-
return node.value;
|
|
1317
|
-
}
|
|
1318
|
-
/**
|
|
1319
|
-
* Checks if a key exists in the cache without changing its access order.
|
|
1320
|
-
* @param key The key to check.
|
|
1321
|
-
* @returns True if the key exists, false otherwise.
|
|
1322
|
-
*/
|
|
1323
|
-
has(key) {
|
|
1324
|
-
return this.map.has(key);
|
|
1325
|
-
}
|
|
1326
|
-
/**
|
|
1327
|
-
* Removes a key and its associated value from the cache.
|
|
1328
|
-
* @param key The key to remove.
|
|
1329
|
-
* @returns True if the key was found and removed, false otherwise.
|
|
1330
|
-
*/
|
|
1331
|
-
delete(key) {
|
|
1332
|
-
const node = this.map.get(key);
|
|
1333
|
-
if (!node) return false;
|
|
1334
|
-
this.extract(node);
|
|
1335
|
-
this.map.delete(key);
|
|
1336
|
-
return true;
|
|
1337
|
-
}
|
|
1338
|
-
/**
|
|
1339
|
-
* Returns an iterator of keys in the order of most recently used to least recently used.
|
|
1340
|
-
* @returns An iterable iterator of keys.
|
|
1341
|
-
*/
|
|
1342
|
-
*keys() {
|
|
1343
|
-
let current = this.head;
|
|
1344
|
-
while (current) {
|
|
1345
|
-
yield current.key;
|
|
1346
|
-
current = current.next;
|
|
1347
|
-
}
|
|
1348
|
-
}
|
|
1349
|
-
/**
|
|
1350
|
-
* Returns the current number of items in the cache.
|
|
1351
|
-
*/
|
|
1352
|
-
get size() {
|
|
1353
|
-
return this.map.size;
|
|
1354
|
-
}
|
|
1355
|
-
/**
|
|
1356
|
-
* Clears all items from the cache.
|
|
1357
|
-
*/
|
|
1358
|
-
clear() {
|
|
1359
|
-
this.map.clear();
|
|
1360
|
-
this.head = null;
|
|
1361
|
-
this.tail = null;
|
|
1362
|
-
}
|
|
1363
|
-
};
|
|
1364
|
-
var CacheEntanglement = class {
|
|
1365
|
-
creation;
|
|
1366
|
-
beforeUpdateHook;
|
|
1367
|
-
capacity;
|
|
1368
|
-
dependencies;
|
|
1369
|
-
caches;
|
|
1370
|
-
parameters;
|
|
1371
|
-
assignments;
|
|
1372
|
-
dependencyProperties;
|
|
1373
|
-
updateRequirements;
|
|
1374
|
-
constructor(creation, option) {
|
|
1375
|
-
option = option ?? {};
|
|
1376
|
-
const {
|
|
1377
|
-
dependencies,
|
|
1378
|
-
capacity,
|
|
1379
|
-
beforeUpdateHook
|
|
1380
|
-
} = option;
|
|
1381
|
-
this.creation = creation;
|
|
1382
|
-
this.beforeUpdateHook = beforeUpdateHook ?? (() => {
|
|
1383
|
-
});
|
|
1384
|
-
this.capacity = capacity ?? 100;
|
|
1385
|
-
this.assignments = [];
|
|
1386
|
-
this.caches = new LRUMap(this.capacity);
|
|
1387
|
-
this.parameters = /* @__PURE__ */ new Map();
|
|
1388
|
-
this.dependencies = dependencies ?? {};
|
|
1389
|
-
this.dependencyProperties = Object.keys(this.dependencies);
|
|
1390
|
-
this.updateRequirements = /* @__PURE__ */ new Set();
|
|
1391
|
-
for (const name in this.dependencies) {
|
|
1392
|
-
const dependency = this.dependencies[name];
|
|
1393
|
-
if (!dependency.assignments.includes(this)) {
|
|
1394
|
-
dependency.assignments.push(this);
|
|
1395
|
-
}
|
|
1396
|
-
}
|
|
1397
|
-
}
|
|
1398
|
-
bubbleUpdateSignal(key) {
|
|
1399
|
-
this.updateRequirements.add(key);
|
|
1400
|
-
for (let i = 0, len = this.assignments.length; i < len; i++) {
|
|
1401
|
-
const t = this.assignments[i];
|
|
1402
|
-
const instance = t;
|
|
1403
|
-
for (const cacheKey of instance.caches.keys()) {
|
|
1404
|
-
if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
|
|
1405
|
-
instance.bubbleUpdateSignal(cacheKey);
|
|
1406
|
-
}
|
|
1407
|
-
}
|
|
1408
|
-
}
|
|
1409
|
-
}
|
|
1410
|
-
dependencyKey(key) {
|
|
1411
|
-
const i = key.lastIndexOf("/");
|
|
1412
|
-
if (i === -1) {
|
|
1413
|
-
return key;
|
|
1414
|
-
}
|
|
1415
|
-
return key.substring(0, i);
|
|
1416
|
-
}
|
|
1417
|
-
/**
|
|
1418
|
-
* Returns all keys stored in the instance.
|
|
1419
|
-
*/
|
|
1420
|
-
keys() {
|
|
1421
|
-
return this.parameters.keys();
|
|
1422
|
-
}
|
|
1423
|
-
/**
|
|
1424
|
-
* Deletes all cache values stored in the instance.
|
|
1425
|
-
*/
|
|
1426
|
-
clear() {
|
|
1427
|
-
for (const key of this.keys()) {
|
|
1428
|
-
this.delete(key);
|
|
1429
|
-
}
|
|
1430
|
-
}
|
|
1431
|
-
/**
|
|
1432
|
-
* Checks if there is a cache value stored in the key within the instance.
|
|
1433
|
-
* @param key The key to search.
|
|
1434
|
-
*/
|
|
1435
|
-
exists(key) {
|
|
1436
|
-
return this.parameters.has(key);
|
|
1437
|
-
}
|
|
1438
|
-
/**
|
|
1439
|
-
* Checks if there is a cache value stored in the key within the instance.
|
|
1440
|
-
* This method is an alias for `exists`.
|
|
1441
|
-
* @param key The key to search.
|
|
1442
|
-
*/
|
|
1443
|
-
has(key) {
|
|
1444
|
-
return this.exists(key);
|
|
1445
|
-
}
|
|
1446
|
-
/**
|
|
1447
|
-
* Deletes the cache value stored in the key within the instance.
|
|
1448
|
-
* @param key The key to delete.
|
|
1449
|
-
*/
|
|
1450
|
-
delete(key) {
|
|
1451
|
-
this.caches.delete(key);
|
|
1452
|
-
this.parameters.delete(key);
|
|
1453
|
-
this.updateRequirements.delete(key);
|
|
1454
|
-
for (let i = 0, len = this.assignments.length; i < len; i++) {
|
|
1455
|
-
const t = this.assignments[i];
|
|
1456
|
-
const instance = t;
|
|
1457
|
-
for (const cacheKey of instance.keys()) {
|
|
1458
|
-
if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
|
|
1459
|
-
instance.delete(cacheKey);
|
|
1460
|
-
}
|
|
1461
|
-
}
|
|
1462
|
-
}
|
|
1463
|
-
}
|
|
1464
|
-
};
|
|
1465
|
-
var CacheData = class _CacheData {
|
|
1466
|
-
static StructuredClone = globalThis.structuredClone.bind(globalThis);
|
|
1467
|
-
_value;
|
|
1468
|
-
constructor(value) {
|
|
1469
|
-
this._value = value;
|
|
1470
|
-
}
|
|
1471
|
-
/**
|
|
1472
|
-
* This is cached data.
|
|
1473
|
-
* It was generated at the time of caching, so there is a risk of modification if it's an object due to shallow copying.
|
|
1474
|
-
* 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.
|
|
1475
|
-
*/
|
|
1476
|
-
get raw() {
|
|
1477
|
-
return this._value;
|
|
1478
|
-
}
|
|
1479
|
-
/**
|
|
1480
|
-
* The method returns a copied value of the cached data.
|
|
1481
|
-
* You can pass a function as a parameter to copy the value. This parameter function should return the copied value.
|
|
1482
|
-
*
|
|
1483
|
-
* If no parameter is passed, it defaults to using `structuredClone` function to copy the value.
|
|
1484
|
-
* If you prefer shallow copying instead of deep copying,
|
|
1485
|
-
* you can use the default options `array-shallow-copy`, `object-shallow-copy` and `deep-copy`,
|
|
1486
|
-
* which are replaced with functions to shallow copy arrays and objects, respectively. This is a syntactic sugar.
|
|
1487
|
-
* @param strategy The function that returns the copied value.
|
|
1488
|
-
* If you want to perform a shallow copy, simply pass the strings `array-shallow-copy` or `object-shallow-copy` for easy use.
|
|
1489
|
-
* The `array-shallow-copy` strategy performs a shallow copy of an array.
|
|
1490
|
-
* The `object-shallow-copy` strategy performs a shallow copy of an object.
|
|
1491
|
-
* The `deep-copy` strategy performs a deep copy of the value using `structuredClone`.
|
|
1492
|
-
* The default is `deep-copy`.
|
|
1493
|
-
*/
|
|
1494
|
-
clone(strategy = "deep-copy") {
|
|
1495
|
-
if (strategy && typeof strategy !== "string") {
|
|
1496
|
-
return strategy(this.raw);
|
|
1497
|
-
}
|
|
1498
|
-
switch (strategy) {
|
|
1499
|
-
case "array-shallow-copy":
|
|
1500
|
-
return [].concat(this.raw);
|
|
1501
|
-
case "object-shallow-copy":
|
|
1502
|
-
return Object.assign({}, this.raw);
|
|
1503
|
-
case "deep-copy":
|
|
1504
|
-
default:
|
|
1505
|
-
return _CacheData.StructuredClone(this.raw);
|
|
1506
|
-
}
|
|
1507
|
-
}
|
|
1508
|
-
};
|
|
1509
|
-
var CacheEntanglementSync = class extends CacheEntanglement {
|
|
1510
|
-
constructor(creation, option) {
|
|
1511
|
-
super(creation, option);
|
|
1512
|
-
}
|
|
1513
|
-
recache(key) {
|
|
1514
|
-
if (!this.parameters.has(key)) {
|
|
1515
|
-
return;
|
|
1516
|
-
}
|
|
1517
|
-
if (!this.caches.has(key) || this.updateRequirements.has(key)) {
|
|
1518
|
-
this.resolve(key, ...this.parameters.get(key));
|
|
1519
|
-
}
|
|
1520
|
-
return this.caches.get(key);
|
|
1521
|
-
}
|
|
1522
|
-
resolve(key, ...parameter) {
|
|
1523
|
-
const resolved = {};
|
|
1524
|
-
const dependencyKey = this.dependencyKey(key);
|
|
1525
|
-
this.beforeUpdateHook(key, dependencyKey, ...parameter);
|
|
1526
|
-
for (let i = 0, len = this.dependencyProperties.length; i < len; i++) {
|
|
1527
|
-
const name = this.dependencyProperties[i];
|
|
1528
|
-
const dependency = this.dependencies[name];
|
|
1529
|
-
if (!dependency.exists(key) && !dependency.exists(dependencyKey)) {
|
|
1530
|
-
throw new Error(`The key '${key}' or '${dependencyKey}' has not been assigned yet in dependency '${name.toString()}'.`, {
|
|
1531
|
-
cause: {
|
|
1532
|
-
from: this
|
|
1533
|
-
}
|
|
1534
|
-
});
|
|
1535
|
-
}
|
|
1536
|
-
const dependencyValue = dependency.recache(key) ?? dependency.recache(dependencyKey);
|
|
1537
|
-
resolved[name] = dependencyValue;
|
|
1538
|
-
}
|
|
1539
|
-
const value = new CacheData(this.creation(key, resolved, ...parameter));
|
|
1540
|
-
this.updateRequirements.delete(key);
|
|
1541
|
-
this.parameters.set(key, parameter);
|
|
1542
|
-
this.caches.set(key, value);
|
|
1543
|
-
return value;
|
|
1544
|
-
}
|
|
1545
|
-
get(key) {
|
|
1546
|
-
if (!this.parameters.has(key)) {
|
|
1547
|
-
throw new Error(`Cache value not found: ${key}`);
|
|
1448
|
+
if (!versions) {
|
|
1449
|
+
const rootAsAny = this.root;
|
|
1450
|
+
if (rootAsAny.diskCache.has(key)) return rootAsAny.diskCache.get(key) !== null;
|
|
1451
|
+
const exists = await strategy.exists(key);
|
|
1452
|
+
if (!exists) rootAsAny.diskCache.set(key, null);
|
|
1453
|
+
return exists;
|
|
1548
1454
|
}
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
if (
|
|
1553
|
-
|
|
1455
|
+
let targetVerObj = null;
|
|
1456
|
+
let nextVerObj = null;
|
|
1457
|
+
const idx = this._findLastLE(versions, snapshotVersion, "version");
|
|
1458
|
+
if (idx >= 0) targetVerObj = versions[idx];
|
|
1459
|
+
if (idx + 1 < versions.length) nextVerObj = versions[idx + 1];
|
|
1460
|
+
if (!targetVerObj) {
|
|
1461
|
+
if (nextVerObj) {
|
|
1462
|
+
const cached = this.deletedCache.get(key);
|
|
1463
|
+
if (cached) {
|
|
1464
|
+
const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
|
|
1465
|
+
if (cIdx >= 0) return true;
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
return false;
|
|
1554
1469
|
}
|
|
1555
|
-
return
|
|
1470
|
+
return targetVerObj.exists;
|
|
1556
1471
|
}
|
|
1557
|
-
|
|
1558
|
-
this.
|
|
1559
|
-
|
|
1560
|
-
|
|
1472
|
+
async _diskDelete(key, snapshotVersion) {
|
|
1473
|
+
const strategy = this.strategy;
|
|
1474
|
+
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
1475
|
+
const rootAsAny = this.root;
|
|
1476
|
+
if (await this._diskExists(key, snapshotVersion)) {
|
|
1477
|
+
const currentVal = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : await strategy.read(key);
|
|
1478
|
+
if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
|
|
1479
|
+
this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: snapshotVersion });
|
|
1480
|
+
await strategy.delete(key);
|
|
1481
|
+
rootAsAny.diskCache.delete(key);
|
|
1482
|
+
}
|
|
1483
|
+
if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
|
|
1484
|
+
this.versionIndex.get(key).push({ version: snapshotVersion, exists: false });
|
|
1561
1485
|
}
|
|
1562
1486
|
};
|
|
1563
1487
|
var BPTreeTransaction = class _BPTreeTransaction {
|
|
1564
|
-
_cachedRegexp;
|
|
1565
|
-
nodes;
|
|
1488
|
+
_cachedRegexp = /* @__PURE__ */ new Map();
|
|
1489
|
+
nodes = /* @__PURE__ */ new Map();
|
|
1566
1490
|
deletedNodeBuffer = /* @__PURE__ */ new Map();
|
|
1567
1491
|
rootTx;
|
|
1568
1492
|
mvccRoot;
|
|
@@ -1592,8 +1516,12 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1592
1516
|
like: (nv, v) => {
|
|
1593
1517
|
const nodeValue = this.comparator.match(nv);
|
|
1594
1518
|
const value = v;
|
|
1595
|
-
|
|
1596
|
-
|
|
1519
|
+
if (!this._cachedRegexp.has(value)) {
|
|
1520
|
+
const pattern = value.replace(/%/g, ".*").replace(/_/g, ".");
|
|
1521
|
+
const regexp2 = new RegExp(`^${pattern}$`, "i");
|
|
1522
|
+
this._cachedRegexp.set(value, regexp2);
|
|
1523
|
+
}
|
|
1524
|
+
const regexp = this._cachedRegexp.get(value);
|
|
1597
1525
|
return regexp.test(nodeValue);
|
|
1598
1526
|
}
|
|
1599
1527
|
};
|
|
@@ -1765,6 +1693,9 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1765
1693
|
}
|
|
1766
1694
|
return true;
|
|
1767
1695
|
}
|
|
1696
|
+
_cloneNode(node) {
|
|
1697
|
+
return JSON.parse(JSON.stringify(node));
|
|
1698
|
+
}
|
|
1768
1699
|
/**
|
|
1769
1700
|
* Selects the best driver key from a condition object.
|
|
1770
1701
|
* The driver key determines the starting point and traversal direction for queries.
|
|
@@ -1797,17 +1728,6 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1797
1728
|
this.strategy = strategy;
|
|
1798
1729
|
this.comparator = comparator;
|
|
1799
1730
|
this.option = option ?? {};
|
|
1800
|
-
this.nodes = new LRUMap(this.option.capacity ?? 1e3);
|
|
1801
|
-
this._cachedRegexp = this._createCachedRegexp();
|
|
1802
|
-
}
|
|
1803
|
-
_createCachedRegexp() {
|
|
1804
|
-
return new CacheEntanglementSync((key) => {
|
|
1805
|
-
const pattern = key.replace(/%/g, ".*").replace(/_/g, ".");
|
|
1806
|
-
const regexp = new RegExp(`^${pattern}$`, "i");
|
|
1807
|
-
return regexp;
|
|
1808
|
-
}, {
|
|
1809
|
-
capacity: this.option.capacity ?? 1e3
|
|
1810
|
-
});
|
|
1811
1731
|
}
|
|
1812
1732
|
ensureValues(v) {
|
|
1813
1733
|
if (!Array.isArray(v)) {
|
|
@@ -1840,7 +1760,6 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1840
1760
|
}
|
|
1841
1761
|
_clearCache() {
|
|
1842
1762
|
this._cachedRegexp.clear();
|
|
1843
|
-
this.nodes.clear();
|
|
1844
1763
|
}
|
|
1845
1764
|
/**
|
|
1846
1765
|
* Clears all cached nodes.
|
|
@@ -1891,9 +1810,6 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
1891
1810
|
);
|
|
1892
1811
|
}
|
|
1893
1812
|
getNode(id) {
|
|
1894
|
-
if (this.nodes.has(id)) {
|
|
1895
|
-
return this.nodes.get(id);
|
|
1896
|
-
}
|
|
1897
1813
|
return this.mvcc.read(id);
|
|
1898
1814
|
}
|
|
1899
1815
|
/**
|
|
@@ -1911,23 +1827,22 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
1911
1827
|
prev
|
|
1912
1828
|
};
|
|
1913
1829
|
this.mvcc.create(id, node);
|
|
1914
|
-
this.nodes.set(id, node);
|
|
1915
1830
|
return node;
|
|
1916
1831
|
}
|
|
1917
1832
|
_updateNode(node) {
|
|
1833
|
+
if (this.mvcc.isDeleted(node.id)) {
|
|
1834
|
+
return;
|
|
1835
|
+
}
|
|
1918
1836
|
this.mvcc.write(node.id, node);
|
|
1919
|
-
this.nodes.set(node.id, node);
|
|
1920
1837
|
}
|
|
1921
1838
|
_deleteNode(node) {
|
|
1839
|
+
if (this.mvcc.isDeleted(node.id)) {
|
|
1840
|
+
return;
|
|
1841
|
+
}
|
|
1922
1842
|
this.mvcc.delete(node.id);
|
|
1923
|
-
this.nodes.delete(node.id);
|
|
1924
1843
|
}
|
|
1925
1844
|
_readHead() {
|
|
1926
|
-
|
|
1927
|
-
return this.nodes.get("__HEAD__") ?? null;
|
|
1928
|
-
}
|
|
1929
|
-
const head = this.mvcc.read("__HEAD__");
|
|
1930
|
-
return head ?? null;
|
|
1845
|
+
return this.mvcc.read("__HEAD__");
|
|
1931
1846
|
}
|
|
1932
1847
|
_writeHead(head) {
|
|
1933
1848
|
if (!this.mvcc.exists("__HEAD__")) {
|
|
@@ -1935,49 +1850,56 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
1935
1850
|
} else {
|
|
1936
1851
|
this.mvcc.write("__HEAD__", head);
|
|
1937
1852
|
}
|
|
1938
|
-
this.nodes.set("__HEAD__", head);
|
|
1939
1853
|
this.rootId = head.root;
|
|
1940
1854
|
}
|
|
1941
1855
|
_insertAtLeaf(node, key, value) {
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1856
|
+
let leaf = node;
|
|
1857
|
+
if (leaf.values.length) {
|
|
1858
|
+
for (let i = 0, len = leaf.values.length; i < len; i++) {
|
|
1859
|
+
const nValue = leaf.values[i];
|
|
1945
1860
|
if (this.comparator.isSame(value, nValue)) {
|
|
1946
|
-
const keys =
|
|
1861
|
+
const keys = leaf.keys[i];
|
|
1947
1862
|
if (keys.includes(key)) {
|
|
1948
1863
|
break;
|
|
1949
1864
|
}
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1865
|
+
leaf = this._cloneNode(leaf);
|
|
1866
|
+
leaf.keys[i].push(key);
|
|
1867
|
+
this._updateNode(leaf);
|
|
1868
|
+
return leaf;
|
|
1953
1869
|
} else if (this.comparator.isLower(value, nValue)) {
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1870
|
+
leaf = this._cloneNode(leaf);
|
|
1871
|
+
leaf.values.splice(i, 0, value);
|
|
1872
|
+
leaf.keys.splice(i, 0, [key]);
|
|
1873
|
+
this._updateNode(leaf);
|
|
1874
|
+
return leaf;
|
|
1875
|
+
} else if (i + 1 === leaf.values.length) {
|
|
1876
|
+
leaf = this._cloneNode(leaf);
|
|
1877
|
+
leaf.values.push(value);
|
|
1878
|
+
leaf.keys.push([key]);
|
|
1879
|
+
this._updateNode(leaf);
|
|
1880
|
+
return leaf;
|
|
1963
1881
|
}
|
|
1964
1882
|
}
|
|
1965
1883
|
} else {
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1884
|
+
leaf = this._cloneNode(leaf);
|
|
1885
|
+
leaf.values = [value];
|
|
1886
|
+
leaf.keys = [[key]];
|
|
1887
|
+
this._updateNode(leaf);
|
|
1888
|
+
return leaf;
|
|
1970
1889
|
}
|
|
1890
|
+
return leaf;
|
|
1971
1891
|
}
|
|
1972
|
-
_insertInParent(node, value,
|
|
1892
|
+
_insertInParent(node, value, newSiblingNode) {
|
|
1973
1893
|
if (this.rootId === node.id) {
|
|
1974
|
-
|
|
1894
|
+
node = this._cloneNode(node);
|
|
1895
|
+
newSiblingNode = this._cloneNode(newSiblingNode);
|
|
1896
|
+
const root = this._createNode(false, [node.id, newSiblingNode.id], [value]);
|
|
1975
1897
|
this.rootId = root.id;
|
|
1976
1898
|
node.parent = root.id;
|
|
1977
|
-
|
|
1978
|
-
if (
|
|
1979
|
-
node.next =
|
|
1980
|
-
|
|
1899
|
+
newSiblingNode.parent = root.id;
|
|
1900
|
+
if (newSiblingNode.leaf) {
|
|
1901
|
+
node.next = newSiblingNode.id;
|
|
1902
|
+
newSiblingNode.prev = node.id;
|
|
1981
1903
|
}
|
|
1982
1904
|
this._writeHead({
|
|
1983
1905
|
root: root.id,
|
|
@@ -1985,53 +1907,54 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
1985
1907
|
data: this.strategy.head.data
|
|
1986
1908
|
});
|
|
1987
1909
|
this._updateNode(node);
|
|
1988
|
-
this._updateNode(
|
|
1910
|
+
this._updateNode(newSiblingNode);
|
|
1989
1911
|
return;
|
|
1990
1912
|
}
|
|
1991
|
-
const parentNode = this.getNode(node.parent);
|
|
1913
|
+
const parentNode = this._cloneNode(this.getNode(node.parent));
|
|
1992
1914
|
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
1993
1915
|
if (nodeIndex === -1) {
|
|
1994
1916
|
throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
|
|
1995
1917
|
}
|
|
1996
1918
|
parentNode.values.splice(nodeIndex, 0, value);
|
|
1997
|
-
parentNode.keys.splice(nodeIndex + 1, 0,
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
1919
|
+
parentNode.keys.splice(nodeIndex + 1, 0, newSiblingNode.id);
|
|
1920
|
+
newSiblingNode = this._cloneNode(newSiblingNode);
|
|
1921
|
+
newSiblingNode.parent = parentNode.id;
|
|
1922
|
+
if (newSiblingNode.leaf) {
|
|
1923
|
+
const leftSibling = this._cloneNode(node);
|
|
2001
1924
|
const oldNextId = leftSibling.next;
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
leftSibling.next =
|
|
1925
|
+
newSiblingNode.prev = leftSibling.id;
|
|
1926
|
+
newSiblingNode.next = oldNextId;
|
|
1927
|
+
leftSibling.next = newSiblingNode.id;
|
|
2005
1928
|
this._updateNode(leftSibling);
|
|
2006
1929
|
if (oldNextId) {
|
|
2007
|
-
const oldNext = this.getNode(oldNextId);
|
|
2008
|
-
oldNext.prev =
|
|
1930
|
+
const oldNext = this._cloneNode(this.getNode(oldNextId));
|
|
1931
|
+
oldNext.prev = newSiblingNode.id;
|
|
2009
1932
|
this._updateNode(oldNext);
|
|
2010
1933
|
}
|
|
2011
1934
|
}
|
|
2012
1935
|
this._updateNode(parentNode);
|
|
2013
|
-
this._updateNode(
|
|
1936
|
+
this._updateNode(newSiblingNode);
|
|
2014
1937
|
if (parentNode.keys.length > this.order) {
|
|
2015
|
-
const
|
|
2016
|
-
|
|
1938
|
+
const newSiblingNodeRecursive = this._createNode(false, [], []);
|
|
1939
|
+
newSiblingNodeRecursive.parent = parentNode.parent;
|
|
2017
1940
|
const mid = Math.ceil(this.order / 2) - 1;
|
|
2018
|
-
|
|
2019
|
-
|
|
1941
|
+
newSiblingNodeRecursive.values = parentNode.values.slice(mid + 1);
|
|
1942
|
+
newSiblingNodeRecursive.keys = parentNode.keys.slice(mid + 1);
|
|
2020
1943
|
const midValue = parentNode.values[mid];
|
|
2021
1944
|
parentNode.values = parentNode.values.slice(0, mid);
|
|
2022
1945
|
parentNode.keys = parentNode.keys.slice(0, mid + 1);
|
|
2023
1946
|
for (const k of parentNode.keys) {
|
|
2024
|
-
const n = this.getNode(k);
|
|
1947
|
+
const n = this._cloneNode(this.getNode(k));
|
|
2025
1948
|
n.parent = parentNode.id;
|
|
2026
1949
|
this._updateNode(n);
|
|
2027
1950
|
}
|
|
2028
|
-
for (const k of
|
|
2029
|
-
const n = this.getNode(k);
|
|
2030
|
-
n.parent =
|
|
1951
|
+
for (const k of newSiblingNodeRecursive.keys) {
|
|
1952
|
+
const n = this._cloneNode(this.getNode(k));
|
|
1953
|
+
n.parent = newSiblingNodeRecursive.id;
|
|
2031
1954
|
this._updateNode(n);
|
|
2032
1955
|
}
|
|
2033
1956
|
this._updateNode(parentNode);
|
|
2034
|
-
this._insertInParent(parentNode, midValue,
|
|
1957
|
+
this._insertInParent(parentNode, midValue, newSiblingNodeRecursive);
|
|
2035
1958
|
}
|
|
2036
1959
|
}
|
|
2037
1960
|
insertableNode(value) {
|
|
@@ -2214,21 +2137,6 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2214
2137
|
}
|
|
2215
2138
|
return false;
|
|
2216
2139
|
}
|
|
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
2140
|
get(key) {
|
|
2233
2141
|
let node = this.leftestNode();
|
|
2234
2142
|
while (true) {
|
|
@@ -2314,10 +2222,10 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2314
2222
|
return map;
|
|
2315
2223
|
}
|
|
2316
2224
|
insert(key, value) {
|
|
2317
|
-
|
|
2318
|
-
this._insertAtLeaf(before, key, value);
|
|
2225
|
+
let before = this.insertableNode(value);
|
|
2226
|
+
before = this._insertAtLeaf(before, key, value);
|
|
2319
2227
|
if (before.values.length === this.order) {
|
|
2320
|
-
|
|
2228
|
+
let after = this._createNode(
|
|
2321
2229
|
true,
|
|
2322
2230
|
[],
|
|
2323
2231
|
[],
|
|
@@ -2326,10 +2234,13 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2326
2234
|
null
|
|
2327
2235
|
);
|
|
2328
2236
|
const mid = Math.ceil(this.order / 2) - 1;
|
|
2237
|
+
after = this._cloneNode(after);
|
|
2329
2238
|
after.values = before.values.slice(mid + 1);
|
|
2330
2239
|
after.keys = before.keys.slice(mid + 1);
|
|
2331
2240
|
before.values = before.values.slice(0, mid + 1);
|
|
2332
2241
|
before.keys = before.keys.slice(0, mid + 1);
|
|
2242
|
+
this._updateNode(before);
|
|
2243
|
+
this._updateNode(after);
|
|
2333
2244
|
this._insertInParent(before, after.values[0], after);
|
|
2334
2245
|
}
|
|
2335
2246
|
}
|
|
@@ -2343,6 +2254,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2343
2254
|
}
|
|
2344
2255
|
}
|
|
2345
2256
|
if (keyIndex !== -1) {
|
|
2257
|
+
node = this._cloneNode(node);
|
|
2346
2258
|
node.keys.splice(keyIndex, 1);
|
|
2347
2259
|
const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
|
|
2348
2260
|
node.values.splice(valueIndex, 1);
|
|
@@ -2352,7 +2264,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2352
2264
|
if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
|
|
2353
2265
|
const keys = node.keys;
|
|
2354
2266
|
this._deleteNode(node);
|
|
2355
|
-
const newRoot = this.getNode(keys[0]);
|
|
2267
|
+
const newRoot = this._cloneNode(this.getNode(keys[0]));
|
|
2356
2268
|
newRoot.parent = null;
|
|
2357
2269
|
this._updateNode(newRoot);
|
|
2358
2270
|
this._writeHead({
|
|
@@ -2360,17 +2272,17 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2360
2272
|
order: this.order,
|
|
2361
2273
|
data: this.strategy.head.data
|
|
2362
2274
|
});
|
|
2363
|
-
return;
|
|
2275
|
+
return node;
|
|
2364
2276
|
} else if (this.rootId === node.id) {
|
|
2365
2277
|
this._writeHead({
|
|
2366
2278
|
root: node.id,
|
|
2367
2279
|
order: this.order,
|
|
2368
2280
|
data: this.strategy.head.data
|
|
2369
2281
|
});
|
|
2370
|
-
return;
|
|
2282
|
+
return node;
|
|
2371
2283
|
} else if (node.keys.length < Math.ceil(this.order / 2) && !node.leaf || node.values.length < Math.ceil((this.order - 1) / 2) && node.leaf) {
|
|
2372
2284
|
if (node.parent === null) {
|
|
2373
|
-
return;
|
|
2285
|
+
return node;
|
|
2374
2286
|
}
|
|
2375
2287
|
let isPredecessor = false;
|
|
2376
2288
|
let parentNode = this.getNode(node.parent);
|
|
@@ -2391,78 +2303,80 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2391
2303
|
}
|
|
2392
2304
|
}
|
|
2393
2305
|
}
|
|
2394
|
-
let
|
|
2306
|
+
let siblingNode;
|
|
2395
2307
|
let guess;
|
|
2396
2308
|
if (prevNode === null) {
|
|
2397
|
-
|
|
2309
|
+
siblingNode = nextNode;
|
|
2398
2310
|
guess = postValue;
|
|
2399
2311
|
} else if (nextNode === null) {
|
|
2400
2312
|
isPredecessor = true;
|
|
2401
|
-
|
|
2313
|
+
siblingNode = prevNode;
|
|
2402
2314
|
guess = prevValue;
|
|
2403
2315
|
} else {
|
|
2404
2316
|
if (node.values.length + nextNode.values.length < this.order) {
|
|
2405
|
-
|
|
2317
|
+
siblingNode = nextNode;
|
|
2406
2318
|
guess = postValue;
|
|
2407
2319
|
} else {
|
|
2408
2320
|
isPredecessor = true;
|
|
2409
|
-
|
|
2321
|
+
siblingNode = prevNode;
|
|
2410
2322
|
guess = prevValue;
|
|
2411
2323
|
}
|
|
2412
2324
|
}
|
|
2413
|
-
if (!
|
|
2414
|
-
return;
|
|
2325
|
+
if (!siblingNode) {
|
|
2326
|
+
return node;
|
|
2415
2327
|
}
|
|
2416
|
-
|
|
2328
|
+
node = this._cloneNode(node);
|
|
2329
|
+
siblingNode = this._cloneNode(siblingNode);
|
|
2330
|
+
if (node.values.length + siblingNode.values.length < this.order) {
|
|
2417
2331
|
if (!isPredecessor) {
|
|
2418
|
-
const pTemp =
|
|
2419
|
-
|
|
2332
|
+
const pTemp = siblingNode;
|
|
2333
|
+
siblingNode = node;
|
|
2420
2334
|
node = pTemp;
|
|
2421
2335
|
}
|
|
2422
|
-
|
|
2336
|
+
siblingNode.keys.push(...node.keys);
|
|
2423
2337
|
if (!node.leaf) {
|
|
2424
|
-
|
|
2338
|
+
siblingNode.values.push(guess);
|
|
2425
2339
|
} else {
|
|
2426
|
-
|
|
2427
|
-
if (
|
|
2428
|
-
const n = this.getNode(
|
|
2429
|
-
n.prev =
|
|
2340
|
+
siblingNode.next = node.next;
|
|
2341
|
+
if (siblingNode.next) {
|
|
2342
|
+
const n = this._cloneNode(this.getNode(siblingNode.next));
|
|
2343
|
+
n.prev = siblingNode.id;
|
|
2430
2344
|
this._updateNode(n);
|
|
2431
2345
|
}
|
|
2432
2346
|
}
|
|
2433
|
-
|
|
2434
|
-
if (!
|
|
2435
|
-
const keys =
|
|
2347
|
+
siblingNode.values.push(...node.values);
|
|
2348
|
+
if (!siblingNode.leaf) {
|
|
2349
|
+
const keys = siblingNode.keys;
|
|
2436
2350
|
for (const key2 of keys) {
|
|
2437
|
-
const node2 = this.getNode(key2);
|
|
2438
|
-
node2.parent =
|
|
2351
|
+
const node2 = this._cloneNode(this.getNode(key2));
|
|
2352
|
+
node2.parent = siblingNode.id;
|
|
2439
2353
|
this._updateNode(node2);
|
|
2440
2354
|
}
|
|
2441
2355
|
}
|
|
2442
2356
|
this._deleteNode(node);
|
|
2443
|
-
this._updateNode(
|
|
2357
|
+
this._updateNode(siblingNode);
|
|
2444
2358
|
this._deleteEntry(this.getNode(node.parent), node.id);
|
|
2445
2359
|
} else {
|
|
2446
2360
|
if (isPredecessor) {
|
|
2447
2361
|
let pointerPm;
|
|
2448
2362
|
let pointerKm;
|
|
2449
2363
|
if (!node.leaf) {
|
|
2450
|
-
pointerPm =
|
|
2451
|
-
pointerKm =
|
|
2364
|
+
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
2365
|
+
pointerKm = siblingNode.values.splice(-1)[0];
|
|
2452
2366
|
node.keys = [pointerPm, ...node.keys];
|
|
2453
2367
|
node.values = [guess, ...node.values];
|
|
2454
|
-
parentNode = this.getNode(node.parent);
|
|
2368
|
+
parentNode = this._cloneNode(this.getNode(node.parent));
|
|
2455
2369
|
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
2456
2370
|
if (nodeIndex > 0) {
|
|
2457
2371
|
parentNode.values[nodeIndex - 1] = pointerKm;
|
|
2458
2372
|
this._updateNode(parentNode);
|
|
2459
2373
|
}
|
|
2460
2374
|
} else {
|
|
2461
|
-
pointerPm =
|
|
2462
|
-
pointerKm =
|
|
2375
|
+
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
2376
|
+
pointerKm = siblingNode.values.splice(-1)[0];
|
|
2463
2377
|
node.keys = [pointerPm, ...node.keys];
|
|
2464
2378
|
node.values = [pointerKm, ...node.values];
|
|
2465
|
-
parentNode = this.getNode(node.parent);
|
|
2379
|
+
parentNode = this._cloneNode(this.getNode(node.parent));
|
|
2466
2380
|
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
2467
2381
|
if (nodeIndex > 0) {
|
|
2468
2382
|
parentNode.values[nodeIndex - 1] = pointerKm;
|
|
@@ -2470,61 +2384,62 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2470
2384
|
}
|
|
2471
2385
|
}
|
|
2472
2386
|
this._updateNode(node);
|
|
2473
|
-
this._updateNode(
|
|
2387
|
+
this._updateNode(siblingNode);
|
|
2474
2388
|
} else {
|
|
2475
2389
|
let pointerP0;
|
|
2476
2390
|
let pointerK0;
|
|
2477
2391
|
if (!node.leaf) {
|
|
2478
|
-
pointerP0 =
|
|
2479
|
-
pointerK0 =
|
|
2392
|
+
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
2393
|
+
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
2480
2394
|
node.keys = [...node.keys, pointerP0];
|
|
2481
2395
|
node.values = [...node.values, guess];
|
|
2482
|
-
parentNode = this.getNode(node.parent);
|
|
2483
|
-
const pointerIndex = parentNode.keys.indexOf(
|
|
2396
|
+
parentNode = this._cloneNode(this.getNode(node.parent));
|
|
2397
|
+
const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
|
|
2484
2398
|
if (pointerIndex > 0) {
|
|
2485
2399
|
parentNode.values[pointerIndex - 1] = pointerK0;
|
|
2486
2400
|
this._updateNode(parentNode);
|
|
2487
2401
|
}
|
|
2488
2402
|
} else {
|
|
2489
|
-
pointerP0 =
|
|
2490
|
-
pointerK0 =
|
|
2403
|
+
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
2404
|
+
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
2491
2405
|
node.keys = [...node.keys, pointerP0];
|
|
2492
2406
|
node.values = [...node.values, pointerK0];
|
|
2493
|
-
parentNode = this.getNode(node.parent);
|
|
2494
|
-
const pointerIndex = parentNode.keys.indexOf(
|
|
2407
|
+
parentNode = this._cloneNode(this.getNode(node.parent));
|
|
2408
|
+
const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
|
|
2495
2409
|
if (pointerIndex > 0) {
|
|
2496
|
-
parentNode.values[pointerIndex - 1] =
|
|
2410
|
+
parentNode.values[pointerIndex - 1] = siblingNode.values[0];
|
|
2497
2411
|
this._updateNode(parentNode);
|
|
2498
2412
|
}
|
|
2499
2413
|
}
|
|
2500
2414
|
this._updateNode(node);
|
|
2501
|
-
this._updateNode(
|
|
2415
|
+
this._updateNode(siblingNode);
|
|
2502
2416
|
}
|
|
2503
|
-
if (!
|
|
2504
|
-
for (const key2 of
|
|
2505
|
-
const n = this.getNode(key2);
|
|
2506
|
-
n.parent =
|
|
2417
|
+
if (!siblingNode.leaf) {
|
|
2418
|
+
for (const key2 of siblingNode.keys) {
|
|
2419
|
+
const n = this._cloneNode(this.getNode(key2));
|
|
2420
|
+
n.parent = siblingNode.id;
|
|
2507
2421
|
this._updateNode(n);
|
|
2508
2422
|
}
|
|
2509
2423
|
}
|
|
2510
2424
|
if (!node.leaf) {
|
|
2511
2425
|
for (const key2 of node.keys) {
|
|
2512
|
-
const n = this.getNode(key2);
|
|
2426
|
+
const n = this._cloneNode(this.getNode(key2));
|
|
2513
2427
|
n.parent = node.id;
|
|
2514
2428
|
this._updateNode(n);
|
|
2515
2429
|
}
|
|
2516
2430
|
}
|
|
2517
2431
|
if (!parentNode.leaf) {
|
|
2518
2432
|
for (const key2 of parentNode.keys) {
|
|
2519
|
-
const n = this.getNode(key2);
|
|
2433
|
+
const n = this._cloneNode(this.getNode(key2));
|
|
2520
2434
|
n.parent = parentNode.id;
|
|
2521
2435
|
this._updateNode(n);
|
|
2522
2436
|
}
|
|
2523
2437
|
}
|
|
2524
2438
|
}
|
|
2525
2439
|
} else {
|
|
2526
|
-
this._updateNode(node);
|
|
2440
|
+
this._updateNode(this._cloneNode(node));
|
|
2527
2441
|
}
|
|
2442
|
+
return node;
|
|
2528
2443
|
}
|
|
2529
2444
|
delete(key, value) {
|
|
2530
2445
|
let node = this.insertableNodeByPrimary(value);
|
|
@@ -2537,13 +2452,15 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2537
2452
|
const keys = node.keys[i];
|
|
2538
2453
|
const keyIndex = keys.indexOf(key);
|
|
2539
2454
|
if (keyIndex !== -1) {
|
|
2540
|
-
|
|
2541
|
-
|
|
2455
|
+
node = this._cloneNode(node);
|
|
2456
|
+
const freshKeys = node.keys[i];
|
|
2457
|
+
freshKeys.splice(keyIndex, 1);
|
|
2458
|
+
if (freshKeys.length === 0) {
|
|
2542
2459
|
node.keys.splice(i, 1);
|
|
2543
2460
|
node.values.splice(i, 1);
|
|
2544
2461
|
}
|
|
2545
2462
|
this._updateNode(node);
|
|
2546
|
-
this._deleteEntry(node, key);
|
|
2463
|
+
node = this._deleteEntry(node, key);
|
|
2547
2464
|
found = true;
|
|
2548
2465
|
break;
|
|
2549
2466
|
}
|
|
@@ -2578,24 +2495,13 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2578
2495
|
commit(label) {
|
|
2579
2496
|
let result = this.mvcc.commit(label);
|
|
2580
2497
|
if (result.success) {
|
|
2581
|
-
const isRootTx = this.rootTx
|
|
2582
|
-
if (isRootTx) {
|
|
2498
|
+
const isRootTx = this.rootTx === this;
|
|
2499
|
+
if (!isRootTx) {
|
|
2583
2500
|
result = this.rootTx.commit(label);
|
|
2584
2501
|
if (result.success) {
|
|
2585
2502
|
this.rootTx.rootId = this.rootId;
|
|
2586
2503
|
}
|
|
2587
2504
|
}
|
|
2588
|
-
if (result.success) {
|
|
2589
|
-
for (const r of result.created) {
|
|
2590
|
-
this.nodes.set(r.key, r.data);
|
|
2591
|
-
}
|
|
2592
|
-
for (const r of result.updated) {
|
|
2593
|
-
this.nodes.set(r.key, r.data);
|
|
2594
|
-
}
|
|
2595
|
-
for (const r of result.deleted) {
|
|
2596
|
-
this.nodes.delete(r.key);
|
|
2597
|
-
}
|
|
2598
|
-
}
|
|
2599
2505
|
}
|
|
2600
2506
|
return result;
|
|
2601
2507
|
}
|
|
@@ -2638,7 +2544,9 @@ var BPTreeMVCCStrategySync = class extends SyncMVCCStrategy {
|
|
|
2638
2544
|
};
|
|
2639
2545
|
var BPTreeSync = class extends BPTreeSyncTransaction {
|
|
2640
2546
|
constructor(strategy, comparator, option) {
|
|
2641
|
-
const mvccRoot = new SyncMVCCTransaction(new BPTreeMVCCStrategySync(strategy)
|
|
2547
|
+
const mvccRoot = new SyncMVCCTransaction(new BPTreeMVCCStrategySync(strategy), {
|
|
2548
|
+
cacheCapacity: option?.capacity ?? void 0
|
|
2549
|
+
});
|
|
2642
2550
|
super(
|
|
2643
2551
|
null,
|
|
2644
2552
|
mvccRoot,
|
|
@@ -2961,9 +2869,6 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
2961
2869
|
});
|
|
2962
2870
|
}
|
|
2963
2871
|
async getNode(id) {
|
|
2964
|
-
if (this.nodes.has(id)) {
|
|
2965
|
-
return this.nodes.get(id);
|
|
2966
|
-
}
|
|
2967
2872
|
return await this.mvcc.read(id);
|
|
2968
2873
|
}
|
|
2969
2874
|
/**
|
|
@@ -2980,24 +2885,31 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
2980
2885
|
next,
|
|
2981
2886
|
prev
|
|
2982
2887
|
};
|
|
2888
|
+
const head = await this._readHead();
|
|
2889
|
+
if (head) {
|
|
2890
|
+
await this._writeHead({
|
|
2891
|
+
root: head.root,
|
|
2892
|
+
order: head.order,
|
|
2893
|
+
data: this.strategy.head.data
|
|
2894
|
+
});
|
|
2895
|
+
}
|
|
2983
2896
|
await this.mvcc.create(id, node);
|
|
2984
|
-
this.nodes.set(id, node);
|
|
2985
2897
|
return node;
|
|
2986
2898
|
}
|
|
2987
2899
|
async _updateNode(node) {
|
|
2900
|
+
if (this.mvcc.isDeleted(node.id)) {
|
|
2901
|
+
return;
|
|
2902
|
+
}
|
|
2988
2903
|
await this.mvcc.write(node.id, node);
|
|
2989
|
-
this.nodes.set(node.id, node);
|
|
2990
2904
|
}
|
|
2991
2905
|
async _deleteNode(node) {
|
|
2906
|
+
if (this.mvcc.isDeleted(node.id)) {
|
|
2907
|
+
return;
|
|
2908
|
+
}
|
|
2992
2909
|
await this.mvcc.delete(node.id);
|
|
2993
|
-
this.nodes.delete(node.id);
|
|
2994
2910
|
}
|
|
2995
2911
|
async _readHead() {
|
|
2996
|
-
|
|
2997
|
-
return this.nodes.get("__HEAD__") ?? null;
|
|
2998
|
-
}
|
|
2999
|
-
const head = await this.mvcc.read("__HEAD__");
|
|
3000
|
-
return head ?? null;
|
|
2912
|
+
return await this.mvcc.read("__HEAD__");
|
|
3001
2913
|
}
|
|
3002
2914
|
async _writeHead(head) {
|
|
3003
2915
|
if (!await this.mvcc.exists("__HEAD__")) {
|
|
@@ -3005,49 +2917,56 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3005
2917
|
} else {
|
|
3006
2918
|
await this.mvcc.write("__HEAD__", head);
|
|
3007
2919
|
}
|
|
3008
|
-
this.nodes.set("__HEAD__", head);
|
|
3009
2920
|
this.rootId = head.root;
|
|
3010
2921
|
}
|
|
3011
2922
|
async _insertAtLeaf(node, key, value) {
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
2923
|
+
let leaf = node;
|
|
2924
|
+
if (leaf.values.length) {
|
|
2925
|
+
for (let i = 0, len = leaf.values.length; i < len; i++) {
|
|
2926
|
+
const nValue = leaf.values[i];
|
|
3015
2927
|
if (this.comparator.isSame(value, nValue)) {
|
|
3016
|
-
const keys =
|
|
2928
|
+
const keys = leaf.keys[i];
|
|
3017
2929
|
if (keys.includes(key)) {
|
|
3018
2930
|
break;
|
|
3019
2931
|
}
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
2932
|
+
leaf = this._cloneNode(leaf);
|
|
2933
|
+
leaf.keys[i].push(key);
|
|
2934
|
+
await this._updateNode(leaf);
|
|
2935
|
+
return leaf;
|
|
3023
2936
|
} else if (this.comparator.isLower(value, nValue)) {
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
2937
|
+
leaf = this._cloneNode(leaf);
|
|
2938
|
+
leaf.values.splice(i, 0, value);
|
|
2939
|
+
leaf.keys.splice(i, 0, [key]);
|
|
2940
|
+
await this._updateNode(leaf);
|
|
2941
|
+
return leaf;
|
|
2942
|
+
} else if (i + 1 === leaf.values.length) {
|
|
2943
|
+
leaf = this._cloneNode(leaf);
|
|
2944
|
+
leaf.values.push(value);
|
|
2945
|
+
leaf.keys.push([key]);
|
|
2946
|
+
await this._updateNode(leaf);
|
|
2947
|
+
return leaf;
|
|
3033
2948
|
}
|
|
3034
2949
|
}
|
|
3035
2950
|
} else {
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
2951
|
+
leaf = this._cloneNode(leaf);
|
|
2952
|
+
leaf.values = [value];
|
|
2953
|
+
leaf.keys = [[key]];
|
|
2954
|
+
await this._updateNode(leaf);
|
|
2955
|
+
return leaf;
|
|
3040
2956
|
}
|
|
2957
|
+
return leaf;
|
|
3041
2958
|
}
|
|
3042
|
-
async _insertInParent(node, value,
|
|
2959
|
+
async _insertInParent(node, value, newSiblingNode) {
|
|
3043
2960
|
if (this.rootId === node.id) {
|
|
3044
|
-
|
|
2961
|
+
node = this._cloneNode(node);
|
|
2962
|
+
newSiblingNode = this._cloneNode(newSiblingNode);
|
|
2963
|
+
const root = await this._createNode(false, [node.id, newSiblingNode.id], [value]);
|
|
3045
2964
|
this.rootId = root.id;
|
|
3046
2965
|
node.parent = root.id;
|
|
3047
|
-
|
|
3048
|
-
if (
|
|
3049
|
-
node.next =
|
|
3050
|
-
|
|
2966
|
+
newSiblingNode.parent = root.id;
|
|
2967
|
+
if (newSiblingNode.leaf) {
|
|
2968
|
+
node.next = newSiblingNode.id;
|
|
2969
|
+
newSiblingNode.prev = node.id;
|
|
3051
2970
|
}
|
|
3052
2971
|
await this._writeHead({
|
|
3053
2972
|
root: root.id,
|
|
@@ -3055,53 +2974,54 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3055
2974
|
data: this.strategy.head.data
|
|
3056
2975
|
});
|
|
3057
2976
|
await this._updateNode(node);
|
|
3058
|
-
await this._updateNode(
|
|
2977
|
+
await this._updateNode(newSiblingNode);
|
|
3059
2978
|
return;
|
|
3060
2979
|
}
|
|
3061
|
-
const parentNode = await this.getNode(node.parent);
|
|
2980
|
+
const parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
3062
2981
|
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
3063
2982
|
if (nodeIndex === -1) {
|
|
3064
2983
|
throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
|
|
3065
2984
|
}
|
|
3066
2985
|
parentNode.values.splice(nodeIndex, 0, value);
|
|
3067
|
-
parentNode.keys.splice(nodeIndex + 1, 0,
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
2986
|
+
parentNode.keys.splice(nodeIndex + 1, 0, newSiblingNode.id);
|
|
2987
|
+
newSiblingNode = this._cloneNode(newSiblingNode);
|
|
2988
|
+
newSiblingNode.parent = parentNode.id;
|
|
2989
|
+
if (newSiblingNode.leaf) {
|
|
2990
|
+
const leftSibling = this._cloneNode(node);
|
|
3071
2991
|
const oldNextId = leftSibling.next;
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
leftSibling.next =
|
|
2992
|
+
newSiblingNode.prev = leftSibling.id;
|
|
2993
|
+
newSiblingNode.next = oldNextId;
|
|
2994
|
+
leftSibling.next = newSiblingNode.id;
|
|
3075
2995
|
await this._updateNode(leftSibling);
|
|
3076
2996
|
if (oldNextId) {
|
|
3077
|
-
const oldNext = await this.getNode(oldNextId);
|
|
3078
|
-
oldNext.prev =
|
|
2997
|
+
const oldNext = this._cloneNode(await this.getNode(oldNextId));
|
|
2998
|
+
oldNext.prev = newSiblingNode.id;
|
|
3079
2999
|
await this._updateNode(oldNext);
|
|
3080
3000
|
}
|
|
3081
3001
|
}
|
|
3082
3002
|
await this._updateNode(parentNode);
|
|
3083
|
-
await this._updateNode(
|
|
3003
|
+
await this._updateNode(newSiblingNode);
|
|
3084
3004
|
if (parentNode.keys.length > this.order) {
|
|
3085
|
-
const
|
|
3086
|
-
|
|
3005
|
+
const newSiblingNodeRecursive = await this._createNode(false, [], []);
|
|
3006
|
+
newSiblingNodeRecursive.parent = parentNode.parent;
|
|
3087
3007
|
const mid = Math.ceil(this.order / 2) - 1;
|
|
3088
|
-
|
|
3089
|
-
|
|
3008
|
+
newSiblingNodeRecursive.values = parentNode.values.slice(mid + 1);
|
|
3009
|
+
newSiblingNodeRecursive.keys = parentNode.keys.slice(mid + 1);
|
|
3090
3010
|
const midValue = parentNode.values[mid];
|
|
3091
3011
|
parentNode.values = parentNode.values.slice(0, mid);
|
|
3092
3012
|
parentNode.keys = parentNode.keys.slice(0, mid + 1);
|
|
3093
3013
|
for (const k of parentNode.keys) {
|
|
3094
|
-
const n = await this.getNode(k);
|
|
3014
|
+
const n = this._cloneNode(await this.getNode(k));
|
|
3095
3015
|
n.parent = parentNode.id;
|
|
3096
3016
|
await this._updateNode(n);
|
|
3097
3017
|
}
|
|
3098
|
-
for (const k of
|
|
3099
|
-
const n = await this.getNode(k);
|
|
3100
|
-
n.parent =
|
|
3018
|
+
for (const k of newSiblingNodeRecursive.keys) {
|
|
3019
|
+
const n = this._cloneNode(await this.getNode(k));
|
|
3020
|
+
n.parent = newSiblingNodeRecursive.id;
|
|
3101
3021
|
await this._updateNode(n);
|
|
3102
3022
|
}
|
|
3103
3023
|
await this._updateNode(parentNode);
|
|
3104
|
-
await this._insertInParent(parentNode, midValue,
|
|
3024
|
+
await this._insertInParent(parentNode, midValue, newSiblingNodeRecursive);
|
|
3105
3025
|
}
|
|
3106
3026
|
}
|
|
3107
3027
|
async insertableNode(value) {
|
|
@@ -3290,21 +3210,6 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3290
3210
|
}
|
|
3291
3211
|
return false;
|
|
3292
3212
|
}
|
|
3293
|
-
async forceUpdate(id) {
|
|
3294
|
-
if (id) {
|
|
3295
|
-
this.nodes.delete(id);
|
|
3296
|
-
await this.getNode(id);
|
|
3297
|
-
return 1;
|
|
3298
|
-
}
|
|
3299
|
-
const keys = Array.from(this.nodes.keys());
|
|
3300
|
-
for (const key of keys) {
|
|
3301
|
-
this.nodes.delete(key);
|
|
3302
|
-
}
|
|
3303
|
-
for (const key of keys) {
|
|
3304
|
-
await this.getNode(key);
|
|
3305
|
-
}
|
|
3306
|
-
return keys.length;
|
|
3307
|
-
}
|
|
3308
3213
|
async get(key) {
|
|
3309
3214
|
let node = await this.leftestNode();
|
|
3310
3215
|
while (true) {
|
|
@@ -3391,10 +3296,10 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3391
3296
|
}
|
|
3392
3297
|
async insert(key, value) {
|
|
3393
3298
|
return this.writeLock(0, async () => {
|
|
3394
|
-
|
|
3395
|
-
await this._insertAtLeaf(before, key, value);
|
|
3299
|
+
let before = await this.insertableNode(value);
|
|
3300
|
+
before = await this._insertAtLeaf(before, key, value);
|
|
3396
3301
|
if (before.values.length === this.order) {
|
|
3397
|
-
|
|
3302
|
+
let after = await this._createNode(
|
|
3398
3303
|
true,
|
|
3399
3304
|
[],
|
|
3400
3305
|
[],
|
|
@@ -3403,10 +3308,13 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3403
3308
|
null
|
|
3404
3309
|
);
|
|
3405
3310
|
const mid = Math.ceil(this.order / 2) - 1;
|
|
3311
|
+
after = this._cloneNode(after);
|
|
3406
3312
|
after.values = before.values.slice(mid + 1);
|
|
3407
3313
|
after.keys = before.keys.slice(mid + 1);
|
|
3408
3314
|
before.values = before.values.slice(0, mid + 1);
|
|
3409
3315
|
before.keys = before.keys.slice(0, mid + 1);
|
|
3316
|
+
await this._updateNode(before);
|
|
3317
|
+
await this._updateNode(after);
|
|
3410
3318
|
await this._insertInParent(before, after.values[0], after);
|
|
3411
3319
|
}
|
|
3412
3320
|
});
|
|
@@ -3421,6 +3329,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3421
3329
|
}
|
|
3422
3330
|
}
|
|
3423
3331
|
if (keyIndex !== -1) {
|
|
3332
|
+
node = this._cloneNode(node);
|
|
3424
3333
|
node.keys.splice(keyIndex, 1);
|
|
3425
3334
|
const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
|
|
3426
3335
|
node.values.splice(valueIndex, 1);
|
|
@@ -3430,7 +3339,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3430
3339
|
if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
|
|
3431
3340
|
const keys = node.keys;
|
|
3432
3341
|
this._deleteNode(node);
|
|
3433
|
-
const newRoot = await this.getNode(keys[0]);
|
|
3342
|
+
const newRoot = this._cloneNode(await this.getNode(keys[0]));
|
|
3434
3343
|
newRoot.parent = null;
|
|
3435
3344
|
await this._updateNode(newRoot);
|
|
3436
3345
|
await this._writeHead({
|
|
@@ -3438,14 +3347,17 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3438
3347
|
order: this.order,
|
|
3439
3348
|
data: this.strategy.head.data
|
|
3440
3349
|
});
|
|
3441
|
-
return;
|
|
3350
|
+
return node;
|
|
3442
3351
|
} else if (this.rootId === node.id) {
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3352
|
+
await this._writeHead({
|
|
3353
|
+
root: node.id,
|
|
3354
|
+
order: this.order,
|
|
3355
|
+
data: this.strategy.head.data
|
|
3356
|
+
});
|
|
3357
|
+
return node;
|
|
3446
3358
|
} else if (node.keys.length < Math.ceil(this.order / 2) && !node.leaf || node.values.length < Math.ceil((this.order - 1) / 2) && node.leaf) {
|
|
3447
3359
|
if (node.parent === null) {
|
|
3448
|
-
return;
|
|
3360
|
+
return node;
|
|
3449
3361
|
}
|
|
3450
3362
|
let isPredecessor = false;
|
|
3451
3363
|
let parentNode = await this.getNode(node.parent);
|
|
@@ -3466,78 +3378,80 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3466
3378
|
}
|
|
3467
3379
|
}
|
|
3468
3380
|
}
|
|
3469
|
-
let
|
|
3381
|
+
let siblingNode;
|
|
3470
3382
|
let guess;
|
|
3471
3383
|
if (prevNode === null) {
|
|
3472
|
-
|
|
3384
|
+
siblingNode = nextNode;
|
|
3473
3385
|
guess = postValue;
|
|
3474
3386
|
} else if (nextNode === null) {
|
|
3475
3387
|
isPredecessor = true;
|
|
3476
|
-
|
|
3388
|
+
siblingNode = prevNode;
|
|
3477
3389
|
guess = prevValue;
|
|
3478
3390
|
} else {
|
|
3479
3391
|
if (node.values.length + nextNode.values.length < this.order) {
|
|
3480
|
-
|
|
3392
|
+
siblingNode = nextNode;
|
|
3481
3393
|
guess = postValue;
|
|
3482
3394
|
} else {
|
|
3483
3395
|
isPredecessor = true;
|
|
3484
|
-
|
|
3396
|
+
siblingNode = prevNode;
|
|
3485
3397
|
guess = prevValue;
|
|
3486
3398
|
}
|
|
3487
3399
|
}
|
|
3488
|
-
if (!
|
|
3489
|
-
return;
|
|
3400
|
+
if (!siblingNode) {
|
|
3401
|
+
return node;
|
|
3490
3402
|
}
|
|
3491
|
-
|
|
3403
|
+
node = this._cloneNode(node);
|
|
3404
|
+
siblingNode = this._cloneNode(siblingNode);
|
|
3405
|
+
if (node.values.length + siblingNode.values.length < this.order) {
|
|
3492
3406
|
if (!isPredecessor) {
|
|
3493
|
-
const pTemp =
|
|
3494
|
-
|
|
3407
|
+
const pTemp = siblingNode;
|
|
3408
|
+
siblingNode = node;
|
|
3495
3409
|
node = pTemp;
|
|
3496
3410
|
}
|
|
3497
|
-
|
|
3411
|
+
siblingNode.keys.push(...node.keys);
|
|
3498
3412
|
if (!node.leaf) {
|
|
3499
|
-
|
|
3413
|
+
siblingNode.values.push(guess);
|
|
3500
3414
|
} else {
|
|
3501
|
-
|
|
3502
|
-
if (
|
|
3503
|
-
const n = await this.getNode(
|
|
3504
|
-
n.prev =
|
|
3415
|
+
siblingNode.next = node.next;
|
|
3416
|
+
if (siblingNode.next) {
|
|
3417
|
+
const n = this._cloneNode(await this.getNode(siblingNode.next));
|
|
3418
|
+
n.prev = siblingNode.id;
|
|
3505
3419
|
await this._updateNode(n);
|
|
3506
3420
|
}
|
|
3507
3421
|
}
|
|
3508
|
-
|
|
3509
|
-
if (!
|
|
3510
|
-
const keys =
|
|
3422
|
+
siblingNode.values.push(...node.values);
|
|
3423
|
+
if (!siblingNode.leaf) {
|
|
3424
|
+
const keys = siblingNode.keys;
|
|
3511
3425
|
for (const key2 of keys) {
|
|
3512
|
-
const node2 = await this.getNode(key2);
|
|
3513
|
-
node2.parent =
|
|
3426
|
+
const node2 = this._cloneNode(await this.getNode(key2));
|
|
3427
|
+
node2.parent = siblingNode.id;
|
|
3514
3428
|
await this._updateNode(node2);
|
|
3515
3429
|
}
|
|
3516
3430
|
}
|
|
3517
3431
|
this._deleteNode(node);
|
|
3518
|
-
await this._updateNode(
|
|
3432
|
+
await this._updateNode(siblingNode);
|
|
3519
3433
|
await this._deleteEntry(await this.getNode(node.parent), node.id);
|
|
3520
3434
|
} else {
|
|
3521
3435
|
if (isPredecessor) {
|
|
3522
3436
|
let pointerPm;
|
|
3523
3437
|
let pointerKm;
|
|
3524
3438
|
if (!node.leaf) {
|
|
3525
|
-
pointerPm =
|
|
3526
|
-
pointerKm =
|
|
3439
|
+
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
3440
|
+
pointerKm = siblingNode.values.splice(-1)[0];
|
|
3527
3441
|
node.keys = [pointerPm, ...node.keys];
|
|
3528
3442
|
node.values = [guess, ...node.values];
|
|
3529
|
-
parentNode = await this.getNode(node.parent);
|
|
3443
|
+
parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
3530
3444
|
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
3531
3445
|
if (nodeIndex > 0) {
|
|
3532
3446
|
parentNode.values[nodeIndex - 1] = pointerKm;
|
|
3533
3447
|
await this._updateNode(parentNode);
|
|
3534
3448
|
}
|
|
3535
3449
|
} else {
|
|
3536
|
-
pointerPm =
|
|
3537
|
-
pointerKm =
|
|
3450
|
+
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
3451
|
+
pointerKm = siblingNode.values.splice(-1)[0];
|
|
3538
3452
|
node.keys = [pointerPm, ...node.keys];
|
|
3539
3453
|
node.values = [pointerKm, ...node.values];
|
|
3540
|
-
parentNode = await this.getNode(node.parent);
|
|
3454
|
+
parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
3541
3455
|
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
3542
3456
|
if (nodeIndex > 0) {
|
|
3543
3457
|
parentNode.values[nodeIndex - 1] = pointerKm;
|
|
@@ -3545,61 +3459,62 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3545
3459
|
}
|
|
3546
3460
|
}
|
|
3547
3461
|
await this._updateNode(node);
|
|
3548
|
-
await this._updateNode(
|
|
3462
|
+
await this._updateNode(siblingNode);
|
|
3549
3463
|
} else {
|
|
3550
3464
|
let pointerP0;
|
|
3551
3465
|
let pointerK0;
|
|
3552
3466
|
if (!node.leaf) {
|
|
3553
|
-
pointerP0 =
|
|
3554
|
-
pointerK0 =
|
|
3467
|
+
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
3468
|
+
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
3555
3469
|
node.keys = [...node.keys, pointerP0];
|
|
3556
3470
|
node.values = [...node.values, guess];
|
|
3557
|
-
parentNode = await this.getNode(node.parent);
|
|
3558
|
-
const pointerIndex = parentNode.keys.indexOf(
|
|
3471
|
+
parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
3472
|
+
const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
|
|
3559
3473
|
if (pointerIndex > 0) {
|
|
3560
3474
|
parentNode.values[pointerIndex - 1] = pointerK0;
|
|
3561
3475
|
await this._updateNode(parentNode);
|
|
3562
3476
|
}
|
|
3563
3477
|
} else {
|
|
3564
|
-
pointerP0 =
|
|
3565
|
-
pointerK0 =
|
|
3478
|
+
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
3479
|
+
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
3566
3480
|
node.keys = [...node.keys, pointerP0];
|
|
3567
3481
|
node.values = [...node.values, pointerK0];
|
|
3568
|
-
parentNode = await this.getNode(node.parent);
|
|
3569
|
-
const pointerIndex = parentNode.keys.indexOf(
|
|
3482
|
+
parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
3483
|
+
const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
|
|
3570
3484
|
if (pointerIndex > 0) {
|
|
3571
|
-
parentNode.values[pointerIndex - 1] =
|
|
3485
|
+
parentNode.values[pointerIndex - 1] = siblingNode.values[0];
|
|
3572
3486
|
await this._updateNode(parentNode);
|
|
3573
3487
|
}
|
|
3574
3488
|
}
|
|
3575
3489
|
await this._updateNode(node);
|
|
3576
|
-
await this._updateNode(
|
|
3490
|
+
await this._updateNode(siblingNode);
|
|
3577
3491
|
}
|
|
3578
|
-
if (!
|
|
3579
|
-
for (const key2 of
|
|
3580
|
-
const n = await this.getNode(key2);
|
|
3581
|
-
n.parent =
|
|
3492
|
+
if (!siblingNode.leaf) {
|
|
3493
|
+
for (const key2 of siblingNode.keys) {
|
|
3494
|
+
const n = this._cloneNode(await this.getNode(key2));
|
|
3495
|
+
n.parent = siblingNode.id;
|
|
3582
3496
|
await this._updateNode(n);
|
|
3583
3497
|
}
|
|
3584
3498
|
}
|
|
3585
3499
|
if (!node.leaf) {
|
|
3586
3500
|
for (const key2 of node.keys) {
|
|
3587
|
-
const n = await this.getNode(key2);
|
|
3501
|
+
const n = this._cloneNode(await this.getNode(key2));
|
|
3588
3502
|
n.parent = node.id;
|
|
3589
3503
|
await this._updateNode(n);
|
|
3590
3504
|
}
|
|
3591
3505
|
}
|
|
3592
3506
|
if (!parentNode.leaf) {
|
|
3593
3507
|
for (const key2 of parentNode.keys) {
|
|
3594
|
-
const n = await this.getNode(key2);
|
|
3508
|
+
const n = this._cloneNode(await this.getNode(key2));
|
|
3595
3509
|
n.parent = parentNode.id;
|
|
3596
3510
|
await this._updateNode(n);
|
|
3597
3511
|
}
|
|
3598
3512
|
}
|
|
3599
3513
|
}
|
|
3600
3514
|
} else {
|
|
3601
|
-
await this._updateNode(node);
|
|
3515
|
+
await this._updateNode(this._cloneNode(node));
|
|
3602
3516
|
}
|
|
3517
|
+
return node;
|
|
3603
3518
|
}
|
|
3604
3519
|
async delete(key, value) {
|
|
3605
3520
|
return this.writeLock(0, async () => {
|
|
@@ -3613,13 +3528,15 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3613
3528
|
const keys = node.keys[i];
|
|
3614
3529
|
const keyIndex = keys.indexOf(key);
|
|
3615
3530
|
if (keyIndex !== -1) {
|
|
3616
|
-
|
|
3617
|
-
|
|
3531
|
+
node = this._cloneNode(node);
|
|
3532
|
+
const freshKeys = node.keys[i];
|
|
3533
|
+
freshKeys.splice(keyIndex, 1);
|
|
3534
|
+
if (freshKeys.length === 0) {
|
|
3618
3535
|
node.keys.splice(i, 1);
|
|
3619
3536
|
node.values.splice(i, 1);
|
|
3620
3537
|
}
|
|
3621
3538
|
await this._updateNode(node);
|
|
3622
|
-
await this._deleteEntry(node, key);
|
|
3539
|
+
node = await this._deleteEntry(node, key);
|
|
3623
3540
|
found = true;
|
|
3624
3541
|
break;
|
|
3625
3542
|
}
|
|
@@ -3662,21 +3579,10 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3662
3579
|
this.rootTx.rootId = this.rootId;
|
|
3663
3580
|
}
|
|
3664
3581
|
}
|
|
3665
|
-
if (result.success) {
|
|
3666
|
-
for (const r of result.created) {
|
|
3667
|
-
this.nodes.set(r.key, r.data);
|
|
3668
|
-
}
|
|
3669
|
-
for (const r of result.updated) {
|
|
3670
|
-
this.nodes.set(r.key, r.data);
|
|
3671
|
-
}
|
|
3672
|
-
for (const r of result.deleted) {
|
|
3673
|
-
this.nodes.delete(r.key);
|
|
3674
|
-
}
|
|
3675
|
-
}
|
|
3676
3582
|
}
|
|
3677
3583
|
return result;
|
|
3678
3584
|
}
|
|
3679
|
-
rollback() {
|
|
3585
|
+
async rollback() {
|
|
3680
3586
|
return this.mvcc.rollback();
|
|
3681
3587
|
}
|
|
3682
3588
|
};
|
|
@@ -3715,7 +3621,9 @@ var BPTreeMVCCStrategyAsync = class extends AsyncMVCCStrategy {
|
|
|
3715
3621
|
};
|
|
3716
3622
|
var BPTreeAsync = class extends BPTreeAsyncTransaction {
|
|
3717
3623
|
constructor(strategy, comparator, option) {
|
|
3718
|
-
const mvccRoot = new AsyncMVCCTransaction(new BPTreeMVCCStrategyAsync(strategy)
|
|
3624
|
+
const mvccRoot = new AsyncMVCCTransaction(new BPTreeMVCCStrategyAsync(strategy), {
|
|
3625
|
+
cacheCapacity: option?.capacity ?? void 0
|
|
3626
|
+
});
|
|
3719
3627
|
super(
|
|
3720
3628
|
null,
|
|
3721
3629
|
mvccRoot,
|
|
@@ -4267,7 +4175,7 @@ var LRUMap2 = class {
|
|
|
4267
4175
|
this.tail = null;
|
|
4268
4176
|
}
|
|
4269
4177
|
};
|
|
4270
|
-
var
|
|
4178
|
+
var CacheEntanglement = class {
|
|
4271
4179
|
creation;
|
|
4272
4180
|
beforeUpdateHook;
|
|
4273
4181
|
capacity;
|
|
@@ -4368,7 +4276,7 @@ var CacheEntanglement2 = class {
|
|
|
4368
4276
|
}
|
|
4369
4277
|
}
|
|
4370
4278
|
};
|
|
4371
|
-
var
|
|
4279
|
+
var CacheData = class _CacheData {
|
|
4372
4280
|
static StructuredClone = globalThis.structuredClone.bind(globalThis);
|
|
4373
4281
|
_value;
|
|
4374
4282
|
constructor(value) {
|
|
@@ -4408,11 +4316,11 @@ var CacheData2 = class _CacheData2 {
|
|
|
4408
4316
|
return Object.assign({}, this.raw);
|
|
4409
4317
|
case "deep-copy":
|
|
4410
4318
|
default:
|
|
4411
|
-
return
|
|
4319
|
+
return _CacheData.StructuredClone(this.raw);
|
|
4412
4320
|
}
|
|
4413
4321
|
}
|
|
4414
4322
|
};
|
|
4415
|
-
var
|
|
4323
|
+
var CacheEntanglementSync = class extends CacheEntanglement {
|
|
4416
4324
|
constructor(creation, option) {
|
|
4417
4325
|
super(creation, option);
|
|
4418
4326
|
}
|
|
@@ -4442,7 +4350,7 @@ var CacheEntanglementSync2 = class extends CacheEntanglement2 {
|
|
|
4442
4350
|
const dependencyValue = dependency.recache(key) ?? dependency.recache(dependencyKey);
|
|
4443
4351
|
resolved[name] = dependencyValue;
|
|
4444
4352
|
}
|
|
4445
|
-
const value = new
|
|
4353
|
+
const value = new CacheData(this.creation(key, resolved, ...parameter));
|
|
4446
4354
|
this.updateRequirements.delete(key);
|
|
4447
4355
|
this.parameters.set(key, parameter);
|
|
4448
4356
|
this.caches.set(key, value);
|
|
@@ -4466,7 +4374,7 @@ var CacheEntanglementSync2 = class extends CacheEntanglement2 {
|
|
|
4466
4374
|
return this.caches.get(key);
|
|
4467
4375
|
}
|
|
4468
4376
|
};
|
|
4469
|
-
var CacheEntanglementAsync = class extends
|
|
4377
|
+
var CacheEntanglementAsync = class extends CacheEntanglement {
|
|
4470
4378
|
constructor(creation, option) {
|
|
4471
4379
|
super(creation, option);
|
|
4472
4380
|
}
|
|
@@ -4496,7 +4404,7 @@ var CacheEntanglementAsync = class extends CacheEntanglement2 {
|
|
|
4496
4404
|
const dependencyValue = await dependency.recache(key) ?? await dependency.recache(dependencyKey);
|
|
4497
4405
|
resolved[name] = dependencyValue;
|
|
4498
4406
|
}
|
|
4499
|
-
const value = new
|
|
4407
|
+
const value = new CacheData(await this.creation(key, resolved, ...parameter));
|
|
4500
4408
|
this.updateRequirements.delete(key);
|
|
4501
4409
|
this.parameters.set(key, parameter);
|
|
4502
4410
|
this.caches.set(key, value);
|
|
@@ -4601,6 +4509,42 @@ var InvertedWeakMap = class {
|
|
|
4601
4509
|
// node_modules/mvcc-api/dist/esm/index.mjs
|
|
4602
4510
|
var MVCCStrategy2 = class {
|
|
4603
4511
|
};
|
|
4512
|
+
var LRUMap3 = class {
|
|
4513
|
+
cache = /* @__PURE__ */ new Map();
|
|
4514
|
+
capacity;
|
|
4515
|
+
constructor(capacity) {
|
|
4516
|
+
this.capacity = capacity;
|
|
4517
|
+
}
|
|
4518
|
+
get(key) {
|
|
4519
|
+
if (!this.cache.has(key)) return void 0;
|
|
4520
|
+
const value = this.cache.get(key);
|
|
4521
|
+
this.cache.delete(key);
|
|
4522
|
+
this.cache.set(key, value);
|
|
4523
|
+
return value;
|
|
4524
|
+
}
|
|
4525
|
+
set(key, value) {
|
|
4526
|
+
if (this.cache.has(key)) {
|
|
4527
|
+
this.cache.delete(key);
|
|
4528
|
+
} else if (this.cache.size >= this.capacity) {
|
|
4529
|
+
const oldestKey = this.cache.keys().next().value;
|
|
4530
|
+
if (oldestKey !== void 0) this.cache.delete(oldestKey);
|
|
4531
|
+
}
|
|
4532
|
+
this.cache.set(key, value);
|
|
4533
|
+
return this;
|
|
4534
|
+
}
|
|
4535
|
+
has(key) {
|
|
4536
|
+
return this.cache.has(key);
|
|
4537
|
+
}
|
|
4538
|
+
delete(key) {
|
|
4539
|
+
return this.cache.delete(key);
|
|
4540
|
+
}
|
|
4541
|
+
clear() {
|
|
4542
|
+
this.cache.clear();
|
|
4543
|
+
}
|
|
4544
|
+
get size() {
|
|
4545
|
+
return this.cache.size;
|
|
4546
|
+
}
|
|
4547
|
+
};
|
|
4604
4548
|
var MVCCTransaction2 = class {
|
|
4605
4549
|
committed;
|
|
4606
4550
|
snapshotVersion;
|
|
@@ -4608,7 +4552,6 @@ var MVCCTransaction2 = class {
|
|
|
4608
4552
|
writeBuffer;
|
|
4609
4553
|
deleteBuffer;
|
|
4610
4554
|
createdKeys;
|
|
4611
|
-
// create()로 생성된 키 추적
|
|
4612
4555
|
deletedValues;
|
|
4613
4556
|
// delete 시 삭제 전 값 저장
|
|
4614
4557
|
originallyExisted;
|
|
@@ -4627,7 +4570,8 @@ var MVCCTransaction2 = class {
|
|
|
4627
4570
|
versionIndex = /* @__PURE__ */ new Map();
|
|
4628
4571
|
deletedCache = /* @__PURE__ */ new Map();
|
|
4629
4572
|
activeTransactions = /* @__PURE__ */ new Set();
|
|
4630
|
-
|
|
4573
|
+
diskCache;
|
|
4574
|
+
constructor(strategy, options, parent, snapshotVersion) {
|
|
4631
4575
|
this.snapshotVersion = snapshotVersion ?? 0;
|
|
4632
4576
|
this.writeBuffer = /* @__PURE__ */ new Map();
|
|
4633
4577
|
this.deleteBuffer = /* @__PURE__ */ new Set();
|
|
@@ -4642,6 +4586,7 @@ var MVCCTransaction2 = class {
|
|
|
4642
4586
|
this.snapshotLocalVersion = parent.localVersion;
|
|
4643
4587
|
this.strategy = void 0;
|
|
4644
4588
|
this.root = parent.root;
|
|
4589
|
+
this.diskCache = parent.diskCache;
|
|
4645
4590
|
} else {
|
|
4646
4591
|
if (!strategy) throw new Error("Root Transaction must get Strategy");
|
|
4647
4592
|
this.strategy = strategy;
|
|
@@ -4649,8 +4594,13 @@ var MVCCTransaction2 = class {
|
|
|
4649
4594
|
this.localVersion = 0;
|
|
4650
4595
|
this.snapshotLocalVersion = 0;
|
|
4651
4596
|
this.root = this;
|
|
4597
|
+
this.diskCache = new LRUMap3(options?.cacheCapacity ?? 1e3);
|
|
4652
4598
|
}
|
|
4653
4599
|
}
|
|
4600
|
+
/**
|
|
4601
|
+
* Checks if the transaction is a root transaction.
|
|
4602
|
+
* @returns True if the transaction is a root transaction, false otherwise.
|
|
4603
|
+
*/
|
|
4654
4604
|
isRoot() {
|
|
4655
4605
|
return !this.parent;
|
|
4656
4606
|
}
|
|
@@ -4667,7 +4617,22 @@ var MVCCTransaction2 = class {
|
|
|
4667
4617
|
}
|
|
4668
4618
|
return false;
|
|
4669
4619
|
}
|
|
4670
|
-
|
|
4620
|
+
/**
|
|
4621
|
+
* Checks if a key was written in this transaction.
|
|
4622
|
+
* @param key The key to check.
|
|
4623
|
+
* @returns True if the key was written in this transaction, false otherwise.
|
|
4624
|
+
*/
|
|
4625
|
+
isWrote(key) {
|
|
4626
|
+
return this.writeBuffer.has(key);
|
|
4627
|
+
}
|
|
4628
|
+
/**
|
|
4629
|
+
* Checks if a key was deleted in this transaction.
|
|
4630
|
+
* @param key The key to check.
|
|
4631
|
+
* @returns True if the key was deleted in this transaction, false otherwise.
|
|
4632
|
+
*/
|
|
4633
|
+
isDeleted(key) {
|
|
4634
|
+
return this.deleteBuffer.has(key);
|
|
4635
|
+
}
|
|
4671
4636
|
_recordHistory(key) {
|
|
4672
4637
|
const existsInWriteBuffer = this.writeBuffer.has(key);
|
|
4673
4638
|
const existsInDeleteBuffer = this.deleteBuffer.has(key);
|
|
@@ -4681,6 +4646,41 @@ var MVCCTransaction2 = class {
|
|
|
4681
4646
|
});
|
|
4682
4647
|
}
|
|
4683
4648
|
}
|
|
4649
|
+
/**
|
|
4650
|
+
* BINARY SEARCH HELPER: Finds the index of the last element in the array
|
|
4651
|
+
* where item[key] <= target. Assumes the array is sorted by 'key' ascending.
|
|
4652
|
+
*/
|
|
4653
|
+
_findLastLE(array, target, property) {
|
|
4654
|
+
let left = 0;
|
|
4655
|
+
let right = array.length - 1;
|
|
4656
|
+
let result = -1;
|
|
4657
|
+
while (left <= right) {
|
|
4658
|
+
const mid = left + right >> 1;
|
|
4659
|
+
if (array[mid][property] <= target) {
|
|
4660
|
+
result = mid;
|
|
4661
|
+
left = mid + 1;
|
|
4662
|
+
} else {
|
|
4663
|
+
right = mid - 1;
|
|
4664
|
+
}
|
|
4665
|
+
}
|
|
4666
|
+
return result;
|
|
4667
|
+
}
|
|
4668
|
+
/**
|
|
4669
|
+
* BINARY SEARCH HELPER: Finds the index of the element in the array
|
|
4670
|
+
* where item[key] === target. Assumes the array is sorted by 'key' ascending.
|
|
4671
|
+
*/
|
|
4672
|
+
_findExact(array, target, property) {
|
|
4673
|
+
let left = 0;
|
|
4674
|
+
let right = array.length - 1;
|
|
4675
|
+
while (left <= right) {
|
|
4676
|
+
const mid = left + right >> 1;
|
|
4677
|
+
const val = array[mid][property];
|
|
4678
|
+
if (val === target) return mid;
|
|
4679
|
+
if (val < target) left = mid + 1;
|
|
4680
|
+
else right = mid - 1;
|
|
4681
|
+
}
|
|
4682
|
+
return -1;
|
|
4683
|
+
}
|
|
4684
4684
|
_bufferCreate(key, value, version) {
|
|
4685
4685
|
if (version === void 0) this.localVersion++;
|
|
4686
4686
|
const targetVersion = version ?? this.localVersion;
|
|
@@ -4730,7 +4730,11 @@ var MVCCTransaction2 = class {
|
|
|
4730
4730
|
deleted.push({ key, data });
|
|
4731
4731
|
}
|
|
4732
4732
|
}
|
|
4733
|
-
return {
|
|
4733
|
+
return {
|
|
4734
|
+
created,
|
|
4735
|
+
updated,
|
|
4736
|
+
deleted
|
|
4737
|
+
};
|
|
4734
4738
|
}
|
|
4735
4739
|
/**
|
|
4736
4740
|
* Rolls back the transaction.
|
|
@@ -4748,7 +4752,12 @@ var MVCCTransaction2 = class {
|
|
|
4748
4752
|
if (this.root !== this) {
|
|
4749
4753
|
this.root.activeTransactions.delete(this);
|
|
4750
4754
|
}
|
|
4751
|
-
return {
|
|
4755
|
+
return {
|
|
4756
|
+
success: true,
|
|
4757
|
+
created,
|
|
4758
|
+
updated,
|
|
4759
|
+
deleted
|
|
4760
|
+
};
|
|
4752
4761
|
}
|
|
4753
4762
|
/**
|
|
4754
4763
|
* Cleans up both deletedCache and versionIndex based on minActiveVersion.
|
|
@@ -4834,7 +4843,7 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
|
|
|
4834
4843
|
createNested() {
|
|
4835
4844
|
if (this.committed) throw new Error("Transaction already committed");
|
|
4836
4845
|
const childVersion = this.isRoot() ? this.version : this.snapshotVersion;
|
|
4837
|
-
const child = new _SyncMVCCTransaction2(void 0, this, childVersion);
|
|
4846
|
+
const child = new _SyncMVCCTransaction2(void 0, void 0, this, childVersion);
|
|
4838
4847
|
this.root.activeTransactions.add(child);
|
|
4839
4848
|
return child;
|
|
4840
4849
|
}
|
|
@@ -4857,78 +4866,114 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
|
|
|
4857
4866
|
return this._diskExists(key, this.snapshotVersion);
|
|
4858
4867
|
}
|
|
4859
4868
|
_existsSnapshot(key, snapshotVersion, snapshotLocalVersion) {
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
return false;
|
|
4870
|
-
}
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4869
|
+
let current = this;
|
|
4870
|
+
let slVer = snapshotLocalVersion;
|
|
4871
|
+
while (current) {
|
|
4872
|
+
if (current.writeBuffer.has(key)) {
|
|
4873
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
4874
|
+
if (slVer === void 0 || keyModVersion <= slVer) return true;
|
|
4875
|
+
}
|
|
4876
|
+
if (current.deleteBuffer.has(key)) {
|
|
4877
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
4878
|
+
if (slVer === void 0 || keyModVersion <= slVer) return false;
|
|
4879
|
+
}
|
|
4880
|
+
const history = current.bufferHistory.get(key);
|
|
4881
|
+
if (history && slVer !== void 0) {
|
|
4882
|
+
const idx = current._findLastLE(history, slVer, "version");
|
|
4883
|
+
if (idx >= 0) return history[idx].exists;
|
|
4884
|
+
}
|
|
4885
|
+
if (current.parent) {
|
|
4886
|
+
slVer = current.snapshotLocalVersion;
|
|
4887
|
+
current = current.parent;
|
|
4888
|
+
} else {
|
|
4889
|
+
return current._diskExists(key, snapshotVersion);
|
|
4878
4890
|
}
|
|
4879
4891
|
}
|
|
4880
|
-
|
|
4881
|
-
return this.parent._existsSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
|
|
4882
|
-
} else {
|
|
4883
|
-
return this._diskExists(key, snapshotVersion);
|
|
4884
|
-
}
|
|
4892
|
+
return false;
|
|
4885
4893
|
}
|
|
4886
4894
|
_readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
4895
|
+
let current = this;
|
|
4896
|
+
let slVer = snapshotLocalVersion;
|
|
4897
|
+
while (current) {
|
|
4898
|
+
if (current.writeBuffer.has(key)) {
|
|
4899
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
4900
|
+
if (slVer === void 0 || keyModVersion <= slVer) {
|
|
4901
|
+
return current.writeBuffer.get(key);
|
|
4902
|
+
}
|
|
4891
4903
|
}
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
|
|
4904
|
+
if (current.deleteBuffer.has(key)) {
|
|
4905
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
4906
|
+
if (slVer === void 0 || keyModVersion <= slVer) {
|
|
4907
|
+
return null;
|
|
4908
|
+
}
|
|
4897
4909
|
}
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
return history[i].exists ? history[i].value : null;
|
|
4910
|
+
const history = current.bufferHistory.get(key);
|
|
4911
|
+
if (history && slVer !== void 0) {
|
|
4912
|
+
const idx = current._findLastLE(history, slVer, "version");
|
|
4913
|
+
if (idx >= 0) {
|
|
4914
|
+
return history[idx].exists ? history[idx].value : null;
|
|
4904
4915
|
}
|
|
4905
4916
|
}
|
|
4917
|
+
if (current.parent) {
|
|
4918
|
+
slVer = current.snapshotLocalVersion;
|
|
4919
|
+
current = current.parent;
|
|
4920
|
+
} else {
|
|
4921
|
+
return current._diskRead(key, snapshotVersion);
|
|
4922
|
+
}
|
|
4906
4923
|
}
|
|
4907
|
-
|
|
4908
|
-
return this.parent._readSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
|
|
4909
|
-
} else {
|
|
4910
|
-
return this._diskRead(key, snapshotVersion);
|
|
4911
|
-
}
|
|
4924
|
+
return null;
|
|
4912
4925
|
}
|
|
4913
4926
|
commit(label) {
|
|
4914
4927
|
const { created, updated, deleted } = this.getResultEntries();
|
|
4915
4928
|
if (this.committed) {
|
|
4916
|
-
return {
|
|
4929
|
+
return {
|
|
4930
|
+
label,
|
|
4931
|
+
success: false,
|
|
4932
|
+
error: "Transaction already committed",
|
|
4933
|
+
conflict: void 0,
|
|
4934
|
+
created,
|
|
4935
|
+
updated,
|
|
4936
|
+
deleted
|
|
4937
|
+
};
|
|
4917
4938
|
}
|
|
4918
4939
|
if (this.hasCommittedAncestor()) {
|
|
4919
|
-
return {
|
|
4940
|
+
return {
|
|
4941
|
+
label,
|
|
4942
|
+
success: false,
|
|
4943
|
+
error: "Ancestor transaction already committed",
|
|
4944
|
+
conflict: void 0,
|
|
4945
|
+
created,
|
|
4946
|
+
updated,
|
|
4947
|
+
deleted
|
|
4948
|
+
};
|
|
4920
4949
|
}
|
|
4921
4950
|
if (this.parent) {
|
|
4922
4951
|
const failure = this.parent._merge(this);
|
|
4923
4952
|
if (failure) {
|
|
4924
|
-
return {
|
|
4953
|
+
return {
|
|
4954
|
+
label,
|
|
4955
|
+
success: false,
|
|
4956
|
+
error: failure.error,
|
|
4957
|
+
conflict: failure.conflict,
|
|
4958
|
+
created,
|
|
4959
|
+
updated,
|
|
4960
|
+
deleted
|
|
4961
|
+
};
|
|
4925
4962
|
}
|
|
4926
4963
|
this.committed = true;
|
|
4927
4964
|
} else {
|
|
4928
4965
|
if (this.writeBuffer.size > 0 || this.deleteBuffer.size > 0) {
|
|
4929
4966
|
const failure = this._merge(this);
|
|
4930
4967
|
if (failure) {
|
|
4931
|
-
return {
|
|
4968
|
+
return {
|
|
4969
|
+
label,
|
|
4970
|
+
success: false,
|
|
4971
|
+
error: failure.error,
|
|
4972
|
+
conflict: failure.conflict,
|
|
4973
|
+
created: [],
|
|
4974
|
+
updated: [],
|
|
4975
|
+
deleted: []
|
|
4976
|
+
};
|
|
4932
4977
|
}
|
|
4933
4978
|
this.writeBuffer.clear();
|
|
4934
4979
|
this.deleteBuffer.clear();
|
|
@@ -4941,7 +4986,13 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
|
|
|
4941
4986
|
this.snapshotVersion = this.version;
|
|
4942
4987
|
}
|
|
4943
4988
|
}
|
|
4944
|
-
return {
|
|
4989
|
+
return {
|
|
4990
|
+
label,
|
|
4991
|
+
success: true,
|
|
4992
|
+
created,
|
|
4993
|
+
updated,
|
|
4994
|
+
deleted
|
|
4995
|
+
};
|
|
4945
4996
|
}
|
|
4946
4997
|
_merge(child) {
|
|
4947
4998
|
if (this.parent) {
|
|
@@ -4950,7 +5001,11 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
|
|
|
4950
5001
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
4951
5002
|
return {
|
|
4952
5003
|
error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
|
|
4953
|
-
conflict: {
|
|
5004
|
+
conflict: {
|
|
5005
|
+
key,
|
|
5006
|
+
parent: this.read(key),
|
|
5007
|
+
child: child.read(key)
|
|
5008
|
+
}
|
|
4954
5009
|
};
|
|
4955
5010
|
}
|
|
4956
5011
|
}
|
|
@@ -4959,7 +5014,11 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
|
|
|
4959
5014
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
4960
5015
|
return {
|
|
4961
5016
|
error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
|
|
4962
|
-
conflict: {
|
|
5017
|
+
conflict: {
|
|
5018
|
+
key,
|
|
5019
|
+
parent: this.read(key),
|
|
5020
|
+
child: child.read(key)
|
|
5021
|
+
}
|
|
4963
5022
|
};
|
|
4964
5023
|
}
|
|
4965
5024
|
}
|
|
@@ -4988,7 +5047,11 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
|
|
|
4988
5047
|
if (lastVer > child.snapshotVersion) {
|
|
4989
5048
|
return {
|
|
4990
5049
|
error: `Commit conflict: Key '${key}' was modified by a newer transaction (v${lastVer})`,
|
|
4991
|
-
conflict: {
|
|
5050
|
+
conflict: {
|
|
5051
|
+
key,
|
|
5052
|
+
parent: this.read(key),
|
|
5053
|
+
child: child.read(key)
|
|
5054
|
+
}
|
|
4992
5055
|
};
|
|
4993
5056
|
}
|
|
4994
5057
|
}
|
|
@@ -4996,7 +5059,11 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
|
|
|
4996
5059
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
4997
5060
|
return {
|
|
4998
5061
|
error: `Commit conflict: Key '${key}' was modified by a newer transaction in the same session (Local v${lastModLocalVer})`,
|
|
4999
|
-
conflict: {
|
|
5062
|
+
conflict: {
|
|
5063
|
+
key,
|
|
5064
|
+
parent: this.read(key),
|
|
5065
|
+
child: child.read(key)
|
|
5066
|
+
}
|
|
5000
5067
|
};
|
|
5001
5068
|
}
|
|
5002
5069
|
}
|
|
@@ -5031,10 +5098,14 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
|
|
|
5031
5098
|
_diskWrite(key, value, version) {
|
|
5032
5099
|
const strategy = this.strategy;
|
|
5033
5100
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
5034
|
-
|
|
5035
|
-
|
|
5101
|
+
const rootAsAny = this.root;
|
|
5102
|
+
if (this._diskExists(key, version)) {
|
|
5103
|
+
const currentVal = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : strategy.read(key);
|
|
5036
5104
|
if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
|
|
5037
5105
|
this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: version });
|
|
5106
|
+
rootAsAny.diskCache.set(key, value);
|
|
5107
|
+
} else {
|
|
5108
|
+
rootAsAny.diskCache.set(key, value);
|
|
5038
5109
|
}
|
|
5039
5110
|
strategy.write(key, value);
|
|
5040
5111
|
if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
|
|
@@ -5045,23 +5116,25 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
|
|
|
5045
5116
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
5046
5117
|
const versions = this.versionIndex.get(key);
|
|
5047
5118
|
if (!versions) {
|
|
5048
|
-
|
|
5119
|
+
const rootAsAny = this.root;
|
|
5120
|
+
if (this._diskExists(key, snapshotVersion)) {
|
|
5121
|
+
const val = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : strategy.read(key);
|
|
5122
|
+
rootAsAny.diskCache.set(key, val);
|
|
5123
|
+
return val;
|
|
5124
|
+
}
|
|
5125
|
+
return null;
|
|
5049
5126
|
}
|
|
5050
5127
|
let targetVerObj = null;
|
|
5051
5128
|
let nextVerObj = null;
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
nextVerObj = v;
|
|
5056
|
-
break;
|
|
5057
|
-
}
|
|
5058
|
-
}
|
|
5129
|
+
const idx = this._findLastLE(versions, snapshotVersion, "version");
|
|
5130
|
+
if (idx >= 0) targetVerObj = versions[idx];
|
|
5131
|
+
if (idx + 1 < versions.length) nextVerObj = versions[idx + 1];
|
|
5059
5132
|
if (!targetVerObj) {
|
|
5060
5133
|
if (nextVerObj) {
|
|
5061
5134
|
const cached2 = this.deletedCache.get(key);
|
|
5062
5135
|
if (cached2) {
|
|
5063
|
-
const
|
|
5064
|
-
if (
|
|
5136
|
+
const cIdx = this._findExact(cached2, nextVerObj.version, "deletedAtVersion");
|
|
5137
|
+
if (cIdx >= 0) return cached2[cIdx].value;
|
|
5065
5138
|
}
|
|
5066
5139
|
}
|
|
5067
5140
|
return null;
|
|
@@ -5069,12 +5142,18 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
|
|
|
5069
5142
|
if (!targetVerObj.exists) return null;
|
|
5070
5143
|
if (!nextVerObj) {
|
|
5071
5144
|
if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
|
|
5072
|
-
|
|
5145
|
+
if (this._diskExists(key, snapshotVersion)) {
|
|
5146
|
+
const rootAsAny = this.root;
|
|
5147
|
+
const val = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : strategy.read(key);
|
|
5148
|
+
rootAsAny.diskCache.set(key, val);
|
|
5149
|
+
return val;
|
|
5150
|
+
}
|
|
5151
|
+
return null;
|
|
5073
5152
|
}
|
|
5074
5153
|
const cached = this.deletedCache.get(key);
|
|
5075
5154
|
if (cached) {
|
|
5076
|
-
const
|
|
5077
|
-
if (
|
|
5155
|
+
const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
|
|
5156
|
+
if (cIdx >= 0) return cached[cIdx].value;
|
|
5078
5157
|
}
|
|
5079
5158
|
return null;
|
|
5080
5159
|
}
|
|
@@ -5083,23 +5162,23 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
|
|
|
5083
5162
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
5084
5163
|
const versions = this.versionIndex.get(key);
|
|
5085
5164
|
if (!versions) {
|
|
5086
|
-
|
|
5165
|
+
const rootAsAny = this.root;
|
|
5166
|
+
if (rootAsAny.diskCache.has(key)) return rootAsAny.diskCache.get(key) !== null;
|
|
5167
|
+
const exists = strategy.exists(key);
|
|
5168
|
+
if (!exists) rootAsAny.diskCache.set(key, null);
|
|
5169
|
+
return exists;
|
|
5087
5170
|
}
|
|
5088
5171
|
let targetVerObj = null;
|
|
5089
5172
|
let nextVerObj = null;
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
nextVerObj = v;
|
|
5094
|
-
break;
|
|
5095
|
-
}
|
|
5096
|
-
}
|
|
5173
|
+
const idx = this._findLastLE(versions, snapshotVersion, "version");
|
|
5174
|
+
if (idx >= 0) targetVerObj = versions[idx];
|
|
5175
|
+
if (idx + 1 < versions.length) nextVerObj = versions[idx + 1];
|
|
5097
5176
|
if (!targetVerObj) {
|
|
5098
5177
|
if (nextVerObj) {
|
|
5099
5178
|
const cached = this.deletedCache.get(key);
|
|
5100
5179
|
if (cached) {
|
|
5101
|
-
const
|
|
5102
|
-
if (
|
|
5180
|
+
const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
|
|
5181
|
+
if (cIdx >= 0) return true;
|
|
5103
5182
|
}
|
|
5104
5183
|
}
|
|
5105
5184
|
return false;
|
|
@@ -5109,11 +5188,13 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
|
|
|
5109
5188
|
_diskDelete(key, snapshotVersion) {
|
|
5110
5189
|
const strategy = this.strategy;
|
|
5111
5190
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
5112
|
-
|
|
5113
|
-
|
|
5191
|
+
const rootAsAny = this.root;
|
|
5192
|
+
if (this._diskExists(key, snapshotVersion)) {
|
|
5193
|
+
const currentVal = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : strategy.read(key);
|
|
5114
5194
|
if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
|
|
5115
5195
|
this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: snapshotVersion });
|
|
5116
5196
|
strategy.delete(key);
|
|
5197
|
+
rootAsAny.diskCache.delete(key);
|
|
5117
5198
|
}
|
|
5118
5199
|
if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
|
|
5119
5200
|
this.versionIndex.get(key).push({ version: snapshotVersion, exists: false });
|
|
@@ -5427,7 +5508,7 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
|
|
|
5427
5508
|
createNested() {
|
|
5428
5509
|
if (this.committed) throw new Error("Transaction already committed");
|
|
5429
5510
|
const childVersion = this.isRoot() ? this.version : this.snapshotVersion;
|
|
5430
|
-
const child = new _AsyncMVCCTransaction2(void 0, this, childVersion);
|
|
5511
|
+
const child = new _AsyncMVCCTransaction2(void 0, void 0, this, childVersion);
|
|
5431
5512
|
this.root.activeTransactions.add(child);
|
|
5432
5513
|
return child;
|
|
5433
5514
|
}
|
|
@@ -5450,78 +5531,114 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
|
|
|
5450
5531
|
return await this._diskExists(key, this.snapshotVersion);
|
|
5451
5532
|
}
|
|
5452
5533
|
async _existsSnapshot(key, snapshotVersion, snapshotLocalVersion) {
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
return false;
|
|
5463
|
-
}
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5534
|
+
let current = this;
|
|
5535
|
+
let slVer = snapshotLocalVersion;
|
|
5536
|
+
while (current) {
|
|
5537
|
+
if (current.writeBuffer.has(key)) {
|
|
5538
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
5539
|
+
if (slVer === void 0 || keyModVersion <= slVer) return true;
|
|
5540
|
+
}
|
|
5541
|
+
if (current.deleteBuffer.has(key)) {
|
|
5542
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
5543
|
+
if (slVer === void 0 || keyModVersion <= slVer) return false;
|
|
5544
|
+
}
|
|
5545
|
+
const history = current.bufferHistory.get(key);
|
|
5546
|
+
if (history && slVer !== void 0) {
|
|
5547
|
+
const idx = current._findLastLE(history, slVer, "version");
|
|
5548
|
+
if (idx >= 0) return history[idx].exists;
|
|
5549
|
+
}
|
|
5550
|
+
if (current.parent) {
|
|
5551
|
+
slVer = current.snapshotLocalVersion;
|
|
5552
|
+
current = current.parent;
|
|
5553
|
+
} else {
|
|
5554
|
+
return await current._diskExists(key, snapshotVersion);
|
|
5471
5555
|
}
|
|
5472
5556
|
}
|
|
5473
|
-
|
|
5474
|
-
return this.parent._existsSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
|
|
5475
|
-
} else {
|
|
5476
|
-
return await this._diskExists(key, snapshotVersion);
|
|
5477
|
-
}
|
|
5557
|
+
return false;
|
|
5478
5558
|
}
|
|
5479
5559
|
async _readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5560
|
+
let current = this;
|
|
5561
|
+
let slVer = snapshotLocalVersion;
|
|
5562
|
+
while (current) {
|
|
5563
|
+
if (current.writeBuffer.has(key)) {
|
|
5564
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
5565
|
+
if (slVer === void 0 || keyModVersion <= slVer) {
|
|
5566
|
+
return current.writeBuffer.get(key);
|
|
5567
|
+
}
|
|
5484
5568
|
}
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5569
|
+
if (current.deleteBuffer.has(key)) {
|
|
5570
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
5571
|
+
if (slVer === void 0 || keyModVersion <= slVer) {
|
|
5572
|
+
return null;
|
|
5573
|
+
}
|
|
5490
5574
|
}
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
return history[i].exists ? history[i].value : null;
|
|
5575
|
+
const history = current.bufferHistory.get(key);
|
|
5576
|
+
if (history && slVer !== void 0) {
|
|
5577
|
+
const idx = current._findLastLE(history, slVer, "version");
|
|
5578
|
+
if (idx >= 0) {
|
|
5579
|
+
return history[idx].exists ? history[idx].value : null;
|
|
5497
5580
|
}
|
|
5498
5581
|
}
|
|
5582
|
+
if (current.parent) {
|
|
5583
|
+
slVer = current.snapshotLocalVersion;
|
|
5584
|
+
current = current.parent;
|
|
5585
|
+
} else {
|
|
5586
|
+
return await current._diskRead(key, snapshotVersion);
|
|
5587
|
+
}
|
|
5499
5588
|
}
|
|
5500
|
-
|
|
5501
|
-
return this.parent._readSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
|
|
5502
|
-
} else {
|
|
5503
|
-
return await this._diskRead(key, snapshotVersion);
|
|
5504
|
-
}
|
|
5589
|
+
return null;
|
|
5505
5590
|
}
|
|
5506
5591
|
async commit(label) {
|
|
5507
5592
|
const { created, updated, deleted } = this.getResultEntries();
|
|
5508
5593
|
if (this.committed) {
|
|
5509
|
-
return {
|
|
5594
|
+
return {
|
|
5595
|
+
label,
|
|
5596
|
+
success: false,
|
|
5597
|
+
error: "Transaction already committed",
|
|
5598
|
+
conflict: void 0,
|
|
5599
|
+
created,
|
|
5600
|
+
updated,
|
|
5601
|
+
deleted
|
|
5602
|
+
};
|
|
5510
5603
|
}
|
|
5511
5604
|
if (this.hasCommittedAncestor()) {
|
|
5512
|
-
return {
|
|
5605
|
+
return {
|
|
5606
|
+
label,
|
|
5607
|
+
success: false,
|
|
5608
|
+
error: "Ancestor transaction already committed",
|
|
5609
|
+
conflict: void 0,
|
|
5610
|
+
created,
|
|
5611
|
+
updated,
|
|
5612
|
+
deleted
|
|
5613
|
+
};
|
|
5513
5614
|
}
|
|
5514
5615
|
if (this.parent) {
|
|
5515
5616
|
const failure = await this.parent._merge(this);
|
|
5516
5617
|
if (failure) {
|
|
5517
|
-
return {
|
|
5618
|
+
return {
|
|
5619
|
+
label,
|
|
5620
|
+
success: false,
|
|
5621
|
+
error: failure.error,
|
|
5622
|
+
conflict: failure.conflict,
|
|
5623
|
+
created,
|
|
5624
|
+
updated,
|
|
5625
|
+
deleted
|
|
5626
|
+
};
|
|
5518
5627
|
}
|
|
5519
5628
|
this.committed = true;
|
|
5520
5629
|
} else {
|
|
5521
5630
|
if (this.writeBuffer.size > 0 || this.deleteBuffer.size > 0) {
|
|
5522
5631
|
const failure = await this._merge(this);
|
|
5523
5632
|
if (failure) {
|
|
5524
|
-
return {
|
|
5633
|
+
return {
|
|
5634
|
+
label,
|
|
5635
|
+
success: false,
|
|
5636
|
+
error: failure.error,
|
|
5637
|
+
conflict: failure.conflict,
|
|
5638
|
+
created: [],
|
|
5639
|
+
updated: [],
|
|
5640
|
+
deleted: []
|
|
5641
|
+
};
|
|
5525
5642
|
}
|
|
5526
5643
|
this.writeBuffer.clear();
|
|
5527
5644
|
this.deleteBuffer.clear();
|
|
@@ -5534,7 +5651,13 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
|
|
|
5534
5651
|
this.snapshotVersion = this.version;
|
|
5535
5652
|
}
|
|
5536
5653
|
}
|
|
5537
|
-
return {
|
|
5654
|
+
return {
|
|
5655
|
+
label,
|
|
5656
|
+
success: true,
|
|
5657
|
+
created,
|
|
5658
|
+
updated,
|
|
5659
|
+
deleted
|
|
5660
|
+
};
|
|
5538
5661
|
}
|
|
5539
5662
|
async _merge(child) {
|
|
5540
5663
|
return this.writeLock(async () => {
|
|
@@ -5544,7 +5667,11 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
|
|
|
5544
5667
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
5545
5668
|
return {
|
|
5546
5669
|
error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
|
|
5547
|
-
conflict: {
|
|
5670
|
+
conflict: {
|
|
5671
|
+
key,
|
|
5672
|
+
parent: await this.read(key),
|
|
5673
|
+
child: await child.read(key)
|
|
5674
|
+
}
|
|
5548
5675
|
};
|
|
5549
5676
|
}
|
|
5550
5677
|
}
|
|
@@ -5553,7 +5680,11 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
|
|
|
5553
5680
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
5554
5681
|
return {
|
|
5555
5682
|
error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
|
|
5556
|
-
conflict: {
|
|
5683
|
+
conflict: {
|
|
5684
|
+
key,
|
|
5685
|
+
parent: await this.read(key),
|
|
5686
|
+
child: await child.read(key)
|
|
5687
|
+
}
|
|
5557
5688
|
};
|
|
5558
5689
|
}
|
|
5559
5690
|
}
|
|
@@ -5583,7 +5714,11 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
|
|
|
5583
5714
|
if (lastVer > child.snapshotVersion) {
|
|
5584
5715
|
return {
|
|
5585
5716
|
error: `Commit conflict: Key '${key}' was modified by a newer transaction (v${lastVer})`,
|
|
5586
|
-
conflict: {
|
|
5717
|
+
conflict: {
|
|
5718
|
+
key,
|
|
5719
|
+
parent: await this.read(key),
|
|
5720
|
+
child: await child.read(key)
|
|
5721
|
+
}
|
|
5587
5722
|
};
|
|
5588
5723
|
}
|
|
5589
5724
|
}
|
|
@@ -5591,7 +5726,11 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
|
|
|
5591
5726
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
5592
5727
|
return {
|
|
5593
5728
|
error: `Commit conflict: Key '${key}' was modified by a newer transaction in the same session (Local v${lastModLocalVer})`,
|
|
5594
|
-
conflict: {
|
|
5729
|
+
conflict: {
|
|
5730
|
+
key,
|
|
5731
|
+
parent: await this.read(key),
|
|
5732
|
+
child: await child.read(key)
|
|
5733
|
+
}
|
|
5595
5734
|
};
|
|
5596
5735
|
}
|
|
5597
5736
|
}
|
|
@@ -5627,10 +5766,14 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
|
|
|
5627
5766
|
async _diskWrite(key, value, version) {
|
|
5628
5767
|
const strategy = this.strategy;
|
|
5629
5768
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
5630
|
-
|
|
5631
|
-
|
|
5769
|
+
const rootAsAny = this.root;
|
|
5770
|
+
if (await this._diskExists(key, version)) {
|
|
5771
|
+
const currentVal = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : await strategy.read(key);
|
|
5632
5772
|
if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
|
|
5633
5773
|
this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: version });
|
|
5774
|
+
rootAsAny.diskCache.set(key, value);
|
|
5775
|
+
} else {
|
|
5776
|
+
rootAsAny.diskCache.set(key, value);
|
|
5634
5777
|
}
|
|
5635
5778
|
await strategy.write(key, value);
|
|
5636
5779
|
if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
|
|
@@ -5641,23 +5784,25 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
|
|
|
5641
5784
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
5642
5785
|
const versions = this.versionIndex.get(key);
|
|
5643
5786
|
if (!versions) {
|
|
5644
|
-
|
|
5787
|
+
const rootAsAny = this.root;
|
|
5788
|
+
if (await this._diskExists(key, snapshotVersion)) {
|
|
5789
|
+
const val = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : await strategy.read(key);
|
|
5790
|
+
rootAsAny.diskCache.set(key, val);
|
|
5791
|
+
return val;
|
|
5792
|
+
}
|
|
5793
|
+
return null;
|
|
5645
5794
|
}
|
|
5646
5795
|
let targetVerObj = null;
|
|
5647
5796
|
let nextVerObj = null;
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
nextVerObj = v;
|
|
5652
|
-
break;
|
|
5653
|
-
}
|
|
5654
|
-
}
|
|
5797
|
+
const idx = this._findLastLE(versions, snapshotVersion, "version");
|
|
5798
|
+
if (idx >= 0) targetVerObj = versions[idx];
|
|
5799
|
+
if (idx + 1 < versions.length) nextVerObj = versions[idx + 1];
|
|
5655
5800
|
if (!targetVerObj) {
|
|
5656
5801
|
if (nextVerObj) {
|
|
5657
5802
|
const cached2 = this.deletedCache.get(key);
|
|
5658
5803
|
if (cached2) {
|
|
5659
|
-
const
|
|
5660
|
-
if (
|
|
5804
|
+
const cIdx = this._findExact(cached2, nextVerObj.version, "deletedAtVersion");
|
|
5805
|
+
if (cIdx >= 0) return cached2[cIdx].value;
|
|
5661
5806
|
}
|
|
5662
5807
|
}
|
|
5663
5808
|
return null;
|
|
@@ -5665,12 +5810,18 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
|
|
|
5665
5810
|
if (!targetVerObj.exists) return null;
|
|
5666
5811
|
if (!nextVerObj) {
|
|
5667
5812
|
if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
|
|
5668
|
-
|
|
5813
|
+
if (await this._diskExists(key, snapshotVersion)) {
|
|
5814
|
+
const rootAsAny = this.root;
|
|
5815
|
+
const val = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : await strategy.read(key);
|
|
5816
|
+
rootAsAny.diskCache.set(key, val);
|
|
5817
|
+
return val;
|
|
5818
|
+
}
|
|
5819
|
+
return null;
|
|
5669
5820
|
}
|
|
5670
5821
|
const cached = this.deletedCache.get(key);
|
|
5671
5822
|
if (cached) {
|
|
5672
|
-
const
|
|
5673
|
-
if (
|
|
5823
|
+
const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
|
|
5824
|
+
if (cIdx >= 0) return cached[cIdx].value;
|
|
5674
5825
|
}
|
|
5675
5826
|
return null;
|
|
5676
5827
|
}
|
|
@@ -5679,23 +5830,23 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
|
|
|
5679
5830
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
5680
5831
|
const versions = this.versionIndex.get(key);
|
|
5681
5832
|
if (!versions) {
|
|
5682
|
-
|
|
5833
|
+
const rootAsAny = this.root;
|
|
5834
|
+
if (rootAsAny.diskCache.has(key)) return rootAsAny.diskCache.get(key) !== null;
|
|
5835
|
+
const exists = await strategy.exists(key);
|
|
5836
|
+
if (!exists) rootAsAny.diskCache.set(key, null);
|
|
5837
|
+
return exists;
|
|
5683
5838
|
}
|
|
5684
5839
|
let targetVerObj = null;
|
|
5685
5840
|
let nextVerObj = null;
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
nextVerObj = v;
|
|
5690
|
-
break;
|
|
5691
|
-
}
|
|
5692
|
-
}
|
|
5841
|
+
const idx = this._findLastLE(versions, snapshotVersion, "version");
|
|
5842
|
+
if (idx >= 0) targetVerObj = versions[idx];
|
|
5843
|
+
if (idx + 1 < versions.length) nextVerObj = versions[idx + 1];
|
|
5693
5844
|
if (!targetVerObj) {
|
|
5694
5845
|
if (nextVerObj) {
|
|
5695
5846
|
const cached = this.deletedCache.get(key);
|
|
5696
5847
|
if (cached) {
|
|
5697
|
-
const
|
|
5698
|
-
if (
|
|
5848
|
+
const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
|
|
5849
|
+
if (cIdx >= 0) return true;
|
|
5699
5850
|
}
|
|
5700
5851
|
}
|
|
5701
5852
|
return false;
|
|
@@ -5705,11 +5856,13 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
|
|
|
5705
5856
|
async _diskDelete(key, snapshotVersion) {
|
|
5706
5857
|
const strategy = this.strategy;
|
|
5707
5858
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
5708
|
-
|
|
5709
|
-
|
|
5859
|
+
const rootAsAny = this.root;
|
|
5860
|
+
if (await this._diskExists(key, snapshotVersion)) {
|
|
5861
|
+
const currentVal = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : await strategy.read(key);
|
|
5710
5862
|
if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
|
|
5711
5863
|
this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: snapshotVersion });
|
|
5712
5864
|
await strategy.delete(key);
|
|
5865
|
+
rootAsAny.diskCache.delete(key);
|
|
5713
5866
|
}
|
|
5714
5867
|
if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
|
|
5715
5868
|
this.versionIndex.get(key).push({ version: snapshotVersion, exists: false });
|