serializable-bptree 8.4.1 → 9.0.0
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 +8 -2
- package/dist/cjs/index.cjs +2756 -1690
- package/dist/esm/index.mjs +2756 -1690
- package/dist/types/BPTreePureAsync.d.ts +34 -0
- package/dist/types/BPTreePureSync.d.ts +43 -0
- package/dist/types/base/BPTreeAlgorithmAsync.d.ts +33 -0
- package/dist/types/base/BPTreeAlgorithmSync.d.ts +47 -0
- package/dist/types/base/BPTreeNodeOps.d.ts +34 -0
- package/dist/types/base/BPTreeTransaction.d.ts +8 -3
- package/dist/types/index.d.ts +2 -0
- package/dist/types/transaction/BPTreeAsyncTransaction.d.ts +10 -5
- package/dist/types/transaction/BPTreeSyncTransaction.d.ts +10 -5
- package/package.json +2 -2
package/dist/cjs/index.cjs
CHANGED
|
@@ -22,6 +22,8 @@ var src_exports = {};
|
|
|
22
22
|
__export(src_exports, {
|
|
23
23
|
BPTreeAsync: () => BPTreeAsync,
|
|
24
24
|
BPTreeAsyncTransaction: () => BPTreeAsyncTransaction,
|
|
25
|
+
BPTreePureAsync: () => BPTreePureAsync,
|
|
26
|
+
BPTreePureSync: () => BPTreePureSync,
|
|
25
27
|
BPTreeSync: () => BPTreeSync,
|
|
26
28
|
BPTreeSyncTransaction: () => BPTreeSyncTransaction,
|
|
27
29
|
InMemoryStoreStrategyAsync: () => InMemoryStoreStrategyAsync,
|
|
@@ -228,6 +230,7 @@ var MVCCTransaction = class {
|
|
|
228
230
|
// 트랜잭션 시작 시점에 디스크에 존재했던 키 (deleted 결과 필터링용)
|
|
229
231
|
bufferHistory = /* @__PURE__ */ new Map();
|
|
230
232
|
// Nested Transaction Properties
|
|
233
|
+
activeDescendantCount = 0;
|
|
231
234
|
parent;
|
|
232
235
|
localVersion;
|
|
233
236
|
// Local version for Nested Conflict Detection
|
|
@@ -304,6 +307,7 @@ var MVCCTransaction = class {
|
|
|
304
307
|
return this.deleteBuffer.has(key);
|
|
305
308
|
}
|
|
306
309
|
_recordHistory(key) {
|
|
310
|
+
if (this.activeDescendantCount === 0) return;
|
|
307
311
|
const existsInWriteBuffer = this.writeBuffer.has(key);
|
|
308
312
|
const existsInDeleteBuffer = this.deleteBuffer.has(key);
|
|
309
313
|
const currentVer = this.keyVersions.get(key);
|
|
@@ -416,6 +420,9 @@ var MVCCTransaction = class {
|
|
|
416
420
|
this._cleanupAll();
|
|
417
421
|
this.committed = true;
|
|
418
422
|
if (this.root !== this) {
|
|
423
|
+
if (this.parent) {
|
|
424
|
+
this.parent._updateActiveDescendantCount(-1);
|
|
425
|
+
}
|
|
419
426
|
this.root.activeTransactions.delete(this);
|
|
420
427
|
}
|
|
421
428
|
return {
|
|
@@ -503,6 +510,16 @@ var MVCCTransaction = class {
|
|
|
503
510
|
}
|
|
504
511
|
}
|
|
505
512
|
}
|
|
513
|
+
/**
|
|
514
|
+
* Updates the descendant count for this transaction and its ancestors.
|
|
515
|
+
* @param delta The amount to change the count by.
|
|
516
|
+
*/
|
|
517
|
+
_updateActiveDescendantCount(delta) {
|
|
518
|
+
this.activeDescendantCount += delta;
|
|
519
|
+
if (this.parent) {
|
|
520
|
+
this.parent._updateActiveDescendantCount(delta);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
506
523
|
};
|
|
507
524
|
var SyncMVCCStrategy = class extends MVCCStrategy {
|
|
508
525
|
};
|
|
@@ -547,7 +564,9 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
547
564
|
if (this.committed) throw new Error("Transaction already committed");
|
|
548
565
|
const childVersion = this.isRoot() ? this.version : this.snapshotVersion;
|
|
549
566
|
const child = new _SyncMVCCTransaction(void 0, void 0, this, childVersion);
|
|
550
|
-
this.
|
|
567
|
+
this._updateActiveDescendantCount(1);
|
|
568
|
+
const rootAny = this.root;
|
|
569
|
+
rootAny.activeTransactions.add(child);
|
|
551
570
|
return child;
|
|
552
571
|
}
|
|
553
572
|
read(key) {
|
|
@@ -665,6 +684,7 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
665
684
|
};
|
|
666
685
|
}
|
|
667
686
|
this._cleanupAll();
|
|
687
|
+
this.parent._updateActiveDescendantCount(-1);
|
|
668
688
|
this.committed = true;
|
|
669
689
|
} else {
|
|
670
690
|
if (this.writeBuffer.size > 0 || this.deleteBuffer.size > 0) {
|
|
@@ -1209,7 +1229,9 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
1209
1229
|
if (this.committed) throw new Error("Transaction already committed");
|
|
1210
1230
|
const childVersion = this.isRoot() ? this.version : this.snapshotVersion;
|
|
1211
1231
|
const child = new _AsyncMVCCTransaction(void 0, void 0, this, childVersion);
|
|
1212
|
-
this.
|
|
1232
|
+
this._updateActiveDescendantCount(1);
|
|
1233
|
+
const rootAny = this.root;
|
|
1234
|
+
rootAny.activeTransactions.add(child);
|
|
1213
1235
|
return child;
|
|
1214
1236
|
}
|
|
1215
1237
|
async read(key) {
|
|
@@ -1327,6 +1349,7 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
1327
1349
|
};
|
|
1328
1350
|
}
|
|
1329
1351
|
this._cleanupAll();
|
|
1352
|
+
this.parent._updateActiveDescendantCount(-1);
|
|
1330
1353
|
this.committed = true;
|
|
1331
1354
|
} else {
|
|
1332
1355
|
if (this.writeBuffer.size > 0 || this.deleteBuffer.size > 0) {
|
|
@@ -1566,86 +1589,120 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
1566
1589
|
}
|
|
1567
1590
|
};
|
|
1568
1591
|
|
|
1569
|
-
// src/base/
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1592
|
+
// src/base/BPTreeAlgorithmSync.ts
|
|
1593
|
+
function cloneNode(node) {
|
|
1594
|
+
return JSON.parse(JSON.stringify(node));
|
|
1595
|
+
}
|
|
1596
|
+
function binarySearchValues(values, target, comparator, usePrimary = false, upperBound = false) {
|
|
1597
|
+
let low = 0;
|
|
1598
|
+
let high = values.length;
|
|
1599
|
+
let found = false;
|
|
1600
|
+
while (low < high) {
|
|
1601
|
+
const mid = low + high >>> 1;
|
|
1602
|
+
const cmp = usePrimary ? comparator.primaryAsc(target, values[mid]) : comparator.asc(target, values[mid]);
|
|
1603
|
+
if (cmp === 0) {
|
|
1604
|
+
found = true;
|
|
1605
|
+
if (upperBound) low = mid + 1;
|
|
1606
|
+
else high = mid;
|
|
1607
|
+
} else if (cmp < 0) {
|
|
1608
|
+
high = mid;
|
|
1609
|
+
} else {
|
|
1610
|
+
low = mid + 1;
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
return { index: low, found };
|
|
1614
|
+
}
|
|
1615
|
+
function insertValueIntoLeaf(leaf, key, value, comparator) {
|
|
1616
|
+
if (leaf.values.length) {
|
|
1617
|
+
const { index, found } = binarySearchValues(leaf.values, value, comparator);
|
|
1618
|
+
if (found) {
|
|
1619
|
+
if (leaf.keys[index].includes(key)) {
|
|
1620
|
+
return false;
|
|
1621
|
+
}
|
|
1622
|
+
leaf.keys[index].push(key);
|
|
1623
|
+
return true;
|
|
1624
|
+
}
|
|
1625
|
+
leaf.values.splice(index, 0, value);
|
|
1626
|
+
leaf.keys.splice(index, 0, [key]);
|
|
1627
|
+
return true;
|
|
1628
|
+
} else {
|
|
1629
|
+
leaf.values = [value];
|
|
1630
|
+
leaf.keys = [[key]];
|
|
1631
|
+
return true;
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
function createVerifierMap(comparator, cachedRegexp, ensureValues) {
|
|
1635
|
+
return {
|
|
1636
|
+
gt: (nv, v) => comparator.isHigher(nv, v),
|
|
1637
|
+
gte: (nv, v) => comparator.isHigher(nv, v) || comparator.isSame(nv, v),
|
|
1638
|
+
lt: (nv, v) => comparator.isLower(nv, v),
|
|
1639
|
+
lte: (nv, v) => comparator.isLower(nv, v) || comparator.isSame(nv, v),
|
|
1640
|
+
equal: (nv, v) => comparator.isSame(nv, v),
|
|
1641
|
+
notEqual: (nv, v) => comparator.isSame(nv, v) === false,
|
|
1642
|
+
or: (nv, v) => ensureValues(v).some((v2) => comparator.isSame(nv, v2)),
|
|
1643
|
+
primaryGt: (nv, v) => comparator.isPrimaryHigher(nv, v),
|
|
1644
|
+
primaryGte: (nv, v) => comparator.isPrimaryHigher(nv, v) || comparator.isPrimarySame(nv, v),
|
|
1645
|
+
primaryLt: (nv, v) => comparator.isPrimaryLower(nv, v),
|
|
1646
|
+
primaryLte: (nv, v) => comparator.isPrimaryLower(nv, v) || comparator.isPrimarySame(nv, v),
|
|
1647
|
+
primaryEqual: (nv, v) => comparator.isPrimarySame(nv, v),
|
|
1648
|
+
primaryNotEqual: (nv, v) => comparator.isPrimarySame(nv, v) === false,
|
|
1649
|
+
primaryOr: (nv, v) => ensureValues(v).some((v2) => comparator.isPrimarySame(nv, v2)),
|
|
1599
1650
|
like: (nv, v) => {
|
|
1600
|
-
const nodeValue =
|
|
1651
|
+
const nodeValue = comparator.match(nv);
|
|
1601
1652
|
const value = v;
|
|
1602
|
-
if (!
|
|
1653
|
+
if (!cachedRegexp.has(value)) {
|
|
1603
1654
|
const pattern = value.replace(/%/g, ".*").replace(/_/g, ".");
|
|
1604
1655
|
const regexp2 = new RegExp(`^${pattern}$`, "i");
|
|
1605
|
-
|
|
1656
|
+
cachedRegexp.set(value, regexp2);
|
|
1606
1657
|
}
|
|
1607
|
-
const regexp =
|
|
1658
|
+
const regexp = cachedRegexp.get(value);
|
|
1608
1659
|
return regexp.test(nodeValue);
|
|
1609
1660
|
}
|
|
1610
1661
|
};
|
|
1611
|
-
|
|
1662
|
+
}
|
|
1663
|
+
function createSearchConfigs(comparator, ensureValues) {
|
|
1664
|
+
const lowest = (v) => [...v].sort((a, b) => comparator.asc(a, b))[0];
|
|
1665
|
+
const highest = (v) => [...v].sort((a, b) => comparator.asc(a, b))[v.length - 1];
|
|
1666
|
+
const lowestPrimary = (v) => [...v].sort((a, b) => comparator.primaryAsc(a, b))[0];
|
|
1667
|
+
const highestPrimary = (v) => [...v].sort((a, b) => comparator.primaryAsc(a, b))[v.length - 1];
|
|
1668
|
+
return {
|
|
1612
1669
|
gt: {
|
|
1613
1670
|
asc: {
|
|
1614
|
-
start: (
|
|
1671
|
+
start: (r, ops, v) => findUpperBoundLeaf(ops, r, v[0], comparator),
|
|
1615
1672
|
end: () => null,
|
|
1616
1673
|
direction: 1,
|
|
1617
1674
|
earlyTerminate: false
|
|
1618
1675
|
},
|
|
1619
1676
|
desc: {
|
|
1620
|
-
start: (
|
|
1621
|
-
end: (
|
|
1677
|
+
start: (r, ops) => rightestNode(ops, r),
|
|
1678
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], -1, comparator),
|
|
1622
1679
|
direction: -1,
|
|
1623
1680
|
earlyTerminate: true
|
|
1624
1681
|
}
|
|
1625
1682
|
},
|
|
1626
1683
|
gte: {
|
|
1627
1684
|
asc: {
|
|
1628
|
-
start: (
|
|
1685
|
+
start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
|
|
1629
1686
|
end: () => null,
|
|
1630
1687
|
direction: 1,
|
|
1631
1688
|
earlyTerminate: false
|
|
1632
1689
|
},
|
|
1633
1690
|
desc: {
|
|
1634
|
-
start: (
|
|
1635
|
-
end: (
|
|
1691
|
+
start: (r, ops) => rightestNode(ops, r),
|
|
1692
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], -1, comparator),
|
|
1636
1693
|
direction: -1,
|
|
1637
1694
|
earlyTerminate: true
|
|
1638
1695
|
}
|
|
1639
1696
|
},
|
|
1640
1697
|
lt: {
|
|
1641
1698
|
asc: {
|
|
1642
|
-
start: (
|
|
1643
|
-
end: (
|
|
1699
|
+
start: (r, ops) => leftestNode(ops, r),
|
|
1700
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
|
|
1644
1701
|
direction: 1,
|
|
1645
1702
|
earlyTerminate: true
|
|
1646
1703
|
},
|
|
1647
1704
|
desc: {
|
|
1648
|
-
start: (
|
|
1705
|
+
start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
|
|
1649
1706
|
end: () => null,
|
|
1650
1707
|
direction: -1,
|
|
1651
1708
|
earlyTerminate: false
|
|
@@ -1653,13 +1710,13 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1653
1710
|
},
|
|
1654
1711
|
lte: {
|
|
1655
1712
|
asc: {
|
|
1656
|
-
start: (
|
|
1657
|
-
end: (
|
|
1713
|
+
start: (r, ops) => leftestNode(ops, r),
|
|
1714
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
|
|
1658
1715
|
direction: 1,
|
|
1659
1716
|
earlyTerminate: true
|
|
1660
1717
|
},
|
|
1661
1718
|
desc: {
|
|
1662
|
-
start: (
|
|
1719
|
+
start: (r, ops, v) => findUpperBoundLeaf(ops, r, v[0], comparator),
|
|
1663
1720
|
end: () => null,
|
|
1664
1721
|
direction: -1,
|
|
1665
1722
|
earlyTerminate: false
|
|
@@ -1667,27 +1724,27 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1667
1724
|
},
|
|
1668
1725
|
equal: {
|
|
1669
1726
|
asc: {
|
|
1670
|
-
start: (
|
|
1671
|
-
end: (
|
|
1727
|
+
start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
|
|
1728
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
|
|
1672
1729
|
direction: 1,
|
|
1673
1730
|
earlyTerminate: true
|
|
1674
1731
|
},
|
|
1675
1732
|
desc: {
|
|
1676
|
-
start: (
|
|
1677
|
-
end: (
|
|
1733
|
+
start: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
|
|
1734
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], -1, comparator),
|
|
1678
1735
|
direction: -1,
|
|
1679
1736
|
earlyTerminate: true
|
|
1680
1737
|
}
|
|
1681
1738
|
},
|
|
1682
1739
|
notEqual: {
|
|
1683
1740
|
asc: {
|
|
1684
|
-
start: (
|
|
1741
|
+
start: (r, ops) => leftestNode(ops, r),
|
|
1685
1742
|
end: () => null,
|
|
1686
1743
|
direction: 1,
|
|
1687
1744
|
earlyTerminate: false
|
|
1688
1745
|
},
|
|
1689
1746
|
desc: {
|
|
1690
|
-
start: (
|
|
1747
|
+
start: (r, ops) => rightestNode(ops, r),
|
|
1691
1748
|
end: () => null,
|
|
1692
1749
|
direction: -1,
|
|
1693
1750
|
earlyTerminate: false
|
|
@@ -1695,55 +1752,55 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1695
1752
|
},
|
|
1696
1753
|
or: {
|
|
1697
1754
|
asc: {
|
|
1698
|
-
start: (
|
|
1699
|
-
end: (
|
|
1755
|
+
start: (r, ops, v) => findLowerBoundLeaf(ops, r, lowest(ensureValues(v)), comparator),
|
|
1756
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, highest(ensureValues(v)), 1, comparator),
|
|
1700
1757
|
direction: 1,
|
|
1701
1758
|
earlyTerminate: false
|
|
1702
1759
|
},
|
|
1703
1760
|
desc: {
|
|
1704
|
-
start: (
|
|
1705
|
-
end: (
|
|
1761
|
+
start: (r, ops, v) => findOuterBoundaryLeaf(ops, r, highest(ensureValues(v)), 1, comparator),
|
|
1762
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, lowest(ensureValues(v)), -1, comparator),
|
|
1706
1763
|
direction: -1,
|
|
1707
1764
|
earlyTerminate: false
|
|
1708
1765
|
}
|
|
1709
1766
|
},
|
|
1710
1767
|
primaryGt: {
|
|
1711
1768
|
asc: {
|
|
1712
|
-
start: (
|
|
1769
|
+
start: (r, ops, v) => findUpperBoundLeaf(ops, r, v[0], comparator),
|
|
1713
1770
|
end: () => null,
|
|
1714
1771
|
direction: 1,
|
|
1715
1772
|
earlyTerminate: false
|
|
1716
1773
|
},
|
|
1717
1774
|
desc: {
|
|
1718
|
-
start: (
|
|
1719
|
-
end: (
|
|
1775
|
+
start: (r, ops) => rightestNode(ops, r),
|
|
1776
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], -1, comparator),
|
|
1720
1777
|
direction: -1,
|
|
1721
1778
|
earlyTerminate: true
|
|
1722
1779
|
}
|
|
1723
1780
|
},
|
|
1724
1781
|
primaryGte: {
|
|
1725
1782
|
asc: {
|
|
1726
|
-
start: (
|
|
1783
|
+
start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
|
|
1727
1784
|
end: () => null,
|
|
1728
1785
|
direction: 1,
|
|
1729
1786
|
earlyTerminate: false
|
|
1730
1787
|
},
|
|
1731
1788
|
desc: {
|
|
1732
|
-
start: (
|
|
1733
|
-
end: (
|
|
1789
|
+
start: (r, ops) => rightestNode(ops, r),
|
|
1790
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], -1, comparator),
|
|
1734
1791
|
direction: -1,
|
|
1735
1792
|
earlyTerminate: true
|
|
1736
1793
|
}
|
|
1737
1794
|
},
|
|
1738
1795
|
primaryLt: {
|
|
1739
1796
|
asc: {
|
|
1740
|
-
start: (
|
|
1741
|
-
end: (
|
|
1797
|
+
start: (r, ops) => leftestNode(ops, r),
|
|
1798
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
|
|
1742
1799
|
direction: 1,
|
|
1743
1800
|
earlyTerminate: true
|
|
1744
1801
|
},
|
|
1745
1802
|
desc: {
|
|
1746
|
-
start: (
|
|
1803
|
+
start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
|
|
1747
1804
|
end: () => null,
|
|
1748
1805
|
direction: -1,
|
|
1749
1806
|
earlyTerminate: false
|
|
@@ -1751,13 +1808,13 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1751
1808
|
},
|
|
1752
1809
|
primaryLte: {
|
|
1753
1810
|
asc: {
|
|
1754
|
-
start: (
|
|
1755
|
-
end: (
|
|
1811
|
+
start: (r, ops) => leftestNode(ops, r),
|
|
1812
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
|
|
1756
1813
|
direction: 1,
|
|
1757
1814
|
earlyTerminate: true
|
|
1758
1815
|
},
|
|
1759
1816
|
desc: {
|
|
1760
|
-
start: (
|
|
1817
|
+
start: (r, ops, v) => findUpperBoundLeaf(ops, r, v[0], comparator),
|
|
1761
1818
|
end: () => null,
|
|
1762
1819
|
direction: -1,
|
|
1763
1820
|
earlyTerminate: false
|
|
@@ -1765,27 +1822,27 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1765
1822
|
},
|
|
1766
1823
|
primaryEqual: {
|
|
1767
1824
|
asc: {
|
|
1768
|
-
start: (
|
|
1769
|
-
end: (
|
|
1825
|
+
start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
|
|
1826
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
|
|
1770
1827
|
direction: 1,
|
|
1771
1828
|
earlyTerminate: true
|
|
1772
1829
|
},
|
|
1773
1830
|
desc: {
|
|
1774
|
-
start: (
|
|
1775
|
-
end: (
|
|
1831
|
+
start: (r, ops, v) => findUpperBoundLeaf(ops, r, v[0], comparator),
|
|
1832
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], -1, comparator),
|
|
1776
1833
|
direction: -1,
|
|
1777
1834
|
earlyTerminate: true
|
|
1778
1835
|
}
|
|
1779
1836
|
},
|
|
1780
1837
|
primaryNotEqual: {
|
|
1781
1838
|
asc: {
|
|
1782
|
-
start: (
|
|
1839
|
+
start: (r, ops) => leftestNode(ops, r),
|
|
1783
1840
|
end: () => null,
|
|
1784
1841
|
direction: 1,
|
|
1785
1842
|
earlyTerminate: false
|
|
1786
1843
|
},
|
|
1787
1844
|
desc: {
|
|
1788
|
-
start: (
|
|
1845
|
+
start: (r, ops) => rightestNode(ops, r),
|
|
1789
1846
|
end: () => null,
|
|
1790
1847
|
direction: -1,
|
|
1791
1848
|
earlyTerminate: false
|
|
@@ -1793,176 +1850,1186 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1793
1850
|
},
|
|
1794
1851
|
primaryOr: {
|
|
1795
1852
|
asc: {
|
|
1796
|
-
start: (
|
|
1797
|
-
end: (
|
|
1853
|
+
start: (r, ops, v) => findLowerBoundLeaf(ops, r, lowestPrimary(ensureValues(v)), comparator),
|
|
1854
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, highestPrimary(ensureValues(v)), 1, comparator),
|
|
1798
1855
|
direction: 1,
|
|
1799
1856
|
earlyTerminate: false
|
|
1800
1857
|
},
|
|
1801
1858
|
desc: {
|
|
1802
|
-
start: (
|
|
1803
|
-
end: (
|
|
1859
|
+
start: (r, ops, v) => findUpperBoundLeaf(ops, r, highestPrimary(ensureValues(v)), comparator),
|
|
1860
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, lowestPrimary(ensureValues(v)), -1, comparator),
|
|
1804
1861
|
direction: -1,
|
|
1805
1862
|
earlyTerminate: false
|
|
1806
1863
|
}
|
|
1807
1864
|
},
|
|
1808
1865
|
like: {
|
|
1809
1866
|
asc: {
|
|
1810
|
-
start: (
|
|
1867
|
+
start: (r, ops) => leftestNode(ops, r),
|
|
1811
1868
|
end: () => null,
|
|
1812
1869
|
direction: 1,
|
|
1813
1870
|
earlyTerminate: false
|
|
1814
1871
|
},
|
|
1815
1872
|
desc: {
|
|
1816
|
-
start: (
|
|
1873
|
+
start: (r, ops) => rightestNode(ops, r),
|
|
1817
1874
|
end: () => null,
|
|
1818
1875
|
direction: -1,
|
|
1819
1876
|
earlyTerminate: false
|
|
1820
1877
|
}
|
|
1821
1878
|
}
|
|
1822
1879
|
};
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
if (candidates.length === 0) return null;
|
|
1863
|
-
if (candidates.length === 1) return candidates[0];
|
|
1864
|
-
let best = candidates[0];
|
|
1865
|
-
let bestScore = 0;
|
|
1866
|
-
for (const candidate of candidates) {
|
|
1867
|
-
let score = 0;
|
|
1868
|
-
for (const key in candidate.condition) {
|
|
1869
|
-
const condKey = key;
|
|
1870
|
-
const priority = _BPTreeTransaction.conditionPriority[condKey] ?? 0;
|
|
1871
|
-
if (priority > score) {
|
|
1872
|
-
score = priority;
|
|
1873
|
-
}
|
|
1874
|
-
}
|
|
1875
|
-
if (score > bestScore) {
|
|
1876
|
-
bestScore = score;
|
|
1877
|
-
best = candidate;
|
|
1878
|
-
}
|
|
1880
|
+
}
|
|
1881
|
+
var _lowerBoundKeys = [
|
|
1882
|
+
"primaryEqual",
|
|
1883
|
+
"equal",
|
|
1884
|
+
"primaryGt",
|
|
1885
|
+
"gt",
|
|
1886
|
+
"primaryGte",
|
|
1887
|
+
"gte",
|
|
1888
|
+
"primaryOr",
|
|
1889
|
+
"or"
|
|
1890
|
+
];
|
|
1891
|
+
var _upperBoundKeys = [
|
|
1892
|
+
"primaryEqual",
|
|
1893
|
+
"equal",
|
|
1894
|
+
"primaryLt",
|
|
1895
|
+
"lt",
|
|
1896
|
+
"primaryLte",
|
|
1897
|
+
"lte",
|
|
1898
|
+
"primaryOr",
|
|
1899
|
+
"or"
|
|
1900
|
+
];
|
|
1901
|
+
var _multiValueKeys = [
|
|
1902
|
+
"or",
|
|
1903
|
+
"primaryOr"
|
|
1904
|
+
];
|
|
1905
|
+
function resolveStartEndConfigs(condition, order, comparator, ensureValues) {
|
|
1906
|
+
const direction = order === "asc" ? 1 : -1;
|
|
1907
|
+
const startCandidates = order === "asc" ? _lowerBoundKeys : _upperBoundKeys;
|
|
1908
|
+
const endCandidates = order === "asc" ? _upperBoundKeys : _lowerBoundKeys;
|
|
1909
|
+
let startKey = null;
|
|
1910
|
+
let endKey = null;
|
|
1911
|
+
let startValues = [];
|
|
1912
|
+
let endValues = [];
|
|
1913
|
+
for (let i = 0, len = startCandidates.length; i < len; i++) {
|
|
1914
|
+
const key = startCandidates[i];
|
|
1915
|
+
if (key in condition) {
|
|
1916
|
+
startKey = key;
|
|
1917
|
+
startValues = _multiValueKeys.includes(key) ? ensureValues(condition[key]) : [condition[key]];
|
|
1918
|
+
break;
|
|
1879
1919
|
}
|
|
1880
|
-
return best;
|
|
1881
1920
|
}
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
return MVCCTransaction.CheckConflicts(transactions.map((tx) => tx.mvcc));
|
|
1921
|
+
for (let i = 0, len = endCandidates.length; i < len; i++) {
|
|
1922
|
+
const key = endCandidates[i];
|
|
1923
|
+
if (key in condition) {
|
|
1924
|
+
endKey = key;
|
|
1925
|
+
endValues = _multiValueKeys.includes(key) ? ensureValues(condition[key]) : [condition[key]];
|
|
1926
|
+
break;
|
|
1927
|
+
}
|
|
1890
1928
|
}
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1929
|
+
return { startKey, endKey, startValues, endValues, direction };
|
|
1930
|
+
}
|
|
1931
|
+
function verify(nodeValue, condition, verifierMap) {
|
|
1932
|
+
for (const key in condition) {
|
|
1933
|
+
const verifyFn = verifierMap[key];
|
|
1934
|
+
const condValue = condition[key];
|
|
1935
|
+
if (!verifyFn(nodeValue, condValue)) {
|
|
1936
|
+
return false;
|
|
1937
|
+
}
|
|
1897
1938
|
}
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1939
|
+
return true;
|
|
1940
|
+
}
|
|
1941
|
+
function locateLeaf(ops, rootId, value, comparator) {
|
|
1942
|
+
let node = ops.getNode(rootId);
|
|
1943
|
+
while (!node.leaf) {
|
|
1944
|
+
const { index } = binarySearchValues(node.values, value, comparator, false, true);
|
|
1945
|
+
node = ops.getNode(node.keys[index]);
|
|
1946
|
+
}
|
|
1947
|
+
return node;
|
|
1948
|
+
}
|
|
1949
|
+
function findLowerBoundLeaf(ops, rootId, value, comparator) {
|
|
1950
|
+
let node = ops.getNode(rootId);
|
|
1951
|
+
while (!node.leaf) {
|
|
1952
|
+
const { index } = binarySearchValues(node.values, value, comparator, true, false);
|
|
1953
|
+
node = ops.getNode(node.keys[index]);
|
|
1954
|
+
}
|
|
1955
|
+
return node;
|
|
1956
|
+
}
|
|
1957
|
+
function findUpperBoundLeaf(ops, rootId, value, comparator) {
|
|
1958
|
+
let node = ops.getNode(rootId);
|
|
1959
|
+
while (!node.leaf) {
|
|
1960
|
+
const { index } = binarySearchValues(node.values, value, comparator, true, true);
|
|
1961
|
+
node = ops.getNode(node.keys[index]);
|
|
1962
|
+
}
|
|
1963
|
+
return node;
|
|
1964
|
+
}
|
|
1965
|
+
function findOuterBoundaryLeaf(ops, rootId, value, direction, comparator) {
|
|
1966
|
+
const insertableNode = direction === -1 ? findLowerBoundLeaf(ops, rootId, value, comparator) : findUpperBoundLeaf(ops, rootId, value, comparator);
|
|
1967
|
+
let key;
|
|
1968
|
+
switch (direction) {
|
|
1969
|
+
case -1:
|
|
1970
|
+
key = "prev";
|
|
1971
|
+
break;
|
|
1972
|
+
case 1:
|
|
1973
|
+
key = "next";
|
|
1974
|
+
break;
|
|
1975
|
+
default:
|
|
1976
|
+
throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
|
|
1904
1977
|
}
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
* @param nodeValue The value to verify.
|
|
1909
|
-
* @param condition The condition to verify against.
|
|
1910
|
-
* @returns Returns true if the value satisfies the condition.
|
|
1911
|
-
*/
|
|
1912
|
-
verify(nodeValue, condition) {
|
|
1913
|
-
for (const key in condition) {
|
|
1914
|
-
const verify = this.verifierMap[key];
|
|
1915
|
-
const condValue = condition[key];
|
|
1916
|
-
if (!verify(nodeValue, condValue)) {
|
|
1917
|
-
return false;
|
|
1918
|
-
}
|
|
1919
|
-
}
|
|
1920
|
-
return true;
|
|
1978
|
+
const guessNode = insertableNode[key];
|
|
1979
|
+
if (!guessNode) {
|
|
1980
|
+
return null;
|
|
1921
1981
|
}
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1982
|
+
return ops.getNode(guessNode);
|
|
1983
|
+
}
|
|
1984
|
+
function leftestNode(ops, rootId) {
|
|
1985
|
+
let node = ops.getNode(rootId);
|
|
1986
|
+
while (!node.leaf) {
|
|
1987
|
+
const keys = node.keys;
|
|
1988
|
+
node = ops.getNode(keys[0]);
|
|
1989
|
+
}
|
|
1990
|
+
return node;
|
|
1991
|
+
}
|
|
1992
|
+
function rightestNode(ops, rootId) {
|
|
1993
|
+
let node = ops.getNode(rootId);
|
|
1994
|
+
while (!node.leaf) {
|
|
1995
|
+
const keys = node.keys;
|
|
1996
|
+
node = ops.getNode(keys[keys.length - 1]);
|
|
1997
|
+
}
|
|
1998
|
+
return node;
|
|
1999
|
+
}
|
|
2000
|
+
function* getPairsGenerator(ops, startNode, endNode, direction) {
|
|
2001
|
+
let node = startNode;
|
|
2002
|
+
while (true) {
|
|
2003
|
+
if (endNode && node.id === endNode.id) {
|
|
2004
|
+
break;
|
|
2005
|
+
}
|
|
2006
|
+
const len = node.values.length;
|
|
2007
|
+
if (direction === 1) {
|
|
2008
|
+
for (let i = 0; i < len; i++) {
|
|
2009
|
+
const nValue = node.values[i];
|
|
2010
|
+
const keys = node.keys[i];
|
|
2011
|
+
for (let j = 0, kLen = keys.length; j < kLen; j++) {
|
|
2012
|
+
yield [keys[j], nValue];
|
|
1934
2013
|
}
|
|
1935
|
-
leaf.keys[index].push(key);
|
|
1936
|
-
return true;
|
|
1937
2014
|
}
|
|
1938
|
-
leaf.values.splice(index, 0, value);
|
|
1939
|
-
leaf.keys.splice(index, 0, [key]);
|
|
1940
|
-
return true;
|
|
1941
2015
|
} else {
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
2016
|
+
let i = len;
|
|
2017
|
+
while (i--) {
|
|
2018
|
+
const nValue = node.values[i];
|
|
2019
|
+
const keys = node.keys[i];
|
|
2020
|
+
let j = keys.length;
|
|
2021
|
+
while (j--) {
|
|
2022
|
+
yield [keys[j], nValue];
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
1945
2025
|
}
|
|
2026
|
+
if (direction === 1) {
|
|
2027
|
+
if (!node.next) break;
|
|
2028
|
+
node = ops.getNode(node.next);
|
|
2029
|
+
} else {
|
|
2030
|
+
if (!node.prev) break;
|
|
2031
|
+
node = ops.getNode(node.prev);
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
function insertAtLeaf(ops, node, key, value, comparator) {
|
|
2036
|
+
let leaf = node;
|
|
2037
|
+
if (leaf.values.length) {
|
|
2038
|
+
for (let i = 0, len = leaf.values.length; i < len; i++) {
|
|
2039
|
+
const nValue = leaf.values[i];
|
|
2040
|
+
if (comparator.isSame(value, nValue)) {
|
|
2041
|
+
const keys = leaf.keys[i];
|
|
2042
|
+
if (keys.includes(key)) {
|
|
2043
|
+
break;
|
|
2044
|
+
}
|
|
2045
|
+
leaf = cloneNode(leaf);
|
|
2046
|
+
leaf.keys[i].push(key);
|
|
2047
|
+
ops.updateNode(leaf);
|
|
2048
|
+
return leaf;
|
|
2049
|
+
} else if (comparator.isLower(value, nValue)) {
|
|
2050
|
+
leaf = cloneNode(leaf);
|
|
2051
|
+
leaf.values.splice(i, 0, value);
|
|
2052
|
+
leaf.keys.splice(i, 0, [key]);
|
|
2053
|
+
ops.updateNode(leaf);
|
|
2054
|
+
return leaf;
|
|
2055
|
+
} else if (i + 1 === leaf.values.length) {
|
|
2056
|
+
leaf = cloneNode(leaf);
|
|
2057
|
+
leaf.values.push(value);
|
|
2058
|
+
leaf.keys.push([key]);
|
|
2059
|
+
ops.updateNode(leaf);
|
|
2060
|
+
return leaf;
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
} else {
|
|
2064
|
+
leaf = cloneNode(leaf);
|
|
2065
|
+
leaf.values = [value];
|
|
2066
|
+
leaf.keys = [[key]];
|
|
2067
|
+
ops.updateNode(leaf);
|
|
2068
|
+
return leaf;
|
|
1946
2069
|
}
|
|
1947
|
-
|
|
1948
|
-
|
|
2070
|
+
return leaf;
|
|
2071
|
+
}
|
|
2072
|
+
function insertInParent(ops, ctx, node, value, newSiblingNode) {
|
|
2073
|
+
if (ctx.rootId === node.id) {
|
|
2074
|
+
node = cloneNode(node);
|
|
2075
|
+
newSiblingNode = cloneNode(newSiblingNode);
|
|
2076
|
+
const root = ops.createNode(false, [node.id, newSiblingNode.id], [value]);
|
|
2077
|
+
ctx.rootId = root.id;
|
|
2078
|
+
node.parent = root.id;
|
|
2079
|
+
newSiblingNode.parent = root.id;
|
|
2080
|
+
if (newSiblingNode.leaf) {
|
|
2081
|
+
;
|
|
2082
|
+
node.next = newSiblingNode.id;
|
|
2083
|
+
newSiblingNode.prev = node.id;
|
|
2084
|
+
}
|
|
2085
|
+
ops.writeHead({
|
|
2086
|
+
root: root.id,
|
|
2087
|
+
order: ctx.order,
|
|
2088
|
+
data: ctx.headData()
|
|
2089
|
+
});
|
|
2090
|
+
ops.updateNode(node);
|
|
2091
|
+
ops.updateNode(newSiblingNode);
|
|
2092
|
+
return;
|
|
2093
|
+
}
|
|
2094
|
+
const parentNode = cloneNode(ops.getNode(node.parent));
|
|
2095
|
+
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
2096
|
+
if (nodeIndex === -1) {
|
|
2097
|
+
throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
|
|
2098
|
+
}
|
|
2099
|
+
parentNode.values.splice(nodeIndex, 0, value);
|
|
2100
|
+
parentNode.keys.splice(nodeIndex + 1, 0, newSiblingNode.id);
|
|
2101
|
+
newSiblingNode = cloneNode(newSiblingNode);
|
|
2102
|
+
newSiblingNode.parent = parentNode.id;
|
|
2103
|
+
if (newSiblingNode.leaf) {
|
|
2104
|
+
const leftSibling = cloneNode(node);
|
|
2105
|
+
const oldNextId = leftSibling.next;
|
|
2106
|
+
newSiblingNode.prev = leftSibling.id;
|
|
2107
|
+
newSiblingNode.next = oldNextId;
|
|
2108
|
+
leftSibling.next = newSiblingNode.id;
|
|
2109
|
+
ops.updateNode(leftSibling);
|
|
2110
|
+
if (oldNextId) {
|
|
2111
|
+
const oldNext = cloneNode(ops.getNode(oldNextId));
|
|
2112
|
+
oldNext.prev = newSiblingNode.id;
|
|
2113
|
+
ops.updateNode(oldNext);
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
ops.updateNode(parentNode);
|
|
2117
|
+
ops.updateNode(newSiblingNode);
|
|
2118
|
+
if (parentNode.keys.length > ctx.order) {
|
|
2119
|
+
const newSiblingNodeRecursive = ops.createNode(false, [], []);
|
|
2120
|
+
newSiblingNodeRecursive.parent = parentNode.parent;
|
|
2121
|
+
const mid = Math.ceil(ctx.order / 2) - 1;
|
|
2122
|
+
newSiblingNodeRecursive.values = parentNode.values.slice(mid + 1);
|
|
2123
|
+
newSiblingNodeRecursive.keys = parentNode.keys.slice(mid + 1);
|
|
2124
|
+
const midValue = parentNode.values[mid];
|
|
2125
|
+
parentNode.values = parentNode.values.slice(0, mid);
|
|
2126
|
+
parentNode.keys = parentNode.keys.slice(0, mid + 1);
|
|
2127
|
+
for (let i = 0, len = newSiblingNodeRecursive.keys.length; i < len; i++) {
|
|
2128
|
+
const k = newSiblingNodeRecursive.keys[i];
|
|
2129
|
+
const n = cloneNode(ops.getNode(k));
|
|
2130
|
+
n.parent = newSiblingNodeRecursive.id;
|
|
2131
|
+
ops.updateNode(n);
|
|
2132
|
+
}
|
|
2133
|
+
ops.updateNode(parentNode);
|
|
2134
|
+
insertInParent(ops, ctx, parentNode, midValue, newSiblingNodeRecursive);
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
function insertOp(ops, ctx, key, value, comparator) {
|
|
2138
|
+
let before = locateLeaf(ops, ctx.rootId, value, comparator);
|
|
2139
|
+
before = insertAtLeaf(ops, before, key, value, comparator);
|
|
2140
|
+
if (before.values.length === ctx.order) {
|
|
2141
|
+
let after = ops.createNode(
|
|
2142
|
+
true,
|
|
2143
|
+
[],
|
|
2144
|
+
[],
|
|
2145
|
+
before.parent,
|
|
2146
|
+
null,
|
|
2147
|
+
null
|
|
2148
|
+
);
|
|
2149
|
+
const mid = Math.ceil(ctx.order / 2) - 1;
|
|
2150
|
+
after = cloneNode(after);
|
|
2151
|
+
after.values = before.values.slice(mid + 1);
|
|
2152
|
+
after.keys = before.keys.slice(mid + 1);
|
|
2153
|
+
before.values = before.values.slice(0, mid + 1);
|
|
2154
|
+
before.keys = before.keys.slice(0, mid + 1);
|
|
2155
|
+
ops.updateNode(before);
|
|
2156
|
+
ops.updateNode(after);
|
|
2157
|
+
insertInParent(ops, ctx, before, after.values[0], after);
|
|
2158
|
+
}
|
|
2159
|
+
}
|
|
2160
|
+
function deleteEntry(ops, ctx, node, key, comparator) {
|
|
2161
|
+
if (!node.leaf) {
|
|
2162
|
+
let keyIndex = -1;
|
|
2163
|
+
for (let i = 0, len = node.keys.length; i < len; i++) {
|
|
2164
|
+
if (node.keys[i] === key) {
|
|
2165
|
+
keyIndex = i;
|
|
2166
|
+
break;
|
|
2167
|
+
}
|
|
2168
|
+
}
|
|
2169
|
+
if (keyIndex !== -1) {
|
|
2170
|
+
node = cloneNode(node);
|
|
2171
|
+
node.keys.splice(keyIndex, 1);
|
|
2172
|
+
const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
|
|
2173
|
+
node.values.splice(valueIndex, 1);
|
|
2174
|
+
ops.updateNode(node);
|
|
2175
|
+
}
|
|
1949
2176
|
}
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
2177
|
+
if (ctx.rootId === node.id && node.keys.length === 1 && !node.leaf) {
|
|
2178
|
+
const keys = node.keys;
|
|
2179
|
+
ops.deleteNode(node);
|
|
2180
|
+
const newRoot = cloneNode(ops.getNode(keys[0]));
|
|
2181
|
+
newRoot.parent = null;
|
|
2182
|
+
ops.updateNode(newRoot);
|
|
2183
|
+
ops.writeHead({
|
|
2184
|
+
root: newRoot.id,
|
|
2185
|
+
order: ctx.order,
|
|
2186
|
+
data: ctx.headData()
|
|
2187
|
+
});
|
|
2188
|
+
ctx.rootId = newRoot.id;
|
|
2189
|
+
return node;
|
|
2190
|
+
} else if (ctx.rootId === node.id) {
|
|
2191
|
+
ops.writeHead({
|
|
2192
|
+
root: node.id,
|
|
2193
|
+
order: ctx.order,
|
|
2194
|
+
data: ctx.headData()
|
|
2195
|
+
});
|
|
2196
|
+
return node;
|
|
2197
|
+
} else if (node.keys.length < Math.ceil(ctx.order / 2) && !node.leaf || node.values.length < Math.ceil((ctx.order - 1) / 2) && node.leaf) {
|
|
2198
|
+
if (node.parent === null) {
|
|
2199
|
+
return node;
|
|
2200
|
+
}
|
|
2201
|
+
let isPredecessor = false;
|
|
2202
|
+
let parentNode = ops.getNode(node.parent);
|
|
2203
|
+
let prevNode = null;
|
|
2204
|
+
let nextNode = null;
|
|
2205
|
+
let prevValue = null;
|
|
2206
|
+
let postValue = null;
|
|
2207
|
+
for (let i = 0, len = parentNode.keys.length; i < len; i++) {
|
|
2208
|
+
const nKey = parentNode.keys[i];
|
|
2209
|
+
if (nKey === node.id) {
|
|
2210
|
+
if (i > 0) {
|
|
2211
|
+
prevNode = ops.getNode(parentNode.keys[i - 1]);
|
|
2212
|
+
prevValue = parentNode.values[i - 1];
|
|
2213
|
+
}
|
|
2214
|
+
if (i < parentNode.keys.length - 1) {
|
|
2215
|
+
nextNode = ops.getNode(parentNode.keys[i + 1]);
|
|
2216
|
+
postValue = parentNode.values[i];
|
|
2217
|
+
}
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
let siblingNode;
|
|
2221
|
+
let guess;
|
|
2222
|
+
if (prevNode === null) {
|
|
2223
|
+
siblingNode = nextNode;
|
|
2224
|
+
guess = postValue;
|
|
2225
|
+
} else if (nextNode === null) {
|
|
2226
|
+
isPredecessor = true;
|
|
2227
|
+
siblingNode = prevNode;
|
|
2228
|
+
guess = prevValue;
|
|
2229
|
+
} else {
|
|
2230
|
+
if (node.values.length + nextNode.values.length < ctx.order) {
|
|
2231
|
+
siblingNode = nextNode;
|
|
2232
|
+
guess = postValue;
|
|
2233
|
+
} else {
|
|
2234
|
+
isPredecessor = true;
|
|
2235
|
+
siblingNode = prevNode;
|
|
2236
|
+
guess = prevValue;
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
if (!siblingNode) {
|
|
2240
|
+
return node;
|
|
2241
|
+
}
|
|
2242
|
+
node = cloneNode(node);
|
|
2243
|
+
siblingNode = cloneNode(siblingNode);
|
|
2244
|
+
if (node.values.length + siblingNode.values.length < ctx.order) {
|
|
2245
|
+
if (!isPredecessor) {
|
|
2246
|
+
const pTemp = siblingNode;
|
|
2247
|
+
siblingNode = node;
|
|
2248
|
+
node = pTemp;
|
|
2249
|
+
}
|
|
2250
|
+
siblingNode.keys.push(...node.keys);
|
|
2251
|
+
if (!node.leaf) {
|
|
2252
|
+
siblingNode.values.push(guess);
|
|
2253
|
+
} else {
|
|
2254
|
+
siblingNode.next = node.next;
|
|
2255
|
+
if (siblingNode.next) {
|
|
2256
|
+
const n = cloneNode(ops.getNode(siblingNode.next));
|
|
2257
|
+
n.prev = siblingNode.id;
|
|
2258
|
+
ops.updateNode(n);
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
siblingNode.values.push(...node.values);
|
|
2262
|
+
if (!siblingNode.leaf) {
|
|
2263
|
+
const keys = siblingNode.keys;
|
|
2264
|
+
for (let i = 0, len = keys.length; i < len; i++) {
|
|
2265
|
+
const k = keys[i];
|
|
2266
|
+
const n = cloneNode(ops.getNode(k));
|
|
2267
|
+
n.parent = siblingNode.id;
|
|
2268
|
+
ops.updateNode(n);
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
ops.deleteNode(node);
|
|
2272
|
+
ops.updateNode(siblingNode);
|
|
2273
|
+
deleteEntry(ops, ctx, ops.getNode(node.parent), node.id, comparator);
|
|
2274
|
+
} else {
|
|
2275
|
+
if (isPredecessor) {
|
|
2276
|
+
let pointerPm;
|
|
2277
|
+
let pointerKm;
|
|
2278
|
+
if (!node.leaf) {
|
|
2279
|
+
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
2280
|
+
pointerKm = siblingNode.values.splice(-1)[0];
|
|
2281
|
+
node.keys = [pointerPm, ...node.keys];
|
|
2282
|
+
node.values = [guess, ...node.values];
|
|
2283
|
+
parentNode = cloneNode(ops.getNode(node.parent));
|
|
2284
|
+
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
2285
|
+
if (nodeIndex > 0) {
|
|
2286
|
+
parentNode.values[nodeIndex - 1] = pointerKm;
|
|
2287
|
+
ops.updateNode(parentNode);
|
|
2288
|
+
}
|
|
2289
|
+
} else {
|
|
2290
|
+
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
2291
|
+
pointerKm = siblingNode.values.splice(-1)[0];
|
|
2292
|
+
node.keys = [pointerPm, ...node.keys];
|
|
2293
|
+
node.values = [pointerKm, ...node.values];
|
|
2294
|
+
parentNode = cloneNode(ops.getNode(node.parent));
|
|
2295
|
+
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
2296
|
+
if (nodeIndex > 0) {
|
|
2297
|
+
parentNode.values[nodeIndex - 1] = pointerKm;
|
|
2298
|
+
ops.updateNode(parentNode);
|
|
2299
|
+
}
|
|
2300
|
+
}
|
|
2301
|
+
ops.updateNode(node);
|
|
2302
|
+
ops.updateNode(siblingNode);
|
|
2303
|
+
} else {
|
|
2304
|
+
let pointerP0;
|
|
2305
|
+
let pointerK0;
|
|
2306
|
+
if (!node.leaf) {
|
|
2307
|
+
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
2308
|
+
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
2309
|
+
node.keys = [...node.keys, pointerP0];
|
|
2310
|
+
node.values = [...node.values, guess];
|
|
2311
|
+
parentNode = cloneNode(ops.getNode(node.parent));
|
|
2312
|
+
const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
|
|
2313
|
+
if (pointerIndex > 0) {
|
|
2314
|
+
parentNode.values[pointerIndex - 1] = pointerK0;
|
|
2315
|
+
ops.updateNode(parentNode);
|
|
2316
|
+
}
|
|
2317
|
+
} else {
|
|
2318
|
+
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
2319
|
+
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
2320
|
+
node.keys = [...node.keys, pointerP0];
|
|
2321
|
+
node.values = [...node.values, pointerK0];
|
|
2322
|
+
parentNode = cloneNode(ops.getNode(node.parent));
|
|
2323
|
+
const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
|
|
2324
|
+
if (pointerIndex > 0) {
|
|
2325
|
+
parentNode.values[pointerIndex - 1] = siblingNode.values[0];
|
|
2326
|
+
ops.updateNode(parentNode);
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
2329
|
+
ops.updateNode(node);
|
|
2330
|
+
ops.updateNode(siblingNode);
|
|
2331
|
+
}
|
|
2332
|
+
if (!siblingNode.leaf) {
|
|
2333
|
+
for (let i = 0, len = siblingNode.keys.length; i < len; i++) {
|
|
2334
|
+
const k = siblingNode.keys[i];
|
|
2335
|
+
const n = cloneNode(ops.getNode(k));
|
|
2336
|
+
n.parent = siblingNode.id;
|
|
2337
|
+
ops.updateNode(n);
|
|
2338
|
+
}
|
|
2339
|
+
}
|
|
2340
|
+
if (!node.leaf) {
|
|
2341
|
+
for (let i = 0, len = node.keys.length; i < len; i++) {
|
|
2342
|
+
const k = node.keys[i];
|
|
2343
|
+
const n = cloneNode(ops.getNode(k));
|
|
2344
|
+
n.parent = node.id;
|
|
2345
|
+
ops.updateNode(n);
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2348
|
+
if (!parentNode.leaf) {
|
|
2349
|
+
for (let i = 0, len = parentNode.keys.length; i < len; i++) {
|
|
2350
|
+
const k = parentNode.keys[i];
|
|
2351
|
+
const n = cloneNode(ops.getNode(k));
|
|
2352
|
+
n.parent = parentNode.id;
|
|
2353
|
+
ops.updateNode(n);
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
} else {
|
|
2358
|
+
ops.updateNode(cloneNode(node));
|
|
2359
|
+
}
|
|
2360
|
+
return node;
|
|
2361
|
+
}
|
|
2362
|
+
function deleteOp(ops, ctx, key, comparator, value) {
|
|
2363
|
+
if (value === void 0) {
|
|
2364
|
+
value = getOp(ops, ctx.rootId, key);
|
|
2365
|
+
}
|
|
2366
|
+
if (value === void 0) {
|
|
2367
|
+
return;
|
|
2368
|
+
}
|
|
2369
|
+
let node = findLowerBoundLeaf(ops, ctx.rootId, value, comparator);
|
|
2370
|
+
let found = false;
|
|
2371
|
+
while (true) {
|
|
2372
|
+
let i = node.values.length;
|
|
2373
|
+
while (i--) {
|
|
2374
|
+
const nValue = node.values[i];
|
|
2375
|
+
if (comparator.isSame(value, nValue)) {
|
|
2376
|
+
const keys = node.keys[i];
|
|
2377
|
+
const keyIndex = keys.indexOf(key);
|
|
2378
|
+
if (keyIndex !== -1) {
|
|
2379
|
+
node = cloneNode(node);
|
|
2380
|
+
const freshKeys = node.keys[i];
|
|
2381
|
+
freshKeys.splice(keyIndex, 1);
|
|
2382
|
+
if (freshKeys.length === 0) {
|
|
2383
|
+
node.keys.splice(i, 1);
|
|
2384
|
+
node.values.splice(i, 1);
|
|
2385
|
+
}
|
|
2386
|
+
ops.updateNode(node);
|
|
2387
|
+
node = deleteEntry(ops, ctx, node, key, comparator);
|
|
2388
|
+
found = true;
|
|
2389
|
+
break;
|
|
2390
|
+
}
|
|
2391
|
+
}
|
|
2392
|
+
}
|
|
2393
|
+
if (found) break;
|
|
2394
|
+
if (node.next) {
|
|
2395
|
+
node = ops.getNode(node.next);
|
|
2396
|
+
continue;
|
|
2397
|
+
}
|
|
2398
|
+
break;
|
|
2399
|
+
}
|
|
2400
|
+
}
|
|
2401
|
+
function batchInsertOp(ops, ctx, entries, comparator) {
|
|
2402
|
+
if (entries.length === 0) return;
|
|
2403
|
+
const sorted = [...entries].sort((a, b) => comparator.asc(a[1], b[1]));
|
|
2404
|
+
let currentLeaf = null;
|
|
2405
|
+
let modified = false;
|
|
2406
|
+
let cachedLeafId = null;
|
|
2407
|
+
let cachedLeafMaxValue = null;
|
|
2408
|
+
for (let i = 0, len = sorted.length; i < len; i++) {
|
|
2409
|
+
const [key, value] = sorted[i];
|
|
2410
|
+
let targetLeaf;
|
|
2411
|
+
if (cachedLeafId !== null && cachedLeafMaxValue !== null && currentLeaf !== null && (comparator.isLower(value, cachedLeafMaxValue) || comparator.isSame(value, cachedLeafMaxValue))) {
|
|
2412
|
+
targetLeaf = currentLeaf;
|
|
2413
|
+
} else {
|
|
2414
|
+
targetLeaf = locateLeaf(ops, ctx.rootId, value, comparator);
|
|
2415
|
+
}
|
|
2416
|
+
if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
|
|
2417
|
+
} else {
|
|
2418
|
+
if (currentLeaf !== null && modified) {
|
|
2419
|
+
ops.updateNode(currentLeaf);
|
|
2420
|
+
}
|
|
2421
|
+
currentLeaf = cloneNode(targetLeaf);
|
|
2422
|
+
modified = false;
|
|
2423
|
+
}
|
|
2424
|
+
cachedLeafId = currentLeaf.id;
|
|
2425
|
+
const changed = insertValueIntoLeaf(currentLeaf, key, value, comparator);
|
|
2426
|
+
modified = modified || changed;
|
|
2427
|
+
cachedLeafMaxValue = currentLeaf.values[currentLeaf.values.length - 1];
|
|
2428
|
+
if (currentLeaf.values.length === ctx.order) {
|
|
2429
|
+
ops.updateNode(currentLeaf);
|
|
2430
|
+
let after = ops.createNode(
|
|
2431
|
+
true,
|
|
2432
|
+
[],
|
|
2433
|
+
[],
|
|
2434
|
+
currentLeaf.parent,
|
|
2435
|
+
null,
|
|
2436
|
+
null
|
|
2437
|
+
);
|
|
2438
|
+
const mid = Math.ceil(ctx.order / 2) - 1;
|
|
2439
|
+
after = cloneNode(after);
|
|
2440
|
+
after.values = currentLeaf.values.slice(mid + 1);
|
|
2441
|
+
after.keys = currentLeaf.keys.slice(mid + 1);
|
|
2442
|
+
currentLeaf.values = currentLeaf.values.slice(0, mid + 1);
|
|
2443
|
+
currentLeaf.keys = currentLeaf.keys.slice(0, mid + 1);
|
|
2444
|
+
ops.updateNode(currentLeaf);
|
|
2445
|
+
ops.updateNode(after);
|
|
2446
|
+
insertInParent(ops, ctx, currentLeaf, after.values[0], after);
|
|
2447
|
+
currentLeaf = null;
|
|
2448
|
+
cachedLeafId = null;
|
|
2449
|
+
cachedLeafMaxValue = null;
|
|
2450
|
+
modified = false;
|
|
2451
|
+
}
|
|
2452
|
+
}
|
|
2453
|
+
if (currentLeaf !== null && modified) {
|
|
2454
|
+
ops.updateNode(currentLeaf);
|
|
2455
|
+
}
|
|
2456
|
+
}
|
|
2457
|
+
function bulkLoadOp(ops, ctx, entries, comparator) {
|
|
2458
|
+
if (entries.length === 0) return;
|
|
2459
|
+
const root = ops.getNode(ctx.rootId);
|
|
2460
|
+
if (!root.leaf || root.values.length > 0) {
|
|
2461
|
+
throw new Error("bulkLoad can only be called on an empty tree. Use batchInsert for non-empty trees.");
|
|
2462
|
+
}
|
|
2463
|
+
const sorted = [...entries].sort((a, b) => comparator.asc(a[1], b[1]));
|
|
2464
|
+
const grouped = [];
|
|
2465
|
+
for (let i = 0, len = sorted.length; i < len; i++) {
|
|
2466
|
+
const [key, value] = sorted[i];
|
|
2467
|
+
const last = grouped[grouped.length - 1];
|
|
2468
|
+
if (last && comparator.isSame(last.value, value)) {
|
|
2469
|
+
if (!last.keys.includes(key)) {
|
|
2470
|
+
last.keys.push(key);
|
|
2471
|
+
}
|
|
2472
|
+
} else {
|
|
2473
|
+
grouped.push({ keys: [key], value });
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
ops.deleteNode(root);
|
|
2477
|
+
const maxLeafSize = ctx.order - 1;
|
|
2478
|
+
const leaves = [];
|
|
2479
|
+
for (let i = 0, len = grouped.length; i < len; i += maxLeafSize) {
|
|
2480
|
+
const chunk = grouped.slice(i, i + maxLeafSize);
|
|
2481
|
+
const leafKeys = chunk.map((g) => g.keys);
|
|
2482
|
+
const leafValues = chunk.map((g) => g.value);
|
|
2483
|
+
const leaf = ops.createNode(
|
|
2484
|
+
true,
|
|
2485
|
+
leafKeys,
|
|
2486
|
+
leafValues,
|
|
2487
|
+
null,
|
|
2488
|
+
null,
|
|
2489
|
+
null
|
|
2490
|
+
);
|
|
2491
|
+
leaves.push(leaf);
|
|
2492
|
+
}
|
|
2493
|
+
for (let i = 0, len = leaves.length; i < len; i++) {
|
|
2494
|
+
if (i > 0) {
|
|
2495
|
+
leaves[i].prev = leaves[i - 1].id;
|
|
2496
|
+
}
|
|
2497
|
+
if (i < len - 1) {
|
|
2498
|
+
leaves[i].next = leaves[i + 1].id;
|
|
2499
|
+
}
|
|
2500
|
+
ops.updateNode(leaves[i]);
|
|
2501
|
+
}
|
|
2502
|
+
let currentLevel = leaves;
|
|
2503
|
+
while (currentLevel.length > 1) {
|
|
2504
|
+
const nextLevel = [];
|
|
2505
|
+
for (let i = 0, len = currentLevel.length; i < len; i += ctx.order) {
|
|
2506
|
+
const children = currentLevel.slice(i, i + ctx.order);
|
|
2507
|
+
const childIds = children.map((c) => c.id);
|
|
2508
|
+
const separators = [];
|
|
2509
|
+
for (let j = 1, cLen = children.length; j < cLen; j++) {
|
|
2510
|
+
separators.push(children[j].values[0]);
|
|
2511
|
+
}
|
|
2512
|
+
const internalNode = ops.createNode(
|
|
2513
|
+
false,
|
|
2514
|
+
childIds,
|
|
2515
|
+
separators,
|
|
2516
|
+
null,
|
|
2517
|
+
null,
|
|
2518
|
+
null
|
|
2519
|
+
);
|
|
2520
|
+
for (let j = 0, cLen = children.length; j < cLen; j++) {
|
|
2521
|
+
const child = children[j];
|
|
2522
|
+
child.parent = internalNode.id;
|
|
2523
|
+
ops.updateNode(child);
|
|
2524
|
+
}
|
|
2525
|
+
nextLevel.push(internalNode);
|
|
2526
|
+
}
|
|
2527
|
+
currentLevel = nextLevel;
|
|
2528
|
+
}
|
|
2529
|
+
const newRoot = currentLevel[0];
|
|
2530
|
+
ops.writeHead({
|
|
2531
|
+
root: newRoot.id,
|
|
2532
|
+
order: ctx.order,
|
|
2533
|
+
data: ctx.headData()
|
|
2534
|
+
});
|
|
2535
|
+
ctx.rootId = newRoot.id;
|
|
2536
|
+
}
|
|
2537
|
+
function existsOp(ops, rootId, key, value, comparator) {
|
|
2538
|
+
const node = locateLeaf(ops, rootId, value, comparator);
|
|
2539
|
+
const { index, found } = binarySearchValues(node.values, value, comparator);
|
|
2540
|
+
if (found) {
|
|
2541
|
+
const keys = node.keys[index];
|
|
2542
|
+
if (keys.includes(key)) {
|
|
2543
|
+
return true;
|
|
2544
|
+
}
|
|
2545
|
+
}
|
|
2546
|
+
return false;
|
|
2547
|
+
}
|
|
2548
|
+
function getOp(ops, rootId, key) {
|
|
2549
|
+
let node = leftestNode(ops, rootId);
|
|
2550
|
+
while (true) {
|
|
2551
|
+
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
2552
|
+
const keys = node.keys[i];
|
|
2553
|
+
for (let j = 0, kLen = keys.length; j < kLen; j++) {
|
|
2554
|
+
if (keys[j] === key) {
|
|
2555
|
+
return node.values[i];
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2558
|
+
}
|
|
2559
|
+
if (!node.next) break;
|
|
2560
|
+
node = ops.getNode(node.next);
|
|
2561
|
+
}
|
|
2562
|
+
return void 0;
|
|
2563
|
+
}
|
|
2564
|
+
function* whereStreamOp(ops, rootId, condition, comparator, verifierMap, searchConfigs, ensureValues, options) {
|
|
2565
|
+
const { filterValues, limit, order = "asc" } = options ?? {};
|
|
2566
|
+
const conditionKeys = Object.keys(condition);
|
|
2567
|
+
if (conditionKeys.length === 0) return;
|
|
2568
|
+
const resolved = resolveStartEndConfigs(condition, order, comparator, ensureValues);
|
|
2569
|
+
const direction = resolved.direction;
|
|
2570
|
+
let startNode;
|
|
2571
|
+
if (resolved.startKey) {
|
|
2572
|
+
const startConfig = searchConfigs[resolved.startKey][order];
|
|
2573
|
+
startNode = startConfig.start(rootId, ops, resolved.startValues);
|
|
2574
|
+
} else {
|
|
2575
|
+
startNode = order === "asc" ? leftestNode(ops, rootId) : rightestNode(ops, rootId);
|
|
2576
|
+
}
|
|
2577
|
+
let endNode = null;
|
|
2578
|
+
if (resolved.endKey) {
|
|
2579
|
+
const endConfig = searchConfigs[resolved.endKey][order];
|
|
2580
|
+
endNode = endConfig.end(rootId, ops, resolved.endValues);
|
|
2581
|
+
}
|
|
2582
|
+
if (!startNode) return;
|
|
2583
|
+
const generator = getPairsGenerator(ops, startNode, endNode, direction);
|
|
2584
|
+
let count = 0;
|
|
2585
|
+
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
2586
|
+
for (const pair of generator) {
|
|
2587
|
+
const [k, v] = pair;
|
|
2588
|
+
if (intersection && !intersection.has(k)) {
|
|
2589
|
+
continue;
|
|
2590
|
+
}
|
|
2591
|
+
if (verify(v, condition, verifierMap)) {
|
|
2592
|
+
yield pair;
|
|
2593
|
+
count++;
|
|
2594
|
+
if (limit !== void 0 && count >= limit) {
|
|
2595
|
+
break;
|
|
2596
|
+
}
|
|
2597
|
+
}
|
|
2598
|
+
}
|
|
2599
|
+
}
|
|
2600
|
+
function* keysStreamOp(ops, rootId, condition, comparator, verifierMap, searchConfigs, ensureValues, options) {
|
|
2601
|
+
const { filterValues, limit } = options ?? {};
|
|
2602
|
+
const stream = whereStreamOp(ops, rootId, condition, comparator, verifierMap, searchConfigs, ensureValues, options);
|
|
2603
|
+
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
2604
|
+
let count = 0;
|
|
2605
|
+
for (const [key] of stream) {
|
|
2606
|
+
if (intersection && !intersection.has(key)) {
|
|
2607
|
+
continue;
|
|
2608
|
+
}
|
|
2609
|
+
yield key;
|
|
2610
|
+
count++;
|
|
2611
|
+
if (limit !== void 0 && count >= limit) {
|
|
2612
|
+
break;
|
|
2613
|
+
}
|
|
2614
|
+
}
|
|
2615
|
+
}
|
|
2616
|
+
function initOp(ops, ctx, strategyOrder, strategyHead, setStrategyHead) {
|
|
2617
|
+
const head = ops.readHead();
|
|
2618
|
+
if (head === null) {
|
|
2619
|
+
ctx.order = strategyOrder;
|
|
2620
|
+
const root = ops.createNode(true, [], []);
|
|
2621
|
+
ops.writeHead({
|
|
2622
|
+
root: root.id,
|
|
2623
|
+
order: ctx.order,
|
|
2624
|
+
data: strategyHead.data
|
|
2625
|
+
});
|
|
2626
|
+
ctx.rootId = root.id;
|
|
2627
|
+
} else {
|
|
2628
|
+
const { root, order } = head;
|
|
2629
|
+
setStrategyHead(head);
|
|
2630
|
+
ctx.order = order;
|
|
2631
|
+
ctx.rootId = root;
|
|
2632
|
+
}
|
|
2633
|
+
if (ctx.order < 3) {
|
|
2634
|
+
throw new Error(`The 'order' parameter must be greater than 2. but got a '${ctx.order}'.`);
|
|
2635
|
+
}
|
|
2636
|
+
}
|
|
2637
|
+
|
|
2638
|
+
// src/base/BPTreeTransaction.ts
|
|
2639
|
+
var BPTreeTransaction = class _BPTreeTransaction {
|
|
2640
|
+
_cachedRegexp = /* @__PURE__ */ new Map();
|
|
2641
|
+
rootTx;
|
|
2642
|
+
mvccRoot;
|
|
2643
|
+
mvcc;
|
|
2644
|
+
strategy;
|
|
2645
|
+
comparator;
|
|
2646
|
+
option;
|
|
2647
|
+
order;
|
|
2648
|
+
rootId;
|
|
2649
|
+
isInitialized = false;
|
|
2650
|
+
isDestroyed = false;
|
|
2651
|
+
verifierMap = {
|
|
2652
|
+
gt: (nv, v) => this.comparator.isHigher(nv, v),
|
|
2653
|
+
gte: (nv, v) => this.comparator.isHigher(nv, v) || this.comparator.isSame(nv, v),
|
|
2654
|
+
lt: (nv, v) => this.comparator.isLower(nv, v),
|
|
2655
|
+
lte: (nv, v) => this.comparator.isLower(nv, v) || this.comparator.isSame(nv, v),
|
|
2656
|
+
equal: (nv, v) => this.comparator.isSame(nv, v),
|
|
2657
|
+
notEqual: (nv, v) => this.comparator.isSame(nv, v) === false,
|
|
2658
|
+
or: (nv, v) => this.ensureValues(v).some((v2) => this.comparator.isSame(nv, v2)),
|
|
2659
|
+
primaryGt: (nv, v) => this.comparator.isPrimaryHigher(nv, v),
|
|
2660
|
+
primaryGte: (nv, v) => this.comparator.isPrimaryHigher(nv, v) || this.comparator.isPrimarySame(nv, v),
|
|
2661
|
+
primaryLt: (nv, v) => this.comparator.isPrimaryLower(nv, v),
|
|
2662
|
+
primaryLte: (nv, v) => this.comparator.isPrimaryLower(nv, v) || this.comparator.isPrimarySame(nv, v),
|
|
2663
|
+
primaryEqual: (nv, v) => this.comparator.isPrimarySame(nv, v),
|
|
2664
|
+
primaryNotEqual: (nv, v) => this.comparator.isPrimarySame(nv, v) === false,
|
|
2665
|
+
primaryOr: (nv, v) => this.ensureValues(v).some((v2) => this.comparator.isPrimarySame(nv, v2)),
|
|
2666
|
+
like: (nv, v) => {
|
|
2667
|
+
const nodeValue = this.comparator.match(nv);
|
|
2668
|
+
const value = v;
|
|
2669
|
+
if (!this._cachedRegexp.has(value)) {
|
|
2670
|
+
const pattern = value.replace(/%/g, ".*").replace(/_/g, ".");
|
|
2671
|
+
const regexp2 = new RegExp(`^${pattern}$`, "i");
|
|
2672
|
+
this._cachedRegexp.set(value, regexp2);
|
|
2673
|
+
}
|
|
2674
|
+
const regexp = this._cachedRegexp.get(value);
|
|
2675
|
+
return regexp.test(nodeValue);
|
|
2676
|
+
}
|
|
2677
|
+
};
|
|
2678
|
+
searchConfigs = {
|
|
2679
|
+
gt: {
|
|
2680
|
+
asc: {
|
|
2681
|
+
start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
|
|
2682
|
+
end: () => null,
|
|
2683
|
+
direction: 1,
|
|
2684
|
+
earlyTerminate: false
|
|
2685
|
+
},
|
|
2686
|
+
desc: {
|
|
2687
|
+
start: (tx) => tx.rightestNode(),
|
|
2688
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
|
|
2689
|
+
direction: -1,
|
|
2690
|
+
earlyTerminate: true
|
|
2691
|
+
}
|
|
2692
|
+
},
|
|
2693
|
+
gte: {
|
|
2694
|
+
asc: {
|
|
2695
|
+
start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
|
|
2696
|
+
end: () => null,
|
|
2697
|
+
direction: 1,
|
|
2698
|
+
earlyTerminate: false
|
|
2699
|
+
},
|
|
2700
|
+
desc: {
|
|
2701
|
+
start: (tx) => tx.rightestNode(),
|
|
2702
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
|
|
2703
|
+
direction: -1,
|
|
2704
|
+
earlyTerminate: true
|
|
2705
|
+
}
|
|
2706
|
+
},
|
|
2707
|
+
lt: {
|
|
2708
|
+
asc: {
|
|
2709
|
+
start: (tx) => tx.leftestNode(),
|
|
2710
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
|
|
2711
|
+
direction: 1,
|
|
2712
|
+
earlyTerminate: true
|
|
2713
|
+
},
|
|
2714
|
+
desc: {
|
|
2715
|
+
start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
|
|
2716
|
+
end: () => null,
|
|
2717
|
+
direction: -1,
|
|
2718
|
+
earlyTerminate: false
|
|
2719
|
+
}
|
|
2720
|
+
},
|
|
2721
|
+
lte: {
|
|
2722
|
+
asc: {
|
|
2723
|
+
start: (tx) => tx.leftestNode(),
|
|
2724
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
|
|
2725
|
+
direction: 1,
|
|
2726
|
+
earlyTerminate: true
|
|
2727
|
+
},
|
|
2728
|
+
desc: {
|
|
2729
|
+
start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
|
|
2730
|
+
end: () => null,
|
|
2731
|
+
direction: -1,
|
|
2732
|
+
earlyTerminate: false
|
|
2733
|
+
}
|
|
2734
|
+
},
|
|
2735
|
+
equal: {
|
|
2736
|
+
asc: {
|
|
2737
|
+
start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
|
|
2738
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
|
|
2739
|
+
direction: 1,
|
|
2740
|
+
earlyTerminate: true
|
|
2741
|
+
},
|
|
2742
|
+
desc: {
|
|
2743
|
+
start: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
|
|
2744
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
|
|
2745
|
+
direction: -1,
|
|
2746
|
+
earlyTerminate: true
|
|
2747
|
+
}
|
|
2748
|
+
},
|
|
2749
|
+
notEqual: {
|
|
2750
|
+
asc: {
|
|
2751
|
+
start: (tx) => tx.leftestNode(),
|
|
2752
|
+
end: () => null,
|
|
2753
|
+
direction: 1,
|
|
2754
|
+
earlyTerminate: false
|
|
2755
|
+
},
|
|
2756
|
+
desc: {
|
|
2757
|
+
start: (tx) => tx.rightestNode(),
|
|
2758
|
+
end: () => null,
|
|
2759
|
+
direction: -1,
|
|
2760
|
+
earlyTerminate: false
|
|
2761
|
+
}
|
|
2762
|
+
},
|
|
2763
|
+
or: {
|
|
2764
|
+
asc: {
|
|
2765
|
+
start: (tx, v) => tx.findLowerBoundLeaf(tx.lowestValue(v)),
|
|
2766
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(tx.highestValue(v), 1),
|
|
2767
|
+
direction: 1,
|
|
2768
|
+
earlyTerminate: false
|
|
2769
|
+
},
|
|
2770
|
+
desc: {
|
|
2771
|
+
start: (tx, v) => tx.findOuterBoundaryLeaf(tx.highestValue(v), 1),
|
|
2772
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(tx.lowestValue(v), -1),
|
|
2773
|
+
direction: -1,
|
|
2774
|
+
earlyTerminate: false
|
|
2775
|
+
}
|
|
2776
|
+
},
|
|
2777
|
+
primaryGt: {
|
|
2778
|
+
asc: {
|
|
2779
|
+
start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
|
|
2780
|
+
end: () => null,
|
|
2781
|
+
direction: 1,
|
|
2782
|
+
earlyTerminate: false
|
|
2783
|
+
},
|
|
2784
|
+
desc: {
|
|
2785
|
+
start: (tx) => tx.rightestNode(),
|
|
2786
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
|
|
2787
|
+
direction: -1,
|
|
2788
|
+
earlyTerminate: true
|
|
2789
|
+
}
|
|
2790
|
+
},
|
|
2791
|
+
primaryGte: {
|
|
2792
|
+
asc: {
|
|
2793
|
+
start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
|
|
2794
|
+
end: () => null,
|
|
2795
|
+
direction: 1,
|
|
2796
|
+
earlyTerminate: false
|
|
2797
|
+
},
|
|
2798
|
+
desc: {
|
|
2799
|
+
start: (tx) => tx.rightestNode(),
|
|
2800
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
|
|
2801
|
+
direction: -1,
|
|
2802
|
+
earlyTerminate: true
|
|
2803
|
+
}
|
|
2804
|
+
},
|
|
2805
|
+
primaryLt: {
|
|
2806
|
+
asc: {
|
|
2807
|
+
start: (tx) => tx.leftestNode(),
|
|
2808
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
|
|
2809
|
+
direction: 1,
|
|
2810
|
+
earlyTerminate: true
|
|
2811
|
+
},
|
|
2812
|
+
desc: {
|
|
2813
|
+
start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
|
|
2814
|
+
end: () => null,
|
|
2815
|
+
direction: -1,
|
|
2816
|
+
earlyTerminate: false
|
|
2817
|
+
}
|
|
2818
|
+
},
|
|
2819
|
+
primaryLte: {
|
|
2820
|
+
asc: {
|
|
2821
|
+
start: (tx) => tx.leftestNode(),
|
|
2822
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
|
|
2823
|
+
direction: 1,
|
|
2824
|
+
earlyTerminate: true
|
|
2825
|
+
},
|
|
2826
|
+
desc: {
|
|
2827
|
+
start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
|
|
2828
|
+
end: () => null,
|
|
2829
|
+
direction: -1,
|
|
2830
|
+
earlyTerminate: false
|
|
2831
|
+
}
|
|
2832
|
+
},
|
|
2833
|
+
primaryEqual: {
|
|
2834
|
+
asc: {
|
|
2835
|
+
start: (tx, v) => tx.findLowerBoundLeaf(v[0]),
|
|
2836
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], 1),
|
|
2837
|
+
direction: 1,
|
|
2838
|
+
earlyTerminate: true
|
|
2839
|
+
},
|
|
2840
|
+
desc: {
|
|
2841
|
+
start: (tx, v) => tx.findUpperBoundLeaf(v[0]),
|
|
2842
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(v[0], -1),
|
|
2843
|
+
direction: -1,
|
|
2844
|
+
earlyTerminate: true
|
|
2845
|
+
}
|
|
2846
|
+
},
|
|
2847
|
+
primaryNotEqual: {
|
|
2848
|
+
asc: {
|
|
2849
|
+
start: (tx) => tx.leftestNode(),
|
|
2850
|
+
end: () => null,
|
|
2851
|
+
direction: 1,
|
|
2852
|
+
earlyTerminate: false
|
|
2853
|
+
},
|
|
2854
|
+
desc: {
|
|
2855
|
+
start: (tx) => tx.rightestNode(),
|
|
2856
|
+
end: () => null,
|
|
2857
|
+
direction: -1,
|
|
2858
|
+
earlyTerminate: false
|
|
2859
|
+
}
|
|
2860
|
+
},
|
|
2861
|
+
primaryOr: {
|
|
2862
|
+
asc: {
|
|
2863
|
+
start: (tx, v) => tx.findLowerBoundLeaf(tx.lowestPrimaryValue(v)),
|
|
2864
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(tx.highestPrimaryValue(v), 1),
|
|
2865
|
+
direction: 1,
|
|
2866
|
+
earlyTerminate: false
|
|
2867
|
+
},
|
|
2868
|
+
desc: {
|
|
2869
|
+
start: (tx, v) => tx.findUpperBoundLeaf(tx.highestPrimaryValue(v)),
|
|
2870
|
+
end: (tx, v) => tx.findOuterBoundaryLeaf(tx.lowestPrimaryValue(v), -1),
|
|
2871
|
+
direction: -1,
|
|
2872
|
+
earlyTerminate: false
|
|
2873
|
+
}
|
|
2874
|
+
},
|
|
2875
|
+
like: {
|
|
2876
|
+
asc: {
|
|
2877
|
+
start: (tx) => tx.leftestNode(),
|
|
2878
|
+
end: () => null,
|
|
2879
|
+
direction: 1,
|
|
2880
|
+
earlyTerminate: false
|
|
2881
|
+
},
|
|
2882
|
+
desc: {
|
|
2883
|
+
start: (tx) => tx.rightestNode(),
|
|
2884
|
+
end: () => null,
|
|
2885
|
+
direction: -1,
|
|
2886
|
+
earlyTerminate: false
|
|
2887
|
+
}
|
|
2888
|
+
}
|
|
2889
|
+
};
|
|
2890
|
+
/**
|
|
2891
|
+
* Priority map for condition types.
|
|
2892
|
+
* Higher value = higher selectivity (fewer expected results).
|
|
2893
|
+
* Used by `chooseDriver` to select the most selective index.
|
|
2894
|
+
*/
|
|
2895
|
+
static conditionPriority = {
|
|
2896
|
+
equal: 100,
|
|
2897
|
+
primaryEqual: 100,
|
|
2898
|
+
or: 80,
|
|
2899
|
+
primaryOr: 80,
|
|
2900
|
+
gt: 50,
|
|
2901
|
+
gte: 50,
|
|
2902
|
+
lt: 50,
|
|
2903
|
+
lte: 50,
|
|
2904
|
+
primaryGt: 50,
|
|
2905
|
+
primaryGte: 50,
|
|
2906
|
+
primaryLt: 50,
|
|
2907
|
+
primaryLte: 50,
|
|
2908
|
+
like: 30,
|
|
2909
|
+
notEqual: 10,
|
|
2910
|
+
primaryNotEqual: 10
|
|
2911
|
+
};
|
|
2912
|
+
/**
|
|
2913
|
+
* Selects the best driver tree from multiple tree/condition pairs.
|
|
2914
|
+
* Uses rule-based optimization to choose the tree with highest estimated selectivity.
|
|
2915
|
+
*
|
|
2916
|
+
* @param candidates Array of { tree, condition } pairs to evaluate
|
|
2917
|
+
* @returns The candidate with highest priority condition, or null if empty
|
|
2918
|
+
*
|
|
2919
|
+
* @example
|
|
2920
|
+
* ```typescript
|
|
2921
|
+
* const driver = BPTreeSync.chooseDriver([
|
|
2922
|
+
* { tree: idxId, condition: { equal: 100 } },
|
|
2923
|
+
* { tree: idxAge, condition: { gt: 20 } }
|
|
2924
|
+
* ])
|
|
2925
|
+
* // Returns { tree: idxId, condition: { equal: 100 } } because 'equal' has higher priority
|
|
2926
|
+
* ```
|
|
2927
|
+
*/
|
|
2928
|
+
static ChooseDriver(candidates) {
|
|
2929
|
+
if (candidates.length === 0) return null;
|
|
2930
|
+
if (candidates.length === 1) return candidates[0];
|
|
2931
|
+
let best = candidates[0];
|
|
2932
|
+
let bestScore = 0;
|
|
2933
|
+
for (const candidate of candidates) {
|
|
2934
|
+
let score = 0;
|
|
2935
|
+
for (const key in candidate.condition) {
|
|
2936
|
+
const condKey = key;
|
|
2937
|
+
const priority = _BPTreeTransaction.conditionPriority[condKey] ?? 0;
|
|
2938
|
+
if (priority > score) {
|
|
2939
|
+
score = priority;
|
|
2940
|
+
}
|
|
2941
|
+
}
|
|
2942
|
+
if (score > bestScore) {
|
|
2943
|
+
bestScore = score;
|
|
2944
|
+
best = candidate;
|
|
2945
|
+
}
|
|
2946
|
+
}
|
|
2947
|
+
return best;
|
|
2948
|
+
}
|
|
2949
|
+
/**
|
|
2950
|
+
* Checks for conflicts between multiple transactions.
|
|
2951
|
+
*
|
|
2952
|
+
* @param transactions Array of BPTreeTransaction instances to check
|
|
2953
|
+
* @returns An array of keys that are in conflict. Empty array if no conflicts.
|
|
2954
|
+
*/
|
|
2955
|
+
static CheckConflicts(transactions) {
|
|
2956
|
+
return MVCCTransaction.CheckConflicts(transactions.map((tx) => tx.mvcc));
|
|
2957
|
+
}
|
|
2958
|
+
/**
|
|
2959
|
+
* Returns the ID of the root node.
|
|
2960
|
+
* @returns The root node ID.
|
|
2961
|
+
*/
|
|
2962
|
+
getRootId() {
|
|
2963
|
+
return this.rootId;
|
|
2964
|
+
}
|
|
2965
|
+
/**
|
|
2966
|
+
* Returns the order of the B+Tree.
|
|
2967
|
+
* @returns The order of the tree.
|
|
2968
|
+
*/
|
|
2969
|
+
getOrder() {
|
|
2970
|
+
return this.order;
|
|
2971
|
+
}
|
|
2972
|
+
/**
|
|
2973
|
+
* Verified if the value satisfies the condition.
|
|
2974
|
+
*
|
|
2975
|
+
* @param nodeValue The value to verify.
|
|
2976
|
+
* @param condition The condition to verify against.
|
|
2977
|
+
* @returns Returns true if the value satisfies the condition.
|
|
2978
|
+
*/
|
|
2979
|
+
verify(nodeValue, condition) {
|
|
2980
|
+
for (const key in condition) {
|
|
2981
|
+
const verify2 = this.verifierMap[key];
|
|
2982
|
+
const condValue = condition[key];
|
|
2983
|
+
if (!verify2(nodeValue, condValue)) {
|
|
2984
|
+
return false;
|
|
2985
|
+
}
|
|
2986
|
+
}
|
|
2987
|
+
return true;
|
|
2988
|
+
}
|
|
2989
|
+
/**
|
|
2990
|
+
* Inserts a key-value pair into an already-cloned leaf node in-place.
|
|
2991
|
+
* Unlike _insertAtLeaf, this does NOT clone or update the node via MVCC.
|
|
2992
|
+
* Used by batchInsert to batch multiple insertions with a single clone/update.
|
|
2993
|
+
* @returns true if the leaf was modified, false if the key already exists.
|
|
2994
|
+
*/
|
|
2995
|
+
_insertValueIntoLeaf(leaf, key, value) {
|
|
2996
|
+
if (leaf.values.length) {
|
|
2997
|
+
const { index, found } = this._binarySearchValues(leaf.values, value);
|
|
2998
|
+
if (found) {
|
|
2999
|
+
if (leaf.keys[index].includes(key)) {
|
|
3000
|
+
return false;
|
|
3001
|
+
}
|
|
3002
|
+
leaf.keys[index].push(key);
|
|
3003
|
+
return true;
|
|
3004
|
+
}
|
|
3005
|
+
leaf.values.splice(index, 0, value);
|
|
3006
|
+
leaf.keys.splice(index, 0, [key]);
|
|
3007
|
+
return true;
|
|
3008
|
+
} else {
|
|
3009
|
+
leaf.values = [value];
|
|
3010
|
+
leaf.keys = [[key]];
|
|
3011
|
+
return true;
|
|
3012
|
+
}
|
|
3013
|
+
}
|
|
3014
|
+
_cloneNode(node) {
|
|
3015
|
+
return JSON.parse(JSON.stringify(node));
|
|
3016
|
+
}
|
|
3017
|
+
/**
|
|
3018
|
+
* Resolves the best start/end configuration by independently examining
|
|
3019
|
+
* all conditions. Selects the tightest lower bound for start and the
|
|
3020
|
+
* tightest upper bound for end (in asc; reversed for desc).
|
|
3021
|
+
*
|
|
3022
|
+
* @param condition The condition to analyze.
|
|
3023
|
+
* @param order The sort order ('asc' or 'desc').
|
|
3024
|
+
* @returns The resolved start/end keys, values, and traversal direction.
|
|
3025
|
+
*/
|
|
3026
|
+
resolveStartEndConfigs(condition, order) {
|
|
3027
|
+
const direction = order === "asc" ? 1 : -1;
|
|
3028
|
+
const startCandidates = order === "asc" ? _BPTreeTransaction._lowerBoundKeys : _BPTreeTransaction._upperBoundKeys;
|
|
3029
|
+
const endCandidates = order === "asc" ? _BPTreeTransaction._upperBoundKeys : _BPTreeTransaction._lowerBoundKeys;
|
|
3030
|
+
let startKey = null;
|
|
3031
|
+
let endKey = null;
|
|
3032
|
+
let startValues = [];
|
|
1966
3033
|
let endValues = [];
|
|
1967
3034
|
for (let i = 0, len = startCandidates.length; i < len; i++) {
|
|
1968
3035
|
const key = startCandidates[i];
|
|
@@ -2051,6 +3118,12 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
2051
3118
|
_clearCache() {
|
|
2052
3119
|
this._cachedRegexp.clear();
|
|
2053
3120
|
}
|
|
3121
|
+
_resetForReload() {
|
|
3122
|
+
this._cachedRegexp.clear();
|
|
3123
|
+
this.isInitialized = false;
|
|
3124
|
+
this.isDestroyed = false;
|
|
3125
|
+
this.mvccRoot.diskCache.clear();
|
|
3126
|
+
}
|
|
2054
3127
|
/**
|
|
2055
3128
|
* Clears all cached nodes.
|
|
2056
3129
|
* This method is useful for freeing up memory when the tree is no longer needed.
|
|
@@ -2091,6 +3164,10 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
2091
3164
|
|
|
2092
3165
|
// src/transaction/BPTreeSyncTransaction.ts
|
|
2093
3166
|
var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
3167
|
+
_ops;
|
|
3168
|
+
_ctx;
|
|
3169
|
+
_verifierMapCached;
|
|
3170
|
+
_searchConfigsCached;
|
|
2094
3171
|
constructor(rootTx, mvccRoot, mvcc, strategy, comparator, option) {
|
|
2095
3172
|
super(
|
|
2096
3173
|
rootTx,
|
|
@@ -2100,248 +3177,113 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2100
3177
|
comparator,
|
|
2101
3178
|
option
|
|
2102
3179
|
);
|
|
3180
|
+
this._initAlgoContext();
|
|
3181
|
+
}
|
|
3182
|
+
_initAlgoContext() {
|
|
3183
|
+
const mvcc = this.mvcc;
|
|
3184
|
+
const strategy = this.strategy;
|
|
3185
|
+
const self = this;
|
|
3186
|
+
this._ops = {
|
|
3187
|
+
getNode(id) {
|
|
3188
|
+
return mvcc.read(id);
|
|
3189
|
+
},
|
|
3190
|
+
createNode(leaf, keys, values, parent = null, next = null, prev = null) {
|
|
3191
|
+
const id = strategy.id(leaf);
|
|
3192
|
+
const node = { id, keys, values, leaf, parent, next, prev };
|
|
3193
|
+
mvcc.create(id, node);
|
|
3194
|
+
return node;
|
|
3195
|
+
},
|
|
3196
|
+
updateNode(node) {
|
|
3197
|
+
if (mvcc.isDeleted(node.id)) {
|
|
3198
|
+
return;
|
|
3199
|
+
}
|
|
3200
|
+
mvcc.write(node.id, node);
|
|
3201
|
+
},
|
|
3202
|
+
deleteNode(node) {
|
|
3203
|
+
if (mvcc.isDeleted(node.id)) {
|
|
3204
|
+
return;
|
|
3205
|
+
}
|
|
3206
|
+
mvcc.delete(node.id);
|
|
3207
|
+
},
|
|
3208
|
+
readHead() {
|
|
3209
|
+
return mvcc.read("__HEAD__");
|
|
3210
|
+
},
|
|
3211
|
+
writeHead(head) {
|
|
3212
|
+
if (!mvcc.exists("__HEAD__")) {
|
|
3213
|
+
mvcc.create("__HEAD__", head);
|
|
3214
|
+
} else {
|
|
3215
|
+
mvcc.write("__HEAD__", head);
|
|
3216
|
+
}
|
|
3217
|
+
self.rootId = head.root;
|
|
3218
|
+
}
|
|
3219
|
+
};
|
|
3220
|
+
this._ctx = {
|
|
3221
|
+
get rootId() {
|
|
3222
|
+
return self.rootId;
|
|
3223
|
+
},
|
|
3224
|
+
set rootId(v) {
|
|
3225
|
+
self.rootId = v;
|
|
3226
|
+
},
|
|
3227
|
+
get order() {
|
|
3228
|
+
return self.order;
|
|
3229
|
+
},
|
|
3230
|
+
set order(v) {
|
|
3231
|
+
self.order = v;
|
|
3232
|
+
},
|
|
3233
|
+
headData: () => this.strategy.head.data
|
|
3234
|
+
};
|
|
3235
|
+
const ensureValues = (v) => this.ensureValues(v);
|
|
3236
|
+
this._verifierMapCached = createVerifierMap(this.comparator, this._cachedRegexp, ensureValues);
|
|
3237
|
+
this._searchConfigsCached = createSearchConfigs(this.comparator, ensureValues);
|
|
2103
3238
|
}
|
|
3239
|
+
// ─── Legacy protected methods (delegating to ops) ────────────────
|
|
2104
3240
|
getNode(id) {
|
|
2105
|
-
return this.
|
|
3241
|
+
return this._ops.getNode(id);
|
|
2106
3242
|
}
|
|
2107
|
-
/**
|
|
2108
|
-
* Create a new node with a unique ID.
|
|
2109
|
-
*/
|
|
2110
3243
|
_createNode(leaf, keys, values, parent = null, next = null, prev = null) {
|
|
2111
|
-
|
|
2112
|
-
const node = {
|
|
2113
|
-
id,
|
|
2114
|
-
keys,
|
|
2115
|
-
values,
|
|
2116
|
-
leaf,
|
|
2117
|
-
parent,
|
|
2118
|
-
next,
|
|
2119
|
-
prev
|
|
2120
|
-
};
|
|
2121
|
-
this.mvcc.create(id, node);
|
|
2122
|
-
return node;
|
|
3244
|
+
return this._ops.createNode(leaf, keys, values, parent, next, prev);
|
|
2123
3245
|
}
|
|
2124
3246
|
_updateNode(node) {
|
|
2125
|
-
|
|
2126
|
-
return;
|
|
2127
|
-
}
|
|
2128
|
-
this.mvcc.write(node.id, node);
|
|
3247
|
+
this._ops.updateNode(node);
|
|
2129
3248
|
}
|
|
2130
3249
|
_deleteNode(node) {
|
|
2131
|
-
|
|
2132
|
-
return;
|
|
2133
|
-
}
|
|
2134
|
-
this.mvcc.delete(node.id);
|
|
3250
|
+
this._ops.deleteNode(node);
|
|
2135
3251
|
}
|
|
2136
3252
|
_readHead() {
|
|
2137
|
-
return this.
|
|
3253
|
+
return this._ops.readHead();
|
|
2138
3254
|
}
|
|
2139
3255
|
_writeHead(head) {
|
|
2140
|
-
|
|
2141
|
-
this.mvcc.create("__HEAD__", head);
|
|
2142
|
-
} else {
|
|
2143
|
-
this.mvcc.write("__HEAD__", head);
|
|
2144
|
-
}
|
|
2145
|
-
this.rootId = head.root;
|
|
3256
|
+
this._ops.writeHead(head);
|
|
2146
3257
|
}
|
|
3258
|
+
// ─── Tree traversal (delegating to algorithm) ────────────────────
|
|
2147
3259
|
_insertAtLeaf(node, key, value) {
|
|
2148
|
-
|
|
2149
|
-
if (leaf.values.length) {
|
|
2150
|
-
for (let i = 0, len = leaf.values.length; i < len; i++) {
|
|
2151
|
-
const nValue = leaf.values[i];
|
|
2152
|
-
if (this.comparator.isSame(value, nValue)) {
|
|
2153
|
-
const keys = leaf.keys[i];
|
|
2154
|
-
if (keys.includes(key)) {
|
|
2155
|
-
break;
|
|
2156
|
-
}
|
|
2157
|
-
leaf = this._cloneNode(leaf);
|
|
2158
|
-
leaf.keys[i].push(key);
|
|
2159
|
-
this._updateNode(leaf);
|
|
2160
|
-
return leaf;
|
|
2161
|
-
} else if (this.comparator.isLower(value, nValue)) {
|
|
2162
|
-
leaf = this._cloneNode(leaf);
|
|
2163
|
-
leaf.values.splice(i, 0, value);
|
|
2164
|
-
leaf.keys.splice(i, 0, [key]);
|
|
2165
|
-
this._updateNode(leaf);
|
|
2166
|
-
return leaf;
|
|
2167
|
-
} else if (i + 1 === leaf.values.length) {
|
|
2168
|
-
leaf = this._cloneNode(leaf);
|
|
2169
|
-
leaf.values.push(value);
|
|
2170
|
-
leaf.keys.push([key]);
|
|
2171
|
-
this._updateNode(leaf);
|
|
2172
|
-
return leaf;
|
|
2173
|
-
}
|
|
2174
|
-
}
|
|
2175
|
-
} else {
|
|
2176
|
-
leaf = this._cloneNode(leaf);
|
|
2177
|
-
leaf.values = [value];
|
|
2178
|
-
leaf.keys = [[key]];
|
|
2179
|
-
this._updateNode(leaf);
|
|
2180
|
-
return leaf;
|
|
2181
|
-
}
|
|
2182
|
-
return leaf;
|
|
3260
|
+
return insertAtLeaf(this._ops, node, key, value, this.comparator);
|
|
2183
3261
|
}
|
|
2184
3262
|
_insertInParent(node, value, newSiblingNode) {
|
|
2185
|
-
|
|
2186
|
-
node = this._cloneNode(node);
|
|
2187
|
-
newSiblingNode = this._cloneNode(newSiblingNode);
|
|
2188
|
-
const root = this._createNode(false, [node.id, newSiblingNode.id], [value]);
|
|
2189
|
-
this.rootId = root.id;
|
|
2190
|
-
node.parent = root.id;
|
|
2191
|
-
newSiblingNode.parent = root.id;
|
|
2192
|
-
if (newSiblingNode.leaf) {
|
|
2193
|
-
node.next = newSiblingNode.id;
|
|
2194
|
-
newSiblingNode.prev = node.id;
|
|
2195
|
-
}
|
|
2196
|
-
this._writeHead({
|
|
2197
|
-
root: root.id,
|
|
2198
|
-
order: this.order,
|
|
2199
|
-
data: this.strategy.head.data
|
|
2200
|
-
});
|
|
2201
|
-
this._updateNode(node);
|
|
2202
|
-
this._updateNode(newSiblingNode);
|
|
2203
|
-
return;
|
|
2204
|
-
}
|
|
2205
|
-
const parentNode = this._cloneNode(this.getNode(node.parent));
|
|
2206
|
-
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
2207
|
-
if (nodeIndex === -1) {
|
|
2208
|
-
throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
|
|
2209
|
-
}
|
|
2210
|
-
parentNode.values.splice(nodeIndex, 0, value);
|
|
2211
|
-
parentNode.keys.splice(nodeIndex + 1, 0, newSiblingNode.id);
|
|
2212
|
-
newSiblingNode = this._cloneNode(newSiblingNode);
|
|
2213
|
-
newSiblingNode.parent = parentNode.id;
|
|
2214
|
-
if (newSiblingNode.leaf) {
|
|
2215
|
-
const leftSibling = this._cloneNode(node);
|
|
2216
|
-
const oldNextId = leftSibling.next;
|
|
2217
|
-
newSiblingNode.prev = leftSibling.id;
|
|
2218
|
-
newSiblingNode.next = oldNextId;
|
|
2219
|
-
leftSibling.next = newSiblingNode.id;
|
|
2220
|
-
this._updateNode(leftSibling);
|
|
2221
|
-
if (oldNextId) {
|
|
2222
|
-
const oldNext = this._cloneNode(this.getNode(oldNextId));
|
|
2223
|
-
oldNext.prev = newSiblingNode.id;
|
|
2224
|
-
this._updateNode(oldNext);
|
|
2225
|
-
}
|
|
2226
|
-
}
|
|
2227
|
-
this._updateNode(parentNode);
|
|
2228
|
-
this._updateNode(newSiblingNode);
|
|
2229
|
-
if (parentNode.keys.length > this.order) {
|
|
2230
|
-
const newSiblingNodeRecursive = this._createNode(false, [], []);
|
|
2231
|
-
newSiblingNodeRecursive.parent = parentNode.parent;
|
|
2232
|
-
const mid = Math.ceil(this.order / 2) - 1;
|
|
2233
|
-
newSiblingNodeRecursive.values = parentNode.values.slice(mid + 1);
|
|
2234
|
-
newSiblingNodeRecursive.keys = parentNode.keys.slice(mid + 1);
|
|
2235
|
-
const midValue = parentNode.values[mid];
|
|
2236
|
-
parentNode.values = parentNode.values.slice(0, mid);
|
|
2237
|
-
parentNode.keys = parentNode.keys.slice(0, mid + 1);
|
|
2238
|
-
for (let i = 0, len = newSiblingNodeRecursive.keys.length; i < len; i++) {
|
|
2239
|
-
const k = newSiblingNodeRecursive.keys[i];
|
|
2240
|
-
const n = this._cloneNode(this.getNode(k));
|
|
2241
|
-
n.parent = newSiblingNodeRecursive.id;
|
|
2242
|
-
this._updateNode(n);
|
|
2243
|
-
}
|
|
2244
|
-
this._updateNode(parentNode);
|
|
2245
|
-
this._insertInParent(parentNode, midValue, newSiblingNodeRecursive);
|
|
2246
|
-
}
|
|
3263
|
+
insertInParent(this._ops, this._ctx, node, value, newSiblingNode);
|
|
2247
3264
|
}
|
|
2248
3265
|
locateLeaf(value) {
|
|
2249
|
-
|
|
2250
|
-
while (!node.leaf) {
|
|
2251
|
-
const { index } = this._binarySearchValues(node.values, value, false, true);
|
|
2252
|
-
node = this.getNode(node.keys[index]);
|
|
2253
|
-
}
|
|
2254
|
-
return node;
|
|
3266
|
+
return locateLeaf(this._ops, this._ctx.rootId, value, this.comparator);
|
|
2255
3267
|
}
|
|
2256
3268
|
findLowerBoundLeaf(value) {
|
|
2257
|
-
|
|
2258
|
-
while (!node.leaf) {
|
|
2259
|
-
const { index } = this._binarySearchValues(node.values, value, true, false);
|
|
2260
|
-
node = this.getNode(node.keys[index]);
|
|
2261
|
-
}
|
|
2262
|
-
return node;
|
|
3269
|
+
return findLowerBoundLeaf(this._ops, this._ctx.rootId, value, this.comparator);
|
|
2263
3270
|
}
|
|
2264
3271
|
findUpperBoundLeaf(value) {
|
|
2265
|
-
|
|
2266
|
-
while (!node.leaf) {
|
|
2267
|
-
const { index } = this._binarySearchValues(node.values, value, true, true);
|
|
2268
|
-
node = this.getNode(node.keys[index]);
|
|
2269
|
-
}
|
|
2270
|
-
return node;
|
|
3272
|
+
return findUpperBoundLeaf(this._ops, this._ctx.rootId, value, this.comparator);
|
|
2271
3273
|
}
|
|
2272
3274
|
findOuterBoundaryLeaf(value, direction) {
|
|
2273
|
-
|
|
2274
|
-
let key;
|
|
2275
|
-
switch (direction) {
|
|
2276
|
-
case -1:
|
|
2277
|
-
key = "prev";
|
|
2278
|
-
break;
|
|
2279
|
-
case 1:
|
|
2280
|
-
key = "next";
|
|
2281
|
-
break;
|
|
2282
|
-
default:
|
|
2283
|
-
throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
|
|
2284
|
-
}
|
|
2285
|
-
const guessNode = insertableNode[key];
|
|
2286
|
-
if (!guessNode) {
|
|
2287
|
-
return null;
|
|
2288
|
-
}
|
|
2289
|
-
return this.getNode(guessNode);
|
|
3275
|
+
return findOuterBoundaryLeaf(this._ops, this._ctx.rootId, value, direction, this.comparator);
|
|
2290
3276
|
}
|
|
2291
3277
|
leftestNode() {
|
|
2292
|
-
|
|
2293
|
-
if (node === null) {
|
|
2294
|
-
debugger;
|
|
2295
|
-
}
|
|
2296
|
-
while (!node.leaf) {
|
|
2297
|
-
const keys = node.keys;
|
|
2298
|
-
node = this.getNode(keys[0]);
|
|
2299
|
-
}
|
|
2300
|
-
return node;
|
|
3278
|
+
return leftestNode(this._ops, this._ctx.rootId);
|
|
2301
3279
|
}
|
|
2302
3280
|
rightestNode() {
|
|
2303
|
-
|
|
2304
|
-
while (!node.leaf) {
|
|
2305
|
-
const keys = node.keys;
|
|
2306
|
-
node = this.getNode(keys[keys.length - 1]);
|
|
2307
|
-
}
|
|
2308
|
-
return node;
|
|
3281
|
+
return rightestNode(this._ops, this._ctx.rootId);
|
|
2309
3282
|
}
|
|
2310
3283
|
*getPairsGenerator(startNode, endNode, direction) {
|
|
2311
|
-
|
|
2312
|
-
while (true) {
|
|
2313
|
-
if (endNode && node.id === endNode.id) {
|
|
2314
|
-
break;
|
|
2315
|
-
}
|
|
2316
|
-
const len = node.values.length;
|
|
2317
|
-
if (direction === 1) {
|
|
2318
|
-
for (let i = 0; i < len; i++) {
|
|
2319
|
-
const nValue = node.values[i];
|
|
2320
|
-
const keys = node.keys[i];
|
|
2321
|
-
for (let j = 0, len2 = keys.length; j < len2; j++) {
|
|
2322
|
-
yield [keys[j], nValue];
|
|
2323
|
-
}
|
|
2324
|
-
}
|
|
2325
|
-
} else {
|
|
2326
|
-
let i = len;
|
|
2327
|
-
while (i--) {
|
|
2328
|
-
const nValue = node.values[i];
|
|
2329
|
-
const keys = node.keys[i];
|
|
2330
|
-
let j = keys.length;
|
|
2331
|
-
while (j--) {
|
|
2332
|
-
yield [keys[j], nValue];
|
|
2333
|
-
}
|
|
2334
|
-
}
|
|
2335
|
-
}
|
|
2336
|
-
if (direction === 1) {
|
|
2337
|
-
if (!node.next) break;
|
|
2338
|
-
node = this.getNode(node.next);
|
|
2339
|
-
} else {
|
|
2340
|
-
if (!node.prev) break;
|
|
2341
|
-
node = this.getNode(node.prev);
|
|
2342
|
-
}
|
|
2343
|
-
}
|
|
3284
|
+
yield* getPairsGenerator(this._ops, startNode, endNode, direction);
|
|
2344
3285
|
}
|
|
3286
|
+
// ─── Lifecycle ───────────────────────────────────────────────────
|
|
2345
3287
|
init() {
|
|
2346
3288
|
if (this.rootTx !== this) {
|
|
2347
3289
|
throw new Error("Cannot call init on a nested transaction");
|
|
@@ -2357,525 +3299,93 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2357
3299
|
}
|
|
2358
3300
|
this.isInitialized = true;
|
|
2359
3301
|
try {
|
|
2360
|
-
this._clearCache();
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
this.
|
|
2364
|
-
|
|
2365
|
-
this.
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
data: this.strategy.head.data
|
|
2369
|
-
});
|
|
2370
|
-
} else {
|
|
2371
|
-
const { root, order } = head;
|
|
2372
|
-
this.strategy.head = head;
|
|
2373
|
-
this.order = order;
|
|
2374
|
-
this.rootId = root;
|
|
2375
|
-
}
|
|
2376
|
-
if (this.order < 3) {
|
|
2377
|
-
throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
|
|
2378
|
-
}
|
|
2379
|
-
} catch (e) {
|
|
2380
|
-
this.isInitialized = false;
|
|
2381
|
-
throw e;
|
|
2382
|
-
}
|
|
2383
|
-
}
|
|
2384
|
-
exists(key, value) {
|
|
2385
|
-
const node = this.locateLeaf(value);
|
|
2386
|
-
const { index, found } = this._binarySearchValues(node.values, value);
|
|
2387
|
-
if (found) {
|
|
2388
|
-
const keys = node.keys[index];
|
|
2389
|
-
if (keys.includes(key)) {
|
|
2390
|
-
return true;
|
|
2391
|
-
}
|
|
2392
|
-
}
|
|
2393
|
-
return false;
|
|
2394
|
-
}
|
|
2395
|
-
get(key) {
|
|
2396
|
-
let node = this.leftestNode();
|
|
2397
|
-
while (true) {
|
|
2398
|
-
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
2399
|
-
const keys = node.keys[i];
|
|
2400
|
-
for (let j = 0, len2 = keys.length; j < len2; j++) {
|
|
2401
|
-
if (keys[j] === key) {
|
|
2402
|
-
return node.values[i];
|
|
2403
|
-
}
|
|
2404
|
-
}
|
|
2405
|
-
}
|
|
2406
|
-
if (!node.next) break;
|
|
2407
|
-
node = this.getNode(node.next);
|
|
2408
|
-
}
|
|
2409
|
-
return void 0;
|
|
2410
|
-
}
|
|
2411
|
-
*keysStream(condition, options) {
|
|
2412
|
-
const { filterValues, limit, order = "asc" } = options ?? {};
|
|
2413
|
-
const stream = this.whereStream(condition, options);
|
|
2414
|
-
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
2415
|
-
let count = 0;
|
|
2416
|
-
for (const [key] of stream) {
|
|
2417
|
-
if (intersection && !intersection.has(key)) {
|
|
2418
|
-
continue;
|
|
2419
|
-
}
|
|
2420
|
-
yield key;
|
|
2421
|
-
count++;
|
|
2422
|
-
if (limit !== void 0 && count >= limit) {
|
|
2423
|
-
break;
|
|
2424
|
-
}
|
|
2425
|
-
}
|
|
2426
|
-
}
|
|
2427
|
-
*whereStream(condition, options) {
|
|
2428
|
-
const { filterValues, limit, order = "asc" } = options ?? {};
|
|
2429
|
-
const conditionKeys = Object.keys(condition);
|
|
2430
|
-
if (conditionKeys.length === 0) return;
|
|
2431
|
-
const resolved = this.resolveStartEndConfigs(condition, order);
|
|
2432
|
-
const direction = resolved.direction;
|
|
2433
|
-
let startNode;
|
|
2434
|
-
if (resolved.startKey) {
|
|
2435
|
-
const startConfig = this.searchConfigs[resolved.startKey][order];
|
|
2436
|
-
startNode = startConfig.start(this, resolved.startValues);
|
|
2437
|
-
} else {
|
|
2438
|
-
startNode = order === "asc" ? this.leftestNode() : this.rightestNode();
|
|
2439
|
-
}
|
|
2440
|
-
let endNode = null;
|
|
2441
|
-
if (resolved.endKey) {
|
|
2442
|
-
const endConfig = this.searchConfigs[resolved.endKey][order];
|
|
2443
|
-
endNode = endConfig.end(this, resolved.endValues);
|
|
2444
|
-
}
|
|
2445
|
-
if (!startNode) return;
|
|
2446
|
-
const generator = this.getPairsGenerator(
|
|
2447
|
-
startNode,
|
|
2448
|
-
endNode,
|
|
2449
|
-
direction
|
|
2450
|
-
);
|
|
2451
|
-
let count = 0;
|
|
2452
|
-
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
2453
|
-
for (const pair of generator) {
|
|
2454
|
-
const [k, v] = pair;
|
|
2455
|
-
if (intersection && !intersection.has(k)) {
|
|
2456
|
-
continue;
|
|
2457
|
-
}
|
|
2458
|
-
if (this.verify(v, condition)) {
|
|
2459
|
-
yield pair;
|
|
2460
|
-
count++;
|
|
2461
|
-
if (limit !== void 0 && count >= limit) {
|
|
2462
|
-
break;
|
|
2463
|
-
}
|
|
2464
|
-
}
|
|
2465
|
-
}
|
|
2466
|
-
}
|
|
2467
|
-
keys(condition, options) {
|
|
2468
|
-
const set = /* @__PURE__ */ new Set();
|
|
2469
|
-
for (const key of this.keysStream(condition, options)) {
|
|
2470
|
-
set.add(key);
|
|
2471
|
-
}
|
|
2472
|
-
return set;
|
|
2473
|
-
}
|
|
2474
|
-
where(condition, options) {
|
|
2475
|
-
const map = /* @__PURE__ */ new Map();
|
|
2476
|
-
for (const [key, value] of this.whereStream(condition, options)) {
|
|
2477
|
-
map.set(key, value);
|
|
2478
|
-
}
|
|
2479
|
-
return map;
|
|
2480
|
-
}
|
|
2481
|
-
insert(key, value) {
|
|
2482
|
-
let before = this.locateLeaf(value);
|
|
2483
|
-
before = this._insertAtLeaf(before, key, value);
|
|
2484
|
-
if (before.values.length === this.order) {
|
|
2485
|
-
let after = this._createNode(
|
|
2486
|
-
true,
|
|
2487
|
-
[],
|
|
2488
|
-
[],
|
|
2489
|
-
before.parent,
|
|
2490
|
-
null,
|
|
2491
|
-
null
|
|
2492
|
-
);
|
|
2493
|
-
const mid = Math.ceil(this.order / 2) - 1;
|
|
2494
|
-
after = this._cloneNode(after);
|
|
2495
|
-
after.values = before.values.slice(mid + 1);
|
|
2496
|
-
after.keys = before.keys.slice(mid + 1);
|
|
2497
|
-
before.values = before.values.slice(0, mid + 1);
|
|
2498
|
-
before.keys = before.keys.slice(0, mid + 1);
|
|
2499
|
-
this._updateNode(before);
|
|
2500
|
-
this._updateNode(after);
|
|
2501
|
-
this._insertInParent(before, after.values[0], after);
|
|
2502
|
-
}
|
|
2503
|
-
}
|
|
2504
|
-
batchInsert(entries) {
|
|
2505
|
-
if (entries.length === 0) return;
|
|
2506
|
-
const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
|
|
2507
|
-
let currentLeaf = null;
|
|
2508
|
-
let modified = false;
|
|
2509
|
-
let cachedLeafId = null;
|
|
2510
|
-
let cachedLeafMaxValue = null;
|
|
2511
|
-
for (let i = 0, len = sorted.length; i < len; i++) {
|
|
2512
|
-
const [key, value] = sorted[i];
|
|
2513
|
-
let targetLeaf;
|
|
2514
|
-
if (cachedLeafId !== null && cachedLeafMaxValue !== null && currentLeaf !== null && (this.comparator.isLower(value, cachedLeafMaxValue) || this.comparator.isSame(value, cachedLeafMaxValue))) {
|
|
2515
|
-
targetLeaf = currentLeaf;
|
|
2516
|
-
} else {
|
|
2517
|
-
targetLeaf = this.locateLeaf(value);
|
|
2518
|
-
}
|
|
2519
|
-
if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
|
|
2520
|
-
} else {
|
|
2521
|
-
if (currentLeaf !== null && modified) {
|
|
2522
|
-
this._updateNode(currentLeaf);
|
|
2523
|
-
}
|
|
2524
|
-
currentLeaf = this._cloneNode(targetLeaf);
|
|
2525
|
-
modified = false;
|
|
2526
|
-
}
|
|
2527
|
-
cachedLeafId = currentLeaf.id;
|
|
2528
|
-
const changed = this._insertValueIntoLeaf(currentLeaf, key, value);
|
|
2529
|
-
modified = modified || changed;
|
|
2530
|
-
cachedLeafMaxValue = currentLeaf.values[currentLeaf.values.length - 1];
|
|
2531
|
-
if (currentLeaf.values.length === this.order) {
|
|
2532
|
-
this._updateNode(currentLeaf);
|
|
2533
|
-
let after = this._createNode(
|
|
2534
|
-
true,
|
|
2535
|
-
[],
|
|
2536
|
-
[],
|
|
2537
|
-
currentLeaf.parent,
|
|
2538
|
-
null,
|
|
2539
|
-
null
|
|
2540
|
-
);
|
|
2541
|
-
const mid = Math.ceil(this.order / 2) - 1;
|
|
2542
|
-
after = this._cloneNode(after);
|
|
2543
|
-
after.values = currentLeaf.values.slice(mid + 1);
|
|
2544
|
-
after.keys = currentLeaf.keys.slice(mid + 1);
|
|
2545
|
-
currentLeaf.values = currentLeaf.values.slice(0, mid + 1);
|
|
2546
|
-
currentLeaf.keys = currentLeaf.keys.slice(0, mid + 1);
|
|
2547
|
-
this._updateNode(currentLeaf);
|
|
2548
|
-
this._updateNode(after);
|
|
2549
|
-
this._insertInParent(currentLeaf, after.values[0], after);
|
|
2550
|
-
currentLeaf = null;
|
|
2551
|
-
cachedLeafId = null;
|
|
2552
|
-
cachedLeafMaxValue = null;
|
|
2553
|
-
modified = false;
|
|
2554
|
-
}
|
|
2555
|
-
}
|
|
2556
|
-
if (currentLeaf !== null && modified) {
|
|
2557
|
-
this._updateNode(currentLeaf);
|
|
2558
|
-
}
|
|
2559
|
-
}
|
|
2560
|
-
bulkLoad(entries) {
|
|
2561
|
-
if (entries.length === 0) return;
|
|
2562
|
-
const root = this.getNode(this.rootId);
|
|
2563
|
-
if (!root.leaf || root.values.length > 0) {
|
|
2564
|
-
throw new Error("bulkLoad can only be called on an empty tree. Use batchInsert for non-empty trees.");
|
|
2565
|
-
}
|
|
2566
|
-
const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
|
|
2567
|
-
const grouped = [];
|
|
2568
|
-
for (let i = 0, len = sorted.length; i < len; i++) {
|
|
2569
|
-
const [key, value] = sorted[i];
|
|
2570
|
-
const last = grouped[grouped.length - 1];
|
|
2571
|
-
if (last && this.comparator.isSame(last.value, value)) {
|
|
2572
|
-
if (!last.keys.includes(key)) {
|
|
2573
|
-
last.keys.push(key);
|
|
2574
|
-
}
|
|
2575
|
-
} else {
|
|
2576
|
-
grouped.push({ keys: [key], value });
|
|
2577
|
-
}
|
|
2578
|
-
}
|
|
2579
|
-
this._deleteNode(root);
|
|
2580
|
-
const maxLeafSize = this.order - 1;
|
|
2581
|
-
const leaves = [];
|
|
2582
|
-
for (let i = 0, len = grouped.length; i < len; i += maxLeafSize) {
|
|
2583
|
-
const chunk = grouped.slice(i, i + maxLeafSize);
|
|
2584
|
-
const leafKeys = chunk.map((g) => g.keys);
|
|
2585
|
-
const leafValues = chunk.map((g) => g.value);
|
|
2586
|
-
const leaf = this._createNode(
|
|
2587
|
-
true,
|
|
2588
|
-
leafKeys,
|
|
2589
|
-
leafValues,
|
|
2590
|
-
null,
|
|
2591
|
-
null,
|
|
2592
|
-
null
|
|
2593
|
-
);
|
|
2594
|
-
leaves.push(leaf);
|
|
2595
|
-
}
|
|
2596
|
-
for (let i = 0, len = leaves.length; i < len; i++) {
|
|
2597
|
-
if (i > 0) {
|
|
2598
|
-
leaves[i].prev = leaves[i - 1].id;
|
|
2599
|
-
}
|
|
2600
|
-
if (i < len - 1) {
|
|
2601
|
-
leaves[i].next = leaves[i + 1].id;
|
|
2602
|
-
}
|
|
2603
|
-
this._updateNode(leaves[i]);
|
|
2604
|
-
}
|
|
2605
|
-
let currentLevel = leaves;
|
|
2606
|
-
while (currentLevel.length > 1) {
|
|
2607
|
-
const nextLevel = [];
|
|
2608
|
-
for (let i = 0, len = currentLevel.length; i < len; i += this.order) {
|
|
2609
|
-
const children = currentLevel.slice(i, i + this.order);
|
|
2610
|
-
const childIds = children.map((c) => c.id);
|
|
2611
|
-
const separators = [];
|
|
2612
|
-
for (let j = 1, len2 = children.length; j < len2; j++) {
|
|
2613
|
-
separators.push(children[j].values[0]);
|
|
2614
|
-
}
|
|
2615
|
-
const internalNode = this._createNode(
|
|
2616
|
-
false,
|
|
2617
|
-
childIds,
|
|
2618
|
-
separators,
|
|
2619
|
-
null,
|
|
2620
|
-
null,
|
|
2621
|
-
null
|
|
2622
|
-
);
|
|
2623
|
-
for (let j = 0, len2 = children.length; j < len2; j++) {
|
|
2624
|
-
const child = children[j];
|
|
2625
|
-
child.parent = internalNode.id;
|
|
2626
|
-
this._updateNode(child);
|
|
2627
|
-
}
|
|
2628
|
-
nextLevel.push(internalNode);
|
|
2629
|
-
}
|
|
2630
|
-
currentLevel = nextLevel;
|
|
2631
|
-
}
|
|
2632
|
-
const newRoot = currentLevel[0];
|
|
2633
|
-
this._writeHead({
|
|
2634
|
-
root: newRoot.id,
|
|
2635
|
-
order: this.order,
|
|
2636
|
-
data: this.strategy.head.data
|
|
2637
|
-
});
|
|
2638
|
-
}
|
|
2639
|
-
_deleteEntry(node, key) {
|
|
2640
|
-
if (!node.leaf) {
|
|
2641
|
-
let keyIndex = -1;
|
|
2642
|
-
for (let i = 0, len = node.keys.length; i < len; i++) {
|
|
2643
|
-
if (node.keys[i] === key) {
|
|
2644
|
-
keyIndex = i;
|
|
2645
|
-
break;
|
|
2646
|
-
}
|
|
2647
|
-
}
|
|
2648
|
-
if (keyIndex !== -1) {
|
|
2649
|
-
node = this._cloneNode(node);
|
|
2650
|
-
node.keys.splice(keyIndex, 1);
|
|
2651
|
-
const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
|
|
2652
|
-
node.values.splice(valueIndex, 1);
|
|
2653
|
-
this._updateNode(node);
|
|
2654
|
-
}
|
|
2655
|
-
}
|
|
2656
|
-
if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
|
|
2657
|
-
const keys = node.keys;
|
|
2658
|
-
this._deleteNode(node);
|
|
2659
|
-
const newRoot = this._cloneNode(this.getNode(keys[0]));
|
|
2660
|
-
newRoot.parent = null;
|
|
2661
|
-
this._updateNode(newRoot);
|
|
2662
|
-
this._writeHead({
|
|
2663
|
-
root: newRoot.id,
|
|
2664
|
-
order: this.order,
|
|
2665
|
-
data: this.strategy.head.data
|
|
2666
|
-
});
|
|
2667
|
-
return node;
|
|
2668
|
-
} else if (this.rootId === node.id) {
|
|
2669
|
-
this._writeHead({
|
|
2670
|
-
root: node.id,
|
|
2671
|
-
order: this.order,
|
|
2672
|
-
data: this.strategy.head.data
|
|
2673
|
-
});
|
|
2674
|
-
return node;
|
|
2675
|
-
} else if (node.keys.length < Math.ceil(this.order / 2) && !node.leaf || node.values.length < Math.ceil((this.order - 1) / 2) && node.leaf) {
|
|
2676
|
-
if (node.parent === null) {
|
|
2677
|
-
return node;
|
|
2678
|
-
}
|
|
2679
|
-
let isPredecessor = false;
|
|
2680
|
-
let parentNode = this.getNode(node.parent);
|
|
2681
|
-
let prevNode = null;
|
|
2682
|
-
let nextNode = null;
|
|
2683
|
-
let prevValue = null;
|
|
2684
|
-
let postValue = null;
|
|
2685
|
-
for (let i = 0, len = parentNode.keys.length; i < len; i++) {
|
|
2686
|
-
const nKey = parentNode.keys[i];
|
|
2687
|
-
if (nKey === node.id) {
|
|
2688
|
-
if (i > 0) {
|
|
2689
|
-
prevNode = this.getNode(parentNode.keys[i - 1]);
|
|
2690
|
-
prevValue = parentNode.values[i - 1];
|
|
2691
|
-
}
|
|
2692
|
-
if (i < parentNode.keys.length - 1) {
|
|
2693
|
-
nextNode = this.getNode(parentNode.keys[i + 1]);
|
|
2694
|
-
postValue = parentNode.values[i];
|
|
2695
|
-
}
|
|
2696
|
-
}
|
|
2697
|
-
}
|
|
2698
|
-
let siblingNode;
|
|
2699
|
-
let guess;
|
|
2700
|
-
if (prevNode === null) {
|
|
2701
|
-
siblingNode = nextNode;
|
|
2702
|
-
guess = postValue;
|
|
2703
|
-
} else if (nextNode === null) {
|
|
2704
|
-
isPredecessor = true;
|
|
2705
|
-
siblingNode = prevNode;
|
|
2706
|
-
guess = prevValue;
|
|
2707
|
-
} else {
|
|
2708
|
-
if (node.values.length + nextNode.values.length < this.order) {
|
|
2709
|
-
siblingNode = nextNode;
|
|
2710
|
-
guess = postValue;
|
|
2711
|
-
} else {
|
|
2712
|
-
isPredecessor = true;
|
|
2713
|
-
siblingNode = prevNode;
|
|
2714
|
-
guess = prevValue;
|
|
2715
|
-
}
|
|
2716
|
-
}
|
|
2717
|
-
if (!siblingNode) {
|
|
2718
|
-
return node;
|
|
2719
|
-
}
|
|
2720
|
-
node = this._cloneNode(node);
|
|
2721
|
-
siblingNode = this._cloneNode(siblingNode);
|
|
2722
|
-
if (node.values.length + siblingNode.values.length < this.order) {
|
|
2723
|
-
if (!isPredecessor) {
|
|
2724
|
-
const pTemp = siblingNode;
|
|
2725
|
-
siblingNode = node;
|
|
2726
|
-
node = pTemp;
|
|
2727
|
-
}
|
|
2728
|
-
siblingNode.keys.push(...node.keys);
|
|
2729
|
-
if (!node.leaf) {
|
|
2730
|
-
siblingNode.values.push(guess);
|
|
2731
|
-
} else {
|
|
2732
|
-
siblingNode.next = node.next;
|
|
2733
|
-
if (siblingNode.next) {
|
|
2734
|
-
const n = this._cloneNode(this.getNode(siblingNode.next));
|
|
2735
|
-
n.prev = siblingNode.id;
|
|
2736
|
-
this._updateNode(n);
|
|
2737
|
-
}
|
|
2738
|
-
}
|
|
2739
|
-
siblingNode.values.push(...node.values);
|
|
2740
|
-
if (!siblingNode.leaf) {
|
|
2741
|
-
const keys = siblingNode.keys;
|
|
2742
|
-
for (let i = 0, len = keys.length; i < len; i++) {
|
|
2743
|
-
const key2 = keys[i];
|
|
2744
|
-
const node2 = this._cloneNode(this.getNode(key2));
|
|
2745
|
-
node2.parent = siblingNode.id;
|
|
2746
|
-
this._updateNode(node2);
|
|
2747
|
-
}
|
|
2748
|
-
}
|
|
2749
|
-
this._deleteNode(node);
|
|
2750
|
-
this._updateNode(siblingNode);
|
|
2751
|
-
this._deleteEntry(this.getNode(node.parent), node.id);
|
|
2752
|
-
} else {
|
|
2753
|
-
if (isPredecessor) {
|
|
2754
|
-
let pointerPm;
|
|
2755
|
-
let pointerKm;
|
|
2756
|
-
if (!node.leaf) {
|
|
2757
|
-
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
2758
|
-
pointerKm = siblingNode.values.splice(-1)[0];
|
|
2759
|
-
node.keys = [pointerPm, ...node.keys];
|
|
2760
|
-
node.values = [guess, ...node.values];
|
|
2761
|
-
parentNode = this._cloneNode(this.getNode(node.parent));
|
|
2762
|
-
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
2763
|
-
if (nodeIndex > 0) {
|
|
2764
|
-
parentNode.values[nodeIndex - 1] = pointerKm;
|
|
2765
|
-
this._updateNode(parentNode);
|
|
2766
|
-
}
|
|
2767
|
-
} else {
|
|
2768
|
-
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
2769
|
-
pointerKm = siblingNode.values.splice(-1)[0];
|
|
2770
|
-
node.keys = [pointerPm, ...node.keys];
|
|
2771
|
-
node.values = [pointerKm, ...node.values];
|
|
2772
|
-
parentNode = this._cloneNode(this.getNode(node.parent));
|
|
2773
|
-
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
2774
|
-
if (nodeIndex > 0) {
|
|
2775
|
-
parentNode.values[nodeIndex - 1] = pointerKm;
|
|
2776
|
-
this._updateNode(parentNode);
|
|
2777
|
-
}
|
|
2778
|
-
}
|
|
2779
|
-
this._updateNode(node);
|
|
2780
|
-
this._updateNode(siblingNode);
|
|
2781
|
-
} else {
|
|
2782
|
-
let pointerP0;
|
|
2783
|
-
let pointerK0;
|
|
2784
|
-
if (!node.leaf) {
|
|
2785
|
-
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
2786
|
-
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
2787
|
-
node.keys = [...node.keys, pointerP0];
|
|
2788
|
-
node.values = [...node.values, guess];
|
|
2789
|
-
parentNode = this._cloneNode(this.getNode(node.parent));
|
|
2790
|
-
const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
|
|
2791
|
-
if (pointerIndex > 0) {
|
|
2792
|
-
parentNode.values[pointerIndex - 1] = pointerK0;
|
|
2793
|
-
this._updateNode(parentNode);
|
|
2794
|
-
}
|
|
2795
|
-
} else {
|
|
2796
|
-
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
2797
|
-
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
2798
|
-
node.keys = [...node.keys, pointerP0];
|
|
2799
|
-
node.values = [...node.values, pointerK0];
|
|
2800
|
-
parentNode = this._cloneNode(this.getNode(node.parent));
|
|
2801
|
-
const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
|
|
2802
|
-
if (pointerIndex > 0) {
|
|
2803
|
-
parentNode.values[pointerIndex - 1] = siblingNode.values[0];
|
|
2804
|
-
this._updateNode(parentNode);
|
|
2805
|
-
}
|
|
2806
|
-
}
|
|
2807
|
-
this._updateNode(node);
|
|
2808
|
-
this._updateNode(siblingNode);
|
|
2809
|
-
}
|
|
2810
|
-
if (!siblingNode.leaf) {
|
|
2811
|
-
for (let i = 0, len = siblingNode.keys.length; i < len; i++) {
|
|
2812
|
-
const key2 = siblingNode.keys[i];
|
|
2813
|
-
const n = this._cloneNode(this.getNode(key2));
|
|
2814
|
-
n.parent = siblingNode.id;
|
|
2815
|
-
this._updateNode(n);
|
|
2816
|
-
}
|
|
2817
|
-
}
|
|
2818
|
-
if (!node.leaf) {
|
|
2819
|
-
for (let i = 0, len = node.keys.length; i < len; i++) {
|
|
2820
|
-
const key2 = node.keys[i];
|
|
2821
|
-
const n = this._cloneNode(this.getNode(key2));
|
|
2822
|
-
n.parent = node.id;
|
|
2823
|
-
this._updateNode(n);
|
|
2824
|
-
}
|
|
2825
|
-
}
|
|
2826
|
-
if (!parentNode.leaf) {
|
|
2827
|
-
for (let i = 0, len = parentNode.keys.length; i < len; i++) {
|
|
2828
|
-
const key2 = parentNode.keys[i];
|
|
2829
|
-
const n = this._cloneNode(this.getNode(key2));
|
|
2830
|
-
n.parent = parentNode.id;
|
|
2831
|
-
this._updateNode(n);
|
|
2832
|
-
}
|
|
3302
|
+
this._clearCache();
|
|
3303
|
+
initOp(
|
|
3304
|
+
this._ops,
|
|
3305
|
+
this._ctx,
|
|
3306
|
+
this.strategy.order,
|
|
3307
|
+
this.strategy.head,
|
|
3308
|
+
(head) => {
|
|
3309
|
+
this.strategy.head = head;
|
|
2833
3310
|
}
|
|
2834
|
-
|
|
2835
|
-
}
|
|
2836
|
-
this.
|
|
3311
|
+
);
|
|
3312
|
+
} catch (e) {
|
|
3313
|
+
this.isInitialized = false;
|
|
3314
|
+
throw e;
|
|
2837
3315
|
}
|
|
2838
|
-
return node;
|
|
2839
3316
|
}
|
|
2840
|
-
|
|
2841
|
-
if (
|
|
2842
|
-
|
|
3317
|
+
reload() {
|
|
3318
|
+
if (this.rootTx !== this) {
|
|
3319
|
+
throw new Error("Cannot call reload on a nested transaction");
|
|
2843
3320
|
}
|
|
2844
|
-
|
|
2845
|
-
|
|
3321
|
+
this._reloadInternal();
|
|
3322
|
+
}
|
|
3323
|
+
_reloadInternal() {
|
|
3324
|
+
this._resetForReload();
|
|
3325
|
+
this._initInternal();
|
|
3326
|
+
}
|
|
3327
|
+
// ─── Query (delegating to algorithm) ─────────────────────────────
|
|
3328
|
+
exists(key, value) {
|
|
3329
|
+
return existsOp(this._ops, this._ctx.rootId, key, value, this.comparator);
|
|
3330
|
+
}
|
|
3331
|
+
get(key) {
|
|
3332
|
+
return getOp(this._ops, this._ctx.rootId, key);
|
|
3333
|
+
}
|
|
3334
|
+
*keysStream(condition, options) {
|
|
3335
|
+
yield* keysStreamOp(
|
|
3336
|
+
this._ops,
|
|
3337
|
+
this._ctx.rootId,
|
|
3338
|
+
condition,
|
|
3339
|
+
this.comparator,
|
|
3340
|
+
this._verifierMapCached,
|
|
3341
|
+
this._searchConfigsCached,
|
|
3342
|
+
this.ensureValues.bind(this),
|
|
3343
|
+
options
|
|
3344
|
+
);
|
|
3345
|
+
}
|
|
3346
|
+
*whereStream(condition, options) {
|
|
3347
|
+
yield* whereStreamOp(
|
|
3348
|
+
this._ops,
|
|
3349
|
+
this._ctx.rootId,
|
|
3350
|
+
condition,
|
|
3351
|
+
this.comparator,
|
|
3352
|
+
this._verifierMapCached,
|
|
3353
|
+
this._searchConfigsCached,
|
|
3354
|
+
this.ensureValues.bind(this),
|
|
3355
|
+
options
|
|
3356
|
+
);
|
|
3357
|
+
}
|
|
3358
|
+
keys(condition, options) {
|
|
3359
|
+
const set = /* @__PURE__ */ new Set();
|
|
3360
|
+
for (const key of this.keysStream(condition, options)) {
|
|
3361
|
+
set.add(key);
|
|
2846
3362
|
}
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
if (this.comparator.isSame(value, nValue)) {
|
|
2854
|
-
const keys = node.keys[i];
|
|
2855
|
-
const keyIndex = keys.indexOf(key);
|
|
2856
|
-
if (keyIndex !== -1) {
|
|
2857
|
-
node = this._cloneNode(node);
|
|
2858
|
-
const freshKeys = node.keys[i];
|
|
2859
|
-
freshKeys.splice(keyIndex, 1);
|
|
2860
|
-
if (freshKeys.length === 0) {
|
|
2861
|
-
node.keys.splice(i, 1);
|
|
2862
|
-
node.values.splice(i, 1);
|
|
2863
|
-
}
|
|
2864
|
-
this._updateNode(node);
|
|
2865
|
-
node = this._deleteEntry(node, key);
|
|
2866
|
-
found = true;
|
|
2867
|
-
break;
|
|
2868
|
-
}
|
|
2869
|
-
}
|
|
2870
|
-
}
|
|
2871
|
-
if (found) break;
|
|
2872
|
-
if (node.next) {
|
|
2873
|
-
node = this.getNode(node.next);
|
|
2874
|
-
continue;
|
|
2875
|
-
}
|
|
2876
|
-
break;
|
|
3363
|
+
return set;
|
|
3364
|
+
}
|
|
3365
|
+
where(condition, options) {
|
|
3366
|
+
const map = /* @__PURE__ */ new Map();
|
|
3367
|
+
for (const [key, value] of this.whereStream(condition, options)) {
|
|
3368
|
+
map.set(key, value);
|
|
2877
3369
|
}
|
|
3370
|
+
return map;
|
|
2878
3371
|
}
|
|
3372
|
+
// ─── Mutation (delegating to algorithm) ──────────────────────────
|
|
3373
|
+
insert(key, value) {
|
|
3374
|
+
insertOp(this._ops, this._ctx, key, value, this.comparator);
|
|
3375
|
+
}
|
|
3376
|
+
batchInsert(entries) {
|
|
3377
|
+
batchInsertOp(this._ops, this._ctx, entries, this.comparator);
|
|
3378
|
+
}
|
|
3379
|
+
bulkLoad(entries) {
|
|
3380
|
+
bulkLoadOp(this._ops, this._ctx, entries, this.comparator);
|
|
3381
|
+
}
|
|
3382
|
+
_deleteEntry(node, key) {
|
|
3383
|
+
return deleteEntry(this._ops, this._ctx, node, key, this.comparator);
|
|
3384
|
+
}
|
|
3385
|
+
delete(key, value) {
|
|
3386
|
+
deleteOp(this._ops, this._ctx, key, this.comparator, value);
|
|
3387
|
+
}
|
|
3388
|
+
// ─── Head Data ───────────────────────────────────────────────────
|
|
2879
3389
|
getHeadData() {
|
|
2880
3390
|
const head = this._readHead();
|
|
2881
3391
|
if (head === null) {
|
|
@@ -2894,6 +3404,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2894
3404
|
data
|
|
2895
3405
|
});
|
|
2896
3406
|
}
|
|
3407
|
+
// ─── Transaction ─────────────────────────────────────────────────
|
|
2897
3408
|
commit(label) {
|
|
2898
3409
|
let result = this.mvcc.commit(label);
|
|
2899
3410
|
if (result.success) {
|
|
@@ -3213,71 +3724,878 @@ var Ryoiki2 = class _Ryoiki2 {
|
|
|
3213
3724
|
rangeTask: [Array, Function],
|
|
3214
3725
|
rangeTaskTimeout: [Array, Function, Number]
|
|
3215
3726
|
}
|
|
3216
|
-
);
|
|
3217
|
-
return this._lock(
|
|
3218
|
-
this.readQueue,
|
|
3219
|
-
range,
|
|
3220
|
-
timeout,
|
|
3221
|
-
task,
|
|
3222
|
-
() => !this.rangeOverlapping(this.writings, range)
|
|
3223
|
-
);
|
|
3224
|
-
}
|
|
3225
|
-
/**
|
|
3226
|
-
* Internal implementation of the write lock. Handles both overloads.
|
|
3227
|
-
* @template T - The return type of the task.
|
|
3228
|
-
* @param arg0 - Either a range or a task callback.
|
|
3229
|
-
* If a range is provided, the task is the second argument.
|
|
3230
|
-
* @param arg1 - The task to execute, required if a range is provided.
|
|
3231
|
-
* @param arg2 - The timeout for acquiring the lock.
|
|
3232
|
-
* If the lock cannot be acquired within this period, an error will be thrown.
|
|
3233
|
-
* If this value is not provided, no timeout will be set.
|
|
3234
|
-
* @returns A promise resolving to the result of the task execution.
|
|
3235
|
-
*/
|
|
3236
|
-
writeLock(arg0, arg1, arg2) {
|
|
3237
|
-
const [range, task, timeout] = this._handleOverload(
|
|
3238
|
-
[arg0, arg1, arg2],
|
|
3239
|
-
{
|
|
3240
|
-
rangeTask: (range2, task2) => [range2, task2, -1],
|
|
3241
|
-
rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
|
|
3242
|
-
task: (task2) => [[-Infinity, Infinity], task2, -1],
|
|
3243
|
-
taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
|
|
3727
|
+
);
|
|
3728
|
+
return this._lock(
|
|
3729
|
+
this.readQueue,
|
|
3730
|
+
range,
|
|
3731
|
+
timeout,
|
|
3732
|
+
task,
|
|
3733
|
+
() => !this.rangeOverlapping(this.writings, range)
|
|
3734
|
+
);
|
|
3735
|
+
}
|
|
3736
|
+
/**
|
|
3737
|
+
* Internal implementation of the write lock. Handles both overloads.
|
|
3738
|
+
* @template T - The return type of the task.
|
|
3739
|
+
* @param arg0 - Either a range or a task callback.
|
|
3740
|
+
* If a range is provided, the task is the second argument.
|
|
3741
|
+
* @param arg1 - The task to execute, required if a range is provided.
|
|
3742
|
+
* @param arg2 - The timeout for acquiring the lock.
|
|
3743
|
+
* If the lock cannot be acquired within this period, an error will be thrown.
|
|
3744
|
+
* If this value is not provided, no timeout will be set.
|
|
3745
|
+
* @returns A promise resolving to the result of the task execution.
|
|
3746
|
+
*/
|
|
3747
|
+
writeLock(arg0, arg1, arg2) {
|
|
3748
|
+
const [range, task, timeout] = this._handleOverload(
|
|
3749
|
+
[arg0, arg1, arg2],
|
|
3750
|
+
{
|
|
3751
|
+
rangeTask: (range2, task2) => [range2, task2, -1],
|
|
3752
|
+
rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
|
|
3753
|
+
task: (task2) => [[-Infinity, Infinity], task2, -1],
|
|
3754
|
+
taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
|
|
3755
|
+
},
|
|
3756
|
+
{
|
|
3757
|
+
task: [Function],
|
|
3758
|
+
taskTimeout: [Function, Number],
|
|
3759
|
+
rangeTask: [Array, Function],
|
|
3760
|
+
rangeTaskTimeout: [Array, Function, Number]
|
|
3761
|
+
}
|
|
3762
|
+
);
|
|
3763
|
+
return this._lock(
|
|
3764
|
+
this.writeQueue,
|
|
3765
|
+
range,
|
|
3766
|
+
timeout,
|
|
3767
|
+
task,
|
|
3768
|
+
() => {
|
|
3769
|
+
return !this.rangeOverlapping(this.writings, range) && !this.rangeOverlapping(this.readings, range);
|
|
3770
|
+
}
|
|
3771
|
+
);
|
|
3772
|
+
}
|
|
3773
|
+
/**
|
|
3774
|
+
* Releases a read lock by its lock ID.
|
|
3775
|
+
* @param lockId - The unique identifier for the lock to release.
|
|
3776
|
+
*/
|
|
3777
|
+
readUnlock(lockId) {
|
|
3778
|
+
this._free(this.readings, lockId);
|
|
3779
|
+
}
|
|
3780
|
+
/**
|
|
3781
|
+
* Releases a write lock by its lock ID.
|
|
3782
|
+
* @param lockId - The unique identifier for the lock to release.
|
|
3783
|
+
*/
|
|
3784
|
+
writeUnlock(lockId) {
|
|
3785
|
+
this._free(this.writings, lockId);
|
|
3786
|
+
}
|
|
3787
|
+
};
|
|
3788
|
+
|
|
3789
|
+
// src/base/BPTreeAlgorithmAsync.ts
|
|
3790
|
+
function createSearchConfigsAsync(comparator, ensureValues) {
|
|
3791
|
+
const lowest = (v) => [...v].sort((a, b) => comparator.asc(a, b))[0];
|
|
3792
|
+
const highest = (v) => [...v].sort((a, b) => comparator.asc(a, b))[v.length - 1];
|
|
3793
|
+
const lowestPrimary = (v) => [...v].sort((a, b) => comparator.primaryAsc(a, b))[0];
|
|
3794
|
+
const highestPrimary = (v) => [...v].sort((a, b) => comparator.primaryAsc(a, b))[v.length - 1];
|
|
3795
|
+
return {
|
|
3796
|
+
gt: {
|
|
3797
|
+
asc: {
|
|
3798
|
+
start: (r, ops, v) => findUpperBoundLeafAsync(ops, r, v[0], comparator),
|
|
3799
|
+
end: async () => null,
|
|
3800
|
+
direction: 1,
|
|
3801
|
+
earlyTerminate: false
|
|
3802
|
+
},
|
|
3803
|
+
desc: {
|
|
3804
|
+
start: (r, ops) => rightestNodeAsync(ops, r),
|
|
3805
|
+
end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], -1, comparator),
|
|
3806
|
+
direction: -1,
|
|
3807
|
+
earlyTerminate: true
|
|
3808
|
+
}
|
|
3809
|
+
},
|
|
3810
|
+
gte: {
|
|
3811
|
+
asc: {
|
|
3812
|
+
start: (r, ops, v) => findLowerBoundLeafAsync(ops, r, v[0], comparator),
|
|
3813
|
+
end: async () => null,
|
|
3814
|
+
direction: 1,
|
|
3815
|
+
earlyTerminate: false
|
|
3816
|
+
},
|
|
3817
|
+
desc: {
|
|
3818
|
+
start: (r, ops) => rightestNodeAsync(ops, r),
|
|
3819
|
+
end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], -1, comparator),
|
|
3820
|
+
direction: -1,
|
|
3821
|
+
earlyTerminate: true
|
|
3822
|
+
}
|
|
3823
|
+
},
|
|
3824
|
+
lt: {
|
|
3825
|
+
asc: {
|
|
3826
|
+
start: (r, ops) => leftestNodeAsync(ops, r),
|
|
3827
|
+
end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], 1, comparator),
|
|
3828
|
+
direction: 1,
|
|
3829
|
+
earlyTerminate: true
|
|
3830
|
+
},
|
|
3831
|
+
desc: {
|
|
3832
|
+
start: (r, ops, v) => findLowerBoundLeafAsync(ops, r, v[0], comparator),
|
|
3833
|
+
end: async () => null,
|
|
3834
|
+
direction: -1,
|
|
3835
|
+
earlyTerminate: false
|
|
3836
|
+
}
|
|
3837
|
+
},
|
|
3838
|
+
lte: {
|
|
3839
|
+
asc: {
|
|
3840
|
+
start: (r, ops) => leftestNodeAsync(ops, r),
|
|
3841
|
+
end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], 1, comparator),
|
|
3842
|
+
direction: 1,
|
|
3843
|
+
earlyTerminate: true
|
|
3844
|
+
},
|
|
3845
|
+
desc: {
|
|
3846
|
+
start: (r, ops, v) => findUpperBoundLeafAsync(ops, r, v[0], comparator),
|
|
3847
|
+
end: async () => null,
|
|
3848
|
+
direction: -1,
|
|
3849
|
+
earlyTerminate: false
|
|
3850
|
+
}
|
|
3851
|
+
},
|
|
3852
|
+
equal: {
|
|
3853
|
+
asc: {
|
|
3854
|
+
start: (r, ops, v) => findLowerBoundLeafAsync(ops, r, v[0], comparator),
|
|
3855
|
+
end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], 1, comparator),
|
|
3856
|
+
direction: 1,
|
|
3857
|
+
earlyTerminate: true
|
|
3858
|
+
},
|
|
3859
|
+
desc: {
|
|
3860
|
+
start: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], 1, comparator),
|
|
3861
|
+
end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], -1, comparator),
|
|
3862
|
+
direction: -1,
|
|
3863
|
+
earlyTerminate: true
|
|
3864
|
+
}
|
|
3865
|
+
},
|
|
3866
|
+
notEqual: {
|
|
3867
|
+
asc: {
|
|
3868
|
+
start: (r, ops) => leftestNodeAsync(ops, r),
|
|
3869
|
+
end: async () => null,
|
|
3870
|
+
direction: 1,
|
|
3871
|
+
earlyTerminate: false
|
|
3872
|
+
},
|
|
3873
|
+
desc: {
|
|
3874
|
+
start: (r, ops) => rightestNodeAsync(ops, r),
|
|
3875
|
+
end: async () => null,
|
|
3876
|
+
direction: -1,
|
|
3877
|
+
earlyTerminate: false
|
|
3878
|
+
}
|
|
3879
|
+
},
|
|
3880
|
+
or: {
|
|
3881
|
+
asc: {
|
|
3882
|
+
start: (r, ops, v) => findLowerBoundLeafAsync(ops, r, lowest(ensureValues(v)), comparator),
|
|
3883
|
+
end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, highest(ensureValues(v)), 1, comparator),
|
|
3884
|
+
direction: 1,
|
|
3885
|
+
earlyTerminate: false
|
|
3886
|
+
},
|
|
3887
|
+
desc: {
|
|
3888
|
+
start: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, highest(ensureValues(v)), 1, comparator),
|
|
3889
|
+
end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, lowest(ensureValues(v)), -1, comparator),
|
|
3890
|
+
direction: -1,
|
|
3891
|
+
earlyTerminate: false
|
|
3892
|
+
}
|
|
3893
|
+
},
|
|
3894
|
+
primaryGt: {
|
|
3895
|
+
asc: {
|
|
3896
|
+
start: (r, ops, v) => findUpperBoundLeafAsync(ops, r, v[0], comparator),
|
|
3897
|
+
end: async () => null,
|
|
3898
|
+
direction: 1,
|
|
3899
|
+
earlyTerminate: false
|
|
3900
|
+
},
|
|
3901
|
+
desc: {
|
|
3902
|
+
start: (r, ops) => rightestNodeAsync(ops, r),
|
|
3903
|
+
end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], -1, comparator),
|
|
3904
|
+
direction: -1,
|
|
3905
|
+
earlyTerminate: true
|
|
3906
|
+
}
|
|
3907
|
+
},
|
|
3908
|
+
primaryGte: {
|
|
3909
|
+
asc: {
|
|
3910
|
+
start: (r, ops, v) => findLowerBoundLeafAsync(ops, r, v[0], comparator),
|
|
3911
|
+
end: async () => null,
|
|
3912
|
+
direction: 1,
|
|
3913
|
+
earlyTerminate: false
|
|
3914
|
+
},
|
|
3915
|
+
desc: {
|
|
3916
|
+
start: (r, ops) => rightestNodeAsync(ops, r),
|
|
3917
|
+
end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], -1, comparator),
|
|
3918
|
+
direction: -1,
|
|
3919
|
+
earlyTerminate: true
|
|
3920
|
+
}
|
|
3921
|
+
},
|
|
3922
|
+
primaryLt: {
|
|
3923
|
+
asc: {
|
|
3924
|
+
start: (r, ops) => leftestNodeAsync(ops, r),
|
|
3925
|
+
end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], 1, comparator),
|
|
3926
|
+
direction: 1,
|
|
3927
|
+
earlyTerminate: true
|
|
3928
|
+
},
|
|
3929
|
+
desc: {
|
|
3930
|
+
start: (r, ops, v) => findLowerBoundLeafAsync(ops, r, v[0], comparator),
|
|
3931
|
+
end: async () => null,
|
|
3932
|
+
direction: -1,
|
|
3933
|
+
earlyTerminate: false
|
|
3934
|
+
}
|
|
3935
|
+
},
|
|
3936
|
+
primaryLte: {
|
|
3937
|
+
asc: {
|
|
3938
|
+
start: (r, ops) => leftestNodeAsync(ops, r),
|
|
3939
|
+
end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], 1, comparator),
|
|
3940
|
+
direction: 1,
|
|
3941
|
+
earlyTerminate: true
|
|
3942
|
+
},
|
|
3943
|
+
desc: {
|
|
3944
|
+
start: (r, ops, v) => findUpperBoundLeafAsync(ops, r, v[0], comparator),
|
|
3945
|
+
end: async () => null,
|
|
3946
|
+
direction: -1,
|
|
3947
|
+
earlyTerminate: false
|
|
3948
|
+
}
|
|
3949
|
+
},
|
|
3950
|
+
primaryEqual: {
|
|
3951
|
+
asc: {
|
|
3952
|
+
start: (r, ops, v) => findLowerBoundLeafAsync(ops, r, v[0], comparator),
|
|
3953
|
+
end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], 1, comparator),
|
|
3954
|
+
direction: 1,
|
|
3955
|
+
earlyTerminate: true
|
|
3956
|
+
},
|
|
3957
|
+
desc: {
|
|
3958
|
+
start: (r, ops, v) => findUpperBoundLeafAsync(ops, r, v[0], comparator),
|
|
3959
|
+
end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, v[0], -1, comparator),
|
|
3960
|
+
direction: -1,
|
|
3961
|
+
earlyTerminate: true
|
|
3962
|
+
}
|
|
3963
|
+
},
|
|
3964
|
+
primaryNotEqual: {
|
|
3965
|
+
asc: {
|
|
3966
|
+
start: (r, ops) => leftestNodeAsync(ops, r),
|
|
3967
|
+
end: async () => null,
|
|
3968
|
+
direction: 1,
|
|
3969
|
+
earlyTerminate: false
|
|
3970
|
+
},
|
|
3971
|
+
desc: {
|
|
3972
|
+
start: (r, ops) => rightestNodeAsync(ops, r),
|
|
3973
|
+
end: async () => null,
|
|
3974
|
+
direction: -1,
|
|
3975
|
+
earlyTerminate: false
|
|
3976
|
+
}
|
|
3977
|
+
},
|
|
3978
|
+
primaryOr: {
|
|
3979
|
+
asc: {
|
|
3980
|
+
start: (r, ops, v) => findLowerBoundLeafAsync(ops, r, lowestPrimary(ensureValues(v)), comparator),
|
|
3981
|
+
end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, highestPrimary(ensureValues(v)), 1, comparator),
|
|
3982
|
+
direction: 1,
|
|
3983
|
+
earlyTerminate: false
|
|
3984
|
+
},
|
|
3985
|
+
desc: {
|
|
3986
|
+
start: (r, ops, v) => findUpperBoundLeafAsync(ops, r, highestPrimary(ensureValues(v)), comparator),
|
|
3987
|
+
end: (r, ops, v) => findOuterBoundaryLeafAsync(ops, r, lowestPrimary(ensureValues(v)), -1, comparator),
|
|
3988
|
+
direction: -1,
|
|
3989
|
+
earlyTerminate: false
|
|
3990
|
+
}
|
|
3991
|
+
},
|
|
3992
|
+
like: {
|
|
3993
|
+
asc: {
|
|
3994
|
+
start: (r, ops) => leftestNodeAsync(ops, r),
|
|
3995
|
+
end: async () => null,
|
|
3996
|
+
direction: 1,
|
|
3997
|
+
earlyTerminate: false
|
|
3244
3998
|
},
|
|
3245
|
-
{
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3999
|
+
desc: {
|
|
4000
|
+
start: (r, ops) => rightestNodeAsync(ops, r),
|
|
4001
|
+
end: async () => null,
|
|
4002
|
+
direction: -1,
|
|
4003
|
+
earlyTerminate: false
|
|
3250
4004
|
}
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
4005
|
+
}
|
|
4006
|
+
};
|
|
4007
|
+
}
|
|
4008
|
+
async function locateLeafAsync(ops, rootId, value, comparator) {
|
|
4009
|
+
let node = await ops.getNode(rootId);
|
|
4010
|
+
while (!node.leaf) {
|
|
4011
|
+
const { index } = binarySearchValues(node.values, value, comparator, false, true);
|
|
4012
|
+
node = await ops.getNode(node.keys[index]);
|
|
4013
|
+
}
|
|
4014
|
+
return node;
|
|
4015
|
+
}
|
|
4016
|
+
async function findLowerBoundLeafAsync(ops, rootId, value, comparator) {
|
|
4017
|
+
let node = await ops.getNode(rootId);
|
|
4018
|
+
while (!node.leaf) {
|
|
4019
|
+
const { index } = binarySearchValues(node.values, value, comparator, true, false);
|
|
4020
|
+
node = await ops.getNode(node.keys[index]);
|
|
4021
|
+
}
|
|
4022
|
+
return node;
|
|
4023
|
+
}
|
|
4024
|
+
async function findUpperBoundLeafAsync(ops, rootId, value, comparator) {
|
|
4025
|
+
let node = await ops.getNode(rootId);
|
|
4026
|
+
while (!node.leaf) {
|
|
4027
|
+
const { index } = binarySearchValues(node.values, value, comparator, true, true);
|
|
4028
|
+
node = await ops.getNode(node.keys[index]);
|
|
4029
|
+
}
|
|
4030
|
+
return node;
|
|
4031
|
+
}
|
|
4032
|
+
async function findOuterBoundaryLeafAsync(ops, rootId, value, direction, comparator) {
|
|
4033
|
+
const insertableNode = direction === -1 ? await findLowerBoundLeafAsync(ops, rootId, value, comparator) : await findUpperBoundLeafAsync(ops, rootId, value, comparator);
|
|
4034
|
+
const key = direction === -1 ? "prev" : "next";
|
|
4035
|
+
const guessNode = insertableNode[key];
|
|
4036
|
+
if (!guessNode) return null;
|
|
4037
|
+
return await ops.getNode(guessNode);
|
|
4038
|
+
}
|
|
4039
|
+
async function leftestNodeAsync(ops, rootId) {
|
|
4040
|
+
let node = await ops.getNode(rootId);
|
|
4041
|
+
while (!node.leaf) {
|
|
4042
|
+
node = await ops.getNode(node.keys[0]);
|
|
4043
|
+
}
|
|
4044
|
+
return node;
|
|
4045
|
+
}
|
|
4046
|
+
async function rightestNodeAsync(ops, rootId) {
|
|
4047
|
+
let node = await ops.getNode(rootId);
|
|
4048
|
+
while (!node.leaf) {
|
|
4049
|
+
node = await ops.getNode(node.keys[node.keys.length - 1]);
|
|
4050
|
+
}
|
|
4051
|
+
return node;
|
|
4052
|
+
}
|
|
4053
|
+
async function* getPairsGeneratorAsync(ops, startNode, endNode, direction) {
|
|
4054
|
+
let node = startNode;
|
|
4055
|
+
let nextNodePromise = null;
|
|
4056
|
+
while (true) {
|
|
4057
|
+
if (endNode && node.id === endNode.id) break;
|
|
4058
|
+
if (direction === 1) {
|
|
4059
|
+
if (node.next) nextNodePromise = ops.getNode(node.next);
|
|
4060
|
+
} else {
|
|
4061
|
+
if (node.prev) nextNodePromise = ops.getNode(node.prev);
|
|
4062
|
+
}
|
|
4063
|
+
const len = node.values.length;
|
|
4064
|
+
if (direction === 1) {
|
|
4065
|
+
for (let i = 0; i < len; i++) {
|
|
4066
|
+
const nValue = node.values[i];
|
|
4067
|
+
const keys = node.keys[i];
|
|
4068
|
+
for (let j = 0, kLen = keys.length; j < kLen; j++) {
|
|
4069
|
+
yield [keys[j], nValue];
|
|
4070
|
+
}
|
|
3259
4071
|
}
|
|
3260
|
-
|
|
4072
|
+
} else {
|
|
4073
|
+
let i = len;
|
|
4074
|
+
while (i--) {
|
|
4075
|
+
const nValue = node.values[i];
|
|
4076
|
+
const keys = node.keys[i];
|
|
4077
|
+
let j = keys.length;
|
|
4078
|
+
while (j--) {
|
|
4079
|
+
yield [keys[j], nValue];
|
|
4080
|
+
}
|
|
4081
|
+
}
|
|
4082
|
+
}
|
|
4083
|
+
if (nextNodePromise) {
|
|
4084
|
+
node = await nextNodePromise;
|
|
4085
|
+
nextNodePromise = null;
|
|
4086
|
+
} else {
|
|
4087
|
+
break;
|
|
4088
|
+
}
|
|
3261
4089
|
}
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
4090
|
+
}
|
|
4091
|
+
async function insertAtLeafAsync(ops, node, key, value, comparator) {
|
|
4092
|
+
let leaf = node;
|
|
4093
|
+
if (leaf.values.length) {
|
|
4094
|
+
for (let i = 0, len = leaf.values.length; i < len; i++) {
|
|
4095
|
+
const nValue = leaf.values[i];
|
|
4096
|
+
if (comparator.isSame(value, nValue)) {
|
|
4097
|
+
if (leaf.keys[i].includes(key)) break;
|
|
4098
|
+
leaf = cloneNode(leaf);
|
|
4099
|
+
leaf.keys[i].push(key);
|
|
4100
|
+
await ops.updateNode(leaf);
|
|
4101
|
+
return leaf;
|
|
4102
|
+
} else if (comparator.isLower(value, nValue)) {
|
|
4103
|
+
leaf = cloneNode(leaf);
|
|
4104
|
+
leaf.values.splice(i, 0, value);
|
|
4105
|
+
leaf.keys.splice(i, 0, [key]);
|
|
4106
|
+
await ops.updateNode(leaf);
|
|
4107
|
+
return leaf;
|
|
4108
|
+
} else if (i + 1 === leaf.values.length) {
|
|
4109
|
+
leaf = cloneNode(leaf);
|
|
4110
|
+
leaf.values.push(value);
|
|
4111
|
+
leaf.keys.push([key]);
|
|
4112
|
+
await ops.updateNode(leaf);
|
|
4113
|
+
return leaf;
|
|
4114
|
+
}
|
|
4115
|
+
}
|
|
4116
|
+
} else {
|
|
4117
|
+
leaf = cloneNode(leaf);
|
|
4118
|
+
leaf.values = [value];
|
|
4119
|
+
leaf.keys = [[key]];
|
|
4120
|
+
await ops.updateNode(leaf);
|
|
4121
|
+
return leaf;
|
|
3268
4122
|
}
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
4123
|
+
return leaf;
|
|
4124
|
+
}
|
|
4125
|
+
async function insertInParentAsync(ops, ctx, node, value, newSiblingNode) {
|
|
4126
|
+
if (ctx.rootId === node.id) {
|
|
4127
|
+
node = cloneNode(node);
|
|
4128
|
+
newSiblingNode = cloneNode(newSiblingNode);
|
|
4129
|
+
const root = await ops.createNode(false, [node.id, newSiblingNode.id], [value]);
|
|
4130
|
+
ctx.rootId = root.id;
|
|
4131
|
+
node.parent = root.id;
|
|
4132
|
+
newSiblingNode.parent = root.id;
|
|
4133
|
+
if (newSiblingNode.leaf) {
|
|
4134
|
+
;
|
|
4135
|
+
node.next = newSiblingNode.id;
|
|
4136
|
+
newSiblingNode.prev = node.id;
|
|
4137
|
+
}
|
|
4138
|
+
await ops.writeHead({ root: root.id, order: ctx.order, data: ctx.headData() });
|
|
4139
|
+
await ops.updateNode(node);
|
|
4140
|
+
await ops.updateNode(newSiblingNode);
|
|
4141
|
+
return;
|
|
4142
|
+
}
|
|
4143
|
+
const parentNode = cloneNode(await ops.getNode(node.parent));
|
|
4144
|
+
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
4145
|
+
if (nodeIndex === -1) throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
|
|
4146
|
+
parentNode.values.splice(nodeIndex, 0, value);
|
|
4147
|
+
parentNode.keys.splice(nodeIndex + 1, 0, newSiblingNode.id);
|
|
4148
|
+
newSiblingNode = cloneNode(newSiblingNode);
|
|
4149
|
+
newSiblingNode.parent = parentNode.id;
|
|
4150
|
+
if (newSiblingNode.leaf) {
|
|
4151
|
+
const leftSibling = cloneNode(node);
|
|
4152
|
+
const oldNextId = leftSibling.next;
|
|
4153
|
+
newSiblingNode.prev = leftSibling.id;
|
|
4154
|
+
newSiblingNode.next = oldNextId;
|
|
4155
|
+
leftSibling.next = newSiblingNode.id;
|
|
4156
|
+
await ops.updateNode(leftSibling);
|
|
4157
|
+
if (oldNextId) {
|
|
4158
|
+
const oldNext = cloneNode(await ops.getNode(oldNextId));
|
|
4159
|
+
oldNext.prev = newSiblingNode.id;
|
|
4160
|
+
await ops.updateNode(oldNext);
|
|
4161
|
+
}
|
|
4162
|
+
}
|
|
4163
|
+
await ops.updateNode(parentNode);
|
|
4164
|
+
await ops.updateNode(newSiblingNode);
|
|
4165
|
+
if (parentNode.keys.length > ctx.order) {
|
|
4166
|
+
const rec = await ops.createNode(false, [], []);
|
|
4167
|
+
rec.parent = parentNode.parent;
|
|
4168
|
+
const mid = Math.ceil(ctx.order / 2) - 1;
|
|
4169
|
+
rec.values = parentNode.values.slice(mid + 1);
|
|
4170
|
+
rec.keys = parentNode.keys.slice(mid + 1);
|
|
4171
|
+
const midValue = parentNode.values[mid];
|
|
4172
|
+
parentNode.values = parentNode.values.slice(0, mid);
|
|
4173
|
+
parentNode.keys = parentNode.keys.slice(0, mid + 1);
|
|
4174
|
+
for (let i = 0, len = rec.keys.length; i < len; i++) {
|
|
4175
|
+
const n = cloneNode(await ops.getNode(rec.keys[i]));
|
|
4176
|
+
n.parent = rec.id;
|
|
4177
|
+
await ops.updateNode(n);
|
|
4178
|
+
}
|
|
4179
|
+
await ops.updateNode(parentNode);
|
|
4180
|
+
await insertInParentAsync(ops, ctx, parentNode, midValue, rec);
|
|
4181
|
+
}
|
|
4182
|
+
}
|
|
4183
|
+
async function insertOpAsync(ops, ctx, key, value, comparator) {
|
|
4184
|
+
let before = await locateLeafAsync(ops, ctx.rootId, value, comparator);
|
|
4185
|
+
before = await insertAtLeafAsync(ops, before, key, value, comparator);
|
|
4186
|
+
if (before.values.length === ctx.order) {
|
|
4187
|
+
let after = await ops.createNode(true, [], [], before.parent, null, null);
|
|
4188
|
+
const mid = Math.ceil(ctx.order / 2) - 1;
|
|
4189
|
+
after = cloneNode(after);
|
|
4190
|
+
after.values = before.values.slice(mid + 1);
|
|
4191
|
+
after.keys = before.keys.slice(mid + 1);
|
|
4192
|
+
before.values = before.values.slice(0, mid + 1);
|
|
4193
|
+
before.keys = before.keys.slice(0, mid + 1);
|
|
4194
|
+
await ops.updateNode(before);
|
|
4195
|
+
await ops.updateNode(after);
|
|
4196
|
+
await insertInParentAsync(ops, ctx, before, after.values[0], after);
|
|
4197
|
+
}
|
|
4198
|
+
}
|
|
4199
|
+
async function deleteEntryAsync(ops, ctx, node, key, comparator) {
|
|
4200
|
+
if (!node.leaf) {
|
|
4201
|
+
let keyIndex = -1;
|
|
4202
|
+
for (let i = 0, len = node.keys.length; i < len; i++) {
|
|
4203
|
+
if (node.keys[i] === key) {
|
|
4204
|
+
keyIndex = i;
|
|
4205
|
+
break;
|
|
4206
|
+
}
|
|
4207
|
+
}
|
|
4208
|
+
if (keyIndex !== -1) {
|
|
4209
|
+
node = cloneNode(node);
|
|
4210
|
+
node.keys.splice(keyIndex, 1);
|
|
4211
|
+
const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
|
|
4212
|
+
node.values.splice(valueIndex, 1);
|
|
4213
|
+
await ops.updateNode(node);
|
|
4214
|
+
}
|
|
3275
4215
|
}
|
|
3276
|
-
|
|
4216
|
+
if (ctx.rootId === node.id && node.keys.length === 1 && !node.leaf) {
|
|
4217
|
+
const keys = node.keys;
|
|
4218
|
+
await ops.deleteNode(node);
|
|
4219
|
+
const newRoot = cloneNode(await ops.getNode(keys[0]));
|
|
4220
|
+
newRoot.parent = null;
|
|
4221
|
+
await ops.updateNode(newRoot);
|
|
4222
|
+
await ops.writeHead({ root: newRoot.id, order: ctx.order, data: ctx.headData() });
|
|
4223
|
+
ctx.rootId = newRoot.id;
|
|
4224
|
+
return node;
|
|
4225
|
+
} else if (ctx.rootId === node.id) {
|
|
4226
|
+
await ops.writeHead({ root: node.id, order: ctx.order, data: ctx.headData() });
|
|
4227
|
+
return node;
|
|
4228
|
+
} else if (node.keys.length < Math.ceil(ctx.order / 2) && !node.leaf || node.values.length < Math.ceil((ctx.order - 1) / 2) && node.leaf) {
|
|
4229
|
+
if (node.parent === null) return node;
|
|
4230
|
+
let isPredecessor = false;
|
|
4231
|
+
let parentNode = await ops.getNode(node.parent);
|
|
4232
|
+
let prevNode = null;
|
|
4233
|
+
let nextNode = null;
|
|
4234
|
+
let prevValue = null;
|
|
4235
|
+
let postValue = null;
|
|
4236
|
+
for (let i = 0, len = parentNode.keys.length; i < len; i++) {
|
|
4237
|
+
if (parentNode.keys[i] === node.id) {
|
|
4238
|
+
if (i > 0) {
|
|
4239
|
+
prevNode = await ops.getNode(parentNode.keys[i - 1]);
|
|
4240
|
+
prevValue = parentNode.values[i - 1];
|
|
4241
|
+
}
|
|
4242
|
+
if (i < parentNode.keys.length - 1) {
|
|
4243
|
+
nextNode = await ops.getNode(parentNode.keys[i + 1]);
|
|
4244
|
+
postValue = parentNode.values[i];
|
|
4245
|
+
}
|
|
4246
|
+
}
|
|
4247
|
+
}
|
|
4248
|
+
let siblingNode;
|
|
4249
|
+
let guess;
|
|
4250
|
+
if (prevNode === null) {
|
|
4251
|
+
siblingNode = nextNode;
|
|
4252
|
+
guess = postValue;
|
|
4253
|
+
} else if (nextNode === null) {
|
|
4254
|
+
isPredecessor = true;
|
|
4255
|
+
siblingNode = prevNode;
|
|
4256
|
+
guess = prevValue;
|
|
4257
|
+
} else {
|
|
4258
|
+
if (node.values.length + nextNode.values.length < ctx.order) {
|
|
4259
|
+
siblingNode = nextNode;
|
|
4260
|
+
guess = postValue;
|
|
4261
|
+
} else {
|
|
4262
|
+
isPredecessor = true;
|
|
4263
|
+
siblingNode = prevNode;
|
|
4264
|
+
guess = prevValue;
|
|
4265
|
+
}
|
|
4266
|
+
}
|
|
4267
|
+
if (!siblingNode) return node;
|
|
4268
|
+
node = cloneNode(node);
|
|
4269
|
+
siblingNode = cloneNode(siblingNode);
|
|
4270
|
+
if (node.values.length + siblingNode.values.length < ctx.order) {
|
|
4271
|
+
if (!isPredecessor) {
|
|
4272
|
+
const t = siblingNode;
|
|
4273
|
+
siblingNode = node;
|
|
4274
|
+
node = t;
|
|
4275
|
+
}
|
|
4276
|
+
siblingNode.keys.push(...node.keys);
|
|
4277
|
+
if (!node.leaf) {
|
|
4278
|
+
siblingNode.values.push(guess);
|
|
4279
|
+
} else {
|
|
4280
|
+
siblingNode.next = node.next;
|
|
4281
|
+
if (siblingNode.next) {
|
|
4282
|
+
const n = cloneNode(await ops.getNode(siblingNode.next));
|
|
4283
|
+
n.prev = siblingNode.id;
|
|
4284
|
+
await ops.updateNode(n);
|
|
4285
|
+
}
|
|
4286
|
+
}
|
|
4287
|
+
siblingNode.values.push(...node.values);
|
|
4288
|
+
if (!siblingNode.leaf) {
|
|
4289
|
+
for (let i = 0, len = siblingNode.keys.length; i < len; i++) {
|
|
4290
|
+
const n = cloneNode(await ops.getNode(siblingNode.keys[i]));
|
|
4291
|
+
n.parent = siblingNode.id;
|
|
4292
|
+
await ops.updateNode(n);
|
|
4293
|
+
}
|
|
4294
|
+
}
|
|
4295
|
+
await ops.deleteNode(node);
|
|
4296
|
+
await ops.updateNode(siblingNode);
|
|
4297
|
+
await deleteEntryAsync(ops, ctx, await ops.getNode(node.parent), node.id, comparator);
|
|
4298
|
+
} else {
|
|
4299
|
+
if (isPredecessor) {
|
|
4300
|
+
let pointerPm, pointerKm;
|
|
4301
|
+
if (!node.leaf) {
|
|
4302
|
+
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
4303
|
+
pointerKm = siblingNode.values.splice(-1)[0];
|
|
4304
|
+
node.keys = [pointerPm, ...node.keys];
|
|
4305
|
+
node.values = [guess, ...node.values];
|
|
4306
|
+
parentNode = cloneNode(await ops.getNode(node.parent));
|
|
4307
|
+
const ni = parentNode.keys.indexOf(node.id);
|
|
4308
|
+
if (ni > 0) {
|
|
4309
|
+
parentNode.values[ni - 1] = pointerKm;
|
|
4310
|
+
await ops.updateNode(parentNode);
|
|
4311
|
+
}
|
|
4312
|
+
} else {
|
|
4313
|
+
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
4314
|
+
pointerKm = siblingNode.values.splice(-1)[0];
|
|
4315
|
+
node.keys = [pointerPm, ...node.keys];
|
|
4316
|
+
node.values = [pointerKm, ...node.values];
|
|
4317
|
+
parentNode = cloneNode(await ops.getNode(node.parent));
|
|
4318
|
+
const ni = parentNode.keys.indexOf(node.id);
|
|
4319
|
+
if (ni > 0) {
|
|
4320
|
+
parentNode.values[ni - 1] = pointerKm;
|
|
4321
|
+
await ops.updateNode(parentNode);
|
|
4322
|
+
}
|
|
4323
|
+
}
|
|
4324
|
+
await ops.updateNode(node);
|
|
4325
|
+
await ops.updateNode(siblingNode);
|
|
4326
|
+
} else {
|
|
4327
|
+
let pointerP0, pointerK0;
|
|
4328
|
+
if (!node.leaf) {
|
|
4329
|
+
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
4330
|
+
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
4331
|
+
node.keys = [...node.keys, pointerP0];
|
|
4332
|
+
node.values = [...node.values, guess];
|
|
4333
|
+
parentNode = cloneNode(await ops.getNode(node.parent));
|
|
4334
|
+
const pi = parentNode.keys.indexOf(siblingNode.id);
|
|
4335
|
+
if (pi > 0) {
|
|
4336
|
+
parentNode.values[pi - 1] = pointerK0;
|
|
4337
|
+
await ops.updateNode(parentNode);
|
|
4338
|
+
}
|
|
4339
|
+
} else {
|
|
4340
|
+
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
4341
|
+
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
4342
|
+
node.keys = [...node.keys, pointerP0];
|
|
4343
|
+
node.values = [...node.values, pointerK0];
|
|
4344
|
+
parentNode = cloneNode(await ops.getNode(node.parent));
|
|
4345
|
+
const pi = parentNode.keys.indexOf(siblingNode.id);
|
|
4346
|
+
if (pi > 0) {
|
|
4347
|
+
parentNode.values[pi - 1] = siblingNode.values[0];
|
|
4348
|
+
await ops.updateNode(parentNode);
|
|
4349
|
+
}
|
|
4350
|
+
}
|
|
4351
|
+
await ops.updateNode(node);
|
|
4352
|
+
await ops.updateNode(siblingNode);
|
|
4353
|
+
}
|
|
4354
|
+
if (!siblingNode.leaf) {
|
|
4355
|
+
for (let i = 0, len = siblingNode.keys.length; i < len; i++) {
|
|
4356
|
+
const n = cloneNode(await ops.getNode(siblingNode.keys[i]));
|
|
4357
|
+
n.parent = siblingNode.id;
|
|
4358
|
+
await ops.updateNode(n);
|
|
4359
|
+
}
|
|
4360
|
+
}
|
|
4361
|
+
if (!node.leaf) {
|
|
4362
|
+
for (let i = 0, len = node.keys.length; i < len; i++) {
|
|
4363
|
+
const n = cloneNode(await ops.getNode(node.keys[i]));
|
|
4364
|
+
n.parent = node.id;
|
|
4365
|
+
await ops.updateNode(n);
|
|
4366
|
+
}
|
|
4367
|
+
}
|
|
4368
|
+
if (!parentNode.leaf) {
|
|
4369
|
+
for (let i = 0, len = parentNode.keys.length; i < len; i++) {
|
|
4370
|
+
const n = cloneNode(await ops.getNode(parentNode.keys[i]));
|
|
4371
|
+
n.parent = parentNode.id;
|
|
4372
|
+
await ops.updateNode(n);
|
|
4373
|
+
}
|
|
4374
|
+
}
|
|
4375
|
+
}
|
|
4376
|
+
} else {
|
|
4377
|
+
await ops.updateNode(cloneNode(node));
|
|
4378
|
+
}
|
|
4379
|
+
return node;
|
|
4380
|
+
}
|
|
4381
|
+
async function deleteOpAsync(ops, ctx, key, comparator, value) {
|
|
4382
|
+
if (value === void 0) {
|
|
4383
|
+
value = await getOpAsync(ops, ctx.rootId, key);
|
|
4384
|
+
}
|
|
4385
|
+
if (value === void 0) return;
|
|
4386
|
+
let node = await findLowerBoundLeafAsync(ops, ctx.rootId, value, comparator);
|
|
4387
|
+
let found = false;
|
|
4388
|
+
while (true) {
|
|
4389
|
+
let i = node.values.length;
|
|
4390
|
+
while (i--) {
|
|
4391
|
+
if (comparator.isSame(value, node.values[i])) {
|
|
4392
|
+
const keyIndex = node.keys[i].indexOf(key);
|
|
4393
|
+
if (keyIndex !== -1) {
|
|
4394
|
+
node = cloneNode(node);
|
|
4395
|
+
node.keys[i].splice(keyIndex, 1);
|
|
4396
|
+
if (node.keys[i].length === 0) {
|
|
4397
|
+
node.keys.splice(i, 1);
|
|
4398
|
+
node.values.splice(i, 1);
|
|
4399
|
+
}
|
|
4400
|
+
await ops.updateNode(node);
|
|
4401
|
+
node = await deleteEntryAsync(ops, ctx, node, key, comparator);
|
|
4402
|
+
found = true;
|
|
4403
|
+
break;
|
|
4404
|
+
}
|
|
4405
|
+
}
|
|
4406
|
+
}
|
|
4407
|
+
if (found) break;
|
|
4408
|
+
if (node.next) {
|
|
4409
|
+
node = await ops.getNode(node.next);
|
|
4410
|
+
continue;
|
|
4411
|
+
}
|
|
4412
|
+
break;
|
|
4413
|
+
}
|
|
4414
|
+
}
|
|
4415
|
+
async function batchInsertOpAsync(ops, ctx, entries, comparator) {
|
|
4416
|
+
if (entries.length === 0) return;
|
|
4417
|
+
const sorted = [...entries].sort((a, b) => comparator.asc(a[1], b[1]));
|
|
4418
|
+
let currentLeaf = null;
|
|
4419
|
+
let modified = false;
|
|
4420
|
+
let cachedLeafId = null;
|
|
4421
|
+
let cachedLeafMaxValue = null;
|
|
4422
|
+
for (let i = 0, len = sorted.length; i < len; i++) {
|
|
4423
|
+
const [key, value] = sorted[i];
|
|
4424
|
+
let targetLeaf;
|
|
4425
|
+
if (cachedLeafId !== null && cachedLeafMaxValue !== null && currentLeaf !== null && (comparator.isLower(value, cachedLeafMaxValue) || comparator.isSame(value, cachedLeafMaxValue))) {
|
|
4426
|
+
targetLeaf = currentLeaf;
|
|
4427
|
+
} else {
|
|
4428
|
+
targetLeaf = await locateLeafAsync(ops, ctx.rootId, value, comparator);
|
|
4429
|
+
}
|
|
4430
|
+
if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
|
|
4431
|
+
} else {
|
|
4432
|
+
if (currentLeaf !== null && modified) await ops.updateNode(currentLeaf);
|
|
4433
|
+
currentLeaf = cloneNode(targetLeaf);
|
|
4434
|
+
modified = false;
|
|
4435
|
+
}
|
|
4436
|
+
cachedLeafId = currentLeaf.id;
|
|
4437
|
+
const changed = insertValueIntoLeaf(currentLeaf, key, value, comparator);
|
|
4438
|
+
modified = modified || changed;
|
|
4439
|
+
cachedLeafMaxValue = currentLeaf.values[currentLeaf.values.length - 1];
|
|
4440
|
+
if (currentLeaf.values.length === ctx.order) {
|
|
4441
|
+
await ops.updateNode(currentLeaf);
|
|
4442
|
+
let after = await ops.createNode(true, [], [], currentLeaf.parent, null, null);
|
|
4443
|
+
const mid = Math.ceil(ctx.order / 2) - 1;
|
|
4444
|
+
after = cloneNode(after);
|
|
4445
|
+
after.values = currentLeaf.values.slice(mid + 1);
|
|
4446
|
+
after.keys = currentLeaf.keys.slice(mid + 1);
|
|
4447
|
+
currentLeaf.values = currentLeaf.values.slice(0, mid + 1);
|
|
4448
|
+
currentLeaf.keys = currentLeaf.keys.slice(0, mid + 1);
|
|
4449
|
+
await ops.updateNode(currentLeaf);
|
|
4450
|
+
await ops.updateNode(after);
|
|
4451
|
+
await insertInParentAsync(ops, ctx, currentLeaf, after.values[0], after);
|
|
4452
|
+
currentLeaf = null;
|
|
4453
|
+
cachedLeafId = null;
|
|
4454
|
+
cachedLeafMaxValue = null;
|
|
4455
|
+
modified = false;
|
|
4456
|
+
}
|
|
4457
|
+
}
|
|
4458
|
+
if (currentLeaf !== null && modified) await ops.updateNode(currentLeaf);
|
|
4459
|
+
}
|
|
4460
|
+
async function bulkLoadOpAsync(ops, ctx, entries, comparator) {
|
|
4461
|
+
if (entries.length === 0) return;
|
|
4462
|
+
const root = await ops.getNode(ctx.rootId);
|
|
4463
|
+
if (!root.leaf || root.values.length > 0) {
|
|
4464
|
+
throw new Error("bulkLoad can only be called on an empty tree. Use batchInsert for non-empty trees.");
|
|
4465
|
+
}
|
|
4466
|
+
const sorted = [...entries].sort((a, b) => comparator.asc(a[1], b[1]));
|
|
4467
|
+
const grouped = [];
|
|
4468
|
+
for (let i = 0, len = sorted.length; i < len; i++) {
|
|
4469
|
+
const [key, value] = sorted[i];
|
|
4470
|
+
const last = grouped[grouped.length - 1];
|
|
4471
|
+
if (last && comparator.isSame(last.value, value)) {
|
|
4472
|
+
if (!last.keys.includes(key)) last.keys.push(key);
|
|
4473
|
+
} else {
|
|
4474
|
+
grouped.push({ keys: [key], value });
|
|
4475
|
+
}
|
|
4476
|
+
}
|
|
4477
|
+
await ops.deleteNode(root);
|
|
4478
|
+
const maxLeafSize = ctx.order - 1;
|
|
4479
|
+
const leaves = [];
|
|
4480
|
+
for (let i = 0, len = grouped.length; i < len; i += maxLeafSize) {
|
|
4481
|
+
const chunk = grouped.slice(i, i + maxLeafSize);
|
|
4482
|
+
const leaf = await ops.createNode(true, chunk.map((g) => g.keys), chunk.map((g) => g.value), null, null, null);
|
|
4483
|
+
leaves.push(leaf);
|
|
4484
|
+
}
|
|
4485
|
+
for (let i = 0, len = leaves.length; i < len; i++) {
|
|
4486
|
+
if (i > 0) leaves[i].prev = leaves[i - 1].id;
|
|
4487
|
+
if (i < len - 1) leaves[i].next = leaves[i + 1].id;
|
|
4488
|
+
await ops.updateNode(leaves[i]);
|
|
4489
|
+
}
|
|
4490
|
+
let currentLevel = leaves;
|
|
4491
|
+
while (currentLevel.length > 1) {
|
|
4492
|
+
const nextLevel = [];
|
|
4493
|
+
for (let i = 0, len = currentLevel.length; i < len; i += ctx.order) {
|
|
4494
|
+
const children = currentLevel.slice(i, i + ctx.order);
|
|
4495
|
+
const separators = [];
|
|
4496
|
+
for (let j = 1, cLen = children.length; j < cLen; j++) separators.push(children[j].values[0]);
|
|
4497
|
+
const internalNode = await ops.createNode(false, children.map((c) => c.id), separators, null, null, null);
|
|
4498
|
+
for (let j = 0, cLen = children.length; j < cLen; j++) {
|
|
4499
|
+
children[j].parent = internalNode.id;
|
|
4500
|
+
await ops.updateNode(children[j]);
|
|
4501
|
+
}
|
|
4502
|
+
nextLevel.push(internalNode);
|
|
4503
|
+
}
|
|
4504
|
+
currentLevel = nextLevel;
|
|
4505
|
+
}
|
|
4506
|
+
const newRoot = currentLevel[0];
|
|
4507
|
+
await ops.writeHead({ root: newRoot.id, order: ctx.order, data: ctx.headData() });
|
|
4508
|
+
ctx.rootId = newRoot.id;
|
|
4509
|
+
}
|
|
4510
|
+
async function existsOpAsync(ops, rootId, key, value, comparator) {
|
|
4511
|
+
const node = await locateLeafAsync(ops, rootId, value, comparator);
|
|
4512
|
+
const { index, found } = binarySearchValues(node.values, value, comparator);
|
|
4513
|
+
if (found && node.keys[index].includes(key)) return true;
|
|
4514
|
+
return false;
|
|
4515
|
+
}
|
|
4516
|
+
async function getOpAsync(ops, rootId, key) {
|
|
4517
|
+
let node = await leftestNodeAsync(ops, rootId);
|
|
4518
|
+
while (true) {
|
|
4519
|
+
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
4520
|
+
const keys = node.keys[i];
|
|
4521
|
+
for (let j = 0, kLen = keys.length; j < kLen; j++) {
|
|
4522
|
+
if (keys[j] === key) return node.values[i];
|
|
4523
|
+
}
|
|
4524
|
+
}
|
|
4525
|
+
if (!node.next) break;
|
|
4526
|
+
node = await ops.getNode(node.next);
|
|
4527
|
+
}
|
|
4528
|
+
return void 0;
|
|
4529
|
+
}
|
|
4530
|
+
async function* whereStreamOpAsync(ops, rootId, condition, comparator, verifierMap, searchConfigs, ensureValues, options) {
|
|
4531
|
+
const { filterValues, limit, order = "asc" } = options ?? {};
|
|
4532
|
+
const conditionKeys = Object.keys(condition);
|
|
4533
|
+
if (conditionKeys.length === 0) return;
|
|
4534
|
+
const resolved = resolveStartEndConfigs(condition, order, comparator, ensureValues);
|
|
4535
|
+
const direction = resolved.direction;
|
|
4536
|
+
let startNode;
|
|
4537
|
+
if (resolved.startKey) {
|
|
4538
|
+
const startConfig = searchConfigs[resolved.startKey][order];
|
|
4539
|
+
startNode = await startConfig.start(rootId, ops, resolved.startValues);
|
|
4540
|
+
} else {
|
|
4541
|
+
startNode = order === "asc" ? await leftestNodeAsync(ops, rootId) : await rightestNodeAsync(ops, rootId);
|
|
4542
|
+
}
|
|
4543
|
+
let endNode = null;
|
|
4544
|
+
if (resolved.endKey) {
|
|
4545
|
+
const endConfig = searchConfigs[resolved.endKey][order];
|
|
4546
|
+
endNode = await endConfig.end(rootId, ops, resolved.endValues);
|
|
4547
|
+
}
|
|
4548
|
+
if (!startNode) return;
|
|
4549
|
+
const generator = getPairsGeneratorAsync(ops, startNode, endNode, direction);
|
|
4550
|
+
let count = 0;
|
|
4551
|
+
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
4552
|
+
for await (const pair of generator) {
|
|
4553
|
+
const [k, v] = pair;
|
|
4554
|
+
if (intersection && !intersection.has(k)) continue;
|
|
4555
|
+
if (verify(v, condition, verifierMap)) {
|
|
4556
|
+
yield pair;
|
|
4557
|
+
count++;
|
|
4558
|
+
if (limit !== void 0 && count >= limit) break;
|
|
4559
|
+
}
|
|
4560
|
+
}
|
|
4561
|
+
}
|
|
4562
|
+
async function* keysStreamOpAsync(ops, rootId, condition, comparator, verifierMap, searchConfigs, ensureValues, options) {
|
|
4563
|
+
const { filterValues, limit } = options ?? {};
|
|
4564
|
+
const stream = whereStreamOpAsync(ops, rootId, condition, comparator, verifierMap, searchConfigs, ensureValues, options);
|
|
4565
|
+
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
4566
|
+
let count = 0;
|
|
4567
|
+
for await (const [key] of stream) {
|
|
4568
|
+
if (intersection && !intersection.has(key)) continue;
|
|
4569
|
+
yield key;
|
|
4570
|
+
count++;
|
|
4571
|
+
if (limit !== void 0 && count >= limit) break;
|
|
4572
|
+
}
|
|
4573
|
+
}
|
|
4574
|
+
async function initOpAsync(ops, ctx, strategyOrder, strategyHead, setStrategyHead) {
|
|
4575
|
+
const head = await ops.readHead();
|
|
4576
|
+
if (head === null) {
|
|
4577
|
+
ctx.order = strategyOrder;
|
|
4578
|
+
const root = await ops.createNode(true, [], []);
|
|
4579
|
+
await ops.writeHead({ root: root.id, order: ctx.order, data: strategyHead.data });
|
|
4580
|
+
ctx.rootId = root.id;
|
|
4581
|
+
} else {
|
|
4582
|
+
const { root, order } = head;
|
|
4583
|
+
setStrategyHead(head);
|
|
4584
|
+
ctx.order = order;
|
|
4585
|
+
ctx.rootId = root;
|
|
4586
|
+
}
|
|
4587
|
+
if (ctx.order < 3) {
|
|
4588
|
+
throw new Error(`The 'order' parameter must be greater than 2. but got a '${ctx.order}'.`);
|
|
4589
|
+
}
|
|
4590
|
+
}
|
|
3277
4591
|
|
|
3278
4592
|
// src/transaction/BPTreeAsyncTransaction.ts
|
|
3279
4593
|
var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
3280
4594
|
lock;
|
|
4595
|
+
_ops;
|
|
4596
|
+
_ctx;
|
|
4597
|
+
_verifierMapCached;
|
|
4598
|
+
_searchConfigsCached;
|
|
3281
4599
|
constructor(rootTx, mvccRoot, mvcc, strategy, comparator, option) {
|
|
3282
4600
|
super(
|
|
3283
4601
|
rootTx,
|
|
@@ -3288,6 +4606,64 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3288
4606
|
option
|
|
3289
4607
|
);
|
|
3290
4608
|
this.lock = new Ryoiki2();
|
|
4609
|
+
this._initAlgoContext();
|
|
4610
|
+
}
|
|
4611
|
+
_initAlgoContext() {
|
|
4612
|
+
const mvcc = this.mvcc;
|
|
4613
|
+
const strategy = this.strategy;
|
|
4614
|
+
const self = this;
|
|
4615
|
+
this._ops = {
|
|
4616
|
+
async getNode(id) {
|
|
4617
|
+
return await mvcc.read(id);
|
|
4618
|
+
},
|
|
4619
|
+
async createNode(leaf, keys, values, parent = null, next = null, prev = null) {
|
|
4620
|
+
const id = await strategy.id(leaf);
|
|
4621
|
+
const node = { id, keys, values, leaf, parent, next, prev };
|
|
4622
|
+
await mvcc.create(id, node);
|
|
4623
|
+
return node;
|
|
4624
|
+
},
|
|
4625
|
+
async updateNode(node) {
|
|
4626
|
+
if (mvcc.isDeleted(node.id)) {
|
|
4627
|
+
return;
|
|
4628
|
+
}
|
|
4629
|
+
await mvcc.write(node.id, node);
|
|
4630
|
+
},
|
|
4631
|
+
async deleteNode(node) {
|
|
4632
|
+
if (mvcc.isDeleted(node.id)) {
|
|
4633
|
+
return;
|
|
4634
|
+
}
|
|
4635
|
+
await mvcc.delete(node.id);
|
|
4636
|
+
},
|
|
4637
|
+
async readHead() {
|
|
4638
|
+
return await mvcc.read("__HEAD__");
|
|
4639
|
+
},
|
|
4640
|
+
async writeHead(head) {
|
|
4641
|
+
if (!await mvcc.exists("__HEAD__")) {
|
|
4642
|
+
await mvcc.create("__HEAD__", head);
|
|
4643
|
+
} else {
|
|
4644
|
+
await mvcc.write("__HEAD__", head);
|
|
4645
|
+
}
|
|
4646
|
+
self.rootId = head.root;
|
|
4647
|
+
}
|
|
4648
|
+
};
|
|
4649
|
+
this._ctx = {
|
|
4650
|
+
get rootId() {
|
|
4651
|
+
return self.rootId;
|
|
4652
|
+
},
|
|
4653
|
+
set rootId(v) {
|
|
4654
|
+
self.rootId = v;
|
|
4655
|
+
},
|
|
4656
|
+
get order() {
|
|
4657
|
+
return self.order;
|
|
4658
|
+
},
|
|
4659
|
+
set order(v) {
|
|
4660
|
+
self.order = v;
|
|
4661
|
+
},
|
|
4662
|
+
headData: () => this.strategy.head.data
|
|
4663
|
+
};
|
|
4664
|
+
const ensureValues = (v) => this.ensureValues(v);
|
|
4665
|
+
this._verifierMapCached = createVerifierMap(this.comparator, this._cachedRegexp, ensureValues);
|
|
4666
|
+
this._searchConfigsCached = createSearchConfigsAsync(this.comparator, ensureValues);
|
|
3291
4667
|
}
|
|
3292
4668
|
async writeLock(id, fn) {
|
|
3293
4669
|
let lockId;
|
|
@@ -3298,256 +4674,54 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3298
4674
|
this.lock.writeUnlock(lockId);
|
|
3299
4675
|
});
|
|
3300
4676
|
}
|
|
4677
|
+
// ─── Legacy protected methods (delegating to ops) ────────────────
|
|
3301
4678
|
async getNode(id) {
|
|
3302
|
-
return
|
|
4679
|
+
return this._ops.getNode(id);
|
|
3303
4680
|
}
|
|
3304
|
-
/**
|
|
3305
|
-
* Create a new node with a unique ID.
|
|
3306
|
-
*/
|
|
3307
4681
|
async _createNode(leaf, keys, values, parent = null, next = null, prev = null) {
|
|
3308
|
-
|
|
3309
|
-
const node = {
|
|
3310
|
-
id,
|
|
3311
|
-
keys,
|
|
3312
|
-
values,
|
|
3313
|
-
leaf,
|
|
3314
|
-
parent,
|
|
3315
|
-
next,
|
|
3316
|
-
prev
|
|
3317
|
-
};
|
|
3318
|
-
await this.mvcc.create(id, node);
|
|
3319
|
-
return node;
|
|
4682
|
+
return this._ops.createNode(leaf, keys, values, parent, next, prev);
|
|
3320
4683
|
}
|
|
3321
4684
|
async _updateNode(node) {
|
|
3322
|
-
|
|
3323
|
-
return;
|
|
3324
|
-
}
|
|
3325
|
-
await this.mvcc.write(node.id, node);
|
|
4685
|
+
await this._ops.updateNode(node);
|
|
3326
4686
|
}
|
|
3327
4687
|
async _deleteNode(node) {
|
|
3328
|
-
|
|
3329
|
-
return;
|
|
3330
|
-
}
|
|
3331
|
-
await this.mvcc.delete(node.id);
|
|
4688
|
+
await this._ops.deleteNode(node);
|
|
3332
4689
|
}
|
|
3333
4690
|
async _readHead() {
|
|
3334
|
-
return
|
|
4691
|
+
return this._ops.readHead();
|
|
3335
4692
|
}
|
|
3336
4693
|
async _writeHead(head) {
|
|
3337
|
-
|
|
3338
|
-
await this.mvcc.create("__HEAD__", head);
|
|
3339
|
-
} else {
|
|
3340
|
-
await this.mvcc.write("__HEAD__", head);
|
|
3341
|
-
}
|
|
3342
|
-
this.rootId = head.root;
|
|
4694
|
+
await this._ops.writeHead(head);
|
|
3343
4695
|
}
|
|
4696
|
+
// ─── Tree traversal (delegating to algorithm) ────────────────────
|
|
3344
4697
|
async _insertAtLeaf(node, key, value) {
|
|
3345
|
-
|
|
3346
|
-
if (leaf.values.length) {
|
|
3347
|
-
for (let i = 0, len = leaf.values.length; i < len; i++) {
|
|
3348
|
-
const nValue = leaf.values[i];
|
|
3349
|
-
if (this.comparator.isSame(value, nValue)) {
|
|
3350
|
-
const keys = leaf.keys[i];
|
|
3351
|
-
if (keys.includes(key)) {
|
|
3352
|
-
break;
|
|
3353
|
-
}
|
|
3354
|
-
leaf = this._cloneNode(leaf);
|
|
3355
|
-
leaf.keys[i].push(key);
|
|
3356
|
-
await this._updateNode(leaf);
|
|
3357
|
-
return leaf;
|
|
3358
|
-
} else if (this.comparator.isLower(value, nValue)) {
|
|
3359
|
-
leaf = this._cloneNode(leaf);
|
|
3360
|
-
leaf.values.splice(i, 0, value);
|
|
3361
|
-
leaf.keys.splice(i, 0, [key]);
|
|
3362
|
-
await this._updateNode(leaf);
|
|
3363
|
-
return leaf;
|
|
3364
|
-
} else if (i + 1 === leaf.values.length) {
|
|
3365
|
-
leaf = this._cloneNode(leaf);
|
|
3366
|
-
leaf.values.push(value);
|
|
3367
|
-
leaf.keys.push([key]);
|
|
3368
|
-
await this._updateNode(leaf);
|
|
3369
|
-
return leaf;
|
|
3370
|
-
}
|
|
3371
|
-
}
|
|
3372
|
-
} else {
|
|
3373
|
-
leaf = this._cloneNode(leaf);
|
|
3374
|
-
leaf.values = [value];
|
|
3375
|
-
leaf.keys = [[key]];
|
|
3376
|
-
await this._updateNode(leaf);
|
|
3377
|
-
return leaf;
|
|
3378
|
-
}
|
|
3379
|
-
return leaf;
|
|
4698
|
+
return insertAtLeafAsync(this._ops, node, key, value, this.comparator);
|
|
3380
4699
|
}
|
|
3381
4700
|
async _insertInParent(node, value, newSiblingNode) {
|
|
3382
|
-
|
|
3383
|
-
node = this._cloneNode(node);
|
|
3384
|
-
newSiblingNode = this._cloneNode(newSiblingNode);
|
|
3385
|
-
const root = await this._createNode(false, [node.id, newSiblingNode.id], [value]);
|
|
3386
|
-
this.rootId = root.id;
|
|
3387
|
-
node.parent = root.id;
|
|
3388
|
-
newSiblingNode.parent = root.id;
|
|
3389
|
-
if (newSiblingNode.leaf) {
|
|
3390
|
-
node.next = newSiblingNode.id;
|
|
3391
|
-
newSiblingNode.prev = node.id;
|
|
3392
|
-
}
|
|
3393
|
-
await this._writeHead({
|
|
3394
|
-
root: root.id,
|
|
3395
|
-
order: this.order,
|
|
3396
|
-
data: this.strategy.head.data
|
|
3397
|
-
});
|
|
3398
|
-
await this._updateNode(node);
|
|
3399
|
-
await this._updateNode(newSiblingNode);
|
|
3400
|
-
return;
|
|
3401
|
-
}
|
|
3402
|
-
const parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
3403
|
-
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
3404
|
-
if (nodeIndex === -1) {
|
|
3405
|
-
throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
|
|
3406
|
-
}
|
|
3407
|
-
parentNode.values.splice(nodeIndex, 0, value);
|
|
3408
|
-
parentNode.keys.splice(nodeIndex + 1, 0, newSiblingNode.id);
|
|
3409
|
-
newSiblingNode = this._cloneNode(newSiblingNode);
|
|
3410
|
-
newSiblingNode.parent = parentNode.id;
|
|
3411
|
-
if (newSiblingNode.leaf) {
|
|
3412
|
-
const leftSibling = this._cloneNode(node);
|
|
3413
|
-
const oldNextId = leftSibling.next;
|
|
3414
|
-
newSiblingNode.prev = leftSibling.id;
|
|
3415
|
-
newSiblingNode.next = oldNextId;
|
|
3416
|
-
leftSibling.next = newSiblingNode.id;
|
|
3417
|
-
await this._updateNode(leftSibling);
|
|
3418
|
-
if (oldNextId) {
|
|
3419
|
-
const oldNext = this._cloneNode(await this.getNode(oldNextId));
|
|
3420
|
-
oldNext.prev = newSiblingNode.id;
|
|
3421
|
-
await this._updateNode(oldNext);
|
|
3422
|
-
}
|
|
3423
|
-
}
|
|
3424
|
-
await this._updateNode(parentNode);
|
|
3425
|
-
await this._updateNode(newSiblingNode);
|
|
3426
|
-
if (parentNode.keys.length > this.order) {
|
|
3427
|
-
const newSiblingNodeRecursive = await this._createNode(false, [], []);
|
|
3428
|
-
newSiblingNodeRecursive.parent = parentNode.parent;
|
|
3429
|
-
const mid = Math.ceil(this.order / 2) - 1;
|
|
3430
|
-
newSiblingNodeRecursive.values = parentNode.values.slice(mid + 1);
|
|
3431
|
-
newSiblingNodeRecursive.keys = parentNode.keys.slice(mid + 1);
|
|
3432
|
-
const midValue = parentNode.values[mid];
|
|
3433
|
-
parentNode.values = parentNode.values.slice(0, mid);
|
|
3434
|
-
parentNode.keys = parentNode.keys.slice(0, mid + 1);
|
|
3435
|
-
for (let i = 0, len = newSiblingNodeRecursive.keys.length; i < len; i++) {
|
|
3436
|
-
const k = newSiblingNodeRecursive.keys[i];
|
|
3437
|
-
const n = this._cloneNode(await this.getNode(k));
|
|
3438
|
-
n.parent = newSiblingNodeRecursive.id;
|
|
3439
|
-
await this._updateNode(n);
|
|
3440
|
-
}
|
|
3441
|
-
await this._updateNode(parentNode);
|
|
3442
|
-
await this._insertInParent(parentNode, midValue, newSiblingNodeRecursive);
|
|
3443
|
-
}
|
|
4701
|
+
await insertInParentAsync(this._ops, this._ctx, node, value, newSiblingNode);
|
|
3444
4702
|
}
|
|
3445
4703
|
async locateLeaf(value) {
|
|
3446
|
-
|
|
3447
|
-
while (!node.leaf) {
|
|
3448
|
-
const { index } = this._binarySearchValues(node.values, value, false, true);
|
|
3449
|
-
node = await this.getNode(node.keys[index]);
|
|
3450
|
-
}
|
|
3451
|
-
return node;
|
|
4704
|
+
return locateLeafAsync(this._ops, this._ctx.rootId, value, this.comparator);
|
|
3452
4705
|
}
|
|
3453
4706
|
async findLowerBoundLeaf(value) {
|
|
3454
|
-
|
|
3455
|
-
while (!node.leaf) {
|
|
3456
|
-
const { index } = this._binarySearchValues(node.values, value, true, false);
|
|
3457
|
-
node = await this.getNode(node.keys[index]);
|
|
3458
|
-
}
|
|
3459
|
-
return node;
|
|
4707
|
+
return findLowerBoundLeafAsync(this._ops, this._ctx.rootId, value, this.comparator);
|
|
3460
4708
|
}
|
|
3461
4709
|
async findUpperBoundLeaf(value) {
|
|
3462
|
-
|
|
3463
|
-
while (!node.leaf) {
|
|
3464
|
-
const { index } = this._binarySearchValues(node.values, value, true, true);
|
|
3465
|
-
node = await this.getNode(node.keys[index]);
|
|
3466
|
-
}
|
|
3467
|
-
return node;
|
|
4710
|
+
return findUpperBoundLeafAsync(this._ops, this._ctx.rootId, value, this.comparator);
|
|
3468
4711
|
}
|
|
3469
4712
|
async findOuterBoundaryLeaf(value, direction) {
|
|
3470
|
-
|
|
3471
|
-
let key;
|
|
3472
|
-
switch (direction) {
|
|
3473
|
-
case -1:
|
|
3474
|
-
key = "prev";
|
|
3475
|
-
break;
|
|
3476
|
-
case 1:
|
|
3477
|
-
key = "next";
|
|
3478
|
-
break;
|
|
3479
|
-
default:
|
|
3480
|
-
throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
|
|
3481
|
-
}
|
|
3482
|
-
const guessNode = insertableNode[key];
|
|
3483
|
-
if (!guessNode) {
|
|
3484
|
-
return null;
|
|
3485
|
-
}
|
|
3486
|
-
return await this.getNode(guessNode);
|
|
4713
|
+
return findOuterBoundaryLeafAsync(this._ops, this._ctx.rootId, value, direction, this.comparator);
|
|
3487
4714
|
}
|
|
3488
4715
|
async leftestNode() {
|
|
3489
|
-
|
|
3490
|
-
if (node === null) {
|
|
3491
|
-
debugger;
|
|
3492
|
-
}
|
|
3493
|
-
while (!node.leaf) {
|
|
3494
|
-
const keys = node.keys;
|
|
3495
|
-
node = await this.getNode(keys[0]);
|
|
3496
|
-
}
|
|
3497
|
-
return node;
|
|
4716
|
+
return leftestNodeAsync(this._ops, this._ctx.rootId);
|
|
3498
4717
|
}
|
|
3499
4718
|
async rightestNode() {
|
|
3500
|
-
|
|
3501
|
-
while (!node.leaf) {
|
|
3502
|
-
const keys = node.keys;
|
|
3503
|
-
node = await this.getNode(keys[keys.length - 1]);
|
|
3504
|
-
}
|
|
3505
|
-
return node;
|
|
4719
|
+
return rightestNodeAsync(this._ops, this._ctx.rootId);
|
|
3506
4720
|
}
|
|
3507
4721
|
async *getPairsGenerator(startNode, endNode, direction) {
|
|
3508
|
-
|
|
3509
|
-
let nextNodePromise = null;
|
|
3510
|
-
while (true) {
|
|
3511
|
-
if (endNode && node.id === endNode.id) {
|
|
3512
|
-
break;
|
|
3513
|
-
}
|
|
3514
|
-
if (direction === 1) {
|
|
3515
|
-
if (node.next) {
|
|
3516
|
-
nextNodePromise = this.getNode(node.next);
|
|
3517
|
-
}
|
|
3518
|
-
} else {
|
|
3519
|
-
if (node.prev) {
|
|
3520
|
-
nextNodePromise = this.getNode(node.prev);
|
|
3521
|
-
}
|
|
3522
|
-
}
|
|
3523
|
-
const len = node.values.length;
|
|
3524
|
-
if (direction === 1) {
|
|
3525
|
-
for (let i = 0; i < len; i++) {
|
|
3526
|
-
const nValue = node.values[i];
|
|
3527
|
-
const keys = node.keys[i];
|
|
3528
|
-
for (let j = 0, len2 = keys.length; j < len2; j++) {
|
|
3529
|
-
yield [keys[j], nValue];
|
|
3530
|
-
}
|
|
3531
|
-
}
|
|
3532
|
-
} else {
|
|
3533
|
-
let i = len;
|
|
3534
|
-
while (i--) {
|
|
3535
|
-
const nValue = node.values[i];
|
|
3536
|
-
const keys = node.keys[i];
|
|
3537
|
-
let j = keys.length;
|
|
3538
|
-
while (j--) {
|
|
3539
|
-
yield [keys[j], nValue];
|
|
3540
|
-
}
|
|
3541
|
-
}
|
|
3542
|
-
}
|
|
3543
|
-
if (nextNodePromise) {
|
|
3544
|
-
node = await nextNodePromise;
|
|
3545
|
-
nextNodePromise = null;
|
|
3546
|
-
} else {
|
|
3547
|
-
break;
|
|
3548
|
-
}
|
|
3549
|
-
}
|
|
4722
|
+
yield* getPairsGeneratorAsync(this._ops, startNode, endNode, direction);
|
|
3550
4723
|
}
|
|
4724
|
+
// ─── Lifecycle ───────────────────────────────────────────────────
|
|
3551
4725
|
async init() {
|
|
3552
4726
|
if (this.rootTx !== this) {
|
|
3553
4727
|
throw new Error("Cannot call init on a nested transaction");
|
|
@@ -3564,111 +4738,60 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3564
4738
|
this.isInitialized = true;
|
|
3565
4739
|
try {
|
|
3566
4740
|
this._clearCache();
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
this.
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
} else {
|
|
3577
|
-
const { root, order } = head;
|
|
3578
|
-
this.strategy.head = head;
|
|
3579
|
-
this.order = order;
|
|
3580
|
-
this.rootId = root;
|
|
3581
|
-
}
|
|
3582
|
-
if (this.order < 3) {
|
|
3583
|
-
throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
|
|
3584
|
-
}
|
|
4741
|
+
await initOpAsync(
|
|
4742
|
+
this._ops,
|
|
4743
|
+
this._ctx,
|
|
4744
|
+
this.strategy.order,
|
|
4745
|
+
this.strategy.head,
|
|
4746
|
+
(head) => {
|
|
4747
|
+
this.strategy.head = head;
|
|
4748
|
+
}
|
|
4749
|
+
);
|
|
3585
4750
|
} catch (e) {
|
|
3586
4751
|
this.isInitialized = false;
|
|
3587
4752
|
throw e;
|
|
3588
4753
|
}
|
|
3589
4754
|
}
|
|
3590
|
-
async
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
if (found) {
|
|
3594
|
-
const keys = node.keys[index];
|
|
3595
|
-
if (keys.includes(key)) {
|
|
3596
|
-
return true;
|
|
3597
|
-
}
|
|
4755
|
+
async reload() {
|
|
4756
|
+
if (this.rootTx !== this) {
|
|
4757
|
+
throw new Error("Cannot call reload on a nested transaction");
|
|
3598
4758
|
}
|
|
3599
|
-
return
|
|
4759
|
+
return await this._reloadInternal();
|
|
4760
|
+
}
|
|
4761
|
+
async _reloadInternal() {
|
|
4762
|
+
this._resetForReload();
|
|
4763
|
+
await this._initInternal();
|
|
4764
|
+
}
|
|
4765
|
+
// ─── Query (delegating to algorithm) ─────────────────────────────
|
|
4766
|
+
async exists(key, value) {
|
|
4767
|
+
return existsOpAsync(this._ops, this._ctx.rootId, key, value, this.comparator);
|
|
3600
4768
|
}
|
|
3601
4769
|
async get(key) {
|
|
3602
|
-
|
|
3603
|
-
while (true) {
|
|
3604
|
-
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
3605
|
-
const keys = node.keys[i];
|
|
3606
|
-
for (let j = 0, len2 = keys.length; j < len2; j++) {
|
|
3607
|
-
if (keys[j] === key) {
|
|
3608
|
-
return node.values[i];
|
|
3609
|
-
}
|
|
3610
|
-
}
|
|
3611
|
-
}
|
|
3612
|
-
if (!node.next) break;
|
|
3613
|
-
node = await this.getNode(node.next);
|
|
3614
|
-
}
|
|
3615
|
-
return void 0;
|
|
4770
|
+
return getOpAsync(this._ops, this._ctx.rootId, key);
|
|
3616
4771
|
}
|
|
3617
4772
|
async *keysStream(condition, options) {
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
if (limit !== void 0 && count >= limit) {
|
|
3629
|
-
break;
|
|
3630
|
-
}
|
|
3631
|
-
}
|
|
4773
|
+
yield* keysStreamOpAsync(
|
|
4774
|
+
this._ops,
|
|
4775
|
+
this._ctx.rootId,
|
|
4776
|
+
condition,
|
|
4777
|
+
this.comparator,
|
|
4778
|
+
this._verifierMapCached,
|
|
4779
|
+
this._searchConfigsCached,
|
|
4780
|
+
this.ensureValues.bind(this),
|
|
4781
|
+
options
|
|
4782
|
+
);
|
|
3632
4783
|
}
|
|
3633
4784
|
async *whereStream(condition, options) {
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
} else {
|
|
3644
|
-
startNode = order === "asc" ? await this.leftestNode() : await this.rightestNode();
|
|
3645
|
-
}
|
|
3646
|
-
let endNode = null;
|
|
3647
|
-
if (resolved.endKey) {
|
|
3648
|
-
const endConfig = this.searchConfigs[resolved.endKey][order];
|
|
3649
|
-
endNode = await endConfig.end(this, resolved.endValues);
|
|
3650
|
-
}
|
|
3651
|
-
if (!startNode) return;
|
|
3652
|
-
const generator = this.getPairsGenerator(
|
|
3653
|
-
startNode,
|
|
3654
|
-
endNode,
|
|
3655
|
-
direction
|
|
4785
|
+
yield* whereStreamOpAsync(
|
|
4786
|
+
this._ops,
|
|
4787
|
+
this._ctx.rootId,
|
|
4788
|
+
condition,
|
|
4789
|
+
this.comparator,
|
|
4790
|
+
this._verifierMapCached,
|
|
4791
|
+
this._searchConfigsCached,
|
|
4792
|
+
this.ensureValues.bind(this),
|
|
4793
|
+
options
|
|
3656
4794
|
);
|
|
3657
|
-
let count = 0;
|
|
3658
|
-
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
3659
|
-
for await (const pair of generator) {
|
|
3660
|
-
const [k, v] = pair;
|
|
3661
|
-
if (intersection && !intersection.has(k)) {
|
|
3662
|
-
continue;
|
|
3663
|
-
}
|
|
3664
|
-
if (this.verify(v, condition)) {
|
|
3665
|
-
yield pair;
|
|
3666
|
-
count++;
|
|
3667
|
-
if (limit !== void 0 && count >= limit) {
|
|
3668
|
-
break;
|
|
3669
|
-
}
|
|
3670
|
-
}
|
|
3671
|
-
}
|
|
3672
4795
|
}
|
|
3673
4796
|
async keys(condition, options) {
|
|
3674
4797
|
const set = /* @__PURE__ */ new Set();
|
|
@@ -3684,412 +4807,33 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3684
4807
|
}
|
|
3685
4808
|
return map;
|
|
3686
4809
|
}
|
|
4810
|
+
// ─── Mutation (delegating to algorithm) ──────────────────────────
|
|
3687
4811
|
async insert(key, value) {
|
|
3688
4812
|
return this.writeLock(0, async () => {
|
|
3689
|
-
|
|
3690
|
-
before = await this._insertAtLeaf(before, key, value);
|
|
3691
|
-
if (before.values.length === this.order) {
|
|
3692
|
-
let after = await this._createNode(
|
|
3693
|
-
true,
|
|
3694
|
-
[],
|
|
3695
|
-
[],
|
|
3696
|
-
before.parent,
|
|
3697
|
-
null,
|
|
3698
|
-
null
|
|
3699
|
-
);
|
|
3700
|
-
const mid = Math.ceil(this.order / 2) - 1;
|
|
3701
|
-
after = this._cloneNode(after);
|
|
3702
|
-
after.values = before.values.slice(mid + 1);
|
|
3703
|
-
after.keys = before.keys.slice(mid + 1);
|
|
3704
|
-
before.values = before.values.slice(0, mid + 1);
|
|
3705
|
-
before.keys = before.keys.slice(0, mid + 1);
|
|
3706
|
-
await this._updateNode(before);
|
|
3707
|
-
await this._updateNode(after);
|
|
3708
|
-
await this._insertInParent(before, after.values[0], after);
|
|
3709
|
-
}
|
|
4813
|
+
await insertOpAsync(this._ops, this._ctx, key, value, this.comparator);
|
|
3710
4814
|
});
|
|
3711
4815
|
}
|
|
3712
4816
|
async batchInsert(entries) {
|
|
3713
4817
|
if (entries.length === 0) return;
|
|
3714
4818
|
return this.writeLock(0, async () => {
|
|
3715
|
-
|
|
3716
|
-
let currentLeaf = null;
|
|
3717
|
-
let modified = false;
|
|
3718
|
-
let cachedLeafId = null;
|
|
3719
|
-
let cachedLeafMaxValue = null;
|
|
3720
|
-
for (let i = 0, len = sorted.length; i < len; i++) {
|
|
3721
|
-
const [key, value] = sorted[i];
|
|
3722
|
-
let targetLeaf;
|
|
3723
|
-
if (cachedLeafId !== null && cachedLeafMaxValue !== null && currentLeaf !== null && (this.comparator.isLower(value, cachedLeafMaxValue) || this.comparator.isSame(value, cachedLeafMaxValue))) {
|
|
3724
|
-
targetLeaf = currentLeaf;
|
|
3725
|
-
} else {
|
|
3726
|
-
targetLeaf = await this.locateLeaf(value);
|
|
3727
|
-
}
|
|
3728
|
-
if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
|
|
3729
|
-
} else {
|
|
3730
|
-
if (currentLeaf !== null && modified) {
|
|
3731
|
-
await this._updateNode(currentLeaf);
|
|
3732
|
-
}
|
|
3733
|
-
currentLeaf = this._cloneNode(targetLeaf);
|
|
3734
|
-
modified = false;
|
|
3735
|
-
}
|
|
3736
|
-
cachedLeafId = currentLeaf.id;
|
|
3737
|
-
const changed = this._insertValueIntoLeaf(currentLeaf, key, value);
|
|
3738
|
-
modified = modified || changed;
|
|
3739
|
-
cachedLeafMaxValue = currentLeaf.values[currentLeaf.values.length - 1];
|
|
3740
|
-
if (currentLeaf.values.length === this.order) {
|
|
3741
|
-
await this._updateNode(currentLeaf);
|
|
3742
|
-
let after = await this._createNode(
|
|
3743
|
-
true,
|
|
3744
|
-
[],
|
|
3745
|
-
[],
|
|
3746
|
-
currentLeaf.parent,
|
|
3747
|
-
null,
|
|
3748
|
-
null
|
|
3749
|
-
);
|
|
3750
|
-
const mid = Math.ceil(this.order / 2) - 1;
|
|
3751
|
-
after = this._cloneNode(after);
|
|
3752
|
-
after.values = currentLeaf.values.slice(mid + 1);
|
|
3753
|
-
after.keys = currentLeaf.keys.slice(mid + 1);
|
|
3754
|
-
currentLeaf.values = currentLeaf.values.slice(0, mid + 1);
|
|
3755
|
-
currentLeaf.keys = currentLeaf.keys.slice(0, mid + 1);
|
|
3756
|
-
await this._updateNode(currentLeaf);
|
|
3757
|
-
await this._updateNode(after);
|
|
3758
|
-
await this._insertInParent(currentLeaf, after.values[0], after);
|
|
3759
|
-
currentLeaf = null;
|
|
3760
|
-
cachedLeafId = null;
|
|
3761
|
-
cachedLeafMaxValue = null;
|
|
3762
|
-
modified = false;
|
|
3763
|
-
}
|
|
3764
|
-
}
|
|
3765
|
-
if (currentLeaf !== null && modified) {
|
|
3766
|
-
await this._updateNode(currentLeaf);
|
|
3767
|
-
}
|
|
4819
|
+
await batchInsertOpAsync(this._ops, this._ctx, entries, this.comparator);
|
|
3768
4820
|
});
|
|
3769
4821
|
}
|
|
3770
4822
|
async bulkLoad(entries) {
|
|
3771
4823
|
if (entries.length === 0) return;
|
|
3772
4824
|
return this.writeLock(0, async () => {
|
|
3773
|
-
|
|
3774
|
-
if (!root.leaf || root.values.length > 0) {
|
|
3775
|
-
throw new Error("bulkLoad can only be called on an empty tree. Use batchInsert for non-empty trees.");
|
|
3776
|
-
}
|
|
3777
|
-
const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
|
|
3778
|
-
const grouped = [];
|
|
3779
|
-
for (let i = 0, len = sorted.length; i < len; i++) {
|
|
3780
|
-
const [key, value] = sorted[i];
|
|
3781
|
-
const last = grouped[grouped.length - 1];
|
|
3782
|
-
if (last && this.comparator.isSame(last.value, value)) {
|
|
3783
|
-
if (!last.keys.includes(key)) {
|
|
3784
|
-
last.keys.push(key);
|
|
3785
|
-
}
|
|
3786
|
-
} else {
|
|
3787
|
-
grouped.push({ keys: [key], value });
|
|
3788
|
-
}
|
|
3789
|
-
}
|
|
3790
|
-
await this._deleteNode(root);
|
|
3791
|
-
const maxLeafSize = this.order - 1;
|
|
3792
|
-
const leaves = [];
|
|
3793
|
-
for (let i = 0, len = grouped.length; i < len; i += maxLeafSize) {
|
|
3794
|
-
const chunk = grouped.slice(i, i + maxLeafSize);
|
|
3795
|
-
const leafKeys = chunk.map((g) => g.keys);
|
|
3796
|
-
const leafValues = chunk.map((g) => g.value);
|
|
3797
|
-
const leaf = await this._createNode(
|
|
3798
|
-
true,
|
|
3799
|
-
leafKeys,
|
|
3800
|
-
leafValues,
|
|
3801
|
-
null,
|
|
3802
|
-
null,
|
|
3803
|
-
null
|
|
3804
|
-
);
|
|
3805
|
-
leaves.push(leaf);
|
|
3806
|
-
}
|
|
3807
|
-
for (let i = 0, len = leaves.length; i < len; i++) {
|
|
3808
|
-
if (i > 0) {
|
|
3809
|
-
leaves[i].prev = leaves[i - 1].id;
|
|
3810
|
-
}
|
|
3811
|
-
if (i < len - 1) {
|
|
3812
|
-
leaves[i].next = leaves[i + 1].id;
|
|
3813
|
-
}
|
|
3814
|
-
await this._updateNode(leaves[i]);
|
|
3815
|
-
}
|
|
3816
|
-
let currentLevel = leaves;
|
|
3817
|
-
while (currentLevel.length > 1) {
|
|
3818
|
-
const nextLevel = [];
|
|
3819
|
-
for (let i = 0, len = currentLevel.length; i < len; i += this.order) {
|
|
3820
|
-
const children = currentLevel.slice(i, i + this.order);
|
|
3821
|
-
const childIds = children.map((c) => c.id);
|
|
3822
|
-
const separators = [];
|
|
3823
|
-
for (let j = 1, len2 = children.length; j < len2; j++) {
|
|
3824
|
-
separators.push(children[j].values[0]);
|
|
3825
|
-
}
|
|
3826
|
-
const internalNode = await this._createNode(
|
|
3827
|
-
false,
|
|
3828
|
-
childIds,
|
|
3829
|
-
separators,
|
|
3830
|
-
null,
|
|
3831
|
-
null,
|
|
3832
|
-
null
|
|
3833
|
-
);
|
|
3834
|
-
for (let j = 0, len2 = children.length; j < len2; j++) {
|
|
3835
|
-
const child = children[j];
|
|
3836
|
-
child.parent = internalNode.id;
|
|
3837
|
-
await this._updateNode(child);
|
|
3838
|
-
}
|
|
3839
|
-
nextLevel.push(internalNode);
|
|
3840
|
-
}
|
|
3841
|
-
currentLevel = nextLevel;
|
|
3842
|
-
}
|
|
3843
|
-
const newRoot = currentLevel[0];
|
|
3844
|
-
await this._writeHead({
|
|
3845
|
-
root: newRoot.id,
|
|
3846
|
-
order: this.order,
|
|
3847
|
-
data: this.strategy.head.data
|
|
3848
|
-
});
|
|
4825
|
+
await bulkLoadOpAsync(this._ops, this._ctx, entries, this.comparator);
|
|
3849
4826
|
});
|
|
3850
4827
|
}
|
|
3851
4828
|
async _deleteEntry(node, key) {
|
|
3852
|
-
|
|
3853
|
-
let keyIndex = -1;
|
|
3854
|
-
for (let i = 0, len = node.keys.length; i < len; i++) {
|
|
3855
|
-
if (node.keys[i] === key) {
|
|
3856
|
-
keyIndex = i;
|
|
3857
|
-
break;
|
|
3858
|
-
}
|
|
3859
|
-
}
|
|
3860
|
-
if (keyIndex !== -1) {
|
|
3861
|
-
node = this._cloneNode(node);
|
|
3862
|
-
node.keys.splice(keyIndex, 1);
|
|
3863
|
-
const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
|
|
3864
|
-
node.values.splice(valueIndex, 1);
|
|
3865
|
-
await this._updateNode(node);
|
|
3866
|
-
}
|
|
3867
|
-
}
|
|
3868
|
-
if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
|
|
3869
|
-
const keys = node.keys;
|
|
3870
|
-
this._deleteNode(node);
|
|
3871
|
-
const newRoot = this._cloneNode(await this.getNode(keys[0]));
|
|
3872
|
-
newRoot.parent = null;
|
|
3873
|
-
await this._updateNode(newRoot);
|
|
3874
|
-
await this._writeHead({
|
|
3875
|
-
root: newRoot.id,
|
|
3876
|
-
order: this.order,
|
|
3877
|
-
data: this.strategy.head.data
|
|
3878
|
-
});
|
|
3879
|
-
return node;
|
|
3880
|
-
} else if (this.rootId === node.id) {
|
|
3881
|
-
await this._writeHead({
|
|
3882
|
-
root: node.id,
|
|
3883
|
-
order: this.order,
|
|
3884
|
-
data: this.strategy.head.data
|
|
3885
|
-
});
|
|
3886
|
-
return node;
|
|
3887
|
-
} else if (node.keys.length < Math.ceil(this.order / 2) && !node.leaf || node.values.length < Math.ceil((this.order - 1) / 2) && node.leaf) {
|
|
3888
|
-
if (node.parent === null) {
|
|
3889
|
-
return node;
|
|
3890
|
-
}
|
|
3891
|
-
let isPredecessor = false;
|
|
3892
|
-
let parentNode = await this.getNode(node.parent);
|
|
3893
|
-
let prevNode = null;
|
|
3894
|
-
let nextNode = null;
|
|
3895
|
-
let prevValue = null;
|
|
3896
|
-
let postValue = null;
|
|
3897
|
-
for (let i = 0, len = parentNode.keys.length; i < len; i++) {
|
|
3898
|
-
const nKey = parentNode.keys[i];
|
|
3899
|
-
if (nKey === node.id) {
|
|
3900
|
-
if (i > 0) {
|
|
3901
|
-
prevNode = await this.getNode(parentNode.keys[i - 1]);
|
|
3902
|
-
prevValue = parentNode.values[i - 1];
|
|
3903
|
-
}
|
|
3904
|
-
if (i < parentNode.keys.length - 1) {
|
|
3905
|
-
nextNode = await this.getNode(parentNode.keys[i + 1]);
|
|
3906
|
-
postValue = parentNode.values[i];
|
|
3907
|
-
}
|
|
3908
|
-
}
|
|
3909
|
-
}
|
|
3910
|
-
let siblingNode;
|
|
3911
|
-
let guess;
|
|
3912
|
-
if (prevNode === null) {
|
|
3913
|
-
siblingNode = nextNode;
|
|
3914
|
-
guess = postValue;
|
|
3915
|
-
} else if (nextNode === null) {
|
|
3916
|
-
isPredecessor = true;
|
|
3917
|
-
siblingNode = prevNode;
|
|
3918
|
-
guess = prevValue;
|
|
3919
|
-
} else {
|
|
3920
|
-
if (node.values.length + nextNode.values.length < this.order) {
|
|
3921
|
-
siblingNode = nextNode;
|
|
3922
|
-
guess = postValue;
|
|
3923
|
-
} else {
|
|
3924
|
-
isPredecessor = true;
|
|
3925
|
-
siblingNode = prevNode;
|
|
3926
|
-
guess = prevValue;
|
|
3927
|
-
}
|
|
3928
|
-
}
|
|
3929
|
-
if (!siblingNode) {
|
|
3930
|
-
return node;
|
|
3931
|
-
}
|
|
3932
|
-
node = this._cloneNode(node);
|
|
3933
|
-
siblingNode = this._cloneNode(siblingNode);
|
|
3934
|
-
if (node.values.length + siblingNode.values.length < this.order) {
|
|
3935
|
-
if (!isPredecessor) {
|
|
3936
|
-
const pTemp = siblingNode;
|
|
3937
|
-
siblingNode = node;
|
|
3938
|
-
node = pTemp;
|
|
3939
|
-
}
|
|
3940
|
-
siblingNode.keys.push(...node.keys);
|
|
3941
|
-
if (!node.leaf) {
|
|
3942
|
-
siblingNode.values.push(guess);
|
|
3943
|
-
} else {
|
|
3944
|
-
siblingNode.next = node.next;
|
|
3945
|
-
if (siblingNode.next) {
|
|
3946
|
-
const n = this._cloneNode(await this.getNode(siblingNode.next));
|
|
3947
|
-
n.prev = siblingNode.id;
|
|
3948
|
-
await this._updateNode(n);
|
|
3949
|
-
}
|
|
3950
|
-
}
|
|
3951
|
-
siblingNode.values.push(...node.values);
|
|
3952
|
-
if (!siblingNode.leaf) {
|
|
3953
|
-
const keys = siblingNode.keys;
|
|
3954
|
-
for (let i = 0, len = keys.length; i < len; i++) {
|
|
3955
|
-
const key2 = keys[i];
|
|
3956
|
-
const node2 = this._cloneNode(await this.getNode(key2));
|
|
3957
|
-
node2.parent = siblingNode.id;
|
|
3958
|
-
await this._updateNode(node2);
|
|
3959
|
-
}
|
|
3960
|
-
}
|
|
3961
|
-
this._deleteNode(node);
|
|
3962
|
-
await this._updateNode(siblingNode);
|
|
3963
|
-
await this._deleteEntry(await this.getNode(node.parent), node.id);
|
|
3964
|
-
} else {
|
|
3965
|
-
if (isPredecessor) {
|
|
3966
|
-
let pointerPm;
|
|
3967
|
-
let pointerKm;
|
|
3968
|
-
if (!node.leaf) {
|
|
3969
|
-
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
3970
|
-
pointerKm = siblingNode.values.splice(-1)[0];
|
|
3971
|
-
node.keys = [pointerPm, ...node.keys];
|
|
3972
|
-
node.values = [guess, ...node.values];
|
|
3973
|
-
parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
3974
|
-
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
3975
|
-
if (nodeIndex > 0) {
|
|
3976
|
-
parentNode.values[nodeIndex - 1] = pointerKm;
|
|
3977
|
-
await this._updateNode(parentNode);
|
|
3978
|
-
}
|
|
3979
|
-
} else {
|
|
3980
|
-
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
3981
|
-
pointerKm = siblingNode.values.splice(-1)[0];
|
|
3982
|
-
node.keys = [pointerPm, ...node.keys];
|
|
3983
|
-
node.values = [pointerKm, ...node.values];
|
|
3984
|
-
parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
3985
|
-
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
3986
|
-
if (nodeIndex > 0) {
|
|
3987
|
-
parentNode.values[nodeIndex - 1] = pointerKm;
|
|
3988
|
-
await this._updateNode(parentNode);
|
|
3989
|
-
}
|
|
3990
|
-
}
|
|
3991
|
-
await this._updateNode(node);
|
|
3992
|
-
await this._updateNode(siblingNode);
|
|
3993
|
-
} else {
|
|
3994
|
-
let pointerP0;
|
|
3995
|
-
let pointerK0;
|
|
3996
|
-
if (!node.leaf) {
|
|
3997
|
-
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
3998
|
-
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
3999
|
-
node.keys = [...node.keys, pointerP0];
|
|
4000
|
-
node.values = [...node.values, guess];
|
|
4001
|
-
parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
4002
|
-
const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
|
|
4003
|
-
if (pointerIndex > 0) {
|
|
4004
|
-
parentNode.values[pointerIndex - 1] = pointerK0;
|
|
4005
|
-
await this._updateNode(parentNode);
|
|
4006
|
-
}
|
|
4007
|
-
} else {
|
|
4008
|
-
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
4009
|
-
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
4010
|
-
node.keys = [...node.keys, pointerP0];
|
|
4011
|
-
node.values = [...node.values, pointerK0];
|
|
4012
|
-
parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
4013
|
-
const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
|
|
4014
|
-
if (pointerIndex > 0) {
|
|
4015
|
-
parentNode.values[pointerIndex - 1] = siblingNode.values[0];
|
|
4016
|
-
await this._updateNode(parentNode);
|
|
4017
|
-
}
|
|
4018
|
-
}
|
|
4019
|
-
await this._updateNode(node);
|
|
4020
|
-
await this._updateNode(siblingNode);
|
|
4021
|
-
}
|
|
4022
|
-
if (!siblingNode.leaf) {
|
|
4023
|
-
for (let i = 0, len = siblingNode.keys.length; i < len; i++) {
|
|
4024
|
-
const key2 = siblingNode.keys[i];
|
|
4025
|
-
const n = this._cloneNode(await this.getNode(key2));
|
|
4026
|
-
n.parent = siblingNode.id;
|
|
4027
|
-
await this._updateNode(n);
|
|
4028
|
-
}
|
|
4029
|
-
}
|
|
4030
|
-
if (!node.leaf) {
|
|
4031
|
-
for (let i = 0, len = node.keys.length; i < len; i++) {
|
|
4032
|
-
const key2 = node.keys[i];
|
|
4033
|
-
const n = this._cloneNode(await this.getNode(key2));
|
|
4034
|
-
n.parent = node.id;
|
|
4035
|
-
await this._updateNode(n);
|
|
4036
|
-
}
|
|
4037
|
-
}
|
|
4038
|
-
if (!parentNode.leaf) {
|
|
4039
|
-
for (let i = 0, len = parentNode.keys.length; i < len; i++) {
|
|
4040
|
-
const key2 = parentNode.keys[i];
|
|
4041
|
-
const n = this._cloneNode(await this.getNode(key2));
|
|
4042
|
-
n.parent = parentNode.id;
|
|
4043
|
-
await this._updateNode(n);
|
|
4044
|
-
}
|
|
4045
|
-
}
|
|
4046
|
-
}
|
|
4047
|
-
} else {
|
|
4048
|
-
await this._updateNode(this._cloneNode(node));
|
|
4049
|
-
}
|
|
4050
|
-
return node;
|
|
4829
|
+
return deleteEntryAsync(this._ops, this._ctx, node, key, this.comparator);
|
|
4051
4830
|
}
|
|
4052
4831
|
async delete(key, value) {
|
|
4053
4832
|
return this.writeLock(0, async () => {
|
|
4054
|
-
|
|
4055
|
-
value = await this.get(key);
|
|
4056
|
-
}
|
|
4057
|
-
if (value === void 0) {
|
|
4058
|
-
return;
|
|
4059
|
-
}
|
|
4060
|
-
let node = await this.findLowerBoundLeaf(value);
|
|
4061
|
-
let found = false;
|
|
4062
|
-
while (true) {
|
|
4063
|
-
let i = node.values.length;
|
|
4064
|
-
while (i--) {
|
|
4065
|
-
const nValue = node.values[i];
|
|
4066
|
-
if (this.comparator.isSame(value, nValue)) {
|
|
4067
|
-
const keys = node.keys[i];
|
|
4068
|
-
const keyIndex = keys.indexOf(key);
|
|
4069
|
-
if (keyIndex !== -1) {
|
|
4070
|
-
node = this._cloneNode(node);
|
|
4071
|
-
const freshKeys = node.keys[i];
|
|
4072
|
-
freshKeys.splice(keyIndex, 1);
|
|
4073
|
-
if (freshKeys.length === 0) {
|
|
4074
|
-
node.keys.splice(i, 1);
|
|
4075
|
-
node.values.splice(i, 1);
|
|
4076
|
-
}
|
|
4077
|
-
await this._updateNode(node);
|
|
4078
|
-
node = await this._deleteEntry(node, key);
|
|
4079
|
-
found = true;
|
|
4080
|
-
break;
|
|
4081
|
-
}
|
|
4082
|
-
}
|
|
4083
|
-
}
|
|
4084
|
-
if (found) break;
|
|
4085
|
-
if (node.next) {
|
|
4086
|
-
node = await this.getNode(node.next);
|
|
4087
|
-
continue;
|
|
4088
|
-
}
|
|
4089
|
-
break;
|
|
4090
|
-
}
|
|
4833
|
+
await deleteOpAsync(this._ops, this._ctx, key, this.comparator, value);
|
|
4091
4834
|
});
|
|
4092
4835
|
}
|
|
4836
|
+
// ─── Head Data ───────────────────────────────────────────────────
|
|
4093
4837
|
async getHeadData() {
|
|
4094
4838
|
const head = await this._readHead();
|
|
4095
4839
|
if (head === null) {
|
|
@@ -4108,6 +4852,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
4108
4852
|
data
|
|
4109
4853
|
});
|
|
4110
4854
|
}
|
|
4855
|
+
// ─── Transaction ─────────────────────────────────────────────────
|
|
4111
4856
|
async commit(label) {
|
|
4112
4857
|
let result = await this.mvcc.commit(label);
|
|
4113
4858
|
if (result.success) {
|
|
@@ -4239,6 +4984,327 @@ var BPTreeAsync = class extends BPTreeAsyncTransaction {
|
|
|
4239
4984
|
}
|
|
4240
4985
|
};
|
|
4241
4986
|
|
|
4987
|
+
// src/BPTreePureSync.ts
|
|
4988
|
+
var BPTreePureSync = class {
|
|
4989
|
+
strategy;
|
|
4990
|
+
comparator;
|
|
4991
|
+
option;
|
|
4992
|
+
_cachedRegexp = /* @__PURE__ */ new Map();
|
|
4993
|
+
_ctx;
|
|
4994
|
+
_ops;
|
|
4995
|
+
_verifierMap;
|
|
4996
|
+
_searchConfigs;
|
|
4997
|
+
constructor(strategy, comparator, option) {
|
|
4998
|
+
this.strategy = strategy;
|
|
4999
|
+
this.comparator = comparator;
|
|
5000
|
+
this.option = option ?? {};
|
|
5001
|
+
const ensureValues = (v) => Array.isArray(v) ? v : [v];
|
|
5002
|
+
this._verifierMap = createVerifierMap(comparator, this._cachedRegexp, ensureValues);
|
|
5003
|
+
this._searchConfigs = createSearchConfigs(comparator, ensureValues);
|
|
5004
|
+
}
|
|
5005
|
+
_ensureValues(v) {
|
|
5006
|
+
return Array.isArray(v) ? v : [v];
|
|
5007
|
+
}
|
|
5008
|
+
_createOps() {
|
|
5009
|
+
const strategy = this.strategy;
|
|
5010
|
+
return {
|
|
5011
|
+
getNode(id) {
|
|
5012
|
+
return strategy.read(id);
|
|
5013
|
+
},
|
|
5014
|
+
createNode(leaf, keys, values, parent = null, next = null, prev = null) {
|
|
5015
|
+
const id = strategy.id(leaf);
|
|
5016
|
+
const node = { id, keys, values, leaf, parent, next, prev };
|
|
5017
|
+
strategy.write(id, node);
|
|
5018
|
+
return node;
|
|
5019
|
+
},
|
|
5020
|
+
updateNode(node) {
|
|
5021
|
+
strategy.write(node.id, node);
|
|
5022
|
+
},
|
|
5023
|
+
deleteNode(node) {
|
|
5024
|
+
strategy.delete(node.id);
|
|
5025
|
+
},
|
|
5026
|
+
readHead() {
|
|
5027
|
+
return strategy.readHead();
|
|
5028
|
+
},
|
|
5029
|
+
writeHead(head) {
|
|
5030
|
+
strategy.writeHead(head);
|
|
5031
|
+
}
|
|
5032
|
+
};
|
|
5033
|
+
}
|
|
5034
|
+
init() {
|
|
5035
|
+
this._ops = this._createOps();
|
|
5036
|
+
this._ctx = {
|
|
5037
|
+
rootId: "",
|
|
5038
|
+
order: this.strategy.order,
|
|
5039
|
+
headData: () => this.strategy.head.data
|
|
5040
|
+
};
|
|
5041
|
+
initOp(
|
|
5042
|
+
this._ops,
|
|
5043
|
+
this._ctx,
|
|
5044
|
+
this.strategy.order,
|
|
5045
|
+
this.strategy.head,
|
|
5046
|
+
(head) => {
|
|
5047
|
+
this.strategy.head = head;
|
|
5048
|
+
}
|
|
5049
|
+
);
|
|
5050
|
+
}
|
|
5051
|
+
/**
|
|
5052
|
+
* Returns the ID of the root node.
|
|
5053
|
+
*/
|
|
5054
|
+
getRootId() {
|
|
5055
|
+
return this._ctx.rootId;
|
|
5056
|
+
}
|
|
5057
|
+
/**
|
|
5058
|
+
* Returns the order of the B+Tree.
|
|
5059
|
+
*/
|
|
5060
|
+
getOrder() {
|
|
5061
|
+
return this._ctx.order;
|
|
5062
|
+
}
|
|
5063
|
+
/**
|
|
5064
|
+
* Verified if the value satisfies the condition.
|
|
5065
|
+
*/
|
|
5066
|
+
verify(nodeValue, condition) {
|
|
5067
|
+
for (const key in condition) {
|
|
5068
|
+
const verifyFn = this._verifierMap[key];
|
|
5069
|
+
const condValue = condition[key];
|
|
5070
|
+
if (!verifyFn(nodeValue, condValue)) {
|
|
5071
|
+
return false;
|
|
5072
|
+
}
|
|
5073
|
+
}
|
|
5074
|
+
return true;
|
|
5075
|
+
}
|
|
5076
|
+
// ─── Query ───────────────────────────────────────────────────────
|
|
5077
|
+
get(key) {
|
|
5078
|
+
return getOp(this._ops, this._ctx.rootId, key);
|
|
5079
|
+
}
|
|
5080
|
+
exists(key, value) {
|
|
5081
|
+
return existsOp(this._ops, this._ctx.rootId, key, value, this.comparator);
|
|
5082
|
+
}
|
|
5083
|
+
*keysStream(condition, options) {
|
|
5084
|
+
yield* keysStreamOp(
|
|
5085
|
+
this._ops,
|
|
5086
|
+
this._ctx.rootId,
|
|
5087
|
+
condition,
|
|
5088
|
+
this.comparator,
|
|
5089
|
+
this._verifierMap,
|
|
5090
|
+
this._searchConfigs,
|
|
5091
|
+
this._ensureValues,
|
|
5092
|
+
options
|
|
5093
|
+
);
|
|
5094
|
+
}
|
|
5095
|
+
*whereStream(condition, options) {
|
|
5096
|
+
yield* whereStreamOp(
|
|
5097
|
+
this._ops,
|
|
5098
|
+
this._ctx.rootId,
|
|
5099
|
+
condition,
|
|
5100
|
+
this.comparator,
|
|
5101
|
+
this._verifierMap,
|
|
5102
|
+
this._searchConfigs,
|
|
5103
|
+
this._ensureValues,
|
|
5104
|
+
options
|
|
5105
|
+
);
|
|
5106
|
+
}
|
|
5107
|
+
keys(condition, options) {
|
|
5108
|
+
const set = /* @__PURE__ */ new Set();
|
|
5109
|
+
for (const key of this.keysStream(condition, options)) {
|
|
5110
|
+
set.add(key);
|
|
5111
|
+
}
|
|
5112
|
+
return set;
|
|
5113
|
+
}
|
|
5114
|
+
where(condition, options) {
|
|
5115
|
+
const map = /* @__PURE__ */ new Map();
|
|
5116
|
+
for (const [key, value] of this.whereStream(condition, options)) {
|
|
5117
|
+
map.set(key, value);
|
|
5118
|
+
}
|
|
5119
|
+
return map;
|
|
5120
|
+
}
|
|
5121
|
+
// ─── Mutation ────────────────────────────────────────────────────
|
|
5122
|
+
insert(key, value) {
|
|
5123
|
+
insertOp(this._ops, this._ctx, key, value, this.comparator);
|
|
5124
|
+
}
|
|
5125
|
+
delete(key, value) {
|
|
5126
|
+
deleteOp(this._ops, this._ctx, key, this.comparator, value);
|
|
5127
|
+
}
|
|
5128
|
+
batchInsert(entries) {
|
|
5129
|
+
batchInsertOp(this._ops, this._ctx, entries, this.comparator);
|
|
5130
|
+
}
|
|
5131
|
+
bulkLoad(entries) {
|
|
5132
|
+
bulkLoadOp(this._ops, this._ctx, entries, this.comparator);
|
|
5133
|
+
}
|
|
5134
|
+
// ─── Head Data ───────────────────────────────────────────────────
|
|
5135
|
+
getHeadData() {
|
|
5136
|
+
const head = this._ops.readHead();
|
|
5137
|
+
if (head === null) {
|
|
5138
|
+
throw new Error("Head not found");
|
|
5139
|
+
}
|
|
5140
|
+
return head.data;
|
|
5141
|
+
}
|
|
5142
|
+
setHeadData(data) {
|
|
5143
|
+
const head = this._ops.readHead();
|
|
5144
|
+
if (head === null) {
|
|
5145
|
+
throw new Error("Head not found");
|
|
5146
|
+
}
|
|
5147
|
+
this._ops.writeHead({
|
|
5148
|
+
root: head.root,
|
|
5149
|
+
order: head.order,
|
|
5150
|
+
data
|
|
5151
|
+
});
|
|
5152
|
+
}
|
|
5153
|
+
// ─── Static utilities ────────────────────────────────────────────
|
|
5154
|
+
static ChooseDriver = BPTreeTransaction.ChooseDriver;
|
|
5155
|
+
};
|
|
5156
|
+
|
|
5157
|
+
// src/BPTreePureAsync.ts
|
|
5158
|
+
var BPTreePureAsync = class {
|
|
5159
|
+
strategy;
|
|
5160
|
+
comparator;
|
|
5161
|
+
option;
|
|
5162
|
+
_cachedRegexp = /* @__PURE__ */ new Map();
|
|
5163
|
+
_ctx;
|
|
5164
|
+
_ops;
|
|
5165
|
+
_verifierMap;
|
|
5166
|
+
_searchConfigs;
|
|
5167
|
+
constructor(strategy, comparator, option) {
|
|
5168
|
+
this.strategy = strategy;
|
|
5169
|
+
this.comparator = comparator;
|
|
5170
|
+
this.option = option ?? {};
|
|
5171
|
+
const ensureValues = (v) => Array.isArray(v) ? v : [v];
|
|
5172
|
+
this._verifierMap = createVerifierMap(comparator, this._cachedRegexp, ensureValues);
|
|
5173
|
+
this._searchConfigs = createSearchConfigsAsync(comparator, ensureValues);
|
|
5174
|
+
}
|
|
5175
|
+
_ensureValues(v) {
|
|
5176
|
+
return Array.isArray(v) ? v : [v];
|
|
5177
|
+
}
|
|
5178
|
+
_createOps() {
|
|
5179
|
+
const strategy = this.strategy;
|
|
5180
|
+
return {
|
|
5181
|
+
async getNode(id) {
|
|
5182
|
+
return await strategy.read(id);
|
|
5183
|
+
},
|
|
5184
|
+
async createNode(leaf, keys, values, parent = null, next = null, prev = null) {
|
|
5185
|
+
const id = await strategy.id(leaf);
|
|
5186
|
+
const node = { id, keys, values, leaf, parent, next, prev };
|
|
5187
|
+
await strategy.write(id, node);
|
|
5188
|
+
return node;
|
|
5189
|
+
},
|
|
5190
|
+
async updateNode(node) {
|
|
5191
|
+
await strategy.write(node.id, node);
|
|
5192
|
+
},
|
|
5193
|
+
async deleteNode(node) {
|
|
5194
|
+
await strategy.delete(node.id);
|
|
5195
|
+
},
|
|
5196
|
+
async readHead() {
|
|
5197
|
+
return await strategy.readHead();
|
|
5198
|
+
},
|
|
5199
|
+
async writeHead(head) {
|
|
5200
|
+
await strategy.writeHead(head);
|
|
5201
|
+
}
|
|
5202
|
+
};
|
|
5203
|
+
}
|
|
5204
|
+
async init() {
|
|
5205
|
+
this._ops = this._createOps();
|
|
5206
|
+
this._ctx = {
|
|
5207
|
+
rootId: "",
|
|
5208
|
+
order: this.strategy.order,
|
|
5209
|
+
headData: () => this.strategy.head.data
|
|
5210
|
+
};
|
|
5211
|
+
await initOpAsync(
|
|
5212
|
+
this._ops,
|
|
5213
|
+
this._ctx,
|
|
5214
|
+
this.strategy.order,
|
|
5215
|
+
this.strategy.head,
|
|
5216
|
+
(head) => {
|
|
5217
|
+
this.strategy.head = head;
|
|
5218
|
+
}
|
|
5219
|
+
);
|
|
5220
|
+
}
|
|
5221
|
+
getRootId() {
|
|
5222
|
+
return this._ctx.rootId;
|
|
5223
|
+
}
|
|
5224
|
+
getOrder() {
|
|
5225
|
+
return this._ctx.order;
|
|
5226
|
+
}
|
|
5227
|
+
verify(nodeValue, condition) {
|
|
5228
|
+
for (const key in condition) {
|
|
5229
|
+
const verifyFn = this._verifierMap[key];
|
|
5230
|
+
const condValue = condition[key];
|
|
5231
|
+
if (!verifyFn(nodeValue, condValue)) return false;
|
|
5232
|
+
}
|
|
5233
|
+
return true;
|
|
5234
|
+
}
|
|
5235
|
+
// ─── Query ───────────────────────────────────────────────────────
|
|
5236
|
+
async get(key) {
|
|
5237
|
+
return getOpAsync(this._ops, this._ctx.rootId, key);
|
|
5238
|
+
}
|
|
5239
|
+
async exists(key, value) {
|
|
5240
|
+
return existsOpAsync(this._ops, this._ctx.rootId, key, value, this.comparator);
|
|
5241
|
+
}
|
|
5242
|
+
async *keysStream(condition, options) {
|
|
5243
|
+
yield* keysStreamOpAsync(
|
|
5244
|
+
this._ops,
|
|
5245
|
+
this._ctx.rootId,
|
|
5246
|
+
condition,
|
|
5247
|
+
this.comparator,
|
|
5248
|
+
this._verifierMap,
|
|
5249
|
+
this._searchConfigs,
|
|
5250
|
+
this._ensureValues,
|
|
5251
|
+
options
|
|
5252
|
+
);
|
|
5253
|
+
}
|
|
5254
|
+
async *whereStream(condition, options) {
|
|
5255
|
+
yield* whereStreamOpAsync(
|
|
5256
|
+
this._ops,
|
|
5257
|
+
this._ctx.rootId,
|
|
5258
|
+
condition,
|
|
5259
|
+
this.comparator,
|
|
5260
|
+
this._verifierMap,
|
|
5261
|
+
this._searchConfigs,
|
|
5262
|
+
this._ensureValues,
|
|
5263
|
+
options
|
|
5264
|
+
);
|
|
5265
|
+
}
|
|
5266
|
+
async keys(condition, options) {
|
|
5267
|
+
const set = /* @__PURE__ */ new Set();
|
|
5268
|
+
for await (const key of this.keysStream(condition, options)) {
|
|
5269
|
+
set.add(key);
|
|
5270
|
+
}
|
|
5271
|
+
return set;
|
|
5272
|
+
}
|
|
5273
|
+
async where(condition, options) {
|
|
5274
|
+
const map = /* @__PURE__ */ new Map();
|
|
5275
|
+
for await (const [key, value] of this.whereStream(condition, options)) {
|
|
5276
|
+
map.set(key, value);
|
|
5277
|
+
}
|
|
5278
|
+
return map;
|
|
5279
|
+
}
|
|
5280
|
+
// ─── Mutation ────────────────────────────────────────────────────
|
|
5281
|
+
async insert(key, value) {
|
|
5282
|
+
await insertOpAsync(this._ops, this._ctx, key, value, this.comparator);
|
|
5283
|
+
}
|
|
5284
|
+
async delete(key, value) {
|
|
5285
|
+
await deleteOpAsync(this._ops, this._ctx, key, this.comparator, value);
|
|
5286
|
+
}
|
|
5287
|
+
async batchInsert(entries) {
|
|
5288
|
+
await batchInsertOpAsync(this._ops, this._ctx, entries, this.comparator);
|
|
5289
|
+
}
|
|
5290
|
+
async bulkLoad(entries) {
|
|
5291
|
+
await bulkLoadOpAsync(this._ops, this._ctx, entries, this.comparator);
|
|
5292
|
+
}
|
|
5293
|
+
// ─── Head Data ───────────────────────────────────────────────────
|
|
5294
|
+
async getHeadData() {
|
|
5295
|
+
const head = await this._ops.readHead();
|
|
5296
|
+
if (head === null) throw new Error("Head not found");
|
|
5297
|
+
return head.data;
|
|
5298
|
+
}
|
|
5299
|
+
async setHeadData(data) {
|
|
5300
|
+
const head = await this._ops.readHead();
|
|
5301
|
+
if (head === null) throw new Error("Head not found");
|
|
5302
|
+
await this._ops.writeHead({ root: head.root, order: head.order, data });
|
|
5303
|
+
}
|
|
5304
|
+
// ─── Static utilities ────────────────────────────────────────────
|
|
5305
|
+
static ChooseDriver = BPTreeTransaction.ChooseDriver;
|
|
5306
|
+
};
|
|
5307
|
+
|
|
4242
5308
|
// src/base/SerializeStrategy.ts
|
|
4243
5309
|
var SerializeStrategy = class {
|
|
4244
5310
|
order;
|