serializable-bptree 8.1.2 → 8.1.4

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.
@@ -93,6 +93,42 @@ var StringComparator = class extends ValueComparator {
93
93
  // node_modules/mvcc-api/dist/esm/index.mjs
94
94
  var MVCCStrategy = class {
95
95
  };
96
+ var LRUMap = class {
97
+ cache = /* @__PURE__ */ new Map();
98
+ capacity;
99
+ constructor(capacity) {
100
+ this.capacity = capacity;
101
+ }
102
+ get(key) {
103
+ if (!this.cache.has(key)) return void 0;
104
+ const value = this.cache.get(key);
105
+ this.cache.delete(key);
106
+ this.cache.set(key, value);
107
+ return value;
108
+ }
109
+ set(key, value) {
110
+ if (this.cache.has(key)) {
111
+ this.cache.delete(key);
112
+ } else if (this.cache.size >= this.capacity) {
113
+ const oldestKey = this.cache.keys().next().value;
114
+ if (oldestKey !== void 0) this.cache.delete(oldestKey);
115
+ }
116
+ this.cache.set(key, value);
117
+ return this;
118
+ }
119
+ has(key) {
120
+ return this.cache.has(key);
121
+ }
122
+ delete(key) {
123
+ return this.cache.delete(key);
124
+ }
125
+ clear() {
126
+ this.cache.clear();
127
+ }
128
+ get size() {
129
+ return this.cache.size;
130
+ }
131
+ };
96
132
  var MVCCTransaction = class {
97
133
  committed;
98
134
  snapshotVersion;
@@ -100,11 +136,11 @@ var MVCCTransaction = class {
100
136
  writeBuffer;
101
137
  deleteBuffer;
102
138
  createdKeys;
103
- // create()로 생성된 키 추적
104
139
  deletedValues;
105
140
  // delete 시 삭제 전 값 저장
106
141
  originallyExisted;
107
142
  // 트랜잭션 시작 시점에 디스크에 존재했던 키 (deleted 결과 필터링용)
143
+ bufferHistory = /* @__PURE__ */ new Map();
108
144
  // Nested Transaction Properties
109
145
  parent;
110
146
  localVersion;
@@ -118,7 +154,8 @@ var MVCCTransaction = class {
118
154
  versionIndex = /* @__PURE__ */ new Map();
119
155
  deletedCache = /* @__PURE__ */ new Map();
120
156
  activeTransactions = /* @__PURE__ */ new Set();
121
- constructor(strategy, parent, snapshotVersion) {
157
+ diskCache;
158
+ constructor(strategy, options, parent, snapshotVersion) {
122
159
  this.snapshotVersion = snapshotVersion ?? 0;
123
160
  this.writeBuffer = /* @__PURE__ */ new Map();
124
161
  this.deleteBuffer = /* @__PURE__ */ new Set();
@@ -133,6 +170,7 @@ var MVCCTransaction = class {
133
170
  this.snapshotLocalVersion = parent.localVersion;
134
171
  this.strategy = void 0;
135
172
  this.root = parent.root;
173
+ this.diskCache = parent.diskCache;
136
174
  } else {
137
175
  if (!strategy) throw new Error("Root Transaction must get Strategy");
138
176
  this.strategy = strategy;
@@ -140,8 +178,13 @@ var MVCCTransaction = class {
140
178
  this.localVersion = 0;
141
179
  this.snapshotLocalVersion = 0;
142
180
  this.root = this;
181
+ this.diskCache = new LRUMap(options?.cacheCapacity ?? 1e3);
143
182
  }
144
183
  }
184
+ /**
185
+ * Checks if the transaction is a root transaction.
186
+ * @returns True if the transaction is a root transaction, false otherwise.
187
+ */
145
188
  isRoot() {
146
189
  return !this.parent;
147
190
  }
@@ -158,27 +201,61 @@ var MVCCTransaction = class {
158
201
  }
159
202
  return false;
160
203
  }
161
- // --- Internal buffer manipulation helpers ---
162
- _bufferCreate(key, value) {
163
- this.localVersion++;
204
+ /**
205
+ * Checks if a key was written in this transaction.
206
+ * @param key The key to check.
207
+ * @returns True if the key was written in this transaction, false otherwise.
208
+ */
209
+ isWrote(key) {
210
+ return this.writeBuffer.has(key);
211
+ }
212
+ /**
213
+ * Checks if a key was deleted in this transaction.
214
+ * @param key The key to check.
215
+ * @returns True if the key was deleted in this transaction, false otherwise.
216
+ */
217
+ isDeleted(key) {
218
+ return this.deleteBuffer.has(key);
219
+ }
220
+ _recordHistory(key) {
221
+ const existsInWriteBuffer = this.writeBuffer.has(key);
222
+ const existsInDeleteBuffer = this.deleteBuffer.has(key);
223
+ const currentVer = this.keyVersions.get(key);
224
+ if (currentVer !== void 0) {
225
+ if (!this.bufferHistory.has(key)) this.bufferHistory.set(key, []);
226
+ this.bufferHistory.get(key).push({
227
+ value: existsInWriteBuffer ? this.writeBuffer.get(key) : this.deletedValues.get(key) ?? null,
228
+ exists: existsInWriteBuffer || !existsInDeleteBuffer,
229
+ version: currentVer
230
+ });
231
+ }
232
+ }
233
+ _bufferCreate(key, value, version) {
234
+ if (version === void 0) this.localVersion++;
235
+ const targetVersion = version ?? this.localVersion;
236
+ this._recordHistory(key);
164
237
  this.writeBuffer.set(key, value);
165
238
  this.createdKeys.add(key);
166
239
  this.deleteBuffer.delete(key);
167
240
  this.originallyExisted.delete(key);
168
- this.keyVersions.set(key, this.localVersion);
241
+ this.keyVersions.set(key, targetVersion);
169
242
  }
170
- _bufferWrite(key, value) {
171
- this.localVersion++;
243
+ _bufferWrite(key, value, version) {
244
+ if (version === void 0) this.localVersion++;
245
+ const targetVersion = version ?? this.localVersion;
246
+ this._recordHistory(key);
172
247
  this.writeBuffer.set(key, value);
173
248
  this.deleteBuffer.delete(key);
174
- this.keyVersions.set(key, this.localVersion);
249
+ this.keyVersions.set(key, targetVersion);
175
250
  }
176
- _bufferDelete(key) {
177
- this.localVersion++;
251
+ _bufferDelete(key, version) {
252
+ if (version === void 0) this.localVersion++;
253
+ const targetVersion = version ?? this.localVersion;
254
+ this._recordHistory(key);
178
255
  this.deleteBuffer.add(key);
179
256
  this.writeBuffer.delete(key);
180
257
  this.createdKeys.delete(key);
181
- this.keyVersions.set(key, this.localVersion);
258
+ this.keyVersions.set(key, targetVersion);
182
259
  }
183
260
  /**
184
261
  * Returns the entries that will be created, updated, and deleted by this transaction.
@@ -202,7 +279,11 @@ var MVCCTransaction = class {
202
279
  deleted.push({ key, data });
203
280
  }
204
281
  }
205
- return { created, updated, deleted };
282
+ return {
283
+ created,
284
+ updated,
285
+ deleted
286
+ };
206
287
  }
207
288
  /**
208
289
  * Rolls back the transaction.
@@ -220,7 +301,12 @@ var MVCCTransaction = class {
220
301
  if (this.root !== this) {
221
302
  this.root.activeTransactions.delete(this);
222
303
  }
223
- return { success: true, created, updated, deleted };
304
+ return {
305
+ success: true,
306
+ created,
307
+ updated,
308
+ deleted
309
+ };
224
310
  }
225
311
  /**
226
312
  * Cleans up both deletedCache and versionIndex based on minActiveVersion.
@@ -255,7 +341,9 @@ var MVCCTransaction = class {
255
341
  break;
256
342
  }
257
343
  }
258
- if (latestInSnapshotIdx > 0) {
344
+ if (latestInSnapshotIdx === versions.length - 1) {
345
+ this.versionIndex.delete(key);
346
+ } else if (latestInSnapshotIdx > 0) {
259
347
  versions.splice(0, latestInSnapshotIdx);
260
348
  }
261
349
  }
@@ -304,7 +392,7 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
304
392
  createNested() {
305
393
  if (this.committed) throw new Error("Transaction already committed");
306
394
  const childVersion = this.isRoot() ? this.version : this.snapshotVersion;
307
- const child = new _SyncMVCCTransaction(void 0, this, childVersion);
395
+ const child = new _SyncMVCCTransaction(void 0, void 0, this, childVersion);
308
396
  this.root.activeTransactions.add(child);
309
397
  return child;
310
398
  }
@@ -312,27 +400,68 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
312
400
  if (this.committed) throw new Error("Transaction already committed");
313
401
  if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
314
402
  if (this.deleteBuffer.has(key)) return null;
315
- return this.root._diskRead(key, this.snapshotVersion);
403
+ if (this.parent) {
404
+ return this.parent._readSnapshot(key, this.snapshotVersion, this.snapshotLocalVersion);
405
+ }
406
+ return this._diskRead(key, this.snapshotVersion);
316
407
  }
317
408
  exists(key) {
318
409
  if (this.committed) throw new Error("Transaction already committed");
319
410
  if (this.deleteBuffer.has(key)) return false;
320
411
  if (this.writeBuffer.has(key)) return true;
321
- return this.root._diskExists(key, this.snapshotVersion);
412
+ if (this.parent) {
413
+ return this.parent._existsSnapshot(key, this.snapshotVersion, this.snapshotLocalVersion);
414
+ }
415
+ return this._diskExists(key, this.snapshotVersion);
416
+ }
417
+ _existsSnapshot(key, snapshotVersion, snapshotLocalVersion) {
418
+ if (this.writeBuffer.has(key)) {
419
+ const keyModVersion = this.keyVersions.get(key);
420
+ if (snapshotLocalVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
421
+ return true;
422
+ }
423
+ }
424
+ if (this.deleteBuffer.has(key)) {
425
+ const keyModVersion = this.keyVersions.get(key);
426
+ if (snapshotLocalVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
427
+ return false;
428
+ }
429
+ }
430
+ const history = this.bufferHistory.get(key);
431
+ if (history && snapshotLocalVersion !== void 0) {
432
+ for (let i = history.length - 1; i >= 0; i--) {
433
+ if (history[i].version <= snapshotLocalVersion) {
434
+ return history[i].exists;
435
+ }
436
+ }
437
+ }
438
+ if (this.parent) {
439
+ return this.parent._existsSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
440
+ } else {
441
+ return this._diskExists(key, snapshotVersion);
442
+ }
322
443
  }
323
444
  _readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
324
445
  if (this.writeBuffer.has(key)) {
325
446
  const keyModVersion = this.keyVersions.get(key);
326
- if (snapshotLocalVersion === void 0 || keyModVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
447
+ if (snapshotLocalVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
327
448
  return this.writeBuffer.get(key);
328
449
  }
329
450
  }
330
451
  if (this.deleteBuffer.has(key)) {
331
452
  const keyModVersion = this.keyVersions.get(key);
332
- if (snapshotLocalVersion === void 0 || keyModVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
453
+ if (snapshotLocalVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
333
454
  return null;
334
455
  }
335
456
  }
457
+ const history = this.bufferHistory.get(key);
458
+ if (history && snapshotLocalVersion !== void 0) {
459
+ for (let i = history.length - 1; i >= 0; i--) {
460
+ if (history[i].version <= snapshotLocalVersion) {
461
+ return history[i].exists ? history[i].value : null;
462
+ }
463
+ }
464
+ }
336
465
  if (this.parent) {
337
466
  return this.parent._readSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
338
467
  } else {
@@ -397,6 +526,7 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
397
526
  this.deletedValues.clear();
398
527
  this.originallyExisted.clear();
399
528
  this.keyVersions.clear();
529
+ this.bufferHistory.clear();
400
530
  this.localVersion = 0;
401
531
  this.snapshotVersion = this.version;
402
532
  }
@@ -437,32 +567,22 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
437
567
  };
438
568
  }
439
569
  }
440
- const newLocalVersion = this.localVersion + 1;
441
- for (const key of child.writeBuffer.keys()) {
442
- this.writeBuffer.set(key, child.writeBuffer.get(key));
443
- this.deleteBuffer.delete(key);
444
- this.keyVersions.set(key, newLocalVersion);
445
- if (child.createdKeys.has(key)) {
446
- this.createdKeys.add(key);
447
- }
570
+ const mergeVersion = ++this.localVersion;
571
+ for (const [key, value] of child.writeBuffer) {
572
+ const wasCreated = child.createdKeys.has(key);
573
+ if (wasCreated) this._bufferCreate(key, value, mergeVersion);
574
+ else this._bufferWrite(key, value, mergeVersion);
448
575
  }
449
576
  for (const key of child.deleteBuffer) {
450
- this.deleteBuffer.add(key);
451
- this.writeBuffer.delete(key);
452
- this.createdKeys.delete(key);
453
- this.keyVersions.set(key, newLocalVersion);
454
577
  const deletedValue = child.deletedValues.get(key);
455
- if (deletedValue !== void 0) {
456
- this.deletedValues.set(key, deletedValue);
457
- }
458
- if (child.originallyExisted.has(key)) {
578
+ if (deletedValue !== void 0) this.deletedValues.set(key, deletedValue);
579
+ if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
459
580
  this.originallyExisted.add(key);
460
581
  }
582
+ this._bufferDelete(key, mergeVersion);
461
583
  }
462
- this.localVersion = newLocalVersion;
463
584
  this.root.activeTransactions.delete(child);
464
585
  } else {
465
- const newVersion = this.version + 1;
466
586
  if (child !== this) {
467
587
  const modifiedKeys = /* @__PURE__ */ new Set([...child.writeBuffer.keys(), ...child.deleteBuffer]);
468
588
  for (const key of modifiedKeys) {
@@ -480,50 +600,57 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
480
600
  };
481
601
  }
482
602
  }
603
+ const lastModLocalVer = this.keyVersions.get(key);
604
+ if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
605
+ return {
606
+ error: `Commit conflict: Key '${key}' was modified by a newer transaction in the same session (Local v${lastModLocalVer})`,
607
+ conflict: {
608
+ key,
609
+ parent: this.read(key),
610
+ child: child.read(key)
611
+ }
612
+ };
613
+ }
483
614
  }
484
- }
485
- for (const [key, value] of child.writeBuffer) {
486
- this.writeBuffer.set(key, value);
487
- this.deleteBuffer.delete(key);
488
- if (child.createdKeys.has(key)) {
489
- this.createdKeys.add(key);
490
- }
491
- }
492
- for (const key of child.deleteBuffer) {
493
- this.deleteBuffer.add(key);
494
- this.writeBuffer.delete(key);
495
- this.createdKeys.delete(key);
496
- const deletedValue = child.deletedValues.get(key);
497
- if (deletedValue !== void 0) {
498
- this.deletedValues.set(key, deletedValue);
615
+ const mergeVersion = ++this.localVersion;
616
+ for (const [key, value] of child.writeBuffer) {
617
+ const wasCreated = child.createdKeys.has(key);
618
+ if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
619
+ this.originallyExisted.add(key);
620
+ }
621
+ if (wasCreated) this._bufferCreate(key, value, mergeVersion);
622
+ else this._bufferWrite(key, value, mergeVersion);
499
623
  }
500
- if (child.originallyExisted.has(key)) {
501
- this.originallyExisted.add(key);
624
+ for (const key of child.deleteBuffer) {
625
+ const deletedValue = child.deletedValues.get(key);
626
+ if (deletedValue !== void 0) this.deletedValues.set(key, deletedValue);
627
+ if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
628
+ this.originallyExisted.add(key);
629
+ }
630
+ this._bufferDelete(key, mergeVersion);
502
631
  }
632
+ this.root.activeTransactions.delete(child);
633
+ } else {
634
+ const newVersion = this.version + 1;
635
+ for (const [key, value] of this.writeBuffer) this._diskWrite(key, value, newVersion);
636
+ for (const key of this.deleteBuffer) this._diskDelete(key, newVersion);
637
+ this.version = newVersion;
638
+ this._cleanupDeletedCache();
503
639
  }
504
- for (const [key, value] of child.writeBuffer) {
505
- this._diskWrite(key, value, newVersion);
506
- }
507
- for (const key of child.deleteBuffer) {
508
- this._diskDelete(key, newVersion);
509
- }
510
- this.version = newVersion;
511
- this.root.activeTransactions.delete(child);
512
- this._cleanupDeletedCache();
513
640
  }
514
641
  return null;
515
642
  }
516
- // --- Internal IO Helpers (Root Only) ---
517
643
  _diskWrite(key, value, version) {
518
644
  const strategy = this.strategy;
519
645
  if (!strategy) throw new Error("Root Transaction missing strategy");
520
- if (strategy.exists(key)) {
521
- const currentVal = strategy.read(key);
646
+ const rootAsAny = this.root;
647
+ if (this._diskExists(key, version)) {
648
+ const currentVal = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : strategy.read(key);
522
649
  if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
523
- this.deletedCache.get(key).push({
524
- value: currentVal,
525
- deletedAtVersion: version
526
- });
650
+ this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: version });
651
+ rootAsAny.diskCache.set(key, value);
652
+ } else {
653
+ rootAsAny.diskCache.set(key, value);
527
654
  }
528
655
  strategy.write(key, value);
529
656
  if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
@@ -534,14 +661,19 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
534
661
  if (!strategy) throw new Error("Root Transaction missing strategy");
535
662
  const versions = this.versionIndex.get(key);
536
663
  if (!versions) {
537
- return strategy.exists(key) ? strategy.read(key) : null;
664
+ const rootAsAny = this.root;
665
+ if (this._diskExists(key, snapshotVersion)) {
666
+ const val = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : strategy.read(key);
667
+ rootAsAny.diskCache.set(key, val);
668
+ return val;
669
+ }
670
+ return null;
538
671
  }
539
672
  let targetVerObj = null;
540
673
  let nextVerObj = null;
541
674
  for (const v of versions) {
542
- if (v.version <= snapshotVersion) {
543
- targetVerObj = v;
544
- } else {
675
+ if (v.version <= snapshotVersion) targetVerObj = v;
676
+ else {
545
677
  nextVerObj = v;
546
678
  break;
547
679
  }
@@ -558,7 +690,14 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
558
690
  }
559
691
  if (!targetVerObj.exists) return null;
560
692
  if (!nextVerObj) {
561
- return strategy.read(key);
693
+ if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
694
+ if (this._diskExists(key, snapshotVersion)) {
695
+ const rootAsAny = this.root;
696
+ const val = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : strategy.read(key);
697
+ rootAsAny.diskCache.set(key, val);
698
+ return val;
699
+ }
700
+ return null;
562
701
  }
563
702
  const cached = this.deletedCache.get(key);
564
703
  if (cached) {
@@ -572,31 +711,44 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
572
711
  if (!strategy) throw new Error("Root Transaction missing strategy");
573
712
  const versions = this.versionIndex.get(key);
574
713
  if (!versions) {
575
- return strategy.exists(key);
714
+ const rootAsAny = this.root;
715
+ if (rootAsAny.diskCache.has(key)) return rootAsAny.diskCache.get(key) !== null;
716
+ const exists = strategy.exists(key);
717
+ if (!exists) rootAsAny.diskCache.set(key, null);
718
+ return exists;
576
719
  }
577
720
  let targetVerObj = null;
721
+ let nextVerObj = null;
578
722
  for (const v of versions) {
579
- if (v.version <= snapshotVersion) {
580
- targetVerObj = v;
581
- } else {
723
+ if (v.version <= snapshotVersion) targetVerObj = v;
724
+ else {
725
+ nextVerObj = v;
582
726
  break;
583
727
  }
584
728
  }
585
- if (!targetVerObj) return strategy.exists(key);
729
+ if (!targetVerObj) {
730
+ if (nextVerObj) {
731
+ const cached = this.deletedCache.get(key);
732
+ if (cached) {
733
+ const match = cached.find((c) => c.deletedAtVersion === nextVerObj.version);
734
+ if (match) return true;
735
+ }
736
+ }
737
+ return false;
738
+ }
586
739
  return targetVerObj.exists;
587
740
  }
588
741
  _diskDelete(key, snapshotVersion) {
589
742
  const strategy = this.strategy;
590
743
  if (!strategy) throw new Error("Root Transaction missing strategy");
591
- if (strategy.exists(key)) {
592
- const currentVal = strategy.read(key);
744
+ const rootAsAny = this.root;
745
+ if (this._diskExists(key, snapshotVersion)) {
746
+ const currentVal = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : strategy.read(key);
593
747
  if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
594
- this.deletedCache.get(key).push({
595
- value: currentVal,
596
- deletedAtVersion: snapshotVersion
597
- });
748
+ this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: snapshotVersion });
749
+ strategy.delete(key);
750
+ rootAsAny.diskCache.delete(key);
598
751
  }
599
- strategy.delete(key);
600
752
  if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
601
753
  this.versionIndex.get(key).push({ version: snapshotVersion, exists: false });
602
754
  }
@@ -909,7 +1061,7 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
909
1061
  createNested() {
910
1062
  if (this.committed) throw new Error("Transaction already committed");
911
1063
  const childVersion = this.isRoot() ? this.version : this.snapshotVersion;
912
- const child = new _AsyncMVCCTransaction(void 0, this, childVersion);
1064
+ const child = new _AsyncMVCCTransaction(void 0, void 0, this, childVersion);
913
1065
  this.root.activeTransactions.add(child);
914
1066
  return child;
915
1067
  }
@@ -917,31 +1069,72 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
917
1069
  if (this.committed) throw new Error("Transaction already committed");
918
1070
  if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
919
1071
  if (this.deleteBuffer.has(key)) return null;
920
- return this.root._diskRead(key, this.snapshotVersion);
1072
+ if (this.parent) {
1073
+ return this.parent._readSnapshot(key, this.snapshotVersion, this.snapshotLocalVersion);
1074
+ }
1075
+ return await this._diskRead(key, this.snapshotVersion);
921
1076
  }
922
1077
  async exists(key) {
923
1078
  if (this.committed) throw new Error("Transaction already committed");
924
1079
  if (this.deleteBuffer.has(key)) return false;
925
1080
  if (this.writeBuffer.has(key)) return true;
926
- return this.root._diskExists(key, this.snapshotVersion);
1081
+ if (this.parent) {
1082
+ return this.parent._existsSnapshot(key, this.snapshotVersion, this.snapshotLocalVersion);
1083
+ }
1084
+ return await this._diskExists(key, this.snapshotVersion);
1085
+ }
1086
+ async _existsSnapshot(key, snapshotVersion, snapshotLocalVersion) {
1087
+ if (this.writeBuffer.has(key)) {
1088
+ const keyModVersion = this.keyVersions.get(key);
1089
+ if (snapshotLocalVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
1090
+ return true;
1091
+ }
1092
+ }
1093
+ if (this.deleteBuffer.has(key)) {
1094
+ const keyModVersion = this.keyVersions.get(key);
1095
+ if (snapshotLocalVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
1096
+ return false;
1097
+ }
1098
+ }
1099
+ const history = this.bufferHistory.get(key);
1100
+ if (history && snapshotLocalVersion !== void 0) {
1101
+ for (let i = history.length - 1; i >= 0; i--) {
1102
+ if (history[i].version <= snapshotLocalVersion) {
1103
+ return history[i].exists;
1104
+ }
1105
+ }
1106
+ }
1107
+ if (this.parent) {
1108
+ return this.parent._existsSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
1109
+ } else {
1110
+ return await this._diskExists(key, snapshotVersion);
1111
+ }
927
1112
  }
928
1113
  async _readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
929
1114
  if (this.writeBuffer.has(key)) {
930
1115
  const keyModVersion = this.keyVersions.get(key);
931
- if (snapshotLocalVersion === void 0 || keyModVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
1116
+ if (snapshotLocalVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
932
1117
  return this.writeBuffer.get(key);
933
1118
  }
934
1119
  }
935
1120
  if (this.deleteBuffer.has(key)) {
936
1121
  const keyModVersion = this.keyVersions.get(key);
937
- if (snapshotLocalVersion === void 0 || keyModVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
1122
+ if (snapshotLocalVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
938
1123
  return null;
939
1124
  }
940
1125
  }
1126
+ const history = this.bufferHistory.get(key);
1127
+ if (history && snapshotLocalVersion !== void 0) {
1128
+ for (let i = history.length - 1; i >= 0; i--) {
1129
+ if (history[i].version <= snapshotLocalVersion) {
1130
+ return history[i].exists ? history[i].value : null;
1131
+ }
1132
+ }
1133
+ }
941
1134
  if (this.parent) {
942
1135
  return this.parent._readSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
943
1136
  } else {
944
- return this._diskRead(key, snapshotVersion);
1137
+ return await this._diskRead(key, snapshotVersion);
945
1138
  }
946
1139
  }
947
1140
  async commit(label) {
@@ -1002,6 +1195,7 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
1002
1195
  this.deletedValues.clear();
1003
1196
  this.originallyExisted.clear();
1004
1197
  this.keyVersions.clear();
1198
+ this.bufferHistory.clear();
1005
1199
  this.localVersion = 0;
1006
1200
  this.snapshotVersion = this.version;
1007
1201
  }
@@ -1043,33 +1237,23 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
1043
1237
  };
1044
1238
  }
