serializable-bptree 8.1.2 → 8.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -69,6 +69,7 @@ var MVCCTransaction = class {
69
69
  // delete 시 삭제 전 값 저장
70
70
  originallyExisted;
71
71
  // 트랜잭션 시작 시점에 디스크에 존재했던 키 (deleted 결과 필터링용)
72
+ bufferHistory = /* @__PURE__ */ new Map();
72
73
  // Nested Transaction Properties
73
74
  parent;
74
75
  localVersion;
@@ -123,26 +124,45 @@ var MVCCTransaction = class {
123
124
  return false;
124
125
  }
125
126
  // --- Internal buffer manipulation helpers ---
126
- _bufferCreate(key, value) {
127
- this.localVersion++;
127
+ _recordHistory(key) {
128
+ const existsInWriteBuffer = this.writeBuffer.has(key);
129
+ const existsInDeleteBuffer = this.deleteBuffer.has(key);
130
+ const currentVer = this.keyVersions.get(key);
131
+ if (currentVer !== void 0) {
132
+ if (!this.bufferHistory.has(key)) this.bufferHistory.set(key, []);
133
+ this.bufferHistory.get(key).push({
134
+ value: existsInWriteBuffer ? this.writeBuffer.get(key) : this.deletedValues.get(key) ?? null,
135
+ exists: existsInWriteBuffer || !existsInDeleteBuffer,
136
+ version: currentVer
137
+ });
138
+ }
139
+ }
140
+ _bufferCreate(key, value, version) {
141
+ if (version === void 0) this.localVersion++;
142
+ const targetVersion = version ?? this.localVersion;
143
+ this._recordHistory(key);
128
144
  this.writeBuffer.set(key, value);
129
145
  this.createdKeys.add(key);
130
146
  this.deleteBuffer.delete(key);
131
147
  this.originallyExisted.delete(key);
132
- this.keyVersions.set(key, this.localVersion);
148
+ this.keyVersions.set(key, targetVersion);
133
149
  }
134
- _bufferWrite(key, value) {
135
- this.localVersion++;
150
+ _bufferWrite(key, value, version) {
151
+ if (version === void 0) this.localVersion++;
152
+ const targetVersion = version ?? this.localVersion;
153
+ this._recordHistory(key);
136
154
  this.writeBuffer.set(key, value);
137
155
  this.deleteBuffer.delete(key);
138
- this.keyVersions.set(key, this.localVersion);
156
+ this.keyVersions.set(key, targetVersion);
139
157
  }
140
- _bufferDelete(key) {
141
- this.localVersion++;
158
+ _bufferDelete(key, version) {
159
+ if (version === void 0) this.localVersion++;
160
+ const targetVersion = version ?? this.localVersion;
161
+ this._recordHistory(key);
142
162
  this.deleteBuffer.add(key);
143
163
  this.writeBuffer.delete(key);
144
164
  this.createdKeys.delete(key);
145
- this.keyVersions.set(key, this.localVersion);
165
+ this.keyVersions.set(key, targetVersion);
146
166
  }
147
167
  /**
148
168
  * Returns the entries that will be created, updated, and deleted by this transaction.
@@ -219,7 +239,9 @@ var MVCCTransaction = class {
219
239
  break;
220
240
  }
221
241
  }
222
- if (latestInSnapshotIdx > 0) {
242
+ if (latestInSnapshotIdx === versions.length - 1) {
243
+ this.versionIndex.delete(key);
244
+ } else if (latestInSnapshotIdx > 0) {
223
245
  versions.splice(0, latestInSnapshotIdx);
224
246
  }
225
247
  }
@@ -276,27 +298,68 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
276
298
  if (this.committed) throw new Error("Transaction already committed");
277
299
  if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
278
300
  if (this.deleteBuffer.has(key)) return null;
279
- return this.root._diskRead(key, this.snapshotVersion);
301
+ if (this.parent) {
302
+ return this.parent._readSnapshot(key, this.snapshotVersion, this.snapshotLocalVersion);
303
+ }
304
+ return this._diskRead(key, this.snapshotVersion);
280
305
  }
281
306
  exists(key) {
282
307
  if (this.committed) throw new Error("Transaction already committed");
283
308
  if (this.deleteBuffer.has(key)) return false;
284
309
  if (this.writeBuffer.has(key)) return true;
285
- return this.root._diskExists(key, this.snapshotVersion);
310
+ if (this.parent) {
311
+ return this.parent._existsSnapshot(key, this.snapshotVersion, this.snapshotLocalVersion);
312
+ }
313
+ return this._diskExists(key, this.snapshotVersion);
314
+ }
315
+ _existsSnapshot(key, snapshotVersion, snapshotLocalVersion) {
316
+ if (this.writeBuffer.has(key)) {
317
+ const keyModVersion = this.keyVersions.get(key);
318
+ if (snapshotLocalVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
319
+ return true;
320
+ }
321
+ }
322
+ if (this.deleteBuffer.has(key)) {
323
+ const keyModVersion = this.keyVersions.get(key);
324
+ if (snapshotLocalVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
325
+ return false;
326
+ }
327
+ }
328
+ const history = this.bufferHistory.get(key);
329
+ if (history && snapshotLocalVersion !== void 0) {
330
+ for (let i = history.length - 1; i >= 0; i--) {
331
+ if (history[i].version <= snapshotLocalVersion) {
332
+ return history[i].exists;
333
+ }
334
+ }
335
+ }
336
+ if (this.parent) {
337
+ return this.parent._existsSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
338
+ } else {
339
+ return this._diskExists(key, snapshotVersion);
340
+ }
286
341
  }
287
342
  _readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
288
343
  if (this.writeBuffer.has(key)) {
289
344
  const keyModVersion = this.keyVersions.get(key);
290
- if (snapshotLocalVersion === void 0 || keyModVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
345
+ if (snapshotLocalVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
291
346
  return this.writeBuffer.get(key);
292
347
  }
293
348
  }
294
349
  if (this.deleteBuffer.has(key)) {
295
350
  const keyModVersion = this.keyVersions.get(key);
296
- if (snapshotLocalVersion === void 0 || keyModVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
351
+ if (snapshotLocalVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
297
352
  return null;
298
353
  }
299
354
  }
355
+ const history = this.bufferHistory.get(key);
356
+ if (history && snapshotLocalVersion !== void 0) {
357
+ for (let i = history.length - 1; i >= 0; i--) {
358
+ if (history[i].version <= snapshotLocalVersion) {
359
+ return history[i].exists ? history[i].value : null;
360
+ }
361
+ }
362
+ }
300
363
  if (this.parent) {
301
364
  return this.parent._readSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
302
365
  } else {
@@ -306,54 +369,22 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
306
369
  commit(label) {
307
370
  const { created, updated, deleted } = this.getResultEntries();
308
371
  if (this.committed) {
309
- return {
310
- label,
311
- success: false,
312
- error: "Transaction already committed",
313
- conflict: void 0,
314
- created,
315
- updated,
316
- deleted
317
- };
372
+ return { label, success: false, error: "Transaction already committed", conflict: void 0, created, updated, deleted };
318
373
  }
319
374
  if (this.hasCommittedAncestor()) {
320
- return {
321
- label,
322
- success: false,
323
- error: "Ancestor transaction already committed",
324
- conflict: void 0,
325
- created,
326
- updated,
327
- deleted
328
- };
375
+ return { label, success: false, error: "Ancestor transaction already committed", conflict: void 0, created, updated, deleted };
329
376
  }
330
377
  if (this.parent) {
331
378
  const failure = this.parent._merge(this);
332
379
  if (failure) {
333
- return {
334
- label,
335
- success: false,
336
- error: failure.error,
337
- conflict: failure.conflict,
338
- created,
339
- updated,
340
- deleted
341
- };
380
+ return { label, success: false, error: failure.error, conflict: failure.conflict, created, updated, deleted };
342
381
  }
343
382
  this.committed = true;
344
383
  } else {
345
384
  if (this.writeBuffer.size > 0 || this.deleteBuffer.size > 0) {
346
385
  const failure = this._merge(this);
347
386
  if (failure) {
348
- return {
349
- label,
350
- success: false,
351
- error: failure.error,
352
- conflict: failure.conflict,
353
- created: [],
354
- updated: [],
355
- deleted: []
356
- };
387
+ return { label, success: false, error: failure.error, conflict: failure.conflict, created: [], updated: [], deleted: [] };
357
388
  }
358
389
  this.writeBuffer.clear();
359
390
  this.deleteBuffer.clear();
@@ -361,17 +392,12 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
361
392
  this.deletedValues.clear();
362
393
  this.originallyExisted.clear();
363
394
  this.keyVersions.clear();
395
+ this.bufferHistory.clear();
364
396
  this.localVersion = 0;
365
397
  this.snapshotVersion = this.version;
366
398
  }
367
399
  }
368
- return {
369
- label,
370
- success: true,
371
- created,
372
- updated,
373
- deleted
374
- };
400
+ return { label, success: true, created, updated, deleted };
375
401
  }
376
402
  _merge(child) {
377
403
  if (this.parent) {
@@ -380,11 +406,7 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
380
406
  if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
381
407
  return {
382
408
  error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
383
- conflict: {
384
- key,
385
- parent: this.read(key),
386
- child: child.read(key)
387
- }
409
+ conflict: { key, parent: this.read(key), child: child.read(key) }
388
410
  };
389
411
  }
390
412
  }
@@ -393,40 +415,26 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
393
415
  if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
394
416
  return {
395
417
  error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
396
- conflict: {
397
- key,
398
- parent: this.read(key),
399
- child: child.read(key)
400
- }
418
+ conflict: { key, parent: this.read(key), child: child.read(key) }
401
419
  };
402
420
  }
403
421
  }
404
- const newLocalVersion = this.localVersion + 1;
405
- for (const key of child.writeBuffer.keys()) {
406
- this.writeBuffer.set(key, child.writeBuffer.get(key));
407
- this.deleteBuffer.delete(key);
408
- this.keyVersions.set(key, newLocalVersion);
409
- if (child.createdKeys.has(key)) {
410
- this.createdKeys.add(key);
411
- }
422
+ const mergeVersion = ++this.localVersion;
423
+ for (const [key, value] of child.writeBuffer) {
424
+ const wasCreated = child.createdKeys.has(key);
425
+ if (wasCreated) this._bufferCreate(key, value, mergeVersion);
426
+ else this._bufferWrite(key, value, mergeVersion);
412
427
  }
413
428
  for (const key of child.deleteBuffer) {
414
- this.deleteBuffer.add(key);
415
- this.writeBuffer.delete(key);
416
- this.createdKeys.delete(key);
417
- this.keyVersions.set(key, newLocalVersion);
418
429
  const deletedValue = child.deletedValues.get(key);
419
- if (deletedValue !== void 0) {
420
- this.deletedValues.set(key, deletedValue);
421
- }
422
- if (child.originallyExisted.has(key)) {
430
+ if (deletedValue !== void 0) this.deletedValues.set(key, deletedValue);
431
+ if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
423
432
  this.originallyExisted.add(key);
424
433
  }
434
+ this._bufferDelete(key, mergeVersion);
425
435
  }
426
- this.localVersion = newLocalVersion;
427
436
  this.root.activeTransactions.delete(child);
428
437
  } else {
429
- const newVersion = this.version + 1;
430
438
  if (child !== this) {
431
439
  const modifiedKeys = /* @__PURE__ */ new Set([...child.writeBuffer.keys(), ...child.deleteBuffer]);
432
440
  for (const key of modifiedKeys) {
@@ -436,58 +444,53 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
436
444
  if (lastVer > child.snapshotVersion) {
437
445
  return {
438
446
  error: `Commit conflict: Key '${key}' was modified by a newer transaction (v${lastVer})`,
439
- conflict: {
440
- key,
441
- parent: this.read(key),
442
- child: child.read(key)
443
- }
447
+ conflict: { key, parent: this.read(key), child: child.read(key) }
444
448
  };
445
449
  }
446
450
  }
451
+ const lastModLocalVer = this.keyVersions.get(key);
452
+ if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
453
+ return {
454
+ error: `Commit conflict: Key '${key}' was modified by a newer transaction in the same session (Local v${lastModLocalVer})`,
455
+ conflict: { key, parent: this.read(key), child: child.read(key) }
456
+ };
457
+ }
447
458
  }
448
- }
449
- for (const [key, value] of child.writeBuffer) {
450
- this.writeBuffer.set(key, value);
451
- this.deleteBuffer.delete(key);
452
- if (child.createdKeys.has(key)) {
453
- this.createdKeys.add(key);
454
- }
455
- }
456
- for (const key of child.deleteBuffer) {
457
- this.deleteBuffer.add(key);
458
- this.writeBuffer.delete(key);
459
- this.createdKeys.delete(key);
460
- const deletedValue = child.deletedValues.get(key);
461
- if (deletedValue !== void 0) {
462
- this.deletedValues.set(key, deletedValue);
459
+ const mergeVersion = ++this.localVersion;
460
+ for (const [key, value] of child.writeBuffer) {
461
+ const wasCreated = child.createdKeys.has(key);
462
+ if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
463
+ this.originallyExisted.add(key);
464
+ }
465
+ if (wasCreated) this._bufferCreate(key, value, mergeVersion);
466
+ else this._bufferWrite(key, value, mergeVersion);
463
467
  }
464
- if (child.originallyExisted.has(key)) {
465
- this.originallyExisted.add(key);
468
+ for (const key of child.deleteBuffer) {
469
+ const deletedValue = child.deletedValues.get(key);
470
+ if (deletedValue !== void 0) this.deletedValues.set(key, deletedValue);
471
+ if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
472
+ this.originallyExisted.add(key);
473
+ }
474
+ this._bufferDelete(key, mergeVersion);
466
475
  }
476
+ this.root.activeTransactions.delete(child);
477
+ } else {
478
+ const newVersion = this.version + 1;
479
+ for (const [key, value] of this.writeBuffer) this._diskWrite(key, value, newVersion);
480
+ for (const key of this.deleteBuffer) this._diskDelete(key, newVersion);
481
+ this.version = newVersion;
482
+ this._cleanupDeletedCache();
467
483
  }
468
- for (const [key, value] of child.writeBuffer) {
469
- this._diskWrite(key, value, newVersion);
470
- }
471
- for (const key of child.deleteBuffer) {
472
- this._diskDelete(key, newVersion);
473
- }
474
- this.version = newVersion;
475
- this.root.activeTransactions.delete(child);
476
- this._cleanupDeletedCache();
477
484
  }
