dataply 0.0.16-alpha.2 → 0.0.16-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cjs/index.js CHANGED
@@ -31,7 +31,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var src_exports = {};
32
32
  __export(src_exports, {
33
33
  BPTreeAsync: () => BPTreeAsync,
34
+ BPTreeAsyncTransaction: () => BPTreeAsyncTransaction,
34
35
  BPTreeSync: () => BPTreeSync,
36
+ BPTreeSyncTransaction: () => BPTreeSyncTransaction,
35
37
  BitmapPageManager: () => BitmapPageManager,
36
38
  CacheEntanglementAsync: () => CacheEntanglementAsync2,
37
39
  CacheEntanglementSync: () => CacheEntanglementSync2,
@@ -50,7 +52,7 @@ __export(src_exports, {
50
52
  OverflowPageManager: () => OverflowPageManager,
51
53
  PageManager: () => PageManager,
52
54
  PageManagerFactory: () => PageManagerFactory,
53
- Ryoiki: () => Ryoiki2,
55
+ Ryoiki: () => Ryoiki,
54
56
  SerializeStrategyAsync: () => SerializeStrategyAsync,
55
57
  SerializeStrategySync: () => SerializeStrategySync,
56
58
  StringComparator: () => StringComparator,
@@ -496,7 +498,21 @@ var BPTree = class _BPTree {
496
498
  comparator;
497
499
  option;
498
500
  order;
499
- root;
501
+ rootId;
502
+ /**
503
+ * Returns the ID of the root node.
504
+ * @returns The root node ID.
505
+ */
506
+ getRootId() {
507
+ return this.rootId;
508
+ }
509
+ /**
510
+ * Returns the order of the B+Tree.
511
+ * @returns The order of the tree.
512
+ */
513
+ getOrder() {
514
+ return this.order;
515
+ }
500
516
  _strategyDirty;
501
517
  _nodeCreateBuffer;
502
518
  _nodeUpdateBuffer;
@@ -729,40 +745,37 @@ var BPTree = class _BPTree {
729
745
  break;
730
746
  }
731
747
  keys.push(key);
732
- this.bufferForNodeUpdate(node);
733
- break;
748
+ return this.bufferForNodeUpdate(node);
734
749
  } else if (this.comparator.isLower(value, nValue)) {
735
750
  node.values.splice(i, 0, value);
736
751
  node.keys.splice(i, 0, [key]);
737
- this.bufferForNodeUpdate(node);
738
- break;
752
+ return this.bufferForNodeUpdate(node);
739
753
  } else if (i + 1 === node.values.length) {
740
754
  node.values.push(value);
741
755
  node.keys.push([key]);
742
- this.bufferForNodeUpdate(node);
743
- break;
756
+ return this.bufferForNodeUpdate(node);
744
757
  }
745
758
  }
746
759
  } else {
747
760
  node.values = [value];
748
761
  node.keys = [[key]];
749
- this.bufferForNodeUpdate(node);
762
+ return this.bufferForNodeUpdate(node);
750
763
  }
751
764
  }
752
765
  bufferForNodeCreate(node) {
753
- if (node.id === this.root.id) {
766
+ if (node.id === this.rootId) {
754
767
  this._strategyDirty = true;
755
768
  }
756
769
  this._nodeCreateBuffer.set(node.id, node);
757
770
  }
758
771
  bufferForNodeUpdate(node) {
759
- if (node.id === this.root.id) {
772
+ if (node.id === this.rootId) {
760
773
  this._strategyDirty = true;
761
774
  }
762
775
  this._nodeUpdateBuffer.set(node.id, node);
763
776
  }
764
777
  bufferForNodeDelete(node) {
765
- if (node.id === this.root.id) {
778
+ if (node.id === this.rootId) {
766
779
  this._strategyDirty = true;
767
780
  }
768
781
  this._nodeDeleteBuffer.set(node.id, node);
@@ -784,7 +797,7 @@ var BPTree = class _BPTree {
784
797
  this.nodes.clear();
785
798
  }
786
799
  };
787
- var BPTreeSync = class extends BPTree {
800
+ var BPTreeSyncBase = class extends BPTree {
788
801
  constructor(strategy, comparator, option) {
789
802
  super(strategy, comparator, option);
790
803
  this.nodes = this._createCachedNode();
@@ -860,7 +873,7 @@ var BPTreeSync = class extends BPTree {
860
873
  }
861
874
  return id;
862
875
  }
863
- _createNode(isLeaf, keys, values, leaf = false, parent = null, next = null, prev = null) {
876
+ _createNode(isLeaf, keys, values, leaf = isLeaf, parent = null, next = null, prev = null) {
864
877
  const id = this._createNodeId(isLeaf);
865
878
  const node = {
866
879
  id,
@@ -871,38 +884,37 @@ var BPTreeSync = class extends BPTree {
871
884
  next,
872
885
  prev
873
886
  };
874
- this._nodeCreateBuffer.set(id, node);
887
+ this.bufferForNodeCreate(node);
875
888
  return node;
876
889
  }
877
890
  _deleteEntry(node, key, value) {
878
891
  if (!node.leaf) {
892
+ let keyIndex = -1;
879
893
  for (let i = 0, len = node.keys.length; i < len; i++) {
880
- const nKey = node.keys[i];
881
- if (nKey === key) {
882
- node.keys.splice(i, 1);
883
- this.bufferForNodeUpdate(node);
894
+ if (node.keys[i] === key) {
895
+ keyIndex = i;
884
896
  break;
885
897
  }
886
898
  }
887
- for (let i = 0, len = node.values.length; i < len; i++) {
888
- const nValue = node.values[i];
889
- if (this.comparator.isSame(value, nValue)) {
890
- node.values.splice(i, 1);
891
- this.bufferForNodeUpdate(node);
892
- break;
893
- }
899
+ if (keyIndex !== -1) {
900
+ node.keys.splice(keyIndex, 1);
901
+ const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
902
+ node.values.splice(valueIndex, 1);
903
+ this.bufferForNodeUpdate(node);
894
904
  }
895
905
  }
896
- if (this.root.id === node.id && node.keys.length === 1) {
906
+ if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
897
907
  const keys = node.keys;
898
- this.bufferForNodeDelete(this.root);
899
- this.root = this.getNode(keys[0]);
900
- this.root.parent = null;
901
- this.strategy.head.root = this.root.id;
902
- this.bufferForNodeUpdate(this.root);
908
+ this.bufferForNodeDelete(node);
909
+ const newRoot = this.getNode(keys[0]);
910
+ this.rootId = newRoot.id;
911
+ newRoot.parent = null;
912
+ this.strategy.head.root = this.rootId;
913
+ this.bufferForNodeUpdate(newRoot);
903
914
  return;
904
- } else if (this.root.id === node.id) {
905
- this.bufferForNodeUpdate(this.root);
915
+ } else if (this.rootId === node.id) {
916
+ const root = this.getNode(this.rootId);
917
+ this.bufferForNodeUpdate(root);
906
918
  return;
907
919
  } else if (node.keys.length < Math.ceil(this.order / 2) && !node.leaf || node.values.length < Math.ceil((this.order - 1) / 2) && node.leaf) {
908
920
  if (node.parent === null) {
@@ -960,20 +972,11 @@ var BPTreeSync = class extends BPTree {
960
972
  pointer.values.push(guess);
961
973
  } else {
962
974
  pointer.next = node.next;
963
- pointer.prev = node.id;
964
975
  if (pointer.next) {
965
- const n = this.getNode(node.next);
976
+ const n = this.getNode(pointer.next);
966
977
  n.prev = pointer.id;
967
978
  this.bufferForNodeUpdate(n);
968
979
  }
969
- if (pointer.prev) {
970
- const n = this.getNode(node.id);
971
- n.next = pointer.id;
972
- this.bufferForNodeUpdate(n);
973
- }
974
- if (isPredecessor) {
975
- pointer.prev = null;
976
- }
977
980
  }
978
981
  pointer.values.push(...node.values);
979
982
  if (!pointer.leaf) {
@@ -997,13 +1000,10 @@ var BPTreeSync = class extends BPTree {
997
1000
  node.keys = [pointerPm, ...node.keys];
998
1001
  node.values = [guess, ...node.values];
999
1002
  parentNode = this.getNode(node.parent);
1000
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
1001
- const nValue = parentNode.values[i];
1002
- if (this.comparator.isSame(guess, nValue)) {
1003
- parentNode.values[i] = pointerKm;
1004
- this.bufferForNodeUpdate(parentNode);
1005
- break;
1006
- }
1003
+ const nodeIndex = parentNode.keys.indexOf(node.id);
1004
+ if (nodeIndex > 0) {
1005
+ parentNode.values[nodeIndex - 1] = pointerKm;
1006
+ this.bufferForNodeUpdate(parentNode);
1007
1007
  }
1008
1008
  } else {
1009
1009
  pointerPm = pointer.keys.splice(-1)[0];
@@ -1011,13 +1011,10 @@ var BPTreeSync = class extends BPTree {
1011
1011
  node.keys = [pointerPm, ...node.keys];
1012
1012
  node.values = [pointerKm, ...node.values];
1013
1013
  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] = pointerKm;
1018
- this.bufferForNodeUpdate(parentNode);
1019
- break;
1020
- }
1014
+ const nodeIndex = parentNode.keys.indexOf(node.id);
1015
+ if (nodeIndex > 0) {
1016
+ parentNode.values[nodeIndex - 1] = pointerKm;
1017
+ this.bufferForNodeUpdate(parentNode);
1021
1018
  }
1022
1019
  }
1023
1020
  this.bufferForNodeUpdate(node);
@@ -1031,13 +1028,10 @@ var BPTreeSync = class extends BPTree {
1031
1028
  node.keys = [...node.keys, pointerP0];
1032
1029
  node.values = [...node.values, guess];
1033
1030
  parentNode = this.getNode(node.parent);
1034
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
1035
- const nValue = parentNode.values[i];
1036
- if (this.comparator.isSame(guess, nValue)) {
1037
- parentNode.values[i] = pointerK0;
1038
- this.bufferForNodeUpdate(parentNode);
1039
- break;
1040
- }
1031
+ const pointerIndex = parentNode.keys.indexOf(pointer.id);
1032
+ if (pointerIndex > 0) {
1033
+ parentNode.values[pointerIndex - 1] = pointerK0;
1034
+ this.bufferForNodeUpdate(parentNode);
1041
1035
  }
1042
1036
  } else {
1043
1037
  pointerP0 = pointer.keys.splice(0, 1)[0];
@@ -1045,13 +1039,10 @@ var BPTreeSync = class extends BPTree {
1045
1039
  node.keys = [...node.keys, pointerP0];
1046
1040
  node.values = [...node.values, pointerK0];
1047
1041
  parentNode = this.getNode(node.parent);
1048
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
1049
- const nValue = parentNode.values[i];
1050
- if (this.comparator.isSame(guess, nValue)) {
1051
- parentNode.values[i] = pointer.values[0];
1052
- this.bufferForNodeUpdate(parentNode);
1053
- break;
1054
- }
1042
+ const pointerIndex = parentNode.keys.indexOf(pointer.id);
1043
+ if (pointerIndex > 0) {
1044
+ parentNode.values[pointerIndex - 1] = pointer.values[0];
1045
+ this.bufferForNodeUpdate(parentNode);
1055
1046
  }
1056
1047
  }
1057
1048
  this.bufferForNodeUpdate(node);
@@ -1079,12 +1070,14 @@ var BPTreeSync = class extends BPTree {
1079
1070
  }
1080
1071
  }
1081
1072
  }
1073
+ } else {
1074
+ this.bufferForNodeUpdate(node);
1082
1075
  }
1083
1076
  }
1084
1077
  _insertInParent(node, value, pointer) {
1085
- if (this.root.id === node.id) {
1078
+ if (this.rootId === node.id) {
1086
1079
  const root = this._createNode(false, [node.id, pointer.id], [value]);
1087
- this.root = root;
1080
+ this.rootId = root.id;
1088
1081
  this.strategy.head.root = root.id;
1089
1082
  node.parent = root.id;
1090
1083
  pointer.parent = root.id;
@@ -1097,31 +1090,25 @@ var BPTreeSync = class extends BPTree {
1097
1090
  return;
1098
1091
  }
1099
1092
  const parentNode = this.getNode(node.parent);
1100
- let insertIndex = 0;
1101
- for (let i = 0; i < parentNode.values.length; i++) {
1102
- if (this.comparator.asc(value, parentNode.values[i]) > 0) {
1103
- insertIndex = i + 1;
1104
- } else {
1105
- break;
1106
- }
1093
+ const nodeIndex = parentNode.keys.indexOf(node.id);
1094
+ if (nodeIndex === -1) {
1095
+ throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
1107
1096
  }
1097
+ const insertIndex = nodeIndex;
1108
1098
  parentNode.values.splice(insertIndex, 0, value);
1109
1099
  parentNode.keys.splice(insertIndex + 1, 0, pointer.id);
1110
1100
  pointer.parent = parentNode.id;
1111
1101
  if (pointer.leaf) {
1112
- const leftSiblingId = parentNode.keys[insertIndex];
1113
- const rightSiblingId = parentNode.keys[insertIndex + 2];
1114
- if (leftSiblingId) {
1115
- const leftSibling = this.getNode(leftSiblingId);
1116
- pointer.prev = leftSibling.id;
1117
- pointer.next = leftSibling.next;
1118
- leftSibling.next = pointer.id;
1119
- this.bufferForNodeUpdate(leftSibling);
1120
- }
1121
- if (rightSiblingId) {
1122
- const rightSibling = this.getNode(rightSiblingId);
1123
- rightSibling.prev = pointer.id;
1124
- this.bufferForNodeUpdate(rightSibling);
1102
+ const leftSibling = node;
1103
+ const oldNextId = leftSibling.next;
1104
+ pointer.prev = leftSibling.id;
1105
+ pointer.next = oldNextId;
1106
+ leftSibling.next = pointer.id;
1107
+ this.bufferForNodeUpdate(leftSibling);
1108
+ if (oldNextId) {
1109
+ const oldNext = this.getNode(oldNextId);
1110
+ oldNext.prev = pointer.id;
1111
+ this.bufferForNodeUpdate(oldNext);
1125
1112
  }
1126
1113
  }
1127
1114
  this.bufferForNodeUpdate(parentNode);
@@ -1150,18 +1137,20 @@ var BPTreeSync = class extends BPTree {
1150
1137
  }
1151
1138
  }
1152
1139
  init() {
1140
+ this.clear();
1153
1141
  const head = this.strategy.readHead();
1154
1142
  if (head === null) {
1155
1143
  this.order = this.strategy.order;
1156
- this.root = this._createNode(true, [], [], true);
1157
- this.strategy.head.root = this.root.id;
1144
+ const root = this._createNode(true, [], [], true);
1145
+ this.rootId = root.id;
1146
+ this.strategy.head.root = this.rootId;
1158
1147
  this.commitHeadBuffer();
1159
1148
  this.commitNodeCreateBuffer();
1160
1149
  } else {
1161
1150
  const { root, order } = head;
1162
1151
  this.strategy.head = head;
1163
1152
  this.order = order;
1164
- this.root = this.getNode(root);
1153
+ this.rootId = root;
1165
1154
  }
1166
1155
  if (this.order < 3) {
1167
1156
  throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
@@ -1178,43 +1167,73 @@ var BPTreeSync = class extends BPTree {
1178
1167
  return cache.raw;
1179
1168
  }
1180
1169
  insertableNode(value) {
1181
- let node = this.getNode(this.root.id);
1170
+ let node = this.getNode(this.rootId);
1171
+ if (node.parent !== null) {
1172
+ node.parent = null;
1173
+ this.bufferForNodeUpdate(node);
1174
+ }
1182
1175
  while (!node.leaf) {
1176
+ const parentId = node.id;
1183
1177
  for (let i = 0, len = node.values.length; i < len; i++) {
1184
1178
  const nValue = node.values[i];
1185
1179
  const k = node.keys;
1186
1180
  if (this.comparator.isSame(value, nValue)) {
1187
1181
  node = this.getNode(k[i + 1]);
1182
+ if (node.parent !== parentId) {
1183
+ node.parent = parentId;
1184
+ this.bufferForNodeUpdate(node);
1185
+ }
1188
1186
  break;
1189
1187
  } else if (this.comparator.isLower(value, nValue)) {
1190
1188
  node = this.getNode(k[i]);
1189
+ if (node.parent !== parentId) {
1190
+ node.parent = parentId;
1191
+ this.bufferForNodeUpdate(node);
1192
+ }
1191
1193
  break;
1192
1194
  } else if (i + 1 === node.values.length) {
1193
1195
  node = this.getNode(k[i + 1]);
1196
+ if (node.parent !== parentId) {
1197
+ node.parent = parentId;
1198
+ this.bufferForNodeUpdate(node);
1199
+ }
1194
1200
  break;
1195
1201
  }
1196
1202
  }
1197
1203
  }
1198
1204
  return node;
1199
1205
  }
1200
- /**
1201
- * Find the insertable node using primaryAsc comparison.
1202
- * This allows finding nodes by primary value only, ignoring unique identifiers.
1203
- */
1204
1206
  insertableNodeByPrimary(value) {
1205
- let node = this.getNode(this.root.id);
1207
+ let node = this.getNode(this.rootId);
1208
+ if (node.parent !== null) {
1209
+ node.parent = null;
1210
+ this.bufferForNodeUpdate(node);
1211
+ }
1206
1212
  while (!node.leaf) {
1213
+ const parentId = node.id;
1207
1214
  for (let i = 0, len = node.values.length; i < len; i++) {
1208
1215
  const nValue = node.values[i];
1209
1216
  const k = node.keys;
1210
1217
  if (this.comparator.isPrimarySame(value, nValue)) {
1211
1218
  node = this.getNode(k[i]);
1219
+ if (node.parent !== parentId) {
1220
+ node.parent = parentId;
1221
+ this.bufferForNodeUpdate(node);
1222
+ }
1212
1223
  break;
1213
1224
  } else if (this.comparator.isPrimaryLower(value, nValue)) {
1214
1225
  node = this.getNode(k[i]);
1226
+ if (node.parent !== parentId) {
1227
+ node.parent = parentId;
1228
+ this.bufferForNodeUpdate(node);
1229
+ }
1215
1230
  break;
1216
1231
  } else if (i + 1 === node.values.length) {
1217
1232
  node = this.getNode(k[i + 1]);
1233
+ if (node.parent !== parentId) {
1234
+ node.parent = parentId;
1235
+ this.bufferForNodeUpdate(node);
1236
+ }
1218
1237
  break;
1219
1238
  }
1220
1239
  }
@@ -1222,17 +1241,30 @@ var BPTreeSync = class extends BPTree {
1222
1241
  return node;
1223
1242
  }
1224
1243
  insertableRightestNodeByPrimary(value) {
1225
- let node = this.getNode(this.root.id);
1244
+ let node = this.getNode(this.rootId);
1245
+ if (node.parent !== null) {
1246
+ node.parent = null;
1247
+ this.bufferForNodeUpdate(node);
1248
+ }
1226
1249
  while (!node.leaf) {
1250
+ const parentId = node.id;
1227
1251
  for (let i = 0, len = node.values.length; i < len; i++) {
1228
1252
  const nValue = node.values[i];
1229
1253
  const k = node.keys;
1230
1254
  if (this.comparator.isPrimaryLower(value, nValue)) {
1231
1255
  node = this.getNode(k[i]);
1256
+ if (node.parent !== parentId) {
1257
+ node.parent = parentId;
1258
+ this.bufferForNodeUpdate(node);
1259
+ }
1232
1260
  break;
1233
1261
  }
1234
1262
  if (i + 1 === node.values.length) {
1235
1263
  node = this.getNode(k[i + 1]);
1264
+ if (node.parent !== parentId) {
1265
+ node.parent = parentId;
1266
+ this.bufferForNodeUpdate(node);
1267
+ }
1236
1268
  break;
1237
1269
  }
1238
1270
  }
@@ -1266,27 +1298,75 @@ var BPTreeSync = class extends BPTree {
1266
1298
  return this.getNode(guessNode);
1267
1299
  }
1268
1300
  leftestNode() {
1269
- let node = this.root;
1301
+ let node = this.getNode(this.rootId);
1302
+ if (node.parent !== null) {
1303
+ node.parent = null;
1304
+ this.bufferForNodeUpdate(node);
1305
+ }
1270
1306
  while (!node.leaf) {
1307
+ const parentId = node.id;
1271
1308
  const keys = node.keys;
1272
1309
  node = this.getNode(keys[0]);
1310
+ if (node.parent !== parentId) {
1311
+ node.parent = parentId;
1312
+ this.bufferForNodeUpdate(node);
1313
+ }
1273
1314
  }
1274
1315
  return node;
1275
1316
  }
1276
1317
  rightestNode() {
1277
- let node = this.root;
1318
+ let node = this.getNode(this.rootId);
1319
+ if (node.parent !== null) {
1320
+ node.parent = null;
1321
+ this.bufferForNodeUpdate(node);
1322
+ }
1278
1323
  while (!node.leaf) {
1324
+ const parentId = node.id;
1279
1325
  const keys = node.keys;
1280
1326
  node = this.getNode(keys[keys.length - 1]);
1327
+ if (node.parent !== parentId) {
1328
+ node.parent = parentId;
1329
+ this.bufferForNodeUpdate(node);
1330
+ }
1281
1331
  }
1282
1332
  return node;
1283
1333
  }
1334
+ exists(key, value) {
1335
+ const node = this.insertableNode(value);
1336
+ for (let i = 0, len = node.values.length; i < len; i++) {
1337
+ if (this.comparator.isSame(value, node.values[i])) {
1338
+ const keys = node.keys[i];
1339
+ if (keys.includes(key)) {
1340
+ return true;
1341
+ }
1342
+ }
1343
+ }
1344
+ return false;
1345
+ }
1346
+ forceUpdate(id) {
1347
+ if (id) {
1348
+ this.nodes.delete(id);
1349
+ this.getNode(id);
1350
+ return 1;
1351
+ }
1352
+ const keys = Array.from(this.nodes.keys());
1353
+ for (const key of keys) {
1354
+ this.nodes.delete(key);
1355
+ }
1356
+ for (const key of keys) {
1357
+ this.getNode(key);
1358
+ }
1359
+ return keys.length;
1360
+ }
1284
1361
  commitHeadBuffer() {
1285
1362
  if (!this._strategyDirty) {
1286
1363
  return;
1287
1364
  }
1288
1365
  this._strategyDirty = false;
1289
1366
  this.strategy.writeHead(this.strategy.head);
1367
+ if (this.strategy.head.root) {
1368
+ this.nodes.delete(this.strategy.head.root);
1369
+ }
1290
1370
  }
1291
1371
  commitNodeCreateBuffer() {
1292
1372
  for (const node of this._nodeCreateBuffer.values()) {
@@ -1297,33 +1377,25 @@ var BPTreeSync = class extends BPTree {
1297
1377
  commitNodeUpdateBuffer() {
1298
1378
  for (const node of this._nodeUpdateBuffer.values()) {
1299
1379
  this.strategy.write(node.id, node);
1380
+ this.nodes.delete(node.id);
1300
1381
  }
1301
1382
  this._nodeUpdateBuffer.clear();
1302
1383
  }
1303
1384
  commitNodeDeleteBuffer() {
1304
1385
  for (const node of this._nodeDeleteBuffer.values()) {
1305
1386
  this.strategy.delete(node.id);
1387
+ this.nodes.delete(node.id);
1306
1388
  }
1307
1389
  this._nodeDeleteBuffer.clear();
1308
1390
  }
1309
- /**
1310
- * Retrieves the value associated with the given key (PK).
1311
- * Note: This method performs a full scan of leaf nodes as the tree is ordered by Value, not Key.
1312
- *
1313
- * @param key The key to search for.
1314
- * @returns The value associated with the key, or undefined if not found.
1315
- */
1316
1391
  get(key) {
1317
1392
  let node = this.leftestNode();
1318
1393
  while (true) {
1319
- if (node.values) {
1320
- const len = node.values.length;
1321
- for (let i = 0; i < len; i++) {
1322
- const keys = node.keys[i];
1323
- for (let j = 0; j < keys.length; j++) {
1324
- if (keys[j] === key) {
1325
- return node.values[i];
1326
- }
1394
+ for (let i = 0, len = node.values.length; i < len; i++) {
1395
+ const keys = node.keys[i];
1396
+ for (let j = 0, kLen = keys.length; j < kLen; j++) {
1397
+ if (keys[j] === key) {
1398
+ return node.values[i];
1327
1399
  }
1328
1400
  }
1329
1401
  }
@@ -1442,21 +1514,15 @@ var BPTreeSync = class extends BPTree {
1442
1514
  const nValue = node.values[i];
1443
1515
  if (this.comparator.isSame(value, nValue)) {
1444
1516
  const keys = node.keys[i];
1445
- if (keys.includes(key)) {
1446
- if (keys.length > 1) {
1447
- keys.splice(keys.indexOf(key), 1);
1448
- this.bufferForNodeUpdate(node);
1449
- } else if (node.id === this.root.id) {
1450
- node.values.splice(i, 1);
1517
+ const keyIndex = keys.indexOf(key);
1518
+ if (keyIndex !== -1) {
1519
+ keys.splice(keyIndex, 1);
1520
+ if (keys.length === 0) {
1451
1521
  node.keys.splice(i, 1);
1452
- this.bufferForNodeUpdate(node);
1453
- } else {
1454
- keys.splice(keys.indexOf(key), 1);
1455
- node.keys.splice(i, 1);
1456
- node.values.splice(node.values.indexOf(value), 1);
1457
- this._deleteEntry(node, key, value);
1458
- this.bufferForNodeUpdate(node);
1522
+ node.values.splice(i, 1);
1459
1523
  }
1524
+ this._deleteEntry(node, key, value);
1525
+ break;
1460
1526
  }
1461
1527
  }
1462
1528
  }
@@ -1465,294 +1531,410 @@ var BPTreeSync = class extends BPTree {
1465
1531
  this.commitNodeUpdateBuffer();
1466
1532
  this.commitNodeDeleteBuffer();
1467
1533
  }
1468
- exists(key, value) {
1469
- const node = this.insertableNode(value);
1470
- for (let i = 0, len = node.values.length; i < len; i++) {
1471
- const nValue = node.values[i];
1472
- if (this.comparator.isSame(value, nValue)) {
1473
- const keys = node.keys[i];
1474
- return keys.includes(key);
1475
- }
1476
- }
1477
- return false;
1534
+ getHeadData() {
1535
+ return this.strategy.head.data;
1478
1536
  }
1479
1537
  setHeadData(data) {
1480
1538
  this.strategy.head.data = data;
1481
- this._strategyDirty = true;
1482
- this.commitHeadBuffer();
1539
+ this.strategy.writeHead(this.strategy.head);
1483
1540
  }
1484
- forceUpdate() {
1485
- const keys = [...this.nodes.keys()];
1486
- this.nodes.clear();
1487
- this.init();
1488
- for (const key of keys) {
1489
- this.getNode(key);
1490
- }
1491
- return keys.length;
1541
+ };
1542
+ var SerializeStrategy = class {
1543
+ order;
1544
+ head;
1545
+ constructor(order) {
1546
+ this.order = order;
1547
+ this.head = {
1548
+ order,
1549
+ root: null,
1550
+ data: {}
1551
+ };
1492
1552
  }
1493
1553
  };
1494
- var Ryoiki = class _Ryoiki {
1495
- readings;
1496
- writings;
1497
- readQueue;
1498
- writeQueue;
1499
- static async CatchError(promise) {
1500
- return await promise.then((v) => [void 0, v]).catch((err) => [err]);
1554
+ var SerializeStrategySync = class extends SerializeStrategy {
1555
+ getHeadData(key, defaultValue) {
1556
+ if (!Object.hasOwn(this.head.data, key)) {
1557
+ this.setHeadData(key, defaultValue);
1558
+ }
1559
+ return this.head.data[key];
1501
1560
  }
1502
- static IsRangeOverlap(a, b) {
1503
- const [start1, end1] = a;
1504
- const [start2, end2] = b;
1505
- if (end1 <= start2 || end2 <= start1) {
1561
+ setHeadData(key, data) {
1562
+ this.head.data[key] = data;
1563
+ this.writeHead(this.head);
1564
+ }
1565
+ autoIncrement(key, defaultValue) {
1566
+ const current = this.getHeadData(key, defaultValue);
1567
+ const next = current + 1;
1568
+ this.setHeadData(key, next);
1569
+ return current;
1570
+ }
1571
+ compareAndSwapHead(oldRoot, newRoot) {
1572
+ if (this.head.root !== oldRoot) {
1506
1573
  return false;
1507
1574
  }
1575
+ this.head.root = newRoot;
1576
+ this.writeHead(this.head);
1508
1577
  return true;
1509
1578
  }
1510
- static ERR_ALREADY_EXISTS(lockId) {
1511
- return new Error(`The '${lockId}' task already existing in queue or running.`);
1579
+ };
1580
+ var InMemoryStoreStrategySync = class extends SerializeStrategySync {
1581
+ node;
1582
+ constructor(order) {
1583
+ super(order);
1584
+ this.node = {};
1512
1585
  }
1513
- static ERR_NOT_EXISTS(lockId) {
1514
- return new Error(`The '${lockId}' task not existing in task queue.`);
1586
+ id(isLeaf) {
1587
+ return this.autoIncrement("index", 1).toString();
1515
1588
  }
1516
- static ERR_TIMEOUT(lockId, timeout) {
1517
- return new Error(`The task with ID '${lockId}' failed to acquire the lock within the timeout(${timeout}ms).`);
1589
+ read(id) {
1590
+ if (!Object.hasOwn(this.node, id)) {
1591
+ throw new Error(`The tree attempted to reference node '${id}', but couldn't find the corresponding node.`);
1592
+ }
1593
+ const node = this.node[id];
1594
+ return JSON.parse(JSON.stringify(node));
1518
1595
  }
1519
- /**
1520
- * Constructs a new instance of the Ryoiki class.
1521
- */
1522
- constructor() {
1523
- this.readings = /* @__PURE__ */ new Map();
1524
- this.writings = /* @__PURE__ */ new Map();
1525
- this.readQueue = /* @__PURE__ */ new Map();
1526
- this.writeQueue = /* @__PURE__ */ new Map();
1596
+ write(id, node) {
1597
+ this.node[id] = node;
1527
1598
  }
1528
- /**
1529
- * Creates a range based on a start value and length.
1530
- * @param start - The starting value of the range.
1531
- * @param length - The length of the range.
1532
- * @returns A range tuple [start, start + length].
1533
- */
1534
- range(start, length) {
1535
- return [start, start + length];
1599
+ delete(id) {
1600
+ delete this.node[id];
1536
1601
  }
1537
- rangeOverlapping(tasks, range) {
1538
- return Array.from(tasks.values()).some((t) => _Ryoiki.IsRangeOverlap(t.range, range));
1602
+ readHead() {
1603
+ if (this.head.root === null) {
1604
+ return null;
1605
+ }
1606
+ return this.head;
1539
1607
  }
1540
- isSameRange(a, b) {
1541
- const [a1, a2] = a;
1542
- const [b1, b2] = b;
1543
- return a1 === b1 && a2 === b2;
1608
+ writeHead(head) {
1609
+ this.head = head;
1544
1610
  }
1545
- fetchUnitAndRun(queue, workspaces) {
1546
- for (const [id, unit] of queue) {
1547
- if (!unit.condition()) {
1548
- continue;
1549
- }
1550
- this._alloc(queue, workspaces, id);
1551
- }
1611
+ };
1612
+ var BPTreeSyncSnapshotStrategy = class extends SerializeStrategySync {
1613
+ baseStrategy;
1614
+ snapshotHead;
1615
+ constructor(baseStrategy, root) {
1616
+ super(baseStrategy.order);
1617
+ this.baseStrategy = baseStrategy;
1618
+ this.snapshotHead = {
1619
+ ...baseStrategy.head,
1620
+ root,
1621
+ data: { ...baseStrategy.head.data }
1622
+ };
1623
+ this.head = this.snapshotHead;
1552
1624
  }
1553
- _handleOverload(args, handlers, argPatterns) {
1554
- for (const [key, pattern] of Object.entries(argPatterns)) {
1555
- if (this._matchArgs(args, pattern)) {
1556
- return handlers[key](...args);
1557
- }
1558
- }
1559
- throw new Error("Invalid arguments");
1625
+ id(isLeaf) {
1626
+ return this.baseStrategy.id(isLeaf);
1560
1627
  }
1561
- _matchArgs(args, pattern) {
1562
- return args.every((arg, index) => {
1563
- const expectedType = pattern[index];
1564
- if (expectedType === void 0) return typeof arg === "undefined";
1565
- if (expectedType === Function) return typeof arg === "function";
1566
- if (expectedType === Number) return typeof arg === "number";
1567
- if (expectedType === Array) return Array.isArray(arg);
1568
- return false;
1569
- });
1628
+ read(id) {
1629
+ return this.baseStrategy.read(id);
1570
1630
  }
1571
- _createRandomId() {
1572
- const timestamp = Date.now().toString(36);
1573
- const random = Math.random().toString(36).substring(2);
1574
- return `${timestamp}${random}`;
1631
+ write(id, node) {
1632
+ this.baseStrategy.write(id, node);
1575
1633
  }
1576
- _alloc(queue, workspaces, lockId) {
1577
- const unit = queue.get(lockId);
1578
- if (!unit) {
1579
- throw _Ryoiki.ERR_NOT_EXISTS(lockId);
1580
- }
1581
- workspaces.set(lockId, unit);
1582
- queue.delete(lockId);
1583
- unit.alloc();
1634
+ delete(id) {
1635
+ this.baseStrategy.delete(id);
1584
1636
  }
1585
- _free(workspaces, lockId) {
1586
- const unit = workspaces.get(lockId);
1587
- if (!unit) {
1588
- throw _Ryoiki.ERR_NOT_EXISTS(lockId);
1589
- }
1590
- workspaces.delete(lockId);
1591
- unit.free();
1637
+ readHead() {
1638
+ return this.snapshotHead;
1592
1639
  }
1593
- _lock(queue, range, timeout, task, condition) {
1594
- return new Promise((resolve, reject) => {
1595
- let timeoutId = null;
1596
- if (timeout >= 0) {
1597
- timeoutId = setTimeout(() => {
1598
- reject(_Ryoiki.ERR_TIMEOUT(id, timeout));
1599
- }, timeout);
1640
+ writeHead(head) {
1641
+ this.snapshotHead.root = head.root;
1642
+ this.snapshotHead.data = { ...head.data };
1643
+ }
1644
+ compareAndSwapHead(oldRoot, newRoot) {
1645
+ return this.baseStrategy.compareAndSwapHead(oldRoot, newRoot);
1646
+ }
1647
+ getHeadData(key, defaultValue) {
1648
+ return this.snapshotHead.data[key] ?? defaultValue;
1649
+ }
1650
+ setHeadData(key, data) {
1651
+ this.snapshotHead.data[key] = data;
1652
+ }
1653
+ autoIncrement(key, defaultValue) {
1654
+ return this.snapshotHead.data[key] ?? defaultValue;
1655
+ }
1656
+ };
1657
+ var BPTreeSyncTransaction = class extends BPTreeSyncBase {
1658
+ realBaseTree;
1659
+ realBaseStrategy;
1660
+ txNodes = /* @__PURE__ */ new Map();
1661
+ dirtyIds;
1662
+ createdInTx;
1663
+ deletedIds;
1664
+ initialRootId;
1665
+ transactionRootId;
1666
+ constructor(baseTree) {
1667
+ super(baseTree.strategy, baseTree.comparator, baseTree.option);
1668
+ this.realBaseTree = baseTree;
1669
+ this.realBaseStrategy = baseTree.strategy;
1670
+ this.order = baseTree.getOrder();
1671
+ this.initialRootId = "";
1672
+ this.transactionRootId = "";
1673
+ this.dirtyIds = /* @__PURE__ */ new Set();
1674
+ this.createdInTx = /* @__PURE__ */ new Set();
1675
+ this.deletedIds = /* @__PURE__ */ new Set();
1676
+ }
1677
+ /**
1678
+ * Initializes the transaction by capturing the current state of the tree.
1679
+ */
1680
+ initTransaction() {
1681
+ const head = this.realBaseStrategy.readHead();
1682
+ if (head) {
1683
+ this.order = head.order;
1684
+ this.initialRootId = head.root;
1685
+ } else {
1686
+ this.initialRootId = this.realBaseTree.getRootId();
1687
+ }
1688
+ if (!this.initialRootId) {
1689
+ const root = this._createNode(true, [], [], true);
1690
+ this.initialRootId = root.id;
1691
+ }
1692
+ this.transactionRootId = this.initialRootId;
1693
+ this.rootId = this.transactionRootId;
1694
+ const snapshotStrategy = new BPTreeSyncSnapshotStrategy(this.realBaseStrategy, this.initialRootId);
1695
+ this.strategy = snapshotStrategy;
1696
+ this.txNodes.clear();
1697
+ this.dirtyIds.clear();
1698
+ this.createdInTx.clear();
1699
+ this.deletedIds.clear();
1700
+ }
1701
+ getNode(id) {
1702
+ if (this.txNodes.has(id)) {
1703
+ return this.txNodes.get(id);
1704
+ }
1705
+ if (this.deletedIds.has(id)) {
1706
+ throw new Error(`The tree attempted to reference deleted node '${id}'`);
1707
+ }
1708
+ const baseNode = this.realBaseStrategy.read(id);
1709
+ const clone = JSON.parse(JSON.stringify(baseNode));
1710
+ this.txNodes.set(id, clone);
1711
+ return clone;
1712
+ }
1713
+ bufferForNodeUpdate(node) {
1714
+ if (this.dirtyIds.has(node.id) && this.txNodes.has(node.id) && node._p) {
1715
+ this.txNodes.set(node.id, node);
1716
+ return;
1717
+ }
1718
+ node._p = true;
1719
+ this.txNodes.set(node.id, node);
1720
+ this.dirtyIds.add(node.id);
1721
+ if (node.leaf) {
1722
+ if (node.next && !this.dirtyIds.has(node.next) && !this.deletedIds.has(node.next)) {
1723
+ try {
1724
+ this.bufferForNodeUpdate(this.getNode(node.next));
1725
+ } catch (e) {
1726
+ }
1600
1727
  }
1601
- const id = this._createRandomId();
1602
- const alloc = async () => {
1603
- if (timeoutId !== null) {
1604
- clearTimeout(timeoutId);
1728
+ if (node.prev && !this.dirtyIds.has(node.prev) && !this.deletedIds.has(node.prev)) {
1729
+ try {
1730
+ this.bufferForNodeUpdate(this.getNode(node.prev));
1731
+ } catch (e) {
1605
1732
  }
1606
- const [err, v] = await _Ryoiki.CatchError(task(id));
1607
- if (err) reject(err);
1608
- else resolve(v);
1609
- };
1610
- const fetch = () => {
1611
- this.fetchUnitAndRun(this.readQueue, this.readings);
1612
- this.fetchUnitAndRun(this.writeQueue, this.writings);
1613
- };
1614
- queue.set(id, { id, range, condition, alloc, free: fetch });
1615
- fetch();
1616
- });
1733
+ }
1734
+ }
1735
+ this.markPathDirty(node);
1736
+ delete node._p;
1617
1737
  }
1618
- _checkWorking(range, workspaces) {
1619
- let isLocked = false;
1620
- for (const lock of workspaces.values()) {
1621
- if (_Ryoiki.IsRangeOverlap(range, lock.range)) {
1622
- isLocked = true;
1738
+ bufferForNodeCreate(node) {
1739
+ this.txNodes.set(node.id, node);
1740
+ this.dirtyIds.add(node.id);
1741
+ this.createdInTx.add(node.id);
1742
+ if (node.leaf) {
1743
+ if (node.next && !this.dirtyIds.has(node.next) && !this.deletedIds.has(node.next)) {
1744
+ try {
1745
+ this.bufferForNodeUpdate(this.getNode(node.next));
1746
+ } catch (e) {
1747
+ }
1748
+ }
1749
+ if (node.prev && !this.dirtyIds.has(node.prev) && !this.deletedIds.has(node.prev)) {
1750
+ try {
1751
+ this.bufferForNodeUpdate(this.getNode(node.prev));
1752
+ } catch (e) {
1753
+ }
1754
+ }
1755
+ }
1756
+ this.markPathDirty(node);
1757
+ }
1758
+ bufferForNodeDelete(node) {
1759
+ this.txNodes.delete(node.id);
1760
+ this.dirtyIds.add(node.id);
1761
+ this.deletedIds.add(node.id);
1762
+ }
1763
+ markPathDirty(node) {
1764
+ let curr = node;
1765
+ while (curr.parent) {
1766
+ if (this.deletedIds.has(curr.parent)) {
1623
1767
  break;
1624
1768
  }
1769
+ if (this.dirtyIds.has(curr.parent) && this.txNodes.has(curr.parent)) {
1770
+ break;
1771
+ }
1772
+ const parent = this.getNode(curr.parent);
1773
+ this.dirtyIds.add(parent.id);
1774
+ curr = parent;
1775
+ }
1776
+ if (!curr.parent) {
1777
+ this.transactionRootId = curr.id;
1625
1778
  }
1626
- return isLocked;
1627
1779
  }
1628
- /**
1629
- * Checks if there is any active read lock within the specified range.
1630
- * @param range The range to check for active read locks.
1631
- * @returns `true` if there is an active read lock within the range, `false` otherwise.
1632
- */
1633
- isReading(range) {
1634
- return this._checkWorking(range, this.readings);
1780
+ _createNode(isLeaf, keys, values, leaf = isLeaf, parent = null, next = null, prev = null) {
1781
+ const id = this.strategy.id(isLeaf);
1782
+ const node = {
1783
+ id,
1784
+ keys,
1785
+ values,
1786
+ leaf,
1787
+ parent,
1788
+ next,
1789
+ prev
1790
+ };
1791
+ this.bufferForNodeCreate(node);
1792
+ return node;
1635
1793
  }
1636
1794
  /**
1637
- * Checks if there is any active write lock within the specified range.
1638
- * @param range The range to check for active write locks.
1639
- * @returns `true` if there is an active write lock within the range, `false` otherwise.
1640
- */
1641
- isWriting(range) {
1642
- return this._checkWorking(range, this.writings);
1795
+ * Attempts to commit the transaction.
1796
+ * Uses Optimistic Locking (Compare-And-Swap) on the root node ID to detect conflicts.
1797
+ *
1798
+ * @returns The transaction result.
1799
+ */
1800
+ commit() {
1801
+ const idMapping = /* @__PURE__ */ new Map();
1802
+ const finalNodes = [];
1803
+ for (const oldId of this.dirtyIds) {
1804
+ if (this.createdInTx.has(oldId)) {
1805
+ idMapping.set(oldId, oldId);
1806
+ } else {
1807
+ const node = this.txNodes.get(oldId);
1808
+ if (node) {
1809
+ const newId = this.realBaseStrategy.id(node.leaf);
1810
+ idMapping.set(oldId, newId);
1811
+ }
1812
+ }
1813
+ }
1814
+ const newCreatedIds = [];
1815
+ for (const oldId of this.dirtyIds) {
1816
+ const node = this.txNodes.get(oldId);
1817
+ if (!node) continue;
1818
+ const newId = idMapping.get(oldId);
1819
+ node.id = newId;
1820
+ if (node.parent && idMapping.has(node.parent)) {
1821
+ node.parent = idMapping.get(node.parent);
1822
+ }
1823
+ if (!node.leaf) {
1824
+ const internal = node;
1825
+ for (let i = 0; i < internal.keys.length; i++) {
1826
+ const childId = internal.keys[i];
1827
+ if (idMapping.has(childId)) {
1828
+ internal.keys[i] = idMapping.get(childId);
1829
+ }
1830
+ }
1831
+ }
1832
+ if (node.leaf) {
1833
+ const leaf = node;
1834
+ if (leaf.next && idMapping.has(leaf.next)) {
1835
+ leaf.next = idMapping.get(leaf.next);
1836
+ }
1837
+ if (leaf.prev && idMapping.has(leaf.prev)) {
1838
+ leaf.prev = idMapping.get(leaf.prev);
1839
+ }
1840
+ }
1841
+ finalNodes.push(node);
1842
+ newCreatedIds.push(newId);
1843
+ }
1844
+ let newRootId = this.rootId;
1845
+ if (idMapping.has(this.rootId)) {
1846
+ newRootId = idMapping.get(this.rootId);
1847
+ }
1848
+ for (const node of finalNodes) {
1849
+ this.realBaseStrategy.write(node.id, node);
1850
+ }
1851
+ const success = this.realBaseStrategy.compareAndSwapHead(this.initialRootId, newRootId);
1852
+ if (success) {
1853
+ const distinctObsolete = /* @__PURE__ */ new Set();
1854
+ for (const oldId of this.dirtyIds) {
1855
+ if (!this.createdInTx.has(oldId) && this.txNodes.has(oldId)) {
1856
+ distinctObsolete.add(oldId);
1857
+ }
1858
+ }
1859
+ return {
1860
+ success: true,
1861
+ createdIds: newCreatedIds,
1862
+ obsoleteIds: Array.from(distinctObsolete)
1863
+ };
1864
+ } else {
1865
+ this.rollback();
1866
+ return {
1867
+ success: false,
1868
+ createdIds: newCreatedIds,
1869
+ obsoleteIds: []
1870
+ };
1871
+ }
1643
1872
  }
1644
1873
  /**
1645
- * Checks if a read lock can be acquired within the specified range.
1646
- * @param range The range to check for read lock availability.
1647
- * @returns `true` if a read lock can be acquired, `false` otherwise.
1874
+ * Rolls back the transaction by clearing all buffered changes.
1875
+ * If cleanup is `true`, it also clears the transaction nodes.
1876
+ * @param cleanup Whether to clear the transaction nodes.
1877
+ * @returns The IDs of nodes that were created in this transaction.
1648
1878
  */
1649
- canRead(range) {
1650
- const writing = this.isWriting(range);
1651
- return !writing;
1879
+ rollback(cleanup = true) {
1880
+ const createdIds = Array.from(this.createdInTx);
1881
+ this.txNodes.clear();
1882
+ this.dirtyIds.clear();
1883
+ this.createdInTx.clear();
1884
+ if (cleanup) {
1885
+ for (const id of createdIds) {
1886
+ this.realBaseStrategy.delete(id);
1887
+ }
1888
+ }
1889
+ return createdIds;
1652
1890
  }
1653
- /**
1654
- * Checks if a write lock can be acquired within the specified range.
1655
- * @param range The range to check for write lock availability.
1656
- * @returns `true` if a write lock can be acquired, `false` otherwise.
1657
- */
1658
- canWrite(range) {
1659
- const reading = this.isReading(range);
1660
- const writing = this.isWriting(range);
1661
- return !reading && !writing;
1891
+ // Override to do nothing, as transaction handles its own commits
1892
+ commitHeadBuffer() {
1662
1893
  }
1663
- /**
1664
- * Internal implementation of the read lock. Handles both overloads.
1665
- * @template T - The return type of the task.
1666
- * @param arg0 - Either a range or a task callback.
1667
- * If a range is provided, the task is the second argument.
1668
- * @param arg1 - The task to execute, required if a range is provided.
1669
- * @param arg2 - The timeout for acquiring the lock.
1670
- * If the lock cannot be acquired within this period, an error will be thrown.
1671
- * If this value is not provided, no timeout will be set.
1672
- * @returns A promise resolving to the result of the task execution.
1673
- */
1674
- readLock(arg0, arg1, arg2) {
1675
- const [range, task, timeout] = this._handleOverload(
1676
- [arg0, arg1, arg2],
1677
- {
1678
- rangeTask: (range2, task2) => [range2, task2, -1],
1679
- rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
1680
- task: (task2) => [[-Infinity, Infinity], task2, -1],
1681
- taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
1682
- },
1683
- {
1684
- task: [Function],
1685
- taskTimeout: [Function, Number],
1686
- rangeTask: [Array, Function],
1687
- rangeTaskTimeout: [Array, Function, Number]
1688
- }
1689
- );
1690
- return this._lock(
1691
- this.readQueue,
1692
- range,
1693
- timeout,
1694
- task,
1695
- () => !this.rangeOverlapping(this.writings, range)
1696
- );
1894
+ commitNodeCreateBuffer() {
1697
1895
  }
1698
- /**
1699
- * Internal implementation of the write lock. Handles both overloads.
1700
- * @template T - The return type of the task.
1701
- * @param arg0 - Either a range or a task callback.
1702
- * If a range is provided, the task is the second argument.
1703
- * @param arg1 - The task to execute, required if a range is provided.
1704
- * @param arg2 - The timeout for acquiring the lock.
1705
- * If the lock cannot be acquired within this period, an error will be thrown.
1706
- * If this value is not provided, no timeout will be set.
1707
- * @returns A promise resolving to the result of the task execution.
1708
- */
1709
- writeLock(arg0, arg1, arg2) {
1710
- const [range, task, timeout] = this._handleOverload(
1711
- [arg0, arg1, arg2],
1712
- {
1713
- rangeTask: (range2, task2) => [range2, task2, -1],
1714
- rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
1715
- task: (task2) => [[-Infinity, Infinity], task2, -1],
1716
- taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
1717
- },
1718
- {
1719
- task: [Function],
1720
- taskTimeout: [Function, Number],
1721
- rangeTask: [Array, Function],
1722
- rangeTaskTimeout: [Array, Function, Number]
1723
- }
1724
- );
1725
- return this._lock(
1726
- this.writeQueue,
1727
- range,
1728
- timeout,
1729
- task,
1730
- () => {
1731
- return !this.rangeOverlapping(this.writings, range) && !this.rangeOverlapping(this.readings, range);
1732
- }
1733
- );
1896
+ commitNodeUpdateBuffer() {
1734
1897
  }
1735
- /**
1736
- * Releases a read lock by its lock ID.
1737
- * @param lockId - The unique identifier for the lock to release.
1738
- */
1739
- readUnlock(lockId) {
1740
- this._free(this.readings, lockId);
1898
+ commitNodeDeleteBuffer() {
1899
+ }
1900
+ };
1901
+ var BPTreeSync = class extends BPTreeSyncBase {
1902
+ constructor(strategy, comparator, option) {
1903
+ super(strategy, comparator, option);
1904
+ this.init();
1741
1905
  }
1742
1906
  /**
1743
- * Releases a write lock by its lock ID.
1744
- * @param lockId - The unique identifier for the lock to release.
1907
+ * Creates a new synchronous transaction.
1908
+ * @returns A new BPTreeSyncTransaction.
1745
1909
  */
1746
- writeUnlock(lockId) {
1747
- this._free(this.writings, lockId);
1910
+ createTransaction() {
1911
+ const tx = new BPTreeSyncTransaction(this);
1912
+ tx.initTransaction();
1913
+ return tx;
1914
+ }
1915
+ insert(key, value) {
1916
+ const tx = this.createTransaction();
1917
+ tx.insert(key, value);
1918
+ const { success } = tx.commit();
1919
+ this.init();
1920
+ if (!success) {
1921
+ throw new Error("Transaction failed: Commit failed due to conflict");
1922
+ }
1923
+ }
1924
+ delete(key, value) {
1925
+ const tx = this.createTransaction();
1926
+ tx.delete(key, value);
1927
+ const { success } = tx.commit();
1928
+ this.init();
1929
+ if (!success) {
1930
+ throw new Error("Transaction failed: Commit failed due to conflict");
1931
+ }
1748
1932
  }
1749
1933
  };
1750
- var BPTreeAsync = class extends BPTree {
1751
- lock;
1934
+ var BPTreeAsyncBase = class extends BPTree {
1752
1935
  constructor(strategy, comparator, option) {
1753
1936
  super(strategy, comparator, option);
1754
1937
  this.nodes = this._createCachedNode();
1755
- this.lock = new Ryoiki();
1756
1938
  }
1757
1939
  _createCachedNode() {
1758
1940
  return new CacheEntanglementAsync(async (key) => {
@@ -1761,24 +1943,6 @@ var BPTreeAsync = class extends BPTree {
1761
1943
  capacity: this.option.capacity ?? 1e3
1762
1944
  });
1763
1945
  }
1764
- async readLock(callback) {
1765
- let lockId;
1766
- return await this.lock.readLock(async (_lockId) => {
1767
- lockId = _lockId;
1768
- return await callback();
1769
- }).finally(() => {
1770
- this.lock.readUnlock(lockId);
1771
- });
1772
- }
1773
- async writeLock(callback) {
1774
- let lockId;
1775
- return await this.lock.writeLock(async (_lockId) => {
1776
- lockId = _lockId;
1777
- return await callback();
1778
- }).finally(() => {
1779
- this.lock.writeUnlock(lockId);
1780
- });
1781
- }
1782
1946
  async *getPairsGenerator(value, startNode, endNode, comparator, direction, earlyTerminate) {
1783
1947
  let node = startNode;
1784
1948
  let done = false;
@@ -1843,7 +2007,7 @@ var BPTreeAsync = class extends BPTree {
1843
2007
  }
1844
2008
  return id;
1845
2009
  }
1846
- async _createNode(isLeaf, keys, values, leaf = false, parent = null, next = null, prev = null) {
2010
+ async _createNode(isLeaf, keys, values, leaf = isLeaf, parent = null, next = null, prev = null) {
1847
2011
  const id = await this._createNodeId(isLeaf);
1848
2012
  const node = {
1849
2013
  id,
@@ -1854,38 +2018,37 @@ var BPTreeAsync = class extends BPTree {
1854
2018
  next,
1855
2019
  prev
1856
2020
  };
1857
- this._nodeCreateBuffer.set(id, node);
2021
+ await this.bufferForNodeCreate(node);
1858
2022
  return node;
1859
2023
  }
1860
2024
  async _deleteEntry(node, key, value) {
1861
2025
  if (!node.leaf) {
2026
+ let keyIndex = -1;
1862
2027
  for (let i = 0, len = node.keys.length; i < len; i++) {
1863
- const nKey = node.keys[i];
1864
- if (nKey === key) {
1865
- node.keys.splice(i, 1);
1866
- this.bufferForNodeUpdate(node);
2028
+ if (node.keys[i] === key) {
2029
+ keyIndex = i;
1867
2030
  break;
1868
2031
  }
1869
2032
  }
1870
- for (let i = 0, len = node.values.length; i < len; i++) {
1871
- const nValue = node.values[i];
1872
- if (this.comparator.isSame(value, nValue)) {
1873
- node.values.splice(i, 1);
1874
- this.bufferForNodeUpdate(node);
1875
- break;
1876
- }
2033
+ if (keyIndex !== -1) {
2034
+ node.keys.splice(keyIndex, 1);
2035
+ const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
2036
+ node.values.splice(valueIndex, 1);
2037
+ await this.bufferForNodeUpdate(node);
1877
2038
  }
1878
2039
  }
1879
- if (this.root.id === node.id && node.keys.length === 1) {
2040
+ if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
1880
2041
  const keys = node.keys;
1881
- this.bufferForNodeDelete(this.root);
1882
- this.root = await this.getNode(keys[0]);
1883
- this.root.parent = null;
1884
- this.strategy.head.root = this.root.id;
1885
- this.bufferForNodeUpdate(this.root);
2042
+ await this.bufferForNodeDelete(node);
2043
+ const newRoot = await this.getNode(keys[0]);
2044
+ this.rootId = newRoot.id;
2045
+ newRoot.parent = null;
2046
+ this.strategy.head.root = this.rootId;
2047
+ await this.bufferForNodeUpdate(newRoot);
1886
2048
  return;
1887
- } else if (this.root.id === node.id) {
1888
- this.bufferForNodeUpdate(this.root);
2049
+ } else if (this.rootId === node.id) {
2050
+ const root = await this.getNode(this.rootId);
2051
+ await this.bufferForNodeUpdate(root);
1889
2052
  return;
1890
2053
  } else if (node.keys.length < Math.ceil(this.order / 2) && !node.leaf || node.values.length < Math.ceil((this.order - 1) / 2) && node.leaf) {
1891
2054
  if (node.parent === null) {
@@ -1943,33 +2106,24 @@ var BPTreeAsync = class extends BPTree {
1943
2106
  pointer.values.push(guess);
1944
2107
  } else {
1945
2108
  pointer.next = node.next;
1946
- pointer.prev = node.id;
1947
2109
  if (pointer.next) {
1948
- const n = await this.getNode(node.next);
2110
+ const n = await this.getNode(pointer.next);
1949
2111
  n.prev = pointer.id;
1950
- this.bufferForNodeUpdate(n);
1951
- }
1952
- if (pointer.prev) {
1953
- const n = await this.getNode(node.id);
1954
- n.next = pointer.id;
1955
- this.bufferForNodeUpdate(n);
1956
- }
1957
- if (isPredecessor) {
1958
- pointer.prev = null;
2112
+ await this.bufferForNodeUpdate(n);
1959
2113
  }
1960
2114
  }
1961
2115
  pointer.values.push(...node.values);
1962
2116
  if (!pointer.leaf) {
1963
2117
  const keys = pointer.keys;
1964
2118
  for (const key2 of keys) {
1965
- const node2 = await this.getNode(key2);
1966
- node2.parent = pointer.id;
1967
- this.bufferForNodeUpdate(node2);
2119
+ const n = await this.getNode(key2);
2120
+ n.parent = pointer.id;
2121
+ await this.bufferForNodeUpdate(n);
1968
2122
  }
1969
2123
  }
1970
2124
  await this._deleteEntry(await this.getNode(node.parent), node.id, guess);
1971
- this.bufferForNodeUpdate(pointer);
1972
- this.bufferForNodeDelete(node);
2125
+ await this.bufferForNodeUpdate(pointer);
2126
+ await this.bufferForNodeDelete(node);
1973
2127
  } else {
1974
2128
  if (isPredecessor) {
1975
2129
  let pointerPm;
@@ -1980,13 +2134,10 @@ var BPTreeAsync = class extends BPTree {
1980
2134
  node.keys = [pointerPm, ...node.keys];
1981
2135
  node.values = [guess, ...node.values];
1982
2136
  parentNode = await this.getNode(node.parent);
1983
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
1984
- const nValue = parentNode.values[i];
1985
- if (this.comparator.isSame(guess, nValue)) {
1986
- parentNode.values[i] = pointerKm;
1987
- this.bufferForNodeUpdate(parentNode);
1988
- break;
1989
- }
2137
+ const nodeIndex = parentNode.keys.indexOf(node.id);
2138
+ if (nodeIndex > 0) {
2139
+ parentNode.values[nodeIndex - 1] = pointerKm;
2140
+ await this.bufferForNodeUpdate(parentNode);
1990
2141
  }
1991
2142
  } else {
1992
2143
  pointerPm = pointer.keys.splice(-1)[0];
@@ -1994,17 +2145,14 @@ var BPTreeAsync = class extends BPTree {
1994
2145
  node.keys = [pointerPm, ...node.keys];
1995
2146
  node.values = [pointerKm, ...node.values];
1996
2147
  parentNode = await this.getNode(node.parent);
1997
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
1998
- const nValue = parentNode.values[i];
1999
- if (this.comparator.isSame(guess, nValue)) {
2000
- parentNode.values[i] = pointerKm;
2001
- this.bufferForNodeUpdate(parentNode);
2002
- break;
2003
- }
2148
+ const nodeIndex = parentNode.keys.indexOf(node.id);
2149
+ if (nodeIndex > 0) {
2150
+ parentNode.values[nodeIndex - 1] = pointerKm;
2151
+ await this.bufferForNodeUpdate(parentNode);
2004
2152
  }
2005
2153
  }
2006
- this.bufferForNodeUpdate(node);
2007
- this.bufferForNodeUpdate(pointer);
2154
+ await this.bufferForNodeUpdate(node);
2155
+ await this.bufferForNodeUpdate(pointer);
2008
2156
  } else {
2009
2157
  let pointerP0;
2010
2158
  let pointerK0;
@@ -2014,13 +2162,10 @@ var BPTreeAsync = class extends BPTree {
2014
2162
  node.keys = [...node.keys, pointerP0];
2015
2163
  node.values = [...node.values, guess];
2016
2164
  parentNode = await this.getNode(node.parent);
2017
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
2018
- const nValue = parentNode.values[i];
2019
- if (this.comparator.isSame(guess, nValue)) {
2020
- parentNode.values[i] = pointerK0;
2021
- this.bufferForNodeUpdate(parentNode);
2022
- break;
2023
- }
2165
+ const pointerIndex = parentNode.keys.indexOf(pointer.id);
2166
+ if (pointerIndex > 0) {
2167
+ parentNode.values[pointerIndex - 1] = pointerK0;
2168
+ await this.bufferForNodeUpdate(parentNode);
2024
2169
  }
2025
2170
  } else {
2026
2171
  pointerP0 = pointer.keys.splice(0, 1)[0];
@@ -2028,87 +2173,85 @@ var BPTreeAsync = class extends BPTree {
2028
2173
  node.keys = [...node.keys, pointerP0];
2029
2174
  node.values = [...node.values, pointerK0];
2030
2175
  parentNode = await this.getNode(node.parent);
2031
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
2032
- const nValue = parentNode.values[i];
2033
- if (this.comparator.isSame(guess, nValue)) {
2034
- parentNode.values[i] = pointer.values[0];
2035
- this.bufferForNodeUpdate(parentNode);
2036
- break;
2037
- }
2176
+ const pointerIndex = parentNode.keys.indexOf(pointer.id);
2177
+ if (pointerIndex > 0) {
2178
+ parentNode.values[pointerIndex - 1] = pointer.values[0];
2179
+ await this.bufferForNodeUpdate(parentNode);
2038
2180
  }
2039
2181
  }
2040
- this.bufferForNodeUpdate(node);
2041
- this.bufferForNodeUpdate(pointer);
2182
+ await this.bufferForNodeUpdate(node);
2183
+ await this.bufferForNodeUpdate(pointer);
2042
2184
  }
2043
2185
  if (!pointer.leaf) {
2044
- for (const key2 of pointer.keys) {
2186
+ const keys = pointer.keys;
2187
+ for (const key2 of keys) {
2045
2188
  const n = await this.getNode(key2);
2046
2189
  n.parent = pointer.id;
2047
- this.bufferForNodeUpdate(n);
2190
+ await this.bufferForNodeUpdate(n);
2048
2191
  }
2049
2192
  }
2050
2193
  if (!node.leaf) {
2051
- for (const key2 of node.keys) {
2194
+ const keys = node.keys;
2195
+ for (const key2 of keys) {
2052
2196
  const n = await this.getNode(key2);
2053
2197
  n.parent = node.id;
2054
- this.bufferForNodeUpdate(n);
2198
+ await this.bufferForNodeUpdate(n);
2055
2199
  }
2056
2200
  }
2057
2201
  if (!parentNode.leaf) {
2058
- for (const key2 of parentNode.keys) {
2202
+ const keys = parentNode.keys;
2203
+ for (const key2 of keys) {
2059
2204
  const n = await this.getNode(key2);
2060
2205
  n.parent = parentNode.id;
2061
- this.bufferForNodeUpdate(n);
2206
+ await this.bufferForNodeUpdate(n);
2062
2207
  }
2063
2208
  }
2064
2209
  }
2210
+ } else {
2211
+ await this.bufferForNodeUpdate(node);
2065
2212
  }
2066
2213
  }
2067
2214
  async _insertInParent(node, value, pointer) {
2068
- if (this.root.id === node.id) {
2215
+ if (this.rootId === node.id) {
2069
2216
  const root = await this._createNode(false, [node.id, pointer.id], [value]);
2070
- this.root = root;
2217
+ this.rootId = root.id;
2071
2218
  this.strategy.head.root = root.id;
2072
2219
  node.parent = root.id;
2073
2220
  pointer.parent = root.id;
2074
2221
  if (pointer.leaf) {
2075
- node.next = pointer.id;
2076
- pointer.prev = node.id;
2222
+ const nNode = node;
2223
+ nNode.next = pointer.id;
2224
+ const nPointer = pointer;
2225
+ nPointer.prev = node.id;
2077
2226
  }
2078
- this.bufferForNodeUpdate(node);
2079
- this.bufferForNodeUpdate(pointer);
2227
+ await this.bufferForNodeUpdate(node);
2228
+ await this.bufferForNodeUpdate(pointer);
2080
2229
  return;
2081
2230
  }
2082
2231
  const parentNode = await this.getNode(node.parent);
2083
- let insertIndex = 0;
2084
- for (let i = 0; i < parentNode.values.length; i++) {
2085
- if (this.comparator.asc(value, parentNode.values[i]) > 0) {
2086
- insertIndex = i + 1;
2087
- } else {
2088
- break;
2089
- }
2232
+ const nodeIndex = parentNode.keys.indexOf(node.id);
2233
+ if (nodeIndex === -1) {
2234
+ throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
2090
2235
  }
2236
+ const insertIndex = nodeIndex;
2091
2237
  parentNode.values.splice(insertIndex, 0, value);
2092
2238
  parentNode.keys.splice(insertIndex + 1, 0, pointer.id);
2093
2239
  pointer.parent = parentNode.id;
2094
2240
  if (pointer.leaf) {
2095
- const leftSiblingId = parentNode.keys[insertIndex];
2096
- const rightSiblingId = parentNode.keys[insertIndex + 2];
2097
- if (leftSiblingId) {
2098
- const leftSibling = await this.getNode(leftSiblingId);
2099
- pointer.prev = leftSibling.id;
2100
- pointer.next = leftSibling.next;
2101
- leftSibling.next = pointer.id;
2102
- this.bufferForNodeUpdate(leftSibling);
2103
- }
2104
- if (rightSiblingId) {
2105
- const rightSibling = await this.getNode(rightSiblingId);
2106
- rightSibling.prev = pointer.id;
2107
- this.bufferForNodeUpdate(rightSibling);
2241
+ const leftSibling = node;
2242
+ const oldNextId = leftSibling.next;
2243
+ pointer.prev = leftSibling.id;
2244
+ pointer.next = oldNextId;
2245
+ leftSibling.next = pointer.id;
2246
+ await this.bufferForNodeUpdate(leftSibling);
2247
+ if (oldNextId) {
2248
+ const oldNext = await this.getNode(oldNextId);
2249
+ oldNext.prev = pointer.id;
2250
+ await this.bufferForNodeUpdate(oldNext);
2108
2251
  }
2109
2252
  }
2110
- this.bufferForNodeUpdate(parentNode);
2111
- this.bufferForNodeUpdate(pointer);
2253
+ await this.bufferForNodeUpdate(parentNode);
2254
+ await this.bufferForNodeUpdate(pointer);
2112
2255
  if (parentNode.keys.length > this.order) {
2113
2256
  const parentPointer = await this._createNode(false, [], []);
2114
2257
  parentPointer.parent = parentNode.parent;
@@ -2119,32 +2262,34 @@ var BPTreeAsync = class extends BPTree {
2119
2262
  parentNode.values = parentNode.values.slice(0, mid);
2120
2263
  parentNode.keys = parentNode.keys.slice(0, mid + 1);
2121
2264
  for (const k of parentNode.keys) {
2122
- const node2 = await this.getNode(k);
2123
- node2.parent = parentNode.id;
2124
- this.bufferForNodeUpdate(node2);
2265
+ const n = await this.getNode(k);
2266
+ n.parent = parentNode.id;
2267
+ await this.bufferForNodeUpdate(n);
2125
2268
  }
2126
2269
  for (const k of parentPointer.keys) {
2127
- const node2 = await this.getNode(k);
2128
- node2.parent = parentPointer.id;
2129
- this.bufferForNodeUpdate(node2);
2270
+ const n = await this.getNode(k);
2271
+ n.parent = parentPointer.id;
2272
+ await this.bufferForNodeUpdate(n);
2130
2273
  }
2131
2274
  await this._insertInParent(parentNode, midValue, parentPointer);
2132
- this.bufferForNodeUpdate(parentNode);
2275
+ await this.bufferForNodeUpdate(parentNode);
2133
2276
  }
2134
2277
  }
2135
2278
  async init() {
2279
+ this.clear();
2136
2280
  const head = await this.strategy.readHead();
2137
2281
  if (head === null) {
2138
2282
  this.order = this.strategy.order;
2139
- this.root = await this._createNode(true, [], [], true);
2140
- this.strategy.head.root = this.root.id;
2283
+ const root = await this._createNode(true, [], [], true);
2284
+ this.rootId = root.id;
2285
+ this.strategy.head.root = this.rootId;
2141
2286
  await this.commitHeadBuffer();
2142
2287
  await this.commitNodeCreateBuffer();
2143
2288
  } else {
2144
2289
  const { root, order } = head;
2145
2290
  this.strategy.head = head;
2146
2291
  this.order = order;
2147
- this.root = await this.getNode(root);
2292
+ this.rootId = root;
2148
2293
  }
2149
2294
  if (this.order < 3) {
2150
2295
  throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
@@ -2161,43 +2306,73 @@ var BPTreeAsync = class extends BPTree {
2161
2306
  return cache.raw;
2162
2307
  }
2163
2308
  async insertableNode(value) {
2164
- let node = await this.getNode(this.root.id);
2309
+ let node = await this.getNode(this.rootId);
2310
+ if (node.parent !== null) {
2311
+ node.parent = null;
2312
+ await this.bufferForNodeUpdate(node);
2313
+ }
2165
2314
  while (!node.leaf) {
2315
+ const parentId = node.id;
2166
2316
  for (let i = 0, len = node.values.length; i < len; i++) {
2167
2317
  const nValue = node.values[i];
2168
2318
  const k = node.keys;
2169
2319
  if (this.comparator.isSame(value, nValue)) {
2170
- node = await this.getNode(k[i + 1]);
2320
+ node = await this.getNode(node.keys[i + 1]);
2321
+ if (node.parent !== parentId) {
2322
+ node.parent = parentId;
2323
+ await this.bufferForNodeUpdate(node);
2324
+ }
2171
2325
  break;
2172
2326
  } else if (this.comparator.isLower(value, nValue)) {
2173
- node = await this.getNode(k[i]);
2327
+ node = await this.getNode(node.keys[i]);
2328
+ if (node.parent !== parentId) {
2329
+ node.parent = parentId;
2330
+ await this.bufferForNodeUpdate(node);
2331
+ }
2174
2332
  break;
2175
2333
  } else if (i + 1 === node.values.length) {
2176
- node = await this.getNode(k[i + 1]);
2334
+ node = await this.getNode(node.keys[i + 1]);
2335
+ if (node.parent !== parentId) {
2336
+ node.parent = parentId;
2337
+ await this.bufferForNodeUpdate(node);
2338
+ }
2177
2339
  break;
2178
2340
  }
2179
2341
  }
2180
2342
  }
2181
2343
  return node;
2182
2344
  }
2183
- /**
2184
- * Find the insertable node using primaryAsc comparison.
2185
- * This allows finding nodes by primary value only, ignoring unique identifiers.
2186
- */
2187
2345
  async insertableNodeByPrimary(value) {
2188
- let node = await this.getNode(this.root.id);
2346
+ let node = await this.getNode(this.rootId);
2347
+ if (node.parent !== null) {
2348
+ node.parent = null;
2349
+ await this.bufferForNodeUpdate(node);
2350
+ }
2189
2351
  while (!node.leaf) {
2352
+ const parentId = node.id;
2190
2353
  for (let i = 0, len = node.values.length; i < len; i++) {
2191
2354
  const nValue = node.values[i];
2192
2355
  const k = node.keys;
2193
2356
  if (this.comparator.isPrimarySame(value, nValue)) {
2194
- node = await this.getNode(k[i]);
2357
+ node = await this.getNode(node.keys[i]);
2358
+ if (node.parent !== parentId) {
2359
+ node.parent = parentId;
2360
+ await this.bufferForNodeUpdate(node);
2361
+ }
2195
2362
  break;
2196
2363
  } else if (this.comparator.isPrimaryLower(value, nValue)) {
2197
- node = await this.getNode(k[i]);
2364
+ node = await this.getNode(node.keys[i]);
2365
+ if (node.parent !== parentId) {
2366
+ node.parent = parentId;
2367
+ await this.bufferForNodeUpdate(node);
2368
+ }
2198
2369
  break;
2199
2370
  } else if (i + 1 === node.values.length) {
2200
- node = await this.getNode(k[i + 1]);
2371
+ node = await this.getNode(node.keys[i + 1]);
2372
+ if (node.parent !== parentId) {
2373
+ node.parent = parentId;
2374
+ await this.bufferForNodeUpdate(node);
2375
+ }
2201
2376
  break;
2202
2377
  }
2203
2378
  }
@@ -2205,17 +2380,30 @@ var BPTreeAsync = class extends BPTree {
2205
2380
  return node;
2206
2381
  }
2207
2382
  async insertableRightestNodeByPrimary(value) {
2208
- let node = await this.getNode(this.root.id);
2383
+ let node = await this.getNode(this.rootId);
2384
+ if (node.parent !== null) {
2385
+ node.parent = null;
2386
+ await this.bufferForNodeUpdate(node);
2387
+ }
2209
2388
  while (!node.leaf) {
2389
+ const parentId = node.id;
2210
2390
  for (let i = 0, len = node.values.length; i < len; i++) {
2211
2391
  const nValue = node.values[i];
2212
2392
  const k = node.keys;
2213
2393
  if (this.comparator.isPrimaryLower(value, nValue)) {
2214
- node = await this.getNode(k[i]);
2394
+ node = await this.getNode(node.keys[i]);
2395
+ if (node.parent !== parentId) {
2396
+ node.parent = parentId;
2397
+ await this.bufferForNodeUpdate(node);
2398
+ }
2215
2399
  break;
2216
2400
  }
2217
2401
  if (i + 1 === node.values.length) {
2218
- node = await this.getNode(k[i + 1]);
2402
+ node = await this.getNode(node.keys[i + 1]);
2403
+ if (node.parent !== parentId) {
2404
+ node.parent = parentId;
2405
+ await this.bufferForNodeUpdate(node);
2406
+ }
2219
2407
  break;
2220
2408
  }
2221
2409
  }
@@ -2249,27 +2437,75 @@ var BPTreeAsync = class extends BPTree {
2249
2437
  return await this.getNode(guessNode);
2250
2438
  }
2251
2439
  async leftestNode() {
2252
- let node = this.root;
2440
+ let node = await this.getNode(this.rootId);
2441
+ if (node.parent !== null) {
2442
+ node.parent = null;
2443
+ await this.bufferForNodeUpdate(node);
2444
+ }
2253
2445
  while (!node.leaf) {
2446
+ const parentId = node.id;
2254
2447
  const keys = node.keys;
2255
- node = await this.getNode(keys[0]);
2448
+ node = await this.getNode(node.keys[0]);
2449
+ if (node.parent !== parentId) {
2450
+ node.parent = parentId;
2451
+ await this.bufferForNodeUpdate(node);
2452
+ }
2256
2453
  }
2257
2454
  return node;
2258
2455
  }
2259
2456
  async rightestNode() {
2260
- let node = this.root;
2457
+ let node = await this.getNode(this.rootId);
2458
+ if (node.parent !== null) {
2459
+ node.parent = null;
2460
+ await this.bufferForNodeUpdate(node);
2461
+ }
2261
2462
  while (!node.leaf) {
2463
+ const parentId = node.id;
2262
2464
  const keys = node.keys;
2263
- node = await this.getNode(keys[keys.length - 1]);
2465
+ node = await this.getNode(node.keys[node.keys.length - 1]);
2466
+ if (node.parent !== parentId) {
2467
+ node.parent = parentId;
2468
+ await this.bufferForNodeUpdate(node);
2469
+ }
2264
2470
  }
2265
2471
  return node;
2266
2472
  }
2473
+ async exists(key, value) {
2474
+ const node = await this.insertableNode(value);
2475
+ for (let i = 0, len = node.values.length; i < len; i++) {
2476
+ if (this.comparator.isSame(value, node.values[i])) {
2477
+ const keys = node.keys[i];
2478
+ if (keys.includes(key)) {
2479
+ return true;
2480
+ }
2481
+ }
2482
+ }
2483
+ return false;
2484
+ }
2485
+ async forceUpdate(id) {
2486
+ if (id) {
2487
+ this.nodes.delete(id);
2488
+ await this.getNode(id);
2489
+ return 1;
2490
+ }
2491
+ const keys = Array.from(this.nodes.keys());
2492
+ for (const key of keys) {
2493
+ this.nodes.delete(key);
2494
+ }
2495
+ for (const key of keys) {
2496
+ await this.getNode(key);
2497
+ }
2498
+ return keys.length;
2499
+ }
2267
2500
  async commitHeadBuffer() {
2268
2501
  if (!this._strategyDirty) {
2269
2502
  return;
2270
2503
  }
2271
2504
  this._strategyDirty = false;
2272
2505
  await this.strategy.writeHead(this.strategy.head);
2506
+ if (this.strategy.head.root) {
2507
+ this.nodes.delete(this.strategy.head.root);
2508
+ }
2273
2509
  }
2274
2510
  async commitNodeCreateBuffer() {
2275
2511
  for (const node of this._nodeCreateBuffer.values()) {
@@ -2280,34 +2516,26 @@ var BPTreeAsync = class extends BPTree {
2280
2516
  async commitNodeUpdateBuffer() {
2281
2517
  for (const node of this._nodeUpdateBuffer.values()) {
2282
2518
  await this.strategy.write(node.id, node);
2519
+ this.nodes.delete(node.id);
2283
2520
  }
2284
2521
  this._nodeUpdateBuffer.clear();
2285
2522
  }
2286
2523
  async commitNodeDeleteBuffer() {
2287
2524
  for (const node of this._nodeDeleteBuffer.values()) {
2288
2525
  await this.strategy.delete(node.id);
2526
+ this.nodes.delete(node.id);
2289
2527
  }
2290
2528
  this._nodeDeleteBuffer.clear();
2291
2529
  }
2292
- /**
2293
- * Retrieves the value associated with the given key (PK).
2294
- * Note: This method performs a full scan of leaf nodes as the tree is ordered by Value, not Key.
2295
- *
2296
- * @param key The key to search for.
2297
- * @returns The value associated with the key, or undefined if not found.
2298
- */
2299
2530
  async get(key) {
2300
- return this.readLock(async () => {
2531
+ return await this.readLock(async () => {
2301
2532
  let node = await this.leftestNode();
2302
2533
  while (true) {
2303
- if (node.values) {
2304
- const len = node.values.length;
2305
- for (let i = 0; i < len; i++) {
2306
- const keys = node.keys[i];
2307
- for (let j = 0; j < keys.length; j++) {
2308
- if (keys[j] === key) {
2309
- return node.values[i];
2310
- }
2534
+ for (let i = 0, len = node.values.length; i < len; i++) {
2535
+ const keys = node.keys[i];
2536
+ for (let j = 0, kLen = keys.length; j < kLen; j++) {
2537
+ if (keys[j] === key) {
2538
+ return node.values[i];
2311
2539
  }
2312
2540
  }
2313
2541
  }
@@ -2379,176 +2607,82 @@ var BPTreeAsync = class extends BPTree {
2379
2607
  break;
2380
2608
  }
2381
2609
  }
2382
- }
2383
- }
2384
- async keys(condition, filterValues) {
2385
- return this.readLock(async () => {
2386
- const set = /* @__PURE__ */ new Set();
2387
- for await (const key of this.keysStream(condition, filterValues)) {
2388
- set.add(key);
2389
- }
2390
- return set;
2391
- });
2392
- }
2393
- async where(condition) {
2394
- return this.readLock(async () => {
2395
- const map = /* @__PURE__ */ new Map();
2396
- for await (const [key, value] of this.whereStream(condition)) {
2397
- map.set(key, value);
2398
- }
2399
- return map;
2400
- });
2401
- }
2402
- async insert(key, value) {
2403
- return this.writeLock(async () => {
2404
- const before = await this.insertableNode(value);
2405
- this._insertAtLeaf(before, key, value);
2406
- if (before.values.length === this.order) {
2407
- const after = await this._createNode(
2408
- true,
2409
- [],
2410
- [],
2411
- true,
2412
- before.parent,
2413
- null,
2414
- null
2415
- );
2416
- const mid = Math.ceil(this.order / 2) - 1;
2417
- after.values = before.values.slice(mid + 1);
2418
- after.keys = before.keys.slice(mid + 1);
2419
- before.values = before.values.slice(0, mid + 1);
2420
- before.keys = before.keys.slice(0, mid + 1);
2421
- await this._insertInParent(before, after.values[0], after);
2422
- this.bufferForNodeUpdate(before);
2423
- }
2424
- await this.commitHeadBuffer();
2425
- await this.commitNodeCreateBuffer();
2426
- await this.commitNodeUpdateBuffer();
2427
- });
2428
- }
2429
- async delete(key, value) {
2430
- return this.writeLock(async () => {
2431
- const node = await this.insertableNode(value);
2432
- let i = node.values.length;
2433
- while (i--) {
2434
- const nValue = node.values[i];
2435
- if (this.comparator.isSame(value, nValue)) {
2436
- const keys = node.keys[i];
2437
- if (keys.includes(key)) {
2438
- if (keys.length > 1) {
2439
- keys.splice(keys.indexOf(key), 1);
2440
- this.bufferForNodeUpdate(node);
2441
- } else if (node.id === this.root.id) {
2442
- node.values.splice(i, 1);
2443
- node.keys.splice(i, 1);
2444
- this.bufferForNodeUpdate(node);
2445
- } else {
2446
- keys.splice(keys.indexOf(key), 1);
2447
- node.keys.splice(i, 1);
2448
- node.values.splice(node.values.indexOf(value), 1);
2449
- await this._deleteEntry(node, key, value);
2450
- this.bufferForNodeUpdate(node);
2451
- }
2452
- }
2453
- }
2454
- }
2455
- await this.commitHeadBuffer();
2456
- await this.commitNodeCreateBuffer();
2457
- await this.commitNodeUpdateBuffer();
2458
- await this.commitNodeDeleteBuffer();
2459
- });
2460
- }
2461
- async exists(key, value) {
2462
- return this.readLock(async () => {
2463
- const node = await this.insertableNode(value);
2464
- for (let i = 0, len = node.values.length; i < len; i++) {
2465
- const nValue = node.values[i];
2466
- if (this.comparator.isSame(value, nValue)) {
2467
- const keys = node.keys[i];
2468
- return keys.includes(key);
2469
- }
2470
- }
2471
- return false;
2472
- });
2473
- }
2474
- async setHeadData(data) {
2475
- return this.writeLock(async () => {
2476
- this.strategy.head.data = data;
2477
- this._strategyDirty = true;
2478
- await this.commitHeadBuffer();
2479
- });
2480
- }
2481
- async forceUpdate() {
2482
- return this.readLock(async () => {
2483
- const keys = [...this.nodes.keys()];
2484
- this.nodes.clear();
2485
- await this.init();
2486
- for (const key of keys) {
2487
- await this.getNode(key);
2488
- }
2489
- return keys.length;
2490
- });
2491
- }
2492
- };
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
- };
2503
- }
2504
- };
2505
- var SerializeStrategySync = class extends SerializeStrategy {
2506
- getHeadData(key, defaultValue) {
2507
- if (!Object.hasOwn(this.head.data, key)) {
2508
- this.setHeadData(key, defaultValue);
2509
- }
2510
- return this.head.data[key];
2511
- }
2512
- setHeadData(key, data) {
2513
- this.head.data[key] = data;
2514
- this.writeHead(this.head);
2515
- }
2516
- autoIncrement(key, defaultValue) {
2517
- const current = this.getHeadData(key, defaultValue);
2518
- const next = current + 1;
2519
- this.setHeadData(key, next);
2520
- return current;
2521
- }
2522
- };
2523
- var InMemoryStoreStrategySync = class extends SerializeStrategySync {
2524
- node;
2525
- constructor(order) {
2526
- super(order);
2527
- this.node = {};
2610
+ }
2528
2611
  }
2529
- id(isLeaf) {
2530
- return this.autoIncrement("index", 1).toString();
2612
+ async keys(condition, filterValues) {
2613
+ const set = /* @__PURE__ */ new Set();
2614
+ for await (const key of this.keysStream(condition, filterValues)) {
2615
+ set.add(key);
2616
+ }
2617
+ return set;
2531
2618
  }
2532
- read(id) {
2533
- if (!Object.hasOwn(this.node, id)) {
2534
- throw new Error(`The tree attempted to reference node '${id}', but couldn't find the corresponding node.`);
2619
+ async where(condition) {
2620
+ const map = /* @__PURE__ */ new Map();
2621
+ for await (const [key, value] of this.whereStream(condition)) {
2622
+ map.set(key, value);
2535
2623
  }
2536
- return this.node[id];
2624
+ return map;
2537
2625
  }
2538
- write(id, node) {
2539
- this.node[id] = node;
2626
+ async insert(key, value) {
2627
+ await this.writeLock(async () => {
2628
+ const before = await this.insertableNode(value);
2629
+ await this._insertAtLeaf(before, key, value);
2630
+ if (before.values.length === this.order) {
2631
+ const after = await this._createNode(
2632
+ true,
2633
+ [],
2634
+ [],
2635
+ true,
2636
+ before.parent,
2637
+ null,
2638
+ null
2639
+ );
2640
+ const mid = Math.ceil(this.order / 2) - 1;
2641
+ after.values = before.values.slice(mid + 1);
2642
+ after.keys = before.keys.slice(mid + 1);
2643
+ before.values = before.values.slice(0, mid + 1);
2644
+ before.keys = before.keys.slice(0, mid + 1);
2645
+ await this._insertInParent(before, after.values[0], after);
2646
+ await this.bufferForNodeUpdate(before);
2647
+ }
2648
+ await this.commitHeadBuffer();
2649
+ await this.commitNodeCreateBuffer();
2650
+ await this.commitNodeUpdateBuffer();
2651
+ });
2540
2652
  }
2541
- delete(id) {
2542
- delete this.node[id];
2653
+ async delete(key, value) {
2654
+ await this.writeLock(async () => {
2655
+ const node = await this.insertableNode(value);
2656
+ let i = node.values.length;
2657
+ while (i--) {
2658
+ const nValue = node.values[i];
2659
+ if (this.comparator.isSame(value, nValue)) {
2660
+ const keys = node.keys[i];
2661
+ const keyIndex = keys.indexOf(key);
2662
+ if (keyIndex !== -1) {
2663
+ keys.splice(keyIndex, 1);
2664
+ if (keys.length === 0) {
2665
+ node.keys.splice(i, 1);
2666
+ node.values.splice(i, 1);
2667
+ }
2668
+ await this._deleteEntry(node, key, value);
2669
+ await this.bufferForNodeUpdate(node);
2670
+ break;
2671
+ }
2672
+ }
2673
+ }
2674
+ await this.commitHeadBuffer();
2675
+ await this.commitNodeCreateBuffer();
2676
+ await this.commitNodeUpdateBuffer();
2677
+ await this.commitNodeDeleteBuffer();
2678
+ });
2543
2679
  }
2544
- readHead() {
2545
- if (this.head.root === null) {
2546
- return null;
2547
- }
2548
- return this.head;
2680
+ getHeadData() {
2681
+ return this.strategy.head.data;
2549
2682
  }
2550
- writeHead(head) {
2551
- this.head = head;
2683
+ async setHeadData(data) {
2684
+ this.strategy.head.data = data;
2685
+ await this.strategy.writeHead(this.strategy.head);
2552
2686
  }
2553
2687
  };
2554
2688
  var SerializeStrategyAsync = class extends SerializeStrategy {
@@ -2568,6 +2702,14 @@ var SerializeStrategyAsync = class extends SerializeStrategy {
2568
2702
  await this.setHeadData(key, next);
2569
2703
  return current;
2570
2704
  }
2705
+ async compareAndSwapHead(oldRoot, newRoot) {
2706
+ if (this.head.root !== oldRoot) {
2707
+ return false;
2708
+ }
2709
+ this.head.root = newRoot;
2710
+ await this.writeHead(this.head);
2711
+ return true;
2712
+ }
2571
2713
  };
2572
2714
  var InMemoryStoreStrategyAsync = class extends SerializeStrategyAsync {
2573
2715
  node;
@@ -2582,7 +2724,8 @@ var InMemoryStoreStrategyAsync = class extends SerializeStrategyAsync {
2582
2724
  if (!Object.hasOwn(this.node, id)) {
2583
2725
  throw new Error(`The tree attempted to reference node '${id}', but couldn't find the corresponding node.`);
2584
2726
  }
2585
- return this.node[id];
2727
+ const node = this.node[id];
2728
+ return JSON.parse(JSON.stringify(node));
2586
2729
  }
2587
2730
  async write(id, node) {
2588
2731
  this.node[id] = node;
@@ -2600,9 +2743,341 @@ var InMemoryStoreStrategyAsync = class extends SerializeStrategyAsync {
2600
2743
  this.head = head;
2601
2744
  }
2602
2745
  };
2746
+ var BPTreeAsyncSnapshotStrategy = class extends SerializeStrategyAsync {
2747
+ baseStrategy;
2748
+ snapshotHead;
2749
+ constructor(baseStrategy, root) {
2750
+ super(baseStrategy.order);
2751
+ this.baseStrategy = baseStrategy;
2752
+ this.snapshotHead = {
2753
+ ...baseStrategy.head,
2754
+ root,
2755
+ data: { ...baseStrategy.head.data }
2756
+ };
2757
+ this.head = this.snapshotHead;
2758
+ }
2759
+ async id(isLeaf) {
2760
+ return await this.baseStrategy.id(isLeaf);
2761
+ }
2762
+ async read(id) {
2763
+ return await this.baseStrategy.read(id);
2764
+ }
2765
+ async write(id, node) {
2766
+ await this.baseStrategy.write(id, node);
2767
+ }
2768
+ async delete(id) {
2769
+ await this.baseStrategy.delete(id);
2770
+ }
2771
+ async readHead() {
2772
+ return this.snapshotHead;
2773
+ }
2774
+ async writeHead(head) {
2775
+ this.snapshotHead.root = head.root;
2776
+ this.snapshotHead.data = { ...head.data };
2777
+ }
2778
+ async compareAndSwapHead(oldRoot, newRoot) {
2779
+ return await this.baseStrategy.compareAndSwapHead(oldRoot, newRoot);
2780
+ }
2781
+ async getHeadData(key, defaultValue) {
2782
+ return this.snapshotHead.data[key] ?? defaultValue;
2783
+ }
2784
+ async setHeadData(key, data) {
2785
+ this.snapshotHead.data[key] = data;
2786
+ }
2787
+ async autoIncrement(key, defaultValue) {
2788
+ return this.snapshotHead.data[key] ?? defaultValue;
2789
+ }
2790
+ };
2791
+ var BPTreeAsyncTransaction = class extends BPTreeAsyncBase {
2792
+ realBaseTree;
2793
+ realBaseStrategy;
2794
+ txNodes = /* @__PURE__ */ new Map();
2795
+ dirtyIds;
2796
+ createdInTx;
2797
+ deletedIds;
2798
+ initialRootId;
2799
+ transactionRootId;
2800
+ constructor(baseTree) {
2801
+ super(baseTree.strategy, baseTree.comparator, baseTree.option);
2802
+ this.realBaseTree = baseTree;
2803
+ this.realBaseStrategy = baseTree.strategy;
2804
+ this.order = baseTree.getOrder();
2805
+ this.initialRootId = "";
2806
+ this.transactionRootId = "";
2807
+ this.dirtyIds = /* @__PURE__ */ new Set();
2808
+ this.createdInTx = /* @__PURE__ */ new Set();
2809
+ this.deletedIds = /* @__PURE__ */ new Set();
2810
+ }
2811
+ /**
2812
+ * Initializes the transaction by capturing the current state of the tree.
2813
+ */
2814
+ async initTransaction() {
2815
+ const head = await this.realBaseStrategy.readHead();
2816
+ if (head) {
2817
+ this.order = head.order;
2818
+ this.initialRootId = head.root;
2819
+ } else {
2820
+ this.initialRootId = this.realBaseTree.getRootId();
2821
+ }
2822
+ if (!this.initialRootId) {
2823
+ const root = await this._createNode(true, [], [], true);
2824
+ this.initialRootId = root.id;
2825
+ }
2826
+ this.transactionRootId = this.initialRootId;
2827
+ this.rootId = this.transactionRootId;
2828
+ const snapshotStrategy = new BPTreeAsyncSnapshotStrategy(this.realBaseStrategy, this.initialRootId);
2829
+ this.strategy = snapshotStrategy;
2830
+ this.txNodes.clear();
2831
+ this.dirtyIds.clear();
2832
+ this.createdInTx.clear();
2833
+ this.deletedIds.clear();
2834
+ }
2835
+ async getNode(id) {
2836
+ if (this.txNodes.has(id)) {
2837
+ return this.txNodes.get(id);
2838
+ }
2839
+ if (this.deletedIds.has(id)) {
2840
+ throw new Error(`The tree attempted to reference deleted node '${id}'`);
2841
+ }
2842
+ const baseNode = await this.realBaseStrategy.read(id);
2843
+ const clone = JSON.parse(JSON.stringify(baseNode));
2844
+ this.txNodes.set(id, clone);
2845
+ return clone;
2846
+ }
2847
+ async bufferForNodeUpdate(node) {
2848
+ if (this.dirtyIds.has(node.id) && this.txNodes.has(node.id) && node._p) {
2849
+ this.txNodes.set(node.id, node);
2850
+ return;
2851
+ }
2852
+ node._p = true;
2853
+ this.txNodes.set(node.id, node);
2854
+ this.dirtyIds.add(node.id);
2855
+ if (node.leaf) {
2856
+ if (node.next && !this.dirtyIds.has(node.next) && !this.deletedIds.has(node.next)) {
2857
+ try {
2858
+ await this.bufferForNodeUpdate(await this.getNode(node.next));
2859
+ } catch (e) {
2860
+ }
2861
+ }
2862
+ if (node.prev && !this.dirtyIds.has(node.prev) && !this.deletedIds.has(node.prev)) {
2863
+ try {
2864
+ await this.bufferForNodeUpdate(await this.getNode(node.prev));
2865
+ } catch (e) {
2866
+ }
2867
+ }
2868
+ }
2869
+ await this.markPathDirty(node);
2870
+ delete node._p;
2871
+ }
2872
+ async bufferForNodeCreate(node) {
2873
+ this.txNodes.set(node.id, node);
2874
+ this.dirtyIds.add(node.id);
2875
+ this.createdInTx.add(node.id);
2876
+ if (node.leaf) {
2877
+ if (node.next && !this.dirtyIds.has(node.next) && !this.deletedIds.has(node.next)) {
2878
+ try {
2879
+ await this.bufferForNodeUpdate(await this.getNode(node.next));
2880
+ } catch (e) {
2881
+ }
2882
+ }
2883
+ if (node.prev && !this.dirtyIds.has(node.prev) && !this.deletedIds.has(node.prev)) {
2884
+ try {
2885
+ await this.bufferForNodeUpdate(await this.getNode(node.prev));
2886
+ } catch (e) {
2887
+ }
2888
+ }
2889
+ }
2890
+ await this.markPathDirty(node);
2891
+ }
2892
+ async bufferForNodeDelete(node) {
2893
+ this.txNodes.delete(node.id);
2894
+ this.dirtyIds.add(node.id);
2895
+ this.deletedIds.add(node.id);
2896
+ }
2897
+ async markPathDirty(node) {
2898
+ let curr = node;
2899
+ while (curr.parent) {
2900
+ if (this.deletedIds.has(curr.parent)) {
2901
+ break;
2902
+ }
2903
+ if (this.dirtyIds.has(curr.parent) && this.txNodes.has(curr.parent)) {
2904
+ break;
2905
+ }
2906
+ const parent = await this.getNode(curr.parent);
2907
+ this.dirtyIds.add(parent.id);
2908
+ curr = parent;
2909
+ }
2910
+ if (!curr.parent) {
2911
+ this.transactionRootId = curr.id;
2912
+ }
2913
+ }
2914
+ async _createNode(isLeaf, keys, values, leaf = isLeaf, parent = null, next = null, prev = null) {
2915
+ const id = await this.strategy.id(isLeaf);
2916
+ const node = {
2917
+ id,
2918
+ keys,
2919
+ values,
2920
+ leaf,
2921
+ parent,
2922
+ next,
2923
+ prev
2924
+ };
2925
+ await this.bufferForNodeCreate(node);
2926
+ return node;
2927
+ }
2928
+ /**
2929
+ * Attempts to commit the transaction.
2930
+ * Uses Optimistic Locking (Compare-And-Swap) on the root node ID to detect conflicts.
2931
+ *
2932
+ * @returns A promise that resolves to the transaction result.
2933
+ */
2934
+ async commit() {
2935
+ const idMapping = /* @__PURE__ */ new Map();
2936
+ const finalNodes = [];
2937
+ for (const oldId of this.dirtyIds) {
2938
+ if (this.createdInTx.has(oldId)) {
2939
+ idMapping.set(oldId, oldId);
2940
+ } else {
2941
+ const node = this.txNodes.get(oldId);
2942
+ if (node) {
2943
+ const newId = await this.realBaseStrategy.id(node.leaf);
2944
+ idMapping.set(oldId, newId);
2945
+ }
2946
+ }
2947
+ }
2948
+ const newCreatedIds = [];
2949
+ for (const oldId of this.dirtyIds) {
2950
+ const node = this.txNodes.get(oldId);
2951
+ if (!node) continue;
2952
+ const newId = idMapping.get(oldId);
2953
+ node.id = newId;
2954
+ if (node.parent && idMapping.has(node.parent)) {
2955
+ node.parent = idMapping.get(node.parent);
2956
+ }
2957
+ if (!node.leaf) {
2958
+ const internal = node;
2959
+ for (let i = 0; i < internal.keys.length; i++) {
2960
+ const childId = internal.keys[i];
2961
+ if (idMapping.has(childId)) {
2962
+ internal.keys[i] = idMapping.get(childId);
2963
+ }
2964
+ }
2965
+ }
2966
+ if (node.leaf) {
2967
+ const leaf = node;
2968
+ if (leaf.next && idMapping.has(leaf.next)) {
2969
+ leaf.next = idMapping.get(leaf.next);
2970
+ }
2971
+ if (leaf.prev && idMapping.has(leaf.prev)) {
2972
+ leaf.prev = idMapping.get(leaf.prev);
2973
+ }
2974
+ }
2975
+ finalNodes.push(node);
2976
+ newCreatedIds.push(newId);
2977
+ }
2978
+ let newRootId = this.rootId;
2979
+ if (idMapping.has(this.rootId)) {
2980
+ newRootId = idMapping.get(this.rootId);
2981
+ }
2982
+ for (const node of finalNodes) {
2983
+ await this.realBaseStrategy.write(node.id, node);
2984
+ }
2985
+ const success = await this.realBaseStrategy.compareAndSwapHead(this.initialRootId, newRootId);
2986
+ if (success) {
2987
+ const distinctObsolete = /* @__PURE__ */ new Set();
2988
+ for (const oldId of this.dirtyIds) {
2989
+ if (!this.createdInTx.has(oldId) && this.txNodes.has(oldId)) {
2990
+ distinctObsolete.add(oldId);
2991
+ }
2992
+ }
2993
+ return {
2994
+ success: true,
2995
+ createdIds: newCreatedIds,
2996
+ obsoleteIds: Array.from(distinctObsolete)
2997
+ };
2998
+ } else {
2999
+ await this.rollback();
3000
+ return {
3001
+ success: false,
3002
+ createdIds: newCreatedIds,
3003
+ obsoleteIds: []
3004
+ };
3005
+ }
3006
+ }
3007
+ /**
3008
+ * Rolls back the transaction by clearing all buffered changes.
3009
+ * If cleanup is `true`, it also clears the transaction nodes.
3010
+ * @param cleanup Whether to clear the transaction nodes.
3011
+ * @returns The IDs of nodes that were created in this transaction.
3012
+ */
3013
+ async rollback(cleanup = true) {
3014
+ const createdIds = Array.from(this.createdInTx);
3015
+ this.txNodes.clear();
3016
+ this.dirtyIds.clear();
3017
+ this.createdInTx.clear();
3018
+ if (cleanup) {
3019
+ for (const id of createdIds) {
3020
+ await this.realBaseStrategy.delete(id);
3021
+ }
3022
+ }
3023
+ return createdIds;
3024
+ }
3025
+ async readLock(fn) {
3026
+ return await fn();
3027
+ }
3028
+ async writeLock(fn) {
3029
+ return await fn();
3030
+ }
3031
+ async commitHeadBuffer() {
3032
+ }
3033
+ async commitNodeCreateBuffer() {
3034
+ }
3035
+ async commitNodeUpdateBuffer() {
3036
+ }
3037
+ async commitNodeDeleteBuffer() {
3038
+ }
3039
+ };
3040
+ var BPTreeAsync = class extends BPTreeAsyncBase {
3041
+ constructor(strategy, comparator, option) {
3042
+ super(strategy, comparator, option);
3043
+ }
3044
+ /**
3045
+ * Creates a new asynchronous transaction.
3046
+ * @returns A promise that resolves to a new BPTreeAsyncTransaction.
3047
+ */
3048
+ async createTransaction() {
3049
+ const tx = new BPTreeAsyncTransaction(this);
3050
+ await tx.initTransaction();
3051
+ return tx;
3052
+ }
3053
+ async insert(key, value) {
3054
+ const tx = await this.createTransaction();
3055
+ await tx.insert(key, value);
3056
+ const { success } = await tx.commit();
3057
+ await this.init();
3058
+ if (!success) {
3059
+ throw new Error("Transaction failed: Commit failed due to conflict");
3060
+ }
3061
+ }
3062
+ async delete(key, value) {
3063
+ const tx = await this.createTransaction();
3064
+ await tx.delete(key, value);
3065
+ const { success } = await tx.commit();
3066
+ await this.init();
3067
+ if (!success) {
3068
+ throw new Error("Transaction failed: Commit failed due to conflict");
3069
+ }
3070
+ }
3071
+ async readLock(fn) {
3072
+ return await fn();
3073
+ }
3074
+ async writeLock(fn) {
3075
+ return await fn();
3076
+ }
3077
+ };
2603
3078
 
2604
3079
  // node_modules/ryoiki/dist/esm/index.mjs
2605
- var Ryoiki2 = class _Ryoiki2 {
3080
+ var Ryoiki = class _Ryoiki {
2606
3081
  readings;
2607
3082
  writings;
2608
3083
  readQueue;
@@ -2646,7 +3121,7 @@ var Ryoiki2 = class _Ryoiki2 {
2646
3121
  return [start, start + length];
2647
3122
  }
2648
3123
  rangeOverlapping(tasks, range) {
2649
- return Array.from(tasks.values()).some((t) => _Ryoiki2.IsRangeOverlap(t.range, range));
3124
+ return Array.from(tasks.values()).some((t) => _Ryoiki.IsRangeOverlap(t.range, range));
2650
3125
  }
2651
3126
  isSameRange(a, b) {
2652
3127
  const [a1, a2] = a;
@@ -2687,7 +3162,7 @@ var Ryoiki2 = class _Ryoiki2 {
2687
3162
  _alloc(queue, workspaces, lockId) {
2688
3163
  const unit = queue.get(lockId);
2689
3164
  if (!unit) {
2690
- throw _Ryoiki2.ERR_NOT_EXISTS(lockId);
3165
+ throw _Ryoiki.ERR_NOT_EXISTS(lockId);
2691
3166
  }
2692
3167
  workspaces.set(lockId, unit);
2693
3168
  queue.delete(lockId);
@@ -2696,7 +3171,7 @@ var Ryoiki2 = class _Ryoiki2 {
2696
3171
  _free(workspaces, lockId) {
2697
3172
  const unit = workspaces.get(lockId);
2698
3173
  if (!unit) {
2699
- throw _Ryoiki2.ERR_NOT_EXISTS(lockId);
3174
+ throw _Ryoiki.ERR_NOT_EXISTS(lockId);
2700
3175
  }
2701
3176
  workspaces.delete(lockId);
2702
3177
  unit.free();
@@ -2706,7 +3181,7 @@ var Ryoiki2 = class _Ryoiki2 {
2706
3181
  let timeoutId = null;
2707
3182
  if (timeout >= 0) {
2708
3183
  timeoutId = setTimeout(() => {
2709
- reject(_Ryoiki2.ERR_TIMEOUT(id, timeout));
3184
+ reject(_Ryoiki.ERR_TIMEOUT(id, timeout));
2710
3185
  }, timeout);
2711
3186
  }
2712
3187
  const id = this._createRandomId();
@@ -2714,7 +3189,7 @@ var Ryoiki2 = class _Ryoiki2 {
2714
3189
  if (timeoutId !== null) {
2715
3190
  clearTimeout(timeoutId);
2716
3191
  }
2717
- const [err, v] = await _Ryoiki2.CatchError(task(id));
3192
+ const [err, v] = await _Ryoiki.CatchError(task(id));
2718
3193
  if (err) reject(err);
2719
3194
  else resolve(v);
2720
3195
  };
@@ -2729,7 +3204,7 @@ var Ryoiki2 = class _Ryoiki2 {
2729
3204
  _checkWorking(range, workspaces) {
2730
3205
  let isLocked = false;
2731
3206
  for (const lock of workspaces.values()) {
2732
- if (_Ryoiki2.IsRangeOverlap(range, lock.range)) {
3207
+ if (_Ryoiki.IsRangeOverlap(range, lock.range)) {
2733
3208
  isLocked = true;
2734
3209
  break;
2735
3210
  }
@@ -5840,8 +6315,11 @@ var RowIdentifierStrategy = class extends SerializeStrategyAsync {
5840
6315
  if (node.leaf) {
5841
6316
  const n = node;
5842
6317
  const keys = new Array(n.keys.length);
5843
- for (let i = 0, len = keys.length; i < len; i++) {
6318
+ let i = 0;
6319
+ const len = keys.length;
6320
+ while (i < len) {
5844
6321
  keys[i] = +n.keys[i][0];
6322
+ i++;
5845
6323
  }
5846
6324
  this.indexPageManger.setIndexId(page, +n.id);
5847
6325
  this.indexPageManger.setParentIndexId(page, +n.parent);
@@ -5854,8 +6332,11 @@ var RowIdentifierStrategy = class extends SerializeStrategyAsync {
5854
6332
  } else {
5855
6333
  const n = node;
5856
6334
  const keys = new Array(n.keys.length);
5857
- for (let i = 0, len = keys.length; i < len; i++) {
6335
+ let i = 0;
6336
+ const len = keys.length;
6337
+ while (i < len) {
5858
6338
  keys[i] = +n.keys[i];
6339
+ i++;
5859
6340
  }
5860
6341
  this.indexPageManger.setIndexId(page, +n.id);
5861
6342
  this.indexPageManger.setParentIndexId(page, +n.parent);
@@ -5890,9 +6371,11 @@ var RowIdentifierStrategy = class extends SerializeStrategyAsync {
5890
6371
  if (rootIndexPageId === -1) {
5891
6372
  return null;
5892
6373
  }
6374
+ const metaOrder = manager.getRootIndexOrder(metadataPage);
6375
+ const order = metaOrder || this.order;
5893
6376
  return {
5894
- root: manager.getRootIndexPageId(metadataPage).toString(),
5895
- order: manager.getRootIndexOrder(metadataPage),
6377
+ root: rootIndexPageId.toString(),
6378
+ order,
5896
6379
  data: {}
5897
6380
  };
5898
6381
  }
@@ -5979,8 +6462,9 @@ var RowTableEngine = class {
5979
6462
  this.pageIdBuffer = new Uint8Array(DataPageManager.CONSTANT.SIZE_PAGE_ID);
5980
6463
  this.maxBodySize = this.pfs.pageSize - DataPageManager.CONSTANT.SIZE_PAGE_HEADER;
5981
6464
  this.order = this.getOptimalOrder(pfs.pageSize, IndexPageManager.CONSTANT.SIZE_KEY, IndexPageManager.CONSTANT.SIZE_VALUE);
6465
+ this.strategy = new RowIdentifierStrategy(this.order, pfs, txContext);
5982
6466
  this.bptree = new BPTreeAsync(
5983
- new RowIdentifierStrategy(this.order, pfs, txContext),
6467
+ this.strategy,
5984
6468
  new NumericComparator(),
5985
6469
  {
5986
6470
  capacity: this.options.pageCacheCapacity
@@ -5988,6 +6472,7 @@ var RowTableEngine = class {
5988
6472
  );
5989
6473
  }
5990
6474
  bptree;
6475
+ strategy;
5991
6476
  order;
5992
6477
  factory;
5993
6478
  metadataPageManager;
@@ -5999,6 +6484,35 @@ var RowTableEngine = class {
5999
6484
  ridBuffer;
6000
6485
  pageIdBuffer;
6001
6486
  initialized = false;
6487
+ /**
6488
+ * Retrieves the BPTree transaction associated with the given transaction.
6489
+ * If it doesn't exist, it creates a new one and registers commit/rollback hooks.
6490
+ * @param tx Dataply transaction
6491
+ * @returns BPTree transaction
6492
+ */
6493
+ async getBPTreeTransaction(tx) {
6494
+ let btx = tx.__getBPTreeTransaction();
6495
+ if (!btx) {
6496
+ btx = await this.bptree.createTransaction();
6497
+ tx.__setBPTreeTransaction(btx);
6498
+ tx.onCommit(async () => {
6499
+ if (!tx.__isBPTreeDirty()) {
6500
+ return;
6501
+ }
6502
+ if (!btx) return;
6503
+ const result = await btx.commit();
6504
+ if (result.success) {
6505
+ await this.bptree.init();
6506
+ for (const id of result.obsoleteIds) {
6507
+ await this.strategy.delete(id);
6508
+ }
6509
+ } else {
6510
+ throw new Error(`BPTree transaction commit failed. Current Root: ${this.bptree.getRootId()}`);
6511
+ }
6512
+ });
6513
+ }
6514
+ return btx;
6515
+ }
6002
6516
  /**
6003
6517
  * Initializes the B+ Tree.
6004
6518
  */
@@ -6128,7 +6642,9 @@ var RowTableEngine = class {
6128
6642
  this.metadataPageManager.setRowCount(freshMetadataPage, currentRowCount + 1);
6129
6643
  }
6130
6644
  await this.pfs.setMetadata(freshMetadataPage, tx);
6131
- await this.bptree.insert(this.getRID(), pk);
6645
+ const btx = await this.getBPTreeTransaction(tx);
6646
+ await btx.insert(this.getRID(), pk);
6647
+ tx.__markBPTreeDirty();
6132
6648
  return pk;
6133
6649
  }
6134
6650
  /**
@@ -6139,11 +6655,8 @@ var RowTableEngine = class {
6139
6655
  * @returns RID or null (if not found)
6140
6656
  */
6141
6657
  async getRidByPK(pk, tx) {
6142
- const pendingUpdate = tx.__getPendingIndexUpdate(pk);
6143
- if (pendingUpdate) {
6144
- return pendingUpdate.newRid;
6145
- }
6146
- const keys = await this.bptree.keys({ equal: pk });
6658
+ const btx = await this.getBPTreeTransaction(tx);
6659
+ const keys = await btx.keys({ equal: pk });
6147
6660
  if (keys.size === 0) {
6148
6661
  return null;
6149
6662
  }
@@ -6162,6 +6675,7 @@ var RowTableEngine = class {
6162
6675
  * @param tx Transaction
6163
6676
  */
6164
6677
  async update(pk, data, tx) {
6678
+ await tx.__acquireWriteLock(0);
6165
6679
  const rid = await this.getRidByPK(pk, tx);
6166
6680
  if (rid === null) {
6167
6681
  return;
@@ -6231,16 +6745,10 @@ var RowTableEngine = class {
6231
6745
  const oldRidNumeric = this.getRID();
6232
6746
  this.setRID(lastInsertDataPageId, newSlotIndex);
6233
6747
  const newRidNumeric = this.getRID();
6234
- if (tx.__getPendingIndexUpdates().size === 0) {
6235
- tx.onCommit(async () => {
6236
- const updates = tx.__getPendingIndexUpdates();
6237
- for (const [key, { newRid, oldRid }] of updates) {
6238
- await this.bptree.delete(oldRid, key);
6239
- await this.bptree.insert(newRid, key);
6240
- }
6241
- });
6242
- }
6243
- tx.__addPendingIndexUpdate(pk, newRidNumeric, oldRidNumeric);
6748
+ const btx = await this.getBPTreeTransaction(tx);
6749
+ await btx.delete(oldRidNumeric, pk);
6750
+ await btx.insert(newRidNumeric, pk);
6751
+ tx.__markBPTreeDirty();
6244
6752
  const freshMetadataPage = await this.pfs.getMetadata(tx);
6245
6753
  this.metadataPageManager.setLastInsertPageId(freshMetadataPage, lastInsertDataPageId);
6246
6754
  await this.pfs.setMetadata(freshMetadataPage, tx);
@@ -6280,6 +6788,9 @@ var RowTableEngine = class {
6280
6788
  }
6281
6789
  this.rowManager.setDeletedFlag(row, true);
6282
6790
  await this.pfs.setPage(pageId, page, tx);
6791
+ const btx = await this.getBPTreeTransaction(tx);
6792
+ await btx.delete(rid, pk);
6793
+ tx.__markBPTreeDirty();
6283
6794
  if (decrementRowCount) {
6284
6795
  const metadataPage2 = await this.pfs.getMetadata(tx);
6285
6796
  const currentRowCount = this.metadataPageManager.getRowCount(metadataPage2);
@@ -6293,12 +6804,14 @@ var RowTableEngine = class {
6293
6804
  if (pageId === lastInsertPageId) {
6294
6805
  allDeleted = false;
6295
6806
  } else {
6296
- for (let i = 0; i < insertedRowCount; i++) {
6807
+ let i = 0;
6808
+ while (i < insertedRowCount) {
6297
6809
  const slotRow = this.dataPageManager.getRow(page, i);
6298
6810
  if (!this.rowManager.getDeletedFlag(slotRow)) {
6299
6811
  allDeleted = false;
6300
6812
  break;
6301
6813
  }
6814
+ i++;
6302
6815
  }
6303
6816
  }
6304
6817
  if (allDeleted) {
@@ -6361,7 +6874,7 @@ var LockManager = class {
6361
6874
  lock;
6362
6875
  unlockMap = /* @__PURE__ */ new Map();
6363
6876
  constructor() {
6364
- this.lock = new Ryoiki2();
6877
+ this.lock = new Ryoiki();
6365
6878
  }
6366
6879
  /**
6367
6880
  * Requests a read (Shared) lock for a page.
@@ -6424,12 +6937,41 @@ var Transaction = class {
6424
6937
  pageLocks = /* @__PURE__ */ new Map();
6425
6938
  /** Undo Logs: PageID -> Original Page Buffer (Snapshot) */
6426
6939
  undoPages = /* @__PURE__ */ new Map();
6427
- /** List of Dirty Pages modified by the transaction */
6940
+ /** Dirty Pages modified by the transaction */
6428
6941
  dirtyPages = /* @__PURE__ */ new Set();
6429
- /** Pending Index Updates: PK -> { newRid, oldRid } */
6430
- pendingIndexUpdates = /* @__PURE__ */ new Map();
6942
+ /** BPTree Transaction instance */
6943
+ bptreeTx;
6944
+ /** Whether the BPTree transaction is dirty */
6945
+ bptreeDirty = false;
6431
6946
  /** List of callbacks to execute on commit */
6432
6947
  commitHooks = [];
6948
+ /**
6949
+ * Sets the BPTree transaction.
6950
+ * @param tx BPTree transaction
6951
+ */
6952
+ __setBPTreeTransaction(tx) {
6953
+ this.bptreeTx = tx;
6954
+ }
6955
+ /**
6956
+ * Returns the BPTree transaction.
6957
+ * @returns BPTree transaction
6958
+ */
6959
+ __getBPTreeTransaction() {
6960
+ return this.bptreeTx;
6961
+ }
6962
+ /**
6963
+ * Marks the BPTree transaction as dirty.
6964
+ */
6965
+ __markBPTreeDirty() {
6966
+ this.bptreeDirty = true;
6967
+ }
6968
+ /**
6969
+ * Returns whether the BPTree transaction is dirty.
6970
+ * @returns True if dirty
6971
+ */
6972
+ __isBPTreeDirty() {
6973
+ return this.bptreeDirty;
6974
+ }
6433
6975
  /**
6434
6976
  * Registers a commit hook.
6435
6977
  * @param hook Function to execute
@@ -6465,32 +7007,6 @@ var Transaction = class {
6465
7007
  __hasUndoPage(pageId) {
6466
7008
  return this.undoPages.has(pageId);
6467
7009
  }
6468
- /**
6469
- * Adds a Pending Index Update.
6470
- * Does not call this method directly. It is called by the `VirtualFileSystem` instance.
6471
- * @param pk PK
6472
- * @param newRid New RID
6473
- * @param oldRid Old RID
6474
- */
6475
- __addPendingIndexUpdate(pk, newRid, oldRid) {
6476
- this.pendingIndexUpdates.set(pk, { newRid, oldRid });
6477
- }
6478
- /**
6479
- * Returns a Pending Index Update.
6480
- * Does not call this method directly. It is called by the `VirtualFileSystem` instance.
6481
- * @param pk PK
6482
- * @returns Pending Index Update
6483
- */
6484
- __getPendingIndexUpdate(pk) {
6485
- return this.pendingIndexUpdates.get(pk);
6486
- }
6487
- /**
6488
- * Returns all Pending Index Updates.
6489
- * Does not call this method directly. It is called by the `VirtualFileSystem` instance.
6490
- */
6491
- __getPendingIndexUpdates() {
6492
- return this.pendingIndexUpdates;
6493
- }
6494
7010
  /**
6495
7011
  * Acquires a write lock.
6496
7012
  * Does not call this method directly. It is called by the `VirtualFileSystem` instance.
@@ -6518,19 +7034,22 @@ var Transaction = class {
6518
7034
  * Commits the transaction.
6519
7035
  */
6520
7036
  async commit() {
6521
- await this.vfs.prepareCommit(this);
6522
- await this.vfs.finalizeCommit(this);
6523
7037
  await this.context.run(this, async () => {
6524
7038
  for (const hook of this.commitHooks) {
6525
7039
  await hook();
6526
7040
  }
6527
7041
  });
7042
+ await this.vfs.prepareCommit(this);
7043
+ await this.vfs.finalizeCommit(this);
6528
7044
  this.releaseAllLocks();
6529
7045
  }
6530
7046
  /**
6531
7047
  * Rolls back the transaction.
6532
7048
  */
6533
- async rollback() {
7049
+ async rollback(cleanup = true) {
7050
+ if (this.bptreeTx) {
7051
+ await this.bptreeTx.rollback(cleanup);
7052
+ }
6534
7053
  await this.vfs.rollback(this);
6535
7054
  this.releaseAllLocks();
6536
7055
  }
@@ -6669,6 +7188,8 @@ var DataplyAPI = class {
6669
7188
  metadataPageManager.setMagicString(metadataPage);
6670
7189
  metadataPageManager.setPageSize(metadataPage, options.pageSize);
6671
7190
  metadataPageManager.setRootIndexPageId(metadataPage, -1);
7191
+ const order = Math.floor((options.pageSize - IndexPageManager.CONSTANT.OFFSET_KEYS_AND_VALUES + IndexPageManager.CONSTANT.SIZE_KEY) / (IndexPageManager.CONSTANT.SIZE_KEY + IndexPageManager.CONSTANT.SIZE_VALUE));
7192
+ metadataPageManager.setRootIndexOrder(metadataPage, order);
6672
7193
  metadataPageManager.setBitmapPageId(metadataPage, 1);
6673
7194
  metadataPageManager.setLastInsertPageId(metadataPage, 2);
6674
7195
  metadataPageManager.setPageCount(metadataPage, 3);
@@ -7047,7 +7568,9 @@ var GlobalTransaction = class {
7047
7568
  // Annotate the CommonJS export names for ESM import in node:
7048
7569
  0 && (module.exports = {
7049
7570
  BPTreeAsync,
7571
+ BPTreeAsyncTransaction,
7050
7572
  BPTreeSync,
7573
+ BPTreeSyncTransaction,
7051
7574
  BitmapPageManager,
7052
7575
  CacheEntanglementAsync,
7053
7576
  CacheEntanglementSync,