dataply 0.0.21 → 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.
Files changed (2) hide show
  1. package/dist/cjs/index.js +1819 -1597
  2. 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: () => CacheEntanglementSync2,
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,11 +168,11 @@ var MVCCTransaction = class {
132
168
  writeBuffer;
133
169
  deleteBuffer;
134
170
  createdKeys;
135
- // create()로 생성된 키 추적
136
171
  deletedValues;
137
172
  // delete 시 삭제 전 값 저장
138
173
  originallyExisted;
139
174
  // 트랜잭션 시작 시점에 디스크에 존재했던 키 (deleted 결과 필터링용)
175
+ bufferHistory = /* @__PURE__ */ new Map();
140
176
  // Nested Transaction Properties
141
177
  parent;
142
178
  localVersion;
@@ -150,7 +186,8 @@ var MVCCTransaction = class {
150
186
  versionIndex = /* @__PURE__ */ new Map();
151
187
  deletedCache = /* @__PURE__ */ new Map();
152
188
  activeTransactions = /* @__PURE__ */ new Set();
153
- constructor(strategy, parent, snapshotVersion) {
189
+ diskCache;
190
+ constructor(strategy, options, parent, snapshotVersion) {
154
191
  this.snapshotVersion = snapshotVersion ?? 0;
155
192
  this.writeBuffer = /* @__PURE__ */ new Map();
156
193
  this.deleteBuffer = /* @__PURE__ */ new Set();
@@ -165,6 +202,7 @@ var MVCCTransaction = class {
165
202
  this.snapshotLocalVersion = parent.localVersion;
166
203
  this.strategy = void 0;
167
204
  this.root = parent.root;
205
+ this.diskCache = parent.diskCache;
168
206
  } else {
169
207
  if (!strategy) throw new Error("Root Transaction must get Strategy");
170
208
  this.strategy = strategy;
@@ -172,8 +210,13 @@ var MVCCTransaction = class {
172
210
  this.localVersion = 0;
173
211
  this.snapshotLocalVersion = 0;
174
212
  this.root = this;
213
+ this.diskCache = new LRUMap(options?.cacheCapacity ?? 1e3);
175
214
  }
176
215
  }
216
+ /**
217
+ * Checks if the transaction is a root transaction.
218
+ * @returns True if the transaction is a root transaction, false otherwise.
219
+ */
177
220
  isRoot() {
178
221
  return !this.parent;
179
222
  }
@@ -190,27 +233,96 @@ var MVCCTransaction = class {
190
233
  }
191
234
  return false;
192
235
  }
193
- // --- Internal buffer manipulation helpers ---
194
- _bufferCreate(key, value) {
195
- this.localVersion++;
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
+ }
252
+ _recordHistory(key) {
253
+ const existsInWriteBuffer = this.writeBuffer.has(key);
254
+ const existsInDeleteBuffer = this.deleteBuffer.has(key);
255
+ const currentVer = this.keyVersions.get(key);
256
+ if (currentVer !== void 0) {
257
+ if (!this.bufferHistory.has(key)) this.bufferHistory.set(key, []);
258
+ this.bufferHistory.get(key).push({
259
+ value: existsInWriteBuffer ? this.writeBuffer.get(key) : this.deletedValues.get(key) ?? null,
260
+ exists: existsInWriteBuffer || !existsInDeleteBuffer,
261
+ version: currentVer
262
+ });
263
+ }
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
+ }
300
+ _bufferCreate(key, value, version) {
301
+ if (version === void 0) this.localVersion++;
302
+ const targetVersion = version ?? this.localVersion;
303
+ this._recordHistory(key);
196
304
  this.writeBuffer.set(key, value);
197
305
  this.createdKeys.add(key);
198
306
  this.deleteBuffer.delete(key);
199
307
  this.originallyExisted.delete(key);
200
- this.keyVersions.set(key, this.localVersion);
308
+ this.keyVersions.set(key, targetVersion);
201
309
  }
202
- _bufferWrite(key, value) {
203
- this.localVersion++;
310
+ _bufferWrite(key, value, version) {
311
+ if (version === void 0) this.localVersion++;
312
+ const targetVersion = version ?? this.localVersion;
313
+ this._recordHistory(key);
204
314
  this.writeBuffer.set(key, value);
205
315
  this.deleteBuffer.delete(key);
206
- this.keyVersions.set(key, this.localVersion);
316
+ this.keyVersions.set(key, targetVersion);
207
317
  }
208
- _bufferDelete(key) {
209
- this.localVersion++;
318
+ _bufferDelete(key, version) {
319
+ if (version === void 0) this.localVersion++;
320
+ const targetVersion = version ?? this.localVersion;
321
+ this._recordHistory(key);
210
322
  this.deleteBuffer.add(key);
211
323
  this.writeBuffer.delete(key);
212
324
  this.createdKeys.delete(key);
213
- this.keyVersions.set(key, this.localVersion);
325
+ this.keyVersions.set(key, targetVersion);
214
326
  }
215
327
  /**
216
328
  * Returns the entries that will be created, updated, and deleted by this transaction.
@@ -234,7 +346,11 @@ var MVCCTransaction = class {
234
346
  deleted.push({ key, data });
235
347
  }
236
348
  }
237
- return { created, updated, deleted };
349
+ return {
350
+ created,
351
+ updated,
352
+ deleted
353
+ };
238
354
  }
239
355
  /**
240
356
  * Rolls back the transaction.
@@ -252,7 +368,12 @@ var MVCCTransaction = class {
252
368
  if (this.root !== this) {
253
369
  this.root.activeTransactions.delete(this);
254
370
  }
255
- return { success: true, created, updated, deleted };
371
+ return {
372
+ success: true,
373
+ created,
374
+ updated,
375
+ deleted
376
+ };
256
377
  }
257
378
  /**
258
379
  * Cleans up both deletedCache and versionIndex based on minActiveVersion.
@@ -287,7 +408,9 @@ var MVCCTransaction = class {
287
408
  break;
288
409
  }
289
410
  }
290
- if (latestInSnapshotIdx > 0) {
411
+ if (latestInSnapshotIdx === versions.length - 1) {
412
+ this.versionIndex.delete(key);
413
+ } else if (latestInSnapshotIdx > 0) {
291
414
  versions.splice(0, latestInSnapshotIdx);
292
415
  }
293
416
  }
@@ -336,7 +459,7 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
336
459
  createNested() {
337
460
  if (this.committed) throw new Error("Transaction already committed");
338
461
  const childVersion = this.isRoot() ? this.version : this.snapshotVersion;
339
- const child = new _SyncMVCCTransaction(void 0, this, childVersion);
462
+ const child = new _SyncMVCCTransaction(void 0, void 0, this, childVersion);
340
463
  this.root.activeTransactions.add(child);
341
464
  return child;
342
465
  }
@@ -344,32 +467,77 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
344
467
  if (this.committed) throw new Error("Transaction already committed");
345
468
  if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
346
469
  if (this.deleteBuffer.has(key)) return null;
347
- return this.root._diskRead(key, this.snapshotVersion);
470
+ if (this.parent) {
471
+ return this.parent._readSnapshot(key, this.snapshotVersion, this.snapshotLocalVersion);
472
+ }
473
+ return this._diskRead(key, this.snapshotVersion);
348
474
  }
349
475
  exists(key) {
350
476
  if (this.committed) throw new Error("Transaction already committed");
351
477
  if (this.deleteBuffer.has(key)) return false;
352
478
  if (this.writeBuffer.has(key)) return true;
353
- return this.root._diskExists(key, this.snapshotVersion);
479
+ if (this.parent) {
480
+ return this.parent._existsSnapshot(key, this.snapshotVersion, this.snapshotLocalVersion);
481
+ }
482
+ return this._diskExists(key, this.snapshotVersion);
354
483
  }
355
- _readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
356
- if (this.writeBuffer.has(key)) {
357
- const keyModVersion = this.keyVersions.get(key);
358
- if (snapshotLocalVersion === void 0 || keyModVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
359
- return this.writeBuffer.get(key);
484
+ _existsSnapshot(key, snapshotVersion, snapshotLocalVersion) {
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);
360
506
  }
361
507
  }
362
- if (this.deleteBuffer.has(key)) {
363
- const keyModVersion = this.keyVersions.get(key);
364
- if (snapshotLocalVersion === void 0 || keyModVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
365
- return null;
508
+ return false;
509
+ }
510
+ _readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
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
+ }
519
+ }
520
+ if (current.deleteBuffer.has(key)) {
521
+ const keyModVersion = current.keyVersions.get(key);
522
+ if (slVer === void 0 || keyModVersion <= slVer) {
523
+ return null;
524
+ }
525
+ }
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;
531
+ }
532
+ }
533
+ if (current.parent) {
534
+ slVer = current.snapshotLocalVersion;
535
+ current = current.parent;
536
+ } else {
537
+ return current._diskRead(key, snapshotVersion);
366
538
  }
367
539
  }
368
- if (this.parent) {
369
- return this.parent._readSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
370
- } else {
371
- return this._diskRead(key, snapshotVersion);
372
- }
540
+ return null;
373
541
  }
374
542
  commit(label) {
375
543
  const { created, updated, deleted } = this.getResultEntries();
@@ -429,6 +597,7 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
429
597
  this.deletedValues.clear();
430
598
  this.originallyExisted.clear();
431
599
  this.keyVersions.clear();
600
+ this.bufferHistory.clear();
432
601
  this.localVersion = 0;
433
602
  this.snapshotVersion = this.version;
434
603
  }
@@ -469,32 +638,22 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
469
638
  };
470
639
  }
471
640
  }
472
- const newLocalVersion = this.localVersion + 1;
473
- for (const key of child.writeBuffer.keys()) {
474
- this.writeBuffer.set(key, child.writeBuffer.get(key));
475
- this.deleteBuffer.delete(key);
476
- this.keyVersions.set(key, newLocalVersion);
477
- if (child.createdKeys.has(key)) {
478
- this.createdKeys.add(key);
479
- }
641
+ const mergeVersion = ++this.localVersion;
642
+ for (const [key, value] of child.writeBuffer) {
643
+ const wasCreated = child.createdKeys.has(key);
644
+ if (wasCreated) this._bufferCreate(key, value, mergeVersion);
645
+ else this._bufferWrite(key, value, mergeVersion);
480
646
  }
481
647
  for (const key of child.deleteBuffer) {
482
- this.deleteBuffer.add(key);
483
- this.writeBuffer.delete(key);
484
- this.createdKeys.delete(key);
485
- this.keyVersions.set(key, newLocalVersion);
486
648
  const deletedValue = child.deletedValues.get(key);
487
- if (deletedValue !== void 0) {
488
- this.deletedValues.set(key, deletedValue);
489
- }
490
- if (child.originallyExisted.has(key)) {
649
+ if (deletedValue !== void 0) this.deletedValues.set(key, deletedValue);
650
+ if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
491
651
  this.originallyExisted.add(key);
492
652
  }
653
+ this._bufferDelete(key, mergeVersion);
493
654
  }
494
- this.localVersion = newLocalVersion;
495
655
  this.root.activeTransactions.delete(child);
496
656
  } else {
497
- const newVersion = this.version + 1;
498
657
  if (child !== this) {
499
658
  const modifiedKeys = /* @__PURE__ */ new Set([...child.writeBuffer.keys(), ...child.deleteBuffer]);
500
659
  for (const key of modifiedKeys) {
@@ -512,50 +671,57 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
512
671
  };
513
672
  }
514
673
  }
674
+ const lastModLocalVer = this.keyVersions.get(key);
675
+ if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
676
+ return {
677
+ error: `Commit conflict: Key '${key}' was modified by a newer transaction in the same session (Local v${lastModLocalVer})`,
678
+ conflict: {
679
+ key,
680
+ parent: this.read(key),
681
+ child: child.read(key)
682
+ }
683
+ };
684
+ }
515
685
  }
516
- }
517
- for (const [key, value] of child.writeBuffer) {
518
- this.writeBuffer.set(key, value);
519
- this.deleteBuffer.delete(key);
520
- if (child.createdKeys.has(key)) {
521
- this.createdKeys.add(key);
522
- }
523
- }
524
- for (const key of child.deleteBuffer) {
525
- this.deleteBuffer.add(key);
526
- this.writeBuffer.delete(key);
527
- this.createdKeys.delete(key);
528
- const deletedValue = child.deletedValues.get(key);
529
- if (deletedValue !== void 0) {
530
- this.deletedValues.set(key, deletedValue);
686
+ const mergeVersion = ++this.localVersion;
687
+ for (const [key, value] of child.writeBuffer) {
688
+ const wasCreated = child.createdKeys.has(key);
689
+ if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
690
+ this.originallyExisted.add(key);
691
+ }
692
+ if (wasCreated) this._bufferCreate(key, value, mergeVersion);
693
+ else this._bufferWrite(key, value, mergeVersion);
531
694
  }
532
- if (child.originallyExisted.has(key)) {
533
- this.originallyExisted.add(key);
695
+ for (const key of child.deleteBuffer) {
696
+ const deletedValue = child.deletedValues.get(key);
697
+ if (deletedValue !== void 0) this.deletedValues.set(key, deletedValue);
698
+ if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
699
+ this.originallyExisted.add(key);
700
+ }
701
+ this._bufferDelete(key, mergeVersion);
534
702
  }
703
+ this.root.activeTransactions.delete(child);
704
+ } else {
705
+ const newVersion = this.version + 1;
706
+ for (const [key, value] of this.writeBuffer) this._diskWrite(key, value, newVersion);
707
+ for (const key of this.deleteBuffer) this._diskDelete(key, newVersion);
708
+ this.version = newVersion;
709
+ this._cleanupDeletedCache();
535
710
  }
536
- for (const [key, value] of child.writeBuffer) {
537
- this._diskWrite(key, value, newVersion);
538
- }
539
- for (const key of child.deleteBuffer) {
540
- this._diskDelete(key, newVersion);
541
- }
542
- this.version = newVersion;
543
- this.root.activeTransactions.delete(child);
544
- this._cleanupDeletedCache();
545
711
  }
546
712
  return null;
547
713
  }
548
- // --- Internal IO Helpers (Root Only) ---
549
714
  _diskWrite(key, value, version) {
550
715
  const strategy = this.strategy;
551
716
  if (!strategy) throw new Error("Root Transaction missing strategy");
552
- if (strategy.exists(key)) {
553
- const currentVal = strategy.read(key);
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);
554
720
  if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
555
- this.deletedCache.get(key).push({
556
- value: currentVal,
557
- deletedAtVersion: version
558
- });
721
+ this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: version });
722
+ rootAsAny.diskCache.set(key, value);
723
+ } else {
724
+ rootAsAny.diskCache.set(key, value);
559
725
  }
560
726
  strategy.write(key, value);
561
727
  if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
@@ -566,36 +732,44 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
566
732
  if (!strategy) throw new Error("Root Transaction missing strategy");
567
733
  const versions = this.versionIndex.get(key);
568
734
  if (!versions) {
569
- return strategy.exists(key) ? strategy.read(key) : null;
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;
570
742
  }
571
743
  let targetVerObj = null;
572
744
  let nextVerObj = null;
573
- for (const v of versions) {
574
- if (v.version <= snapshotVersion) {
575
- targetVerObj = v;
576
- } else {
577
- nextVerObj = v;
578
- break;
579
- }
580
- }
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];
581
748
  if (!targetVerObj) {
582
749
  if (nextVerObj) {
583
750
  const cached2 = this.deletedCache.get(key);
584
751
  if (cached2) {
585
- const match = cached2.find((c) => c.deletedAtVersion === nextVerObj.version);
586
- if (match) return match.value;
752
+ const cIdx = this._findExact(cached2, nextVerObj.version, "deletedAtVersion");
753
+ if (cIdx >= 0) return cached2[cIdx].value;
587
754
  }
588
755
  }
589
756
  return null;
590
757
  }
591
758
  if (!targetVerObj.exists) return null;
592
759
  if (!nextVerObj) {
593
- return strategy.read(key);
760
+ if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
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;
594
768
  }
595
769
  const cached = this.deletedCache.get(key);
596
770
  if (cached) {
597
- const match = cached.find((c) => c.deletedAtVersion === nextVerObj.version);
598
- if (match) return match.value;
771
+ const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
772
+ if (cIdx >= 0) return cached[cIdx].value;
599
773
  }
600
774
  return null;
601
775
  }
@@ -604,31 +778,40 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
604
778
  if (!strategy) throw new Error("Root Transaction missing strategy");
605
779
  const versions = this.versionIndex.get(key);
606
780
  if (!versions) {
607
- return strategy.exists(key);
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;
608
786
  }
609
787
  let targetVerObj = null;
610
- for (const v of versions) {
611
- if (v.version <= snapshotVersion) {
612
- targetVerObj = v;
613
- } else {
614
- break;
788
+ let nextVerObj = null;
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];
792
+ if (!targetVerObj) {
793
+ if (nextVerObj) {
794
+ const cached = this.deletedCache.get(key);
795
+ if (cached) {
796
+ const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
797
+ if (cIdx >= 0) return true;
798
+ }
615
799
  }
800
+ return false;
616
801
  }
617
- if (!targetVerObj) return strategy.exists(key);
618
802
  return targetVerObj.exists;
619
803
  }
620
804
  _diskDelete(key, snapshotVersion) {
621
805
  const strategy = this.strategy;
622
806
  if (!strategy) throw new Error("Root Transaction missing strategy");
623
- if (strategy.exists(key)) {
624
- const currentVal = strategy.read(key);
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);
625
810
  if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
626
- this.deletedCache.get(key).push({
627
- value: currentVal,
628
- deletedAtVersion: snapshotVersion
629
- });
811
+ this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: snapshotVersion });
812
+ strategy.delete(key);
813
+ rootAsAny.diskCache.delete(key);
630
814
  }
631
- strategy.delete(key);
632
815
  if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
633
816
  this.versionIndex.get(key).push({ version: snapshotVersion, exists: false });
634
817
  }
@@ -941,7 +1124,7 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
941
1124
  createNested() {
942
1125
  if (this.committed) throw new Error("Transaction already committed");
943
1126
  const childVersion = this.isRoot() ? this.version : this.snapshotVersion;
944
- const child = new _AsyncMVCCTransaction(void 0, this, childVersion);
1127
+ const child = new _AsyncMVCCTransaction(void 0, void 0, this, childVersion);
945
1128
  this.root.activeTransactions.add(child);
946
1129
  return child;
947
1130
  }
@@ -949,32 +1132,77 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
949
1132
  if (this.committed) throw new Error("Transaction already committed");
950
1133
  if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
951
1134
  if (this.deleteBuffer.has(key)) return null;
952
- return this.root._diskRead(key, this.snapshotVersion);
1135
+ if (this.parent) {
1136
+ return this.parent._readSnapshot(key, this.snapshotVersion, this.snapshotLocalVersion);
1137
+ }
1138
+ return await this._diskRead(key, this.snapshotVersion);
953
1139
  }
954
1140
  async exists(key) {
955
1141
  if (this.committed) throw new Error("Transaction already committed");
956
1142
  if (this.deleteBuffer.has(key)) return false;
957
1143
  if (this.writeBuffer.has(key)) return true;
958
- return this.root._diskExists(key, this.snapshotVersion);
1144
+ if (this.parent) {
1145
+ return this.parent._existsSnapshot(key, this.snapshotVersion, this.snapshotLocalVersion);
1146
+ }
1147
+ return await this._diskExists(key, this.snapshotVersion);
959
1148
  }
960
- async _readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
961
- if (this.writeBuffer.has(key)) {
962
- const keyModVersion = this.keyVersions.get(key);
963
- if (snapshotLocalVersion === void 0 || keyModVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
964
- return this.writeBuffer.get(key);
1149
+ async _existsSnapshot(key, snapshotVersion, snapshotLocalVersion) {
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);
965
1171
  }
966
1172
  }
967
- if (this.deleteBuffer.has(key)) {
968
- const keyModVersion = this.keyVersions.get(key);
969
- if (snapshotLocalVersion === void 0 || keyModVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
970
- return null;
1173
+ return false;
1174
+ }
1175
+ async _readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
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
+ }
1184
+ }
1185
+ if (current.deleteBuffer.has(key)) {
1186
+ const keyModVersion = current.keyVersions.get(key);
1187
+ if (slVer === void 0 || keyModVersion <= slVer) {
1188
+ return null;
1189
+ }
1190
+ }
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;
1196
+ }
1197
+ }
1198
+ if (current.parent) {
1199
+ slVer = current.snapshotLocalVersion;
1200
+ current = current.parent;
1201
+ } else {
1202
+ return await current._diskRead(key, snapshotVersion);
971
1203
  }
972
1204
  }
973
- if (this.parent) {
974
- return this.parent._readSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
975
- } else {
976
- return this._diskRead(key, snapshotVersion);
977
- }
1205
+ return null;
978
1206
  }
