serializable-bptree 7.0.0 → 7.0.2

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.
@@ -475,6 +475,20 @@ var BPTree = class _BPTree {
475
475
  option;
476
476
  order;
477
477
  rootId;
478
+ /**
479
+ * Returns the ID of the root node.
480
+ * @returns The root node ID.
481
+ */
482
+ getRootId() {
483
+ return this.rootId;
484
+ }
485
+ /**
486
+ * Returns the order of the B+Tree.
487
+ * @returns The order of the tree.
488
+ */
489
+ getOrder() {
490
+ return this.order;
491
+ }
478
492
  _strategyDirty;
479
493
  _nodeCreateBuffer;
480
494
  _nodeUpdateBuffer;
@@ -707,24 +721,21 @@ var BPTree = class _BPTree {
707
721
  break;
708
722
  }
709
723
  keys.push(key);
710
- this.bufferForNodeUpdate(node);
711
- break;
724
+ return this.bufferForNodeUpdate(node);
712
725
  } else if (this.comparator.isLower(value, nValue)) {
713
726
  node.values.splice(i, 0, value);
714
727
  node.keys.splice(i, 0, [key]);
715
- this.bufferForNodeUpdate(node);
716
- break;
728
+ return this.bufferForNodeUpdate(node);
717
729
  } else if (i + 1 === node.values.length) {
718
730
  node.values.push(value);
719
731
  node.keys.push([key]);
720
- this.bufferForNodeUpdate(node);
721
- break;
732
+ return this.bufferForNodeUpdate(node);
722
733
  }
723
734
  }
724
735
  } else {
725
736
  node.values = [value];
726
737
  node.keys = [[key]];
727
- this.bufferForNodeUpdate(node);
738
+ return this.bufferForNodeUpdate(node);
728
739
  }
729
740
  }
730
741
  bufferForNodeCreate(node) {
@@ -840,7 +851,7 @@ var BPTreeSyncBase = class extends BPTree {
840
851
  }
841
852
  return id;
842
853
  }
