dataply 0.0.22-alpha.0 → 0.0.22-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.js +1125 -970
- package/package.json +4 -4
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
|
}
|
|
@@ -1203,366 +1446,47 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
1203
1446
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
1204
1447
|
const versions = this.versionIndex.get(key);
|
|
1205
1448
|
if (!versions) {
|
|
1206
|
-
|
|
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;
|
|
1207
1454
|
}
|
|
1208
1455
|
let targetVerObj = null;
|
|
1209
1456
|
let nextVerObj = null;
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
nextVerObj = v;
|
|
1214
|
-
break;
|
|
1215
|
-
}
|
|
1216
|
-
}
|
|
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];
|
|
1217
1460
|
if (!targetVerObj) {
|
|
1218
1461
|
if (nextVerObj) {
|
|
1219
1462
|
const cached = this.deletedCache.get(key);
|
|
1220
1463
|
if (cached) {
|
|
1221
|
-
const
|
|
1222
|
-
if (
|
|
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);
|
|
1464
|
+
const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
|
|
1465
|
+
if (cIdx >= 0) return true;
|
|
1460
1466
|
}
|
|
1461
1467
|
}
|
|
1468
|
+
return false;
|
|
1462
1469
|
}
|
|
1470
|
+
return targetVerObj.exists;
|
|
1463
1471
|
}
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
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}`);
|
|
1548
|
-
}
|
|
1549
|
-
return this.cache(key, ...this.parameters.get(key));
|
|
1550
|
-
}
|
|
1551
|
-
cache(key, ...parameter) {
|
|
1552
|
-
if (!this.caches.has(key) || this.updateRequirements.has(key)) {
|
|
1553
|
-
this.resolve(key, ...parameter);
|
|
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);
|
|
1554
1482
|
}
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
update(key, ...parameter) {
|
|
1558
|
-
this.bubbleUpdateSignal(key);
|
|
1559
|
-
this.resolve(key, ...parameter);
|
|
1560
|
-
return this.caches.get(key);
|
|
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
|
}
|
|
@@ -2586,15 +2503,6 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2586
2503
|
}
|
|
2587
2504
|
}
|
|
2588
2505
|
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
2506
|
}
|
|
2599
2507
|
}
|
|
2600
2508
|
return result;
|
|
@@ -2638,7 +2546,9 @@ var BPTreeMVCCStrategySync = class extends SyncMVCCStrategy {
|
|
|
2638
2546
|
};
|
|
2639
2547
|
var BPTreeSync = class extends BPTreeSyncTransaction {
|
|
2640
2548
|
constructor(strategy, comparator, option) {
|
|
2641
|
-
const mvccRoot = new SyncMVCCTransaction(new BPTreeMVCCStrategySync(strategy)
|
|
2549
|
+
const mvccRoot = new SyncMVCCTransaction(new BPTreeMVCCStrategySync(strategy), {
|
|
2550
|
+
cacheCapacity: option?.capacity ?? void 0
|
|
2551
|
+
});
|
|
2642
2552
|
super(
|
|
2643
2553
|
null,
|
|
2644
2554
|
mvccRoot,
|
|
@@ -2961,9 +2871,6 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
2961
2871
|
});
|
|
2962
2872
|
}
|
|
2963
2873
|
async getNode(id) {
|
|
2964
|
-
if (this.nodes.has(id)) {
|
|
2965
|
-
return this.nodes.get(id);
|
|
2966
|
-
}
|
|
2967
2874
|
return await this.mvcc.read(id);
|
|
2968
2875
|
}
|
|
2969
2876
|
/**
|
|
@@ -2980,24 +2887,31 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
2980
2887
|
next,
|
|
2981
2888
|
prev
|
|
2982
2889
|
};
|
|
2890
|
+
const head = await this._readHead();
|
|
2891
|
+
if (head) {
|
|
2892
|
+
await this._writeHead({
|
|
2893
|
+
root: head.root,
|
|
2894
|
+
order: head.order,
|
|
2895
|
+
data: this.strategy.head.data
|
|
2896
|
+
});
|
|
2897
|
+
}
|
|
2983
2898
|
await this.mvcc.create(id, node);
|
|
2984
|
-
this.nodes.set(id, node);
|
|
2985
2899
|
return node;
|
|
2986
2900
|
}
|
|
2987
2901
|
async _updateNode(node) {
|
|
2902
|
+
if (this.mvcc.isDeleted(node.id)) {
|
|
2903
|
+
return;
|
|
2904
|
+
}
|
|
2988
2905
|
await this.mvcc.write(node.id, node);
|
|
2989
|
-
this.nodes.set(node.id, node);
|
|
2990
2906
|
}
|
|
2991
2907
|
async _deleteNode(node) {
|
|
2908
|
+
if (this.mvcc.isDeleted(node.id)) {
|
|
2909
|
+
return;
|
|
2910
|
+
}
|
|
2992
2911
|
await this.mvcc.delete(node.id);
|
|
2993
|
-
this.nodes.delete(node.id);
|
|
2994
2912
|
}
|
|
2995
2913
|
async _readHead() {
|
|
2996
|
-
|
|
2997
|
-
return this.nodes.get("__HEAD__") ?? null;
|
|
2998
|
-
}
|
|
2999
|
-
const head = await this.mvcc.read("__HEAD__");
|
|
3000
|
-
return head ?? null;
|
|
2914
|
+
return await this.mvcc.read("__HEAD__");
|
|
3001
2915
|
}
|
|
3002
2916
|
async _writeHead(head) {
|
|
3003
2917
|
if (!await this.mvcc.exists("__HEAD__")) {
|
|
@@ -3005,49 +2919,56 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3005
2919
|
} else {
|
|
3006
2920
|
await this.mvcc.write("__HEAD__", head);
|
|
3007
2921
|
}
|
|
3008
|
-
this.nodes.set("__HEAD__", head);
|
|
3009
2922
|
this.rootId = head.root;
|
|
3010
2923
|
}
|
|
3011
2924
|
async _insertAtLeaf(node, key, value) {
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
2925
|
+
let leaf = node;
|
|
2926
|
+
if (leaf.values.length) {
|
|
2927
|
+
for (let i = 0, len = leaf.values.length; i < len; i++) {
|
|
2928
|
+
const nValue = leaf.values[i];
|
|
3015
2929
|
if (this.comparator.isSame(value, nValue)) {
|
|
3016
|
-
const keys =
|
|
2930
|
+
const keys = leaf.keys[i];
|
|
3017
2931
|
if (keys.includes(key)) {
|
|
3018
2932
|
break;
|
|
3019
2933
|
}
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
2934
|
+
leaf = this._cloneNode(leaf);
|
|
2935
|
+
leaf.keys[i].push(key);
|
|
2936
|
+
await this._updateNode(leaf);
|
|
2937
|
+
return leaf;
|
|
3023
2938
|
} else if (this.comparator.isLower(value, nValue)) {
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
2939
|
+
leaf = this._cloneNode(leaf);
|
|
2940
|
+
leaf.values.splice(i, 0, value);
|
|
2941
|
+
leaf.keys.splice(i, 0, [key]);
|
|
2942
|
+
await this._updateNode(leaf);
|
|
2943
|
+
return leaf;
|
|
2944
|
+
} else if (i + 1 === leaf.values.length) {
|
|
2945
|
+
leaf = this._cloneNode(leaf);
|
|
2946
|
+
leaf.values.push(value);
|
|
2947
|
+
leaf.keys.push([key]);
|
|
2948
|
+
await this._updateNode(leaf);
|
|
2949
|
+
return leaf;
|
|
3033
2950
|
}
|
|
3034
2951
|
}
|
|
3035
2952
|
} else {
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
2953
|
+
leaf = this._cloneNode(leaf);
|
|
2954
|
+
leaf.values = [value];
|
|
2955
|
+
leaf.keys = [[key]];
|
|
2956
|
+
await this._updateNode(leaf);
|
|
2957
|
+
return leaf;
|
|
3040
2958
|
}
|
|
2959
|
+
return leaf;
|
|
3041
2960
|
}
|
|
3042
|
-
async _insertInParent(node, value,
|
|
2961
|
+
async _insertInParent(node, value, newSiblingNode) {
|
|
3043
2962
|
if (this.rootId === node.id) {
|
|
3044
|
-
|
|
2963
|
+
node = this._cloneNode(node);
|
|
2964
|
+
newSiblingNode = this._cloneNode(newSiblingNode);
|
|
2965
|
+
const root = await this._createNode(false, [node.id, newSiblingNode.id], [value]);
|
|
3045
2966
|
this.rootId = root.id;
|
|
3046
2967
|
node.parent = root.id;
|
|
3047
|
-
|
|
3048
|
-
if (
|
|
3049
|
-
node.next =
|
|
3050
|
-
|
|
2968
|
+
newSiblingNode.parent = root.id;
|
|
2969
|
+
if (newSiblingNode.leaf) {
|
|
2970
|
+
node.next = newSiblingNode.id;
|
|
2971
|
+
newSiblingNode.prev = node.id;
|
|
3051
2972
|
}
|
|
3052
2973
|
await this._writeHead({
|
|
3053
2974
|
root: root.id,
|
|
@@ -3055,53 +2976,54 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3055
2976
|
data: this.strategy.head.data
|
|
3056
2977
|
});
|
|
3057
2978
|
await this._updateNode(node);
|
|
3058
|
-
await this._updateNode(
|
|
2979
|
+
await this._updateNode(newSiblingNode);
|
|
3059
2980
|
return;
|
|
3060
2981
|
}
|
|
3061
|
-
const parentNode = await this.getNode(node.parent);
|
|
2982
|
+
const parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
3062
2983
|
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
3063
2984
|
if (nodeIndex === -1) {
|
|
3064
2985
|
throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
|
|
3065
2986
|
}
|
|
3066
2987
|
parentNode.values.splice(nodeIndex, 0, value);
|
|
3067
|
-
parentNode.keys.splice(nodeIndex + 1, 0,
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
2988
|
+
parentNode.keys.splice(nodeIndex + 1, 0, newSiblingNode.id);
|
|
2989
|
+
newSiblingNode = this._cloneNode(newSiblingNode);
|
|
2990
|
+
newSiblingNode.parent = parentNode.id;
|
|
2991
|
+
if (newSiblingNode.leaf) {
|
|
2992
|
+
const leftSibling = this._cloneNode(node);
|
|
3071
2993
|
const oldNextId = leftSibling.next;
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
leftSibling.next =
|
|
2994
|
+
newSiblingNode.prev = leftSibling.id;
|
|
2995
|
+
newSiblingNode.next = oldNextId;
|
|
2996
|
+
leftSibling.next = newSiblingNode.id;
|
|
3075
2997
|
await this._updateNode(leftSibling);
|
|
3076
2998
|
if (oldNextId) {
|
|
3077
|
-
const oldNext = await this.getNode(oldNextId);
|
|
3078
|
-
oldNext.prev =
|
|
2999
|
+
const oldNext = this._cloneNode(await this.getNode(oldNextId));
|
|
3000
|
+
oldNext.prev = newSiblingNode.id;
|
|
3079
3001
|
await this._updateNode(oldNext);
|
|
3080
3002
|
}
|
|
3081
3003
|
}
|
|
3082
3004
|
await this._updateNode(parentNode);
|
|
3083
|
-
await this._updateNode(
|
|
3005
|
+
await this._updateNode(newSiblingNode);
|
|
3084
3006
|
if (parentNode.keys.length > this.order) {
|
|
3085
|
-
const
|
|
3086
|
-
|
|
3007
|
+
const newSiblingNodeRecursive = await this._createNode(false, [], []);
|
|
3008
|
+
newSiblingNodeRecursive.parent = parentNode.parent;
|
|
3087
3009
|
const mid = Math.ceil(this.order / 2) - 1;
|
|
3088
|
-
|
|
3089
|
-
|
|
3010
|
+
newSiblingNodeRecursive.values = parentNode.values.slice(mid + 1);
|
|
3011
|
+
newSiblingNodeRecursive.keys = parentNode.keys.slice(mid + 1);
|
|
3090
3012
|
const midValue = parentNode.values[mid];
|
|
3091
3013
|
parentNode.values = parentNode.values.slice(0, mid);
|
|
3092
3014
|
parentNode.keys = parentNode.keys.slice(0, mid + 1);
|
|
3093
3015
|
for (const k of parentNode.keys) {
|
|
3094
|
-
const n = await this.getNode(k);
|
|
3016
|
+
const n = this._cloneNode(await this.getNode(k));
|
|
3095
3017
|
n.parent = parentNode.id;
|
|
3096
3018
|
await this._updateNode(n);
|
|
3097
3019
|
}
|
|
3098
|
-
for (const k of
|
|
3099
|
-
const n = await this.getNode(k);
|
|
3100
|
-
n.parent =
|
|
3020
|
+
for (const k of newSiblingNodeRecursive.keys) {
|
|
3021
|
+
const n = this._cloneNode(await this.getNode(k));
|
|
3022
|
+
n.parent = newSiblingNodeRecursive.id;
|
|
3101
3023
|
await this._updateNode(n);
|
|
3102
3024
|
}
|
|
3103
3025
|
await this._updateNode(parentNode);
|
|
3104
|
-
await this._insertInParent(parentNode, midValue,
|
|
3026
|
+
await this._insertInParent(parentNode, midValue, newSiblingNodeRecursive);
|
|
3105
3027
|
}
|
|
3106
3028
|
}
|
|
3107
3029
|
async insertableNode(value) {
|
|
@@ -3290,21 +3212,6 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3290
3212
|
}
|
|
3291
3213
|
return false;
|
|
3292
3214
|
}
|
|
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
3215
|
async get(key) {
|
|
3309
3216
|
let node = await this.leftestNode();
|
|
3310
3217
|
while (true) {
|
|
@@ -3391,10 +3298,10 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3391
3298
|
}
|
|
3392
3299
|
async insert(key, value) {
|
|
3393
3300
|
return this.writeLock(0, async () => {
|
|
3394
|
-
|
|
3395
|
-
await this._insertAtLeaf(before, key, value);
|
|
3301
|
+
let before = await this.insertableNode(value);
|
|
3302
|
+
before = await this._insertAtLeaf(before, key, value);
|
|
3396
3303
|
if (before.values.length === this.order) {
|
|
3397
|
-
|
|
3304
|
+
let after = await this._createNode(
|
|
3398
3305
|
true,
|
|
3399
3306
|
[],
|
|
3400
3307
|
[],
|
|
@@ -3403,10 +3310,13 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3403
3310
|
null
|
|
3404
3311
|
);
|
|
3405
3312
|
const mid = Math.ceil(this.order / 2) - 1;
|
|
3313
|
+
after = this._cloneNode(after);
|
|
3406
3314
|
after.values = before.values.slice(mid + 1);
|
|
3407
3315
|
after.keys = before.keys.slice(mid + 1);
|
|
3408
3316
|
before.values = before.values.slice(0, mid + 1);
|
|
3409
3317
|
before.keys = before.keys.slice(0, mid + 1);
|
|
3318
|
+
await this._updateNode(before);
|
|
3319
|
+
await this._updateNode(after);
|
|
3410
3320
|
await this._insertInParent(before, after.values[0], after);
|
|
3411
3321
|
}
|
|
3412
3322
|
});
|
|
@@ -3421,6 +3331,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3421
3331
|
}
|
|
3422
3332
|
}
|
|
3423
3333
|
if (keyIndex !== -1) {
|
|
3334
|
+
node = this._cloneNode(node);
|
|
3424
3335
|
node.keys.splice(keyIndex, 1);
|
|
3425
3336
|
const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
|
|
3426
3337
|
node.values.splice(valueIndex, 1);
|
|
@@ -3430,7 +3341,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3430
3341
|
if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
|
|
3431
3342
|
const keys = node.keys;
|
|
3432
3343
|
this._deleteNode(node);
|
|
3433
|
-
const newRoot = await this.getNode(keys[0]);
|
|
3344
|
+
const newRoot = this._cloneNode(await this.getNode(keys[0]));
|
|
3434
3345
|
newRoot.parent = null;
|
|
3435
3346
|
await this._updateNode(newRoot);
|
|
3436
3347
|
await this._writeHead({
|
|
@@ -3438,14 +3349,17 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3438
3349
|
order: this.order,
|
|
3439
3350
|
data: this.strategy.head.data
|
|
3440
3351
|
});
|
|
3441
|
-
return;
|
|
3352
|
+
return node;
|
|
3442
3353
|
} else if (this.rootId === node.id) {
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3354
|
+
await this._writeHead({
|
|
3355
|
+
root: node.id,
|
|
3356
|
+
order: this.order,
|
|
3357
|
+
data: this.strategy.head.data
|
|
3358
|
+
});
|
|
3359
|
+
return node;
|
|
3446
3360
|
} else if (node.keys.length < Math.ceil(this.order / 2) && !node.leaf || node.values.length < Math.ceil((this.order - 1) / 2) && node.leaf) {
|
|
3447
3361
|
if (node.parent === null) {
|
|
3448
|
-
return;
|
|
3362
|
+
return node;
|
|
3449
3363
|
}
|
|
3450
3364
|
let isPredecessor = false;
|
|
3451
3365
|
let parentNode = await this.getNode(node.parent);
|
|
@@ -3466,78 +3380,80 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3466
3380
|
}
|
|
3467
3381
|
}
|
|
3468
3382
|
}
|
|
3469
|
-
let
|
|
3383
|
+
let siblingNode;
|
|
3470
3384
|
let guess;
|
|
3471
3385
|
if (prevNode === null) {
|
|
3472
|
-
|
|
3386
|
+
siblingNode = nextNode;
|
|
3473
3387
|
guess = postValue;
|
|
3474
3388
|
} else if (nextNode === null) {
|
|
3475
3389
|
isPredecessor = true;
|
|
3476
|
-
|
|
3390
|
+
siblingNode = prevNode;
|
|
3477
3391
|
guess = prevValue;
|
|
3478
3392
|
} else {
|
|
3479
3393
|
if (node.values.length + nextNode.values.length < this.order) {
|
|
3480
|
-
|
|
3394
|
+
siblingNode = nextNode;
|
|
3481
3395
|
guess = postValue;
|
|
3482
3396
|
} else {
|
|
3483
3397
|
isPredecessor = true;
|
|
3484
|
-
|
|
3398
|
+
siblingNode = prevNode;
|
|
3485
3399
|
guess = prevValue;
|
|
3486
3400
|
}
|
|
3487
3401
|
}
|
|
3488
|
-
if (!
|
|
3489
|
-
return;
|
|
3402
|
+
if (!siblingNode) {
|
|
3403
|
+
return node;
|
|
3490
3404
|
}
|
|
3491
|
-
|
|
3405
|
+
node = this._cloneNode(node);
|
|
3406
|
+
siblingNode = this._cloneNode(siblingNode);
|
|
3407
|
+
if (node.values.length + siblingNode.values.length < this.order) {
|
|
3492
3408
|
if (!isPredecessor) {
|
|
3493
|
-
const pTemp =
|
|
3494
|
-
|
|
3409
|
+
const pTemp = siblingNode;
|
|
3410
|
+
siblingNode = node;
|
|
3495
3411
|
node = pTemp;
|
|
3496
3412
|
}
|
|
3497
|
-
|
|
3413
|
+
siblingNode.keys.push(...node.keys);
|
|
3498
3414
|
if (!node.leaf) {
|
|
3499
|
-
|
|
3415
|
+
siblingNode.values.push(guess);
|
|
3500
3416
|
} else {
|
|
3501
|
-
|
|
3502
|
-
if (
|
|
3503
|
-
const n = await this.getNode(
|
|
3504
|
-
n.prev =
|
|
3417
|
+
siblingNode.next = node.next;
|
|
3418
|
+
if (siblingNode.next) {
|
|
3419
|
+
const n = this._cloneNode(await this.getNode(siblingNode.next));
|
|
3420
|
+
n.prev = siblingNode.id;
|
|
3505
3421
|
await this._updateNode(n);
|
|
3506
3422
|
}
|
|
3507
3423
|
}
|
|
3508
|
-
|
|
3509
|
-
if (!
|
|
3510
|
-
const keys =
|
|
3424
|
+
siblingNode.values.push(...node.values);
|
|
3425
|
+
if (!siblingNode.leaf) {
|
|
3426
|
+
const keys = siblingNode.keys;
|
|
3511
3427
|
for (const key2 of keys) {
|
|
3512
|
-
const node2 = await this.getNode(key2);
|
|
3513
|
-
node2.parent =
|
|
3428
|
+
const node2 = this._cloneNode(await this.getNode(key2));
|
|
3429
|
+
node2.parent = siblingNode.id;
|
|
3514
3430
|
await this._updateNode(node2);
|
|
3515
3431
|
}
|
|
3516
3432
|
}
|
|
3517
3433
|
this._deleteNode(node);
|
|
3518
|
-
await this._updateNode(
|
|
3434
|
+
await this._updateNode(siblingNode);
|
|
3519
3435
|
await this._deleteEntry(await this.getNode(node.parent), node.id);
|
|
3520
3436
|
} else {
|
|
3521
3437
|
if (isPredecessor) {
|
|
3522
3438
|
let pointerPm;
|
|
3523
3439
|
let pointerKm;
|
|
3524
3440
|
if (!node.leaf) {
|
|
3525
|
-
pointerPm =
|
|
3526
|
-
pointerKm =
|
|
3441
|
+
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
3442
|
+
pointerKm = siblingNode.values.splice(-1)[0];
|
|
3527
3443
|
node.keys = [pointerPm, ...node.keys];
|
|
3528
3444
|
node.values = [guess, ...node.values];
|
|
3529
|
-
parentNode = await this.getNode(node.parent);
|
|
3445
|
+
parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
3530
3446
|
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
3531
3447
|
if (nodeIndex > 0) {
|
|
3532
3448
|
parentNode.values[nodeIndex - 1] = pointerKm;
|
|
3533
3449
|
await this._updateNode(parentNode);
|
|
3534
3450
|
}
|
|
3535
3451
|
} else {
|
|
3536
|
-
pointerPm =
|
|
3537
|
-
pointerKm =
|
|
3452
|
+
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
3453
|
+
pointerKm = siblingNode.values.splice(-1)[0];
|
|
3538
3454
|
node.keys = [pointerPm, ...node.keys];
|
|
3539
3455
|
node.values = [pointerKm, ...node.values];
|
|
3540
|
-
parentNode = await this.getNode(node.parent);
|
|
3456
|
+
parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
3541
3457
|
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
3542
3458
|
if (nodeIndex > 0) {
|
|
3543
3459
|
parentNode.values[nodeIndex - 1] = pointerKm;
|
|
@@ -3545,61 +3461,62 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3545
3461
|
}
|
|
3546
3462
|
}
|
|
3547
3463
|
await this._updateNode(node);
|
|
3548
|
-
await this._updateNode(
|
|
3464
|
+
await this._updateNode(siblingNode);
|
|
3549
3465
|
} else {
|
|
3550
3466
|
let pointerP0;
|
|
3551
3467
|
let pointerK0;
|
|
3552
3468
|
if (!node.leaf) {
|
|
3553
|
-
pointerP0 =
|
|
3554
|
-
pointerK0 =
|
|
3469
|
+
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
3470
|
+
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
3555
3471
|
node.keys = [...node.keys, pointerP0];
|
|
3556
3472
|
node.values = [...node.values, guess];
|
|
3557
|
-
parentNode = await this.getNode(node.parent);
|
|
3558
|
-
const pointerIndex = parentNode.keys.indexOf(
|
|
3473
|
+
parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
3474
|
+
const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
|
|
3559
3475
|
if (pointerIndex > 0) {
|
|
3560
3476
|
parentNode.values[pointerIndex - 1] = pointerK0;
|
|
3561
3477
|
await this._updateNode(parentNode);
|
|
3562
3478
|
}
|
|
3563
3479
|
} else {
|
|
3564
|
-
pointerP0 =
|
|
3565
|
-
pointerK0 =
|
|
3480
|
+
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
3481
|
+
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
3566
3482
|
node.keys = [...node.keys, pointerP0];
|
|
3567
3483
|
node.values = [...node.values, pointerK0];
|
|
3568
|
-
parentNode = await this.getNode(node.parent);
|
|
3569
|
-
const pointerIndex = parentNode.keys.indexOf(
|
|
3484
|
+
parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
3485
|
+
const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
|
|
3570
3486
|
if (pointerIndex > 0) {
|
|
3571
|
-
parentNode.values[pointerIndex - 1] =
|
|
3487
|
+
parentNode.values[pointerIndex - 1] = siblingNode.values[0];
|
|
3572
3488
|
await this._updateNode(parentNode);
|
|
3573
3489
|
}
|
|
3574
3490
|
}
|
|
3575
3491
|
await this._updateNode(node);
|
|
3576
|
-
await this._updateNode(
|
|
3492
|
+
await this._updateNode(siblingNode);
|
|
3577
3493
|
}
|
|
3578
|
-
if (!
|
|
3579
|
-
for (const key2 of
|
|
3580
|
-
const n = await this.getNode(key2);
|
|
3581
|
-
n.parent =
|
|
3494
|
+
if (!siblingNode.leaf) {
|
|
3495
|
+
for (const key2 of siblingNode.keys) {
|
|
3496
|
+
const n = this._cloneNode(await this.getNode(key2));
|
|
3497
|
+
n.parent = siblingNode.id;
|
|
3582
3498
|
await this._updateNode(n);
|
|
3583
3499
|
}
|
|
3584
3500
|
}
|
|
3585
3501
|
if (!node.leaf) {
|
|
3586
3502
|
for (const key2 of node.keys) {
|
|
3587
|
-
const n = await this.getNode(key2);
|
|
3503
|
+
const n = this._cloneNode(await this.getNode(key2));
|
|
3588
3504
|
n.parent = node.id;
|
|
3589
3505
|
await this._updateNode(n);
|
|
3590
3506
|
}
|
|
3591
3507
|
}
|
|
3592
3508
|
if (!parentNode.leaf) {
|
|
3593
3509
|
for (const key2 of parentNode.keys) {
|
|
3594
|
-
const n = await this.getNode(key2);
|
|
3510
|
+
const n = this._cloneNode(await this.getNode(key2));
|
|
3595
3511
|
n.parent = parentNode.id;
|
|
3596
3512
|
await this._updateNode(n);
|
|
3597
3513
|
}
|
|
3598
3514
|
}
|
|
3599
3515
|
}
|
|
3600
3516
|
} else {
|
|
3601
|
-
await this._updateNode(node);
|
|
3517
|
+
await this._updateNode(this._cloneNode(node));
|
|
3602
3518
|
}
|
|
3519
|
+
return node;
|
|
3603
3520
|
}
|
|
3604
3521
|
async delete(key, value) {
|
|
3605
3522
|
return this.writeLock(0, async () => {
|
|
@@ -3613,13 +3530,15 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3613
3530
|
const keys = node.keys[i];
|
|
3614
3531
|
const keyIndex = keys.indexOf(key);
|
|
3615
3532
|
if (keyIndex !== -1) {
|
|
3616
|
-
|
|
3617
|
-
|
|
3533
|
+
node = this._cloneNode(node);
|
|
3534
|
+
const freshKeys = node.keys[i];
|
|
3535
|
+
freshKeys.splice(keyIndex, 1);
|
|
3536
|
+
if (freshKeys.length === 0) {
|
|
3618
3537
|
node.keys.splice(i, 1);
|
|
3619
3538
|
node.values.splice(i, 1);
|
|
3620
3539
|
}
|
|
3621
3540
|
await this._updateNode(node);
|
|
3622
|
-
await this._deleteEntry(node, key);
|
|
3541
|
+
node = await this._deleteEntry(node, key);
|
|
3623
3542
|
found = true;
|
|
3624
3543
|
break;
|
|
3625
3544
|
}
|
|
@@ -3662,21 +3581,10 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3662
3581
|
this.rootTx.rootId = this.rootId;
|
|
3663
3582
|
}
|
|
3664
3583
|
}
|
|
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
3584
|
}
|
|
3677
3585
|
return result;
|
|
3678
3586
|
}
|
|
3679
|
-
rollback() {
|
|
3587
|
+
async rollback() {
|
|
3680
3588
|
return this.mvcc.rollback();
|
|
3681
3589
|
}
|
|
3682
3590
|
};
|
|
@@ -3715,7 +3623,9 @@ var BPTreeMVCCStrategyAsync = class extends AsyncMVCCStrategy {
|
|
|
3715
3623
|
};
|
|
3716
3624
|
var BPTreeAsync = class extends BPTreeAsyncTransaction {
|
|
3717
3625
|
constructor(strategy, comparator, option) {
|
|
3718
|
-
const mvccRoot = new AsyncMVCCTransaction(new BPTreeMVCCStrategyAsync(strategy)
|
|
3626
|
+
const mvccRoot = new AsyncMVCCTransaction(new BPTreeMVCCStrategyAsync(strategy), {
|
|
3627
|
+
cacheCapacity: option?.capacity ?? void 0
|
|
3628
|
+
});
|
|
3719
3629
|
super(
|
|
3720
3630
|
null,
|
|
3721
3631
|
mvccRoot,
|
|
@@ -4267,7 +4177,7 @@ var LRUMap2 = class {
|
|
|
4267
4177
|
this.tail = null;
|
|
4268
4178
|
}
|
|
4269
4179
|
};
|
|
4270
|
-
var
|
|
4180
|
+
var CacheEntanglement = class {
|
|
4271
4181
|
creation;
|
|
4272
4182
|
beforeUpdateHook;
|
|
4273
4183
|
capacity;
|
|
@@ -4368,7 +4278,7 @@ var CacheEntanglement2 = class {
|
|
|
4368
4278
|
}
|
|
4369
4279
|
}
|
|
4370
4280
|
};
|
|
4371
|
-
var
|
|
4281
|
+
var CacheData = class _CacheData {
|
|
4372
4282
|
static StructuredClone = globalThis.structuredClone.bind(globalThis);
|
|
4373
4283
|
_value;
|
|
4374
4284
|
constructor(value) {
|
|
@@ -4408,11 +4318,11 @@ var CacheData2 = class _CacheData2 {
|
|
|
4408
4318
|
return Object.assign({}, this.raw);
|
|
4409
4319
|
case "deep-copy":
|
|
4410
4320
|
default:
|
|
4411
|
-
return
|
|
4321
|
+
return _CacheData.StructuredClone(this.raw);
|
|
4412
4322
|
}
|
|
4413
4323
|
}
|
|
4414
4324
|
};
|
|
4415
|
-
var
|
|
4325
|
+
var CacheEntanglementSync = class extends CacheEntanglement {
|
|
4416
4326
|
constructor(creation, option) {
|
|
4417
4327
|
super(creation, option);
|
|
4418
4328
|
}
|
|
@@ -4442,7 +4352,7 @@ var CacheEntanglementSync2 = class extends CacheEntanglement2 {
|
|
|
4442
4352
|
const dependencyValue = dependency.recache(key) ?? dependency.recache(dependencyKey);
|
|
4443
4353
|
resolved[name] = dependencyValue;
|
|
4444
4354
|
}
|
|
4445
|
-
const value = new
|
|
4355
|
+
const value = new CacheData(this.creation(key, resolved, ...parameter));
|
|
4446
4356
|
this.updateRequirements.delete(key);
|
|
4447
4357
|
this.parameters.set(key, parameter);
|
|
4448
4358
|
this.caches.set(key, value);
|
|
@@ -4466,7 +4376,7 @@ var CacheEntanglementSync2 = class extends CacheEntanglement2 {
|
|
|
4466
4376
|
return this.caches.get(key);
|
|
4467
4377
|
}
|
|
4468
4378
|
};
|
|
4469
|
-
var CacheEntanglementAsync = class extends
|
|
4379
|
+
var CacheEntanglementAsync = class extends CacheEntanglement {
|
|
4470
4380
|
constructor(creation, option) {
|
|
4471
4381
|
super(creation, option);
|
|
4472
4382
|
}
|
|
@@ -4496,7 +4406,7 @@ var CacheEntanglementAsync = class extends CacheEntanglement2 {
|
|
|
4496
4406
|
const dependencyValue = await dependency.recache(key) ?? await dependency.recache(dependencyKey);
|
|
4497
4407
|
resolved[name] = dependencyValue;
|
|
4498
4408
|
}
|
|
4499
|
-
const value = new
|
|
4409
|
+
const value = new CacheData(await this.creation(key, resolved, ...parameter));
|
|
4500
4410
|
this.updateRequirements.delete(key);
|
|
4501
4411
|
this.parameters.set(key, parameter);
|
|
4502
4412
|
this.caches.set(key, value);
|
|
@@ -4601,6 +4511,42 @@ var InvertedWeakMap = class {
|
|
|
4601
4511
|
// node_modules/mvcc-api/dist/esm/index.mjs
|
|
4602
4512
|
var MVCCStrategy2 = class {
|
|
4603
4513
|
};
|
|
4514
|
+
var LRUMap3 = class {
|
|
4515
|
+
cache = /* @__PURE__ */ new Map();
|
|
4516
|
+
capacity;
|
|
4517
|
+
constructor(capacity) {
|
|
4518
|
+
this.capacity = capacity;
|
|
4519
|
+
}
|
|
4520
|
+
get(key) {
|
|
4521
|
+
if (!this.cache.has(key)) return void 0;
|
|
4522
|
+
const value = this.cache.get(key);
|
|
4523
|
+
this.cache.delete(key);
|
|
4524
|
+
this.cache.set(key, value);
|
|
4525
|
+
return value;
|
|
4526
|
+
}
|
|
4527
|
+
set(key, value) {
|
|
4528
|
+
if (this.cache.has(key)) {
|
|
4529
|
+
this.cache.delete(key);
|
|
4530
|
+
} else if (this.cache.size >= this.capacity) {
|
|
4531
|
+
const oldestKey = this.cache.keys().next().value;
|
|
4532
|
+
if (oldestKey !== void 0) this.cache.delete(oldestKey);
|
|
4533
|
+
}
|
|
4534
|
+
this.cache.set(key, value);
|
|
4535
|
+
return this;
|
|
4536
|
+
}
|
|
4537
|
+
has(key) {
|
|
4538
|
+
return this.cache.has(key);
|
|
4539
|
+
}
|
|
4540
|
+
delete(key) {
|
|
4541
|
+
return this.cache.delete(key);
|
|
4542
|
+
}
|
|
4543
|
+
clear() {
|
|
4544
|
+
this.cache.clear();
|
|
4545
|
+
}
|
|
4546
|
+
get size() {
|
|
4547
|
+
return this.cache.size;
|
|
4548
|
+
}
|
|
4549
|
+
};
|
|
4604
4550
|
var MVCCTransaction2 = class {
|
|
4605
4551
|
committed;
|
|
4606
4552
|
snapshotVersion;
|
|
@@ -4608,7 +4554,6 @@ var MVCCTransaction2 = class {
|
|
|
4608
4554
|
writeBuffer;
|
|
4609
4555
|
deleteBuffer;
|
|
4610
4556
|
createdKeys;
|
|
4611
|
-
// create()로 생성된 키 추적
|
|
4612
4557
|
deletedValues;
|
|
4613
4558
|
// delete 시 삭제 전 값 저장
|
|
4614
4559
|
originallyExisted;
|
|
@@ -4627,7 +4572,8 @@ var MVCCTransaction2 = class {
|
|
|
4627
4572
|
versionIndex = /* @__PURE__ */ new Map();
|
|
4628
4573
|
deletedCache = /* @__PURE__ */ new Map();
|
|
4629
4574
|
activeTransactions = /* @__PURE__ */ new Set();
|
|
4630
|
-
|
|
4575
|
+
diskCache;
|
|
4576
|
+
constructor(strategy, options, parent, snapshotVersion) {
|
|
4631
4577
|
this.snapshotVersion = snapshotVersion ?? 0;
|
|
4632
4578
|
this.writeBuffer = /* @__PURE__ */ new Map();
|
|
4633
4579
|
this.deleteBuffer = /* @__PURE__ */ new Set();
|
|
@@ -4642,6 +4588,7 @@ var MVCCTransaction2 = class {
|
|
|
4642
4588
|
this.snapshotLocalVersion = parent.localVersion;
|
|
4643
4589
|
this.strategy = void 0;
|
|
4644
4590
|
this.root = parent.root;
|
|
4591
|
+
this.diskCache = parent.diskCache;
|
|
4645
4592
|
} else {
|
|
4646
4593
|
if (!strategy) throw new Error("Root Transaction must get Strategy");
|
|
4647
4594
|
this.strategy = strategy;
|
|
@@ -4649,8 +4596,13 @@ var MVCCTransaction2 = class {
|
|
|
4649
4596
|
this.localVersion = 0;
|
|
4650
4597
|
this.snapshotLocalVersion = 0;
|
|
4651
4598
|
this.root = this;
|
|
4599
|
+
this.diskCache = new LRUMap3(options?.cacheCapacity ?? 1e3);
|
|
4652
4600
|
}
|
|
4653
4601
|
}
|
|
4602
|
+
/**
|
|
4603
|
+
* Checks if the transaction is a root transaction.
|
|
4604
|
+
* @returns True if the transaction is a root transaction, false otherwise.
|
|
4605
|
+
*/
|
|
4654
4606
|
isRoot() {
|
|
4655
4607
|
return !this.parent;
|
|
4656
4608
|
}
|
|
@@ -4667,7 +4619,22 @@ var MVCCTransaction2 = class {
|
|
|
4667
4619
|
}
|
|
4668
4620
|
return false;
|
|
4669
4621
|
}
|
|
4670
|
-
|
|
4622
|
+
/**
|
|
4623
|
+
* Checks if a key was written in this transaction.
|
|
4624
|
+
* @param key The key to check.
|
|
4625
|
+
* @returns True if the key was written in this transaction, false otherwise.
|
|
4626
|
+
*/
|
|
4627
|
+
isWrote(key) {
|
|
4628
|
+
return this.writeBuffer.has(key);
|
|
4629
|
+
}
|
|
4630
|
+
/**
|
|
4631
|
+
* Checks if a key was deleted in this transaction.
|
|
4632
|
+
* @param key The key to check.
|
|
4633
|
+
* @returns True if the key was deleted in this transaction, false otherwise.
|
|
4634
|
+
*/
|
|
4635
|
+
isDeleted(key) {
|
|
4636
|
+
return this.deleteBuffer.has(key);
|
|
4637
|
+
}
|
|
4671
4638
|
_recordHistory(key) {
|
|
4672
4639
|
const existsInWriteBuffer = this.writeBuffer.has(key);
|
|
4673
4640
|
const existsInDeleteBuffer = this.deleteBuffer.has(key);
|
|
@@ -4681,6 +4648,41 @@ var MVCCTransaction2 = class {
|
|
|
4681
4648
|
});
|
|
4682
4649
|
}
|
|
4683
4650
|
}
|
|
4651
|
+
/**
|
|
4652
|
+
* BINARY SEARCH HELPER: Finds the index of the last element in the array
|
|
4653
|
+
* where item[key] <= target. Assumes the array is sorted by 'key' ascending.
|
|
4654
|
+
*/
|
|
4655
|
+
_findLastLE(array, target, property) {
|
|
4656
|
+
let left = 0;
|
|
4657
|
+
let right = array.length - 1;
|
|
4658
|
+
let result = -1;
|
|
4659
|
+
while (left <= right) {
|
|
4660
|
+
const mid = left + right >> 1;
|
|
4661
|
+
if (array[mid][property] <= target) {
|
|
4662
|
+
result = mid;
|
|
4663
|
+
left = mid + 1;
|
|
4664
|
+
} else {
|
|
4665
|
+
right = mid - 1;
|
|
4666
|
+
}
|
|
4667
|
+
}
|
|
4668
|
+
return result;
|
|
4669
|
+
}
|
|
4670
|
+
/**
|
|
4671
|
+
* BINARY SEARCH HELPER: Finds the index of the element in the array
|
|
4672
|
+
* where item[key] === target. Assumes the array is sorted by 'key' ascending.
|
|
4673
|
+
*/
|
|
4674
|
+
_findExact(array, target, property) {
|
|
4675
|
+
let left = 0;
|
|
4676
|
+
let right = array.length - 1;
|
|
4677
|
+
while (left <= right) {
|
|
4678
|
+
const mid = left + right >> 1;
|
|
4679
|
+
const val = array[mid][property];
|
|
4680
|
+
if (val === target) return mid;
|
|
4681
|
+
if (val < target) left = mid + 1;
|
|
4682
|
+
else right = mid - 1;
|
|
4683
|
+
}
|
|
4684
|
+
return -1;
|
|
4685
|
+
}
|
|
4684
4686
|
_bufferCreate(key, value, version) {
|
|
4685
4687
|
if (version === void 0) this.localVersion++;
|
|
4686
4688
|
const targetVersion = version ?? this.localVersion;
|
|
@@ -4730,7 +4732,11 @@ var MVCCTransaction2 = class {
|
|
|
4730
4732
|
deleted.push({ key, data });
|
|
4731
4733
|
}
|
|
4732
4734
|
}
|
|
4733
|
-
return {
|
|
4735
|
+
return {
|
|
4736
|
+
created,
|
|
4737
|
+
updated,
|
|
4738
|
+
deleted
|
|
4739
|
+
};
|
|
4734
4740
|
}
|
|
4735
4741
|
/**
|
|
4736
4742
|
* Rolls back the transaction.
|
|
@@ -4748,7 +4754,12 @@ var MVCCTransaction2 = class {
|
|
|
4748
4754
|
if (this.root !== this) {
|
|
4749
4755
|
this.root.activeTransactions.delete(this);
|
|
4750
4756
|
}
|
|
4751
|
-
return {
|
|
4757
|
+
return {
|
|
4758
|
+
success: true,
|
|
4759
|
+
created,
|
|
4760
|
+
updated,
|
|
4761
|
+
deleted
|
|
4762
|
+
};
|
|
4752
4763
|
}
|
|
4753
4764
|
/**
|
|
4754
4765
|
* Cleans up both deletedCache and versionIndex based on minActiveVersion.
|
|
@@ -4834,7 +4845,7 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
|
|
|
4834
4845
|
createNested() {
|
|
4835
4846
|
if (this.committed) throw new Error("Transaction already committed");
|
|
4836
4847
|
const childVersion = this.isRoot() ? this.version : this.snapshotVersion;
|
|
4837
|
-
const child = new _SyncMVCCTransaction2(void 0, this, childVersion);
|
|
4848
|
+
const child = new _SyncMVCCTransaction2(void 0, void 0, this, childVersion);
|
|
4838
4849
|
this.root.activeTransactions.add(child);
|
|
4839
4850
|
return child;
|
|
4840
4851
|
}
|
|
@@ -4857,78 +4868,114 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
|
|
|
4857
4868
|
return this._diskExists(key, this.snapshotVersion);
|
|
4858
4869
|
}
|
|
4859
4870
|
_existsSnapshot(key, snapshotVersion, snapshotLocalVersion) {
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
return false;
|
|
4870
|
-
}
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4871
|
+
let current = this;
|
|
4872
|
+
let slVer = snapshotLocalVersion;
|
|
4873
|
+
while (current) {
|
|
4874
|
+
if (current.writeBuffer.has(key)) {
|
|
4875
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
4876
|
+
if (slVer === void 0 || keyModVersion <= slVer) return true;
|
|
4877
|
+
}
|
|
4878
|
+
if (current.deleteBuffer.has(key)) {
|
|
4879
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
4880
|
+
if (slVer === void 0 || keyModVersion <= slVer) return false;
|
|
4881
|
+
}
|
|
4882
|
+
const history = current.bufferHistory.get(key);
|
|
4883
|
+
if (history && slVer !== void 0) {
|
|
4884
|
+
const idx = current._findLastLE(history, slVer, "version");
|
|
4885
|
+
if (idx >= 0) return history[idx].exists;
|
|
4886
|
+
}
|
|
4887
|
+
if (current.parent) {
|
|
4888
|
+
slVer = current.snapshotLocalVersion;
|
|
4889
|
+
current = current.parent;
|
|
4890
|
+
} else {
|
|
4891
|
+
return current._diskExists(key, snapshotVersion);
|
|
4878
4892
|
}
|
|
4879
4893
|
}
|
|
4880
|
-
|
|
4881
|
-
return this.parent._existsSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
|
|
4882
|
-
} else {
|
|
4883
|
-
return this._diskExists(key, snapshotVersion);
|
|
4884
|
-
}
|
|
4894
|
+
return false;
|
|
4885
4895
|
}
|
|
4886
4896
|
_readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
4897
|
+
let current = this;
|
|
4898
|
+
let slVer = snapshotLocalVersion;
|
|
4899
|
+
while (current) {
|
|
4900
|
+
if (current.writeBuffer.has(key)) {
|
|
4901
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
4902
|
+
if (slVer === void 0 || keyModVersion <= slVer) {
|
|
4903
|
+
return current.writeBuffer.get(key);
|
|
4904
|
+
}
|
|
4891
4905
|
}
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
|
|
4906
|
+
if (current.deleteBuffer.has(key)) {
|
|
4907
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
4908
|
+
if (slVer === void 0 || keyModVersion <= slVer) {
|
|
4909
|
+
return null;
|
|
4910
|
+
}
|
|
4897
4911
|
}
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
return history[i].exists ? history[i].value : null;
|
|
4912
|
+
const history = current.bufferHistory.get(key);
|
|
4913
|
+
if (history && slVer !== void 0) {
|
|
4914
|
+
const idx = current._findLastLE(history, slVer, "version");
|
|
4915
|
+
if (idx >= 0) {
|
|
4916
|
+
return history[idx].exists ? history[idx].value : null;
|
|
4904
4917
|
}
|
|
4905
4918
|
}
|
|
4919
|
+
if (current.parent) {
|
|
4920
|
+
slVer = current.snapshotLocalVersion;
|
|
4921
|
+
current = current.parent;
|
|
4922
|
+
} else {
|
|
4923
|
+
return current._diskRead(key, snapshotVersion);
|
|
4924
|
+
}
|
|
4906
4925
|
}
|
|
4907
|
-
|
|
4908
|
-
return this.parent._readSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
|
|
4909
|
-
} else {
|
|
4910
|
-
return this._diskRead(key, snapshotVersion);
|
|
4911
|
-
}
|
|
4926
|
+
return null;
|
|
4912
4927
|
}
|
|
4913
4928
|
commit(label) {
|
|
4914
4929
|
const { created, updated, deleted } = this.getResultEntries();
|
|
4915
4930
|
if (this.committed) {
|
|
4916
|
-
return {
|
|
4931
|
+
return {
|
|
4932
|
+
label,
|
|
4933
|
+
success: false,
|
|
4934
|
+
error: "Transaction already committed",
|
|
4935
|
+
conflict: void 0,
|
|
4936
|
+
created,
|
|
4937
|
+
updated,
|
|
4938
|
+
deleted
|
|
4939
|
+
};
|
|
4917
4940
|
}
|
|
4918
4941
|
if (this.hasCommittedAncestor()) {
|
|
4919
|
-
return {
|
|
4942
|
+
return {
|
|
4943
|
+
label,
|
|
4944
|
+
success: false,
|
|
4945
|
+
error: "Ancestor transaction already committed",
|
|
4946
|
+
conflict: void 0,
|
|
4947
|
+
created,
|
|
4948
|
+
updated,
|
|
4949
|
+
deleted
|
|
4950
|
+
};
|
|
4920
4951
|
}
|
|
4921
4952
|
if (this.parent) {
|
|
4922
4953
|
const failure = this.parent._merge(this);
|
|
4923
4954
|
if (failure) {
|
|
4924
|
-
return {
|
|
4955
|
+
return {
|
|
4956
|
+
label,
|
|
4957
|
+
success: false,
|
|
4958
|
+
error: failure.error,
|
|
4959
|
+
conflict: failure.conflict,
|
|
4960
|
+
created,
|
|
4961
|
+
updated,
|
|
4962
|
+
deleted
|
|
4963
|
+
};
|
|
4925
4964
|
}
|
|
4926
4965
|
this.committed = true;
|
|
4927
4966
|
} else {
|
|
4928
4967
|
if (this.writeBuffer.size > 0 || this.deleteBuffer.size > 0) {
|
|
4929
4968
|
const failure = this._merge(this);
|
|
4930
4969
|
if (failure) {
|
|
4931
|
-
return {
|
|
4970
|
+
return {
|
|
4971
|
+
label,
|
|
4972
|
+
success: false,
|
|
4973
|
+
error: failure.error,
|
|
4974
|
+
conflict: failure.conflict,
|
|
4975
|
+
created: [],
|
|
4976
|
+
updated: [],
|
|
4977
|
+
deleted: []
|
|
4978
|
+
};
|
|
4932
4979
|
}
|
|
4933
4980
|
this.writeBuffer.clear();
|
|
4934
4981
|
this.deleteBuffer.clear();
|
|
@@ -4941,7 +4988,13 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
|
|
|
4941
4988
|
this.snapshotVersion = this.version;
|
|
4942
4989
|
}
|
|
4943
4990
|
}
|
|
4944
|
-
return {
|
|
4991
|
+
return {
|
|
4992
|
+
label,
|
|
4993
|
+
success: true,
|
|
4994
|
+
created,
|
|
4995
|
+
updated,
|
|
4996
|
+
deleted
|
|
4997
|
+
};
|
|
4945
4998
|
}
|
|
4946
4999
|
_merge(child) {
|
|
4947
5000
|
if (this.parent) {
|
|
@@ -4950,7 +5003,11 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
|
|
|
4950
5003
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
4951
5004
|
return {
|
|
4952
5005
|
error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
|
|
4953
|
-
conflict: {
|
|
5006
|
+
conflict: {
|
|
5007
|
+
key,
|
|
5008
|
+
parent: this.read(key),
|
|
5009
|
+
child: child.read(key)
|
|
5010
|
+
}
|
|
4954
5011
|
};
|
|
4955
5012
|
}
|
|
4956
5013
|
}
|
|
@@ -4959,7 +5016,11 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
|
|
|
4959
5016
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
4960
5017
|
return {
|
|
4961
5018
|
error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
|
|
4962
|
-
conflict: {
|
|
5019
|
+
conflict: {
|
|
5020
|
+
key,
|
|
5021
|
+
parent: this.read(key),
|
|
5022
|
+
child: child.read(key)
|
|
5023
|
+
}
|
|
4963
5024
|
};
|
|
4964
5025
|
}
|
|
4965
5026
|
}
|
|
@@ -4988,7 +5049,11 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
|
|
|
4988
5049
|
if (lastVer > child.snapshotVersion) {
|
|
4989
5050
|
return {
|
|
4990
5051
|
error: `Commit conflict: Key '${key}' was modified by a newer transaction (v${lastVer})`,
|
|
4991
|
-
conflict: {
|
|
5052
|
+
conflict: {
|
|
5053
|
+
key,
|
|
5054
|
+
parent: this.read(key),
|
|
5055
|
+
child: child.read(key)
|
|
5056
|
+
}
|
|
4992
5057
|
};
|
|
4993
5058
|
}
|
|
4994
5059
|
}
|
|
@@ -4996,7 +5061,11 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
|
|
|
4996
5061
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
4997
5062
|
return {
|
|
4998
5063
|
error: `Commit conflict: Key '${key}' was modified by a newer transaction in the same session (Local v${lastModLocalVer})`,
|
|
4999
|
-
conflict: {
|
|
5064
|
+
conflict: {
|
|
5065
|
+
key,
|
|
5066
|
+
parent: this.read(key),
|
|
5067
|
+
child: child.read(key)
|
|
5068
|
+
}
|
|
5000
5069
|
};
|
|
5001
5070
|
}
|
|
5002
5071
|
}
|
|
@@ -5031,10 +5100,14 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
|
|
|
5031
5100
|
_diskWrite(key, value, version) {
|
|
5032
5101
|
const strategy = this.strategy;
|
|
5033
5102
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
5034
|
-
|
|
5035
|
-
|
|
5103
|
+
const rootAsAny = this.root;
|
|
5104
|
+
if (this._diskExists(key, version)) {
|
|
5105
|
+
const currentVal = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : strategy.read(key);
|
|
5036
5106
|
if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
|
|
5037
5107
|
this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: version });
|
|
5108
|
+
rootAsAny.diskCache.set(key, value);
|
|
5109
|
+
} else {
|
|
5110
|
+
rootAsAny.diskCache.set(key, value);
|
|
5038
5111
|
}
|
|
5039
5112
|
strategy.write(key, value);
|
|
5040
5113
|
if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
|
|
@@ -5045,23 +5118,25 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
|
|
|
5045
5118
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
5046
5119
|
const versions = this.versionIndex.get(key);
|
|
5047
5120
|
if (!versions) {
|
|
5048
|
-
|
|
5121
|
+
const rootAsAny = this.root;
|
|
5122
|
+
if (this._diskExists(key, snapshotVersion)) {
|
|
5123
|
+
const val = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : strategy.read(key);
|
|
5124
|
+
rootAsAny.diskCache.set(key, val);
|
|
5125
|
+
return val;
|
|
5126
|
+
}
|
|
5127
|
+
return null;
|
|
5049
5128
|
}
|
|
5050
5129
|
let targetVerObj = null;
|
|
5051
5130
|
let nextVerObj = null;
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
nextVerObj = v;
|
|
5056
|
-
break;
|
|
5057
|
-
}
|
|
5058
|
-
}
|
|
5131
|
+
const idx = this._findLastLE(versions, snapshotVersion, "version");
|
|
5132
|
+
if (idx >= 0) targetVerObj = versions[idx];
|
|
5133
|
+
if (idx + 1 < versions.length) nextVerObj = versions[idx + 1];
|
|
5059
5134
|
if (!targetVerObj) {
|
|
5060
5135
|
if (nextVerObj) {
|
|
5061
5136
|
const cached2 = this.deletedCache.get(key);
|
|
5062
5137
|
if (cached2) {
|
|
5063
|
-
const
|
|
5064
|
-
if (
|
|
5138
|
+
const cIdx = this._findExact(cached2, nextVerObj.version, "deletedAtVersion");
|
|
5139
|
+
if (cIdx >= 0) return cached2[cIdx].value;
|
|
5065
5140
|
}
|
|
5066
5141
|
}
|
|
5067
5142
|
return null;
|
|
@@ -5069,12 +5144,18 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
|
|
|
5069
5144
|
if (!targetVerObj.exists) return null;
|
|
5070
5145
|
if (!nextVerObj) {
|
|
5071
5146
|
if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
|
|
5072
|
-
|
|
5147
|
+
if (this._diskExists(key, snapshotVersion)) {
|
|
5148
|
+
const rootAsAny = this.root;
|
|
5149
|
+
const val = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : strategy.read(key);
|
|
5150
|
+
rootAsAny.diskCache.set(key, val);
|
|
5151
|
+
return val;
|
|
5152
|
+
}
|
|
5153
|
+
return null;
|
|
5073
5154
|
}
|
|
5074
5155
|
const cached = this.deletedCache.get(key);
|
|
5075
5156
|
if (cached) {
|
|
5076
|
-
const
|
|
5077
|
-
if (
|
|
5157
|
+
const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
|
|
5158
|
+
if (cIdx >= 0) return cached[cIdx].value;
|
|
5078
5159
|
}
|
|
5079
5160
|
return null;
|
|
5080
5161
|
}
|
|
@@ -5083,23 +5164,23 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
|
|
|
5083
5164
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
5084
5165
|
const versions = this.versionIndex.get(key);
|
|
5085
5166
|
if (!versions) {
|
|
5086
|
-
|
|
5167
|
+
const rootAsAny = this.root;
|
|
5168
|
+
if (rootAsAny.diskCache.has(key)) return rootAsAny.diskCache.get(key) !== null;
|
|
5169
|
+
const exists = strategy.exists(key);
|
|
5170
|
+
if (!exists) rootAsAny.diskCache.set(key, null);
|
|
5171
|
+
return exists;
|
|
5087
5172
|
}
|
|
5088
5173
|
let targetVerObj = null;
|
|
5089
5174
|
let nextVerObj = null;
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
nextVerObj = v;
|
|
5094
|
-
break;
|
|
5095
|
-
}
|
|
5096
|
-
}
|
|
5175
|
+
const idx = this._findLastLE(versions, snapshotVersion, "version");
|
|
5176
|
+
if (idx >= 0) targetVerObj = versions[idx];
|
|
5177
|
+
if (idx + 1 < versions.length) nextVerObj = versions[idx + 1];
|
|
5097
5178
|
if (!targetVerObj) {
|
|
5098
5179
|
if (nextVerObj) {
|
|
5099
5180
|
const cached = this.deletedCache.get(key);
|
|
5100
5181
|
if (cached) {
|
|
5101
|
-
const
|
|
5102
|
-
if (
|
|
5182
|
+
const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
|
|
5183
|
+
if (cIdx >= 0) return true;
|
|
5103
5184
|
}
|
|
5104
5185
|
}
|
|
5105
5186
|
return false;
|
|
@@ -5109,11 +5190,13 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
|
|
|
5109
5190
|
_diskDelete(key, snapshotVersion) {
|
|
5110
5191
|
const strategy = this.strategy;
|
|
5111
5192
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
5112
|
-
|
|
5113
|
-
|
|
5193
|
+
const rootAsAny = this.root;
|
|
5194
|
+
if (this._diskExists(key, snapshotVersion)) {
|
|
5195
|
+
const currentVal = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : strategy.read(key);
|
|
5114
5196
|
if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
|
|
5115
5197
|
this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: snapshotVersion });
|
|
5116
5198
|
strategy.delete(key);
|
|
5199
|
+
rootAsAny.diskCache.delete(key);
|
|
5117
5200
|
}
|
|
5118
5201
|
if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
|
|
5119
5202
|
this.versionIndex.get(key).push({ version: snapshotVersion, exists: false });
|
|
@@ -5427,7 +5510,7 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
|
|
|
5427
5510
|
createNested() {
|
|
5428
5511
|
if (this.committed) throw new Error("Transaction already committed");
|
|
5429
5512
|
const childVersion = this.isRoot() ? this.version : this.snapshotVersion;
|
|
5430
|
-
const child = new _AsyncMVCCTransaction2(void 0, this, childVersion);
|
|
5513
|
+
const child = new _AsyncMVCCTransaction2(void 0, void 0, this, childVersion);
|
|
5431
5514
|
this.root.activeTransactions.add(child);
|
|
5432
5515
|
return child;
|
|
5433
5516
|
}
|
|
@@ -5450,78 +5533,114 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
|
|
|
5450
5533
|
return await this._diskExists(key, this.snapshotVersion);
|
|
5451
5534
|
}
|
|
5452
5535
|
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
|
-
|
|
5536
|
+
let current = this;
|
|
5537
|
+
let slVer = snapshotLocalVersion;
|
|
5538
|
+
while (current) {
|
|
5539
|
+
if (current.writeBuffer.has(key)) {
|
|
5540
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
5541
|
+
if (slVer === void 0 || keyModVersion <= slVer) return true;
|
|
5542
|
+
}
|
|
5543
|
+
if (current.deleteBuffer.has(key)) {
|
|
5544
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
5545
|
+
if (slVer === void 0 || keyModVersion <= slVer) return false;
|
|
5546
|
+
}
|
|
5547
|
+
const history = current.bufferHistory.get(key);
|
|
5548
|
+
if (history && slVer !== void 0) {
|
|
5549
|
+
const idx = current._findLastLE(history, slVer, "version");
|
|
5550
|
+
if (idx >= 0) return history[idx].exists;
|
|
5551
|
+
}
|
|
5552
|
+
if (current.parent) {
|
|
5553
|
+
slVer = current.snapshotLocalVersion;
|
|
5554
|
+
current = current.parent;
|
|
5555
|
+
} else {
|
|
5556
|
+
return await current._diskExists(key, snapshotVersion);
|
|
5471
5557
|
}
|
|
5472
5558
|
}
|
|
5473
|
-
|
|
5474
|
-
return this.parent._existsSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
|
|
5475
|
-
} else {
|
|
5476
|
-
return await this._diskExists(key, snapshotVersion);
|
|
5477
|
-
}
|
|
5559
|
+
return false;
|
|
5478
5560
|
}
|
|
5479
5561
|
async _readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5562
|
+
let current = this;
|
|
5563
|
+
let slVer = snapshotLocalVersion;
|
|
5564
|
+
while (current) {
|
|
5565
|
+
if (current.writeBuffer.has(key)) {
|
|
5566
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
5567
|
+
if (slVer === void 0 || keyModVersion <= slVer) {
|
|
5568
|
+
return current.writeBuffer.get(key);
|
|
5569
|
+
}
|
|
5484
5570
|
}
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5571
|
+
if (current.deleteBuffer.has(key)) {
|
|
5572
|
+
const keyModVersion = current.keyVersions.get(key);
|
|
5573
|
+
if (slVer === void 0 || keyModVersion <= slVer) {
|
|
5574
|
+
return null;
|
|
5575
|
+
}
|
|
5490
5576
|
}
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
return history[i].exists ? history[i].value : null;
|
|
5577
|
+
const history = current.bufferHistory.get(key);
|
|
5578
|
+
if (history && slVer !== void 0) {
|
|
5579
|
+
const idx = current._findLastLE(history, slVer, "version");
|
|
5580
|
+
if (idx >= 0) {
|
|
5581
|
+
return history[idx].exists ? history[idx].value : null;
|
|
5497
5582
|
}
|
|
5498
5583
|
}
|
|
5584
|
+
if (current.parent) {
|
|
5585
|
+
slVer = current.snapshotLocalVersion;
|
|
5586
|
+
current = current.parent;
|
|
5587
|
+
} else {
|
|
5588
|
+
return await current._diskRead(key, snapshotVersion);
|
|
5589
|
+
}
|
|
5499
5590
|
}
|
|
5500
|
-
|
|
5501
|
-
return this.parent._readSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
|
|
5502
|
-
} else {
|
|
5503
|
-
return await this._diskRead(key, snapshotVersion);
|
|
5504
|
-
}
|
|
5591
|
+
return null;
|
|
5505
5592
|
}
|
|
5506
5593
|
async commit(label) {
|
|
5507
5594
|
const { created, updated, deleted } = this.getResultEntries();
|
|
5508
5595
|
if (this.committed) {
|
|
5509
|
-
return {
|
|
5596
|
+
return {
|
|
5597
|
+
label,
|
|
5598
|
+
success: false,
|
|
5599
|
+
error: "Transaction already committed",
|
|
5600
|
+
conflict: void 0,
|
|
5601
|
+
created,
|
|
5602
|
+
updated,
|
|
5603
|
+
deleted
|
|
5604
|
+
};
|
|
5510
5605
|
}
|
|
5511
5606
|
if (this.hasCommittedAncestor()) {
|
|
5512
|
-
return {
|
|
5607
|
+
return {
|
|
5608
|
+
label,
|
|
5609
|
+
success: false,
|
|
5610
|
+
error: "Ancestor transaction already committed",
|
|
5611
|
+
conflict: void 0,
|
|
5612
|
+
created,
|
|
5613
|
+
updated,
|
|
5614
|
+
deleted
|
|
5615
|
+
};
|
|
5513
5616
|
}
|
|
5514
5617
|
if (this.parent) {
|
|
5515
5618
|
const failure = await this.parent._merge(this);
|
|
5516
5619
|
if (failure) {
|
|
5517
|
-
return {
|
|
5620
|
+
return {
|
|
5621
|
+
label,
|
|
5622
|
+
success: false,
|
|
5623
|
+
error: failure.error,
|
|
5624
|
+
conflict: failure.conflict,
|
|
5625
|
+
created,
|
|
5626
|
+
updated,
|
|
5627
|
+
deleted
|
|
5628
|
+
};
|
|
5518
5629
|
}
|
|
5519
5630
|
this.committed = true;
|
|
5520
5631
|
} else {
|
|
5521
5632
|
if (this.writeBuffer.size > 0 || this.deleteBuffer.size > 0) {
|
|
5522
5633
|
const failure = await this._merge(this);
|
|
5523
5634
|
if (failure) {
|
|
5524
|
-
return {
|
|
5635
|
+
return {
|
|
5636
|
+
label,
|
|
5637
|
+
success: false,
|
|
5638
|
+
error: failure.error,
|
|
5639
|
+
conflict: failure.conflict,
|
|
5640
|
+
created: [],
|
|
5641
|
+
updated: [],
|
|
5642
|
+
deleted: []
|
|
5643
|
+
};
|
|
5525
5644
|
}
|
|
5526
5645
|
this.writeBuffer.clear();
|
|
5527
5646
|
this.deleteBuffer.clear();
|
|
@@ -5534,7 +5653,13 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
|
|
|
5534
5653
|
this.snapshotVersion = this.version;
|
|
5535
5654
|
}
|
|
5536
5655
|
}
|
|
5537
|
-
return {
|
|
5656
|
+
return {
|
|
5657
|
+
label,
|
|
5658
|
+
success: true,
|
|
5659
|
+
created,
|
|
5660
|
+
updated,
|
|
5661
|
+
deleted
|
|
5662
|
+
};
|
|
5538
5663
|
}
|
|
5539
5664
|
async _merge(child) {
|
|
5540
5665
|
return this.writeLock(async () => {
|
|
@@ -5544,7 +5669,11 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
|
|
|
5544
5669
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
5545
5670
|
return {
|
|
5546
5671
|
error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
|
|
5547
|
-
conflict: {
|
|
5672
|
+
conflict: {
|
|
5673
|
+
key,
|
|
5674
|
+
parent: await this.read(key),
|
|
5675
|
+
child: await child.read(key)
|
|
5676
|
+
}
|
|
5548
5677
|
};
|
|
5549
5678
|
}
|
|
5550
5679
|
}
|
|
@@ -5553,7 +5682,11 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
|
|
|
5553
5682
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
5554
5683
|
return {
|
|
5555
5684
|
error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
|
|
5556
|
-
conflict: {
|
|
5685
|
+
conflict: {
|
|
5686
|
+
key,
|
|
5687
|
+
parent: await this.read(key),
|
|
5688
|
+
child: await child.read(key)
|
|
5689
|
+
}
|
|
5557
5690
|
};
|
|
5558
5691
|
}
|
|
5559
5692
|
}
|
|
@@ -5583,7 +5716,11 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
|
|
|
5583
5716
|
if (lastVer > child.snapshotVersion) {
|
|
5584
5717
|
return {
|
|
5585
5718
|
error: `Commit conflict: Key '${key}' was modified by a newer transaction (v${lastVer})`,
|
|
5586
|
-
conflict: {
|
|
5719
|
+
conflict: {
|
|
5720
|
+
key,
|
|
5721
|
+
parent: await this.read(key),
|
|
5722
|
+
child: await child.read(key)
|
|
5723
|
+
}
|
|
5587
5724
|
};
|
|
5588
5725
|
}
|
|
5589
5726
|
}
|
|
@@ -5591,7 +5728,11 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
|
|
|
5591
5728
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
5592
5729
|
return {
|
|
5593
5730
|
error: `Commit conflict: Key '${key}' was modified by a newer transaction in the same session (Local v${lastModLocalVer})`,
|
|
5594
|
-
conflict: {
|
|
5731
|
+
conflict: {
|
|
5732
|
+
key,
|
|
5733
|
+
parent: await this.read(key),
|
|
5734
|
+
child: await child.read(key)
|
|
5735
|
+
}
|
|
5595
5736
|
};
|
|
5596
5737
|
}
|
|
5597
5738
|
}
|
|
@@ -5627,10 +5768,14 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
|
|
|
5627
5768
|
async _diskWrite(key, value, version) {
|
|
5628
5769
|
const strategy = this.strategy;
|
|
5629
5770
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
5630
|
-
|
|
5631
|
-
|
|
5771
|
+
const rootAsAny = this.root;
|
|
5772
|
+
if (await this._diskExists(key, version)) {
|
|
5773
|
+
const currentVal = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : await strategy.read(key);
|
|
5632
5774
|
if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
|
|
5633
5775
|
this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: version });
|
|
5776
|
+
rootAsAny.diskCache.set(key, value);
|
|
5777
|
+
} else {
|
|
5778
|
+
rootAsAny.diskCache.set(key, value);
|
|
5634
5779
|
}
|
|
5635
5780
|
await strategy.write(key, value);
|
|
5636
5781
|
if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
|
|
@@ -5641,23 +5786,25 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
|
|
|
5641
5786
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
5642
5787
|
const versions = this.versionIndex.get(key);
|
|
5643
5788
|
if (!versions) {
|
|
5644
|
-
|
|
5789
|
+
const rootAsAny = this.root;
|
|
5790
|
+
if (await this._diskExists(key, snapshotVersion)) {
|
|
5791
|
+
const val = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : await strategy.read(key);
|
|
5792
|
+
rootAsAny.diskCache.set(key, val);
|
|
5793
|
+
return val;
|
|
5794
|
+
}
|
|
5795
|
+
return null;
|
|
5645
5796
|
}
|
|
5646
5797
|
let targetVerObj = null;
|
|
5647
5798
|
let nextVerObj = null;
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
nextVerObj = v;
|
|
5652
|
-
break;
|
|
5653
|
-
}
|
|
5654
|
-
}
|
|
5799
|
+
const idx = this._findLastLE(versions, snapshotVersion, "version");
|
|
5800
|
+
if (idx >= 0) targetVerObj = versions[idx];
|
|
5801
|
+
if (idx + 1 < versions.length) nextVerObj = versions[idx + 1];
|
|
5655
5802
|
if (!targetVerObj) {
|
|
5656
5803
|
if (nextVerObj) {
|
|
5657
5804
|
const cached2 = this.deletedCache.get(key);
|
|
5658
5805
|
if (cached2) {
|
|
5659
|
-
const
|
|
5660
|
-
if (
|
|
5806
|
+
const cIdx = this._findExact(cached2, nextVerObj.version, "deletedAtVersion");
|
|
5807
|
+
if (cIdx >= 0) return cached2[cIdx].value;
|
|
5661
5808
|
}
|
|
5662
5809
|
}
|
|
5663
5810
|
return null;
|
|
@@ -5665,12 +5812,18 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
|
|
|
5665
5812
|
if (!targetVerObj.exists) return null;
|
|
5666
5813
|
if (!nextVerObj) {
|
|
5667
5814
|
if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
|
|
5668
|
-
|
|
5815
|
+
if (await this._diskExists(key, snapshotVersion)) {
|
|
5816
|
+
const rootAsAny = this.root;
|
|
5817
|
+
const val = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : await strategy.read(key);
|
|
5818
|
+
rootAsAny.diskCache.set(key, val);
|
|
5819
|
+
return val;
|
|
5820
|
+
}
|
|
5821
|
+
return null;
|
|
5669
5822
|
}
|
|
5670
5823
|
const cached = this.deletedCache.get(key);
|
|
5671
5824
|
if (cached) {
|
|
5672
|
-
const
|
|
5673
|
-
if (
|
|
5825
|
+
const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
|
|
5826
|
+
if (cIdx >= 0) return cached[cIdx].value;
|
|
5674
5827
|
}
|
|
5675
5828
|
return null;
|
|
5676
5829
|
}
|
|
@@ -5679,23 +5832,23 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
|
|
|
5679
5832
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
5680
5833
|
const versions = this.versionIndex.get(key);
|
|
5681
5834
|
if (!versions) {
|
|
5682
|
-
|
|
5835
|
+
const rootAsAny = this.root;
|
|
5836
|
+
if (rootAsAny.diskCache.has(key)) return rootAsAny.diskCache.get(key) !== null;
|
|
5837
|
+
const exists = await strategy.exists(key);
|
|
5838
|
+
if (!exists) rootAsAny.diskCache.set(key, null);
|
|
5839
|
+
return exists;
|
|
5683
5840
|
}
|
|
5684
5841
|
let targetVerObj = null;
|
|
5685
5842
|
let nextVerObj = null;
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
nextVerObj = v;
|
|
5690
|
-
break;
|
|
5691
|
-
}
|
|
5692
|
-
}
|
|
5843
|
+
const idx = this._findLastLE(versions, snapshotVersion, "version");
|
|
5844
|
+
if (idx >= 0) targetVerObj = versions[idx];
|
|
5845
|
+
if (idx + 1 < versions.length) nextVerObj = versions[idx + 1];
|
|
5693
5846
|
if (!targetVerObj) {
|
|
5694
5847
|
if (nextVerObj) {
|
|
5695
5848
|
const cached = this.deletedCache.get(key);
|
|
5696
5849
|
if (cached) {
|
|
5697
|
-
const
|
|
5698
|
-
if (
|
|
5850
|
+
const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
|
|
5851
|
+
if (cIdx >= 0) return true;
|
|
5699
5852
|
}
|
|
5700
5853
|
}
|
|
5701
5854
|
return false;
|
|
@@ -5705,11 +5858,13 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
|
|
|
5705
5858
|
async _diskDelete(key, snapshotVersion) {
|
|
5706
5859
|
const strategy = this.strategy;
|
|
5707
5860
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
5708
|
-
|
|
5709
|
-
|
|
5861
|
+
const rootAsAny = this.root;
|
|
5862
|
+
if (await this._diskExists(key, snapshotVersion)) {
|
|
5863
|
+
const currentVal = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : await strategy.read(key);
|
|
5710
5864
|
if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
|
|
5711
5865
|
this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: snapshotVersion });
|
|
5712
5866
|
await strategy.delete(key);
|
|
5867
|
+
rootAsAny.diskCache.delete(key);
|
|
5713
5868
|
}
|
|
5714
5869
|
if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
|
|
5715
5870
|
this.versionIndex.get(key).push({ version: snapshotVersion, exists: false });
|