979
1207
  async commit(label) {
980
1208
  const { created, updated, deleted } = this.getResultEntries();
@@ -1034,6 +1262,7 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
1034
1262
  this.deletedValues.clear();
1035
1263
  this.originallyExisted.clear();
1036
1264
  this.keyVersions.clear();
1265
+ this.bufferHistory.clear();
1037
1266
  this.localVersion = 0;
1038
1267
  this.snapshotVersion = this.version;
1039
1268
  }
@@ -1075,33 +1304,23 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
1075
1304
  };
1076
1305
  }
1077
1306
  }
1078
- const newLocalVersion = this.localVersion + 1;
1079
- for (const key of child.writeBuffer.keys()) {
1080
- this.writeBuffer.set(key, child.writeBuffer.get(key));
1081
- this.deleteBuffer.delete(key);
1082
- this.keyVersions.set(key, newLocalVersion);
1083
- if (child.createdKeys.has(key)) {
1084
- this.createdKeys.add(key);
1085
- }
1307
+ const mergeVersion = ++this.localVersion;
1308
+ for (const [key, value] of child.writeBuffer) {
1309
+ const wasCreated = child.createdKeys.has(key);
1310
+ if (wasCreated) this._bufferCreate(key, value, mergeVersion);
1311
+ else this._bufferWrite(key, value, mergeVersion);
1086
1312
  }
1087
1313
  for (const key of child.deleteBuffer) {
1088
- this.deleteBuffer.add(key);
1089
- this.writeBuffer.delete(key);
1090
- this.createdKeys.delete(key);
1091
- this.keyVersions.set(key, newLocalVersion);
1092
1314
  const deletedValue = child.deletedValues.get(key);
1093
- if (deletedValue !== void 0) {
1094
- this.deletedValues.set(key, deletedValue);
1095
- }
1096
- if (child.originallyExisted.has(key)) {
1315
+ if (deletedValue !== void 0) this.deletedValues.set(key, deletedValue);
1316
+ if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
1097
1317
  this.originallyExisted.add(key);
1098
1318
  }
1319
+ this._bufferDelete(key, mergeVersion);
1099
1320
  }
1100
- this.localVersion = newLocalVersion;
1101
1321
  this.root.activeTransactions.delete(child);
1102
1322
  return null;
1103
1323
  } else {
1104
- const newVersion = this.version + 1;
1105
1324
  if (child !== this) {
1106
1325
  const modifiedKeys = /* @__PURE__ */ new Set([...child.writeBuffer.keys(), ...child.deleteBuffer]);
1107
1326
  for (const key of modifiedKeys) {
@@ -1119,51 +1338,58 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
1119
1338
  };
1120
1339
  }
1121
1340
  }
1341
+ const lastModLocalVer = this.keyVersions.get(key);
1342
+ if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
1343
+ return {
1344
+ error: `Commit conflict: Key '${key}' was modified by a newer transaction in the same session (Local v${lastModLocalVer})`,
1345
+ conflict: {
1346
+ key,
1347
+ parent: await this.read(key),
1348
+ child: await child.read(key)
1349
+ }
1350
+ };
1351
+ }
1122
1352
  }
1123
- }
1124
- for (const [key, value] of child.writeBuffer) {
1125
- this.writeBuffer.set(key, value);
1126
- this.deleteBuffer.delete(key);
1127
- if (child.createdKeys.has(key)) {
1128
- this.createdKeys.add(key);
1129
- }
1130
- }
1131
- for (const key of child.deleteBuffer) {
1132
- this.deleteBuffer.add(key);
1133
- this.writeBuffer.delete(key);
1134
- this.createdKeys.delete(key);
1135
- const deletedValue = child.deletedValues.get(key);
1136
- if (deletedValue !== void 0) {
1137
- this.deletedValues.set(key, deletedValue);
1353
+ const mergeVersion = ++this.localVersion;
1354
+ for (const [key, value] of child.writeBuffer) {
1355
+ const wasCreated = child.createdKeys.has(key);
1356
+ if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
1357
+ this.originallyExisted.add(key);
1358
+ }
1359
+ if (wasCreated) this._bufferCreate(key, value, mergeVersion);
1360
+ else this._bufferWrite(key, value, mergeVersion);
1138
1361
  }
1139
- if (child.originallyExisted.has(key)) {
1140
- this.originallyExisted.add(key);
1362
+ for (const key of child.deleteBuffer) {
1363
+ const deletedValue = child.deletedValues.get(key);
1364
+ if (deletedValue !== void 0) this.deletedValues.set(key, deletedValue);
1365
+ if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
1366
+ this.originallyExisted.add(key);
1367
+ }
1368
+ this._bufferDelete(key, mergeVersion);
1141
1369
  }
1370
+ this.root.activeTransactions.delete(child);
1371
+ } else {
1372
+ const newVersion = this.version + 1;
1373
+ for (const [key, value] of this.writeBuffer) await this._diskWrite(key, value, newVersion);
1374
+ for (const key of this.deleteBuffer) await this._diskDelete(key, newVersion);
1375
+ this.version = newVersion;
1376
+ this._cleanupDeletedCache();
1142
1377
  }
1143
- for (const [key, value] of child.writeBuffer) {
1144
- await this._diskWrite(key, value, newVersion);
1145
- }
1146
- for (const key of child.deleteBuffer) {
1147
- await this._diskDelete(key, newVersion);
1148
- }
1149
- this.version = newVersion;
1150
- this.root.activeTransactions.delete(child);
1151
- this._cleanupDeletedCache();
1152
1378
  return null;
1153
1379
  }
1154
1380
  });
1155
1381
  }
1156
- // --- Internal IO Helpers (Root Only) ---
1157
1382
  async _diskWrite(key, value, version) {
1158
1383
  const strategy = this.strategy;
1159
1384
  if (!strategy) throw new Error("Root Transaction missing strategy");
1160
- if (await strategy.exists(key)) {
1161
- const currentVal = await strategy.read(key);
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);
1162
1388
  if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
1163
- this.deletedCache.get(key).push({
1164
- value: currentVal,
1165
- deletedAtVersion: version
1166
- });
1389
+ this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: version });
1390
+ rootAsAny.diskCache.set(key, value);
1391
+ } else {
1392
+ rootAsAny.diskCache.set(key, value);
1167
1393
  }
1168
1394
  await strategy.write(key, value);
1169
1395
  if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
@@ -1174,36 +1400,44 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
1174
1400
  if (!strategy) throw new Error("Root Transaction missing strategy");
1175
1401
  const versions = this.versionIndex.get(key);
1176
1402
  if (!versions) {
1177
- return await strategy.exists(key) ? strategy.read(key) : null;
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;
1178
1410
  }
1179
1411
  let targetVerObj = null;
1180
1412
  let nextVerObj = null;
1181
- for (const v of versions) {
1182
- if (v.version <= snapshotVersion) {
1183
- targetVerObj = v;
1184
- } else {
1185
- nextVerObj = v;
1186
- break;
1187
- }
1188
- }
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];
1189
1416
  if (!targetVerObj) {
1190
1417
  if (nextVerObj) {
1191
1418
  const cached2 = this.deletedCache.get(key);
1192
1419
  if (cached2) {
1193
- const match = cached2.find((c) => c.deletedAtVersion === nextVerObj.version);
1194
- if (match) return match.value;
1420
+ const cIdx = this._findExact(cached2, nextVerObj.version, "deletedAtVersion");
1421
+ if (cIdx >= 0) return cached2[cIdx].value;
1195
1422
  }
1196
1423
  }
1197
1424
  return null;
1198
1425
  }
1199
1426
  if (!targetVerObj.exists) return null;
1200
1427
  if (!nextVerObj) {
1201
- return strategy.read(key);
1428
+ if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
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;
1202
1436
  }
1203
1437
  const cached = this.deletedCache.get(key);
1204
1438
  if (cached) {
1205
- const match = cached.find((c) => c.deletedAtVersion === nextVerObj.version);
1206
- if (match) return match.value;
1439
+ const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
1440
+ if (cIdx >= 0) return cached[cIdx].value;
1207
1441
  }
1208
1442
  return null;
1209
1443
  }
@@ -1212,359 +1446,47 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
1212
1446
  if (!strategy) throw new Error("Root Transaction missing strategy");
1213
1447
  const versions = this.versionIndex.get(key);
1214
1448
  if (!versions) {
1215
- return strategy.exists(key);
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;
1216
1454
  }
1217
1455
  let targetVerObj = null;
1218
- for (const v of versions) {
1219
- if (v.version <= snapshotVersion) {
1220
- targetVerObj = v;
1221
- } else {
1222
- break;
1456
+ let nextVerObj = null;
1457
+ const idx = this._findLastLE(versions, snapshotVersion, "version");
1458
+ if (idx >= 0) targetVerObj = versions[idx];
1459
+ if (idx + 1 < versions.length) nextVerObj = versions[idx + 1];
1460
+ if (!targetVerObj) {
1461
+ if (nextVerObj) {
1462
+ const cached = this.deletedCache.get(key);
1463
+ if (cached) {
1464
+ const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
1465
+ if (cIdx >= 0) return true;
1466
+ }
1223
1467
  }
1468
+ return false;
1224
1469
  }
1225
- if (!targetVerObj) return strategy.exists(key);
1226
1470
  return targetVerObj.exists;
1227
1471
  }
1228
1472
  async _diskDelete(key, snapshotVersion) {
1229
1473
  const strategy = this.strategy;
1230
1474
  if (!strategy) throw new Error("Root Transaction missing strategy");
1231
- if (await strategy.exists(key)) {
1232
- const currentVal = await strategy.read(key);
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);
1233
1478
  if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
1234
- this.deletedCache.get(key).push({
1235
- value: currentVal,
1236
- deletedAtVersion: snapshotVersion
1237
- });
1479
+ this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: snapshotVersion });
1480
+ await strategy.delete(key);
1481
+ rootAsAny.diskCache.delete(key);
1238
1482
  }
1239
- await strategy.delete(key);
1240
1483
  if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
1241
1484
  this.versionIndex.get(key).push({ version: snapshotVersion, exists: false });
1242
1485
  }
1243
1486
  };