1045
1239
  }
1046
- const newLocalVersion = this.localVersion + 1;
1047
- for (const key of child.writeBuffer.keys()) {
1048
- this.writeBuffer.set(key, child.writeBuffer.get(key));
1049
- this.deleteBuffer.delete(key);
1050
- this.keyVersions.set(key, newLocalVersion);
1051
- if (child.createdKeys.has(key)) {
1052
- this.createdKeys.add(key);
1053
- }
1240
+ const mergeVersion = ++this.localVersion;
1241
+ for (const [key, value] of child.writeBuffer) {
1242
+ const wasCreated = child.createdKeys.has(key);
1243
+ if (wasCreated) this._bufferCreate(key, value, mergeVersion);
1244
+ else this._bufferWrite(key, value, mergeVersion);
1054
1245
  }
1055
1246
  for (const key of child.deleteBuffer) {
1056
- this.deleteBuffer.add(key);
1057
- this.writeBuffer.delete(key);
1058
- this.createdKeys.delete(key);
1059
- this.keyVersions.set(key, newLocalVersion);
1060
1247
  const deletedValue = child.deletedValues.get(key);
1061
- if (deletedValue !== void 0) {
1062
- this.deletedValues.set(key, deletedValue);
1063
- }
1064
- if (child.originallyExisted.has(key)) {
1248
+ if (deletedValue !== void 0) this.deletedValues.set(key, deletedValue);
1249
+ if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
1065
1250
  this.originallyExisted.add(key);
1066
1251
  }
1252
+ this._bufferDelete(key, mergeVersion);
1067
1253
  }
1068
- this.localVersion = newLocalVersion;
1069
1254
  this.root.activeTransactions.delete(child);
1070
1255
  return null;
1071
1256
  } else {
1072
- const newVersion = this.version + 1;
1073
1257
  if (child !== this) {
1074
1258
  const modifiedKeys = /* @__PURE__ */ new Set([...child.writeBuffer.keys(), ...child.deleteBuffer]);
1075
1259
  for (const key of modifiedKeys) {
@@ -1087,51 +1271,58 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
1087
1271
  };
1088
1272
  }
1089
1273
  }
1274
+ const lastModLocalVer = this.keyVersions.get(key);
1275
+ if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
1276
+ return {
1277
+ error: `Commit conflict: Key '${key}' was modified by a newer transaction in the same session (Local v${lastModLocalVer})`,
1278
+ conflict: {
1279
+ key,
1280
+ parent: await this.read(key),
1281
+ child: await child.read(key)
1282
+ }
1283
+ };
1284
+ }
1090
1285
  }
1091
- }
1092
- for (const [key, value] of child.writeBuffer) {
1093
- this.writeBuffer.set(key, value);
1094
- this.deleteBuffer.delete(key);
1095
- if (child.createdKeys.has(key)) {
1096
- this.createdKeys.add(key);
1097
- }
1098
- }
1099
- for (const key of child.deleteBuffer) {
1100
- this.deleteBuffer.add(key);
1101
- this.writeBuffer.delete(key);
1102
- this.createdKeys.delete(key);
1103
- const deletedValue = child.deletedValues.get(key);
1104
- if (deletedValue !== void 0) {
1105
- this.deletedValues.set(key, deletedValue);
1286
+ const mergeVersion = ++this.localVersion;
1287
+ for (const [key, value] of child.writeBuffer) {
1288
+ const wasCreated = child.createdKeys.has(key);
1289
+ if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
1290
+ this.originallyExisted.add(key);
1291
+ }
1292
+ if (wasCreated) this._bufferCreate(key, value, mergeVersion);
1293
+ else this._bufferWrite(key, value, mergeVersion);
1106
1294
  }
1107
- if (child.originallyExisted.has(key)) {
1108
- this.originallyExisted.add(key);
1295
+ for (const key of child.deleteBuffer) {
1296
+ const deletedValue = child.deletedValues.get(key);
1297
+ if (deletedValue !== void 0) this.deletedValues.set(key, deletedValue);
1298
+ if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
1299
+ this.originallyExisted.add(key);
1300
+ }
1301
+ this._bufferDelete(key, mergeVersion);
1109
1302
  }
1303
+ this.root.activeTransactions.delete(child);
1304
+ } else {
1305
+ const newVersion = this.version + 1;
1306
+ for (const [key, value] of this.writeBuffer) await this._diskWrite(key, value, newVersion);
1307
+ for (const key of this.deleteBuffer) await this._diskDelete(key, newVersion);
1308
+ this.version = newVersion;
1309
+ this._cleanupDeletedCache();
1110
1310
  }
1111
- for (const [key, value] of child.writeBuffer) {
1112
- await this._diskWrite(key, value, newVersion);
1113
- }
1114
- for (const key of child.deleteBuffer) {
1115
- await this._diskDelete(key, newVersion);
1116
- }
1117
- this.version = newVersion;
1118
- this.root.activeTransactions.delete(child);
1119
- this._cleanupDeletedCache();
1120
1311
  return null;
1121
1312
  }
1122
1313
  });
1123
1314
  }
1124
- // --- Internal IO Helpers (Root Only) ---
1125
1315
  async _diskWrite(key, value, version) {
1126
1316
  const strategy = this.strategy;
1127
1317
  if (!strategy) throw new Error("Root Transaction missing strategy");
1128
- if (await strategy.exists(key)) {
1129
- const currentVal = await strategy.read(key);
1318
+ const rootAsAny = this.root;
1319
+ if (await this._diskExists(key, version)) {
1320
+ const currentVal = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : await strategy.read(key);
1130
1321
  if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
1131
- this.deletedCache.get(key).push({
1132
- value: currentVal,
1133
- deletedAtVersion: version
1134
- });
1322
+ this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: version });
1323
+ rootAsAny.diskCache.set(key, value);
1324
+ } else {
1325
+ rootAsAny.diskCache.set(key, value);
1135
1326
  }
1136
1327
  await strategy.write(key, value);
1137
1328
  if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
@@ -1142,14 +1333,19 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
1142
1333
  if (!strategy) throw new Error("Root Transaction missing strategy");
1143
1334
  const versions = this.versionIndex.get(key);
1144
1335
  if (!versions) {
1145
- return await strategy.exists(key) ? strategy.read(key) : null;
1336
+ const rootAsAny = this.root;
1337
+ if (await this._diskExists(key, snapshotVersion)) {
1338
+ const val = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : await strategy.read(key);
1339
+ rootAsAny.diskCache.set(key, val);
1340
+ return val;
1341
+ }
1342
+ return null;
1146
1343
  }
1147
1344
  let targetVerObj = null;
1148
1345
  let nextVerObj = null;
1149
1346
  for (const v of versions) {
1150
- if (v.version <= snapshotVersion) {
1151
- targetVerObj = v;
1152
- } else {
1347
+ if (v.version <= snapshotVersion) targetVerObj = v;
1348
+ else {
1153
1349
  nextVerObj = v;
1154
1350
  break;
1155
1351
  }
@@ -1166,7 +1362,14 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
1166
1362
  }
1167
1363
  if (!targetVerObj.exists) return null;
1168
1364
  if (!nextVerObj) {
1169
- return strategy.read(key);
1365
+ if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
1366
+ if (await this._diskExists(key, snapshotVersion)) {
1367
+ const rootAsAny = this.root;
1368
+ const val = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : await strategy.read(key);
1369
+ rootAsAny.diskCache.set(key, val);
1370
+ return val;
1371
+ }
1372
+ return null;
1170
1373
  }
1171
1374
  const cached = this.deletedCache.get(key);
1172
1375
  if (cached) {
@@ -1180,393 +1383,89 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
1180
1383
  if (!strategy) throw new Error("Root Transaction missing strategy");
1181
1384
  const versions = this.versionIndex.get(key);
1182
1385
  if (!versions) {
1183
- return strategy.exists(key);
1386
+ const rootAsAny = this.root;
1387
+ if (rootAsAny.diskCache.has(key)) return rootAsAny.diskCache.get(key) !== null;
1388
+ const exists = await strategy.exists(key);
1389
+ if (!exists) rootAsAny.diskCache.set(key, null);
1390
+ return exists;
1184
1391
  }
1185
1392
  let targetVerObj = null;
1393
+ let nextVerObj = null;
1186
1394
  for (const v of versions) {
1187
- if (v.version <= snapshotVersion) {
1188
- targetVerObj = v;
1189
- } else {
1395
+ if (v.version <= snapshotVersion) targetVerObj = v;
1396
+ else {
1397
+ nextVerObj = v;
1190
1398
  break;
1191
1399
  }
1192
1400
  }
1193
- if (!targetVerObj) return strategy.exists(key);
1401
+ if (!targetVerObj) {
1402
+ if (nextVerObj) {
1403
+ const cached = this.deletedCache.get(key);
1404
+ if (cached) {
1405
+ const match = cached.find((c) => c.deletedAtVersion === nextVerObj.version);
1406
+ if (match) return true;
1407
+ }
1408
+ }
1409
+ return false;
1410
+ }
1194
1411
  return targetVerObj.exists;
1195
1412
  }
1196
1413
  async _diskDelete(key, snapshotVersion) {
1197
1414
  const strategy = this.strategy;
1198
1415
  if (!strategy) throw new Error("Root Transaction missing strategy");
1199
- if (await strategy.exists(key)) {
1200
- const currentVal = await strategy.read(key);
1416
+ const rootAsAny = this.root;
1417
+ if (await this._diskExists(key, snapshotVersion)) {
1418
+ const currentVal = rootAsAny.diskCache.has(key) ? rootAsAny.diskCache.get(key) : await strategy.read(key);
1201
1419
  if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
1202
- this.deletedCache.get(key).push({
1203
- value: currentVal,
1204
- deletedAtVersion: snapshotVersion
1205
- });
1420
+ this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: snapshotVersion });
1421
+ await strategy.delete(key);
1422
+ rootAsAny.diskCache.delete(key);
1206
1423
  }
1207
- await strategy.delete(key);
1208
1424
  if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
1209
1425
  this.versionIndex.get(key).push({ version: snapshotVersion, exists: false });
1210
1426
  }
1211
1427
  };
1212
1428
 
