dataply 0.0.16-alpha.1 → 0.0.16-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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;
@@ -525,13 +541,13 @@ var BPTree = class _BPTree {
525
541
  }
526
542
  };
527
543
  verifierStartNode = {
528
- gt: (v) => this.insertableNode(v),
529
- gte: (v) => this.insertableNode(v),
530
- lt: (v) => this.insertableNode(v),
531
- lte: (v) => this.insertableNode(v),
532
- equal: (v) => this.insertableNode(v),
544
+ gt: (v) => this.insertableNodeByPrimary(v),
545
+ gte: (v) => this.insertableNodeByPrimary(v),
546
+ lt: (v) => this.insertableNodeByPrimary(v),
547
+ lte: (v) => this.insertableRightestNodeByPrimary(v),
548
+ equal: (v) => this.insertableNodeByPrimary(v),
533
549
  notEqual: (v) => this.leftestNode(),
534
- or: (v) => this.insertableNode(this.lowestValue(this.ensureValues(v))),
550
+ or: (v) => this.insertableNodeByPrimary(this.lowestPrimaryValue(this.ensureValues(v))),
535
551
  primaryGt: (v) => this.insertableNodeByPrimary(v),
536
552
  primaryGte: (v) => this.insertableNodeByPrimary(v),
537
553
  primaryLt: (v) => this.insertableNodeByPrimary(v),
@@ -556,7 +572,7 @@ var BPTree = class _BPTree {
556
572
  primaryGte: (v) => null,
557
573
  primaryLt: (v) => null,
558
574
  primaryLte: (v) => null,
559
- primaryEqual: (v) => null,
575
+ primaryEqual: (v) => this.insertableRightestEndNodeByPrimary(v),
560
576
  primaryNotEqual: (v) => null,
561
577
  primaryOr: (v) => this.insertableRightestEndNodeByPrimary(
562
578
  this.highestPrimaryValue(this.ensureValues(v))
@@ -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,401 @@ 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
+ * Internal use only.
1648
1876
  */
1649
- canRead(range) {
1650
- const writing = this.isWriting(range);
1651
- return !writing;
1877
+ rollback() {
1878
+ this.txNodes.clear();
1879
+ this.dirtyIds.clear();
1880
+ this.createdInTx.clear();
1652
1881
  }
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;
1882
+ // Override to do nothing, as transaction handles its own commits
1883
+ commitHeadBuffer() {
1662
1884
  }
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
- );
1885
+ commitNodeCreateBuffer() {
1697
1886
  }
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
- );
1887
+ commitNodeUpdateBuffer() {
1734
1888
  }
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);
1889
+ commitNodeDeleteBuffer() {
1890
+ }
1891
+ };
1892
+ var BPTreeSync = class extends BPTreeSyncBase {
1893
+ constructor(strategy, comparator, option) {
1894
+ super(strategy, comparator, option);
1895
+ this.init();
1741
1896
  }
1742
1897
  /**
1743
- * Releases a write lock by its lock ID.
1744
- * @param lockId - The unique identifier for the lock to release.
1898
+ * Creates a new synchronous transaction.
1899
+ * @returns A new BPTreeSyncTransaction.
1745
1900
  */
1746
- writeUnlock(lockId) {
1747
- this._free(this.writings, lockId);
1901
+ createTransaction() {
1902
+ const tx = new BPTreeSyncTransaction(this);
1903
+ tx.initTransaction();
1904
+ return tx;
1905
+ }
1906
+ insert(key, value) {
1907
+ const tx = this.createTransaction();
1908
+ tx.insert(key, value);
1909
+ const { success } = tx.commit();
1910
+ this.init();
1911
+ if (!success) {
1912
+ throw new Error("Transaction failed: Commit failed due to conflict");
1913
+ }
1914
+ }
1915
+ delete(key, value) {
1916
+ const tx = this.createTransaction();
1917
+ tx.delete(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
+ }
1748
1923
  }
1749
1924
  };
1750
- var BPTreeAsync = class extends BPTree {
1751
- lock;
1925
+ var BPTreeAsyncBase = class extends BPTree {
1752
1926
  constructor(strategy, comparator, option) {
1753
1927
  super(strategy, comparator, option);
1754
1928
  this.nodes = this._createCachedNode();
1755
- this.lock = new Ryoiki();
1756
1929
  }
1757
1930
  _createCachedNode() {
1758
1931
  return new CacheEntanglementAsync(async (key) => {
@@ -1761,24 +1934,6 @@ var BPTreeAsync = class extends BPTree {
1761
1934
  capacity: this.option.capacity ?? 1e3
1762
1935
  });
1763
1936
  }
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
1937
  async *getPairsGenerator(value, startNode, endNode, comparator, direction, earlyTerminate) {
1783
1938
  let node = startNode;
1784
1939
  let done = false;
@@ -1843,7 +1998,7 @@ var BPTreeAsync = class extends BPTree {
1843
1998
  }
1844
1999
  return id;
1845
2000
  }
1846
- async _createNode(isLeaf, keys, values, leaf = false, parent = null, next = null, prev = null) {
2001
+ async _createNode(isLeaf, keys, values, leaf = isLeaf, parent = null, next = null, prev = null) {
1847
2002
  const id = await this._createNodeId(isLeaf);
1848
2003
  const node = {
1849
2004
  id,
@@ -1854,38 +2009,37 @@ var BPTreeAsync = class extends BPTree {
1854
2009
  next,
1855
2010
  prev
1856
2011
  };
1857
- this._nodeCreateBuffer.set(id, node);
2012
+ await this.bufferForNodeCreate(node);
1858
2013
  return node;
1859
2014
  }
1860
2015
  async _deleteEntry(node, key, value) {
1861
2016
  if (!node.leaf) {
2017
+ let keyIndex = -1;
1862
2018
  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);
2019
+ if (node.keys[i] === key) {
2020
+ keyIndex = i;
1867
2021
  break;
1868
2022
  }
1869
2023
  }
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
- }
2024
+ if (keyIndex !== -1) {
2025
+ node.keys.splice(keyIndex, 1);
2026
+ const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
2027
+ node.values.splice(valueIndex, 1);
2028
+ await this.bufferForNodeUpdate(node);
1877
2029
  }
1878
2030
  }
1879
- if (this.root.id === node.id && node.keys.length === 1) {
2031
+ if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
1880
2032
  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);
2033
+ await this.bufferForNodeDelete(node);
2034
+ const newRoot = await this.getNode(keys[0]);
2035
+ this.rootId = newRoot.id;
2036
+ newRoot.parent = null;
2037
+ this.strategy.head.root = this.rootId;
2038
+ await this.bufferForNodeUpdate(newRoot);
1886
2039
  return;
1887
- } else if (this.root.id === node.id) {
1888
- this.bufferForNodeUpdate(this.root);
2040
+ } else if (this.rootId === node.id) {
2041
+ const root = await this.getNode(this.rootId);
2042
+ await this.bufferForNodeUpdate(root);
1889
2043
  return;
1890
2044
  } else if (node.keys.length < Math.ceil(this.order / 2) && !node.leaf || node.values.length < Math.ceil((this.order - 1) / 2) && node.leaf) {
1891
2045
  if (node.parent === null) {
@@ -1943,33 +2097,24 @@ var BPTreeAsync = class extends BPTree {
1943
2097
  pointer.values.push(guess);
1944
2098
  } else {
1945
2099
  pointer.next = node.next;
1946
- pointer.prev = node.id;
1947
2100
  if (pointer.next) {
1948
- const n = await this.getNode(node.next);
2101
+ const n = await this.getNode(pointer.next);
1949
2102
  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;
2103
+ await this.bufferForNodeUpdate(n);
1959
2104
  }
1960
2105
  }
1961
2106
  pointer.values.push(...node.values);
1962
2107
  if (!pointer.leaf) {
1963
2108
  const keys = pointer.keys;
1964
2109
  for (const key2 of keys) {
1965
- const node2 = await this.getNode(key2);
1966
- node2.parent = pointer.id;
1967
- this.bufferForNodeUpdate(node2);
2110
+ const n = await this.getNode(key2);
2111
+ n.parent = pointer.id;
2112
+ await this.bufferForNodeUpdate(n);
1968
2113
  }
1969
2114
  }
1970
2115
  await this._deleteEntry(await this.getNode(node.parent), node.id, guess);
1971
- this.bufferForNodeUpdate(pointer);
1972
- this.bufferForNodeDelete(node);
2116
+ await this.bufferForNodeUpdate(pointer);
2117
+ await this.bufferForNodeDelete(node);
1973
2118
  } else {
1974
2119
  if (isPredecessor) {
1975
2120
  let pointerPm;
@@ -1980,13 +2125,10 @@ var BPTreeAsync = class extends BPTree {
1980
2125
  node.keys = [pointerPm, ...node.keys];
1981
2126
  node.values = [guess, ...node.values];
1982
2127
  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
- }
2128
+ const nodeIndex = parentNode.keys.indexOf(node.id);
2129
+ if (nodeIndex > 0) {
2130
+ parentNode.values[nodeIndex - 1] = pointerKm;
2131
+ await this.bufferForNodeUpdate(parentNode);
1990
2132
  }
1991
2133
  } else {
1992
2134
  pointerPm = pointer.keys.splice(-1)[0];
@@ -1994,17 +2136,14 @@ var BPTreeAsync = class extends BPTree {
1994
2136
  node.keys = [pointerPm, ...node.keys];
1995
2137
  node.values = [pointerKm, ...node.values];
1996
2138
  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
- }
2139
+ const nodeIndex = parentNode.keys.indexOf(node.id);
2140
+ if (nodeIndex > 0) {
2141
+ parentNode.values[nodeIndex - 1] = pointerKm;
2142
+ await this.bufferForNodeUpdate(parentNode);
2004
2143
  }
2005
2144
  }
2006
- this.bufferForNodeUpdate(node);
2007
- this.bufferForNodeUpdate(pointer);
2145
+ await this.bufferForNodeUpdate(node);
2146
+ await this.bufferForNodeUpdate(pointer);
2008
2147
  } else {
2009
2148
  let pointerP0;
2010
2149
  let pointerK0;
@@ -2014,13 +2153,10 @@ var BPTreeAsync = class extends BPTree {
2014
2153
  node.keys = [...node.keys, pointerP0];
2015
2154
  node.values = [...node.values, guess];
2016
2155
  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
- }
2156
+ const pointerIndex = parentNode.keys.indexOf(pointer.id);
2157
+ if (pointerIndex > 0) {
2158
+ parentNode.values[pointerIndex - 1] = pointerK0;
2159
+ await this.bufferForNodeUpdate(parentNode);
2024
2160
  }
2025
2161
  } else {
2026
2162
  pointerP0 = pointer.keys.splice(0, 1)[0];
@@ -2028,87 +2164,85 @@ var BPTreeAsync = class extends BPTree {
2028
2164
  node.keys = [...node.keys, pointerP0];
2029
2165
  node.values = [...node.values, pointerK0];
2030
2166
  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
- }
2167
+ const pointerIndex = parentNode.keys.indexOf(pointer.id);
2168
+ if (pointerIndex > 0) {
2169
+ parentNode.values[pointerIndex - 1] = pointer.values[0];
2170
+ await this.bufferForNodeUpdate(parentNode);
2038
2171
  }
2039
2172
  }
2040
- this.bufferForNodeUpdate(node);
2041
- this.bufferForNodeUpdate(pointer);
2173
+ await this.bufferForNodeUpdate(node);
2174
+ await this.bufferForNodeUpdate(pointer);
2042
2175
  }
2043
2176
  if (!pointer.leaf) {
2044
- for (const key2 of pointer.keys) {
2177
+ const keys = pointer.keys;
2178
+ for (const key2 of keys) {
2045
2179
  const n = await this.getNode(key2);
2046
2180
  n.parent = pointer.id;
2047
- this.bufferForNodeUpdate(n);
2181
+ await this.bufferForNodeUpdate(n);
2048
2182
  }
2049
2183
  }
2050
2184
  if (!node.leaf) {
2051
- for (const key2 of node.keys) {
2185
+ const keys = node.keys;
2186
+ for (const key2 of keys) {
2052
2187
  const n = await this.getNode(key2);
2053
2188
  n.parent = node.id;
2054
- this.bufferForNodeUpdate(n);
2189
+ await this.bufferForNodeUpdate(n);
2055
2190
  }
2056
2191
  }
2057
2192
  if (!parentNode.leaf) {
2058
- for (const key2 of parentNode.keys) {
2193
+ const keys = parentNode.keys;
2194
+ for (const key2 of keys) {
2059
2195
  const n = await this.getNode(key2);
2060
2196
  n.parent = parentNode.id;
2061
- this.bufferForNodeUpdate(n);
2197
+ await this.bufferForNodeUpdate(n);
2062
2198
  }
2063
2199
  }
2064
2200
  }
2201
+ } else {
2202
+ await this.bufferForNodeUpdate(node);
2065
2203
  }
2066
2204
  }
2067
2205
  async _insertInParent(node, value, pointer) {
2068
- if (this.root.id === node.id) {
2206
+ if (this.rootId === node.id) {
2069
2207
  const root = await this._createNode(false, [node.id, pointer.id], [value]);
2070
- this.root = root;
2208
+ this.rootId = root.id;
2071
2209
  this.strategy.head.root = root.id;
2072
2210
  node.parent = root.id;
2073
2211
  pointer.parent = root.id;
2074
2212
  if (pointer.leaf) {
2075
- node.next = pointer.id;
2076
- pointer.prev = node.id;
2213
+ const nNode = node;
2214
+ nNode.next = pointer.id;
2215
+ const nPointer = pointer;
2216
+ nPointer.prev = node.id;
2077
2217
  }
2078
- this.bufferForNodeUpdate(node);
2079
- this.bufferForNodeUpdate(pointer);
2218
+ await this.bufferForNodeUpdate(node);
2219
+ await this.bufferForNodeUpdate(pointer);
2080
2220
  return;
2081
2221
  }
2082
2222
  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
- }
2223
+ const nodeIndex = parentNode.keys.indexOf(node.id);
2224
+ if (nodeIndex === -1) {
2225
+ throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
2090
2226
  }
2227
+ const insertIndex = nodeIndex;
2091
2228
  parentNode.values.splice(insertIndex, 0, value);
2092
2229
  parentNode.keys.splice(insertIndex + 1, 0, pointer.id);
2093
2230
  pointer.parent = parentNode.id;
2094
2231
  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);
2232
+ const leftSibling = node;
2233
+ const oldNextId = leftSibling.next;
2234
+ pointer.prev = leftSibling.id;
2235
+ pointer.next = oldNextId;
2236
+ leftSibling.next = pointer.id;
2237
+ await this.bufferForNodeUpdate(leftSibling);
2238
+ if (oldNextId) {
2239
+ const oldNext = await this.getNode(oldNextId);
2240
+ oldNext.prev = pointer.id;
2241
+ await this.bufferForNodeUpdate(oldNext);
2108
2242
  }
2109
2243
  }
2110
- this.bufferForNodeUpdate(parentNode);
2111
- this.bufferForNodeUpdate(pointer);
2244
+ await this.bufferForNodeUpdate(parentNode);
2245
+ await this.bufferForNodeUpdate(pointer);
2112
2246
  if (parentNode.keys.length > this.order) {
2113
2247
  const parentPointer = await this._createNode(false, [], []);
2114
2248
  parentPointer.parent = parentNode.parent;
@@ -2119,32 +2253,34 @@ var BPTreeAsync = class extends BPTree {
2119
2253
  parentNode.values = parentNode.values.slice(0, mid);
2120
2254
  parentNode.keys = parentNode.keys.slice(0, mid + 1);
2121
2255
  for (const k of parentNode.keys) {
2122
- const node2 = await this.getNode(k);
2123
- node2.parent = parentNode.id;
2124
- this.bufferForNodeUpdate(node2);
2256
+ const n = await this.getNode(k);
2257
+ n.parent = parentNode.id;
2258
+ await this.bufferForNodeUpdate(n);
2125
2259
  }
2126
2260
  for (const k of parentPointer.keys) {
2127
- const node2 = await this.getNode(k);
2128
- node2.parent = parentPointer.id;
2129
- this.bufferForNodeUpdate(node2);
2261
+ const n = await this.getNode(k);
2262
+ n.parent = parentPointer.id;
2263
+ await this.bufferForNodeUpdate(n);
2130
2264
  }
2131
2265
  await this._insertInParent(parentNode, midValue, parentPointer);
2132
- this.bufferForNodeUpdate(parentNode);
2266
+ await this.bufferForNodeUpdate(parentNode);
2133
2267
  }
2134
2268
  }
2135
2269
  async init() {
2270
+ this.clear();
2136
2271
  const head = await this.strategy.readHead();
2137
2272
  if (head === null) {
2138
2273
  this.order = this.strategy.order;
2139
- this.root = await this._createNode(true, [], [], true);
2140
- this.strategy.head.root = this.root.id;
2274
+ const root = await this._createNode(true, [], [], true);
2275
+ this.rootId = root.id;
2276
+ this.strategy.head.root = this.rootId;
2141
2277
  await this.commitHeadBuffer();
2142
2278
  await this.commitNodeCreateBuffer();
2143
2279
  } else {
2144
2280
  const { root, order } = head;
2145
2281
  this.strategy.head = head;
2146
2282
  this.order = order;
2147
- this.root = await this.getNode(root);
2283
+ this.rootId = root;
2148
2284
  }
2149
2285
  if (this.order < 3) {
2150
2286
  throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
@@ -2161,43 +2297,73 @@ var BPTreeAsync = class extends BPTree {
2161
2297
  return cache.raw;
2162
2298
  }
2163
2299
  async insertableNode(value) {
2164
- let node = await this.getNode(this.root.id);
2300
+ let node = await this.getNode(this.rootId);
2301
+ if (node.parent !== null) {
2302
+ node.parent = null;
2303
+ await this.bufferForNodeUpdate(node);
2304
+ }
2165
2305
  while (!node.leaf) {
2306
+ const parentId = node.id;
2166
2307
  for (let i = 0, len = node.values.length; i < len; i++) {
2167
2308
  const nValue = node.values[i];
2168
2309
  const k = node.keys;
2169
2310
  if (this.comparator.isSame(value, nValue)) {
2170
- node = await this.getNode(k[i + 1]);
2311
+ node = await this.getNode(node.keys[i + 1]);
2312
+ if (node.parent !== parentId) {
2313
+ node.parent = parentId;
2314
+ await this.bufferForNodeUpdate(node);
2315
+ }
2171
2316
  break;
2172
2317
  } else if (this.comparator.isLower(value, nValue)) {
2173
- node = await this.getNode(k[i]);
2318
+ node = await this.getNode(node.keys[i]);
2319
+ if (node.parent !== parentId) {
2320
+ node.parent = parentId;
2321
+ await this.bufferForNodeUpdate(node);
2322
+ }
2174
2323
  break;
2175
2324
  } else if (i + 1 === node.values.length) {
2176
- node = await this.getNode(k[i + 1]);
2325
+ node = await this.getNode(node.keys[i + 1]);
2326
+ if (node.parent !== parentId) {
2327
+ node.parent = parentId;
2328
+ await this.bufferForNodeUpdate(node);
2329
+ }
2177
2330
  break;
2178
2331
  }
2179
2332
  }
2180
2333
  }
2181
2334
  return node;
2182
2335
  }
2183
- /**
2184
- * Find the insertable node using primaryAsc comparison.
2185
- * This allows finding nodes by primary value only, ignoring unique identifiers.
2186
- */
2187
2336
  async insertableNodeByPrimary(value) {
2188
- let node = await this.getNode(this.root.id);
2337
+ let node = await this.getNode(this.rootId);
2338
+ if (node.parent !== null) {
2339
+ node.parent = null;
2340
+ await this.bufferForNodeUpdate(node);
2341
+ }
2189
2342
  while (!node.leaf) {
2343
+ const parentId = node.id;
2190
2344
  for (let i = 0, len = node.values.length; i < len; i++) {
2191
2345
  const nValue = node.values[i];
2192
2346
  const k = node.keys;
2193
2347
  if (this.comparator.isPrimarySame(value, nValue)) {
2194
- node = await this.getNode(k[i]);
2348
+ node = await this.getNode(node.keys[i]);
2349
+ if (node.parent !== parentId) {
2350
+ node.parent = parentId;
2351
+ await this.bufferForNodeUpdate(node);
2352
+ }
2195
2353
  break;
2196
2354
  } else if (this.comparator.isPrimaryLower(value, nValue)) {
2197
- node = await this.getNode(k[i]);
2355
+ node = await this.getNode(node.keys[i]);
2356
+ if (node.parent !== parentId) {
2357
+ node.parent = parentId;
2358
+ await this.bufferForNodeUpdate(node);
2359
+ }
2198
2360
  break;
2199
2361
  } else if (i + 1 === node.values.length) {
2200
- node = await this.getNode(k[i + 1]);
2362
+ node = await this.getNode(node.keys[i + 1]);
2363
+ if (node.parent !== parentId) {
2364
+ node.parent = parentId;
2365
+ await this.bufferForNodeUpdate(node);
2366
+ }
2201
2367
  break;
2202
2368
  }
2203
2369
  }
@@ -2205,17 +2371,30 @@ var BPTreeAsync = class extends BPTree {
2205
2371
  return node;
2206
2372
  }
2207
2373
  async insertableRightestNodeByPrimary(value) {
2208
- let node = await this.getNode(this.root.id);
2374
+ let node = await this.getNode(this.rootId);
2375
+ if (node.parent !== null) {
2376
+ node.parent = null;
2377
+ await this.bufferForNodeUpdate(node);
2378
+ }
2209
2379
  while (!node.leaf) {
2380
+ const parentId = node.id;
2210
2381
  for (let i = 0, len = node.values.length; i < len; i++) {
2211
2382
  const nValue = node.values[i];
2212
2383
  const k = node.keys;
2213
2384
  if (this.comparator.isPrimaryLower(value, nValue)) {
2214
- node = await this.getNode(k[i]);
2385
+ node = await this.getNode(node.keys[i]);
2386
+ if (node.parent !== parentId) {
2387
+ node.parent = parentId;
2388
+ await this.bufferForNodeUpdate(node);
2389
+ }
2215
2390
  break;
2216
2391
  }
2217
2392
  if (i + 1 === node.values.length) {
2218
- node = await this.getNode(k[i + 1]);
2393
+ node = await this.getNode(node.keys[i + 1]);
2394
+ if (node.parent !== parentId) {
2395
+ node.parent = parentId;
2396
+ await this.bufferForNodeUpdate(node);
2397
+ }
2219
2398
  break;
2220
2399
  }
2221
2400
  }
@@ -2249,27 +2428,75 @@ var BPTreeAsync = class extends BPTree {
2249
2428
  return await this.getNode(guessNode);
2250
2429
  }
2251
2430
  async leftestNode() {
2252
- let node = this.root;
2431
+ let node = await this.getNode(this.rootId);
2432
+ if (node.parent !== null) {
2433
+ node.parent = null;
2434
+ await this.bufferForNodeUpdate(node);
2435
+ }
2253
2436
  while (!node.leaf) {
2437
+ const parentId = node.id;
2254
2438
  const keys = node.keys;
2255
- node = await this.getNode(keys[0]);
2439
+ node = await this.getNode(node.keys[0]);
2440
+ if (node.parent !== parentId) {
2441
+ node.parent = parentId;
2442
+ await this.bufferForNodeUpdate(node);
2443
+ }
2256
2444
  }
2257
2445
  return node;
2258
2446
  }
2259
2447
  async rightestNode() {
2260
- let node = this.root;
2448
+ let node = await this.getNode(this.rootId);
2449
+ if (node.parent !== null) {
2450
+ node.parent = null;
2451
+ await this.bufferForNodeUpdate(node);
2452
+ }
2261
2453
  while (!node.leaf) {
2454
+ const parentId = node.id;
2262
2455
  const keys = node.keys;
2263
- node = await this.getNode(keys[keys.length - 1]);
2456
+ node = await this.getNode(node.keys[node.keys.length - 1]);
2457
+ if (node.parent !== parentId) {
2458
+ node.parent = parentId;
2459
+ await this.bufferForNodeUpdate(node);
2460
+ }
2264
2461
  }
2265
2462
  return node;
2266
2463
  }
2464
+ async exists(key, value) {
2465
+ const node = await this.insertableNode(value);
2466
+ for (let i = 0, len = node.values.length; i < len; i++) {
2467
+ if (this.comparator.isSame(value, node.values[i])) {
2468
+ const keys = node.keys[i];
2469
+ if (keys.includes(key)) {
2470
+ return true;
2471
+ }
2472
+ }
2473
+ }
2474
+ return false;
2475
+ }
2476
+ async forceUpdate(id) {
2477
+ if (id) {
2478
+ this.nodes.delete(id);
2479
+ await this.getNode(id);
2480
+ return 1;
2481
+ }
2482
+ const keys = Array.from(this.nodes.keys());
2483
+ for (const key of keys) {
2484
+ this.nodes.delete(key);
2485
+ }
2486
+ for (const key of keys) {
2487
+ await this.getNode(key);
2488
+ }
2489
+ return keys.length;
2490
+ }
2267
2491
  async commitHeadBuffer() {
2268
2492
  if (!this._strategyDirty) {
2269
2493
  return;
2270
2494
  }
2271
2495
  this._strategyDirty = false;
2272
2496
  await this.strategy.writeHead(this.strategy.head);
2497
+ if (this.strategy.head.root) {
2498
+ this.nodes.delete(this.strategy.head.root);
2499
+ }
2273
2500
  }
2274
2501
  async commitNodeCreateBuffer() {
2275
2502
  for (const node of this._nodeCreateBuffer.values()) {
@@ -2280,34 +2507,26 @@ var BPTreeAsync = class extends BPTree {
2280
2507
  async commitNodeUpdateBuffer() {
2281
2508
  for (const node of this._nodeUpdateBuffer.values()) {
2282
2509
  await this.strategy.write(node.id, node);
2510
+ this.nodes.delete(node.id);
2283
2511
  }
2284
2512
  this._nodeUpdateBuffer.clear();
2285
2513
  }
2286
2514
  async commitNodeDeleteBuffer() {
2287
2515
  for (const node of this._nodeDeleteBuffer.values()) {
2288
2516
  await this.strategy.delete(node.id);
2517
+ this.nodes.delete(node.id);
2289
2518
  }
2290
2519
  this._nodeDeleteBuffer.clear();
2291
2520
  }
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
2521
  async get(key) {
2300
- return this.readLock(async () => {
2522
+ return await this.readLock(async () => {
2301
2523
  let node = await this.leftestNode();
2302
2524
  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
- }
2525
+ for (let i = 0, len = node.values.length; i < len; i++) {
2526
+ const keys = node.keys[i];
2527
+ for (let j = 0, kLen = keys.length; j < kLen; j++) {
2528
+ if (keys[j] === key) {
2529
+ return node.values[i];
2311
2530
  }
2312
2531
  }
2313
2532
  }
@@ -2376,179 +2595,85 @@ var BPTreeAsync = class extends BPTree {
2376
2595
  yield pair;
2377
2596
  count++;
2378
2597
  if (limit !== void 0 && count >= limit) {
2379
- break;
2380
- }
2381
- }
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 = {};
2598
+ break;
2599
+ }
2600
+ }
2601
+ }
2528
2602
  }
2529
- id(isLeaf) {
2530
- return this.autoIncrement("index", 1).toString();
2603
+ async keys(condition, filterValues) {
2604
+ const set = /* @__PURE__ */ new Set();
2605
+ for await (const key of this.keysStream(condition, filterValues)) {
2606
+ set.add(key);
2607
+ }
2608
+ return set;
2531
2609
  }
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.`);
2610
+ async where(condition) {
2611
+ const map = /* @__PURE__ */ new Map();
2612
+ for await (const [key, value] of this.whereStream(condition)) {
2613
+ map.set(key, value);
2535
2614
  }
2536
- return this.node[id];
2615
+ return map;
2537
2616
  }
2538
- write(id, node) {
2539
- this.node[id] = node;
2617
+ async insert(key, value) {
2618
+ await this.writeLock(async () => {
2619
+ const before = await this.insertableNode(value);
2620
+ await this._insertAtLeaf(before, key, value);
2621
+ if (before.values.length === this.order) {
2622
+ const after = await this._createNode(
2623
+ true,
2624
+ [],
2625
+ [],
2626
+ true,
2627
+ before.parent,
2628
+ null,
2629
+ null
2630
+ );
2631
+ const mid = Math.ceil(this.order / 2) - 1;
2632
+ after.values = before.values.slice(mid + 1);
2633
+ after.keys = before.keys.slice(mid + 1);
2634
+ before.values = before.values.slice(0, mid + 1);
2635
+ before.keys = before.keys.slice(0, mid + 1);
2636
+ await this._insertInParent(before, after.values[0], after);
2637
+ await this.bufferForNodeUpdate(before);
2638
+ }
2639
+ await this.commitHeadBuffer();
2640
+ await this.commitNodeCreateBuffer();
2641
+ await this.commitNodeUpdateBuffer();
2642
+ });
2540
2643
  }
2541
- delete(id) {
2542
- delete this.node[id];
2644
+ async delete(key, value) {
2645
+ await this.writeLock(async () => {
2646
+ const node = await this.insertableNode(value);
2647
+ let i = node.values.length;
2648
+ while (i--) {
2649
+ const nValue = node.values[i];
2650
+ if (this.comparator.isSame(value, nValue)) {
2651
+ const keys = node.keys[i];
2652
+ const keyIndex = keys.indexOf(key);
2653
+ if (keyIndex !== -1) {
2654
+ keys.splice(keyIndex, 1);
2655
+ if (keys.length === 0) {
2656
+ node.keys.splice(i, 1);
2657
+ node.values.splice(i, 1);
2658
+ }
2659
+ await this._deleteEntry(node, key, value);
2660
+ await this.bufferForNodeUpdate(node);
2661
+ break;
2662
+ }
2663
+ }
2664
+ }
2665
+ await this.commitHeadBuffer();
2666
+ await this.commitNodeCreateBuffer();
2667
+ await this.commitNodeUpdateBuffer();
2668
+ await this.commitNodeDeleteBuffer();
2669
+ });
2543
2670
  }
2544
- readHead() {
2545
- if (this.head.root === null) {
2546
- return null;
2547
- }
2548
- return this.head;
2671
+ getHeadData() {
2672
+ return this.strategy.head.data;
2549
2673
  }
2550
- writeHead(head) {
2551
- this.head = head;
2674
+ async setHeadData(data) {
2675
+ this.strategy.head.data = data;
2676
+ await this.strategy.writeHead(this.strategy.head);
2552
2677
  }
2553
2678
  };
2554
2679
  var SerializeStrategyAsync = class extends SerializeStrategy {
@@ -2568,6 +2693,14 @@ var SerializeStrategyAsync = class extends SerializeStrategy {
2568
2693
  await this.setHeadData(key, next);
2569
2694
  return current;
2570
2695
  }
2696
+ async compareAndSwapHead(oldRoot, newRoot) {
2697
+ if (this.head.root !== oldRoot) {
2698
+ return false;
2699
+ }
2700
+ this.head.root = newRoot;
2701
+ await this.writeHead(this.head);
2702
+ return true;
2703
+ }
2571
2704
  };
2572
2705
  var InMemoryStoreStrategyAsync = class extends SerializeStrategyAsync {
2573
2706
  node;
@@ -2582,7 +2715,8 @@ var InMemoryStoreStrategyAsync = class extends SerializeStrategyAsync {
2582
2715
  if (!Object.hasOwn(this.node, id)) {
2583
2716
  throw new Error(`The tree attempted to reference node '${id}', but couldn't find the corresponding node.`);
2584
2717
  }
2585
- return this.node[id];
2718
+ const node = this.node[id];
2719
+ return JSON.parse(JSON.stringify(node));
2586
2720
  }
2587
2721
  async write(id, node) {
2588
2722
  this.node[id] = node;
@@ -2600,9 +2734,332 @@ var InMemoryStoreStrategyAsync = class extends SerializeStrategyAsync {
2600
2734
  this.head = head;
2601
2735
  }
2602
2736
  };
2737
+ var BPTreeAsyncSnapshotStrategy = class extends SerializeStrategyAsync {
2738
+ baseStrategy;
2739
+ snapshotHead;
2740
+ constructor(baseStrategy, root) {
2741
+ super(baseStrategy.order);
2742
+ this.baseStrategy = baseStrategy;
2743
+ this.snapshotHead = {
2744
+ ...baseStrategy.head,
2745
+ root,
2746
+ data: { ...baseStrategy.head.data }
2747
+ };
2748
+ this.head = this.snapshotHead;
2749
+ }
2750
+ async id(isLeaf) {
2751
+ return await this.baseStrategy.id(isLeaf);
2752
+ }
2753
+ async read(id) {
2754
+ return await this.baseStrategy.read(id);
2755
+ }
2756
+ async write(id, node) {
2757
+ await this.baseStrategy.write(id, node);
2758
+ }
2759
+ async delete(id) {
2760
+ await this.baseStrategy.delete(id);
2761
+ }
2762
+ async readHead() {
2763
+ return this.snapshotHead;
2764
+ }
2765
+ async writeHead(head) {
2766
+ this.snapshotHead.root = head.root;
2767
+ this.snapshotHead.data = { ...head.data };
2768
+ }
2769
+ async compareAndSwapHead(oldRoot, newRoot) {
2770
+ return await this.baseStrategy.compareAndSwapHead(oldRoot, newRoot);
2771
+ }
2772
+ async getHeadData(key, defaultValue) {
2773
+ return this.snapshotHead.data[key] ?? defaultValue;
2774
+ }
2775
+ async setHeadData(key, data) {
2776
+ this.snapshotHead.data[key] = data;
2777
+ }
2778
+ async autoIncrement(key, defaultValue) {
2779
+ return this.snapshotHead.data[key] ?? defaultValue;
2780
+ }
2781
+ };
2782
+ var BPTreeAsyncTransaction = class extends BPTreeAsyncBase {
2783
+ realBaseTree;
2784
+ realBaseStrategy;
2785
+ txNodes = /* @__PURE__ */ new Map();
2786
+ dirtyIds;
2787
+ createdInTx;
2788
+ deletedIds;
2789
+ initialRootId;
2790
+ transactionRootId;
2791
+ constructor(baseTree) {
2792
+ super(baseTree.strategy, baseTree.comparator, baseTree.option);
2793
+ this.realBaseTree = baseTree;
2794
+ this.realBaseStrategy = baseTree.strategy;
2795
+ this.order = baseTree.getOrder();
2796
+ this.initialRootId = "";
2797
+ this.transactionRootId = "";
2798
+ this.dirtyIds = /* @__PURE__ */ new Set();
2799
+ this.createdInTx = /* @__PURE__ */ new Set();
2800
+ this.deletedIds = /* @__PURE__ */ new Set();
2801
+ }
2802
+ /**
2803
+ * Initializes the transaction by capturing the current state of the tree.
2804
+ */
2805
+ async initTransaction() {
2806
+ const head = await this.realBaseStrategy.readHead();
2807
+ if (head) {
2808
+ this.order = head.order;
2809
+ this.initialRootId = head.root;
2810
+ } else {
2811
+ this.initialRootId = this.realBaseTree.getRootId();
2812
+ }
2813
+ if (!this.initialRootId) {
2814
+ const root = await this._createNode(true, [], [], true);
2815
+ this.initialRootId = root.id;
2816
+ }
2817
+ this.transactionRootId = this.initialRootId;
2818
+ this.rootId = this.transactionRootId;
2819
+ const snapshotStrategy = new BPTreeAsyncSnapshotStrategy(this.realBaseStrategy, this.initialRootId);
2820
+ this.strategy = snapshotStrategy;
2821
+ this.txNodes.clear();
2822
+ this.dirtyIds.clear();
2823
+ this.createdInTx.clear();
2824
+ this.deletedIds.clear();
2825
+ }
2826
+ async getNode(id) {
2827
+ if (this.txNodes.has(id)) {
2828
+ return this.txNodes.get(id);
2829
+ }
2830
+ if (this.deletedIds.has(id)) {
2831
+ throw new Error(`The tree attempted to reference deleted node '${id}'`);
2832
+ }
2833
+ const baseNode = await this.realBaseStrategy.read(id);
2834
+ const clone = JSON.parse(JSON.stringify(baseNode));
2835
+ this.txNodes.set(id, clone);
2836
+ return clone;
2837
+ }
2838
+ async bufferForNodeUpdate(node) {
2839
+ if (this.dirtyIds.has(node.id) && this.txNodes.has(node.id) && node._p) {
2840
+ this.txNodes.set(node.id, node);
2841
+ return;
2842
+ }
2843
+ node._p = true;
2844
+ this.txNodes.set(node.id, node);
2845
+ this.dirtyIds.add(node.id);
2846
+ if (node.leaf) {
2847
+ if (node.next && !this.dirtyIds.has(node.next) && !this.deletedIds.has(node.next)) {
2848
+ try {
2849
+ await this.bufferForNodeUpdate(await this.getNode(node.next));
2850
+ } catch (e) {
2851
+ }
2852
+ }
2853
+ if (node.prev && !this.dirtyIds.has(node.prev) && !this.deletedIds.has(node.prev)) {
2854
+ try {
2855
+ await this.bufferForNodeUpdate(await this.getNode(node.prev));
2856
+ } catch (e) {
2857
+ }
2858
+ }
2859
+ }
2860
+ await this.markPathDirty(node);
2861
+ delete node._p;
2862
+ }
2863
+ async bufferForNodeCreate(node) {
2864
+ this.txNodes.set(node.id, node);
2865
+ this.dirtyIds.add(node.id);
2866
+ this.createdInTx.add(node.id);
2867
+ if (node.leaf) {
2868
+ if (node.next && !this.dirtyIds.has(node.next) && !this.deletedIds.has(node.next)) {
2869
+ try {
2870
+ await this.bufferForNodeUpdate(await this.getNode(node.next));
2871
+ } catch (e) {
2872
+ }
2873
+ }
2874
+ if (node.prev && !this.dirtyIds.has(node.prev) && !this.deletedIds.has(node.prev)) {
2875
+ try {
2876
+ await this.bufferForNodeUpdate(await this.getNode(node.prev));
2877
+ } catch (e) {
2878
+ }
2879
+ }
2880
+ }
2881
+ await this.markPathDirty(node);
2882
+ }
2883
+ async bufferForNodeDelete(node) {
2884
+ this.txNodes.delete(node.id);
2885
+ this.dirtyIds.add(node.id);
2886
+ this.deletedIds.add(node.id);
2887
+ }
2888
+ async markPathDirty(node) {
2889
+ let curr = node;
2890
+ while (curr.parent) {
2891
+ if (this.deletedIds.has(curr.parent)) {
2892
+ break;
2893
+ }
2894
+ if (this.dirtyIds.has(curr.parent) && this.txNodes.has(curr.parent)) {
2895
+ break;
2896
+ }
2897
+ const parent = await this.getNode(curr.parent);
2898
+ this.dirtyIds.add(parent.id);
2899
+ curr = parent;
2900
+ }
2901
+ if (!curr.parent) {
2902
+ this.transactionRootId = curr.id;
2903
+ }
2904
+ }
2905
+ async _createNode(isLeaf, keys, values, leaf = isLeaf, parent = null, next = null, prev = null) {
2906
+ const id = await this.strategy.id(isLeaf);
2907
+ const node = {
2908
+ id,
2909
+ keys,
2910
+ values,
2911
+ leaf,
2912
+ parent,
2913
+ next,
2914
+ prev
2915
+ };
2916
+ await this.bufferForNodeCreate(node);
2917
+ return node;
2918
+ }
2919
+ /**
2920
+ * Attempts to commit the transaction.
2921
+ * Uses Optimistic Locking (Compare-And-Swap) on the root node ID to detect conflicts.
2922
+ *
2923
+ * @returns A promise that resolves to the transaction result.
2924
+ */
2925
+ async commit() {
2926
+ const idMapping = /* @__PURE__ */ new Map();
2927
+ const finalNodes = [];
2928
+ for (const oldId of this.dirtyIds) {
2929
+ if (this.createdInTx.has(oldId)) {
2930
+ idMapping.set(oldId, oldId);
2931
+ } else {
2932
+ const node = this.txNodes.get(oldId);
2933
+ if (node) {
2934
+ const newId = await this.realBaseStrategy.id(node.leaf);
2935
+ idMapping.set(oldId, newId);
2936
+ }
2937
+ }
2938
+ }
2939
+ const newCreatedIds = [];
2940
+ for (const oldId of this.dirtyIds) {
2941
+ const node = this.txNodes.get(oldId);
2942
+ if (!node) continue;
2943
+ const newId = idMapping.get(oldId);
2944
+ node.id = newId;
2945
+ if (node.parent && idMapping.has(node.parent)) {
2946
+ node.parent = idMapping.get(node.parent);
2947
+ }
2948
+ if (!node.leaf) {
2949
+ const internal = node;
2950
+ for (let i = 0; i < internal.keys.length; i++) {
2951
+ const childId = internal.keys[i];
2952
+ if (idMapping.has(childId)) {
2953
+ internal.keys[i] = idMapping.get(childId);
2954
+ }
2955
+ }
2956
+ }
2957
+ if (node.leaf) {
2958
+ const leaf = node;
2959
+ if (leaf.next && idMapping.has(leaf.next)) {
2960
+ leaf.next = idMapping.get(leaf.next);
2961
+ }
2962
+ if (leaf.prev && idMapping.has(leaf.prev)) {
2963
+ leaf.prev = idMapping.get(leaf.prev);
2964
+ }
2965
+ }
2966
+ finalNodes.push(node);
2967
+ newCreatedIds.push(newId);
2968
+ }
2969
+ let newRootId = this.rootId;
2970
+ if (idMapping.has(this.rootId)) {
2971
+ newRootId = idMapping.get(this.rootId);
2972
+ }
2973
+ for (const node of finalNodes) {
2974
+ await this.realBaseStrategy.write(node.id, node);
2975
+ }
2976
+ const success = await this.realBaseStrategy.compareAndSwapHead(this.initialRootId, newRootId);
2977
+ if (success) {
2978
+ const distinctObsolete = /* @__PURE__ */ new Set();
2979
+ for (const oldId of this.dirtyIds) {
2980
+ if (!this.createdInTx.has(oldId) && this.txNodes.has(oldId)) {
2981
+ distinctObsolete.add(oldId);
2982
+ }
2983
+ }
2984
+ return {
2985
+ success: true,
2986
+ createdIds: newCreatedIds,
2987
+ obsoleteIds: Array.from(distinctObsolete)
2988
+ };
2989
+ } else {
2990
+ await this.rollback();
2991
+ return {
2992
+ success: false,
2993
+ createdIds: newCreatedIds,
2994
+ obsoleteIds: []
2995
+ };
2996
+ }
2997
+ }
2998
+ /**
2999
+ * Rolls back the transaction by clearing all buffered changes.
3000
+ * Internal use only.
3001
+ */
3002
+ async rollback() {
3003
+ this.txNodes.clear();
3004
+ this.dirtyIds.clear();
3005
+ this.createdInTx.clear();
3006
+ }
3007
+ async readLock(fn) {
3008
+ return await fn();
3009
+ }
3010
+ async writeLock(fn) {
3011
+ return await fn();
3012
+ }
3013
+ async commitHeadBuffer() {
3014
+ }
3015
+ async commitNodeCreateBuffer() {
3016
+ }
3017
+ async commitNodeUpdateBuffer() {
3018
+ }
3019
+ async commitNodeDeleteBuffer() {
3020
+ }
3021
+ };
3022
+ var BPTreeAsync = class extends BPTreeAsyncBase {
3023
+ constructor(strategy, comparator, option) {
3024
+ super(strategy, comparator, option);
3025
+ }
3026
+ /**
3027
+ * Creates a new asynchronous transaction.
3028
+ * @returns A promise that resolves to a new BPTreeAsyncTransaction.
3029
+ */
3030
+ async createTransaction() {
3031
+ const tx = new BPTreeAsyncTransaction(this);
3032
+ await tx.initTransaction();
3033
+ return tx;
3034
+ }
3035
+ async insert(key, value) {
3036
+ const tx = await this.createTransaction();
3037
+ await tx.insert(key, value);
3038
+ const { success } = await tx.commit();
3039
+ await this.init();
3040
+ if (!success) {
3041
+ throw new Error("Transaction failed: Commit failed due to conflict");
3042
+ }
3043
+ }
3044
+ async delete(key, value) {
3045
+ const tx = await this.createTransaction();
3046
+ await tx.delete(key, value);
3047
+ const { success } = await tx.commit();
3048
+ await this.init();
3049
+ if (!success) {
3050
+ throw new Error("Transaction failed: Commit failed due to conflict");
3051
+ }
3052
+ }
3053
+ async readLock(fn) {
3054
+ return await fn();
3055
+ }
3056
+ async writeLock(fn) {
3057
+ return await fn();
3058
+ }
3059
+ };
2603
3060
 
2604
3061
  // node_modules/ryoiki/dist/esm/index.mjs
2605
- var Ryoiki2 = class _Ryoiki2 {
3062
+ var Ryoiki = class _Ryoiki {
2606
3063
  readings;
2607
3064
  writings;
2608
3065
  readQueue;
@@ -2646,7 +3103,7 @@ var Ryoiki2 = class _Ryoiki2 {
2646
3103
  return [start, start + length];
2647
3104
  }
2648
3105
  rangeOverlapping(tasks, range) {
2649
- return Array.from(tasks.values()).some((t) => _Ryoiki2.IsRangeOverlap(t.range, range));
3106
+ return Array.from(tasks.values()).some((t) => _Ryoiki.IsRangeOverlap(t.range, range));
2650
3107
  }
2651
3108
  isSameRange(a, b) {
2652
3109
  const [a1, a2] = a;
@@ -2687,7 +3144,7 @@ var Ryoiki2 = class _Ryoiki2 {
2687
3144
  _alloc(queue, workspaces, lockId) {
2688
3145
  const unit = queue.get(lockId);
2689
3146
  if (!unit) {
2690
- throw _Ryoiki2.ERR_NOT_EXISTS(lockId);
3147
+ throw _Ryoiki.ERR_NOT_EXISTS(lockId);
2691
3148
  }
2692
3149
  workspaces.set(lockId, unit);
2693
3150
  queue.delete(lockId);
@@ -2696,7 +3153,7 @@ var Ryoiki2 = class _Ryoiki2 {
2696
3153
  _free(workspaces, lockId) {
2697
3154
  const unit = workspaces.get(lockId);
2698
3155
  if (!unit) {
2699
- throw _Ryoiki2.ERR_NOT_EXISTS(lockId);
3156
+ throw _Ryoiki.ERR_NOT_EXISTS(lockId);
2700
3157
  }
2701
3158
  workspaces.delete(lockId);
2702
3159
  unit.free();
@@ -2706,7 +3163,7 @@ var Ryoiki2 = class _Ryoiki2 {
2706
3163
  let timeoutId = null;
2707
3164
  if (timeout >= 0) {
2708
3165
  timeoutId = setTimeout(() => {
2709
- reject(_Ryoiki2.ERR_TIMEOUT(id, timeout));
3166
+ reject(_Ryoiki.ERR_TIMEOUT(id, timeout));
2710
3167
  }, timeout);
2711
3168
  }
2712
3169
  const id = this._createRandomId();
@@ -2714,7 +3171,7 @@ var Ryoiki2 = class _Ryoiki2 {
2714
3171
  if (timeoutId !== null) {
2715
3172
  clearTimeout(timeoutId);
2716
3173
  }
2717
- const [err, v] = await _Ryoiki2.CatchError(task(id));
3174
+ const [err, v] = await _Ryoiki.CatchError(task(id));
2718
3175
  if (err) reject(err);
2719
3176
  else resolve(v);
2720
3177
  };
@@ -2729,7 +3186,7 @@ var Ryoiki2 = class _Ryoiki2 {
2729
3186
  _checkWorking(range, workspaces) {
2730
3187
  let isLocked = false;
2731
3188
  for (const lock of workspaces.values()) {
2732
- if (_Ryoiki2.IsRangeOverlap(range, lock.range)) {
3189
+ if (_Ryoiki.IsRangeOverlap(range, lock.range)) {
2733
3190
  isLocked = true;
2734
3191
  break;
2735
3192
  }
@@ -5840,8 +6297,11 @@ var RowIdentifierStrategy = class extends SerializeStrategyAsync {
5840
6297
  if (node.leaf) {
5841
6298
  const n = node;
5842
6299
  const keys = new Array(n.keys.length);
5843
- for (let i = 0, len = keys.length; i < len; i++) {
6300
+ let i = 0;
6301
+ const len = keys.length;
6302
+ while (i < len) {
5844
6303
  keys[i] = +n.keys[i][0];
6304
+ i++;
5845
6305
  }
5846
6306
  this.indexPageManger.setIndexId(page, +n.id);
5847
6307
  this.indexPageManger.setParentIndexId(page, +n.parent);
@@ -5854,8 +6314,11 @@ var RowIdentifierStrategy = class extends SerializeStrategyAsync {
5854
6314
  } else {
5855
6315
  const n = node;
5856
6316
  const keys = new Array(n.keys.length);
5857
- for (let i = 0, len = keys.length; i < len; i++) {
6317
+ let i = 0;
6318
+ const len = keys.length;
6319
+ while (i < len) {
5858
6320
  keys[i] = +n.keys[i];
6321
+ i++;
5859
6322
  }
5860
6323
  this.indexPageManger.setIndexId(page, +n.id);
5861
6324
  this.indexPageManger.setParentIndexId(page, +n.parent);
@@ -5890,9 +6353,11 @@ var RowIdentifierStrategy = class extends SerializeStrategyAsync {
5890
6353
  if (rootIndexPageId === -1) {
5891
6354
  return null;
5892
6355
  }
6356
+ const metaOrder = manager.getRootIndexOrder(metadataPage);
6357
+ const order = metaOrder || this.order;
5893
6358
  return {
5894
- root: manager.getRootIndexPageId(metadataPage).toString(),
5895
- order: manager.getRootIndexOrder(metadataPage),
6359
+ root: rootIndexPageId.toString(),
6360
+ order,
5896
6361
  data: {}
5897
6362
  };
5898
6363
  }
@@ -5979,8 +6444,9 @@ var RowTableEngine = class {
5979
6444
  this.pageIdBuffer = new Uint8Array(DataPageManager.CONSTANT.SIZE_PAGE_ID);
5980
6445
  this.maxBodySize = this.pfs.pageSize - DataPageManager.CONSTANT.SIZE_PAGE_HEADER;
5981
6446
  this.order = this.getOptimalOrder(pfs.pageSize, IndexPageManager.CONSTANT.SIZE_KEY, IndexPageManager.CONSTANT.SIZE_VALUE);
6447
+ this.strategy = new RowIdentifierStrategy(this.order, pfs, txContext);
5982
6448
  this.bptree = new BPTreeAsync(
5983
- new RowIdentifierStrategy(this.order, pfs, txContext),
6449
+ this.strategy,
5984
6450
  new NumericComparator(),
5985
6451
  {
5986
6452
  capacity: this.options.pageCacheCapacity
@@ -5988,6 +6454,7 @@ var RowTableEngine = class {
5988
6454
  );
5989
6455
  }
5990
6456
  bptree;
6457
+ strategy;
5991
6458
  order;
5992
6459
  factory;
5993
6460
  metadataPageManager;
@@ -5999,6 +6466,35 @@ var RowTableEngine = class {
5999
6466
  ridBuffer;
6000
6467
  pageIdBuffer;
6001
6468
  initialized = false;
6469
+ /**
6470
+ * Retrieves the BPTree transaction associated with the given transaction.
6471
+ * If it doesn't exist, it creates a new one and registers commit/rollback hooks.
6472
+ * @param tx Dataply transaction
6473
+ * @returns BPTree transaction
6474
+ */
6475
+ async getBPTreeTransaction(tx) {
6476
+ let btx = tx.__getBPTreeTransaction();
6477
+ if (!btx) {
6478
+ btx = await this.bptree.createTransaction();
6479
+ tx.__setBPTreeTransaction(btx);
6480
+ tx.onCommit(async () => {
6481
+ if (!tx.__isBPTreeDirty()) {
6482
+ return;
6483
+ }
6484
+ if (!btx) return;
6485
+ const result = await btx.commit();
6486
+ if (result.success) {
6487
+ await this.bptree.init();
6488
+ for (const id of result.obsoleteIds) {
6489
+ await this.strategy.delete(id);
6490
+ }
6491
+ } else {
6492
+ throw new Error(`BPTree transaction commit failed. Current Root: ${this.bptree.getRootId()}`);
6493
+ }
6494
+ });
6495
+ }
6496
+ return btx;
6497
+ }
6002
6498
  /**
6003
6499
  * Initializes the B+ Tree.
6004
6500
  */
@@ -6128,7 +6624,9 @@ var RowTableEngine = class {
6128
6624
  this.metadataPageManager.setRowCount(freshMetadataPage, currentRowCount + 1);
6129
6625
  }
6130
6626
  await this.pfs.setMetadata(freshMetadataPage, tx);
6131
- await this.bptree.insert(this.getRID(), pk);
6627
+ const btx = await this.getBPTreeTransaction(tx);
6628
+ await btx.insert(this.getRID(), pk);
6629
+ tx.__markBPTreeDirty();
6132
6630
  return pk;
6133
6631
  }
6134
6632
  /**
@@ -6139,11 +6637,8 @@ var RowTableEngine = class {
6139
6637
  * @returns RID or null (if not found)
6140
6638
  */
6141
6639
  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 });
6640
+ const btx = await this.getBPTreeTransaction(tx);
6641
+ const keys = await btx.keys({ equal: pk });
6147
6642
  if (keys.size === 0) {
6148
6643
  return null;
6149
6644
  }
@@ -6162,6 +6657,7 @@ var RowTableEngine = class {
6162
6657
  * @param tx Transaction
6163
6658
  */
6164
6659
  async update(pk, data, tx) {
6660
+ await tx.__acquireWriteLock(0);
6165
6661
  const rid = await this.getRidByPK(pk, tx);
6166
6662
  if (rid === null) {
6167
6663
  return;
@@ -6231,16 +6727,10 @@ var RowTableEngine = class {
6231
6727
  const oldRidNumeric = this.getRID();
6232
6728
  this.setRID(lastInsertDataPageId, newSlotIndex);
6233
6729
  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);
6730
+ const btx = await this.getBPTreeTransaction(tx);
6731
+ await btx.delete(oldRidNumeric, pk);
6732
+ await btx.insert(newRidNumeric, pk);
6733
+ tx.__markBPTreeDirty();
6244
6734
  const freshMetadataPage = await this.pfs.getMetadata(tx);
6245
6735
  this.metadataPageManager.setLastInsertPageId(freshMetadataPage, lastInsertDataPageId);
6246
6736
  await this.pfs.setMetadata(freshMetadataPage, tx);
@@ -6280,6 +6770,9 @@ var RowTableEngine = class {
6280
6770
  }
6281
6771
  this.rowManager.setDeletedFlag(row, true);
6282
6772
  await this.pfs.setPage(pageId, page, tx);
6773
+ const btx = await this.getBPTreeTransaction(tx);
6774
+ await btx.delete(rid, pk);
6775
+ tx.__markBPTreeDirty();
6283
6776
  if (decrementRowCount) {
6284
6777
  const metadataPage2 = await this.pfs.getMetadata(tx);
6285
6778
  const currentRowCount = this.metadataPageManager.getRowCount(metadataPage2);
@@ -6293,12 +6786,14 @@ var RowTableEngine = class {
6293
6786
  if (pageId === lastInsertPageId) {
6294
6787
  allDeleted = false;
6295
6788
  } else {
6296
- for (let i = 0; i < insertedRowCount; i++) {
6789
+ let i = 0;
6790
+ while (i < insertedRowCount) {
6297
6791
  const slotRow = this.dataPageManager.getRow(page, i);
6298
6792
  if (!this.rowManager.getDeletedFlag(slotRow)) {
6299
6793
  allDeleted = false;
6300
6794
  break;
6301
6795
  }
6796
+ i++;
6302
6797
  }
6303
6798
  }
6304
6799
  if (allDeleted) {
@@ -6361,7 +6856,7 @@ var LockManager = class {
6361
6856
  lock;
6362
6857
  unlockMap = /* @__PURE__ */ new Map();
6363
6858
  constructor() {
6364
- this.lock = new Ryoiki2();
6859
+ this.lock = new Ryoiki();
6365
6860
  }
6366
6861
  /**
6367
6862
  * Requests a read (Shared) lock for a page.
@@ -6424,12 +6919,41 @@ var Transaction = class {
6424
6919
  pageLocks = /* @__PURE__ */ new Map();
6425
6920
  /** Undo Logs: PageID -> Original Page Buffer (Snapshot) */
6426
6921
  undoPages = /* @__PURE__ */ new Map();
6427
- /** List of Dirty Pages modified by the transaction */
6922
+ /** Dirty Pages modified by the transaction */
6428
6923
  dirtyPages = /* @__PURE__ */ new Set();
6429
- /** Pending Index Updates: PK -> { newRid, oldRid } */
6430
- pendingIndexUpdates = /* @__PURE__ */ new Map();
6924
+ /** BPTree Transaction instance */
6925
+ bptreeTx;
6926
+ /** Whether the BPTree transaction is dirty */
6927
+ bptreeDirty = false;
6431
6928
  /** List of callbacks to execute on commit */
6432
6929
  commitHooks = [];
6930
+ /**
6931
+ * Sets the BPTree transaction.
6932
+ * @param tx BPTree transaction
6933
+ */
6934
+ __setBPTreeTransaction(tx) {
6935
+ this.bptreeTx = tx;
6936
+ }
6937
+ /**
6938
+ * Returns the BPTree transaction.
6939
+ * @returns BPTree transaction
6940
+ */
6941
+ __getBPTreeTransaction() {
6942
+ return this.bptreeTx;
6943
+ }
6944
+ /**
6945
+ * Marks the BPTree transaction as dirty.
6946
+ */
6947
+ __markBPTreeDirty() {
6948
+ this.bptreeDirty = true;
6949
+ }
6950
+ /**
6951
+ * Returns whether the BPTree transaction is dirty.
6952
+ * @returns True if dirty
6953
+ */
6954
+ __isBPTreeDirty() {
6955
+ return this.bptreeDirty;
6956
+ }
6433
6957
  /**
6434
6958
  * Registers a commit hook.
6435
6959
  * @param hook Function to execute
@@ -6465,32 +6989,6 @@ var Transaction = class {
6465
6989
  __hasUndoPage(pageId) {
6466
6990
  return this.undoPages.has(pageId);
6467
6991
  }
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
6992
  /**
6495
6993
  * Acquires a write lock.
6496
6994
  * Does not call this method directly. It is called by the `VirtualFileSystem` instance.
@@ -6518,13 +7016,13 @@ var Transaction = class {
6518
7016
  * Commits the transaction.
6519
7017
  */
6520
7018
  async commit() {
6521
- await this.vfs.prepareCommit(this);
6522
- await this.vfs.finalizeCommit(this);
6523
7019
  await this.context.run(this, async () => {
6524
7020
  for (const hook of this.commitHooks) {
6525
7021
  await hook();
6526
7022
  }
6527
7023
  });
7024
+ await this.vfs.prepareCommit(this);
7025
+ await this.vfs.finalizeCommit(this);
6528
7026
  this.releaseAllLocks();
6529
7027
  }
6530
7028
  /**
@@ -6669,6 +7167,8 @@ var DataplyAPI = class {
6669
7167
  metadataPageManager.setMagicString(metadataPage);
6670
7168
  metadataPageManager.setPageSize(metadataPage, options.pageSize);
6671
7169
  metadataPageManager.setRootIndexPageId(metadataPage, -1);
7170
+ const order = Math.floor((options.pageSize - IndexPageManager.CONSTANT.OFFSET_KEYS_AND_VALUES + IndexPageManager.CONSTANT.SIZE_KEY) / (IndexPageManager.CONSTANT.SIZE_KEY + IndexPageManager.CONSTANT.SIZE_VALUE));
7171
+ metadataPageManager.setRootIndexOrder(metadataPage, order);
6672
7172
  metadataPageManager.setBitmapPageId(metadataPage, 1);
6673
7173
  metadataPageManager.setLastInsertPageId(metadataPage, 2);
6674
7174
  metadataPageManager.setPageCount(metadataPage, 3);
@@ -7047,7 +7547,9 @@ var GlobalTransaction = class {
7047
7547
  // Annotate the CommonJS export names for ESM import in node:
7048
7548
  0 && (module.exports = {
7049
7549
  BPTreeAsync,
7550
+ BPTreeAsyncTransaction,
7050
7551
  BPTreeSync,
7552
+ BPTreeSyncTransaction,
7051
7553
  BitmapPageManager,
7052
7554
  CacheEntanglementAsync,
7053
7555
  CacheEntanglementSync,