1244
- var LRUMap = class {
1245
- capacity;
1246
- map;
1247
- head = null;
1248
- tail = null;
1249
- /**
1250
- * Creates an instance of LRUMap.
1251
- * @param capacity The maximum number of items the cache can hold.
1252
- */
1253
- constructor(capacity) {
1254
- this.capacity = capacity;
1255
- this.map = /* @__PURE__ */ new Map();
1256
- }
1257
- /**
1258
- * Promotes a node to the head of the linked list (marks as most recently used).
1259
- * @param node The node to promote.
1260
- */
1261
- promote(node) {
1262
- this.extract(node);
1263
- this.prepend(node);
1264
- }
1265
- /**
1266
- * Disconnects a node from the doubly linked list.
1267
- * @param node The node to extract.
1268
- */
1269
- extract(node) {
1270
- if (node.prev) node.prev.next = node.next;
1271
- else this.head = node.next;
1272
- if (node.next) node.next.prev = node.prev;
1273
- else this.tail = node.prev;
1274
- node.prev = null;
1275
- node.next = null;
1276
- }
1277
- /**
1278
- * Inserts a node at the head of the doubly linked list.
1279
- * @param node The node to prepend.
1280
- */
1281
- prepend(node) {
1282
- node.next = this.head;
1283
- if (this.head) this.head.prev = node;
1284
- this.head = node;
1285
- if (!this.tail) this.tail = node;
1286
- }
1287
- /**
1288
- * Stores or updates a value by key.
1289
- * If the capacity is exceeded, the least recently used item (tail) is removed.
1290
- * @param key The key to store.
1291
- * @param value The value to store.
1292
- */
1293
- set(key, value) {
1294
- const existing = this.map.get(key);
1295
- if (existing) {
1296
- existing.value = value;
1297
- this.promote(existing);
1298
- return;
1299
- }
1300
- const newNode = { key, value, prev: null, next: null };
1301
- this.map.set(key, newNode);
1302
- this.prepend(newNode);
1303
- if (this.map.size > this.capacity && this.tail) {
1304
- this.map.delete(this.tail.key);
1305
- this.extract(this.tail);
1306
- }
1307
- }
1308
- /**
1309
- * Retrieves a value by key.
1310
- * Accessing the item moves it to the "most recently used" position.
1311
- * @param key The key to look for.
1312
- * @returns The value associated with the key, or undefined if not found.
1313
- */
1314
- get(key) {
1315
- const node = this.map.get(key);
1316
- if (!node) return void 0;
1317
- this.promote(node);
1318
- return node.value;
1319
- }
1320
- /**
1321
- * Checks if a key exists in the cache without changing its access order.
1322
- * @param key The key to check.
1323
- * @returns True if the key exists, false otherwise.
1324
- */
1325
- has(key) {
1326
- return this.map.has(key);
1327
- }
1328
- /**
1329
- * Removes a key and its associated value from the cache.
1330
- * @param key The key to remove.
1331
- * @returns True if the key was found and removed, false otherwise.
1332
- */
1333
- delete(key) {
1334
- const node = this.map.get(key);
1335
- if (!node) return false;
1336
- this.extract(node);
1337
- this.map.delete(key);
1338
- return true;
1339
- }
1340
- /**
1341
- * Returns an iterator of keys in the order of most recently used to least recently used.
1342
- * @returns An iterable iterator of keys.
1343
- */
1344
- *keys() {
1345
- let current = this.head;
1346
- while (current) {
1347
- yield current.key;
1348
- current = current.next;
1349
- }
1350
- }
1351
- /**
1352
- * Returns the current number of items in the cache.
1353
- */
1354
- get size() {
1355
- return this.map.size;
1356
- }
1357
- /**
1358
- * Clears all items from the cache.
1359
- */
1360
- clear() {
1361
- this.map.clear();
1362
- this.head = null;
1363
- this.tail = null;
1364
- }
1365
- };
1366
- var CacheEntanglement = class {
1367
- creation;
1368
- beforeUpdateHook;
1369
- capacity;
1370
- dependencies;
1371
- caches;
1372
- parameters;
1373
- assignments;
1374
- dependencyProperties;
1375
- updateRequirements;
1376
- constructor(creation, option) {
1377
- option = option ?? {};
1378
- const {
1379
- dependencies,
1380
- capacity,
1381
- beforeUpdateHook
1382
- } = option;
1383
- this.creation = creation;
1384
- this.beforeUpdateHook = beforeUpdateHook ?? (() => {
1385
- });
1386
- this.capacity = capacity ?? 100;
1387
- this.assignments = [];
1388
- this.caches = new LRUMap(this.capacity);
1389
- this.parameters = /* @__PURE__ */ new Map();
1390
- this.dependencies = dependencies ?? {};
1391
- this.dependencyProperties = Object.keys(this.dependencies);
1392
- this.updateRequirements = /* @__PURE__ */ new Set();
1393
- for (const name in this.dependencies) {
1394
- const dependency = this.dependencies[name];
1395
- if (!dependency.assignments.includes(this)) {
1396
- dependency.assignments.push(this);
1397
- }
1398
- }
1399
- }
1400
- bubbleUpdateSignal(key) {
1401
- this.updateRequirements.add(key);
1402
- for (let i = 0, len = this.assignments.length; i < len; i++) {
1403
- const t = this.assignments[i];
1404
- const instance = t;
1405
- for (const cacheKey of instance.caches.keys()) {
1406
- if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
1407
- instance.bubbleUpdateSignal(cacheKey);
1408
- }
1409
- }
1410
- }
1411
- }
1412
- dependencyKey(key) {
1413
- const i = key.lastIndexOf("/");
1414
- if (i === -1) {
1415
- return key;
1416
- }
1417
- return key.substring(0, i);
1418
- }
1419
- /**
1420
- * Returns all keys stored in the instance.
1421
- */
1422
- keys() {
1423
- return this.parameters.keys();
1424
- }
1425
- /**
1426
- * Deletes all cache values stored in the instance.
1427
- */
1428
- clear() {
1429
- for (const key of this.keys()) {
1430
- this.delete(key);
1431
- }
1432
- }
1433
- /**
1434
- * Checks if there is a cache value stored in the key within the instance.
1435
- * @param key The key to search.
1436
- */
1437
- exists(key) {
1438
- return this.parameters.has(key);
1439
- }
1440
- /**
1441
- * Checks if there is a cache value stored in the key within the instance.
1442
- * This method is an alias for `exists`.
1443
- * @param key The key to search.
1444
- */
1445
- has(key) {
1446
- return this.exists(key);
1447
- }
1448
- /**
1449
- * Deletes the cache value stored in the key within the instance.
1450
- * @param key The key to delete.
1451
- */
1452
- delete(key) {
1453
- this.caches.delete(key);
1454
- this.parameters.delete(key);
1455
- this.updateRequirements.delete(key);
1456
- for (let i = 0, len = this.assignments.length; i < len; i++) {
1457
- const t = this.assignments[i];
1458
- const instance = t;
1459
- for (const cacheKey of instance.keys()) {
1460
- if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
1461
- instance.delete(cacheKey);
1462
- }
1463
- }
1464
- }
1465
- }
1466
- };
1467
- var CacheData = class _CacheData {
1468
- static StructuredClone = globalThis.structuredClone.bind(globalThis);
1469
- _value;
1470
- constructor(value) {
1471
- this._value = value;
1472
- }
1473
- /**
1474
- * This is cached data.
1475
- * It was generated at the time of caching, so there is a risk of modification if it's an object due to shallow copying.
1476
- * 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.
1477
- */
1478
- get raw() {
1479
- return this._value;
1480
- }
1481
- /**
1482
- * The method returns a copied value of the cached data.
1483
- * You can pass a function as a parameter to copy the value. This parameter function should return the copied value.
1484
- *
1485
- * If no parameter is passed, it defaults to using `structuredClone` function to copy the value.
1486
- * If you prefer shallow copying instead of deep copying,
1487
- * you can use the default options `array-shallow-copy`, `object-shallow-copy` and `deep-copy`,
1488
- * which are replaced with functions to shallow copy arrays and objects, respectively. This is a syntactic sugar.
1489
- * @param strategy The function that returns the copied value.
1490
- * If you want to perform a shallow copy, simply pass the strings `array-shallow-copy` or `object-shallow-copy` for easy use.
1491
- * The `array-shallow-copy` strategy performs a shallow copy of an array.
1492
- * The `object-shallow-copy` strategy performs a shallow copy of an object.
1493
- * The `deep-copy` strategy performs a deep copy of the value using `structuredClone`.
1494
- * The default is `deep-copy`.
1495
- */
1496
- clone(strategy = "deep-copy") {
1497
- if (strategy && typeof strategy !== "string") {
1498
- return strategy(this.raw);
1499
- }
1500
- switch (strategy) {
1501
- case "array-shallow-copy":
1502
- return [].concat(this.raw);
1503
- case "object-shallow-copy":
1504
- return Object.assign({}, this.raw);
1505
- case "deep-copy":
1506
- default:
1507
- return _CacheData.StructuredClone(this.raw);
1508
- }
1509
- }
1510
- };
1511
- var CacheEntanglementSync = class extends CacheEntanglement {
1512
- constructor(creation, option) {
1513
- super(creation, option);
1514
- }
1515
- recache(key) {
1516
- if (!this.parameters.has(key)) {
1517
- return;
1518
- }
1519
- if (!this.caches.has(key) || this.updateRequirements.has(key)) {
1520
- this.resolve(key, ...this.parameters.get(key));
1521
- }
1522
- return this.caches.get(key);
1523
- }
1524
- resolve(key, ...parameter) {
1525
- const resolved = {};
1526
- const dependencyKey = this.dependencyKey(key);
1527
- this.beforeUpdateHook(key, dependencyKey, ...parameter);
1528
- for (let i = 0, len = this.dependencyProperties.length; i < len; i++) {
1529
- const name = this.dependencyProperties[i];
1530
- const dependency = this.dependencies[name];
1531
- if (!dependency.exists(key) && !dependency.exists(dependencyKey)) {
1532
- throw new Error(`The key '${key}' or '${dependencyKey}' has not been assigned yet in dependency '${name.toString()}'.`, {
1533
- cause: {
1534
- from: this
1535
- }
1536
- });
1537
- }
1538
- const dependencyValue = dependency.recache(key) ?? dependency.recache(dependencyKey);
1539
- resolved[name] = dependencyValue;
1540
- }
1541
- const value = new CacheData(this.creation(key, resolved, ...parameter));
1542
- this.updateRequirements.delete(key);
1543
- this.parameters.set(key, parameter);
1544
- this.caches.set(key, value);
1545
- return value;
1546
- }
1547
- get(key) {
1548
- if (!this.parameters.has(key)) {
1549
- throw new Error(`Cache value not found: ${key}`);
1550
- }
1551
- return this.cache(key, ...this.parameters.get(key));
1552
- }
1553
- cache(key, ...parameter) {
1554
- if (!this.caches.has(key) || this.updateRequirements.has(key)) {
1555
- this.resolve(key, ...parameter);
1556
- }
1557
- return this.caches.get(key);
1558
- }
1559
- update(key, ...parameter) {
1560
- this.bubbleUpdateSignal(key);
1561
- this.resolve(key, ...parameter);
1562
- return this.caches.get(key);
1563
- }
1564
- };
1565
1487
  var BPTreeTransaction = class _BPTreeTransaction {
1566
- _cachedRegexp;
1567
- nodes;
1488
+ _cachedRegexp = /* @__PURE__ */ new Map();
1489
+ nodes = /* @__PURE__ */ new Map();
1568
1490
  deletedNodeBuffer = /* @__PURE__ */ new Map();
1569
1491
  rootTx;
1570
1492
  mvccRoot;
@@ -1574,6 +1496,8 @@ var BPTreeTransaction = class _BPTreeTransaction {
1574
1496
  option;
1575
1497
  order;
1576
1498
  rootId;
1499
+ isInitialized = false;
1500
+ isDestroyed = false;
1577
1501
  verifierMap = {
1578
1502
  gt: (nv, v) => this.comparator.isHigher(nv, v),
1579
1503
  gte: (nv, v) => this.comparator.isHigher(nv, v) || this.comparator.isSame(nv, v),
@@ -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
- const cache = this._cachedRegexp.cache(value);
1596
- const regexp = cache.raw;
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)) {
@@ -1838,13 +1758,25 @@ var BPTreeTransaction = class _BPTreeTransaction {
1838
1758
  getResultEntries() {
1839
1759
  return this.mvcc.getResultEntries();
1840
1760
  }
1761
+ _clearCache() {
1762
+ this._cachedRegexp.clear();
1763
+ }
1841
1764
  /**
1842
1765
  * Clears all cached nodes.
1843
1766
  * This method is useful for freeing up memory when the tree is no longer needed.
1844
1767
  */
1845
1768
  clear() {
1846
- this._cachedRegexp.clear();
1847
- this.nodes.clear();
1769
+ if (this.rootTx !== this) {
1770
+ throw new Error("Cannot call clear on a nested transaction");
1771
+ }
1772
+ this._clearInternal();
1773
+ }
1774
+ _clearInternal() {
1775
+ if (this.isDestroyed) {
1776
+ throw new Error("Transaction already destroyed");
1777
+ }
1778
+ this._clearCache();
1779
+ this.isDestroyed = true;
1848
1780
  }
1849
1781
  _binarySearchValues(values, target, usePrimary = false, upperBound = false) {
1850
1782
  let low = 0;
@@ -1878,9 +1810,6 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
1878
1810
  );
1879
1811
  }
1880
1812
  getNode(id) {
1881
- if (this.nodes.has(id)) {
1882
- return this.nodes.get(id);
1883
- }
1884
1813
  return this.mvcc.read(id);
1885
1814
  }
1886
1815
  /**
@@ -1898,23 +1827,22 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
1898
1827
  prev
1899
1828
  };
1900
1829
  this.mvcc.create(id, node);
1901
- this.nodes.set(id, node);
1902
1830
  return node;
1903
1831
  }
1904
1832
  _updateNode(node) {
1833
+ if (this.mvcc.isDeleted(node.id)) {
1834
+ return;
1835
+ }
1905
1836
  this.mvcc.write(node.id, node);
1906
- this.nodes.set(node.id, node);
1907
1837
  }
1908
1838
  _deleteNode(node) {
1839
+ if (this.mvcc.isDeleted(node.id)) {
1840
+ return;
1841
+ }
1909
1842
  this.mvcc.delete(node.id);
1910
- this.nodes.delete(node.id);
1911
1843
  }
1912
1844
  _readHead() {
1913
- if (this.nodes.has("__HEAD__")) {
1914
- return this.nodes.get("__HEAD__") ?? null;
1915
- }
1916
- const head = this.mvcc.read("__HEAD__");
1917
- return head ?? null;
1845
+ return this.mvcc.read("__HEAD__");
1918
1846
  }
1919
1847
  _writeHead(head) {
1920
1848
  if (!this.mvcc.exists("__HEAD__")) {
@@ -1922,49 +1850,56 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
1922
1850
  } else {
1923
1851
  this.mvcc.write("__HEAD__", head);
1924
1852
  }
1925
- this.nodes.set("__HEAD__", head);
1926
1853
  this.rootId = head.root;
1927
1854
  }
1928
1855
  _insertAtLeaf(node, key, value) {
1929
- if (node.values.length) {
1930
- for (let i = 0, len = node.values.length; i < len; i++) {
1931
- const nValue = node.values[i];
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];
1932
1860
  if (this.comparator.isSame(value, nValue)) {
1933
- const keys = node.keys[i];
1861
+ const keys = leaf.keys[i];
1934
1862
  if (keys.includes(key)) {
1935
1863
  break;
1936
1864
  }
1937
- keys.push(key);
1938
- this._updateNode(node);
1939
- return;
1865
+ leaf = this._cloneNode(leaf);
1866
+ leaf.keys[i].push(key);
1867
+ this._updateNode(leaf);
1868
+ return leaf;
1940
1869
  } else if (this.comparator.isLower(value, nValue)) {
1941
- node.values.splice(i, 0, value);
1942
- node.keys.splice(i, 0, [key]);
1943
- this._updateNode(node);
1944
- return;
1945
- } else if (i + 1 === node.values.length) {
1946
- node.values.push(value);
1947
- node.keys.push([key]);
1948
- this._updateNode(node);
1949
- return;
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;
1950
1881
  }
1951
1882
  }
1952
1883
  } else {
1953
- node.values = [value];
1954
- node.keys = [[key]];
1955
- this._updateNode(node);
1956
- return;
1884
+ leaf = this._cloneNode(leaf);
1885
+ leaf.values = [value];
1886
+ leaf.keys = [[key]];
1887
+ this._updateNode(leaf);
1888
+ return leaf;
1957
1889
  }
1890
+ return leaf;
1958
1891
  }
1959
- _insertInParent(node, value, pointer) {
1892
+ _insertInParent(node, value, newSiblingNode) {
1960
1893
  if (this.rootId === node.id) {
1961
- const root = this._createNode(false, [node.id, pointer.id], [value]);
1894
+ node = this._cloneNode(node);
1895
+ newSiblingNode = this._cloneNode(newSiblingNode);
1896
+ const root = this._createNode(false, [node.id, newSiblingNode.id], [value]);
1962
1897
  this.rootId = root.id;
1963
1898
  node.parent = root.id;
1964
- pointer.parent = root.id;
1965
- if (pointer.leaf) {
1966
- node.next = pointer.id;
1967
- pointer.prev = node.id;
1899
+ newSiblingNode.parent = root.id;
1900
+ if (newSiblingNode.leaf) {
1901
+ node.next = newSiblingNode.id;
1902
+ newSiblingNode.prev = node.id;
1968
1903
  }
1969
1904
  this._writeHead({
1970
1905
  root: root.id,
@@ -1972,53 +1907,54 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
1972
1907
  data: this.strategy.head.data
1973
1908
  });
1974
1909
  this._updateNode(node);
1975
- this._updateNode(pointer);
1910
+ this._updateNode(newSiblingNode);
1976
1911
  return;
1977
1912
  }
1978
- const parentNode = this.getNode(node.parent);
1913
+ const parentNode = this._cloneNode(this.getNode(node.parent));
1979
1914
  const nodeIndex = parentNode.keys.indexOf(node.id);
1980
1915
  if (nodeIndex === -1) {
1981
1916
  throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
1982
1917
  }
1983
1918
  parentNode.values.splice(nodeIndex, 0, value);
1984
- parentNode.keys.splice(nodeIndex + 1, 0, pointer.id);
1985
- pointer.parent = parentNode.id;
1986
- if (pointer.leaf) {
1987
- const leftSibling = node;
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);
1988
1924
  const oldNextId = leftSibling.next;
1989
- pointer.prev = leftSibling.id;
1990
- pointer.next = oldNextId;
1991
- leftSibling.next = pointer.id;
1925
+ newSiblingNode.prev = leftSibling.id;
1926
+ newSiblingNode.next = oldNextId;
1927
+ leftSibling.next = newSiblingNode.id;
1992
1928
  this._updateNode(leftSibling);
1993
1929
  if (oldNextId) {
1994
- const oldNext = this.getNode(oldNextId);
1995
- oldNext.prev = pointer.id;
1930
+ const oldNext = this._cloneNode(this.getNode(oldNextId));
1931
+ oldNext.prev = newSiblingNode.id;
1996
1932
  this._updateNode(oldNext);
1997
1933
  }
1998
1934
  }
1999
1935
  this._updateNode(parentNode);
2000
- this._updateNode(pointer);
1936
+ this._updateNode(newSiblingNode);
2001
1937
  if (parentNode.keys.length > this.order) {
2002
- const parentPointer = this._createNode(false, [], []);
2003
- parentPointer.parent = parentNode.parent;
1938
+ const newSiblingNodeRecursive = this._createNode(false, [], []);
1939
+ newSiblingNodeRecursive.parent = parentNode.parent;
2004
1940
  const mid = Math.ceil(this.order / 2) - 1;
2005
- parentPointer.values = parentNode.values.slice(mid + 1);
2006
- parentPointer.keys = parentNode.keys.slice(mid + 1);
1941
+ newSiblingNodeRecursive.values = parentNode.values.slice(mid + 1);
1942
+ newSiblingNodeRecursive.keys = parentNode.keys.slice(mid + 1);
2007
1943
  const midValue = parentNode.values[mid];
2008
1944
  parentNode.values = parentNode.values.slice(0, mid);
2009
1945
  parentNode.keys = parentNode.keys.slice(0, mid + 1);
2010
1946
  for (const k of parentNode.keys) {
2011
- const n = this.getNode(k);
1947
+ const n = this._cloneNode(this.getNode(k));
2012
1948
  n.parent = parentNode.id;
2013
1949
  this._updateNode(n);
2014
1950
  }
2015
- for (const k of parentPointer.keys) {
2016
- const n = this.getNode(k);
2017
- n.parent = parentPointer.id;
1951
+ for (const k of newSiblingNodeRecursive.keys) {
1952
+ const n = this._cloneNode(this.getNode(k));
1953
+ n.parent = newSiblingNodeRecursive.id;
2018
1954
  this._updateNode(n);
2019
1955
  }
2020
1956
  this._updateNode(parentNode);
2021
- this._insertInParent(parentNode, midValue, parentPointer);
1957
+ this._insertInParent(parentNode, midValue, newSiblingNodeRecursive);
2022
1958
  }
2023
1959
  }
2024
1960
  insertableNode(value) {
@@ -2148,28 +2084,46 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2148
2084
  }
2149
2085
  }
2150
2086
  init() {
2151
- this.clear();
2152
- const head = this._readHead();
2153
- if (head === null) {
2154
- this.order = this.strategy.order;
2155
- const root = this._createNode(true, [], []);
2156
- this._writeHead({
2157
- root: root.id,
2158
- order: this.order,
2159
- data: this.strategy.head.data
2160
- });
2161
- } else {
2162
- const { root, order } = head;
2163
- this.strategy.head = head;
2164
- this.order = order;
2165
- this._writeHead({
2166
- root,
2167
- order: this.order,
2168
- data: this.strategy.head.data
2169
- });
2087
+ if (this.rootTx !== this) {
2088
+ throw new Error("Cannot call init on a nested transaction");
2089
+ }
2090
+ this._initInternal();
2091
+ }
2092
+ _initInternal() {
2093
+ if (this.isInitialized) {
2094
+ throw new Error("Transaction already initialized");
2095
+ }
2096
+ if (this.isDestroyed) {
2097
+ throw new Error("Transaction already destroyed");
2170
2098
  }
2171
- if (this.order < 3) {
2172
- throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
2099
+ this.isInitialized = true;
2100
+ try {
2101
+ this._clearCache();
2102
+ const head = this._readHead();
2103
+ if (head === null) {
2104
+ this.order = this.strategy.order;
2105
+ const root = this._createNode(true, [], []);
2106
+ this._writeHead({
2107
+ root: root.id,
2108
+ order: this.order,
2109
+ data: this.strategy.head.data
2110
+ });
2111
+ } else {
2112
+ const { root, order } = head;
2113
+ this.strategy.head = head;
2114
+ this.order = order;
2115
+ this._writeHead({
2116
+ root,
2117
+ order: this.order,
2118
+ data: this.strategy.head.data
2119
+ });
2120
+ }
2121
+ if (this.order < 3) {
2122
+ throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
2123
+ }
2124
+ } catch (e) {
2125
+ this.isInitialized = false;
2126
+ throw e;
2173
2127
  }
2174
2128
  }
2175
2129
  exists(key, value) {
@@ -2183,21 +2137,6 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2183
2137
  }
2184
2138
  return false;
2185
2139
  }
2186
- forceUpdate(id) {
2187
- if (id) {
2188
- this.nodes.delete(id);
2189
- this.getNode(id);
2190
- return 1;
2191
- }
2192
- const keys = Array.from(this.nodes.keys());
2193
- for (const key of keys) {
2194
- this.nodes.delete(key);
2195
- }
2196
- for (const key of keys) {
2197
- this.getNode(key);
2198
- }
2199
- return keys.length;
2200
- }
2201
2140
  get(key) {
2202
2141
  let node = this.leftestNode();
2203
2142
  while (true) {
@@ -2283,10 +2222,10 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2283
2222
  return map;
2284
2223
  }
2285
2224
  insert(key, value) {
2286
- const before = this.insertableNode(value);
2287
- this._insertAtLeaf(before, key, value);
2225
+ let before = this.insertableNode(value);
2226
+ before = this._insertAtLeaf(before, key, value);
2288
2227
  if (before.values.length === this.order) {
2289
- const after = this._createNode(
2228
+ let after = this._createNode(
2290
2229
  true,
2291
2230
  [],
2292
2231
  [],
@@ -2295,10 +2234,13 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2295
2234
  null
2296
2235
  );
2297
2236
  const mid = Math.ceil(this.order / 2) - 1;
2237
+ after = this._cloneNode(after);
2298
2238
  after.values = before.values.slice(mid + 1);
2299
2239
  after.keys = before.keys.slice(mid + 1);
2300
2240
  before.values = before.values.slice(0, mid + 1);
2301
2241
  before.keys = before.keys.slice(0, mid + 1);
2242
+ this._updateNode(before);
2243
+ this._updateNode(after);
2302
2244
  this._insertInParent(before, after.values[0], after);
2303
2245
  }
2304
2246
  }
@@ -2312,6 +2254,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2312
2254
  }
2313
2255
  }
2314
2256
  if (keyIndex !== -1) {
2257
+ node = this._cloneNode(node);
2315
2258
  node.keys.splice(keyIndex, 1);
2316
2259
  const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
2317
2260
  node.values.splice(valueIndex, 1);
@@ -2321,7 +2264,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2321
2264
  if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
2322
2265
  const keys = node.keys;
2323
2266
  this._deleteNode(node);
2324
- const newRoot = this.getNode(keys[0]);
2267
+ const newRoot = this._cloneNode(this.getNode(keys[0]));
2325
2268
  newRoot.parent = null;
2326
2269
  this._updateNode(newRoot);
2327
2270
  this._writeHead({
@@ -2329,17 +2272,17 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2329
2272
  order: this.order,
2330
2273
  data: this.strategy.head.data
2331
2274
  });
2332
- return;
2275
+ return node;
2333
2276
  } else if (this.rootId === node.id) {
2334
2277
  this._writeHead({
2335
2278
  root: node.id,
2336
2279
  order: this.order,
2337
2280
  data: this.strategy.head.data
2338
2281
  });
2339
- return;
2282
+ return node;
2340
2283
  } else if (node.keys.length < Math.ceil(this.order / 2) && !node.leaf || node.values.length < Math.ceil((this.order - 1) / 2) && node.leaf) {
2341
2284
  if (node.parent === null) {
2342
- return;
2285
+ return node;
2343
2286
  }
2344
2287
  let isPredecessor = false;
2345
2288
  let parentNode = this.getNode(node.parent);
@@ -2360,78 +2303,80 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2360
2303
  }
2361
2304
  }
2362
2305
  }
2363
- let pointer;
2306
+ let siblingNode;
2364
2307
  let guess;
2365
2308
  if (prevNode === null) {
2366
- pointer = nextNode;
2309
+ siblingNode = nextNode;
2367
2310
  guess = postValue;
2368
2311
  } else if (nextNode === null) {
2369
2312
  isPredecessor = true;
2370
- pointer = prevNode;
2313
+ siblingNode = prevNode;
2371
2314
  guess = prevValue;
2372
2315
  } else {
2373
2316
  if (node.values.length + nextNode.values.length < this.order) {
2374
- pointer = nextNode;
2317
+ siblingNode = nextNode;
2375
2318
  guess = postValue;
2376
2319
  } else {
2377
2320
  isPredecessor = true;
2378
- pointer = prevNode;
2321
+ siblingNode = prevNode;
2379
2322
  guess = prevValue;
2380
2323
  }
2381
2324
  }
2382
- if (!pointer) {
2383
- return;
2325
+ if (!siblingNode) {
2326
+ return node;
2384
2327
  }
2385
- if (node.values.length + pointer.values.length < this.order) {
2328
+ node = this._cloneNode(node);
2329
+ siblingNode = this._cloneNode(siblingNode);
2330
+ if (node.values.length + siblingNode.values.length < this.order) {
2386
2331
  if (!isPredecessor) {
2387
- const pTemp = pointer;
2388
- pointer = node;
2332
+ const pTemp = siblingNode;
2333
+ siblingNode = node;
2389
2334
  node = pTemp;
2390
2335
  }
2391
- pointer.keys.push(...node.keys);
2336
+ siblingNode.keys.push(...node.keys);
2392
2337
  if (!node.leaf) {
2393
- pointer.values.push(guess);
2338
+ siblingNode.values.push(guess);
2394
2339
  } else {
2395
- pointer.next = node.next;
2396
- if (pointer.next) {
2397
- const n = this.getNode(pointer.next);
2398
- n.prev = pointer.id;
2340
+ siblingNode.next = node.next;
2341
+ if (siblingNode.next) {
2342
+ const n = this._cloneNode(this.getNode(siblingNode.next));
2343
+ n.prev = siblingNode.id;
2399
2344
  this._updateNode(n);
2400
2345
  }
2401
2346
  }
2402
- pointer.values.push(...node.values);
2403
- if (!pointer.leaf) {
2404
- const keys = pointer.keys;
2347
+ siblingNode.values.push(...node.values);
2348
+ if (!siblingNode.leaf) {
2349
+ const keys = siblingNode.keys;
2405
2350
  for (const key2 of keys) {
2406
- const node2 = this.getNode(key2);
2407
- node2.parent = pointer.id;
2351
+ const node2 = this._cloneNode(this.getNode(key2));
2352
+ node2.parent = siblingNode.id;
2408
2353
  this._updateNode(node2);
2409
2354
  }
2410
2355
  }
2411
2356
  this._deleteNode(node);
2412
- this._updateNode(pointer);
2357
+ this._updateNode(siblingNode);
2413
2358
  this._deleteEntry(this.getNode(node.parent), node.id);
2414
2359
  } else {
2415
2360
  if (isPredecessor) {
2416
2361
  let pointerPm;
2417
2362
  let pointerKm;
2418
2363
  if (!node.leaf) {
2419
- pointerPm = pointer.keys.splice(-1)[0];
2420
- pointerKm = pointer.values.splice(-1)[0];
2364
+ pointerPm = siblingNode.keys.splice(-1)[0];
2365
+ pointerKm = siblingNode.values.splice(-1)[0];
2421
2366
  node.keys = [pointerPm, ...node.keys];
2422
2367
  node.values = [guess, ...node.values];
2423
- parentNode = this.getNode(node.parent);
2368
+ parentNode = this._cloneNode(this.getNode(node.parent));
2424
2369
  const nodeIndex = parentNode.keys.indexOf(node.id);
2425
2370
  if (nodeIndex > 0) {
2426
2371
  parentNode.values[nodeIndex - 1] = pointerKm;
2427
2372
  this._updateNode(parentNode);
2428
2373
  }
2429
2374
  } else {
2430
- pointerPm = pointer.keys.splice(-1)[0];
2431
- pointerKm = pointer.values.splice(-1)[0];
2375
+ pointerPm = siblingNode.keys.splice(-1)[0];
2376
+ pointerKm = siblingNode.values.splice(-1)[0];
2432
2377
  node.keys = [pointerPm, ...node.keys];
2433
2378
  node.values = [pointerKm, ...node.values];
2434
- parentNode = this.getNode(node.parent);
2379
+ parentNode = this._cloneNode(this.getNode(node.parent));
2435
2380
  const nodeIndex = parentNode.keys.indexOf(node.id);
2436
2381
  if (nodeIndex > 0) {
2437
2382
  parentNode.values[nodeIndex - 1] = pointerKm;
@@ -2439,61 +2384,62 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2439
2384
  }
2440
2385
  }
2441
2386
  this._updateNode(node);
2442
- this._updateNode(pointer);
2387
+ this._updateNode(siblingNode);
2443
2388
  } else {
2444
2389
  let pointerP0;
2445
2390
  let pointerK0;
2446
2391
  if (!node.leaf) {
2447
- pointerP0 = pointer.keys.splice(0, 1)[0];
2448
- pointerK0 = pointer.values.splice(0, 1)[0];
2392
+ pointerP0 = siblingNode.keys.splice(0, 1)[0];
2393
+ pointerK0 = siblingNode.values.splice(0, 1)[0];
2449
2394
  node.keys = [...node.keys, pointerP0];
2450
2395
  node.values = [...node.values, guess];
2451
- parentNode = this.getNode(node.parent);
2452
- const pointerIndex = parentNode.keys.indexOf(pointer.id);
2396
+ parentNode = this._cloneNode(this.getNode(node.parent));
2397
+ const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
2453
2398
  if (pointerIndex > 0) {
2454
2399
  parentNode.values[pointerIndex - 1] = pointerK0;
2455
2400
  this._updateNode(parentNode);
2456
2401
  }
2457
2402
  } else {
2458
- pointerP0 = pointer.keys.splice(0, 1)[0];
2459
- pointerK0 = pointer.values.splice(0, 1)[0];
2403
+ pointerP0 = siblingNode.keys.splice(0, 1)[0];
2404
+ pointerK0 = siblingNode.values.splice(0, 1)[0];
2460
2405
  node.keys = [...node.keys, pointerP0];
2461
2406
  node.values = [...node.values, pointerK0];
2462
- parentNode = this.getNode(node.parent);
2463
- const pointerIndex = parentNode.keys.indexOf(pointer.id);
2407
+ parentNode = this._cloneNode(this.getNode(node.parent));
2408
+ const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
2464
2409
  if (pointerIndex > 0) {
2465
- parentNode.values[pointerIndex - 1] = pointer.values[0];
2410
+ parentNode.values[pointerIndex - 1] = siblingNode.values[0];
2466
2411
  this._updateNode(parentNode);
2467
2412
  }
2468
2413
  }
2469
2414
  this._updateNode(node);
2470
- this._updateNode(pointer);
2415
+ this._updateNode(siblingNode);
2471
2416
  }
2472
- if (!pointer.leaf) {
2473
- for (const key2 of pointer.keys) {
2474
- const n = this.getNode(key2);
2475
- n.parent = pointer.id;
2417
+ if (!siblingNode.leaf) {
2418
+ for (const key2 of siblingNode.keys) {
2419
+ const n = this._cloneNode(this.getNode(key2));
2420
+ n.parent = siblingNode.id;
2476
2421
  this._updateNode(n);
2477
2422
  }
2478
2423
  }
2479
2424
  if (!node.leaf) {
2480
2425
  for (const key2 of node.keys) {
2481
- const n = this.getNode(key2);
2426
+ const n = this._cloneNode(this.getNode(key2));
2482
2427
  n.parent = node.id;
2483
2428
  this._updateNode(n);
2484
2429
  }
2485
2430
  }
2486
2431
  if (!parentNode.leaf) {
2487
2432
  for (const key2 of parentNode.keys) {
2488
- const n = this.getNode(key2);
2433
+ const n = this._cloneNode(this.getNode(key2));
2489
2434
  n.parent = parentNode.id;
2490
2435
  this._updateNode(n);
2491
2436
  }
2492
2437
  }
2493
2438
  }
2494
2439
  } else {
2495
- this._updateNode(node);
2440
+ this._updateNode(this._cloneNode(node));
2496
2441
  }
2442
+ return node;
2497
2443
  }
2498
2444
  delete(key, value) {
2499
2445
  let node = this.insertableNodeByPrimary(value);
@@ -2506,13 +2452,15 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2506
2452
  const keys = node.keys[i];
2507
2453
  const keyIndex = keys.indexOf(key);
2508
2454
  if (keyIndex !== -1) {
2509
- keys.splice(keyIndex, 1);
2510
- if (keys.length === 0) {
2455
+ node = this._cloneNode(node);
2456
+ const freshKeys = node.keys[i];
2457
+ freshKeys.splice(keyIndex, 1);
2458
+ if (freshKeys.length === 0) {
2511
2459
  node.keys.splice(i, 1);
2512
2460
  node.values.splice(i, 1);
2513
2461
  }
2514
2462
  this._updateNode(node);
2515
- this._deleteEntry(node, key);
2463
+ node = this._deleteEntry(node, key);
2516
2464
  found = true;
2517
2465
  break;
2518
2466
  }
@@ -2547,110 +2495,361 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2547
2495
  commit(label) {
2548
2496
  let result = this.mvcc.commit(label);
2549
2497
  if (result.success) {
2550
- result = this.mvccRoot.commit(label);
2551
- if (result.success && this.rootTx !== this) {
2552
- this.rootTx.rootId = this.rootId;
2498
+ const isRootTx = this.rootTx !== this;
2499
+ if (isRootTx) {
2500
+ result = this.rootTx.commit(label);
2501
+ if (result.success) {
2502
+ this.rootTx.rootId = this.rootId;
2503
+ }
2553
2504
  }
2554
2505
  if (result.success) {
2555
- for (const r of result.created) {
2556
- this.nodes.set(r.key, r.data);
2557
- }
2558
- for (const r of result.updated) {
2559
- this.nodes.set(r.key, r.data);
2560
- }
2561
- for (const r of result.deleted) {
2562
- this.nodes.delete(r.key);
2506
+ }
2507
+ }
2508
+ return result;
2509
+ }
2510
+ rollback() {
2511
+ return this.mvcc.rollback();
2512
+ }
2513
+ };
2514
+ var BPTreeMVCCStrategySync = class extends SyncMVCCStrategy {
2515
+ constructor(strategy) {
2516
+ super();
2517
+ this.strategy = strategy;
2518
+ }
2519
+ read(key) {
2520
+ if (key === "__HEAD__") {
2521
+ return this.strategy.readHead();
2522
+ }
2523
+ return this.strategy.read(key);
2524
+ }
2525
+ write(key, value) {
2526
+ if (key === "__HEAD__") {
2527
+ this.strategy.writeHead(value);
2528
+ } else {
2529
+ this.strategy.write(key, value);
2530
+ }
2531
+ }
2532
+ delete(key) {
2533
+ this.strategy.delete(key);
2534
+ }
2535
+ exists(key) {
2536
+ if (key === "__HEAD__") {
2537
+ return this.strategy.readHead() !== null;
2538
+ }
2539
+ try {
2540
+ const node = this.strategy.read(key);
2541
+ return node !== null && node !== void 0;
2542
+ } catch {
2543
+ return false;
2544
+ }
2545
+ }
2546
+ };
2547
+ var BPTreeSync = class extends BPTreeSyncTransaction {
2548
+ constructor(strategy, comparator, option) {
2549
+ const mvccRoot = new SyncMVCCTransaction(new BPTreeMVCCStrategySync(strategy), {
2550
+ cacheCapacity: option?.capacity ?? void 0
2551
+ });
2552
+ super(
2553
+ null,
2554
+ mvccRoot,
2555
+ mvccRoot,
2556
+ strategy,
2557
+ comparator,
2558
+ option
2559
+ );
2560
+ }
2561
+ /**
2562
+ * Creates a new synchronous transaction.
2563
+ * @returns A new BPTreeSyncTransaction.
2564
+ */
2565
+ createTransaction() {
2566
+ const nestedTx = this.mvcc.createNested();
2567
+ const tx = new BPTreeSyncTransaction(
2568
+ this,
2569
+ this.mvcc,
2570
+ nestedTx,
2571
+ this.strategy,
2572
+ this.comparator,
2573
+ this.option
2574
+ );
2575
+ tx._initInternal();
2576
+ return tx;
2577
+ }
2578
+ insert(key, value) {
2579
+ const tx = this.createTransaction();
2580
+ tx.insert(key, value);
2581
+ const result = tx.commit();
2582
+ if (!result.success) {
2583
+ throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
2584
+ }
2585
+ }
2586
+ delete(key, value) {
2587
+ const tx = this.createTransaction();
2588
+ tx.delete(key, value);
2589
+ const result = tx.commit();
2590
+ if (!result.success) {
2591
+ throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
2592
+ }
2593
+ }
2594
+ };
2595
+ var Ryoiki2 = class _Ryoiki2 {
2596
+ readings;
2597
+ writings;
2598
+ readQueue;
2599
+ writeQueue;
2600
+ static async CatchError(promise) {
2601
+ return await promise.then((v) => [void 0, v]).catch((err) => [err]);
2602
+ }
2603
+ static IsRangeOverlap(a, b) {
2604
+ const [start1, end1] = a;
2605
+ const [start2, end2] = b;
2606
+ if (end1 <= start2 || end2 <= start1) {
2607
+ return false;
2608
+ }
2609
+ return true;
2610
+ }
2611
+ static ERR_ALREADY_EXISTS(lockId) {
2612
+ return new Error(`The '${lockId}' task already existing in queue or running.`);
2613
+ }
2614
+ static ERR_NOT_EXISTS(lockId) {
2615
+ return new Error(`The '${lockId}' task not existing in task queue.`);
2616
+ }
2617
+ static ERR_TIMEOUT(lockId, timeout) {
2618
+ return new Error(`The task with ID '${lockId}' failed to acquire the lock within the timeout(${timeout}ms).`);
2619
+ }
2620
+ /**
2621
+ * Constructs a new instance of the Ryoiki class.
2622
+ */
2623
+ constructor() {
2624
+ this.readings = /* @__PURE__ */ new Map();
2625
+ this.writings = /* @__PURE__ */ new Map();
2626
+ this.readQueue = /* @__PURE__ */ new Map();
2627
+ this.writeQueue = /* @__PURE__ */ new Map();
2628
+ }
2629
+ /**
2630
+ * Creates a range based on a start value and length.
2631
+ * @param start - The starting value of the range.
2632
+ * @param length - The length of the range.
2633
+ * @returns A range tuple [start, start + length].
2634
+ */
2635
+ range(start, length) {
2636
+ return [start, start + length];
2637
+ }
2638
+ rangeOverlapping(tasks, range) {
2639
+ return Array.from(tasks.values()).some((t) => _Ryoiki2.IsRangeOverlap(t.range, range));
2640
+ }
2641
+ isSameRange(a, b) {
2642
+ const [a1, a2] = a;
2643
+ const [b1, b2] = b;
2644
+ return a1 === b1 && a2 === b2;
2645
+ }
2646
+ fetchUnitAndRun(queue, workspaces) {
2647
+ for (const [id, unit] of queue) {
2648
+ if (!unit.condition()) {
2649
+ continue;
2650
+ }
2651
+ this._alloc(queue, workspaces, id);
2652
+ }
2653
+ }
2654
+ _handleOverload(args, handlers, argPatterns) {
2655
+ for (const [key, pattern] of Object.entries(argPatterns)) {
2656
+ if (this._matchArgs(args, pattern)) {
2657
+ return handlers[key](...args);
2658
+ }
2659
+ }
2660
+ throw new Error("Invalid arguments");
2661
+ }
2662
+ _matchArgs(args, pattern) {
2663
+ return args.every((arg, index) => {
2664
+ const expectedType = pattern[index];
2665
+ if (expectedType === void 0) return typeof arg === "undefined";
2666
+ if (expectedType === Function) return typeof arg === "function";
2667
+ if (expectedType === Number) return typeof arg === "number";
2668
+ if (expectedType === Array) return Array.isArray(arg);
2669
+ return false;
2670
+ });
2671
+ }
2672
+ _createRandomId() {
2673
+ const timestamp = Date.now().toString(36);
2674
+ const random = Math.random().toString(36).substring(2);
2675
+ return `${timestamp}${random}`;
2676
+ }
2677
+ _alloc(queue, workspaces, lockId) {
2678
+ const unit = queue.get(lockId);
2679
+ if (!unit) {
2680
+ throw _Ryoiki2.ERR_NOT_EXISTS(lockId);
2681
+ }
2682
+ workspaces.set(lockId, unit);
2683
+ queue.delete(lockId);
2684
+ unit.alloc();
2685
+ }
2686
+ _free(workspaces, lockId) {
2687
+ const unit = workspaces.get(lockId);
2688
+ if (!unit) {
2689
+ throw _Ryoiki2.ERR_NOT_EXISTS(lockId);
2690
+ }
2691
+ workspaces.delete(lockId);
2692
+ unit.free();
2693
+ }
2694
+ _lock(queue, range, timeout, task, condition) {
2695
+ return new Promise((resolve, reject) => {
2696
+ let timeoutId = null;
2697
+ if (timeout >= 0) {
2698
+ timeoutId = setTimeout(() => {
2699
+ reject(_Ryoiki2.ERR_TIMEOUT(id, timeout));
2700
+ }, timeout);
2701
+ }
2702
+ const id = this._createRandomId();
2703
+ const alloc = async () => {
2704
+ if (timeoutId !== null) {
2705
+ clearTimeout(timeoutId);
2563
2706
  }
2707
+ const [err, v] = await _Ryoiki2.CatchError(task(id));
2708
+ if (err) reject(err);
2709
+ else resolve(v);
2710
+ };
2711
+ const fetch = () => {
2712
+ this.fetchUnitAndRun(this.readQueue, this.readings);
2713
+ this.fetchUnitAndRun(this.writeQueue, this.writings);
2714
+ };
2715
+ queue.set(id, { id, range, condition, alloc, free: fetch });
2716
+ fetch();
2717
+ });
2718
+ }
2719
+ _checkWorking(range, workspaces) {
2720
+ let isLocked = false;
2721
+ for (const lock of workspaces.values()) {
2722
+ if (_Ryoiki2.IsRangeOverlap(range, lock.range)) {
2723
+ isLocked = true;
2724
+ break;
2564
2725
  }
2565
2726
  }
2566
- return result;
2567
- }
2568
- rollback() {
2569
- return this.mvcc.rollback();
2570
- }
2571
- };
2572
- var BPTreeMVCCStrategySync = class extends SyncMVCCStrategy {
2573
- constructor(strategy) {
2574
- super();
2575
- this.strategy = strategy;
2727
+ return isLocked;
2576
2728
  }
2577
- read(key) {
2578
- if (key === "__HEAD__") {
2579
- return this.strategy.readHead();
2580
- }
2581
- return this.strategy.read(key);
2729
+ /**
2730
+ * Checks if there is any active read lock within the specified range.
2731
+ * @param range The range to check for active read locks.
2732
+ * @returns `true` if there is an active read lock within the range, `false` otherwise.
2733
+ */
2734
+ isReading(range) {
2735
+ return this._checkWorking(range, this.readings);
2582
2736
  }
2583
- write(key, value) {
2584
- if (key === "__HEAD__") {
2585
- this.strategy.writeHead(value);
2586
- } else {
2587
- this.strategy.write(key, value);
2588
- }
2737
+ /**
2738
+ * Checks if there is any active write lock within the specified range.
2739
+ * @param range The range to check for active write locks.
2740
+ * @returns `true` if there is an active write lock within the range, `false` otherwise.
2741
+ */
2742
+ isWriting(range) {
2743
+ return this._checkWorking(range, this.writings);
2589
2744
  }
2590
- delete(key) {
2591
- this.strategy.delete(key);
2745
+ /**
2746
+ * Checks if a read lock can be acquired within the specified range.
2747
+ * @param range The range to check for read lock availability.
2748
+ * @returns `true` if a read lock can be acquired, `false` otherwise.
2749
+ */
2750
+ canRead(range) {
2751
+ const writing = this.isWriting(range);
2752
+ return !writing;
2592
2753
  }
2593
- exists(key) {
2594
- if (key === "__HEAD__") {
2595
- return this.strategy.readHead() !== null;
2596
- }
2597
- try {
2598
- const node = this.strategy.read(key);
2599
- return node !== null && node !== void 0;
2600
- } catch {
2601
- return false;
2602
- }
2754
+ /**
2755
+ * Checks if a write lock can be acquired within the specified range.
2756
+ * @param range The range to check for write lock availability.
2757
+ * @returns `true` if a write lock can be acquired, `false` otherwise.
2758
+ */
2759
+ canWrite(range) {
2760
+ const reading = this.isReading(range);
2761
+ const writing = this.isWriting(range);
2762
+ return !reading && !writing;
2603
2763
  }
2604
- };
2605
- var BPTreeSync = class extends BPTreeSyncTransaction {
2606
- constructor(strategy, comparator, option) {
2607
- const mvccRoot = new SyncMVCCTransaction(new BPTreeMVCCStrategySync(strategy));
2608
- super(
2609
- null,
2610
- mvccRoot,
2611
- mvccRoot,
2612
- strategy,
2613
- comparator,
2614
- option
2764
+ /**
2765
+ * Internal implementation of the read lock. Handles both overloads.
2766
+ * @template T - The return type of the task.
2767
+ * @param arg0 - Either a range or a task callback.
2768
+ * If a range is provided, the task is the second argument.
2769
+ * @param arg1 - The task to execute, required if a range is provided.
2770
+ * @param arg2 - The timeout for acquiring the lock.
2771
+ * If the lock cannot be acquired within this period, an error will be thrown.
2772
+ * If this value is not provided, no timeout will be set.
2773
+ * @returns A promise resolving to the result of the task execution.
2774
+ */
2775
+ readLock(arg0, arg1, arg2) {
2776
+ const [range, task, timeout] = this._handleOverload(
2777
+ [arg0, arg1, arg2],
2778
+ {
2779
+ rangeTask: (range2, task2) => [range2, task2, -1],
2780
+ rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
2781
+ task: (task2) => [[-Infinity, Infinity], task2, -1],
2782
+ taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
2783
+ },
2784
+ {
2785
+ task: [Function],
2786
+ taskTimeout: [Function, Number],
2787
+ rangeTask: [Array, Function],
2788
+ rangeTaskTimeout: [Array, Function, Number]
2789
+ }
2790
+ );
2791
+ return this._lock(
2792
+ this.readQueue,
2793
+ range,
2794
+ timeout,
2795
+ task,
2796
+ () => !this.rangeOverlapping(this.writings, range)
2615
2797
  );
2616
2798
  }
2617
2799
  /**
2618
- * Creates a new synchronous transaction.
2619
- * @returns A new BPTreeSyncTransaction.
2800
+ * Internal implementation of the write lock. Handles both overloads.
2801
+ * @template T - The return type of the task.
2802
+ * @param arg0 - Either a range or a task callback.
2803
+ * If a range is provided, the task is the second argument.
2804
+ * @param arg1 - The task to execute, required if a range is provided.
2805
+ * @param arg2 - The timeout for acquiring the lock.
2806
+ * If the lock cannot be acquired within this period, an error will be thrown.
2807
+ * If this value is not provided, no timeout will be set.
2808
+ * @returns A promise resolving to the result of the task execution.
2620
2809
  */
2621
- createTransaction() {
2622
- const nestedTx = this.mvcc.createNested();
2623
- const tx = new BPTreeSyncTransaction(
2624
- this,
2625
- this.mvcc,
2626
- nestedTx,
2627
- this.strategy,
2628
- this.comparator,
2629
- this.option
2810
+ writeLock(arg0, arg1, arg2) {
2811
+ const [range, task, timeout] = this._handleOverload(
2812
+ [arg0, arg1, arg2],
2813
+ {
2814
+ rangeTask: (range2, task2) => [range2, task2, -1],
2815
+ rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
2816
+ task: (task2) => [[-Infinity, Infinity], task2, -1],
2817
+ taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
2818
+ },
2819
+ {
2820
+ task: [Function],
2821
+ taskTimeout: [Function, Number],
2822
+ rangeTask: [Array, Function],
2823
+ rangeTaskTimeout: [Array, Function, Number]
2824
+ }
2825
+ );
2826
+ return this._lock(
2827
+ this.writeQueue,
2828
+ range,
2829
+ timeout,
2830
+ task,
2831
+ () => {
2832
+ return !this.rangeOverlapping(this.writings, range) && !this.rangeOverlapping(this.readings, range);
2833
+ }
2630
2834
  );
2631
- tx.init();
2632
- return tx;
2633
2835
  }
2634
- insert(key, value) {
2635
- const tx = this.createTransaction();
2636
- tx.insert(key, value);
2637
- const result = tx.commit();
2638
- if (!result.success) {
2639
- throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
2640
- }
2641
- this.rootId = tx.getRootId();
2836
+ /**
2837
+ * Releases a read lock by its lock ID.
2838
+ * @param lockId - The unique identifier for the lock to release.
2839
+ */
2840
+ readUnlock(lockId) {
2841
+ this._free(this.readings, lockId);
2642
2842
  }
2643
- delete(key, value) {
2644
- const tx = this.createTransaction();
2645
- tx.delete(key, value);
2646
- const result = tx.commit();
2647
- if (!result.success) {
2648
- throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
2649
- }
2650
- this.rootId = tx.getRootId();
2843
+ /**
2844
+ * Releases a write lock by its lock ID.
2845
+ * @param lockId - The unique identifier for the lock to release.
2846
+ */
2847
+ writeUnlock(lockId) {
2848
+ this._free(this.writings, lockId);
2651
2849
  }
2652
2850
  };
2653
2851
  var BPTreeAsyncTransaction = class extends BPTreeTransaction {
2852
+ lock;
2654
2853
  constructor(rootTx, mvccRoot, mvcc, strategy, comparator, option) {
2655
2854
  super(
2656
2855
  rootTx,
@@ -2660,11 +2859,18 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
2660
2859
  comparator,
2661
2860
  option
2662
2861
  );
2862
+ this.lock = new Ryoiki2();
2863
+ }
2864
+ async writeLock(id, fn) {
2865
+ let lockId;
2866
+ return this.lock.writeLock([id, id + 0.1], async (_lockId) => {
2867
+ lockId = _lockId;
2868
+ return fn();
2869
+ }).finally(() => {
2870
+ this.lock.writeUnlock(lockId);
2871
+ });
2663
2872
  }
2664
2873
  async getNode(id) {
2665
- if (this.nodes.has(id)) {
2666
- return this.nodes.get(id);
2667
- }
2668
2874
  return await this.mvcc.read(id);
2669
2875
  }
2670
2876
  /**
@@ -2681,24 +2887,31 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
2681
2887
  next,
2682
2888
  prev
2683
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
+ }
2684
2898
  await this.mvcc.create(id, node);
2685
- this.nodes.set(id, node);
2686
2899
  return node;
2687
2900
  }
2688
2901
  async _updateNode(node) {
2902
+ if (this.mvcc.isDeleted(node.id)) {
2903
+ return;
2904
+ }
2689
2905
  await this.mvcc.write(node.id, node);
2690
- this.nodes.set(node.id, node);
2691
2906
  }
2692
2907
  async _deleteNode(node) {
2908
+ if (this.mvcc.isDeleted(node.id)) {
2909
+ return;
2910
+ }
2693
2911
  await this.mvcc.delete(node.id);
2694
- this.nodes.delete(node.id);
2695
2912
  }
2696
2913
  async _readHead() {
2697
- if (this.nodes.has("__HEAD__")) {
2698
- return this.nodes.get("__HEAD__") ?? null;
2699
- }
2700
- const head = await this.mvcc.read("__HEAD__");
2701
- return head ?? null;
2914
+ return await this.mvcc.read("__HEAD__");
2702
2915
  }
2703
2916
  async _writeHead(head) {
2704
2917
  if (!await this.mvcc.exists("__HEAD__")) {
@@ -2706,49 +2919,56 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
2706
2919
  } else {
2707
2920
  await this.mvcc.write("__HEAD__", head);
2708
2921
  }
2709
- this.nodes.set("__HEAD__", head);
2710
2922
  this.rootId = head.root;
2711
2923
  }
2712
2924
  async _insertAtLeaf(node, key, value) {
2713
- if (node.values.length) {
2714
- for (let i = 0, len = node.values.length; i < len; i++) {
2715
- const nValue = node.values[i];
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];
2716
2929
  if (this.comparator.isSame(value, nValue)) {
2717
- const keys = node.keys[i];
2930
+ const keys = leaf.keys[i];
2718
2931
  if (keys.includes(key)) {
2719
2932
  break;
2720
2933
  }
2721
- keys.push(key);
2722
- await this._updateNode(node);
2723
- return;
2934
+ leaf = this._cloneNode(leaf);
2935
+ leaf.keys[i].push(key);
2936
+ await this._updateNode(leaf);
2937
+ return leaf;
2724
2938
  } else if (this.comparator.isLower(value, nValue)) {
2725
- node.values.splice(i, 0, value);
2726
- node.keys.splice(i, 0, [key]);
2727
- await this._updateNode(node);
2728
- return;
2729
- } else if (i + 1 === node.values.length) {
2730
- node.values.push(value);
2731
- node.keys.push([key]);
2732
- await this._updateNode(node);
2733
- return;
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;
2734
2950
  }
2735
2951
  }
2736
2952
  } else {
2737
- node.values = [value];
2738
- node.keys = [[key]];
2739
- await this._updateNode(node);
2740
- return;
2953
+ leaf = this._cloneNode(leaf);
2954
+ leaf.values = [value];
2955
+ leaf.keys = [[key]];
2956
+ await this._updateNode(leaf);
2957
+ return leaf;
2741
2958
  }
2959
+ return leaf;
2742
2960
  }
2743
- async _insertInParent(node, value, pointer) {
2961
+ async _insertInParent(node, value, newSiblingNode) {
2744
2962
  if (this.rootId === node.id) {
2745
- const root = await this._createNode(false, [node.id, pointer.id], [value]);
2963
+ node = this._cloneNode(node);
2964
+ newSiblingNode = this._cloneNode(newSiblingNode);
2965
+ const root = await this._createNode(false, [node.id, newSiblingNode.id], [value]);
2746
2966
  this.rootId = root.id;
2747
2967
  node.parent = root.id;
2748
- pointer.parent = root.id;
2749
- if (pointer.leaf) {
2750
- node.next = pointer.id;
2751
- pointer.prev = node.id;
2968
+ newSiblingNode.parent = root.id;
2969
+ if (newSiblingNode.leaf) {
2970
+ node.next = newSiblingNode.id;
2971
+ newSiblingNode.prev = node.id;
2752
2972
  }
2753
2973
  await this._writeHead({
2754
2974
  root: root.id,
@@ -2756,53 +2976,54 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
2756
2976
  data: this.strategy.head.data
2757
2977
  });
2758
2978
  await this._updateNode(node);
2759
- await this._updateNode(pointer);
2979
+ await this._updateNode(newSiblingNode);
2760
2980
  return;
2761
2981
  }
2762
- const parentNode = await this.getNode(node.parent);
2982
+ const parentNode = this._cloneNode(await this.getNode(node.parent));
2763
2983
  const nodeIndex = parentNode.keys.indexOf(node.id);
2764
2984
  if (nodeIndex === -1) {
2765
2985
  throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
2766
2986
  }
2767
2987
  parentNode.values.splice(nodeIndex, 0, value);
2768
- parentNode.keys.splice(nodeIndex + 1, 0, pointer.id);
2769
- pointer.parent = parentNode.id;
2770
- if (pointer.leaf) {
2771
- const leftSibling = node;
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);
2772
2993
  const oldNextId = leftSibling.next;
2773
- pointer.prev = leftSibling.id;
2774
- pointer.next = oldNextId;
2775
- leftSibling.next = pointer.id;
2994
+ newSiblingNode.prev = leftSibling.id;
2995
+ newSiblingNode.next = oldNextId;
2996
+ leftSibling.next = newSiblingNode.id;
2776
2997
  await this._updateNode(leftSibling);
2777
2998
  if (oldNextId) {
2778
- const oldNext = await this.getNode(oldNextId);
2779
- oldNext.prev = pointer.id;
2999
+ const oldNext = this._cloneNode(await this.getNode(oldNextId));
3000
+ oldNext.prev = newSiblingNode.id;
2780
3001
  await this._updateNode(oldNext);
2781
3002
  }
2782
3003
  }
2783
3004
  await this._updateNode(parentNode);
2784
- await this._updateNode(pointer);
3005
+ await this._updateNode(newSiblingNode);
2785
3006
  if (parentNode.keys.length > this.order) {
2786
- const parentPointer = await this._createNode(false, [], []);
2787
- parentPointer.parent = parentNode.parent;
3007
+ const newSiblingNodeRecursive = await this._createNode(false, [], []);
3008
+ newSiblingNodeRecursive.parent = parentNode.parent;
2788
3009
  const mid = Math.ceil(this.order / 2) - 1;
2789
- parentPointer.values = parentNode.values.slice(mid + 1);
2790
- parentPointer.keys = parentNode.keys.slice(mid + 1);
3010
+ newSiblingNodeRecursive.values = parentNode.values.slice(mid + 1);
3011
+ newSiblingNodeRecursive.keys = parentNode.keys.slice(mid + 1);
2791
3012
  const midValue = parentNode.values[mid];
2792
3013
  parentNode.values = parentNode.values.slice(0, mid);
2793
3014
  parentNode.keys = parentNode.keys.slice(0, mid + 1);
2794
3015
  for (const k of parentNode.keys) {
2795
- const n = await this.getNode(k);
3016
+ const n = this._cloneNode(await this.getNode(k));
2796
3017
  n.parent = parentNode.id;
2797
3018
  await this._updateNode(n);
2798
3019
  }
2799
- for (const k of parentPointer.keys) {
2800
- const n = await this.getNode(k);
2801
- n.parent = parentPointer.id;
3020
+ for (const k of newSiblingNodeRecursive.keys) {
3021
+ const n = this._cloneNode(await this.getNode(k));
3022
+ n.parent = newSiblingNodeRecursive.id;
2802
3023
  await this._updateNode(n);
2803
3024
  }
2804
3025
  await this._updateNode(parentNode);
2805
- await this._insertInParent(parentNode, midValue, parentPointer);
3026
+ await this._insertInParent(parentNode, midValue, newSiblingNodeRecursive);
2806
3027
  }
2807
3028
  }
2808
3029
  async insertableNode(value) {
@@ -2938,28 +3159,46 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
2938
3159
  }
2939
3160
  }
2940
3161
  async init() {
2941
- this.clear();
2942
- const head = await this._readHead();
2943
- if (head === null) {
2944
- this.order = this.strategy.order;
2945
- const root = await this._createNode(true, [], []);
2946
- await this._writeHead({
2947
- root: root.id,
2948
- order: this.order,
2949
- data: this.strategy.head.data
2950
- });
2951
- } else {
2952
- const { root, order } = head;
2953
- this.strategy.head = head;
2954
- this.order = order;
2955
- await this._writeHead({
2956
- root,
2957
- order: this.order,
2958
- data: this.strategy.head.data
2959
- });
3162
+ if (this.rootTx !== this) {
3163
+ throw new Error("Cannot call init on a nested transaction");
3164
+ }
3165
+ return await this._initInternal();
3166
+ }
3167
+ async _initInternal() {
3168
+ if (this.isInitialized) {
3169
+ throw new Error("Transaction already initialized");
3170
+ }
3171
+ if (this.isDestroyed) {
3172
+ throw new Error("Transaction already destroyed");
2960
3173
  }
2961
- if (this.order < 3) {
2962
- throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
3174
+ this.isInitialized = true;
3175
+ try {
3176
+ this._clearCache();
3177
+ const head = await this._readHead();
3178
+ if (head === null) {
3179
+ this.order = this.strategy.order;
3180
+ const root = await this._createNode(true, [], []);
3181
+ await this._writeHead({
3182
+ root: root.id,
3183
+ order: this.order,
3184
+ data: this.strategy.head.data
3185
+ });
3186
+ } else {
3187
+ const { root, order } = head;
3188
+ this.strategy.head = head;
3189
+ this.order = order;
3190
+ await this._writeHead({
3191
+ root,
3192
+ order: this.order,
3193
+ data: this.strategy.head.data
3194
+ });
3195
+ }
3196
+ if (this.order < 3) {
3197
+ throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
3198
+ }
3199
+ } catch (e) {
3200
+ this.isInitialized = false;
3201
+ throw e;
2963
3202
  }
2964
3203
  }
2965
3204
  async exists(key, value) {
@@ -2973,21 +3212,6 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
2973
3212
  }
2974
3213
  return false;
2975
3214
  }
2976
- async forceUpdate(id) {
2977
- if (id) {
2978
- this.nodes.delete(id);
2979
- await this.getNode(id);
2980
- return 1;
2981
- }
2982
- const keys = Array.from(this.nodes.keys());
2983
- for (const key of keys) {
2984
- this.nodes.delete(key);
2985
- }
2986
- for (const key of keys) {
2987
- await this.getNode(key);
2988
- }
2989
- return keys.length;
2990
- }
2991
3215
  async get(key) {
2992
3216
  let node = await this.leftestNode();
2993
3217
  while (true) {
@@ -3072,25 +3296,30 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3072
3296
  }
3073
3297
  return map;
3074
3298
  }
3075
- async insert(key, value) {
3076
- const before = await this.insertableNode(value);
3077
- await this._insertAtLeaf(before, key, value);
3078
- if (before.values.length === this.order) {
3079
- const after = await this._createNode(
3080
- true,
3081
- [],
3082
- [],
3083
- before.parent,
3084
- null,
3085
- null
3086
- );
3087
- const mid = Math.ceil(this.order / 2) - 1;
3088
- after.values = before.values.slice(mid + 1);
3089
- after.keys = before.keys.slice(mid + 1);
3090
- before.values = before.values.slice(0, mid + 1);
3091
- before.keys = before.keys.slice(0, mid + 1);
3092
- await this._insertInParent(before, after.values[0], after);
3093
- }
3299
+ async insert(key, value) {
3300
+ return this.writeLock(0, async () => {
3301
+ let before = await this.insertableNode(value);
3302
+ before = await this._insertAtLeaf(before, key, value);
3303
+ if (before.values.length === this.order) {
3304
+ let after = await this._createNode(
3305
+ true,
3306
+ [],
3307
+ [],
3308
+ before.parent,
3309
+ null,
3310
+ null
3311
+ );
3312
+ const mid = Math.ceil(this.order / 2) - 1;
3313
+ after = this._cloneNode(after);
3314
+ after.values = before.values.slice(mid + 1);
3315
+ after.keys = before.keys.slice(mid + 1);
3316
+ before.values = before.values.slice(0, mid + 1);
3317
+ before.keys = before.keys.slice(0, mid + 1);
3318
+ await this._updateNode(before);
3319
+ await this._updateNode(after);
3320
+ await this._insertInParent(before, after.values[0], after);
3321
+ }
3322
+ });
3094
3323
  }
3095
3324
  async _deleteEntry(node, key) {
3096
3325
  if (!node.leaf) {
@@ -3102,6 +3331,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3102
3331
  }
3103
3332
  }
3104
3333
  if (keyIndex !== -1) {
3334
+ node = this._cloneNode(node);
3105
3335
  node.keys.splice(keyIndex, 1);
3106
3336
  const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
3107
3337
  node.values.splice(valueIndex, 1);
@@ -3111,7 +3341,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3111
3341
  if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
3112
3342
  const keys = node.keys;
3113
3343
  this._deleteNode(node);
3114
- const newRoot = await this.getNode(keys[0]);
3344
+ const newRoot = this._cloneNode(await this.getNode(keys[0]));
3115
3345
  newRoot.parent = null;
3116
3346
  await this._updateNode(newRoot);
3117
3347
  await this._writeHead({
@@ -3119,14 +3349,17 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3119
3349
  order: this.order,
3120
3350
  data: this.strategy.head.data
3121
3351
  });
3122
- return;
3352
+ return node;
3123
3353
  } else if (this.rootId === node.id) {
3124
- const root = await this.getNode(this.rootId);
3125
- await this._updateNode(root);
3126
- return;
3354
+ await this._writeHead({
3355
+ root: node.id,
3356
+ order: this.order,
3357
+ data: this.strategy.head.data
3358
+ });
3359
+ return node;
3127
3360
  } else if (node.keys.length < Math.ceil(this.order / 2) && !node.leaf || node.values.length < Math.ceil((this.order - 1) / 2) && node.leaf) {
3128
3361
  if (node.parent === null) {
3129
- return;
3362
+ return node;
3130
3363
  }
3131
3364
  let isPredecessor = false;
3132
3365
  let parentNode = await this.getNode(node.parent);
@@ -3147,78 +3380,80 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3147
3380
  }
3148
3381
  }
3149
3382
  }
3150
- let pointer;
3383
+ let siblingNode;
3151
3384
  let guess;
3152
3385
  if (prevNode === null) {
3153
- pointer = nextNode;
3386
+ siblingNode = nextNode;
3154
3387
  guess = postValue;
3155
3388
  } else if (nextNode === null) {
3156
3389
  isPredecessor = true;
3157
- pointer = prevNode;
3390
+ siblingNode = prevNode;
3158
3391
  guess = prevValue;
3159
3392
  } else {
3160
3393
  if (node.values.length + nextNode.values.length < this.order) {
3161
- pointer = nextNode;
3394
+ siblingNode = nextNode;
3162
3395
  guess = postValue;
3163
3396
  } else {
3164
3397
  isPredecessor = true;
3165
- pointer = prevNode;
3398
+ siblingNode = prevNode;
3166
3399
  guess = prevValue;
3167
3400
  }
3168
3401
  }
3169
- if (!pointer) {
3170
- return;
3402
+ if (!siblingNode) {
3403
+ return node;
3171
3404
  }
3172
- if (node.values.length + pointer.values.length < this.order) {
3405
+ node = this._cloneNode(node);
3406
+ siblingNode = this._cloneNode(siblingNode);
3407
+ if (node.values.length + siblingNode.values.length < this.order) {
3173
3408
  if (!isPredecessor) {
3174
- const pTemp = pointer;
3175
- pointer = node;
3409
+ const pTemp = siblingNode;
3410
+ siblingNode = node;
3176
3411
  node = pTemp;
3177
3412
  }
3178
- pointer.keys.push(...node.keys);
3413
+ siblingNode.keys.push(...node.keys);
3179
3414
  if (!node.leaf) {
3180
- pointer.values.push(guess);
3415
+ siblingNode.values.push(guess);
3181
3416
  } else {
3182
- pointer.next = node.next;
3183
- if (pointer.next) {
3184
- const n = await this.getNode(pointer.next);
3185
- n.prev = pointer.id;
3417
+ siblingNode.next = node.next;
3418
+ if (siblingNode.next) {
3419
+ const n = this._cloneNode(await this.getNode(siblingNode.next));
3420
+ n.prev = siblingNode.id;
3186
3421
  await this._updateNode(n);
3187
3422
  }
3188
3423
  }
3189
- pointer.values.push(...node.values);
3190
- if (!pointer.leaf) {
3191
- const keys = pointer.keys;
3424
+ siblingNode.values.push(...node.values);
3425
+ if (!siblingNode.leaf) {
3426
+ const keys = siblingNode.keys;
3192
3427
  for (const key2 of keys) {
3193
- const node2 = await this.getNode(key2);
3194
- node2.parent = pointer.id;
3428
+ const node2 = this._cloneNode(await this.getNode(key2));
3429
+ node2.parent = siblingNode.id;
3195
3430
  await this._updateNode(node2);
3196
3431
  }
3197
3432
  }
3198
3433
  this._deleteNode(node);
3199
- await this._updateNode(pointer);
3434
+ await this._updateNode(siblingNode);
3200
3435
  await this._deleteEntry(await this.getNode(node.parent), node.id);
3201
3436
  } else {
3202
3437
  if (isPredecessor) {
3203
3438
  let pointerPm;
3204
3439
  let pointerKm;
3205
3440
  if (!node.leaf) {
3206
- pointerPm = pointer.keys.splice(-1)[0];
3207
- pointerKm = pointer.values.splice(-1)[0];
3441
+ pointerPm = siblingNode.keys.splice(-1)[0];
3442
+ pointerKm = siblingNode.values.splice(-1)[0];
3208
3443
  node.keys = [pointerPm, ...node.keys];
3209
3444
  node.values = [guess, ...node.values];
3210
- parentNode = await this.getNode(node.parent);
3445
+ parentNode = this._cloneNode(await this.getNode(node.parent));
3211
3446
  const nodeIndex = parentNode.keys.indexOf(node.id);
3212
3447
  if (nodeIndex > 0) {
3213
3448
  parentNode.values[nodeIndex - 1] = pointerKm;
3214
3449
  await this._updateNode(parentNode);
3215
3450
  }
3216
3451
  } else {
3217
- pointerPm = pointer.keys.splice(-1)[0];
3218
- pointerKm = pointer.values.splice(-1)[0];
3452
+ pointerPm = siblingNode.keys.splice(-1)[0];
3453
+ pointerKm = siblingNode.values.splice(-1)[0];
3219
3454
  node.keys = [pointerPm, ...node.keys];
3220
3455
  node.values = [pointerKm, ...node.values];
3221
- parentNode = await this.getNode(node.parent);
3456
+ parentNode = this._cloneNode(await this.getNode(node.parent));
3222
3457
  const nodeIndex = parentNode.keys.indexOf(node.id);
3223
3458
  if (nodeIndex > 0) {
3224
3459
  parentNode.values[nodeIndex - 1] = pointerKm;
@@ -3226,92 +3461,97 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3226
3461
  }
3227
3462
  }
3228
3463
  await this._updateNode(node);
3229
- await this._updateNode(pointer);
3464
+ await this._updateNode(siblingNode);
3230
3465
  } else {
3231
3466
  let pointerP0;
3232
3467
  let pointerK0;
3233
3468
  if (!node.leaf) {
3234
- pointerP0 = pointer.keys.splice(0, 1)[0];
3235
- pointerK0 = pointer.values.splice(0, 1)[0];
3469
+ pointerP0 = siblingNode.keys.splice(0, 1)[0];
3470
+ pointerK0 = siblingNode.values.splice(0, 1)[0];
3236
3471
  node.keys = [...node.keys, pointerP0];
3237
3472
  node.values = [...node.values, guess];
3238
- parentNode = await this.getNode(node.parent);
3239
- const pointerIndex = parentNode.keys.indexOf(pointer.id);
3473
+ parentNode = this._cloneNode(await this.getNode(node.parent));
3474
+ const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
3240
3475
  if (pointerIndex > 0) {
3241
3476
  parentNode.values[pointerIndex - 1] = pointerK0;
3242
3477
  await this._updateNode(parentNode);
3243
3478
  }
3244
3479
  } else {
3245
- pointerP0 = pointer.keys.splice(0, 1)[0];
3246
- pointerK0 = pointer.values.splice(0, 1)[0];
3480
+ pointerP0 = siblingNode.keys.splice(0, 1)[0];
3481
+ pointerK0 = siblingNode.values.splice(0, 1)[0];
3247
3482
  node.keys = [...node.keys, pointerP0];
3248
3483
  node.values = [...node.values, pointerK0];
3249
- parentNode = await this.getNode(node.parent);
3250
- const pointerIndex = parentNode.keys.indexOf(pointer.id);
3484
+ parentNode = this._cloneNode(await this.getNode(node.parent));
3485
+ const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
3251
3486
  if (pointerIndex > 0) {
3252
- parentNode.values[pointerIndex - 1] = pointer.values[0];
3487
+ parentNode.values[pointerIndex - 1] = siblingNode.values[0];
3253
3488
  await this._updateNode(parentNode);
3254
3489
  }
3255
3490
  }
3256
3491
  await this._updateNode(node);
3257
- await this._updateNode(pointer);
3492
+ await this._updateNode(siblingNode);
3258
3493
  }
3259
- if (!pointer.leaf) {
3260
- for (const key2 of pointer.keys) {
3261
- const n = await this.getNode(key2);
3262
- n.parent = pointer.id;
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;
3263
3498
  await this._updateNode(n);
3264
3499
  }
3265
3500
  }
3266
3501
  if (!node.leaf) {
3267
3502
  for (const key2 of node.keys) {
3268
- const n = await this.getNode(key2);
3503
+ const n = this._cloneNode(await this.getNode(key2));
3269
3504
  n.parent = node.id;
3270
3505
  await this._updateNode(n);
3271
3506
  }
3272
3507
  }
3273
3508
  if (!parentNode.leaf) {
3274
3509
  for (const key2 of parentNode.keys) {
3275
- const n = await this.getNode(key2);
3510
+ const n = this._cloneNode(await this.getNode(key2));
3276
3511
  n.parent = parentNode.id;
3277
3512
  await this._updateNode(n);
3278
3513
  }
3279
3514
  }
3280
3515
  }
3281
3516
  } else {
3282
- await this._updateNode(node);
3517
+ await this._updateNode(this._cloneNode(node));
3283
3518
  }
3519
+ return node;
3284
3520
  }
3285
3521
  async delete(key, value) {
3286
- let node = await this.insertableNodeByPrimary(value);
3287
- let found = false;
3288
- while (true) {
3289
- let i = node.values.length;
3290
- while (i--) {
3291
- const nValue = node.values[i];
3292
- if (this.comparator.isSame(value, nValue)) {
3293
- const keys = node.keys[i];
3294
- const keyIndex = keys.indexOf(key);
3295
- if (keyIndex !== -1) {
3296
- keys.splice(keyIndex, 1);
3297
- if (keys.length === 0) {
3298
- node.keys.splice(i, 1);
3299
- node.values.splice(i, 1);
3522
+ return this.writeLock(0, async () => {
3523
+ let node = await this.insertableNodeByPrimary(value);
3524
+ let found = false;
3525
+ while (true) {
3526
+ let i = node.values.length;
3527
+ while (i--) {
3528
+ const nValue = node.values[i];
3529
+ if (this.comparator.isSame(value, nValue)) {
3530
+ const keys = node.keys[i];
3531
+ const keyIndex = keys.indexOf(key);
3532
+ if (keyIndex !== -1) {
3533
+ node = this._cloneNode(node);
3534
+ const freshKeys = node.keys[i];
3535
+ freshKeys.splice(keyIndex, 1);
3536
+ if (freshKeys.length === 0) {
3537
+ node.keys.splice(i, 1);
3538
+ node.values.splice(i, 1);
3539
+ }
3540
+ await this._updateNode(node);
3541
+ node = await this._deleteEntry(node, key);
3542
+ found = true;
3543
+ break;
3300
3544
  }
3301
- await this._updateNode(node);
3302
- await this._deleteEntry(node, key);
3303
- found = true;
3304
- break;
3305
3545
  }
3306
3546
  }
3547
+ if (found) break;
3548
+ if (node.next) {
3549
+ node = await this.getNode(node.next);
3550
+ continue;
3551
+ }
3552
+ break;
3307
3553
  }
3308
- if (found) break;
3309
- if (node.next) {
3310
- node = await this.getNode(node.next);
3311
- continue;
3312
- }
3313
- break;
3314
- }
3554
+ });
3315
3555
  }
3316
3556
  async getHeadData() {
3317
3557
  const head = await this._readHead();
@@ -3320,439 +3560,179 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3320
3560
  }
3321
3561
  return head.data;
3322
3562
  }
3323
- async setHeadData(data) {
3324
- const head = await this._readHead();
3325
- if (head === null) {
3326
- throw new Error("Head not found");
3327
- }
3328
- await this._writeHead({
3329
- root: head.root,
3330
- order: head.order,
3331
- data
3332
- });
3333
- }
3334
- async commit(label) {
3335
- let result = await this.mvcc.commit(label);
3336
- if (result.success) {
3337
- result = await this.mvccRoot.commit(label);
3338
- if (result.success && this.rootTx !== this) {
3339
- this.rootTx.rootId = this.rootId;
3340
- }
3341
- if (result.success) {
3342
- for (const r of result.created) {
3343
- this.nodes.set(r.key, r.data);
3344
- }
3345
- for (const r of result.updated) {
3346
- this.nodes.set(r.key, r.data);
3347
- }
3348
- for (const r of result.deleted) {
3349
- this.nodes.delete(r.key);
3350
- }
3351
- }
3352
- }
3353
- return result;
3354
- }
3355
- rollback() {
3356
- return this.mvcc.rollback();
3357
- }
3358
- };
3359
- var BPTreeMVCCStrategyAsync = class extends AsyncMVCCStrategy {
3360
- constructor(strategy) {
3361
- super();
3362
- this.strategy = strategy;
3363
- }
3364
- async read(key) {
3365
- if (key === "__HEAD__") {
3366
- return await this.strategy.readHead();
3367
- }
3368
- return await this.strategy.read(key);
3369
- }
3370
- async write(key, value) {
3371
- if (key === "__HEAD__") {
3372
- await this.strategy.writeHead(value);
3373
- } else {
3374
- await this.strategy.write(key, value);
3375
- }
3376
- }
3377
- async delete(key) {
3378
- await this.strategy.delete(key);
3379
- }
3380
- async exists(key) {
3381
- if (key === "__HEAD__") {
3382
- return await this.strategy.readHead() !== null;
3383
- }
3384
- try {
3385
- const node = await this.strategy.read(key);
3386
- return node !== null && node !== void 0;
3387
- } catch {
3388
- return false;
3389
- }
3390
- }
3391
- };
3392
- var BPTreeAsync = class extends BPTreeAsyncTransaction {
3393
- constructor(strategy, comparator, option) {
3394
- const mvccRoot = new AsyncMVCCTransaction(new BPTreeMVCCStrategyAsync(strategy));
3395
- super(
3396
- null,
3397
- mvccRoot,
3398
- mvccRoot,
3399
- strategy,
3400
- comparator,
3401
- option
3402
- );
3403
- }
3404
- /**
3405
- * Creates a new asynchronous transaction.
3406
- * @returns A new BPTreeAsyncTransaction.
3407
- */
3408
- async createTransaction() {
3409
- const nestedTx = await this.mvcc.createNested();
3410
- const tx = new BPTreeAsyncTransaction(
3411
- this,
3412
- this.mvcc,
3413
- nestedTx,
3414
- this.strategy,
3415
- this.comparator,
3416
- this.option
3417
- );
3418
- await tx.init();
3419
- return tx;
3420
- }
3421
- async insert(key, value) {
3422
- const tx = await this.createTransaction();
3423
- await tx.insert(key, value);
3424
- const result = await tx.commit();
3425
- if (!result.success) {
3426
- throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
3427
- }
3428
- this.rootId = tx.getRootId();
3429
- }
3430
- async delete(key, value) {
3431
- const tx = await this.createTransaction();
3432
- await tx.delete(key, value);
3433
- const result = await tx.commit();
3434
- if (!result.success) {
3435
- throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
3436
- }
3437
- this.rootId = tx.getRootId();
3438
- }
3439
- };
3440
- var SerializeStrategy = class {
3441
- order;
3442
- head;
3443
- constructor(order) {
3444
- this.order = order;
3445
- this.head = {
3446
- order,
3447
- root: null,
3448
- data: {}
3449
- };
3450
- }
3451
- };
3452
- var SerializeStrategySync = class extends SerializeStrategy {
3453
- getHeadData(key, defaultValue) {
3454
- if (!Object.hasOwn(this.head.data, key)) {
3455
- this.setHeadData(key, defaultValue);
3456
- }
3457
- return this.head.data[key];
3458
- }
3459
- setHeadData(key, data) {
3460
- this.head.data[key] = data;
3461
- this.writeHead(this.head);
3462
- }
3463
- autoIncrement(key, defaultValue) {
3464
- const current = this.getHeadData(key, defaultValue);
3465
- const next = current + 1;
3466
- this.setHeadData(key, next);
3467
- return current;
3468
- }
3469
- };
3470
- var InMemoryStoreStrategySync = class extends SerializeStrategySync {
3471
- node;
3472
- constructor(order) {
3473
- super(order);
3474
- this.node = {};
3475
- }
3476
- id(isLeaf) {
3477
- return this.autoIncrement("index", 1).toString();
3478
- }
3479
- read(id) {
3480
- if (!Object.hasOwn(this.node, id)) {
3481
- throw new Error(`The tree attempted to reference node '${id}', but couldn't find the corresponding node.`);
3482
- }
3483
- const node = this.node[id];
3484
- return JSON.parse(JSON.stringify(node));
3485
- }
3486
- write(id, node) {
3487
- this.node[id] = node;
3488
- }
3489
- delete(id) {
3490
- delete this.node[id];
3491
- }
3492
- readHead() {
3493
- if (this.head.root === null) {
3494
- return null;
3495
- }
3496
- return this.head;
3497
- }
3498
- writeHead(head) {
3499
- this.head = head;
3500
- }
3501
- };
3502
- var Ryoiki2 = class _Ryoiki2 {
3503
- readings;
3504
- writings;
3505
- readQueue;
3506
- writeQueue;
3507
- static async CatchError(promise) {
3508
- return await promise.then((v) => [void 0, v]).catch((err) => [err]);
3509
- }
3510
- static IsRangeOverlap(a, b) {
3511
- const [start1, end1] = a;
3512
- const [start2, end2] = b;
3513
- if (end1 <= start2 || end2 <= start1) {
3514
- return false;
3515
- }
3516
- return true;
3517
- }
3518
- static ERR_ALREADY_EXISTS(lockId) {
3519
- return new Error(`The '${lockId}' task already existing in queue or running.`);
3520
- }
3521
- static ERR_NOT_EXISTS(lockId) {
3522
- return new Error(`The '${lockId}' task not existing in task queue.`);
3523
- }
3524
- static ERR_TIMEOUT(lockId, timeout) {
3525
- return new Error(`The task with ID '${lockId}' failed to acquire the lock within the timeout(${timeout}ms).`);
3526
- }
3527
- /**
3528
- * Constructs a new instance of the Ryoiki class.
3529
- */
3530
- constructor() {
3531
- this.readings = /* @__PURE__ */ new Map();
3532
- this.writings = /* @__PURE__ */ new Map();
3533
- this.readQueue = /* @__PURE__ */ new Map();
3534
- this.writeQueue = /* @__PURE__ */ new Map();
3535
- }
3536
- /**
3537
- * Creates a range based on a start value and length.
3538
- * @param start - The starting value of the range.
3539
- * @param length - The length of the range.
3540
- * @returns A range tuple [start, start + length].
3541
- */
3542
- range(start, length) {
3543
- return [start, start + length];
3544
- }
3545
- rangeOverlapping(tasks, range) {
3546
- return Array.from(tasks.values()).some((t) => _Ryoiki2.IsRangeOverlap(t.range, range));
3547
- }
3548
- isSameRange(a, b) {
3549
- const [a1, a2] = a;
3550
- const [b1, b2] = b;
3551
- return a1 === b1 && a2 === b2;
3552
- }
3553
- fetchUnitAndRun(queue, workspaces) {
3554
- for (const [id, unit] of queue) {
3555
- if (!unit.condition()) {
3556
- continue;
3557
- }
3558
- this._alloc(queue, workspaces, id);
3563
+ async setHeadData(data) {
3564
+ const head = await this._readHead();
3565
+ if (head === null) {
3566
+ throw new Error("Head not found");
3559
3567
  }
3568
+ await this._writeHead({
3569
+ root: head.root,
3570
+ order: head.order,
3571
+ data
3572
+ });
3560
3573
  }
3561
- _handleOverload(args, handlers, argPatterns) {
3562
- for (const [key, pattern] of Object.entries(argPatterns)) {
3563
- if (this._matchArgs(args, pattern)) {
3564
- return handlers[key](...args);
3574
+ async commit(label) {
3575
+ let result = await this.mvcc.commit(label);
3576
+ if (result.success) {
3577
+ const isRootTx = this.rootTx === this;
3578
+ if (!isRootTx) {
3579
+ result = await this.rootTx.commit(label);
3580
+ if (result.success) {
3581
+ this.rootTx.rootId = this.rootId;
3582
+ }
3565
3583
  }
3566
3584
  }
3567
- throw new Error("Invalid arguments");
3585
+ return result;
3568
3586
  }
3569
- _matchArgs(args, pattern) {
3570
- return args.every((arg, index) => {
3571
- const expectedType = pattern[index];
3572
- if (expectedType === void 0) return typeof arg === "undefined";
3573
- if (expectedType === Function) return typeof arg === "function";
3574
- if (expectedType === Number) return typeof arg === "number";
3575
- if (expectedType === Array) return Array.isArray(arg);
3576
- return false;
3577
- });
3587
+ async rollback() {
3588
+ return this.mvcc.rollback();
3578
3589
  }
3579
- _createRandomId() {
3580
- const timestamp = Date.now().toString(36);
3581
- const random = Math.random().toString(36).substring(2);
3582
- return `${timestamp}${random}`;
3590
+ };
3591
+ var BPTreeMVCCStrategyAsync = class extends AsyncMVCCStrategy {
3592
+ constructor(strategy) {
3593
+ super();
3594
+ this.strategy = strategy;
3583
3595
  }
3584
- _alloc(queue, workspaces, lockId) {
3585
- const unit = queue.get(lockId);
3586
- if (!unit) {
3587
- throw _Ryoiki2.ERR_NOT_EXISTS(lockId);
3596
+ async read(key) {
3597
+ if (key === "__HEAD__") {
3598
+ return await this.strategy.readHead();
3588
3599
  }
3589
- workspaces.set(lockId, unit);
3590
- queue.delete(lockId);
3591
- unit.alloc();
3600
+ return await this.strategy.read(key);
3592
3601
  }
3593
- _free(workspaces, lockId) {
3594
- const unit = workspaces.get(lockId);
3595
- if (!unit) {
3596
- throw _Ryoiki2.ERR_NOT_EXISTS(lockId);
3602
+ async write(key, value) {
3603
+ if (key === "__HEAD__") {
3604
+ await this.strategy.writeHead(value);
3605
+ } else {
3606
+ await this.strategy.write(key, value);
3597
3607
  }
3598
- workspaces.delete(lockId);
3599
- unit.free();
3600
3608
  }
3601
- _lock(queue, range, timeout, task, condition) {
3602
- return new Promise((resolve, reject) => {
3603
- let timeoutId = null;
3604
- if (timeout >= 0) {
3605
- timeoutId = setTimeout(() => {
3606
- reject(_Ryoiki2.ERR_TIMEOUT(id, timeout));
3607
- }, timeout);
3608
- }
3609
- const id = this._createRandomId();
3610
- const alloc = async () => {
3611
- if (timeoutId !== null) {
3612
- clearTimeout(timeoutId);
3613
- }
3614
- const [err, v] = await _Ryoiki2.CatchError(task(id));
3615
- if (err) reject(err);
3616
- else resolve(v);
3617
- };
3618
- const fetch = () => {
3619
- this.fetchUnitAndRun(this.readQueue, this.readings);
3620
- this.fetchUnitAndRun(this.writeQueue, this.writings);
3621
- };
3622
- queue.set(id, { id, range, condition, alloc, free: fetch });
3623
- fetch();
3624
- });
3609
+ async delete(key) {
3610
+ await this.strategy.delete(key);
3625
3611
  }
3626
- _checkWorking(range, workspaces) {
3627
- let isLocked = false;
3628
- for (const lock of workspaces.values()) {
3629
- if (_Ryoiki2.IsRangeOverlap(range, lock.range)) {
3630
- isLocked = true;
3631
- break;
3632
- }
3612
+ async exists(key) {
3613
+ if (key === "__HEAD__") {
3614
+ return await this.strategy.readHead() !== null;
3615
+ }
3616
+ try {
3617
+ const node = await this.strategy.read(key);
3618
+ return node !== null && node !== void 0;
3619
+ } catch {
3620
+ return false;
3633
3621
  }
3634
- return isLocked;
3635
- }
3636
- /**
3637
- * Checks if there is any active read lock within the specified range.
3638
- * @param range The range to check for active read locks.
3639
- * @returns `true` if there is an active read lock within the range, `false` otherwise.
3640
- */
3641
- isReading(range) {
3642
- return this._checkWorking(range, this.readings);
3643
- }
3644
- /**
3645
- * Checks if there is any active write lock within the specified range.
3646
- * @param range The range to check for active write locks.
3647
- * @returns `true` if there is an active write lock within the range, `false` otherwise.
3648
- */
3649
- isWriting(range) {
3650
- return this._checkWorking(range, this.writings);
3651
- }
3652
- /**
3653
- * Checks if a read lock can be acquired within the specified range.
3654
- * @param range The range to check for read lock availability.
3655
- * @returns `true` if a read lock can be acquired, `false` otherwise.
3656
- */
3657
- canRead(range) {
3658
- const writing = this.isWriting(range);
3659
- return !writing;
3660
3622
  }
3661
- /**
3662
- * Checks if a write lock can be acquired within the specified range.
3663
- * @param range The range to check for write lock availability.
3664
- * @returns `true` if a write lock can be acquired, `false` otherwise.
3665
- */
3666
- canWrite(range) {
3667
- const reading = this.isReading(range);
3668
- const writing = this.isWriting(range);
3669
- return !reading && !writing;
3623
+ };
3624
+ var BPTreeAsync = class extends BPTreeAsyncTransaction {
3625
+ constructor(strategy, comparator, option) {
3626
+ const mvccRoot = new AsyncMVCCTransaction(new BPTreeMVCCStrategyAsync(strategy), {
3627
+ cacheCapacity: option?.capacity ?? void 0
3628
+ });
3629
+ super(
3630
+ null,
3631
+ mvccRoot,
3632
+ mvccRoot,
3633
+ strategy,
3634
+ comparator,
3635
+ option
3636
+ );
3670
3637
  }
3671
3638
  /**
3672
- * Internal implementation of the read lock. Handles both overloads.
3673
- * @template T - The return type of the task.
3674
- * @param arg0 - Either a range or a task callback.
3675
- * If a range is provided, the task is the second argument.
3676
- * @param arg1 - The task to execute, required if a range is provided.
3677
- * @param arg2 - The timeout for acquiring the lock.
3678
- * If the lock cannot be acquired within this period, an error will be thrown.
3679
- * If this value is not provided, no timeout will be set.
3680
- * @returns A promise resolving to the result of the task execution.
3639
+ * Creates a new asynchronous transaction.
3640
+ * @returns A new BPTreeAsyncTransaction.
3681
3641
  */
3682
- readLock(arg0, arg1, arg2) {
3683
- const [range, task, timeout] = this._handleOverload(
3684
- [arg0, arg1, arg2],
3685
- {
3686
- rangeTask: (range2, task2) => [range2, task2, -1],
3687
- rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
3688
- task: (task2) => [[-Infinity, Infinity], task2, -1],
3689
- taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
3690
- },
3691
- {
3692
- task: [Function],
3693
- taskTimeout: [Function, Number],
3694
- rangeTask: [Array, Function],
3695
- rangeTaskTimeout: [Array, Function, Number]
3696
- }
3697
- );
3698
- return this._lock(
3699
- this.readQueue,
3700
- range,
3701
- timeout,
3702
- task,
3703
- () => !this.rangeOverlapping(this.writings, range)
3642
+ async createTransaction() {
3643
+ const nestedTx = this.mvcc.createNested();
3644
+ const tx = new BPTreeAsyncTransaction(
3645
+ this,
3646
+ this.mvcc,
3647
+ nestedTx,
3648
+ this.strategy,
3649
+ this.comparator,
3650
+ this.option
3704
3651
  );
3652
+ await tx._initInternal();
3653
+ return tx;
3705
3654
  }
3706
- /**
3707
- * Internal implementation of the write lock. Handles both overloads.
3708
- * @template T - The return type of the task.
3709
- * @param arg0 - Either a range or a task callback.
3710
- * If a range is provided, the task is the second argument.
3711
- * @param arg1 - The task to execute, required if a range is provided.
3712
- * @param arg2 - The timeout for acquiring the lock.
3713
- * If the lock cannot be acquired within this period, an error will be thrown.
3714
- * If this value is not provided, no timeout will be set.
3715
- * @returns A promise resolving to the result of the task execution.
3716
- */
3717
- writeLock(arg0, arg1, arg2) {
3718
- const [range, task, timeout] = this._handleOverload(
3719
- [arg0, arg1, arg2],
3720
- {
3721
- rangeTask: (range2, task2) => [range2, task2, -1],
3722
- rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
3723
- task: (task2) => [[-Infinity, Infinity], task2, -1],
3724
- taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
3725
- },
3726
- {
3727
- task: [Function],
3728
- taskTimeout: [Function, Number],
3729
- rangeTask: [Array, Function],
3730
- rangeTaskTimeout: [Array, Function, Number]
3655
+ async insert(key, value) {
3656
+ return this.writeLock(1, async () => {
3657
+ const tx = await this.createTransaction();
3658
+ await tx.insert(key, value);
3659
+ const result = await tx.commit();
3660
+ if (!result.success) {
3661
+ throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
3731
3662
  }
3732
- );
3733
- return this._lock(
3734
- this.writeQueue,
3735
- range,
3736
- timeout,
3737
- task,
3738
- () => {
3739
- return !this.rangeOverlapping(this.writings, range) && !this.rangeOverlapping(this.readings, range);
3663
+ });
3664
+ }
3665
+ async delete(key, value) {
3666
+ return this.writeLock(1, async () => {
3667
+ const tx = await this.createTransaction();
3668
+ await tx.delete(key, value);
3669
+ const result = await tx.commit();
3670
+ if (!result.success) {
3671
+ throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
3740
3672
  }
3741
- );
3673
+ });
3674
+ }
3675
+ };
3676
+ var SerializeStrategy = class {
3677
+ order;
3678
+ head;
3679
+ constructor(order) {
3680
+ this.order = order;
3681
+ this.head = {
3682
+ order,
3683
+ root: null,
3684
+ data: {}
3685
+ };
3686
+ }
3687
+ };
3688
+ var SerializeStrategySync = class extends SerializeStrategy {
3689
+ getHeadData(key, defaultValue) {
3690
+ if (!Object.hasOwn(this.head.data, key)) {
3691
+ this.setHeadData(key, defaultValue);
3692
+ }
3693
+ return this.head.data[key];
3694
+ }
3695
+ setHeadData(key, data) {
3696
+ this.head.data[key] = data;
3697
+ this.writeHead(this.head);
3742
3698
  }
3743
- /**
3744
- * Releases a read lock by its lock ID.
3745
- * @param lockId - The unique identifier for the lock to release.
3746
- */
3747
- readUnlock(lockId) {
3748
- this._free(this.readings, lockId);
3699
+ autoIncrement(key, defaultValue) {
3700
+ const current = this.getHeadData(key, defaultValue);
3701
+ const next = current + 1;
3702
+ this.setHeadData(key, next);
3703
+ return current;
3749
3704
  }
3750
- /**
3751
- * Releases a write lock by its lock ID.
3752
- * @param lockId - The unique identifier for the lock to release.
3753
- */
3754
- writeUnlock(lockId) {
3755
- this._free(this.writings, lockId);
3705
+ };
3706
+ var InMemoryStoreStrategySync = class extends SerializeStrategySync {
3707
+ node;
3708
+ constructor(order) {
3709
+ super(order);
3710
+ this.node = {};
3711
+ }
3712
+ id(isLeaf) {
3713
+ return this.autoIncrement("index", 1).toString();
3714
+ }
3715
+ read(id) {
3716
+ if (!Object.hasOwn(this.node, id)) {
3717
+ throw new Error(`The tree attempted to reference node '${id}', but couldn't find the corresponding node.`);
3718
+ }
3719
+ const node = this.node[id];
3720
+ return JSON.parse(JSON.stringify(node));
3721
+ }
3722
+ write(id, node) {
3723
+ this.node[id] = node;
3724
+ }
3725
+ delete(id) {
3726
+ delete this.node[id];
3727
+ }
3728
+ readHead() {
3729
+ if (this.head.root === null) {
3730
+ return null;
3731
+ }
3732
+ return this.head;
3733
+ }
3734
+ writeHead(head) {
3735
+ this.head = head;
3756
3736
  }
3757
3737
  };
3758
3738
  var SerializeStrategyAsync = class extends SerializeStrategy {
@@ -4197,7 +4177,7 @@ var LRUMap2 = class {
4197
4177
  this.tail = null;
4198
4178
  }
4199
4179
  };
4200
- var CacheEntanglement2 = class {
4180
+ var CacheEntanglement = class {
4201
4181
  creation;
4202
4182
  beforeUpdateHook;
4203
4183
  capacity;
@@ -4298,7 +4278,7 @@ var CacheEntanglement2 = class {
4298
4278
  }
4299
4279
  }
4300
4280
  };
4301
- var CacheData2 = class _CacheData2 {
4281
+ var CacheData = class _CacheData {
4302
4282
  static StructuredClone = globalThis.structuredClone.bind(globalThis);
4303
4283
  _value;
4304
4284
  constructor(value) {
@@ -4338,11 +4318,11 @@ var CacheData2 = class _CacheData2 {
4338
4318
  return Object.assign({}, this.raw);
4339
4319
  case "deep-copy":
4340
4320
  default:
4341
- return _CacheData2.StructuredClone(this.raw);
4321
+ return _CacheData.StructuredClone(this.raw);
4342
4322
  }
4343
4323
  }
4344
4324
  };
4345
- var CacheEntanglementSync2 = class extends CacheEntanglement2 {
4325
+ var CacheEntanglementSync = class extends CacheEntanglement {
4346
4326
  constructor(creation, option) {
4347
4327
  super(creation, option);
4348
4328
  }
@@ -4372,7 +4352,7 @@ var CacheEntanglementSync2 = class extends CacheEntanglement2 {
4372
4352
  const dependencyValue = dependency.recache(key) ?? dependency.recache(dependencyKey);
4373
4353
  resolved[name] = dependencyValue;
4374
4354
  }
4375
- const value = new CacheData2(this.creation(key, resolved, ...parameter));
4355
+ const value = new CacheData(this.creation(key, resolved, ...parameter));
4376
4356
  this.updateRequirements.delete(key);
4377
4357
  this.parameters.set(key, parameter);
4378
4358
  this.caches.set(key, value);
@@ -4396,7 +4376,7 @@ var CacheEntanglementSync2 = class extends CacheEntanglement2 {
4396
4376
  return this.caches.get(key);
4397
4377
  }
4398
4378
  };
4399
- var CacheEntanglementAsync = class extends CacheEntanglement2 {
4379
+ var CacheEntanglementAsync = class extends CacheEntanglement {
4400
4380
  constructor(creation, option) {
4401
4381
  super(creation, option);
4402
4382
  }
@@ -4426,7 +4406,7 @@ var CacheEntanglementAsync = class extends CacheEntanglement2 {
4426
4406
  const dependencyValue = await dependency.recache(key) ?? await dependency.recache(dependencyKey);
4427
4407
  resolved[name] = dependencyValue;
4428
4408
  }
4429
- const value = new CacheData2(await this.creation(key, resolved, ...parameter));
4409
+ const value = new CacheData(await this.creation(key, resolved, ...parameter));
4430
4410
  this.updateRequirements.delete(key);
4431
4411
  this.parameters.set(key, parameter);
4432
4412
  this.caches.set(key, value);
@@ -4531,6 +4511,42 @@ var InvertedWeakMap = class {
4531
4511
  // node_modules/mvcc-api/dist/esm/index.mjs
4532
4512
  var MVCCStrategy2 = class {
4533
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
+ };
4534
4550
  var MVCCTransaction2 = class {
4535
4551
  committed;
4536
4552
  snapshotVersion;
@@ -4538,11 +4554,11 @@ var MVCCTransaction2 = class {
4538
4554
  writeBuffer;
4539
4555
  deleteBuffer;
4540
4556
  createdKeys;
4541
- // create()로 생성된 키 추적
4542
4557
  deletedValues;
4543
4558
  // delete 시 삭제 전 값 저장
4544
4559
  originallyExisted;
4545
4560
  // 트랜잭션 시작 시점에 디스크에 존재했던 키 (deleted 결과 필터링용)
4561
+ bufferHistory = /* @__PURE__ */ new Map();
4546
4562
  // Nested Transaction Properties
4547
4563
  parent;
4548
4564
  localVersion;
@@ -4556,7 +4572,8 @@ var MVCCTransaction2 = class {
4556
4572
  versionIndex = /* @__PURE__ */ new Map();
4557
4573
  deletedCache = /* @__PURE__ */ new Map();
4558
4574
  activeTransactions = /* @__PURE__ */ new Set();
4559
- constructor(strategy, parent, snapshotVersion) {
4575
+ diskCache;
4576
+ constructor(strategy, options, parent, snapshotVersion) {
4560
4577
  this.snapshotVersion = snapshotVersion ?? 0;
4561
4578
  this.writeBuffer = /* @__PURE__ */ new Map();
4562
4579
  this.deleteBuffer = /* @__PURE__ */ new Set();
@@ -4571,6 +4588,7 @@ var MVCCTransaction2 = class {
4571
4588
  this.snapshotLocalVersion = parent.localVersion;
4572
4589
  this.strategy = void 0;
4573
4590
  this.root = parent.root;
4591
+ this.diskCache = parent.diskCache;
4574
4592
  } else {
4575
4593
  if (!strategy) throw new Error("Root Transaction must get Strategy");
4576
4594
  this.strategy = strategy;
@@ -4578,8 +4596,13 @@ var MVCCTransaction2 = class {
4578
4596
  this.localVersion = 0;
4579
4597
  this.snapshotLocalVersion = 0;
4580
4598
  this.root = this;
4599
+ this.diskCache = new LRUMap3(options?.cacheCapacity ?? 1e3);
4581
4600
  }
4582
4601
  }
4602
+ /**
4603
+ * Checks if the transaction is a root transaction.
4604
+ * @returns True if the transaction is a root transaction, false otherwise.
4605
+ */
4583
4606
  isRoot() {
4584
4607
  return !this.parent;
4585
4608
  }
@@ -4596,27 +4619,96 @@ var MVCCTransaction2 = class {
4596
4619
  }
4597
4620
  return false;
4598
4621
  }
4599
- // --- Internal buffer manipulation helpers ---
4600
- _bufferCreate(key, value) {
4601
- this.localVersion++;
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
+ }
4638
+ _recordHistory(key) {
4639
+ const existsInWriteBuffer = this.writeBuffer.has(key);
4640
+ const existsInDeleteBuffer = this.deleteBuffer.has(key);
4641
+ const currentVer = this.keyVersions.get(key);
4642
+ if (currentVer !== void 0) {
4643
+ if (!this.bufferHistory.has(key)) this.bufferHistory.set(key, []);
4644
+ this.bufferHistory.get(key).push({
4645
+ value: existsInWriteBuffer ? this.writeBuffer.get(key) : this.deletedValues.get(key) ?? null,
4646
+ exists: existsInWriteBuffer || !existsInDeleteBuffer,
4647
+ version: currentVer
4648
+ });
4649
+ }
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
+ }
4686
+ _bufferCreate(key, value, version) {
4687
+ if (version === void 0) this.localVersion++;
4688
+ const targetVersion = version ?? this.localVersion;
4689
+ this._recordHistory(key);
4602
4690
  this.writeBuffer.set(key, value);
4603
4691
  this.createdKeys.add(key);
4604
4692
  this.deleteBuffer.delete(key);
4605
4693
  this.originallyExisted.delete(key);
4606
- this.keyVersions.set(key, this.localVersion);
4694
+ this.keyVersions.set(key, targetVersion);
4607
4695
  }
4608
- _bufferWrite(key, value) {
4609
- this.localVersion++;
4696
+ _bufferWrite(key, value, version) {
4697
+ if (version === void 0) this.localVersion++;
4698
+ const targetVersion = version ?? this.localVersion;
4699
+ this._recordHistory(key);
4610
4700
  this.writeBuffer.set(key, value);
4611
4701
  this.deleteBuffer.delete(key);
4612
- this.keyVersions.set(key, this.localVersion);
4702
+ this.keyVersions.set(key, targetVersion);
4613
4703
  }
4614
- _bufferDelete(key) {
4615
- this.localVersion++;
4704
+ _bufferDelete(key, version) {
4705
+ if (version === void 0) this.localVersion++;
4706
+ const targetVersion = version ?? this.localVersion;
4707
+ this._recordHistory(key);
4616
4708
  this.deleteBuffer.add(key);
4617
4709
  this.writeBuffer.delete(key);
4618
4710
  this.createdKeys.delete(key);
4619
- this.keyVersions.set(key, this.localVersion);
4711
+ this.keyVersions.set(key, targetVersion);
4620
4712
  }
4621
4713
  /**
4622
4714
  * Returns the entries that will be created, updated, and deleted by this transaction.
@@ -4640,7 +4732,11 @@ var MVCCTransaction2 = class {
4640
4732
  deleted.push({ key, data });
4641
4733
  }
4642
4734
  }
4643
- return { created, updated, deleted };
4735
+ return {
4736
+ created,
4737
+ updated,
4738
+ deleted
4739
+ };
4644
4740
  }
4645
4741
  /**
4646
4742
  * Rolls back the transaction.
@@ -4658,7 +4754,12 @@ var MVCCTransaction2 = class {
4658
4754
  if (this.root !== this) {
4659
4755
  this.root.activeTransactions.delete(this);
4660
4756
  }
4661
- return { success: true, created, updated, deleted };
4757
+ return {
4758
+ success: true,
4759
+ created,
4760
+ updated,
4761
+ deleted
4762
+ };
4662
4763
  }
4663
4764
  /**
4664
4765
  * Cleans up both deletedCache and versionIndex based on minActiveVersion.
@@ -4693,7 +4794,9 @@ var MVCCTransaction2 = class {
4693
4794
  break;
4694
4795
  }
4695
4796
  }
4696
- if (latestInSnapshotIdx > 0) {
4797
+ if (latestInSnapshotIdx === versions.length - 1) {
4798
+ this.versionIndex.delete(key);
4799
+ } else if (latestInSnapshotIdx > 0) {
4697
4800
  versions.splice(0, latestInSnapshotIdx);
4698
4801
  }
4699
4802
  }
@@ -4742,7 +4845,7 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
4742
4845
  createNested() {
4743
4846
  if (this.committed) throw new Error("Transaction already committed");
4744
4847
  const childVersion = this.isRoot() ? this.version : this.snapshotVersion;
4745
- const child = new _SyncMVCCTransaction2(void 0, this, childVersion);
4848
+ const child = new _SyncMVCCTransaction2(void 0, void 0, this, childVersion);
4746
4849
  this.root.activeTransactions.add(child);
4747
4850
  return child;
4748
4851
  }
@@ -4750,32 +4853,77 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
4750
4853
  if (this.committed) throw new Error("Transaction already committed");
4751
4854
  if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
4752
4855
  if (this.deleteBuffer.has(key)) return null;
4753
- return this.root._diskRead(key, this.snapshotVersion);
4856
+ if (this.parent) {
4857
+ return this.parent._readSnapshot(key, this.snapshotVersion, this.snapshotLocalVersion);
4858
+ }
4859
+ return this._diskRead(key, this.snapshotVersion);
4754
4860
  }
4755
4861
  exists(key) {
4756
4862
  if (this.committed) throw new Error("Transaction already committed");
4757
4863
  if (this.deleteBuffer.has(key)) return false;
4758
4864
  if (this.writeBuffer.has(key)) return true;
4759
- return this.root._diskExists(key, this.snapshotVersion);
4865
+ if (this.parent) {
4866
+ return this.parent._existsSnapshot(key, this.snapshotVersion, this.snapshotLocalVersion);
4867
+ }
4868
+ return this._diskExists(key, this.snapshotVersion);
4760
4869
  }
4761
- _readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
4762
- if (this.writeBuffer.has(key)) {
4763
- const keyModVersion = this.keyVersions.get(key);
4764
- if (snapshotLocalVersion === void 0 || keyModVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
4765
- return this.writeBuffer.get(key);
4870
+ _existsSnapshot(key, snapshotVersion, snapshotLocalVersion) {
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);
4766
4892
  }
4767
4893
  }
4768
- if (this.deleteBuffer.has(key)) {
4769
- const keyModVersion = this.keyVersions.get(key);
4770
- if (snapshotLocalVersion === void 0 || keyModVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
4771
- return null;
4894
+ return false;
4895
+ }
4896
+ _readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
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
+ }
4905
+ }
4906
+ if (current.deleteBuffer.has(key)) {
4907
+ const keyModVersion = current.keyVersions.get(key);
4908
+ if (slVer === void 0 || keyModVersion <= slVer) {
4909
+ return null;
4910
+ }
4911
+ }
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;
4917
+ }
4918
+ }
4919
+ if (current.parent) {
4920
+ slVer = current.snapshotLocalVersion;
4921
+ current = current.parent;
4922
+ } else {
4923
+ return current._diskRead(key, snapshotVersion);
4772
4924
  }
4773
4925
  }
4774
- if (this.parent) {
4775
- return this.parent._readSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
4776
- } else {
4777
- return this._diskRead(key, snapshotVersion);
4778
- }
4926
+ return null;
4779
4927
  }
4780
4928
  commit(label) {
4781
4929
  const { created, updated, deleted } = this.getResultEntries();
@@ -4835,6 +4983,7 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
4835
4983
  this.deletedValues.clear();
4836
4984
  this.originallyExisted.clear();
4837
4985
  this.keyVersions.clear();
4986
+ this.bufferHistory.clear();
4838
4987
  this.localVersion = 0;
4839
4988
  this.snapshotVersion = this.version;
4840
4989
  }
@@ -4875,32 +5024,22 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
4875
5024
  };
4876
5025
  }
4877
5026
  }
4878
- const newLocalVersion = this.localVersion + 1;
4879
- for (const key of child.writeBuffer.keys()) {
4880
- this.writeBuffer.set(key, child.writeBuffer.get(key));
4881
- this.deleteBuffer.delete(key);
4882
- this.keyVersions.set(key, newLocalVersion);
4883
- if (child.createdKeys.has(key)) {
4884
- this.createdKeys.add(key);
4885
- }
5027
+ const mergeVersion = ++this.localVersion;
5028
+ for (const [key, value] of child.writeBuffer) {
5029
+ const wasCreated = child.createdKeys.has(key);
5030
+ if (wasCreated) this._bufferCreate(key, value, mergeVersion);
5031
+ else this._bufferWrite(key, value, mergeVersion);
4886
5032
  }
4887
5033
  for (const key of child.deleteBuffer) {
4888
- this.deleteBuffer.add(key);
4889
- this.writeBuffer.delete(key);
4890
- this.createdKeys.delete(key);
4891
- this.keyVersions.set(key, newLocalVersion);
4892
5034
  const deletedValue = child.deletedValues.get(key);
4893
- if (deletedValue !== void 0) {
4894
- this.deletedValues.set(key, deletedValue);
4895
- }
4896
- if (child.originallyExisted.has(key)) {
5035
+ if (deletedValue !== void 0) this.deletedValues.set(key, deletedValue);
5036
+ if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
4897
5037
  this.originallyExisted.add(key);
4898
5038
  }
5039
+ this._bufferDelete(key, mergeVersion);
4899
5040
  }
4900
- this.localVersion = newLocalVersion;
4901
5041
  this.root.activeTransactions.delete(child);
4902
5042
  } else {
4903
- const newVersion = this.version + 1;
4904
5043
  if (child !== this) {
4905
5044
  const modifiedKeys = /* @__PURE__ */ new Set([...child.writeBuffer.keys(), ...child.deleteBuffer]);
4906
5045
  for (const key of modifiedKeys) {
@@ -4918,50 +5057,57 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
4918
5057
  };
4919
5058
  }
4920
5059
  }
5060
+ const lastModLocalVer = this.keyVersions.get(key);
5061
+ if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
5062
+ return {
5063
+ error: `Commit conflict: Key '${key}' was modified by a newer transaction in the same session (Local v${lastModLocalVer})`,
5064
+ conflict: {
5065
+ key,
5066
+ parent: this.read(key),
5067
+ child: child.read(key)
5068
+ }
5069
+ };
5070
+ }
4921
5071
  }
4922
- }
4923
- for (const [key, value] of child.writeBuffer) {
4924
- this.writeBuffer.set(key, value);
4925
- this.deleteBuffer.delete(key);
4926
- if (child.createdKeys.has(key)) {
4927
- this.createdKeys.add(key);
4928
- }
4929
- }
4930
- for (const key of child.deleteBuffer) {
4931
- this.deleteBuffer.add(key);
4932
- this.writeBuffer.delete(key);
4933
- this.createdKeys.delete(key);
4934
- const deletedValue = child.deletedValues.get(key);
4935
- if (deletedValue !== void 0) {
4936
- this.deletedValues.set(key, deletedValue);
5072
+ const mergeVersion = ++this.localVersion;
5073
+ for (const [key, value] of child.writeBuffer) {
5074
+ const wasCreated = child.createdKeys.has(key);
5075
+ if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
5076
+ this.originallyExisted.add(key);
5077
+ }
5078
+ if (wasCreated) this._bufferCreate(key, value, mergeVersion);
5079
+ else this._bufferWrite(key, value, mergeVersion);
4937
5080
  }
4938
- if (child.originallyExisted.has(key)) {
4939
- this.originallyExisted.add(key);
5081
+ for (const key of child.deleteBuffer) {
5082
+ const deletedValue = child.deletedValues.get(key);
5083
+ if (deletedValue !== void 0) this.deletedValues.set(key, deletedValue);
5084
+ if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
5085
+ this.originallyExisted.add(key);
5086
+ }
5087
+ this._bufferDelete(key, mergeVersion);
4940
5088
  }
5089
+ this.root.activeTransactions.delete(child);
5090
+ } else {
5091
+ const newVersion = this.version + 1;
5092
+ for (const [key, value] of this.writeBuffer) this._diskWrite(key, value, newVersion);
5093
+ for (const key of this.deleteBuffer) this._diskDelete(key, newVersion);
5094
+ this.version = newVersion;
5095
+ this._cleanupDeletedCache();
4941
5096
  }
4942
- for (const [key, value] of child.writeBuffer) {
4943
- this._diskWrite(key, value, newVersion);
4944
- }
4945
- for (const key of child.deleteBuffer) {
4946
- this._diskDelete(key, newVersion);
4947
- }
4948
- this.version = newVersion;
4949
- this.root.activeTransactions.delete(child);
4950
- this._cleanupDeletedCache();
4951
5097
  }
4952
5098
  return null;
4953
5099
  }
4954
- // --- Internal IO Helpers (Root Only) ---
4955
5100
  _diskWrite(key, value, version) {
4956
5101
  const strategy = this.strategy;
4957
5102
  if (!strategy) throw new Error("Root Transaction missing strategy");
4958
- if (strategy.exists(key)) {
4959
- const currentVal = strategy.read(key);
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);
4960
5106
  if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
4961
- this.deletedCache.get(key).push({
4962
- value: currentVal,
4963
- deletedAtVersion: version
4964
- });
5107
+ this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: version });
5108
+ rootAsAny.diskCache.set(key, value);
5109
+ } else {
5110
+ rootAsAny.diskCache.set(key, value);
4965
5111
  }
4966
5112
  strategy.write(key, value);
4967
5113
  if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
@@ -4972,36 +5118,44 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
4972
5118
  if (!strategy) throw new Error("Root Transaction missing strategy");
4973
5119
  const versions = this.versionIndex.get(key);
4974
5120
  if (!versions) {
4975
- return strategy.exists(key) ? strategy.read(key) : null;
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;
4976
5128
  }
4977
5129
  let targetVerObj = null;
4978
5130
  let nextVerObj = null;
4979
- for (const v of versions) {
4980
- if (v.version <= snapshotVersion) {
4981
- targetVerObj = v;
4982
- } else {
4983
- nextVerObj = v;
4984
- break;
4985
- }
4986
- }
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];
4987
5134
  if (!targetVerObj) {
4988
5135
  if (nextVerObj) {
4989
5136
  const cached2 = this.deletedCache.get(key);
4990
5137
  if (cached2) {
4991
- const match = cached2.find((c) => c.deletedAtVersion === nextVerObj.version);
4992
- if (match) return match.value;
5138
+ const cIdx = this._findExact(cached2, nextVerObj.version, "deletedAtVersion");
5139
+ if (cIdx >= 0) return cached2[cIdx].value;
4993
5140
  }
4994
5141
  }
4995
5142
  return null;
4996
5143
  }
4997
5144
  if (!targetVerObj.exists) return null;
4998
5145
  if (!nextVerObj) {
4999
- return strategy.read(key);
5146
+ if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
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;
5000
5154
  }
5001
5155
  const cached = this.deletedCache.get(key);
5002
5156
  if (cached) {
5003
- const match = cached.find((c) => c.deletedAtVersion === nextVerObj.version);
5004
- if (match) return match.value;
5157
+ const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
5158
+ if (cIdx >= 0) return cached[cIdx].value;
5005
5159
  }
5006
5160
  return null;
5007
5161
  }
@@ -5010,31 +5164,40 @@ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2
5010
5164
  if (!strategy) throw new Error("Root Transaction missing strategy");
5011
5165
  const versions = this.versionIndex.get(key);
5012
5166
  if (!versions) {
5013
- return strategy.exists(key);
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;
5014
5172
  }
5015
5173
  let targetVerObj = null;
5016
- for (const v of versions) {
5017
- if (v.version <= snapshotVersion) {
5018
- targetVerObj = v;
5019
- } else {
5020
- break;
5174
+ let nextVerObj = null;
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];
5178
+ if (!targetVerObj) {
5179
+ if (nextVerObj) {
5180
+ const cached = this.deletedCache.get(key);
5181
+ if (cached) {
5182
+ const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
5183
+ if (cIdx >= 0) return true;
5184
+ }
5021
5185
  }
5186
+ return false;
5022
5187
  }
5023
- if (!targetVerObj) return strategy.exists(key);
5024
5188
  return targetVerObj.exists;
5025
5189
  }
5026
5190
  _diskDelete(key, snapshotVersion) {
5027
5191
  const strategy = this.strategy;
5028
5192
  if (!strategy) throw new Error("Root Transaction missing strategy");
5029
- if (strategy.exists(key)) {
5030
- const currentVal = strategy.read(key);
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);
5031
5196
  if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
5032
- this.deletedCache.get(key).push({
5033
- value: currentVal,
5034
- deletedAtVersion: snapshotVersion
5035
- });
5197
+ this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: snapshotVersion });
5198
+ strategy.delete(key);
5199
+ rootAsAny.diskCache.delete(key);
5036
5200
  }
5037
- strategy.delete(key);
5038
5201
  if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
5039
5202
  this.versionIndex.get(key).push({ version: snapshotVersion, exists: false });
5040
5203
  }
@@ -5347,7 +5510,7 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
5347
5510
  createNested() {
5348
5511
  if (this.committed) throw new Error("Transaction already committed");
5349
5512
  const childVersion = this.isRoot() ? this.version : this.snapshotVersion;
5350
- const child = new _AsyncMVCCTransaction2(void 0, this, childVersion);
5513
+ const child = new _AsyncMVCCTransaction2(void 0, void 0, this, childVersion);
5351
5514
  this.root.activeTransactions.add(child);
5352
5515
  return child;
5353
5516
  }
@@ -5355,32 +5518,77 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
5355
5518
  if (this.committed) throw new Error("Transaction already committed");
5356
5519
  if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
5357
5520
  if (this.deleteBuffer.has(key)) return null;
5358
- return this.root._diskRead(key, this.snapshotVersion);
5521
+ if (this.parent) {
5522
+ return this.parent._readSnapshot(key, this.snapshotVersion, this.snapshotLocalVersion);
5523
+ }
5524
+ return await this._diskRead(key, this.snapshotVersion);
5359
5525
  }
5360
5526
  async exists(key) {
5361
5527
  if (this.committed) throw new Error("Transaction already committed");
5362
5528
  if (this.deleteBuffer.has(key)) return false;
5363
5529
  if (this.writeBuffer.has(key)) return true;
5364
- return this.root._diskExists(key, this.snapshotVersion);
5530
+ if (this.parent) {
5531
+ return this.parent._existsSnapshot(key, this.snapshotVersion, this.snapshotLocalVersion);
5532
+ }
5533
+ return await this._diskExists(key, this.snapshotVersion);
5365
5534
  }
5366
- async _readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
5367
- if (this.writeBuffer.has(key)) {
5368
- const keyModVersion = this.keyVersions.get(key);
5369
- if (snapshotLocalVersion === void 0 || keyModVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
5370
- return this.writeBuffer.get(key);
5535
+ async _existsSnapshot(key, snapshotVersion, snapshotLocalVersion) {
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);
5371
5557
  }
5372
5558
  }
5373
- if (this.deleteBuffer.has(key)) {
5374
- const keyModVersion = this.keyVersions.get(key);
5375
- if (snapshotLocalVersion === void 0 || keyModVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
5376
- return null;
5559
+ return false;
5560
+ }
5561
+ async _readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
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
+ }
5570
+ }
5571
+ if (current.deleteBuffer.has(key)) {
5572
+ const keyModVersion = current.keyVersions.get(key);
5573
+ if (slVer === void 0 || keyModVersion <= slVer) {
5574
+ return null;
5575
+ }
5576
+ }
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;
5582
+ }
5583
+ }
5584
+ if (current.parent) {
5585
+ slVer = current.snapshotLocalVersion;
5586
+ current = current.parent;
5587
+ } else {
5588
+ return await current._diskRead(key, snapshotVersion);
5377
5589
  }
5378
5590
  }
5379
- if (this.parent) {
5380
- return this.parent._readSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
5381
- } else {
5382
- return this._diskRead(key, snapshotVersion);
5383
- }
5591
+ return null;
5384
5592
  }
5385
5593
  async commit(label) {
5386
5594
  const { created, updated, deleted } = this.getResultEntries();
@@ -5440,6 +5648,7 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
5440
5648
  this.deletedValues.clear();
5441
5649
  this.originallyExisted.clear();
5442
5650
  this.keyVersions.clear();
5651
+ this.bufferHistory.clear();
5443
5652
  this.localVersion = 0;
5444
5653
  this.snapshotVersion = this.version;
5445
5654
  }
@@ -5481,33 +5690,23 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
5481
5690
  };
5482
5691
  }
5483
5692
  }
5484
- const newLocalVersion = this.localVersion + 1;
5485
- for (const key of child.writeBuffer.keys()) {
5486
- this.writeBuffer.set(key, child.writeBuffer.get(key));
5487
- this.deleteBuffer.delete(key);
5488
- this.keyVersions.set(key, newLocalVersion);
5489
- if (child.createdKeys.has(key)) {
5490
- this.createdKeys.add(key);
5491
- }
5693
+ const mergeVersion = ++this.localVersion;
5694
+ for (const [key, value] of child.writeBuffer) {
5695
+ const wasCreated = child.createdKeys.has(key);
5696
+ if (wasCreated) this._bufferCreate(key, value, mergeVersion);
5697
+ else this._bufferWrite(key, value, mergeVersion);
5492
5698
  }
5493
5699
  for (const key of child.deleteBuffer) {
5494
- this.deleteBuffer.add(key);
5495
- this.writeBuffer.delete(key);
5496
- this.createdKeys.delete(key);
5497
- this.keyVersions.set(key, newLocalVersion);
5498
5700
  const deletedValue = child.deletedValues.get(key);
5499
- if (deletedValue !== void 0) {
5500
- this.deletedValues.set(key, deletedValue);
5501
- }
5502
- if (child.originallyExisted.has(key)) {
5701
+ if (deletedValue !== void 0) this.deletedValues.set(key, deletedValue);
5702
+ if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
5503
5703
  this.originallyExisted.add(key);
5504
5704
  }
5705
+ this._bufferDelete(key, mergeVersion);
5505
5706
  }
5506
- this.localVersion = newLocalVersion;
5507
5707
  this.root.activeTransactions.delete(child);
5508
5708
  return null;
5509
5709
  } else {
5510
- const newVersion = this.version + 1;
5511
5710
  if (child !== this) {
5512
5711
  const modifiedKeys = /* @__PURE__ */ new Set([...child.writeBuffer.keys(), ...child.deleteBuffer]);
5513
5712
  for (const key of modifiedKeys) {
@@ -5525,51 +5724,58 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
5525
5724
  };
5526
5725
  }
5527
5726
  }
5727
+ const lastModLocalVer = this.keyVersions.get(key);
5728
+ if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
5729
+ return {
5730
+ error: `Commit conflict: Key '${key}' was modified by a newer transaction in the same session (Local v${lastModLocalVer})`,
5731
+ conflict: {
5732
+ key,
5733
+ parent: await this.read(key),
5734
+ child: await child.read(key)
5735
+ }
5736
+ };
5737
+ }
5528
5738
  }
5529
- }
5530
- for (const [key, value] of child.writeBuffer) {
5531
- this.writeBuffer.set(key, value);
5532
- this.deleteBuffer.delete(key);
5533
- if (child.createdKeys.has(key)) {
5534
- this.createdKeys.add(key);
5535
- }
5536
- }
5537
- for (const key of child.deleteBuffer) {
5538
- this.deleteBuffer.add(key);
5539
- this.writeBuffer.delete(key);
5540
- this.createdKeys.delete(key);
5541
- const deletedValue = child.deletedValues.get(key);
5542
- if (deletedValue !== void 0) {
5543
- this.deletedValues.set(key, deletedValue);
5739
+ const mergeVersion = ++this.localVersion;
5740
+ for (const [key, value] of child.writeBuffer) {
5741
+ const wasCreated = child.createdKeys.has(key);
5742
+ if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
5743
+ this.originallyExisted.add(key);
5744
+ }
5745
+ if (wasCreated) this._bufferCreate(key, value, mergeVersion);
5746
+ else this._bufferWrite(key, value, mergeVersion);
5544
5747
  }
5545
- if (child.originallyExisted.has(key)) {
5546
- this.originallyExisted.add(key);
5748
+ for (const key of child.deleteBuffer) {
5749
+ const deletedValue = child.deletedValues.get(key);
5750
+ if (deletedValue !== void 0) this.deletedValues.set(key, deletedValue);
5751
+ if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
5752
+ this.originallyExisted.add(key);
5753
+ }
5754
+ this._bufferDelete(key, mergeVersion);
5547
5755
  }
5756
+ this.root.activeTransactions.delete(child);
5757
+ } else {
5758
+ const newVersion = this.version + 1;
5759
+ for (const [key, value] of this.writeBuffer) await this._diskWrite(key, value, newVersion);
5760
+ for (const key of this.deleteBuffer) await this._diskDelete(key, newVersion);
5761
+ this.version = newVersion;
5762
+ this._cleanupDeletedCache();
5548
5763
  }
5549
- for (const [key, value] of child.writeBuffer) {
5550
- await this._diskWrite(key, value, newVersion);
5551
- }
5552
- for (const key of child.deleteBuffer) {
5553
- await this._diskDelete(key, newVersion);
5554
- }
5555
- this.version = newVersion;
5556
- this.root.activeTransactions.delete(child);
5557
- this._cleanupDeletedCache();
5558
5764
  return null;
5559
5765
  }
5560
5766
  });
5561
5767
  }
5562
- // --- Internal IO Helpers (Root Only) ---
5563
5768
  async _diskWrite(key, value, version) {
5564
5769
  const strategy = this.strategy;
5565
5770
  if (!strategy) throw new Error("Root Transaction missing strategy");
5566
- if (await strategy.exists(key)) {
5567
- const currentVal = await strategy.read(key);
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);
5568
5774
  if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
5569
- this.deletedCache.get(key).push({
5570
- value: currentVal,
5571
- deletedAtVersion: version
5572
- });
5775
+ this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: version });
5776
+ rootAsAny.diskCache.set(key, value);
5777
+ } else {
5778
+ rootAsAny.diskCache.set(key, value);
5573
5779
  }
5574
5780
  await strategy.write(key, value);
5575
5781
  if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
@@ -5580,36 +5786,44 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
5580
5786
  if (!strategy) throw new Error("Root Transaction missing strategy");
5581
5787
  const versions = this.versionIndex.get(key);
5582
5788
  if (!versions) {
5583
- return await strategy.exists(key) ? strategy.read(key) : null;
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;
5584
5796
  }
5585
5797
  let targetVerObj = null;
5586
5798
  let nextVerObj = null;
5587
- for (const v of versions) {
5588
- if (v.version <= snapshotVersion) {
5589
- targetVerObj = v;
5590
- } else {
5591
- nextVerObj = v;
5592
- break;
5593
- }
5594
- }
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];
5595
5802
  if (!targetVerObj) {
5596
5803
  if (nextVerObj) {
5597
5804
  const cached2 = this.deletedCache.get(key);
5598
5805
  if (cached2) {
5599
- const match = cached2.find((c) => c.deletedAtVersion === nextVerObj.version);
5600
- if (match) return match.value;
5806
+ const cIdx = this._findExact(cached2, nextVerObj.version, "deletedAtVersion");
5807
+ if (cIdx >= 0) return cached2[cIdx].value;
5601
5808
  }
5602
5809
  }
5603
5810
  return null;
5604
5811
  }
5605
5812
  if (!targetVerObj.exists) return null;
5606
5813
  if (!nextVerObj) {
5607
- return strategy.read(key);
5814
+ if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
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;
5608
5822
  }
5609
5823
  const cached = this.deletedCache.get(key);
5610
5824
  if (cached) {
5611
- const match = cached.find((c) => c.deletedAtVersion === nextVerObj.version);
5612
- if (match) return match.value;
5825
+ const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
5826
+ if (cIdx >= 0) return cached[cIdx].value;
5613
5827
  }
5614
5828
  return null;
5615
5829
  }
@@ -5618,31 +5832,40 @@ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction
5618
5832
  if (!strategy) throw new Error("Root Transaction missing strategy");
5619
5833
  const versions = this.versionIndex.get(key);
5620
5834
  if (!versions) {
5621
- return strategy.exists(key);
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;
5622
5840
  }
5623
5841
  let targetVerObj = null;
5624
- for (const v of versions) {
5625
- if (v.version <= snapshotVersion) {
5626
- targetVerObj = v;
5627
- } else {
5628
- break;
5842
+ let nextVerObj = null;
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];
5846
+ if (!targetVerObj) {
5847
+ if (nextVerObj) {
5848
+ const cached = this.deletedCache.get(key);
5849
+ if (cached) {
5850
+ const cIdx = this._findExact(cached, nextVerObj.version, "deletedAtVersion");
5851
+ if (cIdx >= 0) return true;
5852
+ }
5629
5853
  }
5854
+ return false;
5630
5855
  }
5631
- if (!targetVerObj) return strategy.exists(key);
5632
5856
  return targetVerObj.exists;
5633
5857
  }
5634
5858
  async _diskDelete(key, snapshotVersion) {
5635
5859
  const strategy = this.strategy;
5636
5860
  if (!strategy) throw new Error("Root Transaction missing strategy");
5637
- if (await strategy.exists(key)) {
5638
- const currentVal = await strategy.read(key);
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);
5639
5864
  if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
5640
- this.deletedCache.get(key).push({
5641
- value: currentVal,
5642
- deletedAtVersion: snapshotVersion
5643
- });
5865
+ this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: snapshotVersion });
5866
+ await strategy.delete(key);
5867
+ rootAsAny.diskCache.delete(key);
5644
5868
  }
5645
- await strategy.delete(key);
5646
5869
  if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
5647
5870
  this.versionIndex.get(key).push({ version: snapshotVersion, exists: false });
5648
5871
  }
@@ -8343,7 +8566,6 @@ var RowTableEngine = class {
8343
8566
  if (!btx) return;
8344
8567
  const result = await btx.commit();
8345
8568
  if (result.success) {
8346
- await this.bptree.init();
8347
8569
  for (const entry of result.deleted) {
8348
8570
  await this.strategy.delete(entry.key);
8349
8571
  }