478
485
  return null;
479
486
  }
480
- // --- Internal IO Helpers (Root Only) ---
481
487
  _diskWrite(key, value, version) {
482
488
  const strategy = this.strategy;
483
489
  if (!strategy) throw new Error("Root Transaction missing strategy");
484
490
  if (strategy.exists(key)) {
485
491
  const currentVal = strategy.read(key);
486
492
  if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
487
- this.deletedCache.get(key).push({
488
- value: currentVal,
489
- deletedAtVersion: version
490
- });
493
+ this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: version });
491
494
  }
492
495
  strategy.write(key, value);
493
496
  if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
@@ -503,9 +506,8 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
503
506
  let targetVerObj = null;
504
507
  let nextVerObj = null;
505
508
  for (const v of versions) {
506
- if (v.version <= snapshotVersion) {
507
- targetVerObj = v;
508
- } else {
509
+ if (v.version <= snapshotVersion) targetVerObj = v;
510
+ else {
509
511
  nextVerObj = v;
510
512
  break;
511
513
  }
@@ -522,6 +524,7 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
522
524
  }
523
525
  if (!targetVerObj.exists) return null;
524
526
  if (!nextVerObj) {
527
+ if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
525
528
  return strategy.read(key);
526
529
  }
527
530
  const cached = this.deletedCache.get(key);
@@ -539,14 +542,24 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
539
542
  return strategy.exists(key);
540
543
  }
541
544
  let targetVerObj = null;
545
+ let nextVerObj = null;
542
546
  for (const v of versions) {
543
- if (v.version <= snapshotVersion) {
544
- targetVerObj = v;
545
- } else {
547
+ if (v.version <= snapshotVersion) targetVerObj = v;
548
+ else {
549
+ nextVerObj = v;
546
550
  break;
547
551
  }
548
552
  }
549
- if (!targetVerObj) return strategy.exists(key);
553
+ if (!targetVerObj) {
554
+ if (nextVerObj) {
555
+ const cached = this.deletedCache.get(key);
556
+ if (cached) {
557
+ const match = cached.find((c) => c.deletedAtVersion === nextVerObj.version);
558
+ if (match) return true;
559
+ }
560
+ }
561
+ return false;
562
+ }
550
563
  return targetVerObj.exists;
551
564
  }
552
565
  _diskDelete(key, snapshotVersion) {
@@ -555,12 +568,9 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
555
568
  if (strategy.exists(key)) {
556
569
  const currentVal = strategy.read(key);
557
570
  if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
558
- this.deletedCache.get(key).push({
559
- value: currentVal,
560
- deletedAtVersion: snapshotVersion
561
- });
571
+ this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: snapshotVersion });
572
+ strategy.delete(key);
562
573
  }
563
- strategy.delete(key);
564
574
  if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
565
575
  this.versionIndex.get(key).push({ version: snapshotVersion, exists: false });
566
576
  }
@@ -881,84 +891,93 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
881
891
  if (this.committed) throw new Error("Transaction already committed");
882
892
  if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
883
893
  if (this.deleteBuffer.has(key)) return null;
884
- return this.root._diskRead(key, this.snapshotVersion);
894
+ if (this.parent) {
895
+ return this.parent._readSnapshot(key, this.snapshotVersion, this.snapshotLocalVersion);
896
+ }
897
+ return await this._diskRead(key, this.snapshotVersion);
885
898
  }
886
899
  async exists(key) {
887
900
  if (this.committed) throw new Error("Transaction already committed");
888
901
  if (this.deleteBuffer.has(key)) return false;
889
902
  if (this.writeBuffer.has(key)) return true;
890
- return this.root._diskExists(key, this.snapshotVersion);
903
+ if (this.parent) {
904
+ return this.parent._existsSnapshot(key, this.snapshotVersion, this.snapshotLocalVersion);
905
+ }
906
+ return await this._diskExists(key, this.snapshotVersion);
907
+ }
908
+ async _existsSnapshot(key, snapshotVersion, snapshotLocalVersion) {
909
+ if (this.writeBuffer.has(key)) {
910
+ const keyModVersion = this.keyVersions.get(key);
911
+ if (snapshotLocalVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
912
+ return true;
913
+ }
914
+ }
915
+ if (this.deleteBuffer.has(key)) {
916
+ const keyModVersion = this.keyVersions.get(key);
917
+ if (snapshotLocalVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
918
+ return false;
919
+ }
920
+ }
921
+ const history = this.bufferHistory.get(key);
922
+ if (history && snapshotLocalVersion !== void 0) {
923
+ for (let i = history.length - 1; i >= 0; i--) {
924
+ if (history[i].version <= snapshotLocalVersion) {
925
+ return history[i].exists;
926
+ }
927
+ }
928
+ }
929
+ if (this.parent) {
930
+ return this.parent._existsSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
931
+ } else {
932
+ return await this._diskExists(key, snapshotVersion);
933
+ }
891
934
  }
892
935
  async _readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
893
936
  if (this.writeBuffer.has(key)) {
894
937
  const keyModVersion = this.keyVersions.get(key);
895
- if (snapshotLocalVersion === void 0 || keyModVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
938
+ if (snapshotLocalVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
896
939
  return this.writeBuffer.get(key);
897
940
  }
898
941
  }
899
942
  if (this.deleteBuffer.has(key)) {
900
943
  const keyModVersion = this.keyVersions.get(key);
901
- if (snapshotLocalVersion === void 0 || keyModVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
944
+ if (snapshotLocalVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
902
945
  return null;
903
946
  }
904
947
  }
948
+ const history = this.bufferHistory.get(key);
949
+ if (history && snapshotLocalVersion !== void 0) {
950
+ for (let i = history.length - 1; i >= 0; i--) {
951
+ if (history[i].version <= snapshotLocalVersion) {
952
+ return history[i].exists ? history[i].value : null;
953
+ }
954
+ }
955
+ }
905
956
  if (this.parent) {
906
957
  return this.parent._readSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
907
958
  } else {
908
- return this._diskRead(key, snapshotVersion);
959
+ return await this._diskRead(key, snapshotVersion);
909
960
  }
910
961
  }
911
962
  async commit(label) {
912
963
  const { created, updated, deleted } = this.getResultEntries();
913
964
  if (this.committed) {
914
- return {
915
- label,
916
- success: false,
917
- error: "Transaction already committed",
918
- conflict: void 0,
919
- created,
920
- updated,
921
- deleted
922
- };
965
+ return { label, success: false, error: "Transaction already committed", conflict: void 0, created, updated, deleted };
923
966
  }
924
967
  if (this.hasCommittedAncestor()) {
925
- return {
926
- label,
927
- success: false,
928
- error: "Ancestor transaction already committed",
929
- conflict: void 0,
930
- created,
931
- updated,
932
- deleted
933
- };
968
+ return { label, success: false, error: "Ancestor transaction already committed", conflict: void 0, created, updated, deleted };
934
969
  }
935
970
  if (this.parent) {
936
971
  const failure = await this.parent._merge(this);
937
972
  if (failure) {
938
- return {
939
- label,
940
- success: false,
941
- error: failure.error,
942
- conflict: failure.conflict,
943
- created,
944
- updated,
945
- deleted
946
- };
973
+ return { label, success: false, error: failure.error, conflict: failure.conflict, created, updated, deleted };
947
974
  }
948
975
  this.committed = true;
949
976
  } else {
950
977
  if (this.writeBuffer.size > 0 || this.deleteBuffer.size > 0) {
951
978
  const failure = await this._merge(this);
952
979
  if (failure) {
953
- return {
954
- label,
955
- success: false,
956
- error: failure.error,
957
- conflict: failure.conflict,
958
- created: [],
959
- updated: [],
960
- deleted: []
961
- };
980
+ return { label, success: false, error: failure.error, conflict: failure.conflict, created: [], updated: [], deleted: [] };
962
981
  }
963
982
  this.writeBuffer.clear();
964
983
  this.deleteBuffer.clear();
@@ -966,17 +985,12 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
966
985
  this.deletedValues.clear();
967
986
  this.originallyExisted.clear();
968
987
  this.keyVersions.clear();
988
+ this.bufferHistory.clear();
969
989
  this.localVersion = 0;
970
990
  this.snapshotVersion = this.version;
971
991
  }
972
992
  }
973
- return {
974
- label,
975
- success: true,
976
- created,
977
- updated,
978
- deleted
979
- };
993
+ return { label, success: true, created, updated, deleted };
980
994
  }
981
995
  async _merge(child) {
982
996
  return this.writeLock(async () => {
@@ -986,11 +1000,7 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
986
1000
  if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
987
1001
  return {
988
1002
  error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
989
- conflict: {
990
- key,
991
- parent: await this.read(key),
992
- child: await child.read(key)
993
- }
1003
+ conflict: { key, parent: await this.read(key), child: await child.read(key) }
994
1004
  };
995
1005
  }
996
1006
  }
@@ -999,41 +1009,27 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
999
1009
  if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
1000
1010
  return {
1001
1011
  error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
1002
- conflict: {
1003
- key,
1004
- parent: await this.read(key),
1005
- child: await child.read(key)
1006
- }
1012
+ conflict: { key, parent: await this.read(key), child: await child.read(key) }
1007
1013
  };
1008
1014
  }
1009
1015
  }