1213
- // node_modules/cache-entanglement/dist/esm/index.mjs
1214
- var LRUMap = class {
1215
- capacity;
1216
- map;
1217
- head = null;
1218
- tail = null;
1219
- /**
1220
- * Creates an instance of LRUMap.
1221
- * @param capacity The maximum number of items the cache can hold.
1222
- */
1223
- constructor(capacity) {
1224
- this.capacity = capacity;
1225
- this.map = /* @__PURE__ */ new Map();
1226
- }
1227
- /**
1228
- * Promotes a node to the head of the linked list (marks as most recently used).
1229
- * @param node The node to promote.
1230
- */
1231
- promote(node) {
1232
- this.extract(node);
1233
- this.prepend(node);
1234
- }
1235
- /**
1236
- * Disconnects a node from the doubly linked list.
1237
- * @param node The node to extract.
1238
- */
1239
- extract(node) {
1240
- if (node.prev) node.prev.next = node.next;
1241
- else this.head = node.next;
1242
- if (node.next) node.next.prev = node.prev;
1243
- else this.tail = node.prev;
1244
- node.prev = null;
1245
- node.next = null;
1246
- }
1247
- /**
1248
- * Inserts a node at the head of the doubly linked list.
1249
- * @param node The node to prepend.
1250
- */
1251
- prepend(node) {
1252
- node.next = this.head;
1253
- if (this.head) this.head.prev = node;
1254
- this.head = node;
1255
- if (!this.tail) this.tail = node;
1256
- }
1257
- /**
1258
- * Stores or updates a value by key.
1259
- * If the capacity is exceeded, the least recently used item (tail) is removed.
1260
- * @param key The key to store.
1261
- * @param value The value to store.
1262
- */
1263
- set(key, value) {
1264
- const existing = this.map.get(key);
1265
- if (existing) {
1266
- existing.value = value;
1267
- this.promote(existing);
1268
- return;
1269
- }
1270
- const newNode = { key, value, prev: null, next: null };
1271
- this.map.set(key, newNode);
1272
- this.prepend(newNode);
1273
- if (this.map.size > this.capacity && this.tail) {
1274
- this.map.delete(this.tail.key);
1275
- this.extract(this.tail);
1276
- }
1277
- }
1278
- /**
1279
- * Retrieves a value by key.
1280
- * Accessing the item moves it to the "most recently used" position.
1281
- * @param key The key to look for.
1282
- * @returns The value associated with the key, or undefined if not found.
1283
- */
1284
- get(key) {
1285
- const node = this.map.get(key);
1286
- if (!node) return void 0;
1287
- this.promote(node);
1288
- return node.value;
1289
- }
1290
- /**
1291
- * Checks if a key exists in the cache without changing its access order.
1292
- * @param key The key to check.
1293
- * @returns True if the key exists, false otherwise.
1294
- */
1295
- has(key) {
1296
- return this.map.has(key);
1297
- }
1298
- /**
1299
- * Removes a key and its associated value from the cache.
1300
- * @param key The key to remove.
1301
- * @returns True if the key was found and removed, false otherwise.
1302
- */
1303
- delete(key) {
1304
- const node = this.map.get(key);
1305
- if (!node) return false;
1306
- this.extract(node);
1307
- this.map.delete(key);
1308
- return true;
1309
- }
1310
- /**
1311
- * Returns an iterator of keys in the order of most recently used to least recently used.
1312
- * @returns An iterable iterator of keys.
1313
- */
1314
- *keys() {
1315
- let current = this.head;
1316
- while (current) {
1317
- yield current.key;
1318
- current = current.next;
1319
- }
1320
- }
1321
- /**
1322
- * Returns the current number of items in the cache.
1323
- */
1324
- get size() {
1325
- return this.map.size;
1326
- }
1327
- /**
1328
- * Clears all items from the cache.
1329
- */
1330
- clear() {
1331
- this.map.clear();
1332
- this.head = null;
1333
- this.tail = null;
1334
- }
1335
- };
1336
- var CacheEntanglement = class {
1337
- creation;
1338
- beforeUpdateHook;
1339
- capacity;
1340
- dependencies;
1341
- caches;
1342
- parameters;
1343
- assignments;
1344
- dependencyProperties;
1345
- updateRequirements;
1346
- constructor(creation, option) {
1347
- option = option ?? {};
1348
- const {
1349
- dependencies,
1350
- capacity,
1351
- beforeUpdateHook
1352
- } = option;
1353
- this.creation = creation;
1354
- this.beforeUpdateHook = beforeUpdateHook ?? (() => {
1355
- });
1356
- this.capacity = capacity ?? 100;
1357
- this.assignments = [];
1358
- this.caches = new LRUMap(this.capacity);
1359
- this.parameters = /* @__PURE__ */ new Map();
1360
- this.dependencies = dependencies ?? {};
1361
- this.dependencyProperties = Object.keys(this.dependencies);
1362
- this.updateRequirements = /* @__PURE__ */ new Set();
1363
- for (const name in this.dependencies) {
1364
- const dependency = this.dependencies[name];
1365
- if (!dependency.assignments.includes(this)) {
1366
- dependency.assignments.push(this);
1367
- }
1368
- }
1369
- }
1370
- bubbleUpdateSignal(key) {
1371
- this.updateRequirements.add(key);
1372
- for (let i = 0, len = this.assignments.length; i < len; i++) {
1373
- const t = this.assignments[i];
1374
- const instance = t;
1375
- for (const cacheKey of instance.caches.keys()) {
1376
- if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
1377
- instance.bubbleUpdateSignal(cacheKey);
1378
- }
1379
- }
1380
- }
1381
- }
1382
- dependencyKey(key) {
1383
- const i = key.lastIndexOf("/");
1384
- if (i === -1) {
1385
- return key;
1386
- }
1387
- return key.substring(0, i);
1388
- }
1389
- /**
1390
- * Returns all keys stored in the instance.
1391
- */
1392
- keys() {
1393
- return this.parameters.keys();
1394
- }
1395
- /**
1396
- * Deletes all cache values stored in the instance.
1397
- */
1398
- clear() {
1399
- for (const key of this.keys()) {
1400
- this.delete(key);
1401
- }
1402
- }
1403
- /**
1404
- * Checks if there is a cache value stored in the key within the instance.
1405
- * @param key The key to search.
1406
- */
1407
- exists(key) {
1408
- return this.parameters.has(key);
1409
- }
1410
- /**
1411
- * Checks if there is a cache value stored in the key within the instance.
1412
- * This method is an alias for `exists`.
1413
- * @param key The key to search.
1414
- */
1415
- has(key) {
1416
- return this.exists(key);
1417
- }
1418
- /**
1419
- * Deletes the cache value stored in the key within the instance.
1420
- * @param key The key to delete.
1421
- */
1422
- delete(key) {
1423
- this.caches.delete(key);
1424
- this.parameters.delete(key);
1425
- this.updateRequirements.delete(key);
1426
- for (let i = 0, len = this.assignments.length; i < len; i++) {
1427
- const t = this.assignments[i];
1428
- const instance = t;
1429
- for (const cacheKey of instance.keys()) {
1430
- if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
1431
- instance.delete(cacheKey);
1432
- }
1433
- }
1434
- }
1435
- }
1436
- };
1437
- var CacheData = class _CacheData {
1438
- static StructuredClone = globalThis.structuredClone.bind(globalThis);
1439
- _value;
1440
- constructor(value) {
1441
- this._value = value;
1442
- }
1443
- /**
1444
- * This is cached data.
1445
- * It was generated at the time of caching, so there is a risk of modification if it's an object due to shallow copying.
1446
- * 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.
1447
- */
1448
- get raw() {
1449
- return this._value;
1450
- }
1451
- /**
1452
- * The method returns a copied value of the cached data.
1453
- * You can pass a function as a parameter to copy the value. This parameter function should return the copied value.
1454
- *
1455
- * If no parameter is passed, it defaults to using `structuredClone` function to copy the value.
1456
- * If you prefer shallow copying instead of deep copying,
1457
- * you can use the default options `array-shallow-copy`, `object-shallow-copy` and `deep-copy`,
1458
- * which are replaced with functions to shallow copy arrays and objects, respectively. This is a syntactic sugar.
1459
- * @param strategy The function that returns the copied value.
1460
- * If you want to perform a shallow copy, simply pass the strings `array-shallow-copy` or `object-shallow-copy` for easy use.
1461
- * The `array-shallow-copy` strategy performs a shallow copy of an array.
1462
- * The `object-shallow-copy` strategy performs a shallow copy of an object.
1463
- * The `deep-copy` strategy performs a deep copy of the value using `structuredClone`.
1464
- * The default is `deep-copy`.
1465
- */
1466
- clone(strategy = "deep-copy") {
1467
- if (strategy && typeof strategy !== "string") {
1468
- return strategy(this.raw);
1469
- }
1470
- switch (strategy) {
1471
- case "array-shallow-copy":
1472
- return [].concat(this.raw);
1473
- case "object-shallow-copy":
1474
- return Object.assign({}, this.raw);
1475
- case "deep-copy":
1476
- default:
1477
- return _CacheData.StructuredClone(this.raw);
1478
- }
1479
- }
1480
- };
1481
- var CacheEntanglementSync = class extends CacheEntanglement {
1482
- constructor(creation, option) {
1483
- super(creation, option);
1484
- }
1485
- recache(key) {
1486
- if (!this.parameters.has(key)) {
1487
- return;
1488
- }
1489
- if (!this.caches.has(key) || this.updateRequirements.has(key)) {
1490
- this.resolve(key, ...this.parameters.get(key));
1491
- }
1492
- return this.caches.get(key);
1493
- }
1494
- resolve(key, ...parameter) {
1495
- const resolved = {};
1496
- const dependencyKey = this.dependencyKey(key);
1497
- this.beforeUpdateHook(key, dependencyKey, ...parameter);
1498
- for (let i = 0, len = this.dependencyProperties.length; i < len; i++) {
1499
- const name = this.dependencyProperties[i];
1500
- const dependency = this.dependencies[name];
1501
- if (!dependency.exists(key) && !dependency.exists(dependencyKey)) {
1502
- throw new Error(`The key '${key}' or '${dependencyKey}' has not been assigned yet in dependency '${name.toString()}'.`, {
1503
- cause: {
1504
- from: this
1505
- }
1506
- });
1507
- }
1508
- const dependencyValue = dependency.recache(key) ?? dependency.recache(dependencyKey);
1509
- resolved[name] = dependencyValue;
1510
- }
1511
- const value = new CacheData(this.creation(key, resolved, ...parameter));
1512
- this.updateRequirements.delete(key);
1513
- this.parameters.set(key, parameter);
1514
- this.caches.set(key, value);
1515
- return value;
1516
- }
1517
- get(key) {
1518
- if (!this.parameters.has(key)) {
1519
- throw new Error(`Cache value not found: ${key}`);
1520
- }
1521
- return this.cache(key, ...this.parameters.get(key));
1522
- }
1523
- cache(key, ...parameter) {
1524
- if (!this.caches.has(key) || this.updateRequirements.has(key)) {
1525
- this.resolve(key, ...parameter);
1526
- }
1527
- return this.caches.get(key);
1528
- }
1529
- update(key, ...parameter) {
1530
- this.bubbleUpdateSignal(key);
1531
- this.resolve(key, ...parameter);
1532
- return this.caches.get(key);
1533
- }
1534
- };
1535
-
1536
- // src/base/BPTreeTransaction.ts
1537
- var BPTreeTransaction = class _BPTreeTransaction {
1538
- _cachedRegexp;
1539
- nodes;
1540
- deletedNodeBuffer = /* @__PURE__ */ new Map();
1541
- rootTx;
1542
- mvccRoot;
1543
- mvcc;
1544
- strategy;
1545
- comparator;
1546
- option;
1547
- order;
1548
- rootId;
1549
- verifierMap = {
1550
- gt: (nv, v) => this.comparator.isHigher(nv, v),
1551
- gte: (nv, v) => this.comparator.isHigher(nv, v) || this.comparator.isSame(nv, v),
1552
- lt: (nv, v) => this.comparator.isLower(nv, v),
1553
- lte: (nv, v) => this.comparator.isLower(nv, v) || this.comparator.isSame(nv, v),
1554
- equal: (nv, v) => this.comparator.isSame(nv, v),
1555
- notEqual: (nv, v) => this.comparator.isSame(nv, v) === false,
1556
- or: (nv, v) => this.ensureValues(v).some((v2) => this.comparator.isSame(nv, v2)),
1557
- primaryGt: (nv, v) => this.comparator.isPrimaryHigher(nv, v),
1558
- primaryGte: (nv, v) => this.comparator.isPrimaryHigher(nv, v) || this.comparator.isPrimarySame(nv, v),
1559
- primaryLt: (nv, v) => this.comparator.isPrimaryLower(nv, v),
1560
- primaryLte: (nv, v) => this.comparator.isPrimaryLower(nv, v) || this.comparator.isPrimarySame(nv, v),
1561
- primaryEqual: (nv, v) => this.comparator.isPrimarySame(nv, v),
1562
- primaryNotEqual: (nv, v) => this.comparator.isPrimarySame(nv, v) === false,
1563
- primaryOr: (nv, v) => this.ensureValues(v).some((v2) => this.comparator.isPrimarySame(nv, v2)),
1564
- like: (nv, v) => {
1565
- const nodeValue = this.comparator.match(nv);
1566
- const value = v;
1567
- const cache = this._cachedRegexp.cache(value);
1568
- const regexp = cache.raw;
1569
- return regexp.test(nodeValue);
1429
+ // src/base/BPTreeTransaction.ts
1430
+ var BPTreeTransaction = class _BPTreeTransaction {
1431
+ _cachedRegexp = /* @__PURE__ */ new Map();
1432
+ nodes = /* @__PURE__ */ new Map();
1433
+ deletedNodeBuffer = /* @__PURE__ */ new Map();
1434
+ rootTx;
1435
+ mvccRoot;
1436
+ mvcc;
1437
+ strategy;
1438
+ comparator;
1439
+ option;
1440
+ order;
1441
+ rootId;
1442
+ isInitialized = false;
1443
+ isDestroyed = false;
1444
+ verifierMap = {
1445
+ gt: (nv, v) => this.comparator.isHigher(nv, v),
1446
+ gte: (nv, v) => this.comparator.isHigher(nv, v) || this.comparator.isSame(nv, v),
1447
+ lt: (nv, v) => this.comparator.isLower(nv, v),
1448
+ lte: (nv, v) => this.comparator.isLower(nv, v) || this.comparator.isSame(nv, v),
1449
+ equal: (nv, v) => this.comparator.isSame(nv, v),
1450
+ notEqual: (nv, v) => this.comparator.isSame(nv, v) === false,
1451
+ or: (nv, v) => this.ensureValues(v).some((v2) => this.comparator.isSame(nv, v2)),
1452
+ primaryGt: (nv, v) => this.comparator.isPrimaryHigher(nv, v),
1453
+ primaryGte: (nv, v) => this.comparator.isPrimaryHigher(nv, v) || this.comparator.isPrimarySame(nv, v),
1454
+ primaryLt: (nv, v) => this.comparator.isPrimaryLower(nv, v),
1455
+ primaryLte: (nv, v) => this.comparator.isPrimaryLower(nv, v) || this.comparator.isPrimarySame(nv, v),
1456
+ primaryEqual: (nv, v) => this.comparator.isPrimarySame(nv, v),
1457
+ primaryNotEqual: (nv, v) => this.comparator.isPrimarySame(nv, v) === false,
1458
+ primaryOr: (nv, v) => this.ensureValues(v).some((v2) => this.comparator.isPrimarySame(nv, v2)),
1459
+ like: (nv, v) => {
1460
+ const nodeValue = this.comparator.match(nv);
1461
+ const value = v;
1462
+ if (!this._cachedRegexp.has(value)) {
1463
+ const pattern = value.replace(/%/g, ".*").replace(/_/g, ".");
1464
+ const regexp2 = new RegExp(`^${pattern}$`, "i");
1465
+ this._cachedRegexp.set(value, regexp2);
1466
+ }
1467
+ const regexp = this._cachedRegexp.get(value);
1468
+ return regexp.test(nodeValue);
1570
1469
  }
1571
1470
  };
1572
1471
  verifierStartNode = {
@@ -1737,6 +1636,9 @@ var BPTreeTransaction = class _BPTreeTransaction {
1737
1636
  }
1738
1637
  return true;
1739
1638
  }
1639
+ _cloneNode(node) {
1640
+ return JSON.parse(JSON.stringify(node));
1641
+ }
1740
1642
  /**
1741
1643
  * Selects the best driver key from a condition object.
1742
1644
  * The driver key determines the starting point and traversal direction for queries.
@@ -1769,17 +1671,6 @@ var BPTreeTransaction = class _BPTreeTransaction {
1769
1671
  this.strategy = strategy;
1770
1672
  this.comparator = comparator;
1771
1673
  this.option = option ?? {};
1772
- this.nodes = new LRUMap(this.option.capacity ?? 1e3);
1773
- this._cachedRegexp = this._createCachedRegexp();
1774
- }
1775
- _createCachedRegexp() {
1776
- return new CacheEntanglementSync((key) => {
1777
- const pattern = key.replace(/%/g, ".*").replace(/_/g, ".");
1778
- const regexp = new RegExp(`^${pattern}$`, "i");
1779
- return regexp;
1780
- }, {
1781
- capacity: this.option.capacity ?? 1e3
1782
- });
1783
1674
  }
1784
1675
  ensureValues(v) {
1785
1676
  if (!Array.isArray(v)) {
@@ -1810,13 +1701,25 @@ var BPTreeTransaction = class _BPTreeTransaction {
1810
1701
  getResultEntries() {
1811
1702
  return this.mvcc.getResultEntries();
1812
1703
  }
1704
+ _clearCache() {
1705
+ this._cachedRegexp.clear();
1706
+ }
1813
1707
  /**
1814
1708
  * Clears all cached nodes.
1815
1709
  * This method is useful for freeing up memory when the tree is no longer needed.
1816
1710
  */
1817
1711
  clear() {
1818
- this._cachedRegexp.clear();
1819
- this.nodes.clear();
1712
+ if (this.rootTx !== this) {
1713
+ throw new Error("Cannot call clear on a nested transaction");
1714
+ }
1715
+ this._clearInternal();
1716
+ }
1717
+ _clearInternal() {
1718
+ if (this.isDestroyed) {
1719
+ throw new Error("Transaction already destroyed");
1720
+ }
1721
+ this._clearCache();
1722
+ this.isDestroyed = true;
1820
1723
  }
1821
1724
  _binarySearchValues(values, target, usePrimary = false, upperBound = false) {
1822
1725
  let low = 0;
@@ -1852,9 +1755,6 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
1852
1755
  );
1853
1756
  }
1854
1757
  getNode(id) {
1855
- if (this.nodes.has(id)) {
1856
- return this.nodes.get(id);
1857
- }
1858
1758
  return this.mvcc.read(id);
1859
1759
  }
1860
1760
  /**
@@ -1872,23 +1772,22 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
1872
1772
  prev
1873
1773
  };
1874
1774
  this.mvcc.create(id, node);
1875
- this.nodes.set(id, node);
1876
1775
  return node;
1877
1776
  }
1878
1777
  _updateNode(node) {
1778
+ if (this.mvcc.isDeleted(node.id)) {
1779
+ return;
1780
+ }
1879
1781
  this.mvcc.write(node.id, node);
1880
- this.nodes.set(node.id, node);
1881
1782
  }
1882
1783
  _deleteNode(node) {
1784
+ if (this.mvcc.isDeleted(node.id)) {
1785
+ return;
1786
+ }
1883
1787
  this.mvcc.delete(node.id);
1884
- this.nodes.delete(node.id);
1885
1788
  }
1886
1789
  _readHead() {
1887
- if (this.nodes.has("__HEAD__")) {
1888
- return this.nodes.get("__HEAD__") ?? null;
1889
- }
1890
- const head = this.mvcc.read("__HEAD__");
1891
- return head ?? null;
1790
+ return this.mvcc.read("__HEAD__");
1892
1791
  }
1893
1792
  _writeHead(head) {
1894
1793
  if (!this.mvcc.exists("__HEAD__")) {
@@ -1896,41 +1795,45 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
1896
1795
  } else {
1897
1796
  this.mvcc.write("__HEAD__", head);
1898
1797
  }
1899
- this.nodes.set("__HEAD__", head);
1900
1798
  this.rootId = head.root;
1901
1799
  }
1902
1800
  _insertAtLeaf(node, key, value) {
1903
- if (node.values.length) {
1904
- for (let i = 0, len = node.values.length; i < len; i++) {
1905
- const nValue = node.values[i];
1801
+ let leaf = node;
1802
+ leaf = this._cloneNode(leaf);
1803
+ if (leaf.values.length) {
1804
+ for (let i = 0, len = leaf.values.length; i < len; i++) {
1805
+ const nValue = leaf.values[i];
1906
1806
  if (this.comparator.isSame(value, nValue)) {
1907
- const keys = node.keys[i];
1807
+ const keys = leaf.keys[i];
1908
1808
  if (keys.includes(key)) {
1909
1809
  break;
1910
1810
  }
1911
1811
  keys.push(key);
1912
- this._updateNode(node);
1913
- return;
1812
+ this._updateNode(leaf);
1813
+ return leaf;
1914
1814
  } else if (this.comparator.isLower(value, nValue)) {
1915
- node.values.splice(i, 0, value);
1916
- node.keys.splice(i, 0, [key]);
1917
- this._updateNode(node);
1918
- return;
1919
- } else if (i + 1 === node.values.length) {
1920
- node.values.push(value);
1921
- node.keys.push([key]);
1922
- this._updateNode(node);
1923
- return;
1815
+ leaf.values.splice(i, 0, value);
1816
+ leaf.keys.splice(i, 0, [key]);
1817
+ this._updateNode(leaf);
1818
+ return leaf;
1819
+ } else if (i + 1 === leaf.values.length) {
1820
+ leaf.values.push(value);
1821
+ leaf.keys.push([key]);
1822
+ this._updateNode(leaf);
1823
+ return leaf;
1924
1824
  }
1925
1825
  }
1926
1826
  } else {
1927
- node.values = [value];
1928
- node.keys = [[key]];
1929
- this._updateNode(node);
1930
- return;
1827
+ leaf.values = [value];
1828
+ leaf.keys = [[key]];
1829
+ this._updateNode(leaf);
1830
+ return leaf;
1931
1831
  }
1832
+ return leaf;
1932
1833
  }
1933
1834
  _insertInParent(node, value, pointer) {
1835
+ node = this._cloneNode(node);
1836
+ pointer = this._cloneNode(pointer);
1934
1837
  if (this.rootId === node.id) {
1935
1838
  const root = this._createNode(false, [node.id, pointer.id], [value]);
1936
1839
  this.rootId = root.id;
@@ -1949,7 +1852,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
1949
1852
  this._updateNode(pointer);
1950
1853
  return;
1951
1854
  }
1952
- const parentNode = this.getNode(node.parent);
1855
+ const parentNode = this._cloneNode(this.getNode(node.parent));
1953
1856
  const nodeIndex = parentNode.keys.indexOf(node.id);
1954
1857
  if (nodeIndex === -1) {
1955
1858
  throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
@@ -1965,7 +1868,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
1965
1868
  leftSibling.next = pointer.id;
1966
1869
  this._updateNode(leftSibling);
1967
1870
  if (oldNextId) {
1968
- const oldNext = this.getNode(oldNextId);
1871
+ const oldNext = this._cloneNode(this.getNode(oldNextId));
1969
1872
  oldNext.prev = pointer.id;
1970
1873
  this._updateNode(oldNext);
1971
1874
  }
@@ -1982,12 +1885,12 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
1982
1885
  parentNode.values = parentNode.values.slice(0, mid);
1983
1886
  parentNode.keys = parentNode.keys.slice(0, mid + 1);
1984
1887
  for (const k of parentNode.keys) {
1985
- const n = this.getNode(k);
1888
+ const n = this._cloneNode(this.getNode(k));
1986
1889
  n.parent = parentNode.id;
1987
1890
  this._updateNode(n);
1988
1891
  }
1989
1892
  for (const k of parentPointer.keys) {
1990
- const n = this.getNode(k);
1893
+ const n = this._cloneNode(this.getNode(k));
1991
1894
  n.parent = parentPointer.id;
1992
1895
  this._updateNode(n);
1993
1896
  }
@@ -2122,28 +2025,46 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2122
2025
  }
2123
2026
  }
2124
2027
  init() {
2125
- this.clear();
2126
- const head = this._readHead();
2127
- if (head === null) {
2128
- this.order = this.strategy.order;
2129
- const root = this._createNode(true, [], []);
2130
- this._writeHead({
2131
- root: root.id,
2132
- order: this.order,
2133
- data: this.strategy.head.data
2134
- });
2135
- } else {
2136
- const { root, order } = head;
2137
- this.strategy.head = head;
2138
- this.order = order;
2139
- this._writeHead({
2140
- root,
2141
- order: this.order,
2142
- data: this.strategy.head.data
2143
- });
2028
+ if (this.rootTx !== this) {
2029
+ throw new Error("Cannot call init on a nested transaction");
2030
+ }
2031
+ this._initInternal();
2032
+ }
2033
+ _initInternal() {
2034
+ if (this.isInitialized) {
2035
+ throw new Error("Transaction already initialized");
2036
+ }
2037
+ if (this.isDestroyed) {
2038
+ throw new Error("Transaction already destroyed");
2144
2039
  }
2145
- if (this.order < 3) {
2146
- throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
2040
+ this.isInitialized = true;
2041
+ try {
2042
+ this._clearCache();
2043
+ const head = this._readHead();
2044
+ if (head === null) {
2045
+ this.order = this.strategy.order;
2046
+ const root = this._createNode(true, [], []);
2047
+ this._writeHead({
2048
+ root: root.id,
2049
+ order: this.order,
2050
+ data: this.strategy.head.data
2051
+ });
2052
+ } else {
2053
+ const { root, order } = head;
2054
+ this.strategy.head = head;
2055
+ this.order = order;
2056
+ this._writeHead({
2057
+ root,
2058
+ order: this.order,
2059
+ data: this.strategy.head.data
2060
+ });
2061
+ }
2062
+ if (this.order < 3) {
2063
+ throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
2064
+ }
2065
+ } catch (e) {
2066
+ this.isInitialized = false;
2067
+ throw e;
2147
2068
  }
2148
2069
  }
2149
2070
  exists(key, value) {
@@ -2157,21 +2078,6 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2157
2078
  }
2158
2079
  return false;
2159
2080
  }
2160
- forceUpdate(id) {
2161
- if (id) {
2162
- this.nodes.delete(id);
2163
- this.getNode(id);
2164
- return 1;
2165
- }
2166
- const keys = Array.from(this.nodes.keys());
2167
- for (const key of keys) {
2168
- this.nodes.delete(key);
2169
- }
2170
- for (const key of keys) {
2171
- this.getNode(key);
2172
- }
2173
- return keys.length;
2174
- }
2175
2081
  get(key) {
2176
2082
  let node = this.leftestNode();
2177
2083
  while (true) {
@@ -2257,10 +2163,10 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2257
2163
  return map;
2258
2164
  }
2259
2165
  insert(key, value) {
2260
- const before = this.insertableNode(value);
2261
- this._insertAtLeaf(before, key, value);
2166
+ let before = this.insertableNode(value);
2167
+ before = this._insertAtLeaf(before, key, value);
2262
2168
  if (before.values.length === this.order) {
2263
- const after = this._createNode(
2169
+ let after = this._createNode(
2264
2170
  true,
2265
2171
  [],
2266
2172
  [],
@@ -2269,14 +2175,18 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2269
2175
  null
2270
2176
  );
2271
2177
  const mid = Math.ceil(this.order / 2) - 1;
2178
+ after = this._cloneNode(after);
2272
2179
  after.values = before.values.slice(mid + 1);
2273
2180
  after.keys = before.keys.slice(mid + 1);
2274
2181
  before.values = before.values.slice(0, mid + 1);
2275
2182
  before.keys = before.keys.slice(0, mid + 1);
2183
+ this._updateNode(before);
2184
+ this._updateNode(after);
2276
2185
  this._insertInParent(before, after.values[0], after);
2277
2186
  }
2278
2187
  }
2279
2188
  _deleteEntry(node, key) {
2189
+ node = this._cloneNode(node);
2280
2190
  if (!node.leaf) {
2281
2191
  let keyIndex = -1;
2282
2192
  for (let i = 0, len = node.keys.length; i < len; i++) {
@@ -2295,7 +2205,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2295
2205
  if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
2296
2206
  const keys = node.keys;
2297
2207
  this._deleteNode(node);
2298
- const newRoot = this.getNode(keys[0]);
2208
+ const newRoot = this._cloneNode(this.getNode(keys[0]));
2299
2209
  newRoot.parent = null;
2300
2210
  this._updateNode(newRoot);
2301
2211
  this._writeHead({
@@ -2303,17 +2213,17 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2303
2213
  order: this.order,
2304
2214
  data: this.strategy.head.data
2305
2215
  });
2306
- return;
2216
+ return node;
2307
2217
  } else if (this.rootId === node.id) {
2308
2218
  this._writeHead({
2309
2219
  root: node.id,
2310
2220
  order: this.order,
2311
2221
  data: this.strategy.head.data
2312
2222
  });
2313
- return;
2223
+ return node;
2314
2224
  } else if (node.keys.length < Math.ceil(this.order / 2) && !node.leaf || node.values.length < Math.ceil((this.order - 1) / 2) && node.leaf) {
2315
2225
  if (node.parent === null) {
2316
- return;
2226
+ return node;
2317
2227
  }
2318
2228
  let isPredecessor = false;
2319
2229
  let parentNode = this.getNode(node.parent);
@@ -2325,11 +2235,11 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2325
2235
  const nKey = parentNode.keys[i];
2326
2236
  if (nKey === node.id) {
2327
2237
  if (i > 0) {
2328
- prevNode = this.getNode(parentNode.keys[i - 1]);
2238
+ prevNode = this._cloneNode(this.getNode(parentNode.keys[i - 1]));
2329
2239
  prevValue = parentNode.values[i - 1];
2330
2240
  }
2331
2241
  if (i < parentNode.keys.length - 1) {
2332
- nextNode = this.getNode(parentNode.keys[i + 1]);
2242
+ nextNode = this._cloneNode(this.getNode(parentNode.keys[i + 1]));
2333
2243
  postValue = parentNode.values[i];
2334
2244
  }
2335
2245
  }
@@ -2354,7 +2264,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2354
2264
  }
2355
2265
  }
2356
2266
  if (!pointer) {
2357
- return;
2267
+ return node;
2358
2268
  }
2359
2269
  if (node.values.length + pointer.values.length < this.order) {
2360
2270
  if (!isPredecessor) {
@@ -2368,7 +2278,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2368
2278
  } else {
2369
2279
  pointer.next = node.next;
2370
2280
  if (pointer.next) {
2371
- const n = this.getNode(pointer.next);
2281
+ const n = this._cloneNode(this.getNode(pointer.next));
2372
2282
  n.prev = pointer.id;
2373
2283
  this._updateNode(n);
2374
2284
  }
@@ -2377,14 +2287,14 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2377
2287
  if (!pointer.leaf) {
2378
2288
  const keys = pointer.keys;
2379
2289
  for (const key2 of keys) {
2380
- const node2 = this.getNode(key2);
2290
+ const node2 = this._cloneNode(this.getNode(key2));
2381
2291
  node2.parent = pointer.id;
2382
2292
  this._updateNode(node2);
2383
2293
  }
2384
2294
  }
2385
2295
  this._deleteNode(node);
2386
2296
  this._updateNode(pointer);
2387
- this._deleteEntry(this.getNode(node.parent), node.id);
2297
+ this._deleteEntry(this._cloneNode(this.getNode(node.parent)), node.id);
2388
2298
  } else {
2389
2299
  if (isPredecessor) {
2390
2300
  let pointerPm;
@@ -2394,7 +2304,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2394
2304
  pointerKm = pointer.values.splice(-1)[0];
2395
2305
  node.keys = [pointerPm, ...node.keys];
2396
2306
  node.values = [guess, ...node.values];
2397
- parentNode = this.getNode(node.parent);
2307
+ parentNode = this._cloneNode(this.getNode(node.parent));
2398
2308
  const nodeIndex = parentNode.keys.indexOf(node.id);
2399
2309
  if (nodeIndex > 0) {
2400
2310
  parentNode.values[nodeIndex - 1] = pointerKm;
@@ -2405,7 +2315,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2405
2315
  pointerKm = pointer.values.splice(-1)[0];
2406
2316
  node.keys = [pointerPm, ...node.keys];
2407
2317
  node.values = [pointerKm, ...node.values];
2408
- parentNode = this.getNode(node.parent);
2318
+ parentNode = this._cloneNode(this.getNode(node.parent));
2409
2319
  const nodeIndex = parentNode.keys.indexOf(node.id);
2410
2320
  if (nodeIndex > 0) {
2411
2321
  parentNode.values[nodeIndex - 1] = pointerKm;
@@ -2422,7 +2332,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2422
2332
  pointerK0 = pointer.values.splice(0, 1)[0];
2423
2333
  node.keys = [...node.keys, pointerP0];
2424
2334
  node.values = [...node.values, guess];
2425
- parentNode = this.getNode(node.parent);
2335
+ parentNode = this._cloneNode(this.getNode(node.parent));
2426
2336
  const pointerIndex = parentNode.keys.indexOf(pointer.id);
2427
2337
  if (pointerIndex > 0) {
2428
2338
  parentNode.values[pointerIndex - 1] = pointerK0;
@@ -2433,7 +2343,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2433
2343
  pointerK0 = pointer.values.splice(0, 1)[0];
2434
2344
  node.keys = [...node.keys, pointerP0];
2435
2345
  node.values = [...node.values, pointerK0];
2436
- parentNode = this.getNode(node.parent);
2346
+ parentNode = this._cloneNode(this.getNode(node.parent));
2437
2347
  const pointerIndex = parentNode.keys.indexOf(pointer.id);
2438
2348
  if (pointerIndex > 0) {
2439
2349
  parentNode.values[pointerIndex - 1] = pointer.values[0];
@@ -2445,21 +2355,21 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2445
2355
  }
2446
2356
  if (!pointer.leaf) {
2447
2357
  for (const key2 of pointer.keys) {
2448
- const n = this.getNode(key2);
2358
+ const n = this._cloneNode(this.getNode(key2));
2449
2359
  n.parent = pointer.id;
2450
2360
  this._updateNode(n);
2451
2361
  }
2452
2362
  }
2453
2363
  if (!node.leaf) {
2454
2364
  for (const key2 of node.keys) {
2455
- const n = this.getNode(key2);
2365
+ const n = this._cloneNode(this.getNode(key2));
2456
2366
  n.parent = node.id;
2457
2367
  this._updateNode(n);
2458
2368
  }
2459
2369
  }
2460
2370
  if (!parentNode.leaf) {
2461
2371
  for (const key2 of parentNode.keys) {
2462
- const n = this.getNode(key2);
2372
+ const n = this._cloneNode(this.getNode(key2));
2463
2373
  n.parent = parentNode.id;
2464
2374
  this._updateNode(n);
2465
2375
  }
@@ -2468,10 +2378,12 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2468
2378
  } else {
2469
2379
  this._updateNode(node);
2470
2380
  }
2381
+ return node;
2471
2382
  }
2472
2383
  delete(key, value) {
2473
2384
  let node = this.insertableNodeByPrimary(value);
2474
2385
  let found = false;
2386
+ node = this._cloneNode(node);
2475
2387
  while (true) {
2476
2388
  let i = node.values.length;
2477
2389
  while (i--) {
@@ -2486,7 +2398,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2486
2398
  node.values.splice(i, 1);
2487
2399
  }
2488
2400
  this._updateNode(node);
2489
- this._deleteEntry(node, key);
2401
+ node = this._deleteEntry(node, key);
2490
2402
  found = true;
2491
2403
  break;
2492
2404
  }
@@ -2521,20 +2433,14 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2521
2433
  commit(label) {
2522
2434
  let result = this.mvcc.commit(label);
2523
2435
  if (result.success) {
2524
- result = this.mvccRoot.commit(label);
2525
- if (result.success && this.rootTx !== this) {
2526
- this.rootTx.rootId = this.rootId;
2436
+ const isRootTx = this.rootTx !== this;
2437
+ if (isRootTx) {
2438
+ result = this.rootTx.commit(label);
2439
+ if (result.success) {
2440
+ this.rootTx.rootId = this.rootId;
2441
+ }
2527
2442
  }
2528
2443
  if (result.success) {
2529
- for (const r of result.created) {
2530
- this.nodes.set(r.key, r.data);
2531
- }
2532
- for (const r of result.updated) {
2533
- this.nodes.set(r.key, r.data);
2534
- }
2535
- for (const r of result.deleted) {
2536
- this.nodes.delete(r.key);
2537
- }
2538
2444
  }
2539
2445
  }
2540
2446
  return result;
@@ -2582,7 +2488,9 @@ var BPTreeMVCCStrategySync = class extends SyncMVCCStrategy {
2582
2488
  // src/BPTreeSync.ts
2583
2489
  var BPTreeSync = class extends BPTreeSyncTransaction {
2584
2490
  constructor(strategy, comparator, option) {
2585
- const mvccRoot = new SyncMVCCTransaction(new BPTreeMVCCStrategySync(strategy));
2491
+ const mvccRoot = new SyncMVCCTransaction(new BPTreeMVCCStrategySync(strategy), {
2492
+ cacheCapacity: option?.capacity ?? void 0
2493
+ });
2586
2494
  super(
2587
2495
  null,
2588
2496
  mvccRoot,
@@ -2606,7 +2514,7 @@ var BPTreeSync = class extends BPTreeSyncTransaction {
2606
2514
  this.comparator,
2607
2515
  this.option
2608
2516
  );
2609
- tx.init();
2517
+ tx._initInternal();
2610
2518
  return tx;
2611
2519
  }
2612
2520
  insert(key, value) {
@@ -2616,7 +2524,6 @@ var BPTreeSync = class extends BPTreeSyncTransaction {
2616
2524
  if (!result.success) {
2617
2525
  throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
2618
2526
  }
2619
- this.rootId = tx.getRootId();
2620
2527
  }
2621
2528
  delete(key, value) {
2622
2529
  const tx = this.createTransaction();
@@ -2625,394 +2532,673 @@ var BPTreeSync = class extends BPTreeSyncTransaction {
2625
2532
  if (!result.success) {
2626
2533
  throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
2627
2534
  }
2628
- this.rootId = tx.getRootId();
2629
2535
  }
2630
2536
  };
2631
2537
 
2632
- // src/transaction/BPTreeAsyncTransaction.ts
2633
- var BPTreeAsyncTransaction = class extends BPTreeTransaction {
2634
- constructor(rootTx, mvccRoot, mvcc, strategy, comparator, option) {
2635
- super(
2636
- rootTx,
2637
- mvccRoot,
2638
- mvcc,
2639
- strategy,
2640
- comparator,
2641
- option
2642
- );
2538
+ // node_modules/ryoiki/dist/esm/index.mjs
2539
+ var Ryoiki2 = class _Ryoiki2 {
2540
+ readings;
2541
+ writings;
2542
+ readQueue;
2543
+ writeQueue;
2544
+ static async CatchError(promise) {
2545
+ return await promise.then((v) => [void 0, v]).catch((err) => [err]);
2643
2546
  }
2644
- async getNode(id) {
2645
- if (this.nodes.has(id)) {
2646
- return this.nodes.get(id);
2547
+ static IsRangeOverlap(a, b) {
2548
+ const [start1, end1] = a;
2549
+ const [start2, end2] = b;
2550
+ if (end1 <= start2 || end2 <= start1) {
2551
+ return false;
2647
2552
  }
2648
- return await this.mvcc.read(id);
2553
+ return true;
2554
+ }
2555
+ static ERR_ALREADY_EXISTS(lockId) {
2556
+ return new Error(`The '${lockId}' task already existing in queue or running.`);
2557
+ }
2558
+ static ERR_NOT_EXISTS(lockId) {
2559
+ return new Error(`The '${lockId}' task not existing in task queue.`);
2560
+ }
2561
+ static ERR_TIMEOUT(lockId, timeout) {
2562
+ return new Error(`The task with ID '${lockId}' failed to acquire the lock within the timeout(${timeout}ms).`);
2649
2563
  }
2650
2564
  /**
2651
- * Create a new node with a unique ID.
2565
+ * Constructs a new instance of the Ryoiki class.
2652
2566
  */
2653
- async _createNode(leaf, keys, values, parent = null, next = null, prev = null) {
2654
- const id = await this.strategy.id(leaf);
2655
- const node = {
2656
- id,
2657
- keys,
2658
- values,
2659
- leaf,
2660
- parent,
2661
- next,
2662
- prev
2663
- };
2664
- await this.mvcc.create(id, node);
2665
- this.nodes.set(id, node);
2666
- return node;
2567
+ constructor() {
2568
+ this.readings = /* @__PURE__ */ new Map();
2569
+ this.writings = /* @__PURE__ */ new Map();
2570
+ this.readQueue = /* @__PURE__ */ new Map();
2571
+ this.writeQueue = /* @__PURE__ */ new Map();
2667
2572
  }
2668
- async _updateNode(node) {
2669
- await this.mvcc.write(node.id, node);
2670
- this.nodes.set(node.id, node);
2573
+ /**
2574
+ * Creates a range based on a start value and length.
2575
+ * @param start - The starting value of the range.
2576
+ * @param length - The length of the range.
2577
+ * @returns A range tuple [start, start + length].
2578
+ */
2579
+ range(start, length) {
2580
+ return [start, start + length];
2671
2581
  }
2672
- async _deleteNode(node) {
2673
- await this.mvcc.delete(node.id);
2674
- this.nodes.delete(node.id);
2582
+ rangeOverlapping(tasks, range) {
2583
+ return Array.from(tasks.values()).some((t) => _Ryoiki2.IsRangeOverlap(t.range, range));
2675
2584
  }
2676
- async _readHead() {
2677
- if (this.nodes.has("__HEAD__")) {
2678
- return this.nodes.get("__HEAD__") ?? null;
2679
- }
2680
- const head = await this.mvcc.read("__HEAD__");
2681
- return head ?? null;
2585
+ isSameRange(a, b) {
2586
+ const [a1, a2] = a;
2587
+ const [b1, b2] = b;
2588
+ return a1 === b1 && a2 === b2;
2682
2589
  }
2683
- async _writeHead(head) {
2684
- if (!await this.mvcc.exists("__HEAD__")) {
2685
- await this.mvcc.create("__HEAD__", head);
2686
- } else {
2687
- await this.mvcc.write("__HEAD__", head);
2590
+ fetchUnitAndRun(queue, workspaces) {
2591
+ for (const [id, unit] of queue) {
2592
+ if (!unit.condition()) {
2593
+ continue;
2594
+ }
2595
+ this._alloc(queue, workspaces, id);
2688
2596
  }
2689
- this.nodes.set("__HEAD__", head);
2690
- this.rootId = head.root;
2691
2597
  }
2692
- async _insertAtLeaf(node, key, value) {
2693
- if (node.values.length) {
2694
- for (let i = 0, len = node.values.length; i < len; i++) {
2695
- const nValue = node.values[i];
2696
- if (this.comparator.isSame(value, nValue)) {
2697
- const keys = node.keys[i];
2698
- if (keys.includes(key)) {
2699
- break;
2700
- }
2701
- keys.push(key);
2702
- await this._updateNode(node);
2703
- return;
2704
- } else if (this.comparator.isLower(value, nValue)) {
2705
- node.values.splice(i, 0, value);
2706
- node.keys.splice(i, 0, [key]);
2707
- await this._updateNode(node);
2708
- return;
2709
- } else if (i + 1 === node.values.length) {
2710
- node.values.push(value);
2711
- node.keys.push([key]);
2712
- await this._updateNode(node);
2713
- return;
2714
- }
2715
- }
2716
- } else {
2717
- node.values = [value];
2718
- node.keys = [[key]];
2719
- await this._updateNode(node);
2720
- return;
2721
- }
2722
- }
2723
- async _insertInParent(node, value, pointer) {
2724
- if (this.rootId === node.id) {
2725
- const root = await this._createNode(false, [node.id, pointer.id], [value]);
2726
- this.rootId = root.id;
2727
- node.parent = root.id;
2728
- pointer.parent = root.id;
2729
- if (pointer.leaf) {
2730
- node.next = pointer.id;
2731
- pointer.prev = node.id;
2732
- }
2733
- await this._writeHead({
2734
- root: root.id,
2735
- order: this.order,
2736
- data: this.strategy.head.data
2737
- });
2738
- await this._updateNode(node);
2739
- await this._updateNode(pointer);
2740
- return;
2741
- }
2742
- const parentNode = await this.getNode(node.parent);
2743
- const nodeIndex = parentNode.keys.indexOf(node.id);
2744
- if (nodeIndex === -1) {
2745
- throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
2746
- }
2747
- parentNode.values.splice(nodeIndex, 0, value);
2748
- parentNode.keys.splice(nodeIndex + 1, 0, pointer.id);
2749
- pointer.parent = parentNode.id;
2750
- if (pointer.leaf) {
2751
- const leftSibling = node;
2752
- const oldNextId = leftSibling.next;
2753
- pointer.prev = leftSibling.id;
2754
- pointer.next = oldNextId;
2755
- leftSibling.next = pointer.id;
2756
- await this._updateNode(leftSibling);
2757
- if (oldNextId) {
2758
- const oldNext = await this.getNode(oldNextId);
2759
- oldNext.prev = pointer.id;
2760
- await this._updateNode(oldNext);
2761
- }
2762
- }
2763
- await this._updateNode(parentNode);
2764
- await this._updateNode(pointer);
2765
- if (parentNode.keys.length > this.order) {
2766
- const parentPointer = await this._createNode(false, [], []);
2767
- parentPointer.parent = parentNode.parent;
2768
- const mid = Math.ceil(this.order / 2) - 1;
2769
- parentPointer.values = parentNode.values.slice(mid + 1);
2770
- parentPointer.keys = parentNode.keys.slice(mid + 1);
2771
- const midValue = parentNode.values[mid];
2772
- parentNode.values = parentNode.values.slice(0, mid);
2773
- parentNode.keys = parentNode.keys.slice(0, mid + 1);
2774
- for (const k of parentNode.keys) {
2775
- const n = await this.getNode(k);
2776
- n.parent = parentNode.id;
2777
- await this._updateNode(n);
2778
- }
2779
- for (const k of parentPointer.keys) {
2780
- const n = await this.getNode(k);
2781
- n.parent = parentPointer.id;
2782
- await this._updateNode(n);
2598
+ _handleOverload(args, handlers, argPatterns) {
2599
+ for (const [key, pattern] of Object.entries(argPatterns)) {
2600
+ if (this._matchArgs(args, pattern)) {
2601
+ return handlers[key](...args);
2783
2602
  }
2784
- await this._updateNode(parentNode);
2785
- await this._insertInParent(parentNode, midValue, parentPointer);
2786
- }
2787
- }
2788
- async insertableNode(value) {
2789
- let node = await this.getNode(this.rootId);
2790
- while (!node.leaf) {
2791
- const { index } = this._binarySearchValues(node.values, value, false, true);
2792
- node = await this.getNode(node.keys[index]);
2793
- }
2794
- return node;
2795
- }
2796
- async insertableNodeByPrimary(value) {
2797
- let node = await this.getNode(this.rootId);
2798
- while (!node.leaf) {
2799
- const { index } = this._binarySearchValues(node.values, value, true, false);
2800
- node = await this.getNode(node.keys[index]);
2801
- }
2802
- return node;
2803
- }
2804
- async insertableRightestNodeByPrimary(value) {
2805
- let node = await this.getNode(this.rootId);
2806
- while (!node.leaf) {
2807
- const { index } = this._binarySearchValues(node.values, value, true, true);
2808
- node = await this.getNode(node.keys[index]);
2809
2603
  }
2810
- return node;
2604
+ throw new Error("Invalid arguments");
2811
2605
  }
2812
- async insertableRightestEndNodeByPrimary(value) {
2813
- const node = await this.insertableRightestNodeByPrimary(value);
2814
- if (!node.next) {
2815
- return null;
2816
- }
2817
- return await this.getNode(node.next);
2606
+ _matchArgs(args, pattern) {
2607
+ return args.every((arg, index) => {
2608
+ const expectedType = pattern[index];
2609
+ if (expectedType === void 0) return typeof arg === "undefined";
2610
+ if (expectedType === Function) return typeof arg === "function";
2611
+ if (expectedType === Number) return typeof arg === "number";
2612
+ if (expectedType === Array) return Array.isArray(arg);
2613
+ return false;
2614
+ });
2818
2615
  }
2819
- async insertableEndNode(value, direction) {
2820
- const insertableNode = await this.insertableNode(value);
2821
- let key;
2822
- switch (direction) {
2823
- case -1:
2824
- key = "prev";
2825
- break;
2826
- case 1:
2827
- key = "next";
2828
- break;
2829
- default:
2830
- throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
2831
- }
2832
- const guessNode = insertableNode[key];
2833
- if (!guessNode) {
2834
- return null;
2835
- }
2836
- return await this.getNode(guessNode);
2616
+ _createRandomId() {
2617
+ const timestamp = Date.now().toString(36);
2618
+ const random = Math.random().toString(36).substring(2);
2619
+ return `${timestamp}${random}`;
2837
2620
  }
2838
- async leftestNode() {
2839
- let node = await this.getNode(this.rootId);
2840
- if (node === null) {
2841
- debugger;
2842
- }
2843
- while (!node.leaf) {
2844
- const keys = node.keys;
2845
- node = await this.getNode(keys[0]);
2621
+ _alloc(queue, workspaces, lockId) {
2622
+ const unit = queue.get(lockId);
2623
+ if (!unit) {
2624
+ throw _Ryoiki2.ERR_NOT_EXISTS(lockId);
2846
2625
  }
2847
- return node;
2626
+ workspaces.set(lockId, unit);
2627
+ queue.delete(lockId);
2628
+ unit.alloc();
2848
2629
  }
2849
- async rightestNode() {
2850
- let node = await this.getNode(this.rootId);
2851
- while (!node.leaf) {
2852
- const keys = node.keys;
2853
- node = await this.getNode(keys[keys.length - 1]);
2630
+ _free(workspaces, lockId) {
2631
+ const unit = workspaces.get(lockId);
2632
+ if (!unit) {
2633
+ throw _Ryoiki2.ERR_NOT_EXISTS(lockId);
2854
2634
  }
2855
- return node;
2635
+ workspaces.delete(lockId);
2636
+ unit.free();
2856
2637
  }
2857
- async *getPairsGenerator(value, startNode, endNode, comparator, direction, earlyTerminate) {
2858
- let node = startNode;
2859
- let done = false;
2860
- let hasMatched = false;
2861
- let nextNodePromise = null;
2862
- while (!done) {
2863
- if (endNode && node.id === endNode.id) {
2864
- done = true;
2865
- break;
2866
- }
2867
- if (direction === 1) {
2868
- if (node.next && !done) {
2869
- nextNodePromise = this.getNode(node.next);
2870
- }
2871
- } else {
2872
- if (node.prev && !done) {
2873
- nextNodePromise = this.getNode(node.prev);
2874
- }
2638
+ _lock(queue, range, timeout, task, condition) {
2639
+ return new Promise((resolve, reject) => {
2640
+ let timeoutId = null;
2641
+ if (timeout >= 0) {
2642
+ timeoutId = setTimeout(() => {
2643
+ reject(_Ryoiki2.ERR_TIMEOUT(id, timeout));
2644
+ }, timeout);
2875
2645
  }
2876
- const len = node.values.length;
2877
- if (direction === 1) {
2878
- for (let i = 0; i < len; i++) {
2879
- const nValue = node.values[i];
2880
- const keys = node.keys[i];
2881
- if (comparator(nValue, value)) {
2882
- hasMatched = true;
2883
- for (let j = 0; j < keys.length; j++) {
2884
- yield [keys[j], nValue];
2885
- }
2886
- } else if (earlyTerminate && hasMatched) {
2887
- done = true;
2888
- break;
2889
- }
2890
- }
2891
- } else {
2892
- let i = len;
2893
- while (i--) {
2894
- const nValue = node.values[i];
2895
- const keys = node.keys[i];
2896
- if (comparator(nValue, value)) {
2897
- hasMatched = true;
2898
- let j = keys.length;
2899
- while (j--) {
2900
- yield [keys[j], nValue];
2901
- }
2902
- } else if (earlyTerminate && hasMatched) {
2903
- done = true;
2904
- break;
2905
- }
2646
+ const id = this._createRandomId();
2647
+ const alloc = async () => {
2648
+ if (timeoutId !== null) {
2649
+ clearTimeout(timeoutId);
2906
2650
  }
2907
- }
2908
- if (done) {
2909
- if (nextNodePromise) await nextNodePromise;
2651
+ const [err, v] = await _Ryoiki2.CatchError(task(id));
2652
+ if (err) reject(err);
2653
+ else resolve(v);
2654
+ };
2655
+ const fetch = () => {
2656
+ this.fetchUnitAndRun(this.readQueue, this.readings);
2657
+ this.fetchUnitAndRun(this.writeQueue, this.writings);
2658
+ };
2659
+ queue.set(id, { id, range, condition, alloc, free: fetch });
2660
+ fetch();
2661
+ });
2662
+ }
2663
+ _checkWorking(range, workspaces) {
2664
+ let isLocked = false;
2665
+ for (const lock of workspaces.values()) {
2666
+ if (_Ryoiki2.IsRangeOverlap(range, lock.range)) {
2667
+ isLocked = true;
2910
2668
  break;
2911
2669
  }
2912
- if (nextNodePromise) {
2913
- node = await nextNodePromise;
2914
- nextNodePromise = null;
2915
- } else {
2916
- done = true;
2917
- }
2918
2670
  }
2671
+ return isLocked;
2919
2672
  }
2920
- async init() {
2921
- this.clear();
2922
- const head = await this._readHead();
2923
- if (head === null) {
2924
- this.order = this.strategy.order;
2925
- const root = await this._createNode(true, [], []);
2926
- await this._writeHead({
2927
- root: root.id,
2928
- order: this.order,
2929
- data: this.strategy.head.data
2930
- });
2931
- } else {
2932
- const { root, order } = head;
2933
- this.strategy.head = head;
2934
- this.order = order;
2673
+ /**
2674
+ * Checks if there is any active read lock within the specified range.
2675
+ * @param range The range to check for active read locks.
2676
+ * @returns `true` if there is an active read lock within the range, `false` otherwise.
2677
+ */
2678
+ isReading(range) {
2679
+ return this._checkWorking(range, this.readings);
2680
+ }
2681
+ /**
2682
+ * Checks if there is any active write lock within the specified range.
2683
+ * @param range The range to check for active write locks.
2684
+ * @returns `true` if there is an active write lock within the range, `false` otherwise.
2685
+ */
2686
+ isWriting(range) {
2687
+ return this._checkWorking(range, this.writings);
2688
+ }
2689
+ /**
2690
+ * Checks if a read lock can be acquired within the specified range.
2691
+ * @param range The range to check for read lock availability.
2692
+ * @returns `true` if a read lock can be acquired, `false` otherwise.
2693
+ */
2694
+ canRead(range) {
2695
+ const writing = this.isWriting(range);
2696
+ return !writing;
2697
+ }
2698
+ /**
2699
+ * Checks if a write lock can be acquired within the specified range.
2700
+ * @param range The range to check for write lock availability.
2701
+ * @returns `true` if a write lock can be acquired, `false` otherwise.
2702
+ */
2703
+ canWrite(range) {
2704
+ const reading = this.isReading(range);
2705
+ const writing = this.isWriting(range);
2706
+ return !reading && !writing;
2707
+ }
2708
+ /**
2709
+ * Internal implementation of the read lock. Handles both overloads.
2710
+ * @template T - The return type of the task.
2711
+ * @param arg0 - Either a range or a task callback.
2712
+ * If a range is provided, the task is the second argument.
2713
+ * @param arg1 - The task to execute, required if a range is provided.
2714
+ * @param arg2 - The timeout for acquiring the lock.
2715
+ * If the lock cannot be acquired within this period, an error will be thrown.
2716
+ * If this value is not provided, no timeout will be set.
2717
+ * @returns A promise resolving to the result of the task execution.
2718
+ */
2719
+ readLock(arg0, arg1, arg2) {
2720
+ const [range, task, timeout] = this._handleOverload(
2721
+ [arg0, arg1, arg2],
2722
+ {
2723
+ rangeTask: (range2, task2) => [range2, task2, -1],
2724
+ rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
2725
+ task: (task2) => [[-Infinity, Infinity], task2, -1],
2726
+ taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
2727
+ },
2728
+ {
2729
+ task: [Function],
2730
+ taskTimeout: [Function, Number],
2731
+ rangeTask: [Array, Function],
2732
+ rangeTaskTimeout: [Array, Function, Number]
2733
+ }
2734
+ );
2735
+ return this._lock(
2736
+ this.readQueue,
2737
+ range,
2738
+ timeout,
2739
+ task,
2740
+ () => !this.rangeOverlapping(this.writings, range)
2741
+ );
2742
+ }
2743
+ /**
2744
+ * Internal implementation of the write lock. Handles both overloads.
2745
+ * @template T - The return type of the task.
2746
+ * @param arg0 - Either a range or a task callback.
2747
+ * If a range is provided, the task is the second argument.
2748
+ * @param arg1 - The task to execute, required if a range is provided.
2749
+ * @param arg2 - The timeout for acquiring the lock.
2750
+ * If the lock cannot be acquired within this period, an error will be thrown.
2751
+ * If this value is not provided, no timeout will be set.
2752
+ * @returns A promise resolving to the result of the task execution.
2753
+ */
2754
+ writeLock(arg0, arg1, arg2) {
2755
+ const [range, task, timeout] = this._handleOverload(
2756
+ [arg0, arg1, arg2],
2757
+ {
2758
+ rangeTask: (range2, task2) => [range2, task2, -1],
2759
+ rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
2760
+ task: (task2) => [[-Infinity, Infinity], task2, -1],
2761
+ taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
2762
+ },
2763
+ {
2764
+ task: [Function],
2765
+ taskTimeout: [Function, Number],
2766
+ rangeTask: [Array, Function],
2767
+ rangeTaskTimeout: [Array, Function, Number]
2768
+ }
2769
+ );
2770
+ return this._lock(
2771
+ this.writeQueue,
2772
+ range,
2773
+ timeout,
2774
+ task,
2775
+ () => {
2776
+ return !this.rangeOverlapping(this.writings, range) && !this.rangeOverlapping(this.readings, range);
2777
+ }
2778
+ );
2779
+ }
2780
+ /**
2781
+ * Releases a read lock by its lock ID.
2782
+ * @param lockId - The unique identifier for the lock to release.
2783
+ */
2784
+ readUnlock(lockId) {
2785
+ this._free(this.readings, lockId);
2786
+ }
2787
+ /**
2788
+ * Releases a write lock by its lock ID.
2789
+ * @param lockId - The unique identifier for the lock to release.
2790
+ */
2791
+ writeUnlock(lockId) {
2792
+ this._free(this.writings, lockId);
2793
+ }
2794
+ };
2795
+
2796
+ // src/transaction/BPTreeAsyncTransaction.ts
2797
+ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
2798
+ lock;
2799
+ constructor(rootTx, mvccRoot, mvcc, strategy, comparator, option) {
2800
+ super(
2801
+ rootTx,
2802
+ mvccRoot,
2803
+ mvcc,
2804
+ strategy,
2805
+ comparator,
2806
+ option
2807
+ );
2808
+ this.lock = new Ryoiki2();
2809
+ }
2810
+ async writeLock(id, fn) {
2811
+ let lockId;
2812
+ return this.lock.writeLock([id, id + 0.1], async (_lockId) => {
2813
+ lockId = _lockId;
2814
+ return fn();
2815
+ }).finally(() => {
2816
+ this.lock.writeUnlock(lockId);
2817
+ });
2818
+ }
2819
+ async getNode(id) {
2820
+ return await this.mvcc.read(id);
2821
+ }
2822
+ /**
2823
+ * Create a new node with a unique ID.
2824
+ */
2825
+ async _createNode(leaf, keys, values, parent = null, next = null, prev = null) {
2826
+ const id = await this.strategy.id(leaf);
2827
+ const node = {
2828
+ id,
2829
+ keys,
2830
+ values,
2831
+ leaf,
2832
+ parent,
2833
+ next,
2834
+ prev
2835
+ };
2836
+ const head = await this._readHead();
2837
+ if (head) {
2935
2838
  await this._writeHead({
2936
- root,
2937
- order: this.order,
2839
+ root: head.root,
2840
+ order: head.order,
2938
2841
  data: this.strategy.head.data
2939
2842
  });
2940
2843
  }
2941
- if (this.order < 3) {
2942
- throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
2943
- }
2844
+ await this.mvcc.create(id, node);
2845
+ return node;
2944
2846
  }
2945
- async exists(key, value) {
2946
- const node = await this.insertableNode(value);
2947
- const { index, found } = this._binarySearchValues(node.values, value);
2948
- if (found) {
2949
- const keys = node.keys[index];
2950
- if (keys.includes(key)) {
2951
- return true;
2952
- }
2847
+ async _updateNode(node) {
2848
+ if (this.mvcc.isDeleted(node.id)) {
2849
+ return;
2953
2850
  }
2954
- return false;
2851
+ await this.mvcc.write(node.id, this._cloneNode(node));
2955
2852
  }
2956
- async forceUpdate(id) {
2957
- if (id) {
2958
- this.nodes.delete(id);
2959
- await this.getNode(id);
2960
- return 1;
2961
- }
2962
- const keys = Array.from(this.nodes.keys());
2963
- for (const key of keys) {
2964
- this.nodes.delete(key);
2853
+ async _deleteNode(node) {
2854
+ if (this.mvcc.isDeleted(node.id)) {
2855
+ return;
2965
2856
  }
2966
- for (const key of keys) {
2967
- await this.getNode(key);
2857
+ await this.mvcc.delete(node.id);
2858
+ }
2859
+ async _readHead() {
2860
+ return await this.mvcc.read("__HEAD__");
2861
+ }
2862
+ async _writeHead(head) {
2863
+ if (!await this.mvcc.exists("__HEAD__")) {
2864
+ await this.mvcc.create("__HEAD__", this._cloneNode(head));
2865
+ } else {
2866
+ await this.mvcc.write("__HEAD__", this._cloneNode(head));
2968
2867
  }
2969
- return keys.length;
2868
+ this.rootId = head.root;
2970
2869
  }
2971
- async get(key) {
2972
- let node = await this.leftestNode();
2973
- while (true) {
2974
- for (let i = 0, len = node.values.length; i < len; i++) {
2975
- const keys = node.keys[i];
2976
- for (let j = 0, kLen = keys.length; j < kLen; j++) {
2977
- if (keys[j] === key) {
2978
- return node.values[i];
2870
+ async _insertAtLeaf(node, key, value) {
2871
+ let leaf = node;
2872
+ leaf = this._cloneNode(leaf);
2873
+ if (leaf.values.length) {
2874
+ for (let i = 0, len = leaf.values.length; i < len; i++) {
2875
+ const nValue = leaf.values[i];
2876
+ if (this.comparator.isSame(value, nValue)) {
2877
+ const keys = leaf.keys[i];
2878
+ if (keys.includes(key)) {
2879
+ break;
2979
2880
  }
2881
+ keys.push(key);
2882
+ await this._updateNode(leaf);
2883
+ return leaf;
2884
+ } else if (this.comparator.isLower(value, nValue)) {
2885
+ leaf.values.splice(i, 0, value);
2886
+ leaf.keys.splice(i, 0, [key]);
2887
+ await this._updateNode(leaf);
2888
+ return leaf;
2889
+ } else if (i + 1 === leaf.values.length) {
2890
+ leaf.values.push(value);
2891
+ leaf.keys.push([key]);
2892
+ await this._updateNode(leaf);
2893
+ return leaf;
2980
2894
  }
2981
2895
  }
2982
- if (!node.next) break;
2983
- node = await this.getNode(node.next);
2896
+ } else {
2897
+ leaf.values = [value];
2898
+ leaf.keys = [[key]];
2899
+ await this._updateNode(leaf);
2900
+ return leaf;
2984
2901
  }
2985
- return void 0;
2902
+ return leaf;
2986
2903
  }
2987
- async *keysStream(condition, filterValues, limit, order = "asc") {
2988
- const stream = this.whereStream(condition, limit, order);
2989
- const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
2990
- for await (const [key] of stream) {
2991
- if (intersection && !intersection.has(key)) {
2992
- continue;
2904
+ async _insertInParent(node, value, pointer) {
2905
+ node = this._cloneNode(node);
2906
+ pointer = this._cloneNode(pointer);
2907
+ if (this.rootId === node.id) {
2908
+ const root = await this._createNode(false, [node.id, pointer.id], [value]);
2909
+ this.rootId = root.id;
2910
+ node.parent = root.id;
2911
+ pointer.parent = root.id;
2912
+ if (pointer.leaf) {
2913
+ node.next = pointer.id;
2914
+ pointer.prev = node.id;
2993
2915
  }
2994
- yield key;
2916
+ await this._writeHead({
2917
+ root: root.id,
2918
+ order: this.order,
2919
+ data: this.strategy.head.data
2920
+ });
2921
+ await this._updateNode(node);
2922
+ await this._updateNode(pointer);
2923
+ return;
2995
2924
  }
2996
- }
2997
- async *whereStream(condition, limit, order = "asc") {
2998
- const driverKey = this.getDriverKey(condition);
2999
- if (!driverKey) return;
3000
- const value = condition[driverKey];
3001
- let startNode = await this.verifierStartNode[driverKey](value);
3002
- let endNode = await this.verifierEndNode[driverKey](value);
3003
- let direction = this.verifierDirection[driverKey];
3004
- const comparator = this.verifierMap[driverKey];
3005
- const earlyTerminate = this.verifierEarlyTerminate[driverKey];
3006
- if (order === "desc") {
3007
- startNode = endNode ?? await this.rightestNode();
3008
- endNode = null;
3009
- direction *= -1;
2925
+ const parentNode = this._cloneNode(await this.getNode(node.parent));
2926
+ const nodeIndex = parentNode.keys.indexOf(node.id);
2927
+ if (nodeIndex === -1) {
2928
+ throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
3010
2929
  }
3011
- const generator = this.getPairsGenerator(
3012
- value,
3013
- startNode,
3014
- endNode,
3015
- comparator,
2930
+ parentNode.values.splice(nodeIndex, 0, value);
2931
+ parentNode.keys.splice(nodeIndex + 1, 0, pointer.id);
2932
+ pointer.parent = parentNode.id;
2933
+ if (pointer.leaf) {
2934
+ const leftSibling = node;
2935
+ const oldNextId = leftSibling.next;
2936
+ pointer.prev = leftSibling.id;
2937
+ pointer.next = oldNextId;
2938
+ leftSibling.next = pointer.id;
2939
+ await this._updateNode(leftSibling);
2940
+ if (oldNextId) {
2941
+ const oldNext = this._cloneNode(await this.getNode(oldNextId));
2942
+ oldNext.prev = pointer.id;
2943
+ await this._updateNode(oldNext);
2944
+ }
2945
+ }
2946
+ await this._updateNode(parentNode);
2947
+ await this._updateNode(pointer);
2948
+ if (parentNode.keys.length > this.order) {
2949
+ const parentPointer = await this._createNode(false, [], []);
2950
+ parentPointer.parent = parentNode.parent;
2951
+ const mid = Math.ceil(this.order / 2) - 1;
2952
+ parentPointer.values = parentNode.values.slice(mid + 1);
2953
+ parentPointer.keys = parentNode.keys.slice(mid + 1);
2954
+ const midValue = parentNode.values[mid];
2955
+ parentNode.values = parentNode.values.slice(0, mid);
2956
+ parentNode.keys = parentNode.keys.slice(0, mid + 1);
2957
+ for (const k of parentNode.keys) {
2958
+ const n = this._cloneNode(await this.getNode(k));
2959
+ n.parent = parentNode.id;
2960
+ await this._updateNode(n);
2961
+ }
2962
+ for (const k of parentPointer.keys) {
2963
+ const n = this._cloneNode(await this.getNode(k));
2964
+ n.parent = parentPointer.id;
2965
+ await this._updateNode(n);
2966
+ }
2967
+ await this._updateNode(parentNode);
2968
+ await this._insertInParent(parentNode, midValue, parentPointer);
2969
+ }
2970
+ }
2971
+ async insertableNode(value) {
2972
+ let node = await this.getNode(this.rootId);
2973
+ while (!node.leaf) {
2974
+ const { index } = this._binarySearchValues(node.values, value, false, true);
2975
+ node = await this.getNode(node.keys[index]);
2976
+ }
2977
+ return node;
2978
+ }
2979
+ async insertableNodeByPrimary(value) {
2980
+ let node = await this.getNode(this.rootId);
2981
+ while (!node.leaf) {
2982
+ const { index } = this._binarySearchValues(node.values, value, true, false);
2983
+ node = await this.getNode(node.keys[index]);
2984
+ }
2985
+ return node;
2986
+ }
2987
+ async insertableRightestNodeByPrimary(value) {
2988
+ let node = await this.getNode(this.rootId);
2989
+ while (!node.leaf) {
2990
+ const { index } = this._binarySearchValues(node.values, value, true, true);
2991
+ node = await this.getNode(node.keys[index]);
2992
+ }
2993
+ return node;
2994
+ }
2995
+ async insertableRightestEndNodeByPrimary(value) {
2996
+ const node = await this.insertableRightestNodeByPrimary(value);
2997
+ if (!node.next) {
2998
+ return null;
2999
+ }
3000
+ return await this.getNode(node.next);
3001
+ }
3002
+ async insertableEndNode(value, direction) {
3003
+ const insertableNode = await this.insertableNode(value);
3004
+ let key;
3005
+ switch (direction) {
3006
+ case -1:
3007
+ key = "prev";
3008
+ break;
3009
+ case 1:
3010
+ key = "next";
3011
+ break;
3012
+ default:
3013
+ throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
3014
+ }
3015
+ const guessNode = insertableNode[key];
3016
+ if (!guessNode) {
3017
+ return null;
3018
+ }
3019
+ return await this.getNode(guessNode);
3020
+ }
3021
+ async leftestNode() {
3022
+ let node = await this.getNode(this.rootId);
3023
+ if (node === null) {
3024
+ debugger;
3025
+ }
3026
+ while (!node.leaf) {
3027
+ const keys = node.keys;
3028
+ node = await this.getNode(keys[0]);
3029
+ }
3030
+ return node;
3031
+ }
3032
+ async rightestNode() {
3033
+ let node = await this.getNode(this.rootId);
3034
+ while (!node.leaf) {
3035
+ const keys = node.keys;
3036
+ node = await this.getNode(keys[keys.length - 1]);
3037
+ }
3038
+ return node;
3039
+ }
3040
+ async *getPairsGenerator(value, startNode, endNode, comparator, direction, earlyTerminate) {
3041
+ let node = startNode;
3042
+ let done = false;
3043
+ let hasMatched = false;
3044
+ let nextNodePromise = null;
3045
+ while (!done) {
3046
+ if (endNode && node.id === endNode.id) {
3047
+ done = true;
3048
+ break;
3049
+ }
3050
+ if (direction === 1) {
3051
+ if (node.next && !done) {
3052
+ nextNodePromise = this.getNode(node.next);
3053
+ }
3054
+ } else {
3055
+ if (node.prev && !done) {
3056
+ nextNodePromise = this.getNode(node.prev);
3057
+ }
3058
+ }
3059
+ const len = node.values.length;
3060
+ if (direction === 1) {
3061
+ for (let i = 0; i < len; i++) {
3062
+ const nValue = node.values[i];
3063
+ const keys = node.keys[i];
3064
+ if (comparator(nValue, value)) {
3065
+ hasMatched = true;
3066
+ for (let j = 0; j < keys.length; j++) {
3067
+ yield [keys[j], nValue];
3068
+ }
3069
+ } else if (earlyTerminate && hasMatched) {
3070
+ done = true;
3071
+ break;
3072
+ }
3073
+ }
3074
+ } else {
3075
+ let i = len;
3076
+ while (i--) {
3077
+ const nValue = node.values[i];
3078
+ const keys = node.keys[i];
3079
+ if (comparator(nValue, value)) {
3080
+ hasMatched = true;
3081
+ let j = keys.length;
3082
+ while (j--) {
3083
+ yield [keys[j], nValue];
3084
+ }
3085
+ } else if (earlyTerminate && hasMatched) {
3086
+ done = true;
3087
+ break;
3088
+ }
3089
+ }
3090
+ }
3091
+ if (done) {
3092
+ if (nextNodePromise) await nextNodePromise;
3093
+ break;
3094
+ }
3095
+ if (nextNodePromise) {
3096
+ node = await nextNodePromise;
3097
+ nextNodePromise = null;
3098
+ } else {
3099
+ done = true;
3100
+ }
3101
+ }
3102
+ }
3103
+ async init() {
3104
+ if (this.rootTx !== this) {
3105
+ throw new Error("Cannot call init on a nested transaction");
3106
+ }
3107
+ return await this._initInternal();
3108
+ }
3109
+ async _initInternal() {
3110
+ if (this.isInitialized) {
3111
+ throw new Error("Transaction already initialized");
3112
+ }
3113
+ if (this.isDestroyed) {
3114
+ throw new Error("Transaction already destroyed");
3115
+ }
3116
+ this.isInitialized = true;
3117
+ try {
3118
+ this._clearCache();
3119
+ const head = await this._readHead();
3120
+ if (head === null) {
3121
+ this.order = this.strategy.order;
3122
+ const root = await this._createNode(true, [], []);
3123
+ await this._writeHead({
3124
+ root: root.id,
3125
+ order: this.order,
3126
+ data: this.strategy.head.data
3127
+ });
3128
+ } else {
3129
+ const { root, order } = head;
3130
+ this.strategy.head = head;
3131
+ this.order = order;
3132
+ await this._writeHead({
3133
+ root,
3134
+ order: this.order,
3135
+ data: this.strategy.head.data
3136
+ });
3137
+ }
3138
+ if (this.order < 3) {
3139
+ throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
3140
+ }
3141
+ } catch (e) {
3142
+ this.isInitialized = false;
3143
+ throw e;
3144
+ }
3145
+ }
3146
+ async exists(key, value) {
3147
+ const node = await this.insertableNode(value);
3148
+ const { index, found } = this._binarySearchValues(node.values, value);
3149
+ if (found) {
3150
+ const keys = node.keys[index];
3151
+ if (keys.includes(key)) {
3152
+ return true;
3153
+ }
3154
+ }
3155
+ return false;
3156
+ }
3157
+ async get(key) {
3158
+ let node = await this.leftestNode();
3159
+ while (true) {
3160
+ for (let i = 0, len = node.values.length; i < len; i++) {
3161
+ const keys = node.keys[i];
3162
+ for (let j = 0, kLen = keys.length; j < kLen; j++) {
3163
+ if (keys[j] === key) {
3164
+ return node.values[i];
3165
+ }
3166
+ }
3167
+ }
3168
+ if (!node.next) break;
3169
+ node = await this.getNode(node.next);
3170
+ }
3171
+ return void 0;
3172
+ }
3173
+ async *keysStream(condition, filterValues, limit, order = "asc") {
3174
+ const stream = this.whereStream(condition, limit, order);
3175
+ const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
3176
+ for await (const [key] of stream) {
3177
+ if (intersection && !intersection.has(key)) {
3178
+ continue;
3179
+ }
3180
+ yield key;
3181
+ }
3182
+ }
3183
+ async *whereStream(condition, limit, order = "asc") {
3184
+ const driverKey = this.getDriverKey(condition);
3185
+ if (!driverKey) return;
3186
+ const value = condition[driverKey];
3187
+ let startNode = await this.verifierStartNode[driverKey](value);
3188
+ let endNode = await this.verifierEndNode[driverKey](value);
3189
+ let direction = this.verifierDirection[driverKey];
3190
+ const comparator = this.verifierMap[driverKey];
3191
+ const earlyTerminate = this.verifierEarlyTerminate[driverKey];
3192
+ if (order === "desc") {
3193
+ startNode = endNode ?? await this.rightestNode();
3194
+ endNode = null;
3195
+ direction *= -1;
3196
+ }
3197
+ const generator = this.getPairsGenerator(
3198
+ value,
3199
+ startNode,
3200
+ endNode,
3201
+ comparator,
3016
3202
  direction,
3017
3203
  earlyTerminate
3018
3204
  );
@@ -3053,26 +3239,32 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3053
3239
  return map;
3054
3240
  }
3055
3241
  async insert(key, value) {
3056
- const before = await this.insertableNode(value);
3057
- await this._insertAtLeaf(before, key, value);
3058
- if (before.values.length === this.order) {
3059
- const after = await this._createNode(
3060
- true,
3061
- [],
3062
- [],
3063
- before.parent,
3064
- null,
3065
- null
3066
- );
3067
- const mid = Math.ceil(this.order / 2) - 1;
3068
- after.values = before.values.slice(mid + 1);
3069
- after.keys = before.keys.slice(mid + 1);
3070
- before.values = before.values.slice(0, mid + 1);
3071
- before.keys = before.keys.slice(0, mid + 1);
3072
- await this._insertInParent(before, after.values[0], after);
3073
- }
3242
+ return this.writeLock(0, async () => {
3243
+ let before = await this.insertableNode(value);
3244
+ before = await this._insertAtLeaf(before, key, value);
3245
+ if (before.values.length === this.order) {
3246
+ let after = await this._createNode(
3247
+ true,
3248
+ [],
3249
+ [],
3250
+ before.parent,
3251
+ null,
3252
+ null
3253
+ );
3254
+ const mid = Math.ceil(this.order / 2) - 1;
3255
+ after = this._cloneNode(after);
3256
+ after.values = before.values.slice(mid + 1);
3257
+ after.keys = before.keys.slice(mid + 1);
3258
+ before.values = before.values.slice(0, mid + 1);
3259
+ before.keys = before.keys.slice(0, mid + 1);
3260
+ await this._updateNode(before);
3261
+ await this._updateNode(after);
3262
+ await this._insertInParent(before, after.values[0], after);
3263
+ }
3264
+ });
3074
3265
  }
3075
3266
  async _deleteEntry(node, key) {
3267
+ node = this._cloneNode(node);
3076
3268
  if (!node.leaf) {
3077
3269
  let keyIndex = -1;
3078
3270
  for (let i = 0, len = node.keys.length; i < len; i++) {
@@ -3091,7 +3283,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3091
3283
  if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
3092
3284
  const keys = node.keys;
3093
3285
  this._deleteNode(node);
3094
- const newRoot = await this.getNode(keys[0]);
3286
+ const newRoot = this._cloneNode(await this.getNode(keys[0]));
3095
3287
  newRoot.parent = null;
3096
3288
  await this._updateNode(newRoot);
3097
3289
  await this._writeHead({
@@ -3099,14 +3291,17 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3099
3291
  order: this.order,
3100
3292
  data: this.strategy.head.data
3101
3293
  });
3102
- return;
3294
+ return node;
3103
3295
  } else if (this.rootId === node.id) {
3104
- const root = await this.getNode(this.rootId);
3105
- await this._updateNode(root);
3106
- return;
3296
+ await this._writeHead({
3297
+ root: node.id,
3298
+ order: this.order,
3299
+ data: this.strategy.head.data
3300
+ });
3301
+ return node;
3107
3302
  } else if (node.keys.length < Math.ceil(this.order / 2) && !node.leaf || node.values.length < Math.ceil((this.order - 1) / 2) && node.leaf) {
3108
3303
  if (node.parent === null) {
3109
- return;
3304
+ return node;
3110
3305
  }
3111
3306
  let isPredecessor = false;
3112
3307
  let parentNode = await this.getNode(node.parent);
@@ -3118,11 +3313,11 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3118
3313
  const nKey = parentNode.keys[i];
3119
3314
  if (nKey === node.id) {
3120
3315
  if (i > 0) {
3121
- prevNode = await this.getNode(parentNode.keys[i - 1]);
3316
+ prevNode = this._cloneNode(await this.getNode(parentNode.keys[i - 1]));
3122
3317
  prevValue = parentNode.values[i - 1];
3123
3318
  }
3124
3319
  if (i < parentNode.keys.length - 1) {
3125
- nextNode = await this.getNode(parentNode.keys[i + 1]);
3320
+ nextNode = this._cloneNode(await this.getNode(parentNode.keys[i + 1]));
3126
3321
  postValue = parentNode.values[i];
3127
3322
  }
3128
3323
  }
@@ -3147,7 +3342,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3147
3342
  }
3148
3343
  }
3149
3344
  if (!pointer) {
3150
- return;
3345
+ return node;
3151
3346
  }
3152
3347
  if (node.values.length + pointer.values.length < this.order) {
3153
3348
  if (!isPredecessor) {
@@ -3161,7 +3356,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3161
3356
  } else {
3162
3357
  pointer.next = node.next;
3163
3358
  if (pointer.next) {
3164
- const n = await this.getNode(pointer.next);
3359
+ const n = this._cloneNode(await this.getNode(pointer.next));
3165
3360
  n.prev = pointer.id;
3166
3361
  await this._updateNode(n);
3167
3362
  }
@@ -3170,14 +3365,14 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3170
3365
  if (!pointer.leaf) {
3171
3366
  const keys = pointer.keys;
3172
3367
  for (const key2 of keys) {
3173
- const node2 = await this.getNode(key2);
3368
+ const node2 = this._cloneNode(await this.getNode(key2));
3174
3369
  node2.parent = pointer.id;
3175
3370
  await this._updateNode(node2);
3176
3371
  }
3177
3372
  }
3178
3373
  this._deleteNode(node);
3179
3374
  await this._updateNode(pointer);
3180
- await this._deleteEntry(await this.getNode(node.parent), node.id);
3375
+ await this._deleteEntry(this._cloneNode(await this.getNode(node.parent)), node.id);
3181
3376
  } else {
3182
3377
  if (isPredecessor) {
3183
3378
  let pointerPm;
@@ -3187,7 +3382,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3187
3382
  pointerKm = pointer.values.splice(-1)[0];
3188
3383
  node.keys = [pointerPm, ...node.keys];
3189
3384
  node.values = [guess, ...node.values];
3190
- parentNode = await this.getNode(node.parent);
3385
+ parentNode = this._cloneNode(await this.getNode(node.parent));
3191
3386
  const nodeIndex = parentNode.keys.indexOf(node.id);
3192
3387
  if (nodeIndex > 0) {
3193
3388
  parentNode.values[nodeIndex - 1] = pointerKm;
@@ -3198,7 +3393,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3198
3393
  pointerKm = pointer.values.splice(-1)[0];
3199
3394
  node.keys = [pointerPm, ...node.keys];
3200
3395
  node.values = [pointerKm, ...node.values];
3201
- parentNode = await this.getNode(node.parent);
3396
+ parentNode = this._cloneNode(await this.getNode(node.parent));
3202
3397
  const nodeIndex = parentNode.keys.indexOf(node.id);
3203
3398
  if (nodeIndex > 0) {
3204
3399
  parentNode.values[nodeIndex - 1] = pointerKm;
@@ -3215,7 +3410,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3215
3410
  pointerK0 = pointer.values.splice(0, 1)[0];
3216
3411
  node.keys = [...node.keys, pointerP0];
3217
3412
  node.values = [...node.values, guess];
3218
- parentNode = await this.getNode(node.parent);
3413
+ parentNode = this._cloneNode(await this.getNode(node.parent));
3219
3414
  const pointerIndex = parentNode.keys.indexOf(pointer.id);
3220
3415
  if (pointerIndex > 0) {
3221
3416
  parentNode.values[pointerIndex - 1] = pointerK0;
@@ -3226,7 +3421,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3226
3421
  pointerK0 = pointer.values.splice(0, 1)[0];
3227
3422
  node.keys = [...node.keys, pointerP0];
3228
3423
  node.values = [...node.values, pointerK0];
3229
- parentNode = await this.getNode(node.parent);
3424
+ parentNode = this._cloneNode(await this.getNode(node.parent));
3230
3425
  const pointerIndex = parentNode.keys.indexOf(pointer.id);
3231
3426
  if (pointerIndex > 0) {
3232
3427
  parentNode.values[pointerIndex - 1] = pointer.values[0];
@@ -3238,21 +3433,21 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3238
3433
  }
3239
3434
  if (!pointer.leaf) {
3240
3435
  for (const key2 of pointer.keys) {
3241
- const n = await this.getNode(key2);
3436
+ const n = this._cloneNode(await this.getNode(key2));
3242
3437
  n.parent = pointer.id;
3243
3438
  await this._updateNode(n);
3244
3439
  }
3245
3440
  }
3246
3441
  if (!node.leaf) {
3247
3442
  for (const key2 of node.keys) {
3248
- const n = await this.getNode(key2);
3443
+ const n = this._cloneNode(await this.getNode(key2));
3249
3444
  n.parent = node.id;
3250
3445
  await this._updateNode(n);
3251
3446
  }
3252
3447
  }
3253
3448
  if (!parentNode.leaf) {
3254
3449
  for (const key2 of parentNode.keys) {
3255
- const n = await this.getNode(key2);
3450
+ const n = this._cloneNode(await this.getNode(key2));
3256
3451
  n.parent = parentNode.id;
3257
3452
  await this._updateNode(n);
3258
3453
  }
@@ -3261,37 +3456,42 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3261
3456
  } else {
3262
3457
  await this._updateNode(node);
3263
3458
  }
3459
+ await this._updateNode(node);
3460
+ return node;
3264
3461
  }
3265
3462
  async delete(key, value) {
3266
- let node = await this.insertableNodeByPrimary(value);
3267
- let found = false;
3268
- while (true) {
3269
- let i = node.values.length;
3270
- while (i--) {
3271
- const nValue = node.values[i];
3272
- if (this.comparator.isSame(value, nValue)) {
3273
- const keys = node.keys[i];
3274
- const keyIndex = keys.indexOf(key);
3275
- if (keyIndex !== -1) {
3276
- keys.splice(keyIndex, 1);
3277
- if (keys.length === 0) {
3278
- node.keys.splice(i, 1);
3279
- node.values.splice(i, 1);
3463
+ return this.writeLock(0, async () => {
3464
+ let node = await this.insertableNodeByPrimary(value);
3465
+ let found = false;
3466
+ node = this._cloneNode(node);
3467
+ while (true) {
3468
+ let i = node.values.length;
3469
+ while (i--) {
3470
+ const nValue = node.values[i];
3471
+ if (this.comparator.isSame(value, nValue)) {
3472
+ const keys = node.keys[i];
3473
+ const keyIndex = keys.indexOf(key);
3474
+ if (keyIndex !== -1) {
3475
+ keys.splice(keyIndex, 1);
3476
+ if (keys.length === 0) {
3477
+ node.keys.splice(i, 1);
3478
+ node.values.splice(i, 1);
3479
+ }
3480
+ await this._updateNode(node);
3481
+ node = await this._deleteEntry(node, key);
3482
+ found = true;
3483
+ break;
3280
3484
  }
3281
- await this._updateNode(node);
3282
- await this._deleteEntry(node, key);
3283
- found = true;
3284
- break;
3285
3485
  }
3286
3486
  }
3487
+ if (found) break;
3488
+ if (node.next) {
3489
+ node = await this.getNode(node.next);
3490
+ continue;
3491
+ }
3492
+ break;
3287
3493
  }
3288
- if (found) break;
3289
- if (node.next) {
3290
- node = await this.getNode(node.next);
3291
- continue;
3292
- }
3293
- break;
3294
- }
3494
+ });
3295
3495
  }
3296
3496
  async getHeadData() {
3297
3497
  const head = await this._readHead();
@@ -3302,447 +3502,185 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3302
3502
  }
3303
3503
  async setHeadData(data) {
3304
3504
  const head = await this._readHead();
3305
- if (head === null) {
3306
- throw new Error("Head not found");
3307
- }
3308
- await this._writeHead({
3309
- root: head.root,
3310
- order: head.order,
3311
- data
3312
- });
3313
- }
3314
- async commit(label) {
3315
- let result = await this.mvcc.commit(label);
3316
- if (result.success) {
3317
- result = await this.mvccRoot.commit(label);
3318
- if (result.success && this.rootTx !== this) {
3319
- this.rootTx.rootId = this.rootId;
3320
- }
3321
- if (result.success) {
3322
- for (const r of result.created) {
3323
- this.nodes.set(r.key, r.data);
3324
- }
3325
- for (const r of result.updated) {
3326
- this.nodes.set(r.key, r.data);
3327
- }
3328
- for (const r of result.deleted) {
3329
- this.nodes.delete(r.key);
3330
- }
3331
- }
3332
- }
3333
- return result;
3334
- }
3335
- rollback() {
3336
- return this.mvcc.rollback();
3337
- }
3338
- };
3339
-
3340
- // src/transaction/BPTreeMVCCStrategyAsync.ts
3341
- var BPTreeMVCCStrategyAsync = class extends AsyncMVCCStrategy {
3342
- constructor(strategy) {
3343
- super();
3344
- this.strategy = strategy;
3345
- }
3346
- async read(key) {
3347
- if (key === "__HEAD__") {
3348
- return await this.strategy.readHead();
3349
- }
3350
- return await this.strategy.read(key);
3351
- }
3352
- async write(key, value) {
3353
- if (key === "__HEAD__") {
3354
- await this.strategy.writeHead(value);
3355
- } else {
3356
- await this.strategy.write(key, value);
3357
- }
3358
- }
3359
- async delete(key) {
3360
- await this.strategy.delete(key);
3361
- }
3362
- async exists(key) {
3363
- if (key === "__HEAD__") {
3364
- return await this.strategy.readHead() !== null;
3365
- }
3366
- try {
3367
- const node = await this.strategy.read(key);
3368
- return node !== null && node !== void 0;
3369
- } catch {
3370
- return false;
3371
- }
3372
- }
3373
- };
3374
-
3375
- // src/BPTreeAsync.ts
3376
- var BPTreeAsync = class extends BPTreeAsyncTransaction {
3377
- constructor(strategy, comparator, option) {
3378
- const mvccRoot = new AsyncMVCCTransaction(new BPTreeMVCCStrategyAsync(strategy));
3379
- super(
3380
- null,
3381
- mvccRoot,
3382
- mvccRoot,
3383
- strategy,
3384
- comparator,
3385
- option
3386
- );
3387
- }
3388
- /**
3389
- * Creates a new asynchronous transaction.
3390
- * @returns A new BPTreeAsyncTransaction.
3391
- */
3392
- async createTransaction() {
3393
- const nestedTx = await this.mvcc.createNested();
3394
- const tx = new BPTreeAsyncTransaction(
3395
- this,
3396
- this.mvcc,
3397
- nestedTx,
3398
- this.strategy,
3399
- this.comparator,
3400
- this.option
3401
- );
3402
- await tx.init();
3403
- return tx;
3404
- }
3405
- async insert(key, value) {
3406
- const tx = await this.createTransaction();
3407
- await tx.insert(key, value);
3408
- const result = await tx.commit();
3409
- if (!result.success) {
3410
- throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
3411
- }
3412
- this.rootId = tx.getRootId();
3413
- }
3414
- async delete(key, value) {
3415
- const tx = await this.createTransaction();
3416
- await tx.delete(key, value);
3417
- const result = await tx.commit();
3418
- if (!result.success) {
3419
- throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
3420
- }
3421
- this.rootId = tx.getRootId();
3422
- }
3423
- };
3424
-
3425
- // src/base/SerializeStrategy.ts
3426
- var SerializeStrategy = class {
3427
- order;
3428
- head;
3429
- constructor(order) {
3430
- this.order = order;
3431
- this.head = {
3432
- order,
3433
- root: null,
3434
- data: {}
3435
- };
3436
- }
3437
- };
3438
-
3439
- // src/SerializeStrategySync.ts
3440
- var SerializeStrategySync = class extends SerializeStrategy {
3441
- getHeadData(key, defaultValue) {
3442
- if (!Object.hasOwn(this.head.data, key)) {
3443
- this.setHeadData(key, defaultValue);
3444
- }
3445
- return this.head.data[key];
3446
- }
3447
- setHeadData(key, data) {
3448
- this.head.data[key] = data;
3449
- this.writeHead(this.head);
3450
- }
3451
- autoIncrement(key, defaultValue) {
3452
- const current = this.getHeadData(key, defaultValue);
3453
- const next = current + 1;
3454
- this.setHeadData(key, next);
3455
- return current;
3456
- }
3457
- };
3458
- var InMemoryStoreStrategySync = class extends SerializeStrategySync {
3459
- node;
3460
- constructor(order) {
3461
- super(order);
3462
- this.node = {};
3463
- }
3464
- id(isLeaf) {
3465
- return this.autoIncrement("index", 1).toString();
3466
- }
3467
- read(id) {
3468
- if (!Object.hasOwn(this.node, id)) {
3469
- throw new Error(`The tree attempted to reference node '${id}', but couldn't find the corresponding node.`);
3470
- }
3471
- const node = this.node[id];
3472
- return JSON.parse(JSON.stringify(node));
3473
- }
3474
- write(id, node) {
3475
- this.node[id] = node;
3476
- }
3477
- delete(id) {
3478
- delete this.node[id];
3479
- }
3480
- readHead() {
3481
- if (this.head.root === null) {
3482
- return null;
3483
- }
3484
- return this.head;
3485
- }
3486
- writeHead(head) {
3487
- this.head = head;
3488
- }
3489
- };
3490
-
3491
- // node_modules/ryoiki/dist/esm/index.mjs
3492
- var Ryoiki2 = class _Ryoiki2 {
3493
- readings;
3494
- writings;
3495
- readQueue;
3496
- writeQueue;
3497
- static async CatchError(promise) {
3498
- return await promise.then((v) => [void 0, v]).catch((err) => [err]);
3499
- }
3500
- static IsRangeOverlap(a, b) {
3501
- const [start1, end1] = a;
3502
- const [start2, end2] = b;
3503
- if (end1 <= start2 || end2 <= start1) {
3504
- return false;
3505
- }
3506
- return true;
3507
- }
3508
- static ERR_ALREADY_EXISTS(lockId) {
3509
- return new Error(`The '${lockId}' task already existing in queue or running.`);
3510
- }
3511
- static ERR_NOT_EXISTS(lockId) {
3512
- return new Error(`The '${lockId}' task not existing in task queue.`);
3513
- }
3514
- static ERR_TIMEOUT(lockId, timeout) {
3515
- return new Error(`The task with ID '${lockId}' failed to acquire the lock within the timeout(${timeout}ms).`);
3516
- }
3517
- /**
3518
- * Constructs a new instance of the Ryoiki class.
3519
- */
3520
- constructor() {
3521
- this.readings = /* @__PURE__ */ new Map();
3522
- this.writings = /* @__PURE__ */ new Map();
3523
- this.readQueue = /* @__PURE__ */ new Map();
3524
- this.writeQueue = /* @__PURE__ */ new Map();
3525
- }
3526
- /**
3527
- * Creates a range based on a start value and length.
3528
- * @param start - The starting value of the range.
3529
- * @param length - The length of the range.
3530
- * @returns A range tuple [start, start + length].
3531
- */
3532
- range(start, length) {
3533
- return [start, start + length];
3534
- }
3535
- rangeOverlapping(tasks, range) {
3536
- return Array.from(tasks.values()).some((t) => _Ryoiki2.IsRangeOverlap(t.range, range));
3537
- }
3538
- isSameRange(a, b) {
3539
- const [a1, a2] = a;
3540
- const [b1, b2] = b;
3541
- return a1 === b1 && a2 === b2;
3542
- }
3543
- fetchUnitAndRun(queue, workspaces) {
3544
- for (const [id, unit] of queue) {
3545
- if (!unit.condition()) {
3546
- continue;
3547
- }
3548
- this._alloc(queue, workspaces, id);
3549
- }
3550
- }
3551
- _handleOverload(args, handlers, argPatterns) {
3552
- for (const [key, pattern] of Object.entries(argPatterns)) {
3553
- if (this._matchArgs(args, pattern)) {
3554
- return handlers[key](...args);
3555
- }
3556
- }
3557
- throw new Error("Invalid arguments");
3558
- }
3559
- _matchArgs(args, pattern) {
3560
- return args.every((arg, index) => {
3561
- const expectedType = pattern[index];
3562
- if (expectedType === void 0) return typeof arg === "undefined";
3563
- if (expectedType === Function) return typeof arg === "function";
3564
- if (expectedType === Number) return typeof arg === "number";
3565
- if (expectedType === Array) return Array.isArray(arg);
3566
- return false;
3567
- });
3568
- }
3569
- _createRandomId() {
3570
- const timestamp = Date.now().toString(36);
3571
- const random = Math.random().toString(36).substring(2);
3572
- return `${timestamp}${random}`;
3573
- }
3574
- _alloc(queue, workspaces, lockId) {
3575
- const unit = queue.get(lockId);
3576
- if (!unit) {
3577
- throw _Ryoiki2.ERR_NOT_EXISTS(lockId);
3578
- }
3579
- workspaces.set(lockId, unit);
3580
- queue.delete(lockId);
3581
- unit.alloc();
3582
- }
3583
- _free(workspaces, lockId) {
3584
- const unit = workspaces.get(lockId);
3585
- if (!unit) {
3586
- throw _Ryoiki2.ERR_NOT_EXISTS(lockId);
3587
- }
3588
- workspaces.delete(lockId);
3589
- unit.free();
3590
- }
3591
- _lock(queue, range, timeout, task, condition) {
3592
- return new Promise((resolve, reject) => {
3593
- let timeoutId = null;
3594
- if (timeout >= 0) {
3595
- timeoutId = setTimeout(() => {
3596
- reject(_Ryoiki2.ERR_TIMEOUT(id, timeout));
3597
- }, timeout);
3598
- }
3599
- const id = this._createRandomId();
3600
- const alloc = async () => {
3601
- if (timeoutId !== null) {
3602
- clearTimeout(timeoutId);
3603
- }
3604
- const [err, v] = await _Ryoiki2.CatchError(task(id));
3605
- if (err) reject(err);
3606
- else resolve(v);
3607
- };
3608
- const fetch = () => {
3609
- this.fetchUnitAndRun(this.readQueue, this.readings);
3610
- this.fetchUnitAndRun(this.writeQueue, this.writings);
3611
- };
3612
- queue.set(id, { id, range, condition, alloc, free: fetch });
3613
- fetch();
3505
+ if (head === null) {
3506
+ throw new Error("Head not found");
3507
+ }
3508
+ await this._writeHead({
3509
+ root: head.root,
3510
+ order: head.order,
3511
+ data
3614
3512
  });
3615
3513
  }
3616
- _checkWorking(range, workspaces) {
3617
- let isLocked = false;
3618
- for (const lock of workspaces.values()) {
3619
- if (_Ryoiki2.IsRangeOverlap(range, lock.range)) {
3620
- isLocked = true;
3621
- break;
3514
+ async commit(label) {
3515
+ let result = await this.mvcc.commit(label);
3516
+ if (result.success) {
3517
+ const isRootTx = this.rootTx === this;
3518
+ if (!isRootTx) {
3519
+ result = await this.rootTx.commit(label);
3520
+ if (result.success) {
3521
+ this.rootTx.rootId = this.rootId;
3522
+ }
3622
3523
  }
3623
3524
  }
3624
- return isLocked;
3525
+ return result;
3625
3526
  }
3626
- /**
3627
- * Checks if there is any active read lock within the specified range.
3628
- * @param range The range to check for active read locks.
3629
- * @returns `true` if there is an active read lock within the range, `false` otherwise.
3630
- */
3631
- isReading(range) {
3632
- return this._checkWorking(range, this.readings);
3527
+ async rollback() {
3528
+ return this.mvcc.rollback();
3633
3529
  }
3634
- /**
3635
- * Checks if there is any active write lock within the specified range.
3636
- * @param range The range to check for active write locks.
3637
- * @returns `true` if there is an active write lock within the range, `false` otherwise.
3638
- */
3639
- isWriting(range) {
3640
- return this._checkWorking(range, this.writings);
3530
+ };
3531
+
3532
+ // src/transaction/BPTreeMVCCStrategyAsync.ts
3533
+ var BPTreeMVCCStrategyAsync = class extends AsyncMVCCStrategy {
3534
+ constructor(strategy) {
3535
+ super();
3536
+ this.strategy = strategy;
3641
3537
  }
3642
- /**
3643
- * Checks if a read lock can be acquired within the specified range.
3644
- * @param range The range to check for read lock availability.
3645
- * @returns `true` if a read lock can be acquired, `false` otherwise.
3646
- */
3647
- canRead(range) {
3648
- const writing = this.isWriting(range);
3649
- return !writing;
3538
+ async read(key) {
3539
+ if (key === "__HEAD__") {
3540
+ return await this.strategy.readHead();
3541
+ }
3542
+ return await this.strategy.read(key);
3650
3543
  }
3651
- /**
3652
- * Checks if a write lock can be acquired within the specified range.
3653
- * @param range The range to check for write lock availability.
3654
- * @returns `true` if a write lock can be acquired, `false` otherwise.
3655
- */
3656
- canWrite(range) {
3657
- const reading = this.isReading(range);
3658
- const writing = this.isWriting(range);
3659
- return !reading && !writing;
3544
+ async write(key, value) {
3545
+ if (key === "__HEAD__") {
3546
+ await this.strategy.writeHead(value);
3547
+ } else {
3548
+ await this.strategy.write(key, value);
3549
+ }
3660
3550
  }
3661
- /**
3662
- * Internal implementation of the read lock. Handles both overloads.
3663
- * @template T - The return type of the task.
3664
- * @param arg0 - Either a range or a task callback.
3665
- * If a range is provided, the task is the second argument.
3666
- * @param arg1 - The task to execute, required if a range is provided.
3667
- * @param arg2 - The timeout for acquiring the lock.
3668
- * If the lock cannot be acquired within this period, an error will be thrown.
3669
- * If this value is not provided, no timeout will be set.
3670
- * @returns A promise resolving to the result of the task execution.
3671
- */
3672
- readLock(arg0, arg1, arg2) {
3673
- const [range, task, timeout] = this._handleOverload(
3674
- [arg0, arg1, arg2],
3675
- {
3676
- rangeTask: (range2, task2) => [range2, task2, -1],
3677
- rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
3678
- task: (task2) => [[-Infinity, Infinity], task2, -1],
3679
- taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
3680
- },
3681
- {
3682
- task: [Function],
3683
- taskTimeout: [Function, Number],
3684
- rangeTask: [Array, Function],
3685
- rangeTaskTimeout: [Array, Function, Number]
3686
- }
3687
- );
3688
- return this._lock(
3689
- this.readQueue,
3690
- range,
3691
- timeout,
3692
- task,
3693
- () => !this.rangeOverlapping(this.writings, range)
3551
+ async delete(key) {
3552
+ await this.strategy.delete(key);
3553
+ }
3554
+ async exists(key) {
3555
+ if (key === "__HEAD__") {
3556
+ return await this.strategy.readHead() !== null;
3557
+ }
3558
+ try {
3559
+ const node = await this.strategy.read(key);
3560
+ return node !== null && node !== void 0;
3561
+ } catch {
3562
+ return false;
3563
+ }
3564
+ }
3565
+ };
3566
+
3567
+ // src/BPTreeAsync.ts
3568
+ var BPTreeAsync = class extends BPTreeAsyncTransaction {
3569
+ constructor(strategy, comparator, option) {
3570
+ const mvccRoot = new AsyncMVCCTransaction(new BPTreeMVCCStrategyAsync(strategy), {
3571
+ cacheCapacity: option?.capacity ?? void 0
3572
+ });
3573
+ super(
3574
+ null,
3575
+ mvccRoot,
3576
+ mvccRoot,
3577
+ strategy,
3578
+ comparator,
3579
+ option
3694
3580
  );
3695
3581
  }
3696
3582
  /**
3697
- * Internal implementation of the write lock. Handles both overloads.
3698
- * @template T - The return type of the task.
3699
- * @param arg0 - Either a range or a task callback.
3700
- * If a range is provided, the task is the second argument.
3701
- * @param arg1 - The task to execute, required if a range is provided.
3702
- * @param arg2 - The timeout for acquiring the lock.
3703
- * If the lock cannot be acquired within this period, an error will be thrown.
3704
- * If this value is not provided, no timeout will be set.
3705
- * @returns A promise resolving to the result of the task execution.
3583
+ * Creates a new asynchronous transaction.
3584
+ * @returns A new BPTreeAsyncTransaction.
3706
3585
  */
3707
- writeLock(arg0, arg1, arg2) {
3708
- const [range, task, timeout] = this._handleOverload(
3709
- [arg0, arg1, arg2],
3710
- {
3711
- rangeTask: (range2, task2) => [range2, task2, -1],
3712
- rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
3713
- task: (task2) => [[-Infinity, Infinity], task2, -1],
3714
- taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
3715
- },
3716
- {
3717
- task: [Function],
3718
- taskTimeout: [Function, Number],
3719
- rangeTask: [Array, Function],
3720
- rangeTaskTimeout: [Array, Function, Number]
3721
- }
3586
+ async createTransaction() {
3587
+ const nestedTx = this.mvcc.createNested();
3588
+ const tx = new BPTreeAsyncTransaction(
3589
+ this,
3590
+ this.mvcc,
3591
+ nestedTx,
3592
+ this.strategy,
3593
+ this.comparator,
3594
+ this.option
3722
3595
  );
3723
- return this._lock(
3724
- this.writeQueue,
3725
- range,
3726
- timeout,
3727
- task,
3728
- () => {
3729
- return !this.rangeOverlapping(this.writings, range) && !this.rangeOverlapping(this.readings, range);
3596
+ await tx._initInternal();
3597
+ return tx;
3598
+ }
3599
+ async insert(key, value) {
3600
+ return this.writeLock(1, async () => {
3601
+ const tx = await this.createTransaction();
3602
+ await tx.insert(key, value);
3603
+ const result = await tx.commit();
3604
+ if (!result.success) {
3605
+ throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
3730
3606
  }
3731
- );
3607
+ });
3732
3608
  }
3733
- /**
3734
- * Releases a read lock by its lock ID.
3735
- * @param lockId - The unique identifier for the lock to release.
3736
- */
3737
- readUnlock(lockId) {
3738
- this._free(this.readings, lockId);
3609
+ async delete(key, value) {
3610
+ return this.writeLock(1, async () => {
3611
+ const tx = await this.createTransaction();
3612
+ await tx.delete(key, value);
3613
+ const result = await tx.commit();
3614
+ if (!result.success) {
3615
+ throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
3616
+ }
3617
+ });
3739
3618
  }
3740
- /**
3741
- * Releases a write lock by its lock ID.
3742
- * @param lockId - The unique identifier for the lock to release.
3743
- */
3744
- writeUnlock(lockId) {
3745
- this._free(this.writings, lockId);
3619
+ };
3620
+
3621
+ // src/base/SerializeStrategy.ts
3622
+ var SerializeStrategy = class {
3623
+ order;
3624
+ head;
3625
+ constructor(order) {
3626
+ this.order = order;
3627
+ this.head = {
3628
+ order,
3629
+ root: null,
3630
+ data: {}
3631
+ };
3632
+ }
3633
+ };
3634
+
3635
+ // src/SerializeStrategySync.ts
3636
+ var SerializeStrategySync = class extends SerializeStrategy {
3637
+ getHeadData(key, defaultValue) {
3638
+ if (!Object.hasOwn(this.head.data, key)) {
3639
+ this.setHeadData(key, defaultValue);
3640
+ }
3641
+ return this.head.data[key];
3642
+ }
3643
+ setHeadData(key, data) {
3644
+ this.head.data[key] = data;
3645
+ this.writeHead(this.head);
3646
+ }
3647
+ autoIncrement(key, defaultValue) {
3648
+ const current = this.getHeadData(key, defaultValue);
3649
+ const next = current + 1;
3650
+ this.setHeadData(key, next);
3651
+ return current;
3652
+ }
3653
+ };
3654
+ var InMemoryStoreStrategySync = class extends SerializeStrategySync {
3655
+ node;
3656
+ constructor(order) {
3657
+ super(order);
3658
+ this.node = {};
3659
+ }
3660
+ id(isLeaf) {
3661
+ return this.autoIncrement("index", 1).toString();
3662
+ }
3663
+ read(id) {
3664
+ if (!Object.hasOwn(this.node, id)) {
3665
+ throw new Error(`The tree attempted to reference node '${id}', but couldn't find the corresponding node.`);
3666
+ }
3667
+ const node = this.node[id];
3668
+ return JSON.parse(JSON.stringify(node));
3669
+ }
3670
+ write(id, node) {
3671
+ this.node[id] = node;
3672
+ }
3673
+ delete(id) {
3674
+ delete this.node[id];
3675
+ }
3676
+ readHead() {
3677
+ if (this.head.root === null) {
3678
+ return null;
3679
+ }
3680
+ return this.head;
3681
+ }
3682
+ writeHead(head) {
3683
+ this.head = head;
3746
3684
  }
3747
3685
  };
3748
3686