serializable-bptree 5.2.1 → 6.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,7 +15,7 @@ import {
15
15
 
16
16
  class FileStoreStrategySync extends SerializeStrategySync<K, V> {
17
17
  id(): string {
18
- return this.autoIncrement('index', 1).toString()
18
+ return crypto.randomUUID()
19
19
  }
20
20
 
21
21
  read(id: string): BPTreeNode<K, V> {
@@ -105,10 +105,19 @@ import {
105
105
  ValueComparator,
106
106
  NumericComparator,
107
107
  StringComparator
108
- } from 'https://cdn.jsdelivr.net/npm/serializable-bptree@5/+esm'
108
+ } from 'https://cdn.jsdelivr.com/npm/serializable-bptree@6/+esm'
109
109
  </script>
110
110
  ```
111
111
 
112
+ ## Migration from v5.x.x to v6.0.0
113
+
114
+ Version 6.0.0 includes a critical fix for how internal nodes are sorted.
115
+
116
+ > [!IMPORTANT]
117
+ > **Breaking Changes & Incompatibility**
118
+ > In previous versions, internal nodes were not strictly sorted by value magnitude, which could lead to incorrect traversals and failed queries (especially for the last nodes in a branch).
119
+ > v6.0.0 enforces strict value sorting. **Data structures created with v5.x.x or earlier may be incompatible** with v6.0.0 if they contain unsorted internal nodes. It is highly recommended to rebuild your tree from scratch when upgrading.
120
+
112
121
  ## Conceptualization
113
122
 
114
123
  ### Value comparator
@@ -199,21 +208,11 @@ What does this method mean? And why do we need to construct such a method?
199
208
 
200
209
  When a node is created in the B+tree, the node needs a unique value to represent itself. This is the **node.id** attribute, and you can specify this attribute yourself.
201
210
 
202
- Typically, such an **id** value increases sequentially, and it would be beneficial to store such a value separately within the tree. For that purpose, the **setHeadData** and **getHeadData** methods are available. These methods are responsible for storing arbitrary data in the tree's header or retrieving stored data. Below is an example of usage:
203
-
204
- ```typescript
205
- id(isLeaf: boolean): string {
206
- const current = this.getHeadData('index', 1) as number
207
- this.setHeadData('index', current+1)
208
- return current.toString()
209
- }
210
- ```
211
-
212
- Additionally, there is a more dev-friendly usage of this code.
211
+ Typically, such an **id** value can be a unique string like a UUID. Below is an example of usage:
213
212
 
214
213
  ```typescript
215
214
  id(isLeaf: boolean): string {
216
- return this.autoIncrement('index', 1).toString()
215
+ return crypto.randomUUID()
217
216
  }
218
217
  ```
219
218
 
@@ -415,7 +414,7 @@ import {
415
414
 
416
415
  class FileStoreStrategyAsync extends SerializeStrategyAsync<K, V> {
417
416
  async id(isLeaf: boolean): Promise<string> {
418
- return await this.autoIncrement('index', 1).toString()
417
+ return crypto.randomUUID()
419
418
  }
420
419
 
421
420
  async read(id: string): Promise<BPTreeNode<K, V>> {
@@ -473,9 +472,11 @@ The implementation method for asynchronous operations is not significantly diffe
473
472
 
474
473
  ### Synchronization Issue
475
474
 
476
- The serializable-bptree minimizes file I/O by storing loaded nodes in-memory. This approach works well in situations where there is a 1:1 relationship between the remote storage and the client. However, in a 1:n scenario, where multiple clients read from and write to a single remote storage, data inconsistency between the remote storage and the clients can occur.
475
+ The serializable-bptree minimizes file I/O by storing loaded nodes in-memory (caching). This approach works perfectly when a single tree instance is used for a given storage.
476
+
477
+ However, if **multiple BPTree instances** (e.g., across different processes or servers) read from and write to a **single shared storage**, data inconsistency can occur. This is because each instance maintains its own independent in-memory cache, and changes made by one instance are not automatically reflected in the others.
477
478
 
478
- To solve this problem, it's necessary to update the cached nodes. The forceUpdate method was created for this purpose. It fetches the node data cached in the tree instance again. To use this feature, when you save data to the remote storage, you must send a signal to all clients connected to that remote storage indicating that the node has been updated. Clients must receive this signal and configure logic to call the **forceUpdate** method; however, this goes beyond the scope of the library, so you must implement it yourself.
479
+ To solve this problem, you must synchronize the cached nodes across all instances. The `forceUpdate` method can be used to refresh the nodes cached in a tree instance. When one instance saves data to the shared storage, you should implement a signaling mechanism (e.g., via Pub/Sub or WebSockets) to notify other instances that a node has been updated. Upon receiving this signal, the other instances should call the `forceUpdate` method to ensure they are working with the latest data.
479
480
 
480
481
  ### Concurrency Issue in Asynchronous Trees
481
482
 
@@ -769,6 +769,9 @@ var BPTreeSync = class extends BPTree {
769
769
  guess = prevValue;
770
770
  }
771
771
  }
772
+ if (!pointer) {
773
+ return;
774
+ }
772
775
  if (node.values.length + pointer.values.length < this.order) {
773
776
  if (!isPredecessor) {
774
777
  const pTemp = pointer;
@@ -908,44 +911,65 @@ var BPTreeSync = class extends BPTree {
908
911
  this.strategy.head.root = root.id;
909
912
  node.parent = root.id;
910
913
  pointer.parent = root.id;
914
+ if (pointer.leaf) {
915
+ node.next = pointer.id;
916
+ pointer.prev = node.id;
917
+ }
911
918
  this.bufferForNodeUpdate(node);
912
919
  this.bufferForNodeUpdate(pointer);
913
920
  return;
914
921
  }
915
922
  const parentNode = this.getNode(node.parent);
916
- for (let i = 0, len = parentNode.keys.length; i < len; i++) {
917
- const nKeys = parentNode.keys[i];
918
- if (nKeys === node.id) {
919
- parentNode.values.splice(i, 0, value);
920
- parentNode.keys.splice(i + 1, 0, pointer.id);
921
- this.bufferForNodeUpdate(parentNode);
922
- if (parentNode.keys.length > this.order) {
923
- const parentPointer = this._createNode(false, [], []);
924
- parentPointer.parent = parentNode.parent;
925
- const mid = Math.ceil(this.order / 2) - 1;
926
- parentPointer.values = parentNode.values.slice(mid + 1);
927
- parentPointer.keys = parentNode.keys.slice(mid + 1);
928
- const midValue = parentNode.values[mid];
929
- if (mid === 0) {
930
- parentNode.values = parentNode.values.slice(0, mid + 1);
931
- } else {
932
- parentNode.values = parentNode.values.slice(0, mid);
933
- }
934
- parentNode.keys = parentNode.keys.slice(0, mid + 1);
935
- for (const k of parentNode.keys) {
936
- const node2 = this.getNode(k);
937
- node2.parent = parentNode.id;
938
- this.bufferForNodeUpdate(node2);
939
- }
940
- for (const k of parentPointer.keys) {
941
- const node2 = this.getNode(k);
942
- node2.parent = parentPointer.id;
943
- this.bufferForNodeUpdate(node2);
944
- }
945
- this._insertInParent(parentNode, midValue, parentPointer);
946
- this.bufferForNodeUpdate(parentNode);
947
- }
923
+ let insertIndex = 0;
924
+ for (let i = 0; i < parentNode.values.length; i++) {
925
+ if (this.comparator.asc(value, parentNode.values[i]) > 0) {
926
+ insertIndex = i + 1;
927
+ } else {
928
+ break;
929
+ }
930
+ }
931
+ parentNode.values.splice(insertIndex, 0, value);
932
+ parentNode.keys.splice(insertIndex + 1, 0, pointer.id);
933
+ pointer.parent = parentNode.id;
934
+ if (pointer.leaf) {
935
+ const leftSiblingId = parentNode.keys[insertIndex];
936
+ const rightSiblingId = parentNode.keys[insertIndex + 2];
937
+ if (leftSiblingId) {
938
+ const leftSibling = this.getNode(leftSiblingId);
939
+ pointer.prev = leftSibling.id;
940
+ pointer.next = leftSibling.next;
941
+ leftSibling.next = pointer.id;
942
+ this.bufferForNodeUpdate(leftSibling);
943
+ }
944
+ if (rightSiblingId) {
945
+ const rightSibling = this.getNode(rightSiblingId);
946
+ rightSibling.prev = pointer.id;
947
+ this.bufferForNodeUpdate(rightSibling);
948
+ }
949
+ }
950
+ this.bufferForNodeUpdate(parentNode);
951
+ this.bufferForNodeUpdate(pointer);
952
+ if (parentNode.keys.length > this.order) {
953
+ const parentPointer = this._createNode(false, [], []);
954
+ parentPointer.parent = parentNode.parent;
955
+ const mid = Math.ceil(this.order / 2) - 1;
956
+ parentPointer.values = parentNode.values.slice(mid + 1);
957
+ parentPointer.keys = parentNode.keys.slice(mid + 1);
958
+ const midValue = parentNode.values[mid];
959
+ parentNode.values = parentNode.values.slice(0, mid);
960
+ parentNode.keys = parentNode.keys.slice(0, mid + 1);
961
+ for (const k of parentNode.keys) {
962
+ const node2 = this.getNode(k);
963
+ node2.parent = parentNode.id;
964
+ this.bufferForNodeUpdate(node2);
965
+ }
966
+ for (const k of parentPointer.keys) {
967
+ const node2 = this.getNode(k);
968
+ node2.parent = parentPointer.id;
969
+ this.bufferForNodeUpdate(node2);
948
970
  }
971
+ this._insertInParent(parentNode, midValue, parentPointer);
972
+ this.bufferForNodeUpdate(parentNode);
949
973
  }
950
974
  }
951
975
  init() {
@@ -1111,21 +1135,14 @@ var BPTreeSync = class extends BPTree {
1111
1135
  [],
1112
1136
  true,
1113
1137
  before.parent,
1114
- before.next,
1115
- before.id
1138
+ null,
1139
+ null
1116
1140
  );
1117
1141
  const mid = Math.ceil(this.order / 2) - 1;
1118
- const beforeNext = before.next;
1119
1142
  after.values = before.values.slice(mid + 1);
1120
1143
  after.keys = before.keys.slice(mid + 1);
1121
1144
  before.values = before.values.slice(0, mid + 1);
1122
1145
  before.keys = before.keys.slice(0, mid + 1);
1123
- before.next = after.id;
1124
- if (beforeNext) {
1125
- const node = this.getNode(beforeNext);
1126
- node.prev = after.id;
1127
- this.bufferForNodeUpdate(node);
1128
- }
1129
1146
  this._insertInParent(before, after.values[0], after);
1130
1147
  this.bufferForNodeUpdate(before);
1131
1148
  }
@@ -1639,6 +1656,9 @@ var BPTreeAsync = class extends BPTree {
1639
1656
  guess = prevValue;
1640
1657
  }
1641
1658
  }
1659
+ if (!pointer) {
1660
+ return;
1661
+ }
1642
1662
  if (node.values.length + pointer.values.length < this.order) {
1643
1663
  if (!isPredecessor) {
1644
1664
  const pTemp = pointer;
@@ -1778,44 +1798,65 @@ var BPTreeAsync = class extends BPTree {
1778
1798
  this.strategy.head.root = root.id;
1779
1799
  node.parent = root.id;
1780
1800
  pointer.parent = root.id;
1801
+ if (pointer.leaf) {
1802
+ node.next = pointer.id;
1803
+ pointer.prev = node.id;
1804
+ }
1781
1805
  this.bufferForNodeUpdate(node);
1782
1806
  this.bufferForNodeUpdate(pointer);
1783
1807
  return;
1784
1808
  }
1785
1809
  const parentNode = await this.getNode(node.parent);
1786
- for (let i = 0, len = parentNode.keys.length; i < len; i++) {
1787
- const nKeys = parentNode.keys[i];
1788
- if (nKeys === node.id) {
1789
- parentNode.values.splice(i, 0, value);
1790
- parentNode.keys.splice(i + 1, 0, pointer.id);
1791
- this.bufferForNodeUpdate(parentNode);
1792
- if (parentNode.keys.length > this.order) {
1793
- const parentPointer = await this._createNode(false, [], []);
1794
- parentPointer.parent = parentNode.parent;
1795
- const mid = Math.ceil(this.order / 2) - 1;
1796
- parentPointer.values = parentNode.values.slice(mid + 1);
1797
- parentPointer.keys = parentNode.keys.slice(mid + 1);
1798
- const midValue = parentNode.values[mid];
1799
- if (mid === 0) {
1800
- parentNode.values = parentNode.values.slice(0, mid + 1);
1801
- } else {
1802
- parentNode.values = parentNode.values.slice(0, mid);
1803
- }
1804
- parentNode.keys = parentNode.keys.slice(0, mid + 1);
1805
- for (const k of parentNode.keys) {
1806
- const node2 = await this.getNode(k);
1807
- node2.parent = parentNode.id;
1808
- this.bufferForNodeUpdate(node2);
1809
- }
1810
- for (const k of parentPointer.keys) {
1811
- const node2 = await this.getNode(k);
1812
- node2.parent = parentPointer.id;
1813
- this.bufferForNodeUpdate(node2);
1814
- }
1815
- await this._insertInParent(parentNode, midValue, parentPointer);
1816
- this.bufferForNodeUpdate(parentNode);
1817
- }
1810
+ let insertIndex = 0;
1811
+ for (let i = 0; i < parentNode.values.length; i++) {
1812
+ if (this.comparator.asc(value, parentNode.values[i]) > 0) {
1813
+ insertIndex = i + 1;
1814
+ } else {
1815
+ break;
1816
+ }
1817
+ }
1818
+ parentNode.values.splice(insertIndex, 0, value);
1819
+ parentNode.keys.splice(insertIndex + 1, 0, pointer.id);
1820
+ pointer.parent = parentNode.id;
1821
+ if (pointer.leaf) {
1822
+ const leftSiblingId = parentNode.keys[insertIndex];
1823
+ const rightSiblingId = parentNode.keys[insertIndex + 2];
1824
+ if (leftSiblingId) {
1825
+ const leftSibling = await this.getNode(leftSiblingId);
1826
+ pointer.prev = leftSibling.id;
1827
+ pointer.next = leftSibling.next;
1828
+ leftSibling.next = pointer.id;
1829
+ this.bufferForNodeUpdate(leftSibling);
1830
+ }
1831
+ if (rightSiblingId) {
1832
+ const rightSibling = await this.getNode(rightSiblingId);
1833
+ rightSibling.prev = pointer.id;
1834
+ this.bufferForNodeUpdate(rightSibling);
1835
+ }
1836
+ }
1837
+ this.bufferForNodeUpdate(parentNode);
1838
+ this.bufferForNodeUpdate(pointer);
1839
+ if (parentNode.keys.length > this.order) {
1840
+ const parentPointer = await this._createNode(false, [], []);
1841
+ parentPointer.parent = parentNode.parent;
1842
+ const mid = Math.ceil(this.order / 2) - 1;
1843
+ parentPointer.values = parentNode.values.slice(mid + 1);
1844
+ parentPointer.keys = parentNode.keys.slice(mid + 1);
1845
+ const midValue = parentNode.values[mid];
1846
+ parentNode.values = parentNode.values.slice(0, mid);
1847
+ parentNode.keys = parentNode.keys.slice(0, mid + 1);
1848
+ for (const k of parentNode.keys) {
1849
+ const node2 = await this.getNode(k);
1850
+ node2.parent = parentNode.id;
1851
+ this.bufferForNodeUpdate(node2);
1852
+ }
1853
+ for (const k of parentPointer.keys) {
1854
+ const node2 = await this.getNode(k);
1855
+ node2.parent = parentPointer.id;
1856
+ this.bufferForNodeUpdate(node2);
1818
1857
  }
1858
+ await this._insertInParent(parentNode, midValue, parentPointer);
1859
+ this.bufferForNodeUpdate(parentNode);
1819
1860
  }
1820
1861
  }
1821
1862
  async init() {
@@ -1986,21 +2027,14 @@ var BPTreeAsync = class extends BPTree {
1986
2027
  [],
1987
2028
  true,
1988
2029
  before.parent,
1989
- before.next,
1990
- before.id
2030
+ null,
2031
+ null
1991
2032
  );
1992
2033
  const mid = Math.ceil(this.order / 2) - 1;
1993
- const beforeNext = before.next;
1994
2034
  after.values = before.values.slice(mid + 1);
1995
2035
  after.keys = before.keys.slice(mid + 1);
1996
2036
  before.values = before.values.slice(0, mid + 1);
1997
2037
  before.keys = before.keys.slice(0, mid + 1);
1998
- before.next = after.id;
1999
- if (beforeNext) {
2000
- const node = await this.getNode(beforeNext);
2001
- node.prev = after.id;
2002
- this.bufferForNodeUpdate(node);
2003
- }
2004
2038
  await this._insertInParent(before, after.values[0], after);
2005
2039
  this.bufferForNodeUpdate(before);
2006
2040
  }
@@ -735,6 +735,9 @@ var BPTreeSync = class extends BPTree {
735
735
  guess = prevValue;
736
736
  }
737
737
  }
738
+ if (!pointer) {
739
+ return;
740
+ }
738
741
  if (node.values.length + pointer.values.length < this.order) {
739
742
  if (!isPredecessor) {
740
743
  const pTemp = pointer;
@@ -874,44 +877,65 @@ var BPTreeSync = class extends BPTree {
874
877
  this.strategy.head.root = root.id;
875
878
  node.parent = root.id;
876
879
  pointer.parent = root.id;
880
+ if (pointer.leaf) {
881
+ node.next = pointer.id;
882
+ pointer.prev = node.id;
883
+ }
877
884
  this.bufferForNodeUpdate(node);
878
885
  this.bufferForNodeUpdate(pointer);
879
886
  return;
880
887
  }
881
888
  const parentNode = this.getNode(node.parent);
882
- for (let i = 0, len = parentNode.keys.length; i < len; i++) {
883
- const nKeys = parentNode.keys[i];
884
- if (nKeys === node.id) {
885
- parentNode.values.splice(i, 0, value);
886
- parentNode.keys.splice(i + 1, 0, pointer.id);
887
- this.bufferForNodeUpdate(parentNode);
888
- if (parentNode.keys.length > this.order) {
889
- const parentPointer = this._createNode(false, [], []);
890
- parentPointer.parent = parentNode.parent;
891
- const mid = Math.ceil(this.order / 2) - 1;
892
- parentPointer.values = parentNode.values.slice(mid + 1);
893
- parentPointer.keys = parentNode.keys.slice(mid + 1);
894
- const midValue = parentNode.values[mid];
895
- if (mid === 0) {
896
- parentNode.values = parentNode.values.slice(0, mid + 1);
897
- } else {
898
- parentNode.values = parentNode.values.slice(0, mid);
899
- }
900
- parentNode.keys = parentNode.keys.slice(0, mid + 1);
901
- for (const k of parentNode.keys) {
902
- const node2 = this.getNode(k);
903
- node2.parent = parentNode.id;
904
- this.bufferForNodeUpdate(node2);
905
- }
906
- for (const k of parentPointer.keys) {
907
- const node2 = this.getNode(k);
908
- node2.parent = parentPointer.id;
909
- this.bufferForNodeUpdate(node2);
910
- }
911
- this._insertInParent(parentNode, midValue, parentPointer);
912
- this.bufferForNodeUpdate(parentNode);
913
- }
889
+ let insertIndex = 0;
890
+ for (let i = 0; i < parentNode.values.length; i++) {
891
+ if (this.comparator.asc(value, parentNode.values[i]) > 0) {
892
+ insertIndex = i + 1;
893
+ } else {
894
+ break;
895
+ }
896
+ }
897
+ parentNode.values.splice(insertIndex, 0, value);
898
+ parentNode.keys.splice(insertIndex + 1, 0, pointer.id);
899
+ pointer.parent = parentNode.id;
900
+ if (pointer.leaf) {
901
+ const leftSiblingId = parentNode.keys[insertIndex];
902
+ const rightSiblingId = parentNode.keys[insertIndex + 2];
903
+ if (leftSiblingId) {
904
+ const leftSibling = this.getNode(leftSiblingId);
905
+ pointer.prev = leftSibling.id;
906
+ pointer.next = leftSibling.next;
907
+ leftSibling.next = pointer.id;
908
+ this.bufferForNodeUpdate(leftSibling);
909
+ }
910
+ if (rightSiblingId) {
911
+ const rightSibling = this.getNode(rightSiblingId);
912
+ rightSibling.prev = pointer.id;
913
+ this.bufferForNodeUpdate(rightSibling);
914
+ }
915
+ }
916
+ this.bufferForNodeUpdate(parentNode);
917
+ this.bufferForNodeUpdate(pointer);
918
+ if (parentNode.keys.length > this.order) {
919
+ const parentPointer = this._createNode(false, [], []);
920
+ parentPointer.parent = parentNode.parent;
921
+ const mid = Math.ceil(this.order / 2) - 1;
922
+ parentPointer.values = parentNode.values.slice(mid + 1);
923
+ parentPointer.keys = parentNode.keys.slice(mid + 1);
924
+ const midValue = parentNode.values[mid];
925
+ parentNode.values = parentNode.values.slice(0, mid);
926
+ parentNode.keys = parentNode.keys.slice(0, mid + 1);
927
+ for (const k of parentNode.keys) {
928
+ const node2 = this.getNode(k);
929
+ node2.parent = parentNode.id;
930
+ this.bufferForNodeUpdate(node2);
931
+ }
932
+ for (const k of parentPointer.keys) {
933
+ const node2 = this.getNode(k);
934
+ node2.parent = parentPointer.id;
935
+ this.bufferForNodeUpdate(node2);
914
936
  }
937
+ this._insertInParent(parentNode, midValue, parentPointer);
938
+ this.bufferForNodeUpdate(parentNode);
915
939
  }
916
940
  }
917
941
  init() {
@@ -1077,21 +1101,14 @@ var BPTreeSync = class extends BPTree {
1077
1101
  [],
1078
1102
  true,
1079
1103
  before.parent,
1080
- before.next,
1081
- before.id
1104
+ null,
1105
+ null
1082
1106
  );
1083
1107
  const mid = Math.ceil(this.order / 2) - 1;
1084
- const beforeNext = before.next;
1085
1108
  after.values = before.values.slice(mid + 1);
1086
1109
  after.keys = before.keys.slice(mid + 1);
1087
1110
  before.values = before.values.slice(0, mid + 1);
1088
1111
  before.keys = before.keys.slice(0, mid + 1);
1089
- before.next = after.id;
1090
- if (beforeNext) {
1091
- const node = this.getNode(beforeNext);
1092
- node.prev = after.id;
1093
- this.bufferForNodeUpdate(node);
1094
- }
1095
1112
  this._insertInParent(before, after.values[0], after);
1096
1113
  this.bufferForNodeUpdate(before);
1097
1114
  }
@@ -1605,6 +1622,9 @@ var BPTreeAsync = class extends BPTree {
1605
1622
  guess = prevValue;
1606
1623
  }
1607
1624
  }
1625
+ if (!pointer) {
1626
+ return;
1627
+ }
1608
1628
  if (node.values.length + pointer.values.length < this.order) {
1609
1629
  if (!isPredecessor) {
1610
1630
  const pTemp = pointer;
@@ -1744,44 +1764,65 @@ var BPTreeAsync = class extends BPTree {
1744
1764
  this.strategy.head.root = root.id;
1745
1765
  node.parent = root.id;
1746
1766
  pointer.parent = root.id;
1767
+ if (pointer.leaf) {
1768
+ node.next = pointer.id;
1769
+ pointer.prev = node.id;
1770
+ }
1747
1771
  this.bufferForNodeUpdate(node);
1748
1772
  this.bufferForNodeUpdate(pointer);
1749
1773
  return;
1750
1774
  }
1751
1775
  const parentNode = await this.getNode(node.parent);
1752
- for (let i = 0, len = parentNode.keys.length; i < len; i++) {
1753
- const nKeys = parentNode.keys[i];
1754
- if (nKeys === node.id) {
1755
- parentNode.values.splice(i, 0, value);
1756
- parentNode.keys.splice(i + 1, 0, pointer.id);
1757
- this.bufferForNodeUpdate(parentNode);
1758
- if (parentNode.keys.length > this.order) {
1759
- const parentPointer = await this._createNode(false, [], []);
1760
- parentPointer.parent = parentNode.parent;
1761
- const mid = Math.ceil(this.order / 2) - 1;
1762
- parentPointer.values = parentNode.values.slice(mid + 1);
1763
- parentPointer.keys = parentNode.keys.slice(mid + 1);
1764
- const midValue = parentNode.values[mid];
1765
- if (mid === 0) {
1766
- parentNode.values = parentNode.values.slice(0, mid + 1);
1767
- } else {
1768
- parentNode.values = parentNode.values.slice(0, mid);
1769
- }
1770
- parentNode.keys = parentNode.keys.slice(0, mid + 1);
1771
- for (const k of parentNode.keys) {
1772
- const node2 = await this.getNode(k);
1773
- node2.parent = parentNode.id;
1774
- this.bufferForNodeUpdate(node2);
1775
- }
1776
- for (const k of parentPointer.keys) {
1777
- const node2 = await this.getNode(k);
1778
- node2.parent = parentPointer.id;
1779
- this.bufferForNodeUpdate(node2);
1780
- }
1781
- await this._insertInParent(parentNode, midValue, parentPointer);
1782
- this.bufferForNodeUpdate(parentNode);
1783
- }
1776
+ let insertIndex = 0;
1777
+ for (let i = 0; i < parentNode.values.length; i++) {
1778
+ if (this.comparator.asc(value, parentNode.values[i]) > 0) {
1779
+ insertIndex = i + 1;
1780
+ } else {
1781
+ break;
1782
+ }
1783
+ }
1784
+ parentNode.values.splice(insertIndex, 0, value);
1785
+ parentNode.keys.splice(insertIndex + 1, 0, pointer.id);
1786
+ pointer.parent = parentNode.id;
1787
+ if (pointer.leaf) {
1788
+ const leftSiblingId = parentNode.keys[insertIndex];
1789
+ const rightSiblingId = parentNode.keys[insertIndex + 2];
1790
+ if (leftSiblingId) {
1791
+ const leftSibling = await this.getNode(leftSiblingId);
1792
+ pointer.prev = leftSibling.id;
1793
+ pointer.next = leftSibling.next;
1794
+ leftSibling.next = pointer.id;
1795
+ this.bufferForNodeUpdate(leftSibling);
1796
+ }
1797
+ if (rightSiblingId) {
1798
+ const rightSibling = await this.getNode(rightSiblingId);
1799
+ rightSibling.prev = pointer.id;
1800
+ this.bufferForNodeUpdate(rightSibling);
1801
+ }
1802
+ }
1803
+ this.bufferForNodeUpdate(parentNode);
1804
+ this.bufferForNodeUpdate(pointer);
1805
+ if (parentNode.keys.length > this.order) {
1806
+ const parentPointer = await this._createNode(false, [], []);
1807
+ parentPointer.parent = parentNode.parent;
1808
+ const mid = Math.ceil(this.order / 2) - 1;
1809
+ parentPointer.values = parentNode.values.slice(mid + 1);
1810
+ parentPointer.keys = parentNode.keys.slice(mid + 1);
1811
+ const midValue = parentNode.values[mid];
1812
+ parentNode.values = parentNode.values.slice(0, mid);
1813
+ parentNode.keys = parentNode.keys.slice(0, mid + 1);
1814
+ for (const k of parentNode.keys) {
1815
+ const node2 = await this.getNode(k);
1816
+ node2.parent = parentNode.id;
1817
+ this.bufferForNodeUpdate(node2);
1818
+ }
1819
+ for (const k of parentPointer.keys) {
1820
+ const node2 = await this.getNode(k);
1821
+ node2.parent = parentPointer.id;
1822
+ this.bufferForNodeUpdate(node2);
1784
1823
  }
1824
+ await this._insertInParent(parentNode, midValue, parentPointer);
1825
+ this.bufferForNodeUpdate(parentNode);
1785
1826
  }
1786
1827
  }
1787
1828
  async init() {
@@ -1952,21 +1993,14 @@ var BPTreeAsync = class extends BPTree {
1952
1993
  [],
1953
1994
  true,
1954
1995
  before.parent,
1955
- before.next,
1956
- before.id
1996
+ null,
1997
+ null
1957
1998
  );
1958
1999
  const mid = Math.ceil(this.order / 2) - 1;
1959
- const beforeNext = before.next;
1960
2000
  after.values = before.values.slice(mid + 1);
1961
2001
  after.keys = before.keys.slice(mid + 1);
1962
2002
  before.values = before.values.slice(0, mid + 1);
1963
2003
  before.keys = before.keys.slice(0, mid + 1);
1964
- before.next = after.id;
1965
- if (beforeNext) {
1966
- const node = await this.getNode(beforeNext);
1967
- node.prev = after.id;
1968
- this.bufferForNodeUpdate(node);
1969
- }
1970
2004
  await this._insertInParent(before, after.values[0], after);
1971
2005
  this.bufferForNodeUpdate(before);
1972
2006
  }
@@ -8,8 +8,8 @@ export declare class BPTreeAsync<K, V> extends BPTree<K, V> {
8
8
  private readonly lock;
9
9
  constructor(strategy: SerializeStrategyAsync<K, V>, comparator: ValueComparator<V>, option?: BPTreeConstructorOption);
10
10
  private _createCachedNode;
11
- private readLock;
12
- private writeLock;
11
+ protected readLock<T>(callback: () => Promise<T>): Promise<T>;
12
+ protected writeLock<T>(callback: () => Promise<T>): Promise<T>;
13
13
  protected getPairsRightToLeft(value: V, startNode: BPTreeLeafNode<K, V>, endNode: BPTreeLeafNode<K, V> | null, comparator: (nodeValue: V, value: V) => boolean): Promise<BPTreePair<K, V>>;
14
14
  protected getPairsLeftToRight(value: V, startNode: BPTreeLeafNode<K, V>, endNode: BPTreeLeafNode<K, V> | null, comparator: (nodeValue: V, value: V) => boolean): Promise<BPTreePair<K, V>>;
15
15
  protected getPairs(value: V, startNode: BPTreeLeafNode<K, V>, endNode: BPTreeLeafNode<K, V> | null, comparator: (nodeValue: V, value: V) => boolean, direction: 1 | -1): Promise<BPTreePair<K, V>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "serializable-bptree",
3
- "version": "5.2.1",
3
+ "version": "6.0.1",
4
4
  "description": "Store the B+tree flexibly, not only in-memory.",
5
5
  "types": "./dist/types/index.d.ts",
6
6
  "main": "./dist/cjs/index.cjs",