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