843
- _createNode(isLeaf, keys, values, leaf = false, parent = null, next = null, prev = null) {
854
+ _createNode(isLeaf, keys, values, leaf = isLeaf, parent = null, next = null, prev = null) {
844
855
  const id = this._createNodeId(isLeaf);
845
856
  const node = {
846
857
  id,
@@ -851,26 +862,23 @@ var BPTreeSyncBase = class extends BPTree {
851
862
  next,
852
863
  prev
853
864
  };
854
- this._nodeCreateBuffer.set(id, node);
865
+ this.bufferForNodeCreate(node);
855
866
  return node;
856
867
  }
857
868
  _deleteEntry(node, key, value) {
858
869
  if (!node.leaf) {
870
+ let keyIndex = -1;
859
871
  for (let i = 0, len = node.keys.length; i < len; i++) {
860
- const nKey = node.keys[i];
861
- if (nKey === key) {
862
- node.keys.splice(i, 1);
863
- this.bufferForNodeUpdate(node);
872
+ if (node.keys[i] === key) {
873
+ keyIndex = i;
864
874
  break;
865
875
  }
866
876
  }
867
- for (let i = 0, len = node.values.length; i < len; i++) {
868
- const nValue = node.values[i];
869
- if (this.comparator.isSame(value, nValue)) {
870
- node.values.splice(i, 1);
871
- this.bufferForNodeUpdate(node);
872
- break;
873
- }
877
+ if (keyIndex !== -1) {
878
+ node.keys.splice(keyIndex, 1);
879
+ const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
880
+ node.values.splice(valueIndex, 1);
881
+ this.bufferForNodeUpdate(node);
874
882
  }
875
883
  }
876
884
  if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
@@ -970,13 +978,10 @@ var BPTreeSyncBase = class extends BPTree {
970
978
  node.keys = [pointerPm, ...node.keys];
971
979
  node.values = [guess, ...node.values];
972
980
  parentNode = this.getNode(node.parent);
973
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
974
- const nValue = parentNode.values[i];
975
- if (this.comparator.isSame(guess, nValue)) {
976
- parentNode.values[i] = pointerKm;
977
- this.bufferForNodeUpdate(parentNode);
978
- break;
979
- }
981
+ const nodeIndex = parentNode.keys.indexOf(node.id);
982
+ if (nodeIndex > 0) {
983
+ parentNode.values[nodeIndex - 1] = pointerKm;
984
+ this.bufferForNodeUpdate(parentNode);
980
985
  }
981
986
  } else {
982
987
  pointerPm = pointer.keys.splice(-1)[0];
@@ -984,13 +989,10 @@ var BPTreeSyncBase = class extends BPTree {
984
989
  node.keys = [pointerPm, ...node.keys];
985
990
  node.values = [pointerKm, ...node.values];
986
991
  parentNode = this.getNode(node.parent);
987
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
988
- const nValue = parentNode.values[i];
989
- if (this.comparator.isSame(guess, nValue)) {
990
- parentNode.values[i] = pointerKm;
991
- this.bufferForNodeUpdate(parentNode);
992
- break;
993
- }
992
+ const nodeIndex = parentNode.keys.indexOf(node.id);
993
+ if (nodeIndex > 0) {
994
+ parentNode.values[nodeIndex - 1] = pointerKm;
995
+ this.bufferForNodeUpdate(parentNode);
994
996
  }
995
997
  }
996
998
  this.bufferForNodeUpdate(node);
@@ -1004,13 +1006,10 @@ var BPTreeSyncBase = class extends BPTree {
1004
1006
  node.keys = [...node.keys, pointerP0];
1005
1007
  node.values = [...node.values, guess];
1006
1008
  parentNode = this.getNode(node.parent);
1007
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
1008
- const nValue = parentNode.values[i];
1009
- if (this.comparator.isSame(guess, nValue)) {
1010
- parentNode.values[i] = pointerK0;
1011
- this.bufferForNodeUpdate(parentNode);
1012
- break;
1013
- }
1009
+ const pointerIndex = parentNode.keys.indexOf(pointer.id);
1010
+ if (pointerIndex > 0) {
1011
+ parentNode.values[pointerIndex - 1] = pointerK0;
1012
+ this.bufferForNodeUpdate(parentNode);
1014
1013
  }
1015
1014
  } else {
1016
1015
  pointerP0 = pointer.keys.splice(0, 1)[0];
@@ -1018,13 +1017,10 @@ var BPTreeSyncBase = class extends BPTree {
1018
1017
  node.keys = [...node.keys, pointerP0];
1019
1018
  node.values = [...node.values, pointerK0];
1020
1019
  parentNode = this.getNode(node.parent);
1021
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
1022
- const nValue = parentNode.values[i];
1023
- if (this.comparator.isSame(guess, nValue)) {
1024
- parentNode.values[i] = pointer.values[0];
1025
- this.bufferForNodeUpdate(parentNode);
1026
- break;
1027
- }
1020
+ const pointerIndex = parentNode.keys.indexOf(pointer.id);
1021
+ if (pointerIndex > 0) {
1022
+ parentNode.values[pointerIndex - 1] = pointer.values[0];
1023
+ this.bufferForNodeUpdate(parentNode);
1028
1024
  }
1029
1025
  }
1030
1026
  this.bufferForNodeUpdate(node);
@@ -1052,6 +1048,8 @@ var BPTreeSyncBase = class extends BPTree {
1052
1048
  }
1053
1049
  }
1054
1050
  }
1051
+ } else {
1052
+ this.bufferForNodeUpdate(node);
1055
1053
  }
1056
1054
  }
1057
1055
  _insertInParent(node, value, pointer) {
@@ -1070,31 +1068,25 @@ var BPTreeSyncBase = class extends BPTree {
1070
1068
  return;
1071
1069
  }
1072
1070
  const parentNode = this.getNode(node.parent);
1073
- let insertIndex = 0;
1074
- for (let i = 0; i < parentNode.values.length; i++) {
1075
- if (this.comparator.asc(value, parentNode.values[i]) > 0) {
1076
- insertIndex = i + 1;
1077
- } else {
1078
- break;
1079
- }
1071
+ const nodeIndex = parentNode.keys.indexOf(node.id);
1072
+ if (nodeIndex === -1) {
1073
+ throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
1080
1074
  }
1075
+ const insertIndex = nodeIndex;
1081
1076
  parentNode.values.splice(insertIndex, 0, value);
1082
1077
  parentNode.keys.splice(insertIndex + 1, 0, pointer.id);
1083
1078
  pointer.parent = parentNode.id;
1084
1079
  if (pointer.leaf) {
1085
- const leftSiblingId = parentNode.keys[insertIndex];
1086
- const rightSiblingId = parentNode.keys[insertIndex + 2];
1087
- if (leftSiblingId) {
1088
- const leftSibling = this.getNode(leftSiblingId);
1089
- pointer.prev = leftSibling.id;
1090
- pointer.next = leftSibling.next;
1091
- leftSibling.next = pointer.id;
1092
- this.bufferForNodeUpdate(leftSibling);
1093
- }
1094
- if (rightSiblingId) {
1095
- const rightSibling = this.getNode(rightSiblingId);
1096
- rightSibling.prev = pointer.id;
1097
- this.bufferForNodeUpdate(rightSibling);
1080
+ const leftSibling = node;
1081
+ const oldNextId = leftSibling.next;
1082
+ pointer.prev = leftSibling.id;
1083
+ pointer.next = oldNextId;
1084
+ leftSibling.next = pointer.id;
1085
+ this.bufferForNodeUpdate(leftSibling);
1086
+ if (oldNextId) {
1087
+ const oldNext = this.getNode(oldNextId);
1088
+ oldNext.prev = pointer.id;
1089
+ this.bufferForNodeUpdate(oldNext);
1098
1090
  }
1099
1091
  }
1100
1092
  this.bufferForNodeUpdate(parentNode);
@@ -1123,6 +1115,7 @@ var BPTreeSyncBase = class extends BPTree {
1123
1115
  }
1124
1116
  }
1125
1117
  init() {
1118
+ this.clear();
1126
1119
  const head = this.strategy.readHead();
1127
1120
  if (head === null) {
1128
1121
  this.order = this.strategy.order;
@@ -1153,18 +1146,35 @@ var BPTreeSyncBase = class extends BPTree {
1153
1146
  }
1154
1147
  insertableNode(value) {
1155
1148
  let node = this.getNode(this.rootId);
1149
+ if (node.parent !== null) {
1150
+ node.parent = null;
1151
+ this.bufferForNodeUpdate(node);
1152
+ }
1156
1153
  while (!node.leaf) {
1154
+ const parentId = node.id;
1157
1155
  for (let i = 0, len = node.values.length; i < len; i++) {
1158
1156
  const nValue = node.values[i];
1159
1157
  const k = node.keys;
1160
1158
  if (this.comparator.isSame(value, nValue)) {
1161
1159
  node = this.getNode(k[i + 1]);
1160
+ if (node.parent !== parentId) {
1161
+ node.parent = parentId;
1162
+ this.bufferForNodeUpdate(node);
1163
+ }
1162
1164
  break;
1163
1165
  } else if (this.comparator.isLower(value, nValue)) {
1164
1166
  node = this.getNode(k[i]);
1167
+ if (node.parent !== parentId) {
1168
+ node.parent = parentId;
1169
+ this.bufferForNodeUpdate(node);
1170
+ }
1165
1171
  break;
1166
1172
  } else if (i + 1 === node.values.length) {
1167
1173
  node = this.getNode(k[i + 1]);
1174
+ if (node.parent !== parentId) {
1175
+ node.parent = parentId;
1176
+ this.bufferForNodeUpdate(node);
1177
+ }
1168
1178
  break;
1169
1179
  }
1170
1180
  }
@@ -1173,18 +1183,35 @@ var BPTreeSyncBase = class extends BPTree {
1173
1183
  }
1174
1184
  insertableNodeByPrimary(value) {
1175
1185
  let node = this.getNode(this.rootId);
1186
+ if (node.parent !== null) {
1187
+ node.parent = null;
1188
+ this.bufferForNodeUpdate(node);
1189
+ }
1176
1190
  while (!node.leaf) {
1191
+ const parentId = node.id;
1177
1192
  for (let i = 0, len = node.values.length; i < len; i++) {
1178
1193
  const nValue = node.values[i];
1179
1194
  const k = node.keys;
1180
1195
  if (this.comparator.isPrimarySame(value, nValue)) {
1181
1196
  node = this.getNode(k[i]);
1197
+ if (node.parent !== parentId) {
1198
+ node.parent = parentId;
1199
+ this.bufferForNodeUpdate(node);
1200
+ }
1182
1201
  break;
1183
1202
  } else if (this.comparator.isPrimaryLower(value, nValue)) {
1184
1203
  node = this.getNode(k[i]);
1204
+ if (node.parent !== parentId) {
1205
+ node.parent = parentId;
1206
+ this.bufferForNodeUpdate(node);
1207
+ }
1185
1208
  break;
1186
1209
  } else if (i + 1 === node.values.length) {
1187
1210
  node = this.getNode(k[i + 1]);
1211
+ if (node.parent !== parentId) {
1212
+ node.parent = parentId;
1213
+ this.bufferForNodeUpdate(node);
1214
+ }
1188
1215
  break;
1189
1216
  }
1190
1217
  }
@@ -1193,16 +1220,29 @@ var BPTreeSyncBase = class extends BPTree {
1193
1220
  }
1194
1221
  insertableRightestNodeByPrimary(value) {
1195
1222
  let node = this.getNode(this.rootId);
1223
+ if (node.parent !== null) {
1224
+ node.parent = null;
1225
+ this.bufferForNodeUpdate(node);
1226
+ }
1196
1227
  while (!node.leaf) {
1228
+ const parentId = node.id;
1197
1229
  for (let i = 0, len = node.values.length; i < len; i++) {
1198
1230
  const nValue = node.values[i];
1199
1231
  const k = node.keys;
1200
1232
  if (this.comparator.isPrimaryLower(value, nValue)) {
1201
1233
  node = this.getNode(k[i]);
1234
+ if (node.parent !== parentId) {
1235
+ node.parent = parentId;
1236
+ this.bufferForNodeUpdate(node);
1237
+ }
1202
1238
  break;
1203
1239
  }
1204
1240
  if (i + 1 === node.values.length) {
1205
1241
  node = this.getNode(k[i + 1]);
1242
+ if (node.parent !== parentId) {
1243
+ node.parent = parentId;
1244
+ this.bufferForNodeUpdate(node);
1245
+ }
1206
1246
  break;
1207
1247
  }
1208
1248
  }
@@ -1237,17 +1277,35 @@ var BPTreeSyncBase = class extends BPTree {
1237
1277
  }
1238
1278
  leftestNode() {
1239
1279
  let node = this.getNode(this.rootId);
1280
+ if (node.parent !== null) {
1281
+ node.parent = null;
1282
+ this.bufferForNodeUpdate(node);
1283
+ }
1240
1284
  while (!node.leaf) {
1285
+ const parentId = node.id;
1241
1286
  const keys = node.keys;
1242
1287
  node = this.getNode(keys[0]);
1288
+ if (node.parent !== parentId) {
1289
+ node.parent = parentId;
1290
+ this.bufferForNodeUpdate(node);
1291
+ }
1243
1292
  }
1244
1293
  return node;
1245
1294
  }
1246
1295
  rightestNode() {
1247
1296
  let node = this.getNode(this.rootId);
1297
+ if (node.parent !== null) {
1298
+ node.parent = null;
1299
+ this.bufferForNodeUpdate(node);
1300
+ }
1248
1301
  while (!node.leaf) {
1302
+ const parentId = node.id;
1249
1303
  const keys = node.keys;
1250
1304
  node = this.getNode(keys[keys.length - 1]);
1305
+ if (node.parent !== parentId) {
1306
+ node.parent = parentId;
1307
+ this.bufferForNodeUpdate(node);
1308
+ }
1251
1309
  }
1252
1310
  return node;
1253
1311
  }
@@ -1586,23 +1644,37 @@ var BPTreeSyncTransaction = class extends BPTreeSyncBase {
1586
1644
  realBaseTree;
1587
1645
  realBaseStrategy;
1588
1646
  txNodes = /* @__PURE__ */ new Map();
1589
- dirtyIds = /* @__PURE__ */ new Set();
1590
- createdInTx = /* @__PURE__ */ new Set();
1647
+ dirtyIds;
1648
+ createdInTx;
1649
+ deletedIds;
1591
1650
  initialRootId;
1592
1651
  transactionRootId;
1593
1652
  constructor(baseTree) {
1594
1653
  super(baseTree.strategy, baseTree.comparator, baseTree.option);
1595
1654
  this.realBaseTree = baseTree;
1596
1655
  this.realBaseStrategy = baseTree.strategy;
1656
+ this.order = baseTree.getOrder();
1597
1657
  this.initialRootId = "";
1598
1658
  this.transactionRootId = "";
1659
+ this.dirtyIds = /* @__PURE__ */ new Set();
1660
+ this.createdInTx = /* @__PURE__ */ new Set();
1661
+ this.deletedIds = /* @__PURE__ */ new Set();
1599
1662
  }
1600
1663
  /**
1601
1664
  * Initializes the transaction by capturing the current state of the tree.
1602
1665
  */
1603
1666
  initTransaction() {
1604
1667
  const head = this.realBaseStrategy.readHead();
1605
- this.initialRootId = head?.root ?? this.realBaseTree.rootId;
1668
+ if (head) {
1669
+ this.order = head.order;
1670
+ this.initialRootId = head.root;
1671
+ } else {
1672
+ this.initialRootId = this.realBaseTree.getRootId();
1673
+ }
1674
+ if (!this.initialRootId) {
1675
+ const root = this._createNode(true, [], [], true);
1676
+ this.initialRootId = root.id;
1677
+ }
1606
1678
  this.transactionRootId = this.initialRootId;
1607
1679
  this.rootId = this.transactionRootId;
1608
1680
  const snapshotStrategy = new BPTreeSyncSnapshotStrategy(this.realBaseStrategy, this.initialRootId);
@@ -1610,34 +1682,76 @@ var BPTreeSyncTransaction = class extends BPTreeSyncBase {
1610
1682
  this.txNodes.clear();
1611
1683
  this.dirtyIds.clear();
1612
1684
  this.createdInTx.clear();
1685
+ this.deletedIds.clear();
1613
1686
  }
1614
1687
  getNode(id) {
1615
1688
  if (this.txNodes.has(id)) {
1616
1689
  return this.txNodes.get(id);
1617
1690
  }
1691
+ if (this.deletedIds.has(id)) {
1692
+ throw new Error(`The tree attempted to reference deleted node '${id}'`);
1693
+ }
1618
1694
  const baseNode = this.realBaseStrategy.read(id);
1619
1695
  const clone = JSON.parse(JSON.stringify(baseNode));
1620
1696
  this.txNodes.set(id, clone);
1621
1697
  return clone;
1622
1698
  }
1623
1699
  bufferForNodeUpdate(node) {
1700
+ if (this.dirtyIds.has(node.id) && this.txNodes.has(node.id) && node._p) {
1701
+ this.txNodes.set(node.id, node);
1702
+ return;
1703
+ }
1704
+ node._p = true;
1624
1705
  this.txNodes.set(node.id, node);
1625
1706
  this.dirtyIds.add(node.id);
1707
+ if (node.leaf) {
1708
+ if (node.next && !this.dirtyIds.has(node.next) && !this.deletedIds.has(node.next)) {
1709
+ try {
1710
+ this.bufferForNodeUpdate(this.getNode(node.next));
1711
+ } catch (e) {
1712
+ }
1713
+ }
1714
+ if (node.prev && !this.dirtyIds.has(node.prev) && !this.deletedIds.has(node.prev)) {
1715
+ try {
1716
+ this.bufferForNodeUpdate(this.getNode(node.prev));
1717
+ } catch (e) {
1718
+ }
1719
+ }
1720
+ }
1626
1721
  this.markPathDirty(node);
1722
+ delete node._p;
1627
1723
  }
1628
1724
  bufferForNodeCreate(node) {
1629
1725
  this.txNodes.set(node.id, node);
1630
1726
  this.dirtyIds.add(node.id);
1631
1727
  this.createdInTx.add(node.id);
1728
+ if (node.leaf) {
1729
+ if (node.next && !this.dirtyIds.has(node.next) && !this.deletedIds.has(node.next)) {
1730
+ try {
1731
+ this.bufferForNodeUpdate(this.getNode(node.next));
1732
+ } catch (e) {
1733
+ }
1734
+ }
1735
+ if (node.prev && !this.dirtyIds.has(node.prev) && !this.deletedIds.has(node.prev)) {
1736
+ try {
1737
+ this.bufferForNodeUpdate(this.getNode(node.prev));
1738
+ } catch (e) {
1739
+ }
1740
+ }
1741
+ }
1632
1742
  this.markPathDirty(node);
1633
1743
  }
1634
1744
  bufferForNodeDelete(node) {
1635
1745
  this.txNodes.delete(node.id);
1636
1746
  this.dirtyIds.add(node.id);
1747
+ this.deletedIds.add(node.id);
1637
1748
  }
1638
1749
  markPathDirty(node) {
1639
1750
  let curr = node;
1640
1751
  while (curr.parent) {
1752
+ if (this.deletedIds.has(curr.parent)) {
1753
+ break;
1754
+ }
1641
1755
  if (this.dirtyIds.has(curr.parent) && this.txNodes.has(curr.parent)) {
1642
1756
  break;
1643
1757
  }
@@ -1649,13 +1763,13 @@ var BPTreeSyncTransaction = class extends BPTreeSyncBase {
1649
1763
  this.transactionRootId = curr.id;
1650
1764
  }
1651
1765
  }
1652
- _createNode(isLeaf, keys, values, leaf = false, parent = null, next = null, prev = null) {
1653
- const id = this.realBaseStrategy.id(isLeaf);
1766
+ _createNode(isLeaf, keys, values, leaf = isLeaf, parent = null, next = null, prev = null) {
1767
+ const id = this.strategy.id(isLeaf);
1654
1768
  const node = {
1655
1769
  id,
1656
1770
  keys,
1657
1771
  values,
1658
- leaf: isLeaf,
1772
+ leaf,
1659
1773
  parent,
1660
1774
  next,
1661
1775
  prev
@@ -1713,9 +1827,9 @@ var BPTreeSyncTransaction = class extends BPTreeSyncBase {
1713
1827
  finalNodes.push(node);
1714
1828
  newCreatedIds.push(newId);
1715
1829
  }
1716
- let newRootId = this.transactionRootId;
1717
- if (idMapping.has(this.transactionRootId)) {
1718
- newRootId = idMapping.get(this.transactionRootId);
1830
+ let newRootId = this.rootId;
1831
+ if (idMapping.has(this.rootId)) {
1832
+ newRootId = idMapping.get(this.rootId);
1719
1833
  }
1720
1834
  for (const node of finalNodes) {
1721
1835
  this.realBaseStrategy.write(node.id, node);
@@ -1744,12 +1858,21 @@ var BPTreeSyncTransaction = class extends BPTreeSyncBase {
1744
1858
  }
1745
1859
  /**
1746
1860
  * Rolls back the transaction by clearing all buffered changes.
1747
- * Internal use only.
1861
+ * If cleanup is `true`, it also clears the transaction nodes.
1862
+ * @param cleanup Whether to clear the transaction nodes.
1863
+ * @returns The IDs of nodes that were created in this transaction.
1748
1864
  */
1749
- rollback() {
1865
+ rollback(cleanup = true) {
1866
+ const createdIds = Array.from(this.createdInTx);
1750
1867
  this.txNodes.clear();
1751
1868
  this.dirtyIds.clear();
1752
1869
  this.createdInTx.clear();
1870
+ if (cleanup) {
1871
+ for (const id of createdIds) {
1872
+ this.realBaseStrategy.delete(id);
1873
+ }
1874
+ }
1875
+ return createdIds;
1753
1876
  }
1754
1877
  // Override to do nothing, as transaction handles its own commits
1755
1878
  commitHeadBuffer() {
@@ -1766,6 +1889,7 @@ var BPTreeSyncTransaction = class extends BPTreeSyncBase {
1766
1889
  var BPTreeSync = class extends BPTreeSyncBase {
1767
1890
  constructor(strategy, comparator, option) {
1768
1891
  super(strategy, comparator, option);
1892
+ this.init();
1769
1893
  }
1770
1894
  /**
1771
1895
  * Creates a new synchronous transaction.
@@ -1873,7 +1997,7 @@ var BPTreeAsyncBase = class extends BPTree {
1873
1997
  }
1874
1998
  return id;
1875
1999
  }
1876
- async _createNode(isLeaf, keys, values, leaf = false, parent = null, next = null, prev = null) {
2000
+ async _createNode(isLeaf, keys, values, leaf = isLeaf, parent = null, next = null, prev = null) {
1877
2001
  const id = await this._createNodeId(isLeaf);
1878
2002
  const node = {
1879
2003
  id,
@@ -1884,40 +2008,37 @@ var BPTreeAsyncBase = class extends BPTree {
1884
2008
  next,
1885
2009
  prev
1886
2010
  };
1887
- this._nodeCreateBuffer.set(id, node);
2011
+ await this.bufferForNodeCreate(node);
1888
2012
  return node;
1889
2013
  }
1890
2014
  async _deleteEntry(node, key, value) {
1891
2015
  if (!node.leaf) {
2016
+ let keyIndex = -1;
1892
2017
  for (let i = 0, len = node.keys.length; i < len; i++) {
1893
- const nKey = node.keys[i];
1894
- if (nKey === key) {
1895
- node.keys.splice(i, 1);
1896
- this.bufferForNodeUpdate(node);
2018
+ if (node.keys[i] === key) {
2019
+ keyIndex = i;
1897
2020
  break;
1898
2021
  }
1899
2022
  }
1900
- for (let i = 0, len = node.values.length; i < len; i++) {
1901
- const nValue = node.values[i];
1902
- if (this.comparator.isSame(value, nValue)) {
1903
- node.values.splice(i, 1);
1904
- this.bufferForNodeUpdate(node);
1905
- break;
1906
- }
2023
+ if (keyIndex !== -1) {
2024
+ node.keys.splice(keyIndex, 1);
2025
+ const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
2026
+ node.values.splice(valueIndex, 1);
2027
+ await this.bufferForNodeUpdate(node);
1907
2028
  }
1908
2029
  }
1909
2030
  if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
1910
2031
  const keys = node.keys;
1911
- this.bufferForNodeDelete(node);
2032
+ await this.bufferForNodeDelete(node);
1912
2033
  const newRoot = await this.getNode(keys[0]);
1913
2034
  this.rootId = newRoot.id;
1914
2035
  newRoot.parent = null;
1915
2036
  this.strategy.head.root = this.rootId;
1916
- this.bufferForNodeUpdate(newRoot);
2037
+ await this.bufferForNodeUpdate(newRoot);
1917
2038
  return;
1918
2039
  } else if (this.rootId === node.id) {
1919
2040
  const root = await this.getNode(this.rootId);
1920
- this.bufferForNodeUpdate(root);
2041
+ await this.bufferForNodeUpdate(root);
1921
2042
  return;
1922
2043
  } else if (node.keys.length < Math.ceil(this.order / 2) && !node.leaf || node.values.length < Math.ceil((this.order - 1) / 2) && node.leaf) {
1923
2044
  if (node.parent === null) {
@@ -1978,7 +2099,7 @@ var BPTreeAsyncBase = class extends BPTree {
1978
2099
  if (pointer.next) {
1979
2100
  const n = await this.getNode(pointer.next);
1980
2101
  n.prev = pointer.id;
1981
- this.bufferForNodeUpdate(n);
2102
+ await this.bufferForNodeUpdate(n);
1982
2103
  }
1983
2104
  }
1984
2105
  pointer.values.push(...node.values);
@@ -1987,12 +2108,12 @@ var BPTreeAsyncBase = class extends BPTree {
1987
2108
  for (const key2 of keys) {
1988
2109
  const n = await this.getNode(key2);
1989
2110
  n.parent = pointer.id;
1990
- this.bufferForNodeUpdate(n);
2111
+ await this.bufferForNodeUpdate(n);
1991
2112
  }
1992
2113
  }
1993
2114
  await this._deleteEntry(await this.getNode(node.parent), node.id, guess);
1994
- this.bufferForNodeUpdate(pointer);
1995
- this.bufferForNodeDelete(node);
2115
+ await this.bufferForNodeUpdate(pointer);
2116
+ await this.bufferForNodeDelete(node);
1996
2117
  } else {
1997
2118
  if (isPredecessor) {
1998
2119
  let pointerPm;
@@ -2003,13 +2124,10 @@ var BPTreeAsyncBase = class extends BPTree {
2003
2124
  node.keys = [pointerPm, ...node.keys];
2004
2125
  node.values = [guess, ...node.values];
2005
2126
  parentNode = await this.getNode(node.parent);
2006
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
2007
- const nValue = parentNode.values[i];
2008
- if (this.comparator.isSame(guess, nValue)) {
2009
- parentNode.values[i] = pointerKm;
2010
- this.bufferForNodeUpdate(parentNode);
2011
- break;
2012
- }
2127
+ const nodeIndex = parentNode.keys.indexOf(node.id);
2128
+ if (nodeIndex > 0) {
2129
+ parentNode.values[nodeIndex - 1] = pointerKm;
2130
+ await this.bufferForNodeUpdate(parentNode);
2013
2131
  }
2014
2132
  } else {
2015
2133
  pointerPm = pointer.keys.splice(-1)[0];
@@ -2017,17 +2135,14 @@ var BPTreeAsyncBase = class extends BPTree {
2017
2135
  node.keys = [pointerPm, ...node.keys];
2018
2136
  node.values = [pointerKm, ...node.values];
2019
2137
  parentNode = await this.getNode(node.parent);
2020
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
2021
- const nValue = parentNode.values[i];
2022
- if (this.comparator.isSame(guess, nValue)) {
2023
- parentNode.values[i] = pointerKm;
2024
- this.bufferForNodeUpdate(parentNode);
2025
- break;
2026
- }
2138
+ const nodeIndex = parentNode.keys.indexOf(node.id);
2139
+ if (nodeIndex > 0) {
2140
+ parentNode.values[nodeIndex - 1] = pointerKm;
2141
+ await this.bufferForNodeUpdate(parentNode);
2027
2142
  }
2028
2143
  }
2029
- this.bufferForNodeUpdate(node);
2030
- this.bufferForNodeUpdate(pointer);
2144
+ await this.bufferForNodeUpdate(node);
2145
+ await this.bufferForNodeUpdate(pointer);
2031
2146
  } else {
2032
2147
  let pointerP0;
2033
2148
  let pointerK0;
@@ -2037,13 +2152,10 @@ var BPTreeAsyncBase = class extends BPTree {
2037
2152
  node.keys = [...node.keys, pointerP0];
2038
2153
  node.values = [...node.values, guess];
2039
2154
  parentNode = await this.getNode(node.parent);
2040
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
2041
- const nValue = parentNode.values[i];
2042
- if (this.comparator.isSame(guess, nValue)) {
2043
- parentNode.values[i] = pointerK0;
2044
- this.bufferForNodeUpdate(parentNode);
2045
- break;
2046
- }
2155
+ const pointerIndex = parentNode.keys.indexOf(pointer.id);
2156
+ if (pointerIndex > 0) {
2157
+ parentNode.values[pointerIndex - 1] = pointerK0;
2158
+ await this.bufferForNodeUpdate(parentNode);
2047
2159
  }
2048
2160
  } else {
2049
2161
  pointerP0 = pointer.keys.splice(0, 1)[0];
@@ -2051,24 +2163,21 @@ var BPTreeAsyncBase = class extends BPTree {
2051
2163
  node.keys = [...node.keys, pointerP0];
2052
2164
  node.values = [...node.values, pointerK0];
2053
2165
  parentNode = await this.getNode(node.parent);
2054
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
2055
- const nValue = parentNode.values[i];
2056
- if (this.comparator.isSame(guess, nValue)) {
2057
- parentNode.values[i] = pointer.values[0];
2058
- this.bufferForNodeUpdate(parentNode);
2059
- break;
2060
- }
2166
+ const pointerIndex = parentNode.keys.indexOf(pointer.id);
2167
+ if (pointerIndex > 0) {
2168
+ parentNode.values[pointerIndex - 1] = pointer.values[0];
2169
+ await this.bufferForNodeUpdate(parentNode);
2061
2170
  }
2062
2171
  }
2063
- this.bufferForNodeUpdate(node);
2064
- this.bufferForNodeUpdate(pointer);
2172
+ await this.bufferForNodeUpdate(node);
2173
+ await this.bufferForNodeUpdate(pointer);
2065
2174
  }
2066
2175
  if (!pointer.leaf) {
2067
2176
  const keys = pointer.keys;
2068
2177
  for (const key2 of keys) {
2069
2178
  const n = await this.getNode(key2);
2070
2179
  n.parent = pointer.id;
2071
- this.bufferForNodeUpdate(n);
2180
+ await this.bufferForNodeUpdate(n);
2072
2181
  }
2073
2182
  }
2074
2183
  if (!node.leaf) {
@@ -2076,7 +2185,7 @@ var BPTreeAsyncBase = class extends BPTree {
2076
2185
  for (const key2 of keys) {
2077
2186
  const n = await this.getNode(key2);
2078
2187
  n.parent = node.id;
2079
- this.bufferForNodeUpdate(n);
2188
+ await this.bufferForNodeUpdate(n);
2080
2189
  }
2081
2190
  }
2082
2191
  if (!parentNode.leaf) {
@@ -2084,10 +2193,12 @@ var BPTreeAsyncBase = class extends BPTree {
2084
2193
  for (const key2 of keys) {
2085
2194
  const n = await this.getNode(key2);
2086
2195
  n.parent = parentNode.id;
2087
- this.bufferForNodeUpdate(n);
2196
+ await this.bufferForNodeUpdate(n);
2088
2197
  }
2089
2198
  }
2090
2199
  }
2200
+ } else {
2201
+ await this.bufferForNodeUpdate(node);
2091
2202
  }
2092
2203
  }
2093
2204
  async _insertInParent(node, value, pointer) {
@@ -2098,43 +2209,39 @@ var BPTreeAsyncBase = class extends BPTree {
2098
2209
  node.parent = root.id;
2099
2210
  pointer.parent = root.id;
2100
2211
  if (pointer.leaf) {
2101
- node.next = pointer.id;
2102
- pointer.prev = node.id;
2212
+ const nNode = node;
2213
+ nNode.next = pointer.id;
2214
+ const nPointer = pointer;
2215
+ nPointer.prev = node.id;
2103
2216
  }
2104
- this.bufferForNodeUpdate(node);
2105
- this.bufferForNodeUpdate(pointer);
2217
+ await this.bufferForNodeUpdate(node);
2218
+ await this.bufferForNodeUpdate(pointer);
2106
2219
  return;
2107
2220
  }
2108
2221
  const parentNode = await this.getNode(node.parent);
2109
- let insertIndex = 0;
2110
- for (let i = 0; i < parentNode.values.length; i++) {
2111
- if (this.comparator.asc(value, parentNode.values[i]) > 0) {
2112
- insertIndex = i + 1;
2113
- } else {
2114
- break;
2115
- }
2222
+ const nodeIndex = parentNode.keys.indexOf(node.id);
2223
+ if (nodeIndex === -1) {
2224
+ throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
2116
2225
  }
2226
+ const insertIndex = nodeIndex;
2117
2227
  parentNode.values.splice(insertIndex, 0, value);
2118
2228
  parentNode.keys.splice(insertIndex + 1, 0, pointer.id);
2119
2229
  pointer.parent = parentNode.id;
2120
2230
  if (pointer.leaf) {
2121
- const leftSiblingId = parentNode.keys[insertIndex];
2122
- const rightSiblingId = parentNode.keys[insertIndex + 2];
2123
- if (leftSiblingId) {
2124
- const leftSibling = await this.getNode(leftSiblingId);
2125
- pointer.prev = leftSibling.id;
2126
- pointer.next = leftSibling.next;
2127
- leftSibling.next = pointer.id;
2128
- this.bufferForNodeUpdate(leftSibling);
2129
- }
2130
- if (rightSiblingId) {
2131
- const rightSibling = await this.getNode(rightSiblingId);
2132
- rightSibling.prev = pointer.id;
2133
- this.bufferForNodeUpdate(rightSibling);
2134
- }
2135
- }
2136
- this.bufferForNodeUpdate(parentNode);
2137
- this.bufferForNodeUpdate(pointer);
2231
+ const leftSibling = node;
2232
+ const oldNextId = leftSibling.next;
2233
+ pointer.prev = leftSibling.id;
2234
+ pointer.next = oldNextId;
2235
+ leftSibling.next = pointer.id;
2236
+ await this.bufferForNodeUpdate(leftSibling);
2237
+ if (oldNextId) {
2238
+ const oldNext = await this.getNode(oldNextId);
2239
+ oldNext.prev = pointer.id;
2240
+ await this.bufferForNodeUpdate(oldNext);
2241
+ }
2242
+ }
2243
+ await this.bufferForNodeUpdate(parentNode);
2244
+ await this.bufferForNodeUpdate(pointer);
2138
2245
  if (parentNode.keys.length > this.order) {
2139
2246
  const parentPointer = await this._createNode(false, [], []);
2140
2247
  parentPointer.parent = parentNode.parent;
@@ -2147,18 +2254,19 @@ var BPTreeAsyncBase = class extends BPTree {
2147
2254
  for (const k of parentNode.keys) {
2148
2255
  const n = await this.getNode(k);
2149
2256
  n.parent = parentNode.id;
2150
- this.bufferForNodeUpdate(n);
2257
+ await this.bufferForNodeUpdate(n);
2151
2258
  }
2152
2259
  for (const k of parentPointer.keys) {
2153
2260
  const n = await this.getNode(k);
2154
2261
  n.parent = parentPointer.id;
2155
- this.bufferForNodeUpdate(n);
2262
+ await this.bufferForNodeUpdate(n);
2156
2263
  }
2157
2264
  await this._insertInParent(parentNode, midValue, parentPointer);
2158
- this.bufferForNodeUpdate(parentNode);
2265
+ await this.bufferForNodeUpdate(parentNode);
2159
2266
  }
2160
2267
  }
2161
2268
  async init() {
2269
+ this.clear();
2162
2270
  const head = await this.strategy.readHead();
2163
2271
  if (head === null) {
2164
2272
  this.order = this.strategy.order;
@@ -2189,18 +2297,35 @@ var BPTreeAsyncBase = class extends BPTree {
2189
2297
  }
2190
2298
  async insertableNode(value) {
2191
2299
  let node = await this.getNode(this.rootId);
2300
+ if (node.parent !== null) {
2301
+ node.parent = null;
2302
+ await this.bufferForNodeUpdate(node);
2303
+ }
2192
2304
  while (!node.leaf) {
2305
+ const parentId = node.id;
2193
2306
  for (let i = 0, len = node.values.length; i < len; i++) {
2194
2307
  const nValue = node.values[i];
2195
2308
  const k = node.keys;
2196
2309
  if (this.comparator.isSame(value, nValue)) {
2197
2310
  node = await this.getNode(node.keys[i + 1]);
2311
+ if (node.parent !== parentId) {
2312
+ node.parent = parentId;
2313
+ await this.bufferForNodeUpdate(node);
2314
+ }
2198
2315
  break;
2199
2316
  } else if (this.comparator.isLower(value, nValue)) {
2200
2317
  node = await this.getNode(node.keys[i]);
2318
+ if (node.parent !== parentId) {
2319
+ node.parent = parentId;
2320
+ await this.bufferForNodeUpdate(node);
2321
+ }
2201
2322
  break;
2202
2323
  } else if (i + 1 === node.values.length) {
2203
2324
  node = await this.getNode(node.keys[i + 1]);
2325
+ if (node.parent !== parentId) {
2326
+ node.parent = parentId;
2327
+ await this.bufferForNodeUpdate(node);
2328
+ }
2204
2329
  break;
2205
2330
  }
2206
2331
  }
@@ -2209,18 +2334,35 @@ var BPTreeAsyncBase = class extends BPTree {
2209
2334
  }
2210
2335
  async insertableNodeByPrimary(value) {
2211
2336
  let node = await this.getNode(this.rootId);
2337
+ if (node.parent !== null) {
2338
+ node.parent = null;
2339
+ await this.bufferForNodeUpdate(node);
2340
+ }
2212
2341
  while (!node.leaf) {
2342
+ const parentId = node.id;
2213
2343
  for (let i = 0, len = node.values.length; i < len; i++) {
2214
2344
  const nValue = node.values[i];
2215
2345
  const k = node.keys;
2216
2346
  if (this.comparator.isPrimarySame(value, nValue)) {
2217
2347
  node = await this.getNode(node.keys[i]);
2348
+ if (node.parent !== parentId) {
2349
+ node.parent = parentId;
2350
+ await this.bufferForNodeUpdate(node);
2351
+ }
2218
2352
  break;
2219
2353
  } else if (this.comparator.isPrimaryLower(value, nValue)) {
2220
2354
  node = await this.getNode(node.keys[i]);
2355
+ if (node.parent !== parentId) {
2356
+ node.parent = parentId;
2357
+ await this.bufferForNodeUpdate(node);
2358
+ }
2221
2359
  break;
2222
2360
  } else if (i + 1 === node.values.length) {
2223
2361
  node = await this.getNode(node.keys[i + 1]);
2362
+ if (node.parent !== parentId) {
2363
+ node.parent = parentId;
2364
+ await this.bufferForNodeUpdate(node);
2365
+ }
2224
2366
  break;
2225
2367
  }
2226
2368
  }
@@ -2229,16 +2371,29 @@ var BPTreeAsyncBase = class extends BPTree {
2229
2371
  }
2230
2372
  async insertableRightestNodeByPrimary(value) {
2231
2373
  let node = await this.getNode(this.rootId);
2374
+ if (node.parent !== null) {
2375
+ node.parent = null;
2376
+ await this.bufferForNodeUpdate(node);
2377
+ }
2232
2378
  while (!node.leaf) {
2379
+ const parentId = node.id;
2233
2380
  for (let i = 0, len = node.values.length; i < len; i++) {
2234
2381
  const nValue = node.values[i];
2235
2382
  const k = node.keys;
2236
2383
  if (this.comparator.isPrimaryLower(value, nValue)) {
2237
2384
  node = await this.getNode(node.keys[i]);
2385
+ if (node.parent !== parentId) {
2386
+ node.parent = parentId;
2387
+ await this.bufferForNodeUpdate(node);
2388
+ }
2238
2389
  break;
2239
2390
  }
2240
2391
  if (i + 1 === node.values.length) {
2241
2392
  node = await this.getNode(node.keys[i + 1]);
2393
+ if (node.parent !== parentId) {
2394
+ node.parent = parentId;
2395
+ await this.bufferForNodeUpdate(node);
2396
+ }
2242
2397
  break;
2243
2398
  }
2244
2399
  }
@@ -2273,17 +2428,35 @@ var BPTreeAsyncBase = class extends BPTree {
2273
2428
  }
2274
2429
  async leftestNode() {
2275
2430
  let node = await this.getNode(this.rootId);
2431
+ if (node.parent !== null) {
2432
+ node.parent = null;
2433
+ await this.bufferForNodeUpdate(node);
2434
+ }
2276
2435
  while (!node.leaf) {
2436
+ const parentId = node.id;
2277
2437
  const keys = node.keys;
2278
2438
  node = await this.getNode(node.keys[0]);
2439
+ if (node.parent !== parentId) {
2440
+ node.parent = parentId;
2441
+ await this.bufferForNodeUpdate(node);
2442
+ }
2279
2443
  }
2280
2444
  return node;
2281
2445
  }
2282
2446
  async rightestNode() {
2283
2447
  let node = await this.getNode(this.rootId);
2448
+ if (node.parent !== null) {
2449
+ node.parent = null;
2450
+ await this.bufferForNodeUpdate(node);
2451
+ }
2284
2452
  while (!node.leaf) {
2453
+ const parentId = node.id;
2285
2454
  const keys = node.keys;
2286
2455
  node = await this.getNode(node.keys[node.keys.length - 1]);
2456
+ if (node.parent !== parentId) {
2457
+ node.parent = parentId;
2458
+ await this.bufferForNodeUpdate(node);
2459
+ }
2287
2460
  }
2288
2461
  return node;
2289
2462
  }
@@ -2443,7 +2616,7 @@ var BPTreeAsyncBase = class extends BPTree {
2443
2616
  async insert(key, value) {
2444
2617
  await this.writeLock(async () => {
2445
2618
  const before = await this.insertableNode(value);
2446
- this._insertAtLeaf(before, key, value);
2619
+ await this._insertAtLeaf(before, key, value);
2447
2620
  if (before.values.length === this.order) {
2448
2621
  const after = await this._createNode(
2449
2622
  true,
@@ -2460,7 +2633,7 @@ var BPTreeAsyncBase = class extends BPTree {
2460
2633
  before.values = before.values.slice(0, mid + 1);
2461
2634
  before.keys = before.keys.slice(0, mid + 1);
2462
2635
  await this._insertInParent(before, after.values[0], after);
2463
- this.bufferForNodeUpdate(before);
2636
+ await this.bufferForNodeUpdate(before);
2464
2637
  }
2465
2638
  await this.commitHeadBuffer();
2466
2639
  await this.commitNodeCreateBuffer();
@@ -2483,11 +2656,13 @@ var BPTreeAsyncBase = class extends BPTree {
2483
2656
  node.values.splice(i, 1);
2484
2657
  }
2485
2658
  await this._deleteEntry(node, key, value);
2659
+ await this.bufferForNodeUpdate(node);
2486
2660
  break;
2487
2661
  }
2488
2662
  }
2489
2663
  }
2490
2664
  await this.commitHeadBuffer();
2665
+ await this.commitNodeCreateBuffer();
2491
2666
  await this.commitNodeUpdateBuffer();
2492
2667
  await this.commitNodeDeleteBuffer();
2493
2668
  });
@@ -2613,23 +2788,37 @@ var BPTreeAsyncTransaction = class extends BPTreeAsyncBase {
2613
2788
  realBaseTree;
2614
2789
  realBaseStrategy;
2615
2790
  txNodes = /* @__PURE__ */ new Map();
2616
- dirtyIds = /* @__PURE__ */ new Set();
2617
- createdInTx = /* @__PURE__ */ new Set();
2791
+ dirtyIds;
2792
+ createdInTx;
2793
+ deletedIds;
2618
2794
  initialRootId;
2619
2795
  transactionRootId;
2620
2796
  constructor(baseTree) {
2621
2797
  super(baseTree.strategy, baseTree.comparator, baseTree.option);
2622
2798
  this.realBaseTree = baseTree;
2623
2799
  this.realBaseStrategy = baseTree.strategy;
2800
+ this.order = baseTree.getOrder();
2624
2801
  this.initialRootId = "";
2625
2802
  this.transactionRootId = "";
2803
+ this.dirtyIds = /* @__PURE__ */ new Set();
2804
+ this.createdInTx = /* @__PURE__ */ new Set();
2805
+ this.deletedIds = /* @__PURE__ */ new Set();
2626
2806
  }
2627
2807
  /**
2628
2808
  * Initializes the transaction by capturing the current state of the tree.
2629
2809
  */
2630
2810
  async initTransaction() {
2631
2811
  const head = await this.realBaseStrategy.readHead();
2632
- this.initialRootId = head?.root ?? this.realBaseTree.rootId;
2812
+ if (head) {
2813
+ this.order = head.order;
2814
+ this.initialRootId = head.root;
2815
+ } else {
2816
+ this.initialRootId = this.realBaseTree.getRootId();
2817
+ }
2818
+ if (!this.initialRootId) {
2819
+ const root = await this._createNode(true, [], [], true);
2820
+ this.initialRootId = root.id;
2821
+ }
2633
2822
  this.transactionRootId = this.initialRootId;
2634
2823
  this.rootId = this.transactionRootId;
2635
2824
  const snapshotStrategy = new BPTreeAsyncSnapshotStrategy(this.realBaseStrategy, this.initialRootId);
@@ -2637,34 +2826,76 @@ var BPTreeAsyncTransaction = class extends BPTreeAsyncBase {
2637
2826
  this.txNodes.clear();
2638
2827
  this.dirtyIds.clear();
2639
2828
  this.createdInTx.clear();
2829
+ this.deletedIds.clear();
2640
2830
  }
2641
2831
  async getNode(id) {
2642
2832
  if (this.txNodes.has(id)) {
2643
2833
  return this.txNodes.get(id);
2644
2834
  }
2835
+ if (this.deletedIds.has(id)) {
2836
+ throw new Error(`The tree attempted to reference deleted node '${id}'`);
2837
+ }
2645
2838
  const baseNode = await this.realBaseStrategy.read(id);
2646
2839
  const clone = JSON.parse(JSON.stringify(baseNode));
2647
2840
  this.txNodes.set(id, clone);
2648
2841
  return clone;
2649
2842
  }
2650
2843
  async bufferForNodeUpdate(node) {
2844
+ if (this.dirtyIds.has(node.id) && this.txNodes.has(node.id) && node._p) {
2845
+ this.txNodes.set(node.id, node);
2846
+ return;
2847
+ }
2848
+ node._p = true;
2651
2849
  this.txNodes.set(node.id, node);
2652
2850
  this.dirtyIds.add(node.id);
2851
+ if (node.leaf) {
2852
+ if (node.next && !this.dirtyIds.has(node.next) && !this.deletedIds.has(node.next)) {
2853
+ try {
2854
+ await this.bufferForNodeUpdate(await this.getNode(node.next));
2855
+ } catch (e) {
2856
+ }
2857
+ }
2858
+ if (node.prev && !this.dirtyIds.has(node.prev) && !this.deletedIds.has(node.prev)) {
2859
+ try {
2860
+ await this.bufferForNodeUpdate(await this.getNode(node.prev));
2861
+ } catch (e) {
2862
+ }
2863
+ }
2864
+ }
2653
2865
  await this.markPathDirty(node);
2866
+ delete node._p;
2654
2867
  }
2655
2868
  async bufferForNodeCreate(node) {
2656
2869
  this.txNodes.set(node.id, node);
2657
2870
  this.dirtyIds.add(node.id);
2658
2871
  this.createdInTx.add(node.id);
2872
+ if (node.leaf) {
2873
+ if (node.next && !this.dirtyIds.has(node.next) && !this.deletedIds.has(node.next)) {
2874
+ try {
2875
+ await this.bufferForNodeUpdate(await this.getNode(node.next));
2876
+ } catch (e) {
2877
+ }
2878
+ }
2879
+ if (node.prev && !this.dirtyIds.has(node.prev) && !this.deletedIds.has(node.prev)) {
2880
+ try {
2881
+ await this.bufferForNodeUpdate(await this.getNode(node.prev));
2882
+ } catch (e) {
2883
+ }
2884
+ }
2885
+ }
2659
2886
  await this.markPathDirty(node);
2660
2887
  }
2661
2888
  async bufferForNodeDelete(node) {
2662
2889
  this.txNodes.delete(node.id);
2663
2890
  this.dirtyIds.add(node.id);
2891
+ this.deletedIds.add(node.id);
2664
2892
  }
2665
2893
  async markPathDirty(node) {
2666
2894
  let curr = node;
2667
2895
  while (curr.parent) {
2896
+ if (this.deletedIds.has(curr.parent)) {
2897
+ break;
2898
+ }
2668
2899
  if (this.dirtyIds.has(curr.parent) && this.txNodes.has(curr.parent)) {
2669
2900
  break;
2670
2901
  }
@@ -2676,13 +2907,13 @@ var BPTreeAsyncTransaction = class extends BPTreeAsyncBase {
2676
2907
  this.transactionRootId = curr.id;
2677
2908
  }
2678
2909
  }
2679
- async _createNode(isLeaf, keys, values, leaf = false, parent = null, next = null, prev = null) {
2680
- const id = await this.realBaseStrategy.id(isLeaf);
2910
+ async _createNode(isLeaf, keys, values, leaf = isLeaf, parent = null, next = null, prev = null) {
2911
+ const id = await this.strategy.id(isLeaf);
2681
2912
  const node = {
2682
2913
  id,
2683
2914
  keys,
2684
2915
  values,
2685
- leaf: isLeaf,
2916
+ leaf,
2686
2917
  parent,
2687
2918
  next,
2688
2919
  prev
@@ -2740,9 +2971,9 @@ var BPTreeAsyncTransaction = class extends BPTreeAsyncBase {
2740
2971
  finalNodes.push(node);
2741
2972
  newCreatedIds.push(newId);
2742
2973
  }
2743
- let newRootId = this.transactionRootId;
2744
- if (idMapping.has(this.transactionRootId)) {
2745
- newRootId = idMapping.get(this.transactionRootId);
2974
+ let newRootId = this.rootId;
2975
+ if (idMapping.has(this.rootId)) {
2976
+ newRootId = idMapping.get(this.rootId);
2746
2977
  }
2747
2978
  for (const node of finalNodes) {
2748
2979
  await this.realBaseStrategy.write(node.id, node);
@@ -2771,12 +3002,21 @@ var BPTreeAsyncTransaction = class extends BPTreeAsyncBase {
2771
3002
  }
2772
3003
  /**
2773
3004
  * Rolls back the transaction by clearing all buffered changes.
2774
- * Internal use only.
3005
+ * If cleanup is `true`, it also clears the transaction nodes.
3006
+ * @param cleanup Whether to clear the transaction nodes.
3007
+ * @returns The IDs of nodes that were created in this transaction.
2775
3008
  */
2776
- async rollback() {
3009
+ async rollback(cleanup = true) {
3010
+ const createdIds = Array.from(this.createdInTx);
2777
3011
  this.txNodes.clear();
2778
3012
  this.dirtyIds.clear();
2779
3013
  this.createdInTx.clear();
3014
+ if (cleanup) {
3015
+ for (const id of createdIds) {
3016
+ await this.realBaseStrategy.delete(id);
3017
+ }
3018
+ }
3019
+ return createdIds;
2780
3020
  }
2781
3021
  async readLock(fn) {
2782
3022
  return await fn();