1010
- const newLocalVersion = this.localVersion + 1;
1011
- for (const key of child.writeBuffer.keys()) {
1012
- this.writeBuffer.set(key, child.writeBuffer.get(key));
1013
- this.deleteBuffer.delete(key);
1014
- this.keyVersions.set(key, newLocalVersion);
1015
- if (child.createdKeys.has(key)) {
1016
- this.createdKeys.add(key);
1017
- }
1016
+ const mergeVersion = ++this.localVersion;
1017
+ for (const [key, value] of child.writeBuffer) {
1018
+ const wasCreated = child.createdKeys.has(key);
1019
+ if (wasCreated) this._bufferCreate(key, value, mergeVersion);
1020
+ else this._bufferWrite(key, value, mergeVersion);
1018
1021
  }
1019
1022
  for (const key of child.deleteBuffer) {
1020
- this.deleteBuffer.add(key);
1021
- this.writeBuffer.delete(key);
1022
- this.createdKeys.delete(key);
1023
- this.keyVersions.set(key, newLocalVersion);
1024
1023
  const deletedValue = child.deletedValues.get(key);
1025
- if (deletedValue !== void 0) {
1026
- this.deletedValues.set(key, deletedValue);
1027
- }
1028
- if (child.originallyExisted.has(key)) {
1024
+ if (deletedValue !== void 0) this.deletedValues.set(key, deletedValue);
1025
+ if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
1029
1026
  this.originallyExisted.add(key);
1030
1027
  }
1028
+ this._bufferDelete(key, mergeVersion);
1031
1029
  }
1032
- this.localVersion = newLocalVersion;
1033
1030
  this.root.activeTransactions.delete(child);
1034
1031
  return null;
1035
1032
  } else {
1036
- const newVersion = this.version + 1;
1037
1033
  if (child !== this) {
1038
1034
  const modifiedKeys = /* @__PURE__ */ new Set([...child.writeBuffer.keys(), ...child.deleteBuffer]);
1039
1035
  for (const key of modifiedKeys) {
@@ -1043,59 +1039,54 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
1043
1039
  if (lastVer > child.snapshotVersion) {
1044
1040
  return {
1045
1041
  error: `Commit conflict: Key '${key}' was modified by a newer transaction (v${lastVer})`,
1046
- conflict: {
1047
- key,
1048
- parent: await this.read(key),
1049
- child: await child.read(key)
1050
- }
1042
+ conflict: { key, parent: await this.read(key), child: await child.read(key) }
1051
1043
  };
1052
1044
  }
1053
1045
  }
1046
+ const lastModLocalVer = this.keyVersions.get(key);
1047
+ if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
1048
+ return {
1049
+ error: `Commit conflict: Key '${key}' was modified by a newer transaction in the same session (Local v${lastModLocalVer})`,
1050
+ conflict: { key, parent: await this.read(key), child: await child.read(key) }
1051
+ };
1052
+ }
1054
1053
  }
1055
- }
1056
- for (const [key, value] of child.writeBuffer) {
1057
- this.writeBuffer.set(key, value);
1058
- this.deleteBuffer.delete(key);
1059
- if (child.createdKeys.has(key)) {
1060
- this.createdKeys.add(key);
1061
- }
1062
- }
1063
- for (const key of child.deleteBuffer) {
1064
- this.deleteBuffer.add(key);
1065
- this.writeBuffer.delete(key);
1066
- this.createdKeys.delete(key);
1067
- const deletedValue = child.deletedValues.get(key);
1068
- if (deletedValue !== void 0) {
1069
- this.deletedValues.set(key, deletedValue);
1054
+ const mergeVersion = ++this.localVersion;
1055
+ for (const [key, value] of child.writeBuffer) {
1056
+ const wasCreated = child.createdKeys.has(key);
1057
+ if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
1058
+ this.originallyExisted.add(key);
1059
+ }
1060
+ if (wasCreated) this._bufferCreate(key, value, mergeVersion);
1061
+ else this._bufferWrite(key, value, mergeVersion);
1070
1062
  }
1071
- if (child.originallyExisted.has(key)) {
1072
- this.originallyExisted.add(key);
1063
+ for (const key of child.deleteBuffer) {
1064
+ const deletedValue = child.deletedValues.get(key);
1065
+ if (deletedValue !== void 0) this.deletedValues.set(key, deletedValue);
1066
+ if (child.originallyExisted.has(key) && !this.createdKeys.has(key)) {
1067
+ this.originallyExisted.add(key);
1068
+ }
1069
+ this._bufferDelete(key, mergeVersion);
1073
1070
  }
1071
+ this.root.activeTransactions.delete(child);
1072
+ } else {
1073
+ const newVersion = this.version + 1;
1074
+ for (const [key, value] of this.writeBuffer) await this._diskWrite(key, value, newVersion);
1075
+ for (const key of this.deleteBuffer) await this._diskDelete(key, newVersion);
1076
+ this.version = newVersion;
1077
+ this._cleanupDeletedCache();
1074
1078
  }
1075
- for (const [key, value] of child.writeBuffer) {
1076
- await this._diskWrite(key, value, newVersion);
1077
- }
1078
- for (const key of child.deleteBuffer) {
1079
- await this._diskDelete(key, newVersion);
1080
- }
1081
- this.version = newVersion;
1082
- this.root.activeTransactions.delete(child);
1083
- this._cleanupDeletedCache();
1084
1079
  return null;
1085
1080
  }
1086
1081
  });
1087
1082
  }
1088
- // --- Internal IO Helpers (Root Only) ---
1089
1083
  async _diskWrite(key, value, version) {
1090
1084
  const strategy = this.strategy;
1091
1085
  if (!strategy) throw new Error("Root Transaction missing strategy");
1092
1086
  if (await strategy.exists(key)) {
1093
1087
  const currentVal = await strategy.read(key);
1094
1088
  if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
1095
- this.deletedCache.get(key).push({
1096
- value: currentVal,
1097
- deletedAtVersion: version
1098
- });
1089
+ this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: version });
1099
1090
  }
1100
1091
  await strategy.write(key, value);
1101
1092
  if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
@@ -1106,14 +1097,13 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
1106
1097
  if (!strategy) throw new Error("Root Transaction missing strategy");
1107
1098
  const versions = this.versionIndex.get(key);
1108
1099
  if (!versions) {
1109
- return await strategy.exists(key) ? strategy.read(key) : null;
1100
+ return await strategy.exists(key) ? await strategy.read(key) : null;
1110
1101
  }
1111
1102
  let targetVerObj = null;
1112
1103
  let nextVerObj = null;
