serializable-bptree 6.2.3 → 7.0.1

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.
@@ -21,7 +21,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
23
  BPTreeAsync: () => BPTreeAsync,
24
+ BPTreeAsyncTransaction: () => BPTreeAsyncTransaction,
24
25
  BPTreeSync: () => BPTreeSync,
26
+ BPTreeSyncTransaction: () => BPTreeSyncTransaction,
25
27
  InMemoryStoreStrategyAsync: () => InMemoryStoreStrategyAsync,
26
28
  InMemoryStoreStrategySync: () => InMemoryStoreStrategySync,
27
29
  NumericComparator: () => NumericComparator,
@@ -473,6 +475,20 @@ var BPTree = class _BPTree {
473
475
  option;
474
476
  order;
475
477
  rootId;
478
+ /**
479
+ * Returns the ID of the root node.
480
+ * @returns The root node ID.
481
+ */
482
+ getRootId() {
483
+ return this.rootId;
484
+ }
485
+ /**
486
+ * Returns the order of the B+Tree.
487
+ * @returns The order of the tree.
488
+ */
489
+ getOrder() {
490
+ return this.order;
491
+ }
476
492
  _strategyDirty;
477
493
  _nodeCreateBuffer;
478
494
  _nodeUpdateBuffer;
@@ -705,24 +721,21 @@ var BPTree = class _BPTree {
705
721
  break;
706
722
  }
707
723
  keys.push(key);
708
- this.bufferForNodeUpdate(node);
709
- break;
724
+ return this.bufferForNodeUpdate(node);
710
725
  } else if (this.comparator.isLower(value, nValue)) {
711
726
  node.values.splice(i, 0, value);
712
727
  node.keys.splice(i, 0, [key]);
713
- this.bufferForNodeUpdate(node);
714
- break;
728
+ return this.bufferForNodeUpdate(node);
715
729
  } else if (i + 1 === node.values.length) {
716
730
  node.values.push(value);
717
731
  node.keys.push([key]);
718
- this.bufferForNodeUpdate(node);
719
- break;
732
+ return this.bufferForNodeUpdate(node);
720
733
  }
721
734
  }
722
735
  } else {
723
736
  node.values = [value];
724
737
  node.keys = [[key]];
725
- this.bufferForNodeUpdate(node);
738
+ return this.bufferForNodeUpdate(node);
726
739
  }
727
740
  }
728
741
  bufferForNodeCreate(node) {
@@ -761,8 +774,8 @@ var BPTree = class _BPTree {
761
774
  }
762
775
  };
763
776
 
