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.
@@ -439,6 +439,20 @@ var BPTree = class _BPTree {
439
439
  option;
440
440
  order;
441
441
  rootId;
442
+ /**
443
+ * Returns the ID of the root node.
444
+ * @returns The root node ID.
445
+ */
446
+ getRootId() {
447
+ return this.rootId;
448
+ }
449
+ /**
450
+ * Returns the order of the B+Tree.
451
+ * @returns The order of the tree.
452
+ */
453
+ getOrder() {
454
+ return this.order;
455
+ }
442
456
  _strategyDirty;
443
457
  _nodeCreateBuffer;
444
458
  _nodeUpdateBuffer;
@@ -671,24 +685,21 @@ var BPTree = class _BPTree {
671
685
  break;
672
686
  }
673
687
  keys.push(key);
674
- this.bufferForNodeUpdate(node);
675
- break;
688
+ return this.bufferForNodeUpdate(node);
676
689
  } else if (this.comparator.isLower(value, nValue)) {
677
690
  node.values.splice(i, 0, value);
678
691
  node.keys.splice(i, 0, [key]);
679
- this.bufferForNodeUpdate(node);
680
- break;
692
+ return this.bufferForNodeUpdate(node);
681
693
  } else if (i + 1 === node.values.length) {
682
694
  node.values.push(value);
683
695
  node.keys.push([key]);
684
- this.bufferForNodeUpdate(node);
685
- break;
696
+ return this.bufferForNodeUpdate(node);
686
697
  }
687
698
  }
688
699
  } else {
689
700
  node.values = [value];
690
701
  node.keys = [[key]];
691
- this.bufferForNodeUpdate(node);
702
+ return this.bufferForNodeUpdate(node);
692
703
  }
693
704
  }
694
705
  bufferForNodeCreate(node) {
@@ -804,7 +815,7 @@ var BPTreeSyncBase = class extends BPTree {
804
815
  }
805
816
  return id;
806
817
  }