1113
1104
  for (const v of versions) {
1114
- if (v.version <= snapshotVersion) {
1115
- targetVerObj = v;
1116
- } else {
1105
+ if (v.version <= snapshotVersion) targetVerObj = v;
1106
+ else {
1117
1107
  nextVerObj = v;
1118
1108
  break;
1119
1109
  }
@@ -1130,6 +1120,7 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
1130
1120
  }
1131
1121
  if (!targetVerObj.exists) return null;
1132
1122
  if (!nextVerObj) {
1123
+ if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
1133
1124
  return strategy.read(key);
1134
1125
  }
1135
1126
  const cached = this.deletedCache.get(key);
@@ -1144,17 +1135,27 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
1144
1135
  if (!strategy) throw new Error("Root Transaction missing strategy");
1145
1136
  const versions = this.versionIndex.get(key);
1146
1137
  if (!versions) {
1147
- return strategy.exists(key);
1138
+ return await strategy.exists(key);
1148
1139
  }
1149
1140
  let targetVerObj = null;
1141
+ let nextVerObj = null;
1150
1142
  for (const v of versions) {
1151
- if (v.version <= snapshotVersion) {
1152
- targetVerObj = v;
1153
- } else {
1143
+ if (v.version <= snapshotVersion) targetVerObj = v;
1144
+ else {
1145
+ nextVerObj = v;
1154
1146
  break;
1155
1147
  }
1156
1148
  }
1157
- if (!targetVerObj) return strategy.exists(key);
1149
+ if (!targetVerObj) {
1150
+ if (nextVerObj) {
1151
+ const cached = this.deletedCache.get(key);
1152
+ if (cached) {
1153
+ const match = cached.find((c) => c.deletedAtVersion === nextVerObj.version);
1154
+ if (match) return true;
1155
+ }
1156
+ }
1157
+ return false;
1158
+ }
1158
1159
  return targetVerObj.exists;
1159
1160
  }
1160
1161
  async _diskDelete(key, snapshotVersion) {
@@ -1163,12 +1164,9 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
1163
1164
  if (await strategy.exists(key)) {
1164
1165
  const currentVal = await strategy.read(key);
1165
1166
  if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
1166
- this.deletedCache.get(key).push({
1167
- value: currentVal,
1168
- deletedAtVersion: snapshotVersion
1169
- });
1167
+ this.deletedCache.get(key).push({ value: currentVal, deletedAtVersion: snapshotVersion });
1168
+ await strategy.delete(key);
1170
1169
  }
1171
- await strategy.delete(key);
1172
1170
  if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
1173
1171
  this.versionIndex.get(key).push({ version: snapshotVersion, exists: false });
1174
1172
  }
@@ -1510,6 +1508,8 @@ var BPTreeTransaction = class _BPTreeTransaction {
1510
1508
  option;
1511
1509
  order;
1512
1510
  rootId;
1511
+ isInitialized = false;
1512
+ isDestroyed = false;
1513
1513
  verifierMap = {
1514
1514
  gt: (nv, v) => this.comparator.isHigher(nv, v),
1515
1515
  gte: (nv, v) => this.comparator.isHigher(nv, v) || this.comparator.isSame(nv, v),
@@ -1774,13 +1774,26 @@ var BPTreeTransaction = class _BPTreeTransaction {
1774
1774
  getResultEntries() {
1775
1775
  return this.mvcc.getResultEntries();
1776
1776
  }
1777
+ _clearCache() {
1778
+ this._cachedRegexp.clear();
1779
+ this.nodes.clear();
1780
+ }
1777
1781
  /**
1778
1782
  * Clears all cached nodes.
1779
1783
  * This method is useful for freeing up memory when the tree is no longer needed.
1780
1784
  */
1781
1785
  clear() {
1782
- this._cachedRegexp.clear();
1783
- this.nodes.clear();
1786
+ if (this.rootTx !== this) {
1787
+ throw new Error("Cannot call clear on a nested transaction");
1788
+ }
1789
+ this._clearInternal();
1790
+ }
1791
+ _clearInternal() {
1792
+ if (this.isDestroyed) {
1793
+ throw new Error("Transaction already destroyed");
1794
+ }
1795
+ this._clearCache();
1796
+ this.isDestroyed = true;
1784
1797
  }
1785
1798
  _binarySearchValues(values, target, usePrimary = false, upperBound = false) {
1786
1799
  let low = 0;
@@ -2086,28 +2099,46 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2086
2099
  }
2087
2100
  }
2088
2101
  init() {
2089
- this.clear();
2090
- const head = this._readHead();
2091
- if (head === null) {
2092
- this.order = this.strategy.order;
2093
- const root = this._createNode(true, [], []);
2094
- this._writeHead({
2095
- root: root.id,
2096
- order: this.order,
2097
- data: this.strategy.head.data
2098
- });
2099
- } else {
2100
- const { root, order } = head;
2101
- this.strategy.head = head;
2102
- this.order = order;
2103
- this._writeHead({
2104
- root,
2105
- order: this.order,
2106
- data: this.strategy.head.data
2107
- });
2102
+ if (this.rootTx !== this) {
2103
+ throw new Error("Cannot call init on a nested transaction");
2104
+ }
2105
+ this._initInternal();
2106
+ }
2107
+ _initInternal() {
2108
+ if (this.isInitialized) {
2109
+ throw new Error("Transaction already initialized");
2110
+ }
2111
+ if (this.isDestroyed) {
2112
+ throw new Error("Transaction already destroyed");
2108
2113
  }
2109
- if (this.order < 3) {
2110
- throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
2114
+ this.isInitialized = true;
2115
+ try {
2116
+ this._clearCache();
2117
+ const head = this._readHead();
2118
+ if (head === null) {
2119
+ this.order = this.strategy.order;
2120
+ const root = this._createNode(true, [], []);
2121
+ this._writeHead({
2122
+ root: root.id,
2123
+ order: this.order,
2124
+ data: this.strategy.head.data
2125
+ });
2126
+ } else {
2127
+ const { root, order } = head;
2128
+ this.strategy.head = head;
2129
+ this.order = order;
2130
+ this._writeHead({
2131
+ root,
2132
+ order: this.order,
2133
+ data: this.strategy.head.data
2134
+ });
2135
+ }
2136
+ if (this.order < 3) {
2137
+ throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
2138
+ }
2139
+ } catch (e) {
2140
+ this.isInitialized = false;
2141
+ throw e;
2111
2142
  }
2112
2143
  }
2113
2144
  exists(key, value) {
@@ -2485,9 +2516,12 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2485
2516
  commit(label) {
2486
2517
  let result = this.mvcc.commit(label);
2487
2518
  if (result.success) {
2488
- result = this.mvccRoot.commit(label);
2489
- if (result.success && this.rootTx !== this) {
2490
- this.rootTx.rootId = this.rootId;
2519
+ const isRootTx = this.rootTx !== this;
2520
+ if (isRootTx) {
2521
+ result = this.rootTx.commit(label);
2522
+ if (result.success) {
2523
+ this.rootTx.rootId = this.rootId;
2524
+ }
2491
2525
  }
2492
2526
  if (result.success) {
2493
2527
  for (const r of result.created) {
@@ -2570,7 +2604,7 @@ var BPTreeSync = class extends BPTreeSyncTransaction {
2570
2604
  this.comparator,
2571
2605
  this.option
2572
2606
  );
2573
- tx.init();
2607
+ tx._initInternal();
2574
2608
  return tx;
2575
2609
  }
2576
2610
  insert(key, value) {
@@ -2580,7 +2614,6 @@ var BPTreeSync = class extends BPTreeSyncTransaction {
2580
2614
  if (!result.success) {
2581
2615
  throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
2582
2616
  }
2583
- this.rootId = tx.getRootId();
2584
2617
  }
2585
2618
  delete(key, value) {
2586
2619
  const tx = this.createTransaction();
@@ -2589,244 +2622,512 @@ var BPTreeSync = class extends BPTreeSyncTransaction {
2589
2622
  if (!result.success) {
2590
2623
  throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
2591
2624
  }
2592
- this.rootId = tx.getRootId();
2593
2625
  }
2594
2626
  };
2595
2627
 
2596
- // src/transaction/BPTreeAsyncTransaction.ts
2597
- var BPTreeAsyncTransaction = class extends BPTreeTransaction {
2598
- constructor(rootTx, mvccRoot, mvcc, strategy, comparator, option) {
2599
- super(
2600
- rootTx,
2601
- mvccRoot,
2602
- mvcc,
2603
- strategy,
2604
- comparator,
2605
- option
2606
- );
2628
+ // node_modules/ryoiki/dist/esm/index.mjs
2629
+ var Ryoiki2 = class _Ryoiki2 {
2630
+ readings;
2631
+ writings;
2632
+ readQueue;
2633
+ writeQueue;
2634
+ static async CatchError(promise) {
2635
+ return await promise.then((v) => [void 0, v]).catch((err) => [err]);
2607
2636
  }
2608
- async getNode(id) {
2609
- if (this.nodes.has(id)) {
2610
- return this.nodes.get(id);
2637
+ static IsRangeOverlap(a, b) {
2638
+ const [start1, end1] = a;
2639
+ const [start2, end2] = b;
2640
+ if (end1 <= start2 || end2 <= start1) {
2641
+ return false;
2611
2642
  }
2612
- return await this.mvcc.read(id);
2643
+ return true;
2644
+ }
2645
+ static ERR_ALREADY_EXISTS(lockId) {
2646
+ return new Error(`The '${lockId}' task already existing in queue or running.`);
2647
+ }
2648
+ static ERR_NOT_EXISTS(lockId) {
2649
+ return new Error(`The '${lockId}' task not existing in task queue.`);
2650
+ }
2651
+ static ERR_TIMEOUT(lockId, timeout) {
2652
+ return new Error(`The task with ID '${lockId}' failed to acquire the lock within the timeout(${timeout}ms).`);
2613
2653
  }
2614
2654
  /**
2615
- * Create a new node with a unique ID.
2655
+ * Constructs a new instance of the Ryoiki class.
2616
2656
  */
2617
- async _createNode(leaf, keys, values, parent = null, next = null, prev = null) {
2618
- const id = await this.strategy.id(leaf);
2619
- const node = {
2620
- id,
2621
- keys,
2622
- values,
2623
- leaf,
2624
- parent,
2625
- next,
2626
- prev
2627
- };
2628
- await this.mvcc.create(id, node);
2629
- this.nodes.set(id, node);
2630
- return node;
2657
+ constructor() {
2658
+ this.readings = /* @__PURE__ */ new Map();
2659
+ this.writings = /* @__PURE__ */ new Map();
2660
+ this.readQueue = /* @__PURE__ */ new Map();
2661
+ this.writeQueue = /* @__PURE__ */ new Map();
2631
2662
  }
2632
- async _updateNode(node) {
2633
- await this.mvcc.write(node.id, node);
2634
- this.nodes.set(node.id, node);
2663
+ /**
2664
+ * Creates a range based on a start value and length.
2665
+ * @param start - The starting value of the range.
2666
+ * @param length - The length of the range.
2667
+ * @returns A range tuple [start, start + length].
2668
+ */
2669
+ range(start, length) {
2670
+ return [start, start + length];
2635
2671
  }
2636
- async _deleteNode(node) {
2637
- await this.mvcc.delete(node.id);
2638
- this.nodes.delete(node.id);
2672
+ rangeOverlapping(tasks, range) {
2673
+ return Array.from(tasks.values()).some((t) => _Ryoiki2.IsRangeOverlap(t.range, range));
2639
2674
  }
2640
- async _readHead() {
2641
- if (this.nodes.has("__HEAD__")) {
2642
- return this.nodes.get("__HEAD__") ?? null;
2643
- }
2644
- const head = await this.mvcc.read("__HEAD__");
2645
- return head ?? null;
2646
- }
2647
- async _writeHead(head) {
2648
- if (!await this.mvcc.exists("__HEAD__")) {
2649
- await this.mvcc.create("__HEAD__", head);
2650
- } else {
2651
- await this.mvcc.write("__HEAD__", head);
2652
- }
2653
- this.nodes.set("__HEAD__", head);
2654
- this.rootId = head.root;
2675
+ isSameRange(a, b) {
2676
+ const [a1, a2] = a;
2677
+ const [b1, b2] = b;
2678
+ return a1 === b1 && a2 === b2;
2655
2679
  }
2656
- async _insertAtLeaf(node, key, value) {
2657
- if (node.values.length) {
2658
- for (let i = 0, len = node.values.length; i < len; i++) {
2659
- const nValue = node.values[i];
2660
- if (this.comparator.isSame(value, nValue)) {
2661
- const keys = node.keys[i];
2662
- if (keys.includes(key)) {
2663
- break;
2664
- }
2665
- keys.push(key);
2666
- await this._updateNode(node);
2667
- return;
2668
- } else if (this.comparator.isLower(value, nValue)) {
2669
- node.values.splice(i, 0, value);
2670
- node.keys.splice(i, 0, [key]);
2671
- await this._updateNode(node);
2672
- return;
2673
- } else if (i + 1 === node.values.length) {
2674
- node.values.push(value);
2675
- node.keys.push([key]);
2676
- await this._updateNode(node);
2677
- return;
2678
- }
2680
+ fetchUnitAndRun(queue, workspaces) {
2681
+ for (const [id, unit] of queue) {
2682
+ if (!unit.condition()) {
2683
+ continue;
2679
2684
  }
2680
- } else {
2681
- node.values = [value];
2682
- node.keys = [[key]];
2683
- await this._updateNode(node);
2684
- return;
2685
+ this._alloc(queue, workspaces, id);
2685
2686
  }
2686
2687
  }
2687
- async _insertInParent(node, value, pointer) {
2688
- if (this.rootId === node.id) {
2689
- const root = await this._createNode(false, [node.id, pointer.id], [value]);
2690
- this.rootId = root.id;
2691
- node.parent = root.id;
2692
- pointer.parent = root.id;
2693
- if (pointer.leaf) {
2694
- node.next = pointer.id;
2695
- pointer.prev = node.id;
2696
- }
2697
- await this._writeHead({
2698
- root: root.id,
2699
- order: this.order,
2700
- data: this.strategy.head.data
2701
- });
2702
- await this._updateNode(node);
2703
- await this._updateNode(pointer);
2704
- return;
2705
- }
2706
- const parentNode = await this.getNode(node.parent);
2707
- const nodeIndex = parentNode.keys.indexOf(node.id);
2708
- if (nodeIndex === -1) {
2709
- throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
2710
- }
2711
- parentNode.values.splice(nodeIndex, 0, value);
2712
- parentNode.keys.splice(nodeIndex + 1, 0, pointer.id);
2713
- pointer.parent = parentNode.id;
2714
- if (pointer.leaf) {
2715
- const leftSibling = node;
2716
- const oldNextId = leftSibling.next;
2717
- pointer.prev = leftSibling.id;
2718
- pointer.next = oldNextId;
2719
- leftSibling.next = pointer.id;
2720
- await this._updateNode(leftSibling);
2721
- if (oldNextId) {
2722
- const oldNext = await this.getNode(oldNextId);
2723
- oldNext.prev = pointer.id;
2724
- await this._updateNode(oldNext);
2725
- }
2726
- }
2727
- await this._updateNode(parentNode);
2728
- await this._updateNode(pointer);
2729
- if (parentNode.keys.length > this.order) {
2730
- const parentPointer = await this._createNode(false, [], []);
2731
- parentPointer.parent = parentNode.parent;
2732
- const mid = Math.ceil(this.order / 2) - 1;
2733
- parentPointer.values = parentNode.values.slice(mid + 1);
2734
- parentPointer.keys = parentNode.keys.slice(mid + 1);
2735
- const midValue = parentNode.values[mid];
2736
- parentNode.values = parentNode.values.slice(0, mid);
2737
- parentNode.keys = parentNode.keys.slice(0, mid + 1);
2738
- for (const k of parentNode.keys) {
2739
- const n = await this.getNode(k);
2740
- n.parent = parentNode.id;
2741
- await this._updateNode(n);
2742
- }
2743
- for (const k of parentPointer.keys) {
2744
- const n = await this.getNode(k);
2745
- n.parent = parentPointer.id;
2746
- await this._updateNode(n);
2688
+ _handleOverload(args, handlers, argPatterns) {
2689
+ for (const [key, pattern] of Object.entries(argPatterns)) {
2690
+ if (this._matchArgs(args, pattern)) {
2691
+ return handlers[key](...args);
2747
2692
  }
2748
- await this._updateNode(parentNode);
2749
- await this._insertInParent(parentNode, midValue, parentPointer);
2750
2693
  }
2694
+ throw new Error("Invalid arguments");
2751
2695
  }
2752
- async insertableNode(value) {
2753
- let node = await this.getNode(this.rootId);
2754
- while (!node.leaf) {
2755
- const { index } = this._binarySearchValues(node.values, value, false, true);
2756
- node = await this.getNode(node.keys[index]);
2757
- }
2758
- return node;
2696
+ _matchArgs(args, pattern) {
2697
+ return args.every((arg, index) => {
2698
+ const expectedType = pattern[index];
2699
+ if (expectedType === void 0) return typeof arg === "undefined";
2700
+ if (expectedType === Function) return typeof arg === "function";
2701
+ if (expectedType === Number) return typeof arg === "number";
2702
+ if (expectedType === Array) return Array.isArray(arg);
2703
+ return false;
2704
+ });
2759
2705
  }
2760
- async insertableNodeByPrimary(value) {
2761
- let node = await this.getNode(this.rootId);
2762
- while (!node.leaf) {
2763
- const { index } = this._binarySearchValues(node.values, value, true, false);
2764
- node = await this.getNode(node.keys[index]);
2765
- }
2766
- return node;
2706
+ _createRandomId() {
2707
+ const timestamp = Date.now().toString(36);
2708
+ const random = Math.random().toString(36).substring(2);
2709
+ return `${timestamp}${random}`;
2767
2710
  }
2768
- async insertableRightestNodeByPrimary(value) {
2769
- let node = await this.getNode(this.rootId);
2770
- while (!node.leaf) {
2771
- const { index } = this._binarySearchValues(node.values, value, true, true);
2772
- node = await this.getNode(node.keys[index]);
2711
+ _alloc(queue, workspaces, lockId) {
2712
+ const unit = queue.get(lockId);
2713
+ if (!unit) {
2714
+ throw _Ryoiki2.ERR_NOT_EXISTS(lockId);
2773
2715
  }
2774
- return node;
2716
+ workspaces.set(lockId, unit);
2717
+ queue.delete(lockId);
2718
+ unit.alloc();
2775
2719
  }
2776
- async insertableRightestEndNodeByPrimary(value) {
2777
- const node = await this.insertableRightestNodeByPrimary(value);
2778
- if (!node.next) {
2779
- return null;
2720
+ _free(workspaces, lockId) {
2721
+ const unit = workspaces.get(lockId);
2722
+ if (!unit) {
2723
+ throw _Ryoiki2.ERR_NOT_EXISTS(lockId);
2780
2724
  }
2781
- return await this.getNode(node.next);
2725
+ workspaces.delete(lockId);
2726
+ unit.free();
2782
2727
  }
2783
- async insertableEndNode(value, direction) {
2784
- const insertableNode = await this.insertableNode(value);
2785
- let key;
2786
- switch (direction) {
2787
- case -1:
2788
- key = "prev";
2789
- break;
2790
- case 1:
2791
- key = "next";
2728
+ _lock(queue, range, timeout, task, condition) {
2729
+ return new Promise((resolve, reject) => {
2730
+ let timeoutId = null;
2731
+ if (timeout >= 0) {
2732
+ timeoutId = setTimeout(() => {
2733
+ reject(_Ryoiki2.ERR_TIMEOUT(id, timeout));
2734
+ }, timeout);
2735
+ }
2736
+ const id = this._createRandomId();
2737
+ const alloc = async () => {
2738
+ if (timeoutId !== null) {
2739
+ clearTimeout(timeoutId);
2740
+ }
2741
+ const [err, v] = await _Ryoiki2.CatchError(task(id));
2742
+ if (err) reject(err);
2743
+ else resolve(v);
2744
+ };
2745
+ const fetch = () => {
2746
+ this.fetchUnitAndRun(this.readQueue, this.readings);
2747
+ this.fetchUnitAndRun(this.writeQueue, this.writings);
2748
+ };
2749
+ queue.set(id, { id, range, condition, alloc, free: fetch });
2750
+ fetch();
2751
+ });
2752
+ }
2753
+ _checkWorking(range, workspaces) {
2754
+ let isLocked = false;
2755
+ for (const lock of workspaces.values()) {
2756
+ if (_Ryoiki2.IsRangeOverlap(range, lock.range)) {
2757
+ isLocked = true;
2792
2758
  break;
2793
- default:
2794
- throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
2795
- }
2796
- const guessNode = insertableNode[key];
2797
- if (!guessNode) {
2798
- return null;
2759
+ }
2799
2760
  }
2800
- return await this.getNode(guessNode);
2761
+ return isLocked;
2801
2762
  }
2802
- async leftestNode() {
2803
- let node = await this.getNode(this.rootId);
2804
- if (node === null) {
2805
- debugger;
2806
- }
2807
- while (!node.leaf) {
2808
- const keys = node.keys;
2809
- node = await this.getNode(keys[0]);
2810
- }
2811
- return node;
2763
+ /**
2764
+ * Checks if there is any active read lock within the specified range.
2765
+ * @param range The range to check for active read locks.
2766
+ * @returns `true` if there is an active read lock within the range, `false` otherwise.
2767
+ */
2768
+ isReading(range) {
2769
+ return this._checkWorking(range, this.readings);
2812
2770
  }
2813
- async rightestNode() {
2814
- let node = await this.getNode(this.rootId);
2815
- while (!node.leaf) {
2816
- const keys = node.keys;
2817
- node = await this.getNode(keys[keys.length - 1]);
2818
- }
2819
- return node;
2771
+ /**
2772
+ * Checks if there is any active write lock within the specified range.
2773
+ * @param range The range to check for active write locks.
2774
+ * @returns `true` if there is an active write lock within the range, `false` otherwise.
2775
+ */
2776
+ isWriting(range) {
2777
+ return this._checkWorking(range, this.writings);
2820
2778
  }
2821
- async *getPairsGenerator(value, startNode, endNode, comparator, direction, earlyTerminate) {
2822
- let node = startNode;
2823
- let done = false;
2824
- let hasMatched = false;
2825
- let nextNodePromise = null;
2826
- while (!done) {
2827
- if (endNode && node.id === endNode.id) {
2828
- done = true;
2829
- break;
2779
+ /**
2780
+ * Checks if a read lock can be acquired within the specified range.
2781
+ * @param range The range to check for read lock availability.
2782
+ * @returns `true` if a read lock can be acquired, `false` otherwise.
2783
+ */
2784
+ canRead(range) {
2785
+ const writing = this.isWriting(range);
2786
+ return !writing;
2787
+ }
2788
+ /**
2789
+ * Checks if a write lock can be acquired within the specified range.
2790
+ * @param range The range to check for write lock availability.
2791
+ * @returns `true` if a write lock can be acquired, `false` otherwise.
2792
+ */
2793
+ canWrite(range) {
2794
+ const reading = this.isReading(range);
2795
+ const writing = this.isWriting(range);
2796
+ return !reading && !writing;
2797
+ }
2798
+ /**
2799
+ * Internal implementation of the read lock. Handles both overloads.
2800
+ * @template T - The return type of the task.
2801
+ * @param arg0 - Either a range or a task callback.
2802
+ * If a range is provided, the task is the second argument.
2803
+ * @param arg1 - The task to execute, required if a range is provided.
2804
+ * @param arg2 - The timeout for acquiring the lock.
2805
+ * If the lock cannot be acquired within this period, an error will be thrown.
2806
+ * If this value is not provided, no timeout will be set.
2807
+ * @returns A promise resolving to the result of the task execution.
2808
+ */
2809
+ readLock(arg0, arg1, arg2) {
2810
+ const [range, task, timeout] = this._handleOverload(
2811
+ [arg0, arg1, arg2],
2812
+ {
2813
+ rangeTask: (range2, task2) => [range2, task2, -1],
2814
+ rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
2815
+ task: (task2) => [[-Infinity, Infinity], task2, -1],
2816
+ taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
2817
+ },
2818
+ {
2819
+ task: [Function],
2820
+ taskTimeout: [Function, Number],
2821
+ rangeTask: [Array, Function],
2822
+ rangeTaskTimeout: [Array, Function, Number]
2823
+ }
2824
+ );
2825
+ return this._lock(
2826
+ this.readQueue,
2827
+ range,
2828
+ timeout,
2829
+ task,
2830
+ () => !this.rangeOverlapping(this.writings, range)
2831
+ );
2832
+ }
2833
+ /**
2834
+ * Internal implementation of the write lock. Handles both overloads.
2835
+ * @template T - The return type of the task.
2836
+ * @param arg0 - Either a range or a task callback.
2837
+ * If a range is provided, the task is the second argument.
2838
+ * @param arg1 - The task to execute, required if a range is provided.
2839
+ * @param arg2 - The timeout for acquiring the lock.
2840
+ * If the lock cannot be acquired within this period, an error will be thrown.
2841
+ * If this value is not provided, no timeout will be set.
2842
+ * @returns A promise resolving to the result of the task execution.
2843
+ */
2844
+ writeLock(arg0, arg1, arg2) {
2845
+ const [range, task, timeout] = this._handleOverload(
2846
+ [arg0, arg1, arg2],
2847
+ {
2848
+ rangeTask: (range2, task2) => [range2, task2, -1],
2849
+ rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
2850
+ task: (task2) => [[-Infinity, Infinity], task2, -1],
2851
+ taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
2852
+ },
2853
+ {
2854
+ task: [Function],
2855
+ taskTimeout: [Function, Number],
2856
+ rangeTask: [Array, Function],
2857
+ rangeTaskTimeout: [Array, Function, Number]
2858
+ }
2859
+ );
2860
+ return this._lock(
2861
+ this.writeQueue,
2862
+ range,
2863
+ timeout,
2864
+ task,
2865
+ () => {
2866
+ return !this.rangeOverlapping(this.writings, range) && !this.rangeOverlapping(this.readings, range);
2867
+ }
2868
+ );
2869
+ }
2870
+ /**
2871
+ * Releases a read lock by its lock ID.
2872
+ * @param lockId - The unique identifier for the lock to release.
2873
+ */
2874
+ readUnlock(lockId) {
2875
+ this._free(this.readings, lockId);
2876
+ }
2877
+ /**
2878
+ * Releases a write lock by its lock ID.
2879
+ * @param lockId - The unique identifier for the lock to release.
2880
+ */
2881
+ writeUnlock(lockId) {
2882
+ this._free(this.writings, lockId);
2883
+ }
2884
+ };
2885
+
2886
+ // src/transaction/BPTreeAsyncTransaction.ts
2887
+ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
2888
+ lock;
2889
+ constructor(rootTx, mvccRoot, mvcc, strategy, comparator, option) {
2890
+ super(
2891
+ rootTx,
2892
+ mvccRoot,
2893
+ mvcc,
2894
+ strategy,
2895
+ comparator,
2896
+ option
2897
+ );
2898
+ this.lock = new Ryoiki2();
2899
+ }
2900
+ async writeLock(id, fn) {
2901
+ let lockId;
2902
+ return this.lock.writeLock([id, id + 0.1], async (_lockId) => {
2903
+ lockId = _lockId;
2904
+ return fn();
2905
+ }).finally(() => {
2906
+ this.lock.writeUnlock(lockId);
2907
+ });
2908
+ }
2909
+ async getNode(id) {
2910
+ if (this.nodes.has(id)) {
2911
+ return this.nodes.get(id);
2912
+ }
2913
+ return await this.mvcc.read(id);
2914
+ }
2915
+ /**
2916
+ * Create a new node with a unique ID.
2917
+ */
2918
+ async _createNode(leaf, keys, values, parent = null, next = null, prev = null) {
2919
+ const id = await this.strategy.id(leaf);
2920
+ const node = {
2921
+ id,
2922
+ keys,
2923
+ values,
2924
+ leaf,
2925
+ parent,
2926
+ next,
2927
+ prev
2928
+ };
2929
+ await this.mvcc.create(id, node);
2930
+ this.nodes.set(id, node);
2931
+ return node;
2932
+ }
2933
+ async _updateNode(node) {
2934
+ await this.mvcc.write(node.id, node);
2935
+ this.nodes.set(node.id, node);
2936
+ }
2937
+ async _deleteNode(node) {
2938
+ await this.mvcc.delete(node.id);
2939
+ this.nodes.delete(node.id);
2940
+ }
2941
+ async _readHead() {
2942
+ if (this.nodes.has("__HEAD__")) {
2943
+ return this.nodes.get("__HEAD__") ?? null;
2944
+ }
2945
+ const head = await this.mvcc.read("__HEAD__");
2946
+ return head ?? null;
2947
+ }
2948
+ async _writeHead(head) {
2949
+ if (!await this.mvcc.exists("__HEAD__")) {
2950
+ await this.mvcc.create("__HEAD__", head);
2951
+ } else {
2952
+ await this.mvcc.write("__HEAD__", head);
2953
+ }
2954
+ this.nodes.set("__HEAD__", head);
2955
+ this.rootId = head.root;
2956
+ }
2957
+ async _insertAtLeaf(node, key, value) {
2958
+ if (node.values.length) {
2959
+ for (let i = 0, len = node.values.length; i < len; i++) {
2960
+ const nValue = node.values[i];
2961
+ if (this.comparator.isSame(value, nValue)) {
2962
+ const keys = node.keys[i];
2963
+ if (keys.includes(key)) {
2964
+ break;
2965
+ }
2966
+ keys.push(key);
2967
+ await this._updateNode(node);
2968
+ return;
2969
+ } else if (this.comparator.isLower(value, nValue)) {
2970
+ node.values.splice(i, 0, value);
2971
+ node.keys.splice(i, 0, [key]);
2972
+ await this._updateNode(node);
2973
+ return;
2974
+ } else if (i + 1 === node.values.length) {
2975
+ node.values.push(value);
2976
+ node.keys.push([key]);
2977
+ await this._updateNode(node);
2978
+ return;
2979
+ }
2980
+ }
2981
+ } else {
2982
+ node.values = [value];
2983
+ node.keys = [[key]];
2984
+ await this._updateNode(node);
2985
+ return;
2986
+ }
2987
+ }
2988
+ async _insertInParent(node, value, pointer) {
2989
+ if (this.rootId === node.id) {
2990
+ const root = await this._createNode(false, [node.id, pointer.id], [value]);
2991
+ this.rootId = root.id;
2992
+ node.parent = root.id;
2993
+ pointer.parent = root.id;
2994
+ if (pointer.leaf) {
2995
+ node.next = pointer.id;
2996
+ pointer.prev = node.id;
2997
+ }
2998
+ await this._writeHead({
2999
+ root: root.id,
3000
+ order: this.order,
3001
+ data: this.strategy.head.data
3002
+ });
3003
+ await this._updateNode(node);
3004
+ await this._updateNode(pointer);
3005
+ return;
3006
+ }
3007
+ const parentNode = await this.getNode(node.parent);
3008
+ const nodeIndex = parentNode.keys.indexOf(node.id);
3009
+ if (nodeIndex === -1) {
3010
+ throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
3011
+ }
3012
+ parentNode.values.splice(nodeIndex, 0, value);
3013
+ parentNode.keys.splice(nodeIndex + 1, 0, pointer.id);
3014
+ pointer.parent = parentNode.id;
3015
+ if (pointer.leaf) {
3016
+ const leftSibling = node;
3017
+ const oldNextId = leftSibling.next;
3018
+ pointer.prev = leftSibling.id;
3019
+ pointer.next = oldNextId;
3020
+ leftSibling.next = pointer.id;
3021
+ await this._updateNode(leftSibling);
3022
+ if (oldNextId) {
3023
+ const oldNext = await this.getNode(oldNextId);
3024
+ oldNext.prev = pointer.id;
3025
+ await this._updateNode(oldNext);
3026
+ }
3027
+ }
3028
+ await this._updateNode(parentNode);
3029
+ await this._updateNode(pointer);
3030
+ if (parentNode.keys.length > this.order) {
3031
+ const parentPointer = await this._createNode(false, [], []);
3032
+ parentPointer.parent = parentNode.parent;
3033
+ const mid = Math.ceil(this.order / 2) - 1;
3034
+ parentPointer.values = parentNode.values.slice(mid + 1);
3035
+ parentPointer.keys = parentNode.keys.slice(mid + 1);
3036
+ const midValue = parentNode.values[mid];
3037
+ parentNode.values = parentNode.values.slice(0, mid);
3038
+ parentNode.keys = parentNode.keys.slice(0, mid + 1);
3039
+ for (const k of parentNode.keys) {
3040
+ const n = await this.getNode(k);
3041
+ n.parent = parentNode.id;
3042
+ await this._updateNode(n);
3043
+ }
3044
+ for (const k of parentPointer.keys) {
3045
+ const n = await this.getNode(k);
3046
+ n.parent = parentPointer.id;
3047
+ await this._updateNode(n);
3048
+ }
3049
+ await this._updateNode(parentNode);
3050
+ await this._insertInParent(parentNode, midValue, parentPointer);
3051
+ }
3052
+ }
3053
+ async insertableNode(value) {
3054
+ let node = await this.getNode(this.rootId);
3055
+ while (!node.leaf) {
3056
+ const { index } = this._binarySearchValues(node.values, value, false, true);
3057
+ node = await this.getNode(node.keys[index]);
3058
+ }
3059
+ return node;
3060
+ }
3061
+ async insertableNodeByPrimary(value) {
3062
+ let node = await this.getNode(this.rootId);
3063
+ while (!node.leaf) {
3064
+ const { index } = this._binarySearchValues(node.values, value, true, false);
3065
+ node = await this.getNode(node.keys[index]);
3066
+ }
3067
+ return node;
3068
+ }
3069
+ async insertableRightestNodeByPrimary(value) {
3070
+ let node = await this.getNode(this.rootId);
3071
+ while (!node.leaf) {
3072
+ const { index } = this._binarySearchValues(node.values, value, true, true);
3073
+ node = await this.getNode(node.keys[index]);
3074
+ }
3075
+ return node;
3076
+ }
3077
+ async insertableRightestEndNodeByPrimary(value) {
3078
+ const node = await this.insertableRightestNodeByPrimary(value);
3079
+ if (!node.next) {
3080
+ return null;
3081
+ }
3082
+ return await this.getNode(node.next);
3083
+ }
3084
+ async insertableEndNode(value, direction) {
3085
+ const insertableNode = await this.insertableNode(value);
3086
+ let key;
3087
+ switch (direction) {
3088
+ case -1:
3089
+ key = "prev";
3090
+ break;
3091
+ case 1:
3092
+ key = "next";
3093
+ break;
3094
+ default:
3095
+ throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
3096
+ }
3097
+ const guessNode = insertableNode[key];
3098
+ if (!guessNode) {
3099
+ return null;
3100
+ }
3101
+ return await this.getNode(guessNode);
3102
+ }
3103
+ async leftestNode() {
3104
+ let node = await this.getNode(this.rootId);
3105
+ if (node === null) {
3106
+ debugger;
3107
+ }
3108
+ while (!node.leaf) {
3109
+ const keys = node.keys;
3110
+ node = await this.getNode(keys[0]);
3111
+ }
3112
+ return node;
3113
+ }
3114
+ async rightestNode() {
3115
+ let node = await this.getNode(this.rootId);
3116
+ while (!node.leaf) {
3117
+ const keys = node.keys;
3118
+ node = await this.getNode(keys[keys.length - 1]);
3119
+ }
3120
+ return node;
3121
+ }
3122
+ async *getPairsGenerator(value, startNode, endNode, comparator, direction, earlyTerminate) {
3123
+ let node = startNode;
3124
+ let done = false;
3125
+ let hasMatched = false;
3126
+ let nextNodePromise = null;
3127
+ while (!done) {
3128
+ if (endNode && node.id === endNode.id) {
3129
+ done = true;
3130
+ break;
2830
3131
  }
2831
3132
  if (direction === 1) {
2832
3133
  if (node.next && !done) {
@@ -2882,28 +3183,46 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
2882
3183
  }
2883
3184
  }
2884
3185
  async init() {
2885
- this.clear();
2886
- const head = await this._readHead();
2887
- if (head === null) {
2888
- this.order = this.strategy.order;
2889
- const root = await this._createNode(true, [], []);
2890
- await this._writeHead({
2891
- root: root.id,
2892
- order: this.order,
2893
- data: this.strategy.head.data
2894
- });
2895
- } else {
2896
- const { root, order } = head;
2897
- this.strategy.head = head;
2898
- this.order = order;
2899
- await this._writeHead({
2900
- root,
2901
- order: this.order,
2902
- data: this.strategy.head.data
2903
- });
3186
+ if (this.rootTx !== this) {
3187
+ throw new Error("Cannot call init on a nested transaction");
2904
3188
  }
2905
- if (this.order < 3) {
2906
- throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
3189
+ return await this._initInternal();
3190
+ }
3191
+ async _initInternal() {
3192
+ if (this.isInitialized) {
3193
+ throw new Error("Transaction already initialized");
3194
+ }
3195
+ if (this.isDestroyed) {
3196
+ throw new Error("Transaction already destroyed");
3197
+ }
3198
+ this.isInitialized = true;
3199
+ try {
3200
+ this._clearCache();
3201
+ const head = await this._readHead();
3202
+ if (head === null) {
3203
+ this.order = this.strategy.order;
3204
+ const root = await this._createNode(true, [], []);
3205
+ await this._writeHead({
3206
+ root: root.id,
3207
+ order: this.order,
3208
+ data: this.strategy.head.data
3209
+ });
3210
+ } else {
3211
+ const { root, order } = head;
3212
+ this.strategy.head = head;
3213
+ this.order = order;
3214
+ await this._writeHead({
3215
+ root,
3216
+ order: this.order,
3217
+ data: this.strategy.head.data
3218
+ });
3219
+ }
3220
+ if (this.order < 3) {
3221
+ throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
3222
+ }
3223
+ } catch (e) {
3224
+ this.isInitialized = false;
3225
+ throw e;
2907
3226
  }
2908
3227
  }
2909
3228
  async exists(key, value) {
@@ -3003,38 +3322,40 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3003
3322
  }
3004
3323
  }
3005
3324
  async keys(condition, filterValues, order = "asc") {
3006
- const set = /* @__PURE__ */ new Set();
3007
- for await (const key of this.keysStream(condition, filterValues, void 0, order)) {
3008
- set.add(key);
3009
- }
3010
- return set;
3011
- }
3012
- async where(condition, order = "asc") {
3013
- const map = /* @__PURE__ */ new Map();
3014
- for await (const [key, value] of this.whereStream(condition, void 0, order)) {
3015
- map.set(key, value);
3016
- }
3017
- return map;
3018
- }
3019
- async insert(key, value) {
3020
- const before = await this.insertableNode(value);
3021
- await this._insertAtLeaf(before, key, value);
3022
- if (before.values.length === this.order) {
3023
- const after = await this._createNode(
3024
- true,
3025
- [],
3026
- [],
3027
- before.parent,
3028
- null,
3029
- null
3030
- );
3031
- const mid = Math.ceil(this.order / 2) - 1;
3032
- after.values = before.values.slice(mid + 1);
3033
- after.keys = before.keys.slice(mid + 1);
3034
- before.values = before.values.slice(0, mid + 1);
3035
- before.keys = before.keys.slice(0, mid + 1);
3036
- await this._insertInParent(before, after.values[0], after);
3325
+ const set = /* @__PURE__ */ new Set();
3326
+ for await (const key of this.keysStream(condition, filterValues, void 0, order)) {
3327
+ set.add(key);
3328
+ }
3329
+ return set;
3330
+ }
3331
+ async where(condition, order = "asc") {
3332
+ const map = /* @__PURE__ */ new Map();
3333
+ for await (const [key, value] of this.whereStream(condition, void 0, order)) {
3334
+ map.set(key, value);
3037
3335
  }
3336
+ return map;
3337
+ }
3338
+ async insert(key, value) {
3339
+ return this.writeLock(0, async () => {
3340
+ const before = await this.insertableNode(value);
3341
+ await this._insertAtLeaf(before, key, value);
3342
+ if (before.values.length === this.order) {
3343
+ const after = await this._createNode(
3344
+ true,
3345
+ [],
3346
+ [],
3347
+ before.parent,
3348
+ null,
3349
+ null
3350
+ );
3351
+ const mid = Math.ceil(this.order / 2) - 1;
3352
+ after.values = before.values.slice(mid + 1);
3353
+ after.keys = before.keys.slice(mid + 1);
3354
+ before.values = before.values.slice(0, mid + 1);
3355
+ before.keys = before.keys.slice(0, mid + 1);
3356
+ await this._insertInParent(before, after.values[0], after);
3357
+ }
3358
+ });
3038
3359
  }
3039
3360
  async _deleteEntry(node, key) {
3040
3361
  if (!node.leaf) {
@@ -3227,35 +3548,37 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3227
3548
  }
3228
3549
  }
3229
3550
  async delete(key, value) {
3230
- let node = await this.insertableNodeByPrimary(value);
3231
- let found = false;
3232
- while (true) {
3233
- let i = node.values.length;
3234
- while (i--) {
3235
- const nValue = node.values[i];
3236
- if (this.comparator.isSame(value, nValue)) {
3237
- const keys = node.keys[i];
3238
- const keyIndex = keys.indexOf(key);
3239
- if (keyIndex !== -1) {
3240
- keys.splice(keyIndex, 1);
3241
- if (keys.length === 0) {
3242
- node.keys.splice(i, 1);
3243
- node.values.splice(i, 1);
3551
+ return this.writeLock(0, async () => {
3552
+ let node = await this.insertableNodeByPrimary(value);
3553
+ let found = false;
3554
+ while (true) {
3555
+ let i = node.values.length;
3556
+ while (i--) {
3557
+ const nValue = node.values[i];
3558
+ if (this.comparator.isSame(value, nValue)) {
3559
+ const keys = node.keys[i];
3560
+ const keyIndex = keys.indexOf(key);
3561
+ if (keyIndex !== -1) {
3562
+ keys.splice(keyIndex, 1);
3563
+ if (keys.length === 0) {
3564
+ node.keys.splice(i, 1);
3565
+ node.values.splice(i, 1);
3566
+ }
3567
+ await this._updateNode(node);
3568
+ await this._deleteEntry(node, key);
3569
+ found = true;
3570
+ break;
3244
3571
  }
3245
- await this._updateNode(node);
3246
- await this._deleteEntry(node, key);
3247
- found = true;
3248
- break;
3249
3572
  }
3250
3573
  }
3574
+ if (found) break;
3575
+ if (node.next) {
3576
+ node = await this.getNode(node.next);
3577
+ continue;
3578
+ }
3579
+ break;
3251
3580
  }
3252
- if (found) break;
3253
- if (node.next) {
3254
- node = await this.getNode(node.next);
3255
- continue;
3256
- }
3257
- break;
3258
- }
3581
+ });
3259
3582
  }
3260
3583
  async getHeadData() {
3261
3584
  const head = await this._readHead();
@@ -3278,9 +3601,12 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3278
3601
  async commit(label) {
3279
3602
  let result = await this.mvcc.commit(label);
3280
3603
  if (result.success) {
3281
- result = await this.mvccRoot.commit(label);
3282
- if (result.success && this.rootTx !== this) {
3283
- this.rootTx.rootId = this.rootId;
3604
+ const isRootTx = this.rootTx === this;
3605
+ if (!isRootTx) {
3606
+ result = await this.rootTx.commit(label);
3607
+ if (result.success) {
3608
+ this.rootTx.rootId = this.rootId;
3609
+ }
3284
3610
  }
3285
3611
  if (result.success) {
3286
3612
  for (const r of result.created) {
@@ -3316,397 +3642,141 @@ var BPTreeMVCCStrategyAsync = class extends AsyncMVCCStrategy {
3316
3642
  async write(key, value) {
3317
3643
  if (key === "__HEAD__") {
3318
3644
  await this.strategy.writeHead(value);
3319
- } else {
3320
- await this.strategy.write(key, value);
3321
- }
3322
- }
3323
- async delete(key) {
3324
- await this.strategy.delete(key);
3325
- }
3326
- async exists(key) {
3327
- if (key === "__HEAD__") {
3328
- return await this.strategy.readHead() !== null;
3329
- }
3330
- try {
3331
- const node = await this.strategy.read(key);
3332
- return node !== null && node !== void 0;
3333
- } catch {
3334
- return false;
3335
- }
3336
- }
3337
- };
3338
-
3339
- // src/BPTreeAsync.ts
3340
- var BPTreeAsync = class extends BPTreeAsyncTransaction {
3341
- constructor(strategy, comparator, option) {
3342
- const mvccRoot = new AsyncMVCCTransaction(new BPTreeMVCCStrategyAsync(strategy));
3343
- super(
3344
- null,
3345
- mvccRoot,
3346
- mvccRoot,
3347
- strategy,
3348
- comparator,
3349
- option
3350
- );
3351
- }
3352
- /**
3353
- * Creates a new asynchronous transaction.
3354
- * @returns A new BPTreeAsyncTransaction.
3355
- */
3356
- async createTransaction() {
3357
- const nestedTx = await this.mvcc.createNested();
3358
- const tx = new BPTreeAsyncTransaction(
3359
- this,
3360
- this.mvcc,
3361
- nestedTx,
3362
- this.strategy,
3363
- this.comparator,
3364
- this.option
3365
- );
3366
- await tx.init();
3367
- return tx;
3368
- }
3369
- async insert(key, value) {
3370
- const tx = await this.createTransaction();
3371
- await tx.insert(key, value);
3372
- const result = await tx.commit();
3373
- if (!result.success) {
3374
- throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
3375
- }
3376
- this.rootId = tx.getRootId();
3377
- }
3378
- async delete(key, value) {
3379
- const tx = await this.createTransaction();
3380
- await tx.delete(key, value);
3381
- const result = await tx.commit();
3382
- if (!result.success) {
3383
- throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
3384
- }
3385
- this.rootId = tx.getRootId();
3386
- }
3387
- };
3388
-
3389
- // src/base/SerializeStrategy.ts
3390
- var SerializeStrategy = class {
3391
- order;
3392
- head;
3393
- constructor(order) {
3394
- this.order = order;
3395
- this.head = {
3396
- order,
3397
- root: null,
3398
- data: {}
3399
- };
3400
- }
3401
- };
3402
-
3403
- // src/SerializeStrategySync.ts
3404
- var SerializeStrategySync = class extends SerializeStrategy {
3405
- getHeadData(key, defaultValue) {
3406
- if (!Object.hasOwn(this.head.data, key)) {
3407
- this.setHeadData(key, defaultValue);
3408
- }
3409
- return this.head.data[key];
3410
- }
3411
- setHeadData(key, data) {
3412
- this.head.data[key] = data;
3413
- this.writeHead(this.head);
3414
- }
3415
- autoIncrement(key, defaultValue) {
3416
- const current = this.getHeadData(key, defaultValue);
3417
- const next = current + 1;
3418
- this.setHeadData(key, next);
3419
- return current;
3420
- }
3421
- };
3422
- var InMemoryStoreStrategySync = class extends SerializeStrategySync {
3423
- node;
3424
- constructor(order) {
3425
- super(order);
3426
- this.node = {};
3427
- }
3428
- id(isLeaf) {
3429
- return this.autoIncrement("index", 1).toString();
3430
- }
3431
- read(id) {
3432
- if (!Object.hasOwn(this.node, id)) {
3433
- throw new Error(`The tree attempted to reference node '${id}', but couldn't find the corresponding node.`);
3434
- }
3435
- const node = this.node[id];
3436
- return JSON.parse(JSON.stringify(node));
3437
- }
3438
- write(id, node) {
3439
- this.node[id] = node;
3440
- }
3441
- delete(id) {
3442
- delete this.node[id];
3443
- }
3444
- readHead() {
3445
- if (this.head.root === null) {
3446
- return null;
3447
- }
3448
- return this.head;
3449
- }
3450
- writeHead(head) {
3451
- this.head = head;
3452
- }
3453
- };
3454
-
3455
- // node_modules/ryoiki/dist/esm/index.mjs
3456
- var Ryoiki2 = class _Ryoiki2 {
3457
- readings;
3458
- writings;
3459
- readQueue;
3460
- writeQueue;
3461
- static async CatchError(promise) {
3462
- return await promise.then((v) => [void 0, v]).catch((err) => [err]);
3463
- }
3464
- static IsRangeOverlap(a, b) {
3465
- const [start1, end1] = a;
3466
- const [start2, end2] = b;
3467
- if (end1 <= start2 || end2 <= start1) {
3468
- return false;
3469
- }
3470
- return true;
3471
- }
3472
- static ERR_ALREADY_EXISTS(lockId) {
3473
- return new Error(`The '${lockId}' task already existing in queue or running.`);
3474
- }
3475
- static ERR_NOT_EXISTS(lockId) {
3476
- return new Error(`The '${lockId}' task not existing in task queue.`);
3477
- }
3478
- static ERR_TIMEOUT(lockId, timeout) {
3479
- return new Error(`The task with ID '${lockId}' failed to acquire the lock within the timeout(${timeout}ms).`);
3480
- }
3481
- /**
3482
- * Constructs a new instance of the Ryoiki class.
3483
- */
3484
- constructor() {
3485
- this.readings = /* @__PURE__ */ new Map();
3486
- this.writings = /* @__PURE__ */ new Map();
3487
- this.readQueue = /* @__PURE__ */ new Map();
3488
- this.writeQueue = /* @__PURE__ */ new Map();
3489
- }
3490
- /**
3491
- * Creates a range based on a start value and length.
3492
- * @param start - The starting value of the range.
3493
- * @param length - The length of the range.
3494
- * @returns A range tuple [start, start + length].
3495
- */
3496
- range(start, length) {
3497
- return [start, start + length];
3498
- }
3499
- rangeOverlapping(tasks, range) {
3500
- return Array.from(tasks.values()).some((t) => _Ryoiki2.IsRangeOverlap(t.range, range));
3501
- }
3502
- isSameRange(a, b) {
3503
- const [a1, a2] = a;
3504
- const [b1, b2] = b;
3505
- return a1 === b1 && a2 === b2;
3506
- }
3507
- fetchUnitAndRun(queue, workspaces) {
3508
- for (const [id, unit] of queue) {
3509
- if (!unit.condition()) {
3510
- continue;
3511
- }
3512
- this._alloc(queue, workspaces, id);
3513
- }
3514
- }
3515
- _handleOverload(args, handlers, argPatterns) {
3516
- for (const [key, pattern] of Object.entries(argPatterns)) {
3517
- if (this._matchArgs(args, pattern)) {
3518
- return handlers[key](...args);
3519
- }
3520
- }
3521
- throw new Error("Invalid arguments");
3522
- }
3523
- _matchArgs(args, pattern) {
3524
- return args.every((arg, index) => {
3525
- const expectedType = pattern[index];
3526
- if (expectedType === void 0) return typeof arg === "undefined";
3527
- if (expectedType === Function) return typeof arg === "function";
3528
- if (expectedType === Number) return typeof arg === "number";
3529
- if (expectedType === Array) return Array.isArray(arg);
3530
- return false;
3531
- });
3532
- }
3533
- _createRandomId() {
3534
- const timestamp = Date.now().toString(36);
3535
- const random = Math.random().toString(36).substring(2);
3536
- return `${timestamp}${random}`;
3537
- }
3538
- _alloc(queue, workspaces, lockId) {
3539
- const unit = queue.get(lockId);
3540
- if (!unit) {
3541
- throw _Ryoiki2.ERR_NOT_EXISTS(lockId);
3645
+ } else {
3646
+ await this.strategy.write(key, value);
3542
3647
  }
3543
- workspaces.set(lockId, unit);
3544
- queue.delete(lockId);
3545
- unit.alloc();
3546
3648
  }
3547
- _free(workspaces, lockId) {
3548
- const unit = workspaces.get(lockId);
3549
- if (!unit) {
3550
- throw _Ryoiki2.ERR_NOT_EXISTS(lockId);
3649
+ async delete(key) {
3650
+ await this.strategy.delete(key);
3651
+ }
3652
+ async exists(key) {
3653
+ if (key === "__HEAD__") {
3654
+ return await this.strategy.readHead() !== null;
3655
+ }
3656
+ try {
3657
+ const node = await this.strategy.read(key);
3658
+ return node !== null && node !== void 0;
3659
+ } catch {
3660
+ return false;
3551
3661
  }
3552
- workspaces.delete(lockId);
3553
- unit.free();
3554
3662
  }
3555
- _lock(queue, range, timeout, task, condition) {
3556
- return new Promise((resolve, reject) => {
3557
- let timeoutId = null;
3558
- if (timeout >= 0) {
3559
- timeoutId = setTimeout(() => {
3560
- reject(_Ryoiki2.ERR_TIMEOUT(id, timeout));
3561
- }, timeout);
3663
+ };
3664
+
3665
+ // src/BPTreeAsync.ts
3666
+ var BPTreeAsync = class extends BPTreeAsyncTransaction {
3667
+ constructor(strategy, comparator, option) {
3668
+ const mvccRoot = new AsyncMVCCTransaction(new BPTreeMVCCStrategyAsync(strategy));
3669
+ super(
3670
+ null,
3671
+ mvccRoot,
3672
+ mvccRoot,
3673
+ strategy,
3674
+ comparator,
3675
+ option
3676
+ );
3677
+ }
3678
+ /**
3679
+ * Creates a new asynchronous transaction.
3680
+ * @returns A new BPTreeAsyncTransaction.
3681
+ */
3682
+ async createTransaction() {
3683
+ const nestedTx = this.mvcc.createNested();
3684
+ const tx = new BPTreeAsyncTransaction(
3685
+ this,
3686
+ this.mvcc,
3687
+ nestedTx,
3688
+ this.strategy,
3689
+ this.comparator,
3690
+ this.option
3691
+ );
3692
+ await tx._initInternal();
3693
+ return tx;
3694
+ }
3695
+ async insert(key, value) {
3696
+ return this.writeLock(1, async () => {
3697
+ const tx = await this.createTransaction();
3698
+ await tx.insert(key, value);
3699
+ const result = await tx.commit();
3700
+ if (!result.success) {
3701
+ throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
3562
3702
  }
3563
- const id = this._createRandomId();
3564
- const alloc = async () => {
3565
- if (timeoutId !== null) {
3566
- clearTimeout(timeoutId);
3567
- }
3568
- const [err, v] = await _Ryoiki2.CatchError(task(id));
3569
- if (err) reject(err);
3570
- else resolve(v);
3571
- };
3572
- const fetch = () => {
3573
- this.fetchUnitAndRun(this.readQueue, this.readings);
3574
- this.fetchUnitAndRun(this.writeQueue, this.writings);
3575
- };
3576
- queue.set(id, { id, range, condition, alloc, free: fetch });
3577
- fetch();
3578
3703
  });
3579
3704
  }
3580
- _checkWorking(range, workspaces) {
3581
- let isLocked = false;
3582
- for (const lock of workspaces.values()) {
3583
- if (_Ryoiki2.IsRangeOverlap(range, lock.range)) {
3584
- isLocked = true;
3585
- break;
3705
+ async delete(key, value) {
3706
+ return this.writeLock(1, async () => {
3707
+ const tx = await this.createTransaction();
3708
+ await tx.delete(key, value);
3709
+ const result = await tx.commit();
3710
+ if (!result.success) {
3711
+ throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
3586
3712
  }
3713
+ });
3714
+ }
3715
+ };
3716
+
3717
+ // src/base/SerializeStrategy.ts
3718
+ var SerializeStrategy = class {
3719
+ order;
3720
+ head;
3721
+ constructor(order) {
3722
+ this.order = order;
3723
+ this.head = {
3724
+ order,
3725
+ root: null,
3726
+ data: {}
3727
+ };
3728
+ }
3729
+ };
3730
+
3731
+ // src/SerializeStrategySync.ts
3732
+ var SerializeStrategySync = class extends SerializeStrategy {
3733
+ getHeadData(key, defaultValue) {
3734
+ if (!Object.hasOwn(this.head.data, key)) {
3735
+ this.setHeadData(key, defaultValue);
3587
3736
  }
3588
- return isLocked;
3737
+ return this.head.data[key];
3589
3738
  }
3590
- /**
3591
- * Checks if there is any active read lock within the specified range.
3592
- * @param range The range to check for active read locks.
3593
- * @returns `true` if there is an active read lock within the range, `false` otherwise.
3594
- */
3595
- isReading(range) {
3596
- return this._checkWorking(range, this.readings);
3739
+ setHeadData(key, data) {
3740
+ this.head.data[key] = data;
3741
+ this.writeHead(this.head);
3597
3742
  }
3598
- /**
3599
- * Checks if there is any active write lock within the specified range.
3600
- * @param range The range to check for active write locks.
3601
- * @returns `true` if there is an active write lock within the range, `false` otherwise.
3602
- */
3603
- isWriting(range) {
3604
- return this._checkWorking(range, this.writings);
3743
+ autoIncrement(key, defaultValue) {
3744
+ const current = this.getHeadData(key, defaultValue);
3745
+ const next = current + 1;
3746
+ this.setHeadData(key, next);
3747
+ return current;
3605
3748
  }
3606
- /**
3607
- * Checks if a read lock can be acquired within the specified range.
3608
- * @param range The range to check for read lock availability.
3609
- * @returns `true` if a read lock can be acquired, `false` otherwise.
3610
- */
3611
- canRead(range) {
3612
- const writing = this.isWriting(range);
3613
- return !writing;
3749
+ };
3750
+ var InMemoryStoreStrategySync = class extends SerializeStrategySync {
3751
+ node;
3752
+ constructor(order) {
3753
+ super(order);
3754
+ this.node = {};
3614
3755
  }
3615
- /**
3616
- * Checks if a write lock can be acquired within the specified range.
3617
- * @param range The range to check for write lock availability.
3618
- * @returns `true` if a write lock can be acquired, `false` otherwise.
3619
- */
3620
- canWrite(range) {
3621
- const reading = this.isReading(range);
3622
- const writing = this.isWriting(range);
3623
- return !reading && !writing;
3756
+ id(isLeaf) {
3757
+ return this.autoIncrement("index", 1).toString();
3624
3758
  }
3625
- /**
3626
- * Internal implementation of the read lock. Handles both overloads.
3627
- * @template T - The return type of the task.
3628
- * @param arg0 - Either a range or a task callback.
3629
- * If a range is provided, the task is the second argument.
3630
- * @param arg1 - The task to execute, required if a range is provided.
3631
- * @param arg2 - The timeout for acquiring the lock.
3632
- * If the lock cannot be acquired within this period, an error will be thrown.
3633
- * If this value is not provided, no timeout will be set.
3634
- * @returns A promise resolving to the result of the task execution.
3635
- */
3636
- readLock(arg0, arg1, arg2) {
3637
- const [range, task, timeout] = this._handleOverload(
3638
- [arg0, arg1, arg2],
3639
- {
3640
- rangeTask: (range2, task2) => [range2, task2, -1],
3641
- rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
3642
- task: (task2) => [[-Infinity, Infinity], task2, -1],
3643
- taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
3644
- },
3645
- {
3646
- task: [Function],
3647
- taskTimeout: [Function, Number],
3648
- rangeTask: [Array, Function],
3649
- rangeTaskTimeout: [Array, Function, Number]
3650
- }
3651
- );
3652
- return this._lock(
3653
- this.readQueue,
3654
- range,
3655
- timeout,
3656
- task,
3657
- () => !this.rangeOverlapping(this.writings, range)
3658
- );
3759
+ read(id) {
3760
+ if (!Object.hasOwn(this.node, id)) {
3761
+ throw new Error(`The tree attempted to reference node '${id}', but couldn't find the corresponding node.`);
3762
+ }
3763
+ const node = this.node[id];
3764
+ return JSON.parse(JSON.stringify(node));
3659
3765
  }
3660
- /**
3661
- * Internal implementation of the write lock. Handles both overloads.
3662
- * @template T - The return type of the task.
3663
- * @param arg0 - Either a range or a task callback.
3664
- * If a range is provided, the task is the second argument.
3665
- * @param arg1 - The task to execute, required if a range is provided.
3666
- * @param arg2 - The timeout for acquiring the lock.
3667
- * If the lock cannot be acquired within this period, an error will be thrown.
3668
- * If this value is not provided, no timeout will be set.
3669
- * @returns A promise resolving to the result of the task execution.
3670
- */
3671
- writeLock(arg0, arg1, arg2) {
3672
- const [range, task, timeout] = this._handleOverload(
3673
- [arg0, arg1, arg2],
3674
- {
3675
- rangeTask: (range2, task2) => [range2, task2, -1],
3676
- rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
3677
- task: (task2) => [[-Infinity, Infinity], task2, -1],
3678
- taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
3679
- },
3680
- {
3681
- task: [Function],
3682
- taskTimeout: [Function, Number],
3683
- rangeTask: [Array, Function],
3684
- rangeTaskTimeout: [Array, Function, Number]
3685
- }
3686
- );
3687
- return this._lock(
3688
- this.writeQueue,
3689
- range,
3690
- timeout,
3691
- task,
3692
- () => {
3693
- return !this.rangeOverlapping(this.writings, range) && !this.rangeOverlapping(this.readings, range);
3694
- }
3695
- );
3766
+ write(id, node) {
3767
+ this.node[id] = node;
3696
3768
  }
3697
- /**
3698
- * Releases a read lock by its lock ID.
3699
- * @param lockId - The unique identifier for the lock to release.
3700
- */
3701
- readUnlock(lockId) {
3702
- this._free(this.readings, lockId);
3769
+ delete(id) {
3770
+ delete this.node[id];
3703
3771
  }
3704
- /**
3705
- * Releases a write lock by its lock ID.
3706
- * @param lockId - The unique identifier for the lock to release.
3707
- */
3708
- writeUnlock(lockId) {
3709
- this._free(this.writings, lockId);
3772
+ readHead() {
3773
+ if (this.head.root === null) {
3774
+ return null;
3775
+ }
3776
+ return this.head;
3777
+ }
3778
+ writeHead(head) {
3779
+ this.head = head;
3710
3780
  }
3711
3781
  };
3712
3782