764
- // src/BPTreeSync.ts
765
- var BPTreeSync = class extends BPTree {
777
+ // src/base/BPTreeSyncBase.ts
778
+ var BPTreeSyncBase = class extends BPTree {
766
779
  constructor(strategy, comparator, option) {
767
780
  super(strategy, comparator, option);
768
781
  this.nodes = this._createCachedNode();
@@ -838,7 +851,7 @@ var BPTreeSync = class extends BPTree {
838
851
  }
839
852
  return id;
840
853
  }
841
- _createNode(isLeaf, keys, values, leaf = false, parent = null, next = null, prev = null) {
854
+ _createNode(isLeaf, keys, values, leaf = isLeaf, parent = null, next = null, prev = null) {
842
855
  const id = this._createNodeId(isLeaf);
843
856
  const node = {
844
857
  id,
@@ -849,29 +862,26 @@ var BPTreeSync = class extends BPTree {
849
862
  next,
850
863
  prev
851
864
  };
852
- this._nodeCreateBuffer.set(id, node);
865
+ this.bufferForNodeCreate(node);
853
866
  return node;
854
867
  }
855
868
  _deleteEntry(node, key, value) {
856
869
  if (!node.leaf) {
870
+ let keyIndex = -1;
857
871
  for (let i = 0, len = node.keys.length; i < len; i++) {
858
- const nKey = node.keys[i];
859
- if (nKey === key) {
860
- node.keys.splice(i, 1);
861
- this.bufferForNodeUpdate(node);
872
+ if (node.keys[i] === key) {
873
+ keyIndex = i;
862
874
  break;
863
875
  }
864
876
  }
865
- for (let i = 0, len = node.values.length; i < len; i++) {
866
- const nValue = node.values[i];
867
- if (this.comparator.isSame(value, nValue)) {
868
- node.values.splice(i, 1);
869
- this.bufferForNodeUpdate(node);
870
- break;
871
- }
877
+ if (keyIndex !== -1) {
878
+ node.keys.splice(keyIndex, 1);
879
+ const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
880
+ node.values.splice(valueIndex, 1);
881
+ this.bufferForNodeUpdate(node);
872
882
  }
873
883
  }
874
- if (this.rootId === node.id && node.keys.length === 1) {
884
+ if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
875
885
  const keys = node.keys;
876
886
  this.bufferForNodeDelete(node);
877
887
  const newRoot = this.getNode(keys[0]);
@@ -940,20 +950,11 @@ var BPTreeSync = class extends BPTree {
940
950
  pointer.values.push(guess);
941
951
  } else {
942
952
  pointer.next = node.next;
943
- pointer.prev = node.id;
944
953
  if (pointer.next) {
945
- const n = this.getNode(node.next);
954
+ const n = this.getNode(pointer.next);
946
955
  n.prev = pointer.id;
947
956
  this.bufferForNodeUpdate(n);
948
957
  }
949
- if (pointer.prev) {
950
- const n = this.getNode(node.id);
951
- n.next = pointer.id;
952
- this.bufferForNodeUpdate(n);
953
- }
954
- if (isPredecessor) {
955
- pointer.prev = null;
956
- }
957
958
  }
958
959
  pointer.values.push(...node.values);
959
960
  if (!pointer.leaf) {
@@ -977,13 +978,10 @@ var BPTreeSync = class extends BPTree {
977
978
  node.keys = [pointerPm, ...node.keys];
978
979
  node.values = [guess, ...node.values];
979
980
  parentNode = this.getNode(node.parent);
980
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
981
- const nValue = parentNode.values[i];
982
- if (this.comparator.isSame(guess, nValue)) {
983
- parentNode.values[i] = pointerKm;
984
- this.bufferForNodeUpdate(parentNode);
985
- break;
986
- }
981
+ const nodeIndex = parentNode.keys.indexOf(node.id);
982
+ if (nodeIndex > 0) {
983
+ parentNode.values[nodeIndex - 1] = pointerKm;
984
+ this.bufferForNodeUpdate(parentNode);
987
985
  }
988
986
  } else {
989
987
  pointerPm = pointer.keys.splice(-1)[0];
@@ -991,13 +989,10 @@ var BPTreeSync = class extends BPTree {
991
989
  node.keys = [pointerPm, ...node.keys];
992
990
  node.values = [pointerKm, ...node.values];
993
991
  parentNode = this.getNode(node.parent);
994
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
995
- const nValue = parentNode.values[i];
996
- if (this.comparator.isSame(guess, nValue)) {
997
- parentNode.values[i] = pointerKm;
998
- this.bufferForNodeUpdate(parentNode);
999
- break;
1000
- }
992
+ const nodeIndex = parentNode.keys.indexOf(node.id);
993
+ if (nodeIndex > 0) {
994
+ parentNode.values[nodeIndex - 1] = pointerKm;
995
+ this.bufferForNodeUpdate(parentNode);
1001
996
  }
1002
997
  }
1003
998
  this.bufferForNodeUpdate(node);
@@ -1011,13 +1006,10 @@ var BPTreeSync = class extends BPTree {
1011
1006
  node.keys = [...node.keys, pointerP0];
1012
1007
  node.values = [...node.values, guess];
1013
1008
  parentNode = this.getNode(node.parent);
1014
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
1015
- const nValue = parentNode.values[i];
1016
- if (this.comparator.isSame(guess, nValue)) {
1017
- parentNode.values[i] = pointerK0;
1018
- this.bufferForNodeUpdate(parentNode);
1019
- break;
1020
- }
1009
+ const pointerIndex = parentNode.keys.indexOf(pointer.id);
1010
+ if (pointerIndex > 0) {
1011
+ parentNode.values[pointerIndex - 1] = pointerK0;
1012
+ this.bufferForNodeUpdate(parentNode);
1021
1013
  }
1022
1014
  } else {
1023
1015
  pointerP0 = pointer.keys.splice(0, 1)[0];
@@ -1025,13 +1017,10 @@ var BPTreeSync = class extends BPTree {
1025
1017
  node.keys = [...node.keys, pointerP0];
1026
1018
  node.values = [...node.values, pointerK0];
1027
1019
  parentNode = this.getNode(node.parent);
1028
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
1029
- const nValue = parentNode.values[i];
1030
- if (this.comparator.isSame(guess, nValue)) {
1031
- parentNode.values[i] = pointer.values[0];
1032
- this.bufferForNodeUpdate(parentNode);
1033
- break;
1034
- }
1020
+ const pointerIndex = parentNode.keys.indexOf(pointer.id);
1021
+ if (pointerIndex > 0) {
1022
+ parentNode.values[pointerIndex - 1] = pointer.values[0];
1023
+ this.bufferForNodeUpdate(parentNode);
1035
1024
  }
1036
1025
  }
1037
1026
  this.bufferForNodeUpdate(node);
@@ -1059,6 +1048,8 @@ var BPTreeSync = class extends BPTree {
1059
1048
  }
1060
1049
  }
1061
1050
  }
1051
+ } else {
1052
+ this.bufferForNodeUpdate(node);
1062
1053
  }
1063
1054
  }
1064
1055
  _insertInParent(node, value, pointer) {
@@ -1077,31 +1068,25 @@ var BPTreeSync = class extends BPTree {
1077
1068
  return;
1078
1069
  }
1079
1070
  const parentNode = this.getNode(node.parent);
1080
- let insertIndex = 0;
1081
- for (let i = 0; i < parentNode.values.length; i++) {
1082
- if (this.comparator.asc(value, parentNode.values[i]) > 0) {
1083
- insertIndex = i + 1;
1084
- } else {
1085
- break;
1086
- }
1071
+ const nodeIndex = parentNode.keys.indexOf(node.id);
1072
+ if (nodeIndex === -1) {
1073
+ throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
1087
1074
  }
1075
+ const insertIndex = nodeIndex;
1088
1076
  parentNode.values.splice(insertIndex, 0, value);
1089
1077
  parentNode.keys.splice(insertIndex + 1, 0, pointer.id);
1090
1078
  pointer.parent = parentNode.id;
1091
1079
  if (pointer.leaf) {
1092
- const leftSiblingId = parentNode.keys[insertIndex];
1093
- const rightSiblingId = parentNode.keys[insertIndex + 2];
1094
- if (leftSiblingId) {
1095
- const leftSibling = this.getNode(leftSiblingId);
1096
- pointer.prev = leftSibling.id;
1097
- pointer.next = leftSibling.next;
1098
- leftSibling.next = pointer.id;
1099
- this.bufferForNodeUpdate(leftSibling);
1100
- }
1101
- if (rightSiblingId) {
1102
- const rightSibling = this.getNode(rightSiblingId);
1103
- rightSibling.prev = pointer.id;
1104
- this.bufferForNodeUpdate(rightSibling);
1080
+ const leftSibling = node;
1081
+ const oldNextId = leftSibling.next;
1082
+ pointer.prev = leftSibling.id;
1083
+ pointer.next = oldNextId;
1084
+ leftSibling.next = pointer.id;
1085
+ this.bufferForNodeUpdate(leftSibling);
1086
+ if (oldNextId) {
1087
+ const oldNext = this.getNode(oldNextId);
1088
+ oldNext.prev = pointer.id;
1089
+ this.bufferForNodeUpdate(oldNext);
1105
1090
  }
1106
1091
  }
1107
1092
  this.bufferForNodeUpdate(parentNode);
@@ -1130,6 +1115,7 @@ var BPTreeSync = class extends BPTree {
1130
1115
  }
1131
1116
  }
1132
1117
  init() {
1118
+ this.clear();
1133
1119
  const head = this.strategy.readHead();
1134
1120
  if (head === null) {
1135
1121
  this.order = this.strategy.order;
@@ -1160,42 +1146,72 @@ var BPTreeSync = class extends BPTree {
1160
1146
  }
1161
1147
  insertableNode(value) {
1162
1148
  let node = this.getNode(this.rootId);
1149
+ if (node.parent !== null) {
1150
+ node.parent = null;
1151
+ this.bufferForNodeUpdate(node);
1152
+ }
1163
1153
  while (!node.leaf) {
1154
+ const parentId = node.id;
1164
1155
  for (let i = 0, len = node.values.length; i < len; i++) {
1165
1156
  const nValue = node.values[i];
1166
1157
  const k = node.keys;
1167
1158
  if (this.comparator.isSame(value, nValue)) {
1168
1159
  node = this.getNode(k[i + 1]);
1160
+ if (node.parent !== parentId) {
1161
+ node.parent = parentId;
1162
+ this.bufferForNodeUpdate(node);
1163
+ }
1169
1164
  break;
1170
1165
  } else if (this.comparator.isLower(value, nValue)) {
1171
1166
  node = this.getNode(k[i]);
1167
+ if (node.parent !== parentId) {
1168
+ node.parent = parentId;
1169
+ this.bufferForNodeUpdate(node);
1170
+ }
1172
1171
  break;
1173
1172
  } else if (i + 1 === node.values.length) {
1174
1173
  node = this.getNode(k[i + 1]);
1174
+ if (node.parent !== parentId) {
1175
+ node.parent = parentId;
1176
+ this.bufferForNodeUpdate(node);
1177
+ }
1175
1178
  break;
1176
1179
  }
1177
1180
  }
1178
1181
  }
1179
1182
  return node;
1180
1183
  }
1181
- /**
1182
- * Find the insertable node using primaryAsc comparison.
1183
- * This allows finding nodes by primary value only, ignoring unique identifiers.
1184
- */
1185
1184
  insertableNodeByPrimary(value) {
1186
1185
  let node = this.getNode(this.rootId);
1186
+ if (node.parent !== null) {
1187
+ node.parent = null;
1188
+ this.bufferForNodeUpdate(node);
1189
+ }
1187
1190
  while (!node.leaf) {
1191
+ const parentId = node.id;
1188
1192
  for (let i = 0, len = node.values.length; i < len; i++) {
1189
1193
  const nValue = node.values[i];
1190
1194
  const k = node.keys;
1191
1195
  if (this.comparator.isPrimarySame(value, nValue)) {
1192
1196
  node = this.getNode(k[i]);
1197
+ if (node.parent !== parentId) {
1198
+ node.parent = parentId;
1199
+ this.bufferForNodeUpdate(node);
1200
+ }
1193
1201
  break;
1194
1202
  } else if (this.comparator.isPrimaryLower(value, nValue)) {
1195
1203
  node = this.getNode(k[i]);
1204
+ if (node.parent !== parentId) {
1205
+ node.parent = parentId;
1206
+ this.bufferForNodeUpdate(node);
1207
+ }
1196
1208
  break;
1197
1209
  } else if (i + 1 === node.values.length) {
1198
1210
  node = this.getNode(k[i + 1]);
1211
+ if (node.parent !== parentId) {
1212
+ node.parent = parentId;
1213
+ this.bufferForNodeUpdate(node);
1214
+ }
1199
1215
  break;
1200
1216
  }
1201
1217
  }
@@ -1204,16 +1220,29 @@ var BPTreeSync = class extends BPTree {
1204
1220
  }
1205
1221
  insertableRightestNodeByPrimary(value) {
1206
1222
  let node = this.getNode(this.rootId);
1223
+ if (node.parent !== null) {
1224
+ node.parent = null;
1225
+ this.bufferForNodeUpdate(node);
1226
+ }
1207
1227
  while (!node.leaf) {
1228
+ const parentId = node.id;
1208
1229
  for (let i = 0, len = node.values.length; i < len; i++) {
1209
1230
  const nValue = node.values[i];
1210
1231
  const k = node.keys;
1211
1232
  if (this.comparator.isPrimaryLower(value, nValue)) {
1212
1233
  node = this.getNode(k[i]);
1234
+ if (node.parent !== parentId) {
1235
+ node.parent = parentId;
1236
+ this.bufferForNodeUpdate(node);
1237
+ }
1213
1238
  break;
1214
1239
  }
1215
1240
  if (i + 1 === node.values.length) {
1216
1241
  node = this.getNode(k[i + 1]);
1242
+ if (node.parent !== parentId) {
1243
+ node.parent = parentId;
1244
+ this.bufferForNodeUpdate(node);
1245
+ }
1217
1246
  break;
1218
1247
  }
1219
1248
  }
@@ -1248,20 +1277,65 @@ var BPTreeSync = class extends BPTree {
1248
1277
  }
1249
1278
  leftestNode() {
1250
1279
  let node = this.getNode(this.rootId);
1280
+ if (node.parent !== null) {
1281
+ node.parent = null;
1282
+ this.bufferForNodeUpdate(node);
1283
+ }
1251
1284
  while (!node.leaf) {
1285
+ const parentId = node.id;
1252
1286
  const keys = node.keys;
1253
1287
  node = this.getNode(keys[0]);
1288
+ if (node.parent !== parentId) {
1289
+ node.parent = parentId;
1290
+ this.bufferForNodeUpdate(node);
1291
+ }
1254
1292
  }
1255
1293
  return node;
1256
1294
  }
1257
1295
  rightestNode() {
1258
1296
  let node = this.getNode(this.rootId);
1297
+ if (node.parent !== null) {
1298
+ node.parent = null;
1299
+ this.bufferForNodeUpdate(node);
1300
+ }
1259
1301
  while (!node.leaf) {
1302
+ const parentId = node.id;
1260
1303
  const keys = node.keys;
1261
1304
  node = this.getNode(keys[keys.length - 1]);
1305
+ if (node.parent !== parentId) {
1306
+ node.parent = parentId;
1307
+ this.bufferForNodeUpdate(node);
1308
+ }
1262
1309
  }
1263
1310
  return node;
1264
1311
  }
1312
+ exists(key, value) {
1313
+ const node = this.insertableNode(value);
1314
+ for (let i = 0, len = node.values.length; i < len; i++) {
1315
+ if (this.comparator.isSame(value, node.values[i])) {
1316
+ const keys = node.keys[i];
1317
+ if (keys.includes(key)) {
1318
+ return true;
1319
+ }
1320
+ }
1321
+ }
1322
+ return false;
1323
+ }
1324
+ forceUpdate(id) {
1325
+ if (id) {
1326
+ this.nodes.delete(id);
1327
+ this.getNode(id);
1328
+ return 1;
1329
+ }
1330
+ const keys = Array.from(this.nodes.keys());
1331
+ for (const key of keys) {
1332
+ this.nodes.delete(key);
1333
+ }
1334
+ for (const key of keys) {
1335
+ this.getNode(key);
1336
+ }
1337
+ return keys.length;
1338
+ }
1265
1339
  commitHeadBuffer() {
1266
1340
  if (!this._strategyDirty) {
1267
1341
  return;
@@ -1292,24 +1366,14 @@ var BPTreeSync = class extends BPTree {
1292
1366
  }
1293
1367
  this._nodeDeleteBuffer.clear();
1294
1368
  }
1295
- /**
1296
- * Retrieves the value associated with the given key (PK).
1297
- * Note: This method performs a full scan of leaf nodes as the tree is ordered by Value, not Key.
1298
- *
1299
- * @param key The key to search for.
1300
- * @returns The value associated with the key, or undefined if not found.
1301
- */
1302
1369
  get(key) {
1303
1370
  let node = this.leftestNode();
1304
1371
  while (true) {
1305
- if (node.values) {
1306
- const len = node.values.length;
1307
- for (let i = 0; i < len; i++) {
1308
- const keys = node.keys[i];
1309
- for (let j = 0; j < keys.length; j++) {
1310
- if (keys[j] === key) {
1311
- return node.values[i];
1312
- }
1372
+ for (let i = 0, len = node.values.length; i < len; i++) {
1373
+ const keys = node.keys[i];
1374
+ for (let j = 0, kLen = keys.length; j < kLen; j++) {
1375
+ if (keys[j] === key) {
1376
+ return node.values[i];
1313
1377
  }
1314
1378
  }
1315
1379
  }
@@ -1428,21 +1492,15 @@ var BPTreeSync = class extends BPTree {
1428
1492
  const nValue = node.values[i];
1429
1493
  if (this.comparator.isSame(value, nValue)) {
1430
1494
  const keys = node.keys[i];
1431
- if (keys.includes(key)) {
1432
- if (keys.length > 1) {
1433
- keys.splice(keys.indexOf(key), 1);
1434
- this.bufferForNodeUpdate(node);
1435
- } else if (node.id === this.rootId) {
1436
- node.values.splice(i, 1);
1495
+ const keyIndex = keys.indexOf(key);
1496
+ if (keyIndex !== -1) {
1497
+ keys.splice(keyIndex, 1);
1498
+ if (keys.length === 0) {
1437
1499
  node.keys.splice(i, 1);
1438
- this.bufferForNodeUpdate(node);
1439
- } else {
1440
- keys.splice(keys.indexOf(key), 1);
1441
- node.keys.splice(i, 1);
1442
- node.values.splice(node.values.indexOf(value), 1);
1443
- this._deleteEntry(node, key, value);
1444
- this.bufferForNodeUpdate(node);
1500
+ node.values.splice(i, 1);
1445
1501
  }
1502
+ this._deleteEntry(node, key, value);
1503
+ break;
1446
1504
  }
1447
1505
  }
1448
1506
  }
@@ -1451,327 +1509,424 @@ var BPTreeSync = class extends BPTree {
1451
1509
  this.commitNodeUpdateBuffer();
1452
1510
  this.commitNodeDeleteBuffer();
1453
1511
  }
1454
- exists(key, value) {
1455
- const node = this.insertableNode(value);
1456
- for (let i = 0, len = node.values.length; i < len; i++) {
1457
- const nValue = node.values[i];
1458
- if (this.comparator.isSame(value, nValue)) {
1459
- const keys = node.keys[i];
1460
- return keys.includes(key);
1461
- }
1462
- }
1463
- return false;
1512
+ getHeadData() {
1513
+ return this.strategy.head.data;
1464
1514
  }
1465
1515
  setHeadData(data) {
1466
1516
  this.strategy.head.data = data;
1467
- this._strategyDirty = true;
1468
- this.commitHeadBuffer();
1517
+ this.strategy.writeHead(this.strategy.head);
1469
1518
  }
1470
- forceUpdate() {
1471
- const keys = [...this.nodes.keys()];
1472
- this.nodes.clear();
1473
- this.init();
1474
- for (const key of keys) {
1475
- this.getNode(key);
1476
- }
1477
- return keys.length;
1519
+ };
1520
+
1521
+ // src/base/SerializeStrategy.ts
1522
+ var SerializeStrategy = class {
1523
+ order;
1524
+ head;
1525
+ constructor(order) {
1526
+ this.order = order;
1527
+ this.head = {
1528
+ order,
1529
+ root: null,
1530
+ data: {}
1531
+ };
1478
1532
  }
1479
1533
  };
1480
1534
 
1481
- // node_modules/ryoiki/dist/esm/index.mjs
1482
- var Ryoiki = class _Ryoiki {
1483
- readings;
1484
- writings;
1485
- readQueue;
1486
- writeQueue;
1487
- static async CatchError(promise) {
1488
- return await promise.then((v) => [void 0, v]).catch((err) => [err]);
1489
- }
1490
- static IsRangeOverlap(a, b) {
1491
- const [start1, end1] = a;
1492
- const [start2, end2] = b;
1493
- if (end1 <= start2 || end2 <= start1) {
1494
- return false;
1535
+ // src/SerializeStrategySync.ts
1536
+ var SerializeStrategySync = class extends SerializeStrategy {
1537
+ getHeadData(key, defaultValue) {
1538
+ if (!Object.hasOwn(this.head.data, key)) {
1539
+ this.setHeadData(key, defaultValue);
1495
1540
  }
1496
- return true;
1541
+ return this.head.data[key];
1497
1542
  }
1498
- static ERR_ALREADY_EXISTS(lockId) {
1499
- return new Error(`The '${lockId}' task already existing in queue or running.`);
1543
+ setHeadData(key, data) {
1544
+ this.head.data[key] = data;
1545
+ this.writeHead(this.head);
1500
1546
  }
1501
- static ERR_NOT_EXISTS(lockId) {
1502
- return new Error(`The '${lockId}' task not existing in task queue.`);
1547
+ autoIncrement(key, defaultValue) {
1548
+ const current = this.getHeadData(key, defaultValue);
1549
+ const next = current + 1;
1550
+ this.setHeadData(key, next);
1551
+ return current;
1503
1552
  }
1504
- static ERR_TIMEOUT(lockId, timeout) {
1505
- return new Error(`The task with ID '${lockId}' failed to acquire the lock within the timeout(${timeout}ms).`);
1553
+ compareAndSwapHead(oldRoot, newRoot) {
1554
+ if (this.head.root !== oldRoot) {
1555
+ return false;
1556
+ }
1557
+ this.head.root = newRoot;
1558
+ this.writeHead(this.head);
1559
+ return true;
1506
1560
  }
1507
- /**
1508
- * Constructs a new instance of the Ryoiki class.
1509
- */
1510
- constructor() {
1511
- this.readings = /* @__PURE__ */ new Map();
1512
- this.writings = /* @__PURE__ */ new Map();
1513
- this.readQueue = /* @__PURE__ */ new Map();
1514
- this.writeQueue = /* @__PURE__ */ new Map();
1561
+ };
1562
+ var InMemoryStoreStrategySync = class extends SerializeStrategySync {
1563
+ node;
1564
+ constructor(order) {
1565
+ super(order);
1566
+ this.node = {};
1515
1567
  }
1516
- /**
1517
- * Creates a range based on a start value and length.
1518
- * @param start - The starting value of the range.
1519
- * @param length - The length of the range.
1520
- * @returns A range tuple [start, start + length].
1521
- */
1522
- range(start, length) {
1523
- return [start, start + length];
1568
+ id(isLeaf) {
1569
+ return this.autoIncrement("index", 1).toString();
1524
1570
  }
1525
- rangeOverlapping(tasks, range) {
1526
- return Array.from(tasks.values()).some((t) => _Ryoiki.IsRangeOverlap(t.range, range));
1571
+ read(id) {
1572
+ if (!Object.hasOwn(this.node, id)) {
1573
+ throw new Error(`The tree attempted to reference node '${id}', but couldn't find the corresponding node.`);
1574
+ }
1575
+ const node = this.node[id];
1576
+ return JSON.parse(JSON.stringify(node));
1527
1577
  }
1528
- isSameRange(a, b) {
1529
- const [a1, a2] = a;
1530
- const [b1, b2] = b;
1531
- return a1 === b1 && a2 === b2;
1578
+ write(id, node) {
1579
+ this.node[id] = node;
1532
1580
  }
1533
- fetchUnitAndRun(queue, workspaces) {
1534
- for (const [id, unit] of queue) {
1535
- if (!unit.condition()) {
1536
- continue;
1537
- }
1538
- this._alloc(queue, workspaces, id);
1539
- }
1581
+ delete(id) {
1582
+ delete this.node[id];
1540
1583
  }
1541
- _handleOverload(args, handlers, argPatterns) {
1542
- for (const [key, pattern] of Object.entries(argPatterns)) {
1543
- if (this._matchArgs(args, pattern)) {
1544
- return handlers[key](...args);
1545
- }
1584
+ readHead() {
1585
+ if (this.head.root === null) {
1586
+ return null;
1546
1587
  }
1547
- throw new Error("Invalid arguments");
1588
+ return this.head;
1548
1589
  }
1549
- _matchArgs(args, pattern) {
1550
- return args.every((arg, index) => {
1551
- const expectedType = pattern[index];
1552
- if (expectedType === void 0) return typeof arg === "undefined";
1553
- if (expectedType === Function) return typeof arg === "function";
1554
- if (expectedType === Number) return typeof arg === "number";
1555
- if (expectedType === Array) return Array.isArray(arg);
1556
- return false;
1557
- });
1590
+ writeHead(head) {
1591
+ this.head = head;
1558
1592
  }
1559
- _createRandomId() {
1560
- const timestamp = Date.now().toString(36);
1561
- const random = Math.random().toString(36).substring(2);
1562
- return `${timestamp}${random}`;
1563
- }
1564
- _alloc(queue, workspaces, lockId) {
1565
- const unit = queue.get(lockId);
1566
- if (!unit) {
1567
- throw _Ryoiki.ERR_NOT_EXISTS(lockId);
1568
- }
1569
- workspaces.set(lockId, unit);
1570
- queue.delete(lockId);
1571
- unit.alloc();
1572
- }
1573
- _free(workspaces, lockId) {
1574
- const unit = workspaces.get(lockId);
1575
- if (!unit) {
1576
- throw _Ryoiki.ERR_NOT_EXISTS(lockId);
1577
- }
1578
- workspaces.delete(lockId);
1579
- unit.free();
1580
- }
1581
- _lock(queue, range, timeout, task, condition) {
1582
- return new Promise((resolve, reject) => {
1583
- let timeoutId = null;
1584
- if (timeout >= 0) {
1585
- timeoutId = setTimeout(() => {
1586
- reject(_Ryoiki.ERR_TIMEOUT(id, timeout));
1587
- }, timeout);
1588
- }
1589
- const id = this._createRandomId();
1590
- const alloc = async () => {
1591
- if (timeoutId !== null) {
1592
- clearTimeout(timeoutId);
1593
- }
1594
- const [err, v] = await _Ryoiki.CatchError(task(id));
1595
- if (err) reject(err);
1596
- else resolve(v);
1597
- };
1598
- const fetch = () => {
1599
- this.fetchUnitAndRun(this.readQueue, this.readings);
1600
- this.fetchUnitAndRun(this.writeQueue, this.writings);
1601
- };
1602
- queue.set(id, { id, range, condition, alloc, free: fetch });
1603
- fetch();
1604
- });
1593
+ };
1594
+
1595
+ // src/transaction/BPTreeSyncSnapshotStrategy.ts
1596
+ var BPTreeSyncSnapshotStrategy = class extends SerializeStrategySync {
1597
+ baseStrategy;
1598
+ snapshotHead;
1599
+ constructor(baseStrategy, root) {
1600
+ super(baseStrategy.order);
1601
+ this.baseStrategy = baseStrategy;
1602
+ this.snapshotHead = {
1603
+ ...baseStrategy.head,
1604
+ root,
1605
+ data: { ...baseStrategy.head.data }
1606
+ };
1607
+ this.head = this.snapshotHead;
1605
1608
  }
1606
- _checkWorking(range, workspaces) {
1607
- let isLocked = false;
1608
- for (const lock of workspaces.values()) {
1609
- if (_Ryoiki.IsRangeOverlap(range, lock.range)) {
1610
- isLocked = true;
1611
- break;
1612
- }
1613
- }
1614
- return isLocked;
1609
+ id(isLeaf) {
1610
+ return this.baseStrategy.id(isLeaf);
1615
1611
  }
1616
- /**
1617
- * Checks if there is any active read lock within the specified range.
1618
- * @param range The range to check for active read locks.
1619
- * @returns `true` if there is an active read lock within the range, `false` otherwise.
1620
- */
1621
- isReading(range) {
1622
- return this._checkWorking(range, this.readings);
1612
+ read(id) {
1613
+ return this.baseStrategy.read(id);
1623
1614
  }
1624
- /**
1625
- * Checks if there is any active write lock within the specified range.
1626
- * @param range The range to check for active write locks.
1627
- * @returns `true` if there is an active write lock within the range, `false` otherwise.
1628
- */
1629
- isWriting(range) {
1630
- return this._checkWorking(range, this.writings);
1615
+ write(id, node) {
1616
+ this.baseStrategy.write(id, node);
1631
1617
  }
1632
- /**
1633
- * Checks if a read lock can be acquired within the specified range.
1634
- * @param range The range to check for read lock availability.
1635
- * @returns `true` if a read lock can be acquired, `false` otherwise.
1636
- */
1637
- canRead(range) {
1638
- const writing = this.isWriting(range);
1639
- return !writing;
1618
+ delete(id) {
1619
+ this.baseStrategy.delete(id);
1640
1620
  }
1641
- /**
1642
- * Checks if a write lock can be acquired within the specified range.
1643
- * @param range The range to check for write lock availability.
1644
- * @returns `true` if a write lock can be acquired, `false` otherwise.
1645
- */
1646
- canWrite(range) {
1647
- const reading = this.isReading(range);
1648
- const writing = this.isWriting(range);
1649
- return !reading && !writing;
1621
+ readHead() {
1622
+ return this.snapshotHead;
1650
1623
  }
1651
- /**
1652
- * Internal implementation of the read lock. Handles both overloads.
1653
- * @template T - The return type of the task.
1654
- * @param arg0 - Either a range or a task callback.
1655
- * If a range is provided, the task is the second argument.
1656
- * @param arg1 - The task to execute, required if a range is provided.
1657
- * @param arg2 - The timeout for acquiring the lock.
1658
- * If the lock cannot be acquired within this period, an error will be thrown.
1659
- * If this value is not provided, no timeout will be set.
1660
- * @returns A promise resolving to the result of the task execution.
1661
- */
1662
- readLock(arg0, arg1, arg2) {
1663
- const [range, task, timeout] = this._handleOverload(
1664
- [arg0, arg1, arg2],
1665
- {
1666
- rangeTask: (range2, task2) => [range2, task2, -1],
1667
- rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
1668
- task: (task2) => [[-Infinity, Infinity], task2, -1],
1669
- taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
1670
- },
1671
- {
1672
- task: [Function],
1673
- taskTimeout: [Function, Number],
1674
- rangeTask: [Array, Function],
1675
- rangeTaskTimeout: [Array, Function, Number]
1676
- }
1677
- );
1678
- return this._lock(
1679
- this.readQueue,
1680
- range,
1681
- timeout,
1682
- task,
1683
- () => !this.rangeOverlapping(this.writings, range)
1684
- );
1624
+ writeHead(head) {
1625
+ this.snapshotHead.root = head.root;
1626
+ this.snapshotHead.data = { ...head.data };
1685
1627
  }
1686
- /**
1687
- * Internal implementation of the write lock. Handles both overloads.
1688
- * @template T - The return type of the task.
1689
- * @param arg0 - Either a range or a task callback.
1690
- * If a range is provided, the task is the second argument.
1691
- * @param arg1 - The task to execute, required if a range is provided.
1692
- * @param arg2 - The timeout for acquiring the lock.
1693
- * If the lock cannot be acquired within this period, an error will be thrown.
1694
- * If this value is not provided, no timeout will be set.
1695
- * @returns A promise resolving to the result of the task execution.
1696
- */
1697
- writeLock(arg0, arg1, arg2) {
1698
- const [range, task, timeout] = this._handleOverload(
1699
- [arg0, arg1, arg2],
1700
- {
1701
- rangeTask: (range2, task2) => [range2, task2, -1],
1702
- rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
1703
- task: (task2) => [[-Infinity, Infinity], task2, -1],
1704
- taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
1705
- },
1706
- {
1707
- task: [Function],
1708
- taskTimeout: [Function, Number],
1709
- rangeTask: [Array, Function],
1710
- rangeTaskTimeout: [Array, Function, Number]
1711
- }
1712
- );
1713
- return this._lock(
1714
- this.writeQueue,
1715
- range,
1716
- timeout,
1717
- task,
1718
- () => {
1719
- return !this.rangeOverlapping(this.writings, range) && !this.rangeOverlapping(this.readings, range);
1720
- }
1721
- );
1628
+ compareAndSwapHead(oldRoot, newRoot) {
1629
+ return this.baseStrategy.compareAndSwapHead(oldRoot, newRoot);
1722
1630
  }
1723
- /**
1724
- * Releases a read lock by its lock ID.
1725
- * @param lockId - The unique identifier for the lock to release.
1726
- */
1727
- readUnlock(lockId) {
1728
- this._free(this.readings, lockId);
1631
+ getHeadData(key, defaultValue) {
1632
+ return this.snapshotHead.data[key] ?? defaultValue;
1729
1633
  }
1730
- /**
1731
- * Releases a write lock by its lock ID.
1732
- * @param lockId - The unique identifier for the lock to release.
1733
- */
1734
- writeUnlock(lockId) {
1735
- this._free(this.writings, lockId);
1634
+ setHeadData(key, data) {
1635
+ this.snapshotHead.data[key] = data;
1636
+ }
1637
+ autoIncrement(key, defaultValue) {
1638
+ return this.snapshotHead.data[key] ?? defaultValue;
1736
1639
  }
1737
1640
  };
1738
1641
 
1739
- // src/BPTreeAsync.ts
1740
- var BPTreeAsync = class extends BPTree {
1741
- lock;
1742
- constructor(strategy, comparator, option) {
1743
- super(strategy, comparator, option);
1744
- this.nodes = this._createCachedNode();
1745
- this.lock = new Ryoiki();
1642
+ // src/transaction/BPTreeSyncTransaction.ts
1643
+ var BPTreeSyncTransaction = class extends BPTreeSyncBase {
1644
+ realBaseTree;
1645
+ realBaseStrategy;
1646
+ txNodes = /* @__PURE__ */ new Map();
1647
+ dirtyIds;
1648
+ createdInTx;
1649
+ deletedIds;
1650
+ initialRootId;
1651
+ transactionRootId;
1652
+ constructor(baseTree) {
1653
+ super(baseTree.strategy, baseTree.comparator, baseTree.option);
1654
+ this.realBaseTree = baseTree;
1655
+ this.realBaseStrategy = baseTree.strategy;
1656
+ this.order = baseTree.getOrder();
1657
+ this.initialRootId = "";
1658
+ this.transactionRootId = "";
1659
+ this.dirtyIds = /* @__PURE__ */ new Set();
1660
+ this.createdInTx = /* @__PURE__ */ new Set();
1661
+ this.deletedIds = /* @__PURE__ */ new Set();
1746
1662
  }
1747
- _createCachedNode() {
1748
- return new CacheEntanglementAsync(async (key) => {
1749
- return await this.strategy.read(key);
1750
- }, {
1751
- capacity: this.option.capacity ?? 1e3
1752
- });
1663
+ /**
1664
+ * Initializes the transaction by capturing the current state of the tree.
1665
+ */
1666
+ initTransaction() {
1667
+ const head = this.realBaseStrategy.readHead();
1668
+ if (head) {
1669
+ this.order = head.order;
1670
+ this.initialRootId = head.root;
1671
+ } else {
1672
+ this.initialRootId = this.realBaseTree.getRootId();
1673
+ }
1674
+ if (!this.initialRootId) {
1675
+ const root = this._createNode(true, [], [], true);
1676
+ this.initialRootId = root.id;
1677
+ }
1678
+ this.transactionRootId = this.initialRootId;
1679
+ this.rootId = this.transactionRootId;
1680
+ const snapshotStrategy = new BPTreeSyncSnapshotStrategy(this.realBaseStrategy, this.initialRootId);
1681
+ this.strategy = snapshotStrategy;
1682
+ this.txNodes.clear();
1683
+ this.dirtyIds.clear();
1684
+ this.createdInTx.clear();
1685
+ this.deletedIds.clear();
1753
1686
  }
1754
- async readLock(callback) {
1755
- let lockId;
1756
- return await this.lock.readLock(async (_lockId) => {
1757
- lockId = _lockId;
1758
- return await callback();
1759
- }).finally(() => {
1760
- this.lock.readUnlock(lockId);
1761
- });
1687
+ getNode(id) {
1688
+ if (this.txNodes.has(id)) {
1689
+ return this.txNodes.get(id);
1690
+ }
1691
+ if (this.deletedIds.has(id)) {
1692
+ throw new Error(`The tree attempted to reference deleted node '${id}'`);
1693
+ }
1694
+ const baseNode = this.realBaseStrategy.read(id);
1695
+ const clone = JSON.parse(JSON.stringify(baseNode));
1696
+ this.txNodes.set(id, clone);
1697
+ return clone;
1762
1698
  }
1763
- async writeLock(callback) {
1764
- let lockId;
1765
- return await this.lock.writeLock(async (_lockId) => {
1766
- lockId = _lockId;
1767
- return await callback();
1768
- }).finally(() => {
1769
- this.lock.writeUnlock(lockId);
1770
- });
1699
+ bufferForNodeUpdate(node) {
1700
+ if (this.dirtyIds.has(node.id) && this.txNodes.has(node.id) && node._p) {
1701
+ this.txNodes.set(node.id, node);
1702
+ return;
1703
+ }
1704
+ node._p = true;
1705
+ this.txNodes.set(node.id, node);
1706
+ this.dirtyIds.add(node.id);
1707
+ if (node.leaf) {
1708
+ if (node.next && !this.dirtyIds.has(node.next) && !this.deletedIds.has(node.next)) {
1709
+ try {
1710
+ this.bufferForNodeUpdate(this.getNode(node.next));
1711
+ } catch (e) {
1712
+ }
1713
+ }
1714
+ if (node.prev && !this.dirtyIds.has(node.prev) && !this.deletedIds.has(node.prev)) {
1715
+ try {
1716
+ this.bufferForNodeUpdate(this.getNode(node.prev));
1717
+ } catch (e) {
1718
+ }
1719
+ }
1720
+ }
1721
+ this.markPathDirty(node);
1722
+ delete node._p;
1771
1723
  }
1772
- async *getPairsGenerator(value, startNode, endNode, comparator, direction, earlyTerminate) {
1773
- let node = startNode;
1774
- let done = false;
1724
+ bufferForNodeCreate(node) {
1725
+ this.txNodes.set(node.id, node);
1726
+ this.dirtyIds.add(node.id);
1727
+ this.createdInTx.add(node.id);
1728
+ if (node.leaf) {
1729
+ if (node.next && !this.dirtyIds.has(node.next) && !this.deletedIds.has(node.next)) {
1730
+ try {
1731
+ this.bufferForNodeUpdate(this.getNode(node.next));
1732
+ } catch (e) {
1733
+ }
1734
+ }
1735
+ if (node.prev && !this.dirtyIds.has(node.prev) && !this.deletedIds.has(node.prev)) {
1736
+ try {
1737
+ this.bufferForNodeUpdate(this.getNode(node.prev));
1738
+ } catch (e) {
1739
+ }
1740
+ }
1741
+ }
1742
+ this.markPathDirty(node);
1743
+ }
1744
+ bufferForNodeDelete(node) {
1745
+ this.txNodes.delete(node.id);
1746
+ this.dirtyIds.add(node.id);
1747
+ this.deletedIds.add(node.id);
1748
+ }
1749
+ markPathDirty(node) {
1750
+ let curr = node;
1751
+ while (curr.parent) {
1752
+ if (this.deletedIds.has(curr.parent)) {
1753
+ break;
1754
+ }
1755
+ if (this.dirtyIds.has(curr.parent) && this.txNodes.has(curr.parent)) {
1756
+ break;
1757
+ }
1758
+ const parent = this.getNode(curr.parent);
1759
+ this.dirtyIds.add(parent.id);
1760
+ curr = parent;
1761
+ }
1762
+ if (!curr.parent) {
1763
+ this.transactionRootId = curr.id;
1764
+ }
1765
+ }
1766
+ _createNode(isLeaf, keys, values, leaf = isLeaf, parent = null, next = null, prev = null) {
1767
+ const id = this.strategy.id(isLeaf);
1768
+ const node = {
1769
+ id,
1770
+ keys,
1771
+ values,
1772
+ leaf,
1773
+ parent,
1774
+ next,
1775
+ prev
1776
+ };
1777
+ this.bufferForNodeCreate(node);
1778
+ return node;
1779
+ }
1780
+ /**
1781
+ * Attempts to commit the transaction.
1782
+ * Uses Optimistic Locking (Compare-And-Swap) on the root node ID to detect conflicts.
1783
+ *
1784
+ * @returns The transaction result.
1785
+ */
1786
+ commit() {
1787
+ const idMapping = /* @__PURE__ */ new Map();
1788
+ const finalNodes = [];
1789
+ for (const oldId of this.dirtyIds) {
1790
+ if (this.createdInTx.has(oldId)) {
1791
+ idMapping.set(oldId, oldId);
1792
+ } else {
1793
+ const node = this.txNodes.get(oldId);
1794
+ if (node) {
1795
+ const newId = this.realBaseStrategy.id(node.leaf);
1796
+ idMapping.set(oldId, newId);
1797
+ }
1798
+ }
1799
+ }
1800
+ const newCreatedIds = [];
1801
+ for (const oldId of this.dirtyIds) {
1802
+ const node = this.txNodes.get(oldId);
1803
+ if (!node) continue;
1804
+ const newId = idMapping.get(oldId);
1805
+ node.id = newId;
1806
+ if (node.parent && idMapping.has(node.parent)) {
1807
+ node.parent = idMapping.get(node.parent);
1808
+ }
1809
+ if (!node.leaf) {
1810
+ const internal = node;
1811
+ for (let i = 0; i < internal.keys.length; i++) {
1812
+ const childId = internal.keys[i];
1813
+ if (idMapping.has(childId)) {
1814
+ internal.keys[i] = idMapping.get(childId);
1815
+ }
1816
+ }
1817
+ }
1818
+ if (node.leaf) {
1819
+ const leaf = node;
1820
+ if (leaf.next && idMapping.has(leaf.next)) {
1821
+ leaf.next = idMapping.get(leaf.next);
1822
+ }
1823
+ if (leaf.prev && idMapping.has(leaf.prev)) {
1824
+ leaf.prev = idMapping.get(leaf.prev);
1825
+ }
1826
+ }
1827
+ finalNodes.push(node);
1828
+ newCreatedIds.push(newId);
1829
+ }
1830
+ let newRootId = this.rootId;
1831
+ if (idMapping.has(this.rootId)) {
1832
+ newRootId = idMapping.get(this.rootId);
1833
+ }
1834
+ for (const node of finalNodes) {
1835
+ this.realBaseStrategy.write(node.id, node);
1836
+ }
1837
+ const success = this.realBaseStrategy.compareAndSwapHead(this.initialRootId, newRootId);
1838
+ if (success) {
1839
+ const distinctObsolete = /* @__PURE__ */ new Set();
1840
+ for (const oldId of this.dirtyIds) {
1841
+ if (!this.createdInTx.has(oldId) && this.txNodes.has(oldId)) {
1842
+ distinctObsolete.add(oldId);
1843
+ }
1844
+ }
1845
+ return {
1846
+ success: true,
1847
+ createdIds: newCreatedIds,
1848
+ obsoleteIds: Array.from(distinctObsolete)
1849
+ };
1850
+ } else {
1851
+ this.rollback();
1852
+ return {
1853
+ success: false,
1854
+ createdIds: newCreatedIds,
1855
+ obsoleteIds: []
1856
+ };
1857
+ }
1858
+ }
1859
+ /**
1860
+ * Rolls back the transaction by clearing all buffered changes.
1861
+ * Internal use only.
1862
+ */
1863
+ rollback() {
1864
+ this.txNodes.clear();
1865
+ this.dirtyIds.clear();
1866
+ this.createdInTx.clear();
1867
+ }
1868
+ // Override to do nothing, as transaction handles its own commits
1869
+ commitHeadBuffer() {
1870
+ }
1871
+ commitNodeCreateBuffer() {
1872
+ }
1873
+ commitNodeUpdateBuffer() {
1874
+ }
1875
+ commitNodeDeleteBuffer() {
1876
+ }
1877
+ };
1878
+
1879
+ // src/BPTreeSync.ts
1880
+ var BPTreeSync = class extends BPTreeSyncBase {
1881
+ constructor(strategy, comparator, option) {
1882
+ super(strategy, comparator, option);
1883
+ this.init();
1884
+ }
1885
+ /**
1886
+ * Creates a new synchronous transaction.
1887
+ * @returns A new BPTreeSyncTransaction.
1888
+ */
1889
+ createTransaction() {
1890
+ const tx = new BPTreeSyncTransaction(this);
1891
+ tx.initTransaction();
1892
+ return tx;
1893
+ }
1894
+ insert(key, value) {
1895
+ const tx = this.createTransaction();
1896
+ tx.insert(key, value);
1897
+ const { success } = tx.commit();
1898
+ this.init();
1899
+ if (!success) {
1900
+ throw new Error("Transaction failed: Commit failed due to conflict");
1901
+ }
1902
+ }
1903
+ delete(key, value) {
1904
+ const tx = this.createTransaction();
1905
+ tx.delete(key, value);
1906
+ const { success } = tx.commit();
1907
+ this.init();
1908
+ if (!success) {
1909
+ throw new Error("Transaction failed: Commit failed due to conflict");
1910
+ }
1911
+ }
1912
+ };
1913
+
1914
+ // src/base/BPTreeAsyncBase.ts
1915
+ var BPTreeAsyncBase = class extends BPTree {
1916
+ constructor(strategy, comparator, option) {
1917
+ super(strategy, comparator, option);
1918
+ this.nodes = this._createCachedNode();
1919
+ }
1920
+ _createCachedNode() {
1921
+ return new CacheEntanglementAsync(async (key) => {
1922
+ return await this.strategy.read(key);
1923
+ }, {
1924
+ capacity: this.option.capacity ?? 1e3
1925
+ });
1926
+ }
1927
+ async *getPairsGenerator(value, startNode, endNode, comparator, direction, earlyTerminate) {
1928
+ let node = startNode;
1929
+ let done = false;
1775
1930
  let hasMatched = false;
1776
1931
  while (!done) {
1777
1932
  if (endNode && node.id === endNode.id) {
@@ -1833,7 +1988,7 @@ var BPTreeAsync = class extends BPTree {
1833
1988
  }
1834
1989
  return id;
1835
1990
  }
1836
- async _createNode(isLeaf, keys, values, leaf = false, parent = null, next = null, prev = null) {
1991
+ async _createNode(isLeaf, keys, values, leaf = isLeaf, parent = null, next = null, prev = null) {
1837
1992
  const id = await this._createNodeId(isLeaf);
1838
1993
  const node = {
1839
1994
  id,
@@ -1844,40 +1999,37 @@ var BPTreeAsync = class extends BPTree {
1844
1999
  next,
1845
2000
  prev
1846
2001
  };
1847
- this._nodeCreateBuffer.set(id, node);
2002
+ await this.bufferForNodeCreate(node);
1848
2003
  return node;
1849
2004
  }
1850
2005
  async _deleteEntry(node, key, value) {
1851
2006
  if (!node.leaf) {
2007
+ let keyIndex = -1;
1852
2008
  for (let i = 0, len = node.keys.length; i < len; i++) {
1853
- const nKey = node.keys[i];
1854
- if (nKey === key) {
1855
- node.keys.splice(i, 1);
1856
- this.bufferForNodeUpdate(node);
2009
+ if (node.keys[i] === key) {
2010
+ keyIndex = i;
1857
2011
  break;
1858
2012
  }
1859
2013
  }
1860
- for (let i = 0, len = node.values.length; i < len; i++) {
1861
- const nValue = node.values[i];
1862
- if (this.comparator.isSame(value, nValue)) {
1863
- node.values.splice(i, 1);
1864
- this.bufferForNodeUpdate(node);
1865
- break;
1866
- }
2014
+ if (keyIndex !== -1) {
2015
+ node.keys.splice(keyIndex, 1);
2016
+ const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
2017
+ node.values.splice(valueIndex, 1);
2018
+ await this.bufferForNodeUpdate(node);
1867
2019
  }
1868
2020
  }
1869
- if (this.rootId === node.id && node.keys.length === 1) {
2021
+ if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
1870
2022
  const keys = node.keys;
1871
- this.bufferForNodeDelete(node);
2023
+ await this.bufferForNodeDelete(node);
1872
2024
  const newRoot = await this.getNode(keys[0]);
1873
2025
  this.rootId = newRoot.id;
1874
2026
  newRoot.parent = null;
1875
2027
  this.strategy.head.root = this.rootId;
1876
- this.bufferForNodeUpdate(newRoot);
2028
+ await this.bufferForNodeUpdate(newRoot);
1877
2029
  return;
1878
2030
  } else if (this.rootId === node.id) {
1879
2031
  const root = await this.getNode(this.rootId);
1880
- this.bufferForNodeUpdate(root);
2032
+ await this.bufferForNodeUpdate(root);
1881
2033
  return;
1882
2034
  } else if (node.keys.length < Math.ceil(this.order / 2) && !node.leaf || node.values.length < Math.ceil((this.order - 1) / 2) && node.leaf) {
1883
2035
  if (node.parent === null) {
@@ -1935,33 +2087,24 @@ var BPTreeAsync = class extends BPTree {
1935
2087
  pointer.values.push(guess);
1936
2088
  } else {
1937
2089
  pointer.next = node.next;
1938
- pointer.prev = node.id;
1939
2090
  if (pointer.next) {
1940
- const n = await this.getNode(node.next);
2091
+ const n = await this.getNode(pointer.next);
1941
2092
  n.prev = pointer.id;
1942
- this.bufferForNodeUpdate(n);
1943
- }
1944
- if (pointer.prev) {
1945
- const n = await this.getNode(node.id);
1946
- n.next = pointer.id;
1947
- this.bufferForNodeUpdate(n);
1948
- }
1949
- if (isPredecessor) {
1950
- pointer.prev = null;
2093
+ await this.bufferForNodeUpdate(n);
1951
2094
  }
1952
2095
  }
1953
2096
  pointer.values.push(...node.values);
1954
2097
  if (!pointer.leaf) {
1955
2098
  const keys = pointer.keys;
1956
2099
  for (const key2 of keys) {
1957
- const node2 = await this.getNode(key2);
1958
- node2.parent = pointer.id;
1959
- this.bufferForNodeUpdate(node2);
2100
+ const n = await this.getNode(key2);
2101
+ n.parent = pointer.id;
2102
+ await this.bufferForNodeUpdate(n);
1960
2103
  }
1961
2104
  }
1962
2105
  await this._deleteEntry(await this.getNode(node.parent), node.id, guess);
1963
- this.bufferForNodeUpdate(pointer);
1964
- this.bufferForNodeDelete(node);
2106
+ await this.bufferForNodeUpdate(pointer);
2107
+ await this.bufferForNodeDelete(node);
1965
2108
  } else {
1966
2109
  if (isPredecessor) {
1967
2110
  let pointerPm;
@@ -1972,13 +2115,10 @@ var BPTreeAsync = class extends BPTree {
1972
2115
  node.keys = [pointerPm, ...node.keys];
1973
2116
  node.values = [guess, ...node.values];
1974
2117
  parentNode = await this.getNode(node.parent);
1975
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
1976
- const nValue = parentNode.values[i];
1977
- if (this.comparator.isSame(guess, nValue)) {
1978
- parentNode.values[i] = pointerKm;
1979
- this.bufferForNodeUpdate(parentNode);
1980
- break;
1981
- }
2118
+ const nodeIndex = parentNode.keys.indexOf(node.id);
2119
+ if (nodeIndex > 0) {
2120
+ parentNode.values[nodeIndex - 1] = pointerKm;
2121
+ await this.bufferForNodeUpdate(parentNode);
1982
2122
  }
1983
2123
  } else {
1984
2124
  pointerPm = pointer.keys.splice(-1)[0];
@@ -1986,17 +2126,14 @@ var BPTreeAsync = class extends BPTree {
1986
2126
  node.keys = [pointerPm, ...node.keys];
1987
2127
  node.values = [pointerKm, ...node.values];
1988
2128
  parentNode = await this.getNode(node.parent);
1989
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
1990
- const nValue = parentNode.values[i];
1991
- if (this.comparator.isSame(guess, nValue)) {
1992
- parentNode.values[i] = pointerKm;
1993
- this.bufferForNodeUpdate(parentNode);
1994
- break;
1995
- }
2129
+ const nodeIndex = parentNode.keys.indexOf(node.id);
2130
+ if (nodeIndex > 0) {
2131
+ parentNode.values[nodeIndex - 1] = pointerKm;
2132
+ await this.bufferForNodeUpdate(parentNode);
1996
2133
  }
1997
2134
  }
1998
- this.bufferForNodeUpdate(node);
1999
- this.bufferForNodeUpdate(pointer);
2135
+ await this.bufferForNodeUpdate(node);
2136
+ await this.bufferForNodeUpdate(pointer);
2000
2137
  } else {
2001
2138
  let pointerP0;
2002
2139
  let pointerK0;
@@ -2006,13 +2143,10 @@ var BPTreeAsync = class extends BPTree {
2006
2143
  node.keys = [...node.keys, pointerP0];
2007
2144
  node.values = [...node.values, guess];
2008
2145
  parentNode = await this.getNode(node.parent);
2009
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
2010
- const nValue = parentNode.values[i];
2011
- if (this.comparator.isSame(guess, nValue)) {
2012
- parentNode.values[i] = pointerK0;
2013
- this.bufferForNodeUpdate(parentNode);
2014
- break;
2015
- }
2146
+ const pointerIndex = parentNode.keys.indexOf(pointer.id);
2147
+ if (pointerIndex > 0) {
2148
+ parentNode.values[pointerIndex - 1] = pointerK0;
2149
+ await this.bufferForNodeUpdate(parentNode);
2016
2150
  }
2017
2151
  } else {
2018
2152
  pointerP0 = pointer.keys.splice(0, 1)[0];
@@ -2020,40 +2154,42 @@ var BPTreeAsync = class extends BPTree {
2020
2154
  node.keys = [...node.keys, pointerP0];
2021
2155
  node.values = [...node.values, pointerK0];
2022
2156
  parentNode = await this.getNode(node.parent);
2023
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
2024
- const nValue = parentNode.values[i];
2025
- if (this.comparator.isSame(guess, nValue)) {
2026
- parentNode.values[i] = pointer.values[0];
2027
- this.bufferForNodeUpdate(parentNode);
2028
- break;
2029
- }
2157
+ const pointerIndex = parentNode.keys.indexOf(pointer.id);
2158
+ if (pointerIndex > 0) {
2159
+ parentNode.values[pointerIndex - 1] = pointer.values[0];
2160
+ await this.bufferForNodeUpdate(parentNode);
2030
2161
  }
2031
2162
  }
2032
- this.bufferForNodeUpdate(node);
2033
- this.bufferForNodeUpdate(pointer);
2163
+ await this.bufferForNodeUpdate(node);
2164
+ await this.bufferForNodeUpdate(pointer);
2034
2165
  }
2035
2166
  if (!pointer.leaf) {
2036
- for (const key2 of pointer.keys) {
2167
+ const keys = pointer.keys;
2168
+ for (const key2 of keys) {
2037
2169
  const n = await this.getNode(key2);
2038
2170
  n.parent = pointer.id;
2039
- this.bufferForNodeUpdate(n);
2171
+ await this.bufferForNodeUpdate(n);
2040
2172
  }
2041
2173
  }
2042
2174
  if (!node.leaf) {
2043
- for (const key2 of node.keys) {
2175
+ const keys = node.keys;
2176
+ for (const key2 of keys) {
2044
2177
  const n = await this.getNode(key2);
2045
2178
  n.parent = node.id;
2046
- this.bufferForNodeUpdate(n);
2179
+ await this.bufferForNodeUpdate(n);
2047
2180
  }
2048
2181
  }
2049
2182
  if (!parentNode.leaf) {
2050
- for (const key2 of parentNode.keys) {
2183
+ const keys = parentNode.keys;
2184
+ for (const key2 of keys) {
2051
2185
  const n = await this.getNode(key2);
2052
2186
  n.parent = parentNode.id;
2053
- this.bufferForNodeUpdate(n);
2187
+ await this.bufferForNodeUpdate(n);
2054
2188
  }
2055
2189
  }
2056
2190
  }
2191
+ } else {
2192
+ await this.bufferForNodeUpdate(node);
2057
2193
  }
2058
2194
  }
2059
2195
  async _insertInParent(node, value, pointer) {
@@ -2064,43 +2200,39 @@ var BPTreeAsync = class extends BPTree {
2064
2200
  node.parent = root.id;
2065
2201
  pointer.parent = root.id;
2066
2202
  if (pointer.leaf) {
2067
- node.next = pointer.id;
2068
- pointer.prev = node.id;
2203
+ const nNode = node;
2204
+ nNode.next = pointer.id;
2205
+ const nPointer = pointer;
2206
+ nPointer.prev = node.id;
2069
2207
  }
2070
- this.bufferForNodeUpdate(node);
2071
- this.bufferForNodeUpdate(pointer);
2208
+ await this.bufferForNodeUpdate(node);
2209
+ await this.bufferForNodeUpdate(pointer);
2072
2210
  return;
2073
2211
  }
2074
2212
  const parentNode = await this.getNode(node.parent);
2075
- let insertIndex = 0;
2076
- for (let i = 0; i < parentNode.values.length; i++) {
2077
- if (this.comparator.asc(value, parentNode.values[i]) > 0) {
2078
- insertIndex = i + 1;
2079
- } else {
2080
- break;
2081
- }
2213
+ const nodeIndex = parentNode.keys.indexOf(node.id);
2214
+ if (nodeIndex === -1) {
2215
+ throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
2082
2216
  }
2217
+ const insertIndex = nodeIndex;
2083
2218
  parentNode.values.splice(insertIndex, 0, value);
2084
2219
  parentNode.keys.splice(insertIndex + 1, 0, pointer.id);
2085
2220
  pointer.parent = parentNode.id;
2086
2221
  if (pointer.leaf) {
2087
- const leftSiblingId = parentNode.keys[insertIndex];
2088
- const rightSiblingId = parentNode.keys[insertIndex + 2];
2089
- if (leftSiblingId) {
2090
- const leftSibling = await this.getNode(leftSiblingId);
2091
- pointer.prev = leftSibling.id;
2092
- pointer.next = leftSibling.next;
2093
- leftSibling.next = pointer.id;
2094
- this.bufferForNodeUpdate(leftSibling);
2095
- }
2096
- if (rightSiblingId) {
2097
- const rightSibling = await this.getNode(rightSiblingId);
2098
- rightSibling.prev = pointer.id;
2099
- this.bufferForNodeUpdate(rightSibling);
2100
- }
2101
- }
2102
- this.bufferForNodeUpdate(parentNode);
2103
- this.bufferForNodeUpdate(pointer);
2222
+ const leftSibling = node;
2223
+ const oldNextId = leftSibling.next;
2224
+ pointer.prev = leftSibling.id;
2225
+ pointer.next = oldNextId;
2226
+ leftSibling.next = pointer.id;
2227
+ await this.bufferForNodeUpdate(leftSibling);
2228
+ if (oldNextId) {
2229
+ const oldNext = await this.getNode(oldNextId);
2230
+ oldNext.prev = pointer.id;
2231
+ await this.bufferForNodeUpdate(oldNext);
2232
+ }
2233
+ }
2234
+ await this.bufferForNodeUpdate(parentNode);
2235
+ await this.bufferForNodeUpdate(pointer);
2104
2236
  if (parentNode.keys.length > this.order) {
2105
2237
  const parentPointer = await this._createNode(false, [], []);
2106
2238
  parentPointer.parent = parentNode.parent;
@@ -2111,20 +2243,21 @@ var BPTreeAsync = class extends BPTree {
2111
2243
  parentNode.values = parentNode.values.slice(0, mid);
2112
2244
  parentNode.keys = parentNode.keys.slice(0, mid + 1);
2113
2245
  for (const k of parentNode.keys) {
2114
- const node2 = await this.getNode(k);
2115
- node2.parent = parentNode.id;
2116
- this.bufferForNodeUpdate(node2);
2246
+ const n = await this.getNode(k);
2247
+ n.parent = parentNode.id;
2248
+ await this.bufferForNodeUpdate(n);
2117
2249
  }
2118
2250
  for (const k of parentPointer.keys) {
2119
- const node2 = await this.getNode(k);
2120
- node2.parent = parentPointer.id;
2121
- this.bufferForNodeUpdate(node2);
2251
+ const n = await this.getNode(k);
2252
+ n.parent = parentPointer.id;
2253
+ await this.bufferForNodeUpdate(n);
2122
2254
  }
2123
2255
  await this._insertInParent(parentNode, midValue, parentPointer);
2124
- this.bufferForNodeUpdate(parentNode);
2256
+ await this.bufferForNodeUpdate(parentNode);
2125
2257
  }
2126
2258
  }
2127
2259
  async init() {
2260
+ this.clear();
2128
2261
  const head = await this.strategy.readHead();
2129
2262
  if (head === null) {
2130
2263
  this.order = this.strategy.order;
@@ -2155,42 +2288,72 @@ var BPTreeAsync = class extends BPTree {
2155
2288
  }
2156
2289
  async insertableNode(value) {
2157
2290
  let node = await this.getNode(this.rootId);
2291
+ if (node.parent !== null) {
2292
+ node.parent = null;
2293
+ await this.bufferForNodeUpdate(node);
2294
+ }
2158
2295
  while (!node.leaf) {
2296
+ const parentId = node.id;
2159
2297
  for (let i = 0, len = node.values.length; i < len; i++) {
2160
2298
  const nValue = node.values[i];
2161
2299
  const k = node.keys;
2162
2300
  if (this.comparator.isSame(value, nValue)) {
2163
- node = await this.getNode(k[i + 1]);
2301
+ node = await this.getNode(node.keys[i + 1]);
2302
+ if (node.parent !== parentId) {
2303
+ node.parent = parentId;
2304
+ await this.bufferForNodeUpdate(node);
2305
+ }
2164
2306
  break;
2165
2307
  } else if (this.comparator.isLower(value, nValue)) {
2166
- node = await this.getNode(k[i]);
2308
+ node = await this.getNode(node.keys[i]);
2309
+ if (node.parent !== parentId) {
2310
+ node.parent = parentId;
2311
+ await this.bufferForNodeUpdate(node);
2312
+ }
2167
2313
  break;
2168
2314
  } else if (i + 1 === node.values.length) {
2169
- node = await this.getNode(k[i + 1]);
2315
+ node = await this.getNode(node.keys[i + 1]);
2316
+ if (node.parent !== parentId) {
2317
+ node.parent = parentId;
2318
+ await this.bufferForNodeUpdate(node);
2319
+ }
2170
2320
  break;
2171
2321
  }
2172
2322
  }
2173
2323
  }
2174
2324
  return node;
2175
2325
  }
2176
- /**
2177
- * Find the insertable node using primaryAsc comparison.
2178
- * This allows finding nodes by primary value only, ignoring unique identifiers.
2179
- */
2180
2326
  async insertableNodeByPrimary(value) {
2181
2327
  let node = await this.getNode(this.rootId);
2328
+ if (node.parent !== null) {
2329
+ node.parent = null;
2330
+ await this.bufferForNodeUpdate(node);
2331
+ }
2182
2332
  while (!node.leaf) {
2333
+ const parentId = node.id;
2183
2334
  for (let i = 0, len = node.values.length; i < len; i++) {
2184
2335
  const nValue = node.values[i];
2185
2336
  const k = node.keys;
2186
2337
  if (this.comparator.isPrimarySame(value, nValue)) {
2187
- node = await this.getNode(k[i]);
2338
+ node = await this.getNode(node.keys[i]);
2339
+ if (node.parent !== parentId) {
2340
+ node.parent = parentId;
2341
+ await this.bufferForNodeUpdate(node);
2342
+ }
2188
2343
  break;
2189
2344
  } else if (this.comparator.isPrimaryLower(value, nValue)) {
2190
- node = await this.getNode(k[i]);
2345
+ node = await this.getNode(node.keys[i]);
2346
+ if (node.parent !== parentId) {
2347
+ node.parent = parentId;
2348
+ await this.bufferForNodeUpdate(node);
2349
+ }
2191
2350
  break;
2192
2351
  } else if (i + 1 === node.values.length) {
2193
- node = await this.getNode(k[i + 1]);
2352
+ node = await this.getNode(node.keys[i + 1]);
2353
+ if (node.parent !== parentId) {
2354
+ node.parent = parentId;
2355
+ await this.bufferForNodeUpdate(node);
2356
+ }
2194
2357
  break;
2195
2358
  }
2196
2359
  }
@@ -2199,16 +2362,29 @@ var BPTreeAsync = class extends BPTree {
2199
2362
  }
2200
2363
  async insertableRightestNodeByPrimary(value) {
2201
2364
  let node = await this.getNode(this.rootId);
2365
+ if (node.parent !== null) {
2366
+ node.parent = null;
2367
+ await this.bufferForNodeUpdate(node);
2368
+ }
2202
2369
  while (!node.leaf) {
2370
+ const parentId = node.id;
2203
2371
  for (let i = 0, len = node.values.length; i < len; i++) {
2204
2372
  const nValue = node.values[i];
2205
2373
  const k = node.keys;
2206
2374
  if (this.comparator.isPrimaryLower(value, nValue)) {
2207
- node = await this.getNode(k[i]);
2375
+ node = await this.getNode(node.keys[i]);
2376
+ if (node.parent !== parentId) {
2377
+ node.parent = parentId;
2378
+ await this.bufferForNodeUpdate(node);
2379
+ }
2208
2380
  break;
2209
2381
  }
2210
2382
  if (i + 1 === node.values.length) {
2211
- node = await this.getNode(k[i + 1]);
2383
+ node = await this.getNode(node.keys[i + 1]);
2384
+ if (node.parent !== parentId) {
2385
+ node.parent = parentId;
2386
+ await this.bufferForNodeUpdate(node);
2387
+ }
2212
2388
  break;
2213
2389
  }
2214
2390
  }
@@ -2243,20 +2419,65 @@ var BPTreeAsync = class extends BPTree {
2243
2419
  }
2244
2420
  async leftestNode() {
2245
2421
  let node = await this.getNode(this.rootId);
2422
+ if (node.parent !== null) {
2423
+ node.parent = null;
2424
+ await this.bufferForNodeUpdate(node);
2425
+ }
2246
2426
  while (!node.leaf) {
2427
+ const parentId = node.id;
2247
2428
  const keys = node.keys;
2248
- node = await this.getNode(keys[0]);
2429
+ node = await this.getNode(node.keys[0]);
2430
+ if (node.parent !== parentId) {
2431
+ node.parent = parentId;
2432
+ await this.bufferForNodeUpdate(node);
2433
+ }
2249
2434
  }
2250
2435
  return node;
2251
2436
  }
2252
2437
  async rightestNode() {
2253
2438
  let node = await this.getNode(this.rootId);
2439
+ if (node.parent !== null) {
2440
+ node.parent = null;
2441
+ await this.bufferForNodeUpdate(node);
2442
+ }
2254
2443
  while (!node.leaf) {
2444
+ const parentId = node.id;
2255
2445
  const keys = node.keys;
2256
- node = await this.getNode(keys[keys.length - 1]);
2446
+ node = await this.getNode(node.keys[node.keys.length - 1]);
2447
+ if (node.parent !== parentId) {
2448
+ node.parent = parentId;
2449
+ await this.bufferForNodeUpdate(node);
2450
+ }
2257
2451
  }
2258
2452
  return node;
2259
2453
  }
2454
+ async exists(key, value) {
2455
+ const node = await this.insertableNode(value);
2456
+ for (let i = 0, len = node.values.length; i < len; i++) {
2457
+ if (this.comparator.isSame(value, node.values[i])) {
2458
+ const keys = node.keys[i];
2459
+ if (keys.includes(key)) {
2460
+ return true;
2461
+ }
2462
+ }
2463
+ }
2464
+ return false;
2465
+ }
2466
+ async forceUpdate(id) {
2467
+ if (id) {
2468
+ this.nodes.delete(id);
2469
+ await this.getNode(id);
2470
+ return 1;
2471
+ }
2472
+ const keys = Array.from(this.nodes.keys());
2473
+ for (const key of keys) {
2474
+ this.nodes.delete(key);
2475
+ }
2476
+ for (const key of keys) {
2477
+ await this.getNode(key);
2478
+ }
2479
+ return keys.length;
2480
+ }
2260
2481
  async commitHeadBuffer() {
2261
2482
  if (!this._strategyDirty) {
2262
2483
  return;
@@ -2287,25 +2508,15 @@ var BPTreeAsync = class extends BPTree {
2287
2508
  }
2288
2509
  this._nodeDeleteBuffer.clear();
2289
2510
  }
2290
- /**
2291
- * Retrieves the value associated with the given key (PK).
2292
- * Note: This method performs a full scan of leaf nodes as the tree is ordered by Value, not Key.
2293
- *
2294
- * @param key The key to search for.
2295
- * @returns The value associated with the key, or undefined if not found.
2296
- */
2297
2511
  async get(key) {
2298
- return this.readLock(async () => {
2512
+ return await this.readLock(async () => {
2299
2513
  let node = await this.leftestNode();
2300
2514
  while (true) {
2301
- if (node.values) {
2302
- const len = node.values.length;
2303
- for (let i = 0; i < len; i++) {
2304
- const keys = node.keys[i];
2305
- for (let j = 0; j < keys.length; j++) {
2306
- if (keys[j] === key) {
2307
- return node.values[i];
2308
- }
2515
+ for (let i = 0, len = node.values.length; i < len; i++) {
2516
+ const keys = node.keys[i];
2517
+ for (let j = 0, kLen = keys.length; j < kLen; j++) {
2518
+ if (keys[j] === key) {
2519
+ return node.values[i];
2309
2520
  }
2310
2521
  }
2311
2522
  }
@@ -2380,27 +2591,23 @@ var BPTreeAsync = class extends BPTree {
2380
2591
  }
2381
2592
  }
2382
2593
  async keys(condition, filterValues) {
2383
- return this.readLock(async () => {
2384
- const set = /* @__PURE__ */ new Set();
2385
- for await (const key of this.keysStream(condition, filterValues)) {
2386
- set.add(key);
2387
- }
2388
- return set;
2389
- });
2594
+ const set = /* @__PURE__ */ new Set();
2595
+ for await (const key of this.keysStream(condition, filterValues)) {
2596
+ set.add(key);
2597
+ }
2598
+ return set;
2390
2599
  }
2391
2600
  async where(condition) {
2392
- return this.readLock(async () => {
2393
- const map = /* @__PURE__ */ new Map();
2394
- for await (const [key, value] of this.whereStream(condition)) {
2395
- map.set(key, value);
2396
- }
2397
- return map;
2398
- });
2601
+ const map = /* @__PURE__ */ new Map();
2602
+ for await (const [key, value] of this.whereStream(condition)) {
2603
+ map.set(key, value);
2604
+ }
2605
+ return map;
2399
2606
  }
2400
2607
  async insert(key, value) {
2401
- return this.writeLock(async () => {
2608
+ await this.writeLock(async () => {
2402
2609
  const before = await this.insertableNode(value);
2403
- this._insertAtLeaf(before, key, value);
2610
+ await this._insertAtLeaf(before, key, value);
2404
2611
  if (before.values.length === this.order) {
2405
2612
  const after = await this._createNode(
2406
2613
  true,
@@ -2417,7 +2624,7 @@ var BPTreeAsync = class extends BPTree {
2417
2624
  before.values = before.values.slice(0, mid + 1);
2418
2625
  before.keys = before.keys.slice(0, mid + 1);
2419
2626
  await this._insertInParent(before, after.values[0], after);
2420
- this.bufferForNodeUpdate(before);
2627
+ await this.bufferForNodeUpdate(before);
2421
2628
  }
2422
2629
  await this.commitHeadBuffer();
2423
2630
  await this.commitNodeCreateBuffer();
@@ -2425,28 +2632,23 @@ var BPTreeAsync = class extends BPTree {
2425
2632
  });
2426
2633
  }
2427
2634
  async delete(key, value) {
2428
- return this.writeLock(async () => {
2635
+ await this.writeLock(async () => {
2429
2636
  const node = await this.insertableNode(value);
2430
2637
  let i = node.values.length;
2431
2638
  while (i--) {
2432
2639
  const nValue = node.values[i];
2433
2640
  if (this.comparator.isSame(value, nValue)) {
2434
2641
  const keys = node.keys[i];
2435
- if (keys.includes(key)) {
2436
- if (keys.length > 1) {
2437
- keys.splice(keys.indexOf(key), 1);
2438
- this.bufferForNodeUpdate(node);
2439
- } else if (node.id === this.rootId) {
2440
- node.values.splice(i, 1);
2642
+ const keyIndex = keys.indexOf(key);
2643
+ if (keyIndex !== -1) {
2644
+ keys.splice(keyIndex, 1);
2645
+ if (keys.length === 0) {
2441
2646
  node.keys.splice(i, 1);
2442
- this.bufferForNodeUpdate(node);
2443
- } else {
2444
- keys.splice(keys.indexOf(key), 1);
2445
- node.keys.splice(i, 1);
2446
- node.values.splice(node.values.indexOf(value), 1);
2447
- await this._deleteEntry(node, key, value);
2448
- this.bufferForNodeUpdate(node);
2647
+ node.values.splice(i, 1);
2449
2648
  }
2649
+ await this._deleteEntry(node, key, value);
2650
+ await this.bufferForNodeUpdate(node);
2651
+ break;
2450
2652
  }
2451
2653
  }
2452
2654
  }
@@ -2456,151 +2658,400 @@ var BPTreeAsync = class extends BPTree {
2456
2658
  await this.commitNodeDeleteBuffer();
2457
2659
  });
2458
2660
  }
2459
- async exists(key, value) {
2460
- return this.readLock(async () => {
2461
- const node = await this.insertableNode(value);
2462
- for (let i = 0, len = node.values.length; i < len; i++) {
2463
- const nValue = node.values[i];
2464
- if (this.comparator.isSame(value, nValue)) {
2465
- const keys = node.keys[i];
2466
- return keys.includes(key);
2467
- }
2468
- }
2469
- return false;
2470
- });
2661
+ getHeadData() {
2662
+ return this.strategy.head.data;
2471
2663
  }
2472
2664
  async setHeadData(data) {
2473
- return this.writeLock(async () => {
2474
- this.strategy.head.data = data;
2475
- this._strategyDirty = true;
2476
- await this.commitHeadBuffer();
2477
- });
2478
- }
2479
- async forceUpdate() {
2480
- return this.readLock(async () => {
2481
- const keys = [...this.nodes.keys()];
2482
- this.nodes.clear();
2483
- await this.init();
2484
- for (const key of keys) {
2485
- await this.getNode(key);
2486
- }
2487
- return keys.length;
2488
- });
2489
- }
2490
- };
2491
-
2492
- // src/base/SerializeStrategy.ts
2493
- var SerializeStrategy = class {
2494
- order;
2495
- head;
2496
- constructor(order) {
2497
- this.order = order;
2498
- this.head = {
2499
- order,
2500
- root: null,
2501
- data: {}
2502
- };
2665
+ this.strategy.head.data = data;
2666
+ await this.strategy.writeHead(this.strategy.head);
2503
2667
  }
2504
2668
  };
2505
2669
 
2506
- // src/SerializeStrategySync.ts
2507
- var SerializeStrategySync = class extends SerializeStrategy {
2508
- getHeadData(key, defaultValue) {
2670
+ // src/SerializeStrategyAsync.ts
2671
+ var SerializeStrategyAsync = class extends SerializeStrategy {
2672
+ async getHeadData(key, defaultValue) {
2509
2673
  if (!Object.hasOwn(this.head.data, key)) {
2510
- this.setHeadData(key, defaultValue);
2674
+ await this.setHeadData(key, defaultValue);
2511
2675
  }
2512
2676
  return this.head.data[key];
2513
2677
  }
2514
- setHeadData(key, data) {
2678
+ async setHeadData(key, data) {
2515
2679
  this.head.data[key] = data;
2516
- this.writeHead(this.head);
2680
+ await this.writeHead(this.head);
2517
2681
  }
2518
- autoIncrement(key, defaultValue) {
2519
- const current = this.getHeadData(key, defaultValue);
2682
+ async autoIncrement(key, defaultValue) {
2683
+ const current = await this.getHeadData(key, defaultValue);
2520
2684
  const next = current + 1;
2521
- this.setHeadData(key, next);
2685
+ await this.setHeadData(key, next);
2522
2686
  return current;
2523
2687
  }
2688
+ async compareAndSwapHead(oldRoot, newRoot) {
2689
+ if (this.head.root !== oldRoot) {
2690
+ return false;
2691
+ }
2692
+ this.head.root = newRoot;
2693
+ await this.writeHead(this.head);
2694
+ return true;
2695
+ }
2524
2696
  };
2525
- var InMemoryStoreStrategySync = class extends SerializeStrategySync {
2697
+ var InMemoryStoreStrategyAsync = class extends SerializeStrategyAsync {
2526
2698
  node;
2527
2699
  constructor(order) {
2528
2700
  super(order);
2529
2701
  this.node = {};
2530
2702
  }
2531
- id(isLeaf) {
2532
- return this.autoIncrement("index", 1).toString();
2703
+ async id(isLeaf) {
2704
+ return (await this.autoIncrement("index", 1)).toString();
2533
2705
  }
2534
- read(id) {
2706
+ async read(id) {
2535
2707
  if (!Object.hasOwn(this.node, id)) {
2536
2708
  throw new Error(`The tree attempted to reference node '${id}', but couldn't find the corresponding node.`);
2537
2709
  }
2538
- return this.node[id];
2710
+ const node = this.node[id];
2711
+ return JSON.parse(JSON.stringify(node));
2539
2712
  }
2540
- write(id, node) {
2713
+ async write(id, node) {
2541
2714
  this.node[id] = node;
2542
2715
  }
2543
- delete(id) {
2716
+ async delete(id) {
2544
2717
  delete this.node[id];
2545
2718
  }
2546
- readHead() {
2719
+ async readHead() {
2547
2720
  if (this.head.root === null) {
2548
2721
  return null;
2549
2722
  }
2550
2723
  return this.head;
2551
2724
  }
2552
- writeHead(head) {
2725
+ async writeHead(head) {
2553
2726
  this.head = head;
2554
2727
  }
2555
2728
  };
2556
2729
 
2557
- // src/SerializeStrategyAsync.ts
2558
- var SerializeStrategyAsync = class extends SerializeStrategy {
2730
+ // src/transaction/BPTreeAsyncSnapshotStrategy.ts
2731
+ var BPTreeAsyncSnapshotStrategy = class extends SerializeStrategyAsync {
2732
+ baseStrategy;
2733
+ snapshotHead;
2734
+ constructor(baseStrategy, root) {
2735
+ super(baseStrategy.order);
2736
+ this.baseStrategy = baseStrategy;
2737
+ this.snapshotHead = {
2738
+ ...baseStrategy.head,
2739
+ root,
2740
+ data: { ...baseStrategy.head.data }
2741
+ };
2742
+ this.head = this.snapshotHead;
2743
+ }
2744
+ async id(isLeaf) {
2745
+ return await this.baseStrategy.id(isLeaf);
2746
+ }
2747
+ async read(id) {
2748
+ return await this.baseStrategy.read(id);
2749
+ }
2750
+ async write(id, node) {
2751
+ await this.baseStrategy.write(id, node);
2752
+ }
2753
+ async delete(id) {
2754
+ await this.baseStrategy.delete(id);
2755
+ }
2756
+ async readHead() {
2757
+ return this.snapshotHead;
2758
+ }
2759
+ async writeHead(head) {
2760
+ this.snapshotHead.root = head.root;
2761
+ this.snapshotHead.data = { ...head.data };
2762
+ }
2763
+ async compareAndSwapHead(oldRoot, newRoot) {
2764
+ return await this.baseStrategy.compareAndSwapHead(oldRoot, newRoot);
2765
+ }
2559
2766
  async getHeadData(key, defaultValue) {
2560
- if (!Object.hasOwn(this.head.data, key)) {
2561
- await this.setHeadData(key, defaultValue);
2562
- }
2563
- return this.head.data[key];
2767
+ return this.snapshotHead.data[key] ?? defaultValue;
2564
2768
  }
2565
2769
  async setHeadData(key, data) {
2566
- this.head.data[key] = data;
2567
- await this.writeHead(this.head);
2770
+ this.snapshotHead.data[key] = data;
2568
2771
  }
2569
2772
  async autoIncrement(key, defaultValue) {
2570
- const current = await this.getHeadData(key, defaultValue);
2571
- const next = current + 1;
2572
- await this.setHeadData(key, next);
2573
- return current;
2773
+ return this.snapshotHead.data[key] ?? defaultValue;
2574
2774
  }
2575
2775
  };
2576
- var InMemoryStoreStrategyAsync = class extends SerializeStrategyAsync {
2577
- node;
2578
- constructor(order) {
2579
- super(order);
2580
- this.node = {};
2776
+
2777
+ // src/transaction/BPTreeAsyncTransaction.ts
2778
+ var BPTreeAsyncTransaction = class extends BPTreeAsyncBase {
2779
+ realBaseTree;
2780
+ realBaseStrategy;
2781
+ txNodes = /* @__PURE__ */ new Map();
2782
+ dirtyIds;
2783
+ createdInTx;
2784
+ deletedIds;
2785
+ initialRootId;
2786
+ transactionRootId;
2787
+ constructor(baseTree) {
2788
+ super(baseTree.strategy, baseTree.comparator, baseTree.option);
2789
+ this.realBaseTree = baseTree;
2790
+ this.realBaseStrategy = baseTree.strategy;
2791
+ this.order = baseTree.getOrder();
2792
+ this.initialRootId = "";
2793
+ this.transactionRootId = "";
2794
+ this.dirtyIds = /* @__PURE__ */ new Set();
2795
+ this.createdInTx = /* @__PURE__ */ new Set();
2796
+ this.deletedIds = /* @__PURE__ */ new Set();
2581
2797
  }
2582
- async id(isLeaf) {
2583
- return (await this.autoIncrement("index", 1)).toString();
2798
+ /**
2799
+ * Initializes the transaction by capturing the current state of the tree.
2800
+ */
2801
+ async initTransaction() {
2802
+ const head = await this.realBaseStrategy.readHead();
2803
+ if (head) {
2804
+ this.order = head.order;
2805
+ this.initialRootId = head.root;
2806
+ } else {
2807
+ this.initialRootId = this.realBaseTree.getRootId();
2808
+ }
2809
+ if (!this.initialRootId) {
2810
+ const root = await this._createNode(true, [], [], true);
2811
+ this.initialRootId = root.id;
2812
+ }
2813
+ this.transactionRootId = this.initialRootId;
2814
+ this.rootId = this.transactionRootId;
2815
+ const snapshotStrategy = new BPTreeAsyncSnapshotStrategy(this.realBaseStrategy, this.initialRootId);
2816
+ this.strategy = snapshotStrategy;
2817
+ this.txNodes.clear();
2818
+ this.dirtyIds.clear();
2819
+ this.createdInTx.clear();
2820
+ this.deletedIds.clear();
2584
2821
  }
2585
- async read(id) {
2586
- if (!Object.hasOwn(this.node, id)) {
2587
- throw new Error(`The tree attempted to reference node '${id}', but couldn't find the corresponding node.`);
2822
+ async getNode(id) {
2823
+ if (this.txNodes.has(id)) {
2824
+ return this.txNodes.get(id);
2825
+ }
2826
+ if (this.deletedIds.has(id)) {
2827
+ throw new Error(`The tree attempted to reference deleted node '${id}'`);
2588
2828
  }
2589
- return this.node[id];
2829
+ const baseNode = await this.realBaseStrategy.read(id);
2830
+ const clone = JSON.parse(JSON.stringify(baseNode));
2831
+ this.txNodes.set(id, clone);
2832
+ return clone;
2590
2833
  }
2591
- async write(id, node) {
2592
- this.node[id] = node;
2834
+ async bufferForNodeUpdate(node) {
2835
+ if (this.dirtyIds.has(node.id) && this.txNodes.has(node.id) && node._p) {
2836
+ this.txNodes.set(node.id, node);
2837
+ return;
2838
+ }
2839
+ node._p = true;
2840
+ this.txNodes.set(node.id, node);
2841
+ this.dirtyIds.add(node.id);
2842
+ if (node.leaf) {
2843
+ if (node.next && !this.dirtyIds.has(node.next) && !this.deletedIds.has(node.next)) {
2844
+ try {
2845
+ await this.bufferForNodeUpdate(await this.getNode(node.next));
2846
+ } catch (e) {
2847
+ }
2848
+ }
2849
+ if (node.prev && !this.dirtyIds.has(node.prev) && !this.deletedIds.has(node.prev)) {
2850
+ try {
2851
+ await this.bufferForNodeUpdate(await this.getNode(node.prev));
2852
+ } catch (e) {
2853
+ }
2854
+ }
2855
+ }
2856
+ await this.markPathDirty(node);
2857
+ delete node._p;
2593
2858
  }
2594
- async delete(id) {
2595
- delete this.node[id];
2859
+ async bufferForNodeCreate(node) {
2860
+ this.txNodes.set(node.id, node);
2861
+ this.dirtyIds.add(node.id);
2862
+ this.createdInTx.add(node.id);
2863
+ if (node.leaf) {
2864
+ if (node.next && !this.dirtyIds.has(node.next) && !this.deletedIds.has(node.next)) {
2865
+ try {
2866
+ await this.bufferForNodeUpdate(await this.getNode(node.next));
2867
+ } catch (e) {
2868
+ }
2869
+ }
2870
+ if (node.prev && !this.dirtyIds.has(node.prev) && !this.deletedIds.has(node.prev)) {
2871
+ try {
2872
+ await this.bufferForNodeUpdate(await this.getNode(node.prev));
2873
+ } catch (e) {
2874
+ }
2875
+ }
2876
+ }
2877
+ await this.markPathDirty(node);
2596
2878
  }
2597
- async readHead() {
2598
- if (this.head.root === null) {
2599
- return null;
2879
+ async bufferForNodeDelete(node) {
2880
+ this.txNodes.delete(node.id);
2881
+ this.dirtyIds.add(node.id);
2882
+ this.deletedIds.add(node.id);
2883
+ }
2884
+ async markPathDirty(node) {
2885
+ let curr = node;
2886
+ while (curr.parent) {
2887
+ if (this.deletedIds.has(curr.parent)) {
2888
+ break;
2889
+ }
2890
+ if (this.dirtyIds.has(curr.parent) && this.txNodes.has(curr.parent)) {
2891
+ break;
2892
+ }
2893
+ const parent = await this.getNode(curr.parent);
2894
+ this.dirtyIds.add(parent.id);
2895
+ curr = parent;
2896
+ }
2897
+ if (!curr.parent) {
2898
+ this.transactionRootId = curr.id;
2600
2899
  }
2601
- return this.head;
2602
2900
  }
2603
- async writeHead(head) {
2604
- this.head = head;
2901
+ async _createNode(isLeaf, keys, values, leaf = isLeaf, parent = null, next = null, prev = null) {
2902
+ const id = await this.strategy.id(isLeaf);
2903
+ const node = {
2904
+ id,
2905
+ keys,
2906
+ values,
2907
+ leaf,
2908
+ parent,
2909
+ next,
2910
+ prev
2911
+ };
2912
+ await this.bufferForNodeCreate(node);
2913
+ return node;
2914
+ }
2915
+ /**
2916
+ * Attempts to commit the transaction.
2917
+ * Uses Optimistic Locking (Compare-And-Swap) on the root node ID to detect conflicts.
2918
+ *
2919
+ * @returns A promise that resolves to the transaction result.
2920
+ */
2921
+ async commit() {
2922
+ const idMapping = /* @__PURE__ */ new Map();
2923
+ const finalNodes = [];
2924
+ for (const oldId of this.dirtyIds) {
2925
+ if (this.createdInTx.has(oldId)) {
2926
+ idMapping.set(oldId, oldId);
2927
+ } else {
2928
+ const node = this.txNodes.get(oldId);
2929
+ if (node) {
2930
+ const newId = await this.realBaseStrategy.id(node.leaf);
2931
+ idMapping.set(oldId, newId);
2932
+ }
2933
+ }
2934
+ }
2935
+ const newCreatedIds = [];
2936
+ for (const oldId of this.dirtyIds) {
2937
+ const node = this.txNodes.get(oldId);
2938
+ if (!node) continue;
2939
+ const newId = idMapping.get(oldId);
2940
+ node.id = newId;
2941
+ if (node.parent && idMapping.has(node.parent)) {
2942
+ node.parent = idMapping.get(node.parent);
2943
+ }
2944
+ if (!node.leaf) {
2945
+ const internal = node;
2946
+ for (let i = 0; i < internal.keys.length; i++) {
2947
+ const childId = internal.keys[i];
2948
+ if (idMapping.has(childId)) {
2949
+ internal.keys[i] = idMapping.get(childId);
2950
+ }
2951
+ }
2952
+ }
2953
+ if (node.leaf) {
2954
+ const leaf = node;
2955
+ if (leaf.next && idMapping.has(leaf.next)) {
2956
+ leaf.next = idMapping.get(leaf.next);
2957
+ }
2958
+ if (leaf.prev && idMapping.has(leaf.prev)) {
2959
+ leaf.prev = idMapping.get(leaf.prev);
2960
+ }
2961
+ }
2962
+ finalNodes.push(node);
2963
+ newCreatedIds.push(newId);
2964
+ }
2965
+ let newRootId = this.rootId;
2966
+ if (idMapping.has(this.rootId)) {
2967
+ newRootId = idMapping.get(this.rootId);
2968
+ }
2969
+ for (const node of finalNodes) {
2970
+ await this.realBaseStrategy.write(node.id, node);
2971
+ }
2972
+ const success = await this.realBaseStrategy.compareAndSwapHead(this.initialRootId, newRootId);
2973
+ if (success) {
2974
+ const distinctObsolete = /* @__PURE__ */ new Set();
2975
+ for (const oldId of this.dirtyIds) {
2976
+ if (!this.createdInTx.has(oldId) && this.txNodes.has(oldId)) {
2977
+ distinctObsolete.add(oldId);
2978
+ }
2979
+ }
2980
+ return {
2981
+ success: true,
2982
+ createdIds: newCreatedIds,
2983
+ obsoleteIds: Array.from(distinctObsolete)
2984
+ };
2985
+ } else {
2986
+ await this.rollback();
2987
+ return {
2988
+ success: false,
2989
+ createdIds: newCreatedIds,
2990
+ obsoleteIds: []
2991
+ };
2992
+ }
2993
+ }
2994
+ /**
2995
+ * Rolls back the transaction by clearing all buffered changes.
2996
+ * Internal use only.
2997
+ */
2998
+ async rollback() {
2999
+ this.txNodes.clear();
3000
+ this.dirtyIds.clear();
3001
+ this.createdInTx.clear();
3002
+ }
3003
+ async readLock(fn) {
3004
+ return await fn();
3005
+ }
3006
+ async writeLock(fn) {
3007
+ return await fn();
3008
+ }
3009
+ async commitHeadBuffer() {
3010
+ }
3011
+ async commitNodeCreateBuffer() {
3012
+ }
3013
+ async commitNodeUpdateBuffer() {
3014
+ }
3015
+ async commitNodeDeleteBuffer() {
3016
+ }
3017
+ };
3018
+
3019
+ // src/BPTreeAsync.ts
3020
+ var BPTreeAsync = class extends BPTreeAsyncBase {
3021
+ constructor(strategy, comparator, option) {
3022
+ super(strategy, comparator, option);
3023
+ }
3024
+ /**
3025
+ * Creates a new asynchronous transaction.
3026
+ * @returns A promise that resolves to a new BPTreeAsyncTransaction.
3027
+ */
3028
+ async createTransaction() {
3029
+ const tx = new BPTreeAsyncTransaction(this);
3030
+ await tx.initTransaction();
3031
+ return tx;
3032
+ }
3033
+ async insert(key, value) {
3034
+ const tx = await this.createTransaction();
3035
+ await tx.insert(key, value);
3036
+ const { success } = await tx.commit();
3037
+ await this.init();
3038
+ if (!success) {
3039
+ throw new Error("Transaction failed: Commit failed due to conflict");
3040
+ }
3041
+ }
3042
+ async delete(key, value) {
3043
+ const tx = await this.createTransaction();
3044
+ await tx.delete(key, value);
3045
+ const { success } = await tx.commit();
3046
+ await this.init();
3047
+ if (!success) {
3048
+ throw new Error("Transaction failed: Commit failed due to conflict");
3049
+ }
3050
+ }
3051
+ async readLock(fn) {
3052
+ return await fn();
3053
+ }
3054
+ async writeLock(fn) {
3055
+ return await fn();
2605
3056
  }
2606
3057
  };