807
- _createNode(isLeaf, keys, values, leaf = false, parent = null, next = null, prev = null) {
818
+ _createNode(isLeaf, keys, values, leaf = isLeaf, parent = null, next = null, prev = null) {
808
819
  const id = this._createNodeId(isLeaf);
809
820
  const node = {
810
821
  id,
@@ -815,26 +826,23 @@ var BPTreeSyncBase = class extends BPTree {
815
826
  next,
816
827
  prev
817
828
  };
818
- this._nodeCreateBuffer.set(id, node);
829
+ this.bufferForNodeCreate(node);
819
830
  return node;
820
831
  }
821
832
  _deleteEntry(node, key, value) {
822
833
  if (!node.leaf) {
834
+ let keyIndex = -1;
823
835
  for (let i = 0, len = node.keys.length; i < len; i++) {
824
- const nKey = node.keys[i];
825
- if (nKey === key) {
826
- node.keys.splice(i, 1);
827
- this.bufferForNodeUpdate(node);
836
+ if (node.keys[i] === key) {
837
+ keyIndex = i;
828
838
  break;
829
839
  }
830
840
  }
831
- for (let i = 0, len = node.values.length; i < len; i++) {
832
- const nValue = node.values[i];
833
- if (this.comparator.isSame(value, nValue)) {
834
- node.values.splice(i, 1);
835
- this.bufferForNodeUpdate(node);
836
- break;
837
- }
841
+ if (keyIndex !== -1) {
842
+ node.keys.splice(keyIndex, 1);
843
+ const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
844
+ node.values.splice(valueIndex, 1);
845
+ this.bufferForNodeUpdate(node);
838
846
  }
839
847
  }
840
848
  if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
@@ -934,13 +942,10 @@ var BPTreeSyncBase = class extends BPTree {
934
942
  node.keys = [pointerPm, ...node.keys];
935
943
  node.values = [guess, ...node.values];
936
944
  parentNode = this.getNode(node.parent);
937
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
938
- const nValue = parentNode.values[i];
939
- if (this.comparator.isSame(guess, nValue)) {
940
- parentNode.values[i] = pointerKm;
941
- this.bufferForNodeUpdate(parentNode);
942
- break;
943
- }
945
+ const nodeIndex = parentNode.keys.indexOf(node.id);
946
+ if (nodeIndex > 0) {
947
+ parentNode.values[nodeIndex - 1] = pointerKm;
948
+ this.bufferForNodeUpdate(parentNode);
944
949
  }
945
950
  } else {
946
951
  pointerPm = pointer.keys.splice(-1)[0];
@@ -948,13 +953,10 @@ var BPTreeSyncBase = class extends BPTree {
948
953
  node.keys = [pointerPm, ...node.keys];
949
954
  node.values = [pointerKm, ...node.values];
950
955
  parentNode = this.getNode(node.parent);
951
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
952
- const nValue = parentNode.values[i];
953
- if (this.comparator.isSame(guess, nValue)) {
954
- parentNode.values[i] = pointerKm;
955
- this.bufferForNodeUpdate(parentNode);
956
- break;
957
- }
956
+ const nodeIndex = parentNode.keys.indexOf(node.id);
957
+ if (nodeIndex > 0) {
958
+ parentNode.values[nodeIndex - 1] = pointerKm;
959
+ this.bufferForNodeUpdate(parentNode);
958
960
  }
959
961
  }
960
962
  this.bufferForNodeUpdate(node);
@@ -968,13 +970,10 @@ var BPTreeSyncBase = class extends BPTree {
968
970
  node.keys = [...node.keys, pointerP0];
969
971
  node.values = [...node.values, guess];
970
972
  parentNode = this.getNode(node.parent);
971
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
972
- const nValue = parentNode.values[i];
973
- if (this.comparator.isSame(guess, nValue)) {
974
- parentNode.values[i] = pointerK0;
975
- this.bufferForNodeUpdate(parentNode);
976
- break;
977
- }
973
+ const pointerIndex = parentNode.keys.indexOf(pointer.id);
974
+ if (pointerIndex > 0) {
975
+ parentNode.values[pointerIndex - 1] = pointerK0;
976
+ this.bufferForNodeUpdate(parentNode);
978
977
  }
979
978
  } else {
980
979
  pointerP0 = pointer.keys.splice(0, 1)[0];
@@ -982,13 +981,10 @@ var BPTreeSyncBase = class extends BPTree {
982
981
  node.keys = [...node.keys, pointerP0];
983
982
  node.values = [...node.values, pointerK0];
984
983
  parentNode = this.getNode(node.parent);
985
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
986
- const nValue = parentNode.values[i];
987
- if (this.comparator.isSame(guess, nValue)) {
988
- parentNode.values[i] = pointer.values[0];
989
- this.bufferForNodeUpdate(parentNode);
990
- break;
991
- }
984
+ const pointerIndex = parentNode.keys.indexOf(pointer.id);
985
+ if (pointerIndex > 0) {
986
+ parentNode.values[pointerIndex - 1] = pointer.values[0];
987
+ this.bufferForNodeUpdate(parentNode);
992
988
  }
993
989
  }
994
990
  this.bufferForNodeUpdate(node);
@@ -1016,6 +1012,8 @@ var BPTreeSyncBase = class extends BPTree {
1016
1012
  }
1017
1013
  }
1018
1014
  }
1015
+ } else {
1016
+ this.bufferForNodeUpdate(node);
1019
1017
  }
1020
1018
  }
1021
1019
  _insertInParent(node, value, pointer) {
@@ -1034,31 +1032,25 @@ var BPTreeSyncBase = class extends BPTree {
1034
1032
  return;
1035
1033
  }
1036
1034
  const parentNode = this.getNode(node.parent);
1037
- let insertIndex = 0;
1038
- for (let i = 0; i < parentNode.values.length; i++) {
1039
- if (this.comparator.asc(value, parentNode.values[i]) > 0) {
1040
- insertIndex = i + 1;
1041
- } else {
1042
- break;
1043
- }
1035
+ const nodeIndex = parentNode.keys.indexOf(node.id);
1036
+ if (nodeIndex === -1) {
1037
+ throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
1044
1038
  }
1039
+ const insertIndex = nodeIndex;
1045
1040
  parentNode.values.splice(insertIndex, 0, value);
1046
1041
  parentNode.keys.splice(insertIndex + 1, 0, pointer.id);
1047
1042
  pointer.parent = parentNode.id;
1048
1043
  if (pointer.leaf) {
1049
- const leftSiblingId = parentNode.keys[insertIndex];
1050
- const rightSiblingId = parentNode.keys[insertIndex + 2];
1051
- if (leftSiblingId) {
1052
- const leftSibling = this.getNode(leftSiblingId);
1053
- pointer.prev = leftSibling.id;
1054
- pointer.next = leftSibling.next;
1055
- leftSibling.next = pointer.id;
1056
- this.bufferForNodeUpdate(leftSibling);
1057
- }
1058
- if (rightSiblingId) {
1059
- const rightSibling = this.getNode(rightSiblingId);
1060
- rightSibling.prev = pointer.id;
1061
- this.bufferForNodeUpdate(rightSibling);
1044
+ const leftSibling = node;
1045
+ const oldNextId = leftSibling.next;
1046
+ pointer.prev = leftSibling.id;
1047
+ pointer.next = oldNextId;
1048
+ leftSibling.next = pointer.id;
1049
+ this.bufferForNodeUpdate(leftSibling);
1050
+ if (oldNextId) {
1051
+ const oldNext = this.getNode(oldNextId);
1052
+ oldNext.prev = pointer.id;
1053
+ this.bufferForNodeUpdate(oldNext);
1062
1054
  }
1063
1055
  }
1064
1056
  this.bufferForNodeUpdate(parentNode);
@@ -1087,6 +1079,7 @@ var BPTreeSyncBase = class extends BPTree {
1087
1079
  }
1088
1080
  }
1089
1081
  init() {
1082
+ this.clear();
1090
1083
  const head = this.strategy.readHead();
1091
1084
  if (head === null) {
1092
1085
  this.order = this.strategy.order;
@@ -1117,18 +1110,35 @@ var BPTreeSyncBase = class extends BPTree {
1117
1110
  }
1118
1111
  insertableNode(value) {
1119
1112
  let node = this.getNode(this.rootId);
1113
+ if (node.parent !== null) {
1114
+ node.parent = null;
1115
+ this.bufferForNodeUpdate(node);
1116
+ }
1120
1117
  while (!node.leaf) {
1118
+ const parentId = node.id;
1121
1119
  for (let i = 0, len = node.values.length; i < len; i++) {
1122
1120
  const nValue = node.values[i];
1123
1121
  const k = node.keys;
1124
1122
  if (this.comparator.isSame(value, nValue)) {
1125
1123
  node = this.getNode(k[i + 1]);
1124
+ if (node.parent !== parentId) {
1125
+ node.parent = parentId;
1126
+ this.bufferForNodeUpdate(node);
1127
+ }
1126
1128
  break;
1127
1129
  } else if (this.comparator.isLower(value, nValue)) {
1128
1130
  node = this.getNode(k[i]);
1131
+ if (node.parent !== parentId) {
1132
+ node.parent = parentId;
1133
+ this.bufferForNodeUpdate(node);
1134
+ }
1129
1135
  break;
1130
1136
  } else if (i + 1 === node.values.length) {
1131
1137
  node = this.getNode(k[i + 1]);
1138
+ if (node.parent !== parentId) {
1139
+ node.parent = parentId;
1140
+ this.bufferForNodeUpdate(node);
1141
+ }
1132
1142
  break;
1133
1143
  }
1134
1144
  }
@@ -1137,18 +1147,35 @@ var BPTreeSyncBase = class extends BPTree {
1137
1147
  }
1138
1148
  insertableNodeByPrimary(value) {
1139
1149
  let node = this.getNode(this.rootId);
1150
+ if (node.parent !== null) {
1151
+ node.parent = null;
1152
+ this.bufferForNodeUpdate(node);
1153
+ }
1140
1154
  while (!node.leaf) {
1155
+ const parentId = node.id;
1141
1156
  for (let i = 0, len = node.values.length; i < len; i++) {
1142
1157
  const nValue = node.values[i];
1143
1158
  const k = node.keys;
1144
1159
  if (this.comparator.isPrimarySame(value, nValue)) {
1145
1160
  node = this.getNode(k[i]);
1161
+ if (node.parent !== parentId) {
1162
+ node.parent = parentId;
1163
+ this.bufferForNodeUpdate(node);
1164
+ }
1146
1165
  break;
1147
1166
  } else if (this.comparator.isPrimaryLower(value, nValue)) {
1148
1167
  node = this.getNode(k[i]);
1168
+ if (node.parent !== parentId) {
1169
+ node.parent = parentId;
1170
+ this.bufferForNodeUpdate(node);
1171
+ }
1149
1172
  break;
1150
1173
  } else if (i + 1 === node.values.length) {
1151
1174
  node = this.getNode(k[i + 1]);
1175
+ if (node.parent !== parentId) {
1176
+ node.parent = parentId;
1177
+ this.bufferForNodeUpdate(node);
1178
+ }
1152
1179
  break;
1153
1180
  }
1154
1181
  }
@@ -1157,16 +1184,29 @@ var BPTreeSyncBase = class extends BPTree {
1157
1184
  }
1158
1185
  insertableRightestNodeByPrimary(value) {
1159
1186
  let node = this.getNode(this.rootId);
1187
+ if (node.parent !== null) {
1188
+ node.parent = null;
1189
+ this.bufferForNodeUpdate(node);
1190
+ }
1160
1191
  while (!node.leaf) {
1192
+ const parentId = node.id;
1161
1193
  for (let i = 0, len = node.values.length; i < len; i++) {
1162
1194
  const nValue = node.values[i];
1163
1195
  const k = node.keys;
1164
1196
  if (this.comparator.isPrimaryLower(value, nValue)) {
1165
1197
  node = this.getNode(k[i]);
1198
+ if (node.parent !== parentId) {
1199
+ node.parent = parentId;
1200
+ this.bufferForNodeUpdate(node);
1201
+ }
1166
1202
  break;
1167
1203
  }
1168
1204
  if (i + 1 === node.values.length) {
1169
1205
  node = this.getNode(k[i + 1]);
1206
+ if (node.parent !== parentId) {
1207
+ node.parent = parentId;
1208
+ this.bufferForNodeUpdate(node);
1209
+ }
1170
1210
  break;
1171
1211
  }
1172
1212
  }
@@ -1201,17 +1241,35 @@ var BPTreeSyncBase = class extends BPTree {
1201
1241
  }
1202
1242
  leftestNode() {
1203
1243
  let node = this.getNode(this.rootId);
1244
+ if (node.parent !== null) {
1245
+ node.parent = null;
1246
+ this.bufferForNodeUpdate(node);
1247
+ }
1204
1248
  while (!node.leaf) {
1249
+ const parentId = node.id;
1205
1250
  const keys = node.keys;
1206
1251
  node = this.getNode(keys[0]);
1252
+ if (node.parent !== parentId) {
1253
+ node.parent = parentId;
1254
+ this.bufferForNodeUpdate(node);
1255
+ }
1207
1256
  }
1208
1257
  return node;
1209
1258
  }
1210
1259
  rightestNode() {
1211
1260
  let node = this.getNode(this.rootId);
1261
+ if (node.parent !== null) {
1262
+ node.parent = null;
1263
+ this.bufferForNodeUpdate(node);
1264
+ }
1212
1265
  while (!node.leaf) {
1266
+ const parentId = node.id;
1213
1267
  const keys = node.keys;
1214
1268
  node = this.getNode(keys[keys.length - 1]);
1269
+ if (node.parent !== parentId) {
1270
+ node.parent = parentId;
1271
+ this.bufferForNodeUpdate(node);
1272
+ }
1215
1273
  }
1216
1274
  return node;
1217
1275
  }
@@ -1550,23 +1608,37 @@ var BPTreeSyncTransaction = class extends BPTreeSyncBase {
1550
1608
  realBaseTree;
1551
1609
  realBaseStrategy;
1552
1610
  txNodes = /* @__PURE__ */ new Map();
1553
- dirtyIds = /* @__PURE__ */ new Set();
1554
- createdInTx = /* @__PURE__ */ new Set();
1611
+ dirtyIds;
1612
+ createdInTx;
1613
+ deletedIds;
1555
1614
  initialRootId;
1556
1615
  transactionRootId;
1557
1616
  constructor(baseTree) {
1558
1617
  super(baseTree.strategy, baseTree.comparator, baseTree.option);
1559
1618
  this.realBaseTree = baseTree;
1560
1619
  this.realBaseStrategy = baseTree.strategy;
1620
+ this.order = baseTree.getOrder();
1561
1621
  this.initialRootId = "";
1562
1622
  this.transactionRootId = "";
1623
+ this.dirtyIds = /* @__PURE__ */ new Set();
1624
+ this.createdInTx = /* @__PURE__ */ new Set();
1625
+ this.deletedIds = /* @__PURE__ */ new Set();
1563
1626
  }
1564
1627
  /**
1565
1628
  * Initializes the transaction by capturing the current state of the tree.
1566
1629
  */
1567
1630
  initTransaction() {
1568
1631
  const head = this.realBaseStrategy.readHead();
1569
- this.initialRootId = head?.root ?? this.realBaseTree.rootId;
1632
+ if (head) {
1633
+ this.order = head.order;
1634
+ this.initialRootId = head.root;
1635
+ } else {
1636
+ this.initialRootId = this.realBaseTree.getRootId();
1637
+ }
1638
+ if (!this.initialRootId) {
1639
+ const root = this._createNode(true, [], [], true);
1640
+ this.initialRootId = root.id;
1641
+ }
1570
1642
  this.transactionRootId = this.initialRootId;
1571
1643
  this.rootId = this.transactionRootId;
1572
1644
  const snapshotStrategy = new BPTreeSyncSnapshotStrategy(this.realBaseStrategy, this.initialRootId);
@@ -1574,34 +1646,76 @@ var BPTreeSyncTransaction = class extends BPTreeSyncBase {
1574
1646
  this.txNodes.clear();
1575
1647
  this.dirtyIds.clear();
1576
1648
  this.createdInTx.clear();
1649
+ this.deletedIds.clear();
1577
1650
  }
1578
1651
  getNode(id) {
1579
1652
  if (this.txNodes.has(id)) {
1580
1653
  return this.txNodes.get(id);
1581
1654
  }
1655
+ if (this.deletedIds.has(id)) {
1656
+ throw new Error(`The tree attempted to reference deleted node '${id}'`);
1657
+ }
1582
1658
  const baseNode = this.realBaseStrategy.read(id);
1583
1659
  const clone = JSON.parse(JSON.stringify(baseNode));
1584
1660
  this.txNodes.set(id, clone);
1585
1661
  return clone;
1586
1662
  }
1587
1663
  bufferForNodeUpdate(node) {
1664
+ if (this.dirtyIds.has(node.id) && this.txNodes.has(node.id) && node._p) {
1665
+ this.txNodes.set(node.id, node);
1666
+ return;
1667
+ }
1668
+ node._p = true;
1588
1669
  this.txNodes.set(node.id, node);
1589
1670
  this.dirtyIds.add(node.id);
1671
+ if (node.leaf) {
1672
+ if (node.next && !this.dirtyIds.has(node.next) && !this.deletedIds.has(node.next)) {
1673
+ try {
1674
+ this.bufferForNodeUpdate(this.getNode(node.next));
1675
+ } catch (e) {
1676
+ }
1677
+ }
1678
+ if (node.prev && !this.dirtyIds.has(node.prev) && !this.deletedIds.has(node.prev)) {
1679
+ try {
1680
+ this.bufferForNodeUpdate(this.getNode(node.prev));
1681
+ } catch (e) {
1682
+ }
1683
+ }
1684
+ }
1590
1685
  this.markPathDirty(node);
1686
+ delete node._p;
1591
1687
  }
1592
1688
  bufferForNodeCreate(node) {
1593
1689
  this.txNodes.set(node.id, node);
1594
1690
  this.dirtyIds.add(node.id);
1595
1691
  this.createdInTx.add(node.id);
1692
+ if (node.leaf) {
1693
+ if (node.next && !this.dirtyIds.has(node.next) && !this.deletedIds.has(node.next)) {
1694
+ try {
1695
+ this.bufferForNodeUpdate(this.getNode(node.next));
1696
+ } catch (e) {
1697
+ }
1698
+ }
1699
+ if (node.prev && !this.dirtyIds.has(node.prev) && !this.deletedIds.has(node.prev)) {
1700
+ try {
1701
+ this.bufferForNodeUpdate(this.getNode(node.prev));
1702
+ } catch (e) {
1703
+ }
1704
+ }
1705
+ }
1596
1706
  this.markPathDirty(node);
1597
1707
  }
1598
1708
  bufferForNodeDelete(node) {
1599
1709
  this.txNodes.delete(node.id);
1600
1710
  this.dirtyIds.add(node.id);
1711
+ this.deletedIds.add(node.id);
1601
1712
  }
1602
1713
  markPathDirty(node) {
1603
1714
  let curr = node;
1604
1715
  while (curr.parent) {
1716
+ if (this.deletedIds.has(curr.parent)) {
1717
+ break;
1718
+ }
1605
1719
  if (this.dirtyIds.has(curr.parent) && this.txNodes.has(curr.parent)) {
1606
1720
  break;
1607
1721
  }
@@ -1613,13 +1727,13 @@ var BPTreeSyncTransaction = class extends BPTreeSyncBase {
1613
1727
  this.transactionRootId = curr.id;
1614
1728
  }
1615
1729
  }
1616
- _createNode(isLeaf, keys, values, leaf = false, parent = null, next = null, prev = null) {
1617
- const id = this.realBaseStrategy.id(isLeaf);
1730
+ _createNode(isLeaf, keys, values, leaf = isLeaf, parent = null, next = null, prev = null) {
1731
+ const id = this.strategy.id(isLeaf);
1618
1732
  const node = {
1619
1733
  id,
1620
1734
  keys,
1621
1735
  values,
1622
- leaf: isLeaf,
1736
+ leaf,
1623
1737
  parent,
1624
1738
  next,
1625
1739
  prev
@@ -1677,9 +1791,9 @@ var BPTreeSyncTransaction = class extends BPTreeSyncBase {
1677
1791
  finalNodes.push(node);
1678
1792
  newCreatedIds.push(newId);
1679
1793
  }
1680
- let newRootId = this.transactionRootId;
1681
- if (idMapping.has(this.transactionRootId)) {
1682
- newRootId = idMapping.get(this.transactionRootId);
1794
+ let newRootId = this.rootId;
1795
+ if (idMapping.has(this.rootId)) {
1796
+ newRootId = idMapping.get(this.rootId);
1683
1797
  }
1684
1798
  for (const node of finalNodes) {
1685
1799
  this.realBaseStrategy.write(node.id, node);
@@ -1708,12 +1822,21 @@ var BPTreeSyncTransaction = class extends BPTreeSyncBase {
1708
1822
  }
1709
1823
  /**
1710
1824
  * Rolls back the transaction by clearing all buffered changes.
1711
- * Internal use only.
1825
+ * If cleanup is `true`, it also clears the transaction nodes.
1826
+ * @param cleanup Whether to clear the transaction nodes.
1827
+ * @returns The IDs of nodes that were created in this transaction.
1712
1828
  */
1713
- rollback() {
1829
+ rollback(cleanup = true) {
1830
+ const createdIds = Array.from(this.createdInTx);
1714
1831
  this.txNodes.clear();
1715
1832
  this.dirtyIds.clear();
1716
1833
  this.createdInTx.clear();
1834
+ if (cleanup) {
1835
+ for (const id of createdIds) {
1836
+ this.realBaseStrategy.delete(id);
1837
+ }
1838
+ }
1839
+ return createdIds;
1717
1840
  }
1718
1841
  // Override to do nothing, as transaction handles its own commits
1719
1842
  commitHeadBuffer() {
@@ -1730,6 +1853,7 @@ var BPTreeSyncTransaction = class extends BPTreeSyncBase {
1730
1853
  var BPTreeSync = class extends BPTreeSyncBase {
1731
1854
  constructor(strategy, comparator, option) {
1732
1855
  super(strategy, comparator, option);
1856
+ this.init();
1733
1857
  }
1734
1858
  /**
1735
1859
  * Creates a new synchronous transaction.
@@ -1837,7 +1961,7 @@ var BPTreeAsyncBase = class extends BPTree {
1837
1961
  }
1838
1962
  return id;
1839
1963
  }
1840
- async _createNode(isLeaf, keys, values, leaf = false, parent = null, next = null, prev = null) {
1964
+ async _createNode(isLeaf, keys, values, leaf = isLeaf, parent = null, next = null, prev = null) {
1841
1965
  const id = await this._createNodeId(isLeaf);
1842
1966
  const node = {
1843
1967
  id,
@@ -1848,40 +1972,37 @@ var BPTreeAsyncBase = class extends BPTree {
1848
1972
  next,
1849
1973
  prev
1850
1974
  };
1851
- this._nodeCreateBuffer.set(id, node);
1975
+ await this.bufferForNodeCreate(node);
1852
1976
  return node;
1853
1977
  }
1854
1978
  async _deleteEntry(node, key, value) {
1855
1979
  if (!node.leaf) {
1980
+ let keyIndex = -1;
1856
1981
  for (let i = 0, len = node.keys.length; i < len; i++) {
1857
- const nKey = node.keys[i];
1858
- if (nKey === key) {
1859
- node.keys.splice(i, 1);
1860
- this.bufferForNodeUpdate(node);
1982
+ if (node.keys[i] === key) {
1983
+ keyIndex = i;
1861
1984
  break;
1862
1985
  }
1863
1986
  }
1864
- for (let i = 0, len = node.values.length; i < len; i++) {
1865
- const nValue = node.values[i];
1866
- if (this.comparator.isSame(value, nValue)) {
1867
- node.values.splice(i, 1);
1868
- this.bufferForNodeUpdate(node);
1869
- break;
1870
- }
1987
+ if (keyIndex !== -1) {
1988
+ node.keys.splice(keyIndex, 1);
1989
+ const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
1990
+ node.values.splice(valueIndex, 1);
1991
+ await this.bufferForNodeUpdate(node);
1871
1992
  }
1872
1993
  }
1873
1994
  if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
1874
1995
  const keys = node.keys;
1875
- this.bufferForNodeDelete(node);
1996
+ await this.bufferForNodeDelete(node);
1876
1997
  const newRoot = await this.getNode(keys[0]);
1877
1998
  this.rootId = newRoot.id;
1878
1999
  newRoot.parent = null;
1879
2000
  this.strategy.head.root = this.rootId;
1880
- this.bufferForNodeUpdate(newRoot);
2001
+ await this.bufferForNodeUpdate(newRoot);
1881
2002
  return;
1882
2003
  } else if (this.rootId === node.id) {
1883
2004
  const root = await this.getNode(this.rootId);
1884
- this.bufferForNodeUpdate(root);
2005
+ await this.bufferForNodeUpdate(root);
1885
2006
  return;
1886
2007
  } else if (node.keys.length < Math.ceil(this.order / 2) && !node.leaf || node.values.length < Math.ceil((this.order - 1) / 2) && node.leaf) {
1887
2008
  if (node.parent === null) {
@@ -1942,7 +2063,7 @@ var BPTreeAsyncBase = class extends BPTree {
1942
2063
  if (pointer.next) {
1943
2064
  const n = await this.getNode(pointer.next);
1944
2065
  n.prev = pointer.id;
1945
- this.bufferForNodeUpdate(n);
2066
+ await this.bufferForNodeUpdate(n);
1946
2067
  }
1947
2068
  }
1948
2069
  pointer.values.push(...node.values);
@@ -1951,12 +2072,12 @@ var BPTreeAsyncBase = class extends BPTree {
1951
2072
  for (const key2 of keys) {
1952
2073
  const n = await this.getNode(key2);
1953
2074
  n.parent = pointer.id;
1954
- this.bufferForNodeUpdate(n);
2075
+ await this.bufferForNodeUpdate(n);
1955
2076
  }
1956
2077
  }
1957
2078
  await this._deleteEntry(await this.getNode(node.parent), node.id, guess);
1958
- this.bufferForNodeUpdate(pointer);
1959
- this.bufferForNodeDelete(node);
2079
+ await this.bufferForNodeUpdate(pointer);
2080
+ await this.bufferForNodeDelete(node);
1960
2081
  } else {
1961
2082
  if (isPredecessor) {
1962
2083
  let pointerPm;
@@ -1967,13 +2088,10 @@ var BPTreeAsyncBase = class extends BPTree {
1967
2088
  node.keys = [pointerPm, ...node.keys];
1968
2089
  node.values = [guess, ...node.values];
1969
2090
  parentNode = await this.getNode(node.parent);
1970
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
1971
- const nValue = parentNode.values[i];
1972
- if (this.comparator.isSame(guess, nValue)) {
1973
- parentNode.values[i] = pointerKm;
1974
- this.bufferForNodeUpdate(parentNode);
1975
- break;
1976
- }
2091
+ const nodeIndex = parentNode.keys.indexOf(node.id);
2092
+ if (nodeIndex > 0) {
2093
+ parentNode.values[nodeIndex - 1] = pointerKm;
2094
+ await this.bufferForNodeUpdate(parentNode);
1977
2095
  }
1978
2096
  } else {
1979
2097
  pointerPm = pointer.keys.splice(-1)[0];
@@ -1981,17 +2099,14 @@ var BPTreeAsyncBase = class extends BPTree {
1981
2099
  node.keys = [pointerPm, ...node.keys];
1982
2100
  node.values = [pointerKm, ...node.values];
1983
2101
  parentNode = await this.getNode(node.parent);
1984
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
1985
- const nValue = parentNode.values[i];
1986
- if (this.comparator.isSame(guess, nValue)) {
1987
- parentNode.values[i] = pointerKm;
1988
- this.bufferForNodeUpdate(parentNode);
1989
- break;
1990
- }
2102
+ const nodeIndex = parentNode.keys.indexOf(node.id);
2103
+ if (nodeIndex > 0) {
2104
+ parentNode.values[nodeIndex - 1] = pointerKm;
2105
+ await this.bufferForNodeUpdate(parentNode);
1991
2106
  }
1992
2107
  }
1993
- this.bufferForNodeUpdate(node);
1994
- this.bufferForNodeUpdate(pointer);
2108
+ await this.bufferForNodeUpdate(node);
2109
+ await this.bufferForNodeUpdate(pointer);
1995
2110
  } else {
1996
2111
  let pointerP0;
1997
2112
  let pointerK0;
@@ -2001,13 +2116,10 @@ var BPTreeAsyncBase = class extends BPTree {
2001
2116
  node.keys = [...node.keys, pointerP0];
2002
2117
  node.values = [...node.values, guess];
2003
2118
  parentNode = await this.getNode(node.parent);
2004
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
2005
- const nValue = parentNode.values[i];
2006
- if (this.comparator.isSame(guess, nValue)) {
2007
- parentNode.values[i] = pointerK0;
2008
- this.bufferForNodeUpdate(parentNode);
2009
- break;
2010
- }
2119
+ const pointerIndex = parentNode.keys.indexOf(pointer.id);
2120
+ if (pointerIndex > 0) {
2121
+ parentNode.values[pointerIndex - 1] = pointerK0;
2122
+ await this.bufferForNodeUpdate(parentNode);
2011
2123
  }
2012
2124
  } else {
2013
2125
  pointerP0 = pointer.keys.splice(0, 1)[0];
@@ -2015,24 +2127,21 @@ var BPTreeAsyncBase = class extends BPTree {
2015
2127
  node.keys = [...node.keys, pointerP0];
2016
2128
  node.values = [...node.values, pointerK0];
2017
2129
  parentNode = await this.getNode(node.parent);
2018
- for (let i = 0, len = parentNode.values.length; i < len; i++) {
2019
- const nValue = parentNode.values[i];
2020
- if (this.comparator.isSame(guess, nValue)) {
2021
- parentNode.values[i] = pointer.values[0];
2022
- this.bufferForNodeUpdate(parentNode);
2023
- break;
2024
- }
2130
+ const pointerIndex = parentNode.keys.indexOf(pointer.id);
2131
+ if (pointerIndex > 0) {
2132
+ parentNode.values[pointerIndex - 1] = pointer.values[0];
2133
+ await this.bufferForNodeUpdate(parentNode);
2025
2134
  }
2026
2135
  }
2027
- this.bufferForNodeUpdate(node);
2028
- this.bufferForNodeUpdate(pointer);
2136
+ await this.bufferForNodeUpdate(node);
2137
+ await this.bufferForNodeUpdate(pointer);
2029
2138
  }
2030
2139
  if (!pointer.leaf) {
2031
2140
  const keys = pointer.keys;
2032
2141
  for (const key2 of keys) {
2033
2142
  const n = await this.getNode(key2);
2034
2143
  n.parent = pointer.id;
2035
- this.bufferForNodeUpdate(n);
2144
+ await this.bufferForNodeUpdate(n);
2036
2145
  }
2037
2146
  }
2038
2147
  if (!node.leaf) {
@@ -2040,7 +2149,7 @@ var BPTreeAsyncBase = class extends BPTree {
2040
2149
  for (const key2 of keys) {
2041
2150
  const n = await this.getNode(key2);
2042
2151
  n.parent = node.id;
2043
- this.bufferForNodeUpdate(n);
2152
+ await this.bufferForNodeUpdate(n);
2044
2153
  }
2045
2154
  }
2046
2155
  if (!parentNode.leaf) {
@@ -2048,10 +2157,12 @@ var BPTreeAsyncBase = class extends BPTree {
2048
2157
  for (const key2 of keys) {
2049
2158
  const n = await this.getNode(key2);
2050
2159
  n.parent = parentNode.id;
2051
- this.bufferForNodeUpdate(n);
2160
+ await this.bufferForNodeUpdate(n);
2052
2161
  }
2053
2162
  }
2054
2163
  }
2164
+ } else {
2165
+ await this.bufferForNodeUpdate(node);
2055
2166
  }
2056
2167
  }
2057
2168
  async _insertInParent(node, value, pointer) {
@@ -2062,43 +2173,39 @@ var BPTreeAsyncBase = class extends BPTree {
2062
2173
  node.parent = root.id;
2063
2174
  pointer.parent = root.id;
2064
2175
  if (pointer.leaf) {
2065
- node.next = pointer.id;
2066
- pointer.prev = node.id;
2176
+ const nNode = node;
2177
+ nNode.next = pointer.id;
2178
+ const nPointer = pointer;
2179
+ nPointer.prev = node.id;
2067
2180
  }
2068
- this.bufferForNodeUpdate(node);
2069
- this.bufferForNodeUpdate(pointer);
2181
+ await this.bufferForNodeUpdate(node);
2182
+ await this.bufferForNodeUpdate(pointer);
2070
2183
  return;
2071
2184
  }
2072
2185
  const parentNode = await this.getNode(node.parent);
2073
- let insertIndex = 0;
2074
- for (let i = 0; i < parentNode.values.length; i++) {
2075
- if (this.comparator.asc(value, parentNode.values[i]) > 0) {
2076
- insertIndex = i + 1;
2077
- } else {
2078
- break;
2079
- }
2186
+ const nodeIndex = parentNode.keys.indexOf(node.id);
2187
+ if (nodeIndex === -1) {
2188
+ throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
2080
2189
  }
2190
+ const insertIndex = nodeIndex;
2081
2191
  parentNode.values.splice(insertIndex, 0, value);
2082
2192
  parentNode.keys.splice(insertIndex + 1, 0, pointer.id);
2083
2193
  pointer.parent = parentNode.id;
2084
2194
  if (pointer.leaf) {
2085
- const leftSiblingId = parentNode.keys[insertIndex];
2086
- const rightSiblingId = parentNode.keys[insertIndex + 2];
2087
- if (leftSiblingId) {
2088
- const leftSibling = await this.getNode(leftSiblingId);
2089
- pointer.prev = leftSibling.id;
2090
- pointer.next = leftSibling.next;
2091
- leftSibling.next = pointer.id;
2092
- this.bufferForNodeUpdate(leftSibling);
2093
- }
2094
- if (rightSiblingId) {
2095
- const rightSibling = await this.getNode(rightSiblingId);
2096
- rightSibling.prev = pointer.id;
2097
- this.bufferForNodeUpdate(rightSibling);
2098
- }
2099
- }
2100
- this.bufferForNodeUpdate(parentNode);
2101
- this.bufferForNodeUpdate(pointer);
2195
+ const leftSibling = node;
2196
+ const oldNextId = leftSibling.next;
2197
+ pointer.prev = leftSibling.id;
2198
+ pointer.next = oldNextId;
2199
+ leftSibling.next = pointer.id;
2200
+ await this.bufferForNodeUpdate(leftSibling);
2201
+ if (oldNextId) {
2202
+ const oldNext = await this.getNode(oldNextId);
2203
+ oldNext.prev = pointer.id;
2204
+ await this.bufferForNodeUpdate(oldNext);
2205
+ }
2206
+ }
2207
+ await this.bufferForNodeUpdate(parentNode);
2208
+ await this.bufferForNodeUpdate(pointer);
2102
2209
  if (parentNode.keys.length > this.order) {
2103
2210
  const parentPointer = await this._createNode(false, [], []);
2104
2211
  parentPointer.parent = parentNode.parent;
@@ -2111,18 +2218,19 @@ var BPTreeAsyncBase = class extends BPTree {
2111
2218
  for (const k of parentNode.keys) {
2112
2219
  const n = await this.getNode(k);
2113
2220
  n.parent = parentNode.id;
2114
- this.bufferForNodeUpdate(n);
2221
+ await this.bufferForNodeUpdate(n);
2115
2222
  }
2116
2223
  for (const k of parentPointer.keys) {
2117
2224
  const n = await this.getNode(k);
2118
2225
  n.parent = parentPointer.id;
2119
- this.bufferForNodeUpdate(n);
2226
+ await this.bufferForNodeUpdate(n);
2120
2227
  }
2121
2228
  await this._insertInParent(parentNode, midValue, parentPointer);
2122
- this.bufferForNodeUpdate(parentNode);
2229
+ await this.bufferForNodeUpdate(parentNode);
2123
2230
  }
2124
2231
  }
2125
2232
  async init() {
2233
+ this.clear();
2126
2234
  const head = await this.strategy.readHead();
2127
2235
  if (head === null) {
2128
2236
  this.order = this.strategy.order;
@@ -2153,18 +2261,35 @@ var BPTreeAsyncBase = class extends BPTree {
2153
2261
  }
2154
2262
  async insertableNode(value) {
2155
2263
  let node = await this.getNode(this.rootId);
2264
+ if (node.parent !== null) {
2265
+ node.parent = null;
2266
+ await this.bufferForNodeUpdate(node);
2267
+ }
2156
2268
  while (!node.leaf) {
2269
+ const parentId = node.id;
2157
2270
  for (let i = 0, len = node.values.length; i < len; i++) {
2158
2271
  const nValue = node.values[i];
2159
2272
  const k = node.keys;
2160
2273
  if (this.comparator.isSame(value, nValue)) {
2161
2274
  node = await this.getNode(node.keys[i + 1]);
2275
+ if (node.parent !== parentId) {
2276
+ node.parent = parentId;
2277
+ await this.bufferForNodeUpdate(node);
2278
+ }
2162
2279
  break;
2163
2280
  } else if (this.comparator.isLower(value, nValue)) {
2164
2281
  node = await this.getNode(node.keys[i]);
2282
+ if (node.parent !== parentId) {
2283
+ node.parent = parentId;
2284
+ await this.bufferForNodeUpdate(node);
2285
+ }
2165
2286
  break;
2166
2287
  } else if (i + 1 === node.values.length) {
2167
2288
  node = await this.getNode(node.keys[i + 1]);
2289
+ if (node.parent !== parentId) {
2290
+ node.parent = parentId;
2291
+ await this.bufferForNodeUpdate(node);
2292
+ }
2168
2293
  break;
2169
2294
  }
2170
2295
  }
@@ -2173,18 +2298,35 @@ var BPTreeAsyncBase = class extends BPTree {
2173
2298
  }
2174
2299
  async insertableNodeByPrimary(value) {
2175
2300
  let node = await this.getNode(this.rootId);
2301
+ if (node.parent !== null) {
2302
+ node.parent = null;
2303
+ await this.bufferForNodeUpdate(node);
2304
+ }
2176
2305
  while (!node.leaf) {
2306
+ const parentId = node.id;
2177
2307
  for (let i = 0, len = node.values.length; i < len; i++) {
2178
2308
  const nValue = node.values[i];
2179
2309
  const k = node.keys;
2180
2310
  if (this.comparator.isPrimarySame(value, nValue)) {
2181
2311
  node = await this.getNode(node.keys[i]);
2312
+ if (node.parent !== parentId) {
2313
+ node.parent = parentId;
2314
+ await this.bufferForNodeUpdate(node);
2315
+ }
2182
2316
  break;
2183
2317
  } else if (this.comparator.isPrimaryLower(value, nValue)) {
2184
2318
  node = await this.getNode(node.keys[i]);
2319
+ if (node.parent !== parentId) {
2320
+ node.parent = parentId;
2321
+ await this.bufferForNodeUpdate(node);
2322
+ }
2185
2323
  break;
2186
2324
  } else if (i + 1 === node.values.length) {
2187
2325
  node = await this.getNode(node.keys[i + 1]);
2326
+ if (node.parent !== parentId) {
2327
+ node.parent = parentId;
2328
+ await this.bufferForNodeUpdate(node);
2329
+ }
2188
2330
  break;
2189
2331
  }
2190
2332
  }
@@ -2193,16 +2335,29 @@ var BPTreeAsyncBase = class extends BPTree {
2193
2335
  }
2194
2336
  async insertableRightestNodeByPrimary(value) {
2195
2337
  let node = await this.getNode(this.rootId);
2338
+ if (node.parent !== null) {
2339
+ node.parent = null;
2340
+ await this.bufferForNodeUpdate(node);
2341
+ }
2196
2342
  while (!node.leaf) {
2343
+ const parentId = node.id;
2197
2344
  for (let i = 0, len = node.values.length; i < len; i++) {
2198
2345
  const nValue = node.values[i];
2199
2346
  const k = node.keys;
2200
2347
  if (this.comparator.isPrimaryLower(value, nValue)) {
2201
2348
  node = await this.getNode(node.keys[i]);
2349
+ if (node.parent !== parentId) {
2350
+ node.parent = parentId;
2351
+ await this.bufferForNodeUpdate(node);
2352
+ }
2202
2353
  break;
2203
2354
  }
2204
2355
  if (i + 1 === node.values.length) {
2205
2356
  node = await this.getNode(node.keys[i + 1]);
2357
+ if (node.parent !== parentId) {
2358
+ node.parent = parentId;
2359
+ await this.bufferForNodeUpdate(node);
2360
+ }
2206
2361
  break;
2207
2362
  }
2208
2363
  }
@@ -2237,17 +2392,35 @@ var BPTreeAsyncBase = class extends BPTree {
2237
2392
  }
2238
2393
  async leftestNode() {
2239
2394
  let node = await this.getNode(this.rootId);
2395
+ if (node.parent !== null) {
2396
+ node.parent = null;
2397
+ await this.bufferForNodeUpdate(node);
2398
+ }
2240
2399
  while (!node.leaf) {
2400
+ const parentId = node.id;
2241
2401
  const keys = node.keys;
2242
2402
  node = await this.getNode(node.keys[0]);
2403
+ if (node.parent !== parentId) {
2404
+ node.parent = parentId;
2405
+ await this.bufferForNodeUpdate(node);
2406
+ }
2243
2407
  }
2244
2408
  return node;
2245
2409
  }
2246
2410
  async rightestNode() {
2247
2411
  let node = await this.getNode(this.rootId);
2412
+ if (node.parent !== null) {
2413
+ node.parent = null;
2414
+ await this.bufferForNodeUpdate(node);
2415
+ }
2248
2416
  while (!node.leaf) {
2417
+ const parentId = node.id;
2249
2418
  const keys = node.keys;
2250
2419
  node = await this.getNode(node.keys[node.keys.length - 1]);
2420
+ if (node.parent !== parentId) {
2421
+ node.parent = parentId;
2422
+ await this.bufferForNodeUpdate(node);
2423
+ }
2251
2424
  }
2252
2425
  return node;
2253
2426
  }
@@ -2407,7 +2580,7 @@ var BPTreeAsyncBase = class extends BPTree {
2407
2580
  async insert(key, value) {
2408
2581
  await this.writeLock(async () => {
2409
2582
  const before = await this.insertableNode(value);
2410
- this._insertAtLeaf(before, key, value);
2583
+ await this._insertAtLeaf(before, key, value);
2411
2584
  if (before.values.length === this.order) {
2412
2585
  const after = await this._createNode(
2413
2586
  true,
@@ -2424,7 +2597,7 @@ var BPTreeAsyncBase = class extends BPTree {
2424
2597
  before.values = before.values.slice(0, mid + 1);
2425
2598
  before.keys = before.keys.slice(0, mid + 1);
2426
2599
  await this._insertInParent(before, after.values[0], after);
2427
- this.bufferForNodeUpdate(before);
2600
+ await this.bufferForNodeUpdate(before);
2428
2601
  }
2429
2602
  await this.commitHeadBuffer();
2430
2603
  await this.commitNodeCreateBuffer();
@@ -2447,11 +2620,13 @@ var BPTreeAsyncBase = class extends BPTree {
2447
2620
  node.values.splice(i, 1);
2448
2621
  }
2449
2622
  await this._deleteEntry(node, key, value);
2623
+ await this.bufferForNodeUpdate(node);
2450
2624
  break;
2451
2625
  }
2452
2626
  }
2453
2627
  }
2454
2628
  await this.commitHeadBuffer();
2629
+ await this.commitNodeCreateBuffer();
2455
2630
  await this.commitNodeUpdateBuffer();
2456
2631
  await this.commitNodeDeleteBuffer();
2457
2632
  });
@@ -2577,23 +2752,37 @@ var BPTreeAsyncTransaction = class extends BPTreeAsyncBase {
2577
2752
  realBaseTree;
2578
2753
  realBaseStrategy;
2579
2754
  txNodes = /* @__PURE__ */ new Map();
2580
- dirtyIds = /* @__PURE__ */ new Set();
2581
- createdInTx = /* @__PURE__ */ new Set();
2755
+ dirtyIds;
2756
+ createdInTx;
2757
+ deletedIds;
2582
2758
  initialRootId;
2583
2759
  transactionRootId;
2584
2760
  constructor(baseTree) {
2585
2761
  super(baseTree.strategy, baseTree.comparator, baseTree.option);
2586
2762
  this.realBaseTree = baseTree;
2587
2763
  this.realBaseStrategy = baseTree.strategy;
2764
+ this.order = baseTree.getOrder();
2588
2765
  this.initialRootId = "";
2589
2766
  this.transactionRootId = "";
2767
+ this.dirtyIds = /* @__PURE__ */ new Set();
2768
+ this.createdInTx = /* @__PURE__ */ new Set();
2769
+ this.deletedIds = /* @__PURE__ */ new Set();
2590
2770
  }
2591
2771
  /**
2592
2772
  * Initializes the transaction by capturing the current state of the tree.
2593
2773
  */
2594
2774
  async initTransaction() {
2595
2775
  const head = await this.realBaseStrategy.readHead();
2596
- this.initialRootId = head?.root ?? this.realBaseTree.rootId;
2776
+ if (head) {
2777
+ this.order = head.order;
2778
+ this.initialRootId = head.root;
2779
+ } else {
2780
+ this.initialRootId = this.realBaseTree.getRootId();
2781
+ }
2782
+ if (!this.initialRootId) {
2783
+ const root = await this._createNode(true, [], [], true);
2784
+ this.initialRootId = root.id;
2785
+ }
2597
2786
  this.transactionRootId = this.initialRootId;
2598
2787
  this.rootId = this.transactionRootId;
2599
2788
  const snapshotStrategy = new BPTreeAsyncSnapshotStrategy(this.realBaseStrategy, this.initialRootId);
@@ -2601,34 +2790,76 @@ var BPTreeAsyncTransaction = class extends BPTreeAsyncBase {
2601
2790
  this.txNodes.clear();
2602
2791
  this.dirtyIds.clear();
2603
2792
  this.createdInTx.clear();
2793
+ this.deletedIds.clear();
2604
2794
  }
2605
2795
  async getNode(id) {
2606
2796
  if (this.txNodes.has(id)) {
2607
2797
  return this.txNodes.get(id);
2608
2798
  }
2799
+ if (this.deletedIds.has(id)) {
2800
+ throw new Error(`The tree attempted to reference deleted node '${id}'`);
2801
+ }
2609
2802
  const baseNode = await this.realBaseStrategy.read(id);
2610
2803
  const clone = JSON.parse(JSON.stringify(baseNode));
2611
2804
  this.txNodes.set(id, clone);
2612
2805
  return clone;
2613
2806
  }
2614
2807
  async bufferForNodeUpdate(node) {
2808
+ if (this.dirtyIds.has(node.id) && this.txNodes.has(node.id) && node._p) {
2809
+ this.txNodes.set(node.id, node);
2810
+ return;
2811
+ }
2812
+ node._p = true;
2615
2813
  this.txNodes.set(node.id, node);
2616
2814
  this.dirtyIds.add(node.id);
2815
+ if (node.leaf) {
2816
+ if (node.next && !this.dirtyIds.has(node.next) && !this.deletedIds.has(node.next)) {
2817
+ try {
2818
+ await this.bufferForNodeUpdate(await this.getNode(node.next));
2819
+ } catch (e) {
2820
+ }
2821
+ }
2822
+ if (node.prev && !this.dirtyIds.has(node.prev) && !this.deletedIds.has(node.prev)) {
2823
+ try {
2824
+ await this.bufferForNodeUpdate(await this.getNode(node.prev));
2825
+ } catch (e) {
2826
+ }
2827
+ }
2828
+ }
2617
2829
  await this.markPathDirty(node);
2830
+ delete node._p;
2618
2831
  }
2619
2832
  async bufferForNodeCreate(node) {
2620
2833
  this.txNodes.set(node.id, node);
2621
2834
  this.dirtyIds.add(node.id);
2622
2835
  this.createdInTx.add(node.id);
2836
+ if (node.leaf) {
2837
+ if (node.next && !this.dirtyIds.has(node.next) && !this.deletedIds.has(node.next)) {
2838
+ try {
2839
+ await this.bufferForNodeUpdate(await this.getNode(node.next));
2840
+ } catch (e) {
2841
+ }
2842
+ }
2843
+ if (node.prev && !this.dirtyIds.has(node.prev) && !this.deletedIds.has(node.prev)) {
2844
+ try {
2845
+ await this.bufferForNodeUpdate(await this.getNode(node.prev));
2846
+ } catch (e) {
2847
+ }
2848
+ }
2849
+ }
2623
2850
  await this.markPathDirty(node);
2624
2851
  }
2625
2852
  async bufferForNodeDelete(node) {
2626
2853
  this.txNodes.delete(node.id);
2627
2854
  this.dirtyIds.add(node.id);
2855
+ this.deletedIds.add(node.id);
2628
2856
  }
2629
2857
  async markPathDirty(node) {
2630
2858
  let curr = node;
2631
2859
  while (curr.parent) {
2860
+ if (this.deletedIds.has(curr.parent)) {
2861
+ break;
2862
+ }
2632
2863
  if (this.dirtyIds.has(curr.parent) && this.txNodes.has(curr.parent)) {
2633
2864
  break;
2634
2865
  }
@@ -2640,13 +2871,13 @@ var BPTreeAsyncTransaction = class extends BPTreeAsyncBase {
2640
2871
  this.transactionRootId = curr.id;
2641
2872
  }
2642
2873
  }
2643
- async _createNode(isLeaf, keys, values, leaf = false, parent = null, next = null, prev = null) {
2644
- const id = await this.realBaseStrategy.id(isLeaf);
2874
+ async _createNode(isLeaf, keys, values, leaf = isLeaf, parent = null, next = null, prev = null) {
2875
+ const id = await this.strategy.id(isLeaf);
2645
2876
  const node = {
2646
2877
  id,
2647
2878
  keys,
2648
2879
  values,
2649
- leaf: isLeaf,
2880
+ leaf,
2650
2881
  parent,
2651
2882
  next,
2652
2883
  prev
@@ -2704,9 +2935,9 @@ var BPTreeAsyncTransaction = class extends BPTreeAsyncBase {
2704
2935
  finalNodes.push(node);
2705
2936
  newCreatedIds.push(newId);
2706
2937
  }
2707
- let newRootId = this.transactionRootId;
2708
- if (idMapping.has(this.transactionRootId)) {
2709
- newRootId = idMapping.get(this.transactionRootId);
2938
+ let newRootId = this.rootId;
2939
+ if (idMapping.has(this.rootId)) {
2940
+ newRootId = idMapping.get(this.rootId);
2710
2941
  }
2711
2942
  for (const node of finalNodes) {
2712
2943
  await this.realBaseStrategy.write(node.id, node);
@@ -2735,12 +2966,21 @@ var BPTreeAsyncTransaction = class extends BPTreeAsyncBase {
2735
2966
  }
2736
2967
  /**
2737
2968
  * Rolls back the transaction by clearing all buffered changes.
2738
- * Internal use only.
2969
+ * If cleanup is `true`, it also clears the transaction nodes.
2970
+ * @param cleanup Whether to clear the transaction nodes.
2971
+ * @returns The IDs of nodes that were created in this transaction.
2739
2972
  */
2740
- async rollback() {
2973
+ async rollback(cleanup = true) {
2974
+ const createdIds = Array.from(this.createdInTx);
2741
2975
  this.txNodes.clear();
2742
2976
  this.dirtyIds.clear();
2743
2977
  this.createdInTx.clear();
2978
+ if (cleanup) {
2979
+ for (const id of createdIds) {
2980
+ await this.realBaseStrategy.delete(id);
2981
+ }
2982
+ }
2983
+ return createdIds;
2744
2984
  }
2745
2985
  async readLock(fn) {
2746
2986
  return await fn();