serializable-bptree 8.4.2 → 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 +2739 -1697
- package/dist/esm/index.mjs +2739 -1697
- 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 +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/transaction/BPTreeAsyncTransaction.d.ts +8 -5
- package/dist/types/transaction/BPTreeSyncTransaction.d.ts +8 -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,84 +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
|
-
|
|
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)),
|
|
1597
1650
|
like: (nv, v) => {
|
|
1598
|
-
const nodeValue =
|
|
1651
|
+
const nodeValue = comparator.match(nv);
|
|
1599
1652
|
const value = v;
|
|
1600
|
-
if (!
|
|
1653
|
+
if (!cachedRegexp.has(value)) {
|
|
1601
1654
|
const pattern = value.replace(/%/g, ".*").replace(/_/g, ".");
|
|
1602
1655
|
const regexp2 = new RegExp(`^${pattern}$`, "i");
|
|
1603
|
-
|
|
1656
|
+
cachedRegexp.set(value, regexp2);
|
|
1604
1657
|
}
|
|
1605
|
-
const regexp =
|
|
1658
|
+
const regexp = cachedRegexp.get(value);
|
|
1606
1659
|
return regexp.test(nodeValue);
|
|
1607
1660
|
}
|
|
1608
1661
|
};
|
|
1609
|
-
|
|
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 {
|
|
1610
1669
|
gt: {
|
|
1611
1670
|
asc: {
|
|
1612
|
-
start: (
|
|
1671
|
+
start: (r, ops, v) => findUpperBoundLeaf(ops, r, v[0], comparator),
|
|
1613
1672
|
end: () => null,
|
|
1614
1673
|
direction: 1,
|
|
1615
1674
|
earlyTerminate: false
|
|
1616
1675
|
},
|
|
1617
1676
|
desc: {
|
|
1618
|
-
start: (
|
|
1619
|
-
end: (
|
|
1677
|
+
start: (r, ops) => rightestNode(ops, r),
|
|
1678
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], -1, comparator),
|
|
1620
1679
|
direction: -1,
|
|
1621
1680
|
earlyTerminate: true
|
|
1622
1681
|
}
|
|
1623
1682
|
},
|
|
1624
1683
|
gte: {
|
|
1625
1684
|
asc: {
|
|
1626
|
-
start: (
|
|
1685
|
+
start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
|
|
1627
1686
|
end: () => null,
|
|
1628
1687
|
direction: 1,
|
|
1629
1688
|
earlyTerminate: false
|
|
1630
1689
|
},
|
|
1631
1690
|
desc: {
|
|
1632
|
-
start: (
|
|
1633
|
-
end: (
|
|
1691
|
+
start: (r, ops) => rightestNode(ops, r),
|
|
1692
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], -1, comparator),
|
|
1634
1693
|
direction: -1,
|
|
1635
1694
|
earlyTerminate: true
|
|
1636
1695
|
}
|
|
1637
1696
|
},
|
|
1638
1697
|
lt: {
|
|
1639
1698
|
asc: {
|
|
1640
|
-
start: (
|
|
1641
|
-
end: (
|
|
1699
|
+
start: (r, ops) => leftestNode(ops, r),
|
|
1700
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
|
|
1642
1701
|
direction: 1,
|
|
1643
1702
|
earlyTerminate: true
|
|
1644
1703
|
},
|
|
1645
1704
|
desc: {
|
|
1646
|
-
start: (
|
|
1705
|
+
start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
|
|
1647
1706
|
end: () => null,
|
|
1648
1707
|
direction: -1,
|
|
1649
1708
|
earlyTerminate: false
|
|
@@ -1651,13 +1710,13 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1651
1710
|
},
|
|
1652
1711
|
lte: {
|
|
1653
1712
|
asc: {
|
|
1654
|
-
start: (
|
|
1655
|
-
end: (
|
|
1713
|
+
start: (r, ops) => leftestNode(ops, r),
|
|
1714
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
|
|
1656
1715
|
direction: 1,
|
|
1657
1716
|
earlyTerminate: true
|
|
1658
1717
|
},
|
|
1659
1718
|
desc: {
|
|
1660
|
-
start: (
|
|
1719
|
+
start: (r, ops, v) => findUpperBoundLeaf(ops, r, v[0], comparator),
|
|
1661
1720
|
end: () => null,
|
|
1662
1721
|
direction: -1,
|
|
1663
1722
|
earlyTerminate: false
|
|
@@ -1665,27 +1724,27 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1665
1724
|
},
|
|
1666
1725
|
equal: {
|
|
1667
1726
|
asc: {
|
|
1668
|
-
start: (
|
|
1669
|
-
end: (
|
|
1727
|
+
start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
|
|
1728
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
|
|
1670
1729
|
direction: 1,
|
|
1671
1730
|
earlyTerminate: true
|
|
1672
1731
|
},
|
|
1673
1732
|
desc: {
|
|
1674
|
-
start: (
|
|
1675
|
-
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),
|
|
1676
1735
|
direction: -1,
|
|
1677
1736
|
earlyTerminate: true
|
|
1678
1737
|
}
|
|
1679
1738
|
},
|
|
1680
1739
|
notEqual: {
|
|
1681
1740
|
asc: {
|
|
1682
|
-
start: (
|
|
1741
|
+
start: (r, ops) => leftestNode(ops, r),
|
|
1683
1742
|
end: () => null,
|
|
1684
1743
|
direction: 1,
|
|
1685
1744
|
earlyTerminate: false
|
|
1686
1745
|
},
|
|
1687
1746
|
desc: {
|
|
1688
|
-
start: (
|
|
1747
|
+
start: (r, ops) => rightestNode(ops, r),
|
|
1689
1748
|
end: () => null,
|
|
1690
1749
|
direction: -1,
|
|
1691
1750
|
earlyTerminate: false
|
|
@@ -1693,55 +1752,55 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1693
1752
|
},
|
|
1694
1753
|
or: {
|
|
1695
1754
|
asc: {
|
|
1696
|
-
start: (
|
|
1697
|
-
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),
|
|
1698
1757
|
direction: 1,
|
|
1699
1758
|
earlyTerminate: false
|
|
1700
1759
|
},
|
|
1701
1760
|
desc: {
|
|
1702
|
-
start: (
|
|
1703
|
-
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),
|
|
1704
1763
|
direction: -1,
|
|
1705
1764
|
earlyTerminate: false
|
|
1706
1765
|
}
|
|
1707
1766
|
},
|
|
1708
1767
|
primaryGt: {
|
|
1709
1768
|
asc: {
|
|
1710
|
-
start: (
|
|
1769
|
+
start: (r, ops, v) => findUpperBoundLeaf(ops, r, v[0], comparator),
|
|
1711
1770
|
end: () => null,
|
|
1712
1771
|
direction: 1,
|
|
1713
1772
|
earlyTerminate: false
|
|
1714
1773
|
},
|
|
1715
1774
|
desc: {
|
|
1716
|
-
start: (
|
|
1717
|
-
end: (
|
|
1775
|
+
start: (r, ops) => rightestNode(ops, r),
|
|
1776
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], -1, comparator),
|
|
1718
1777
|
direction: -1,
|
|
1719
1778
|
earlyTerminate: true
|
|
1720
1779
|
}
|
|
1721
1780
|
},
|
|
1722
1781
|
primaryGte: {
|
|
1723
1782
|
asc: {
|
|
1724
|
-
start: (
|
|
1783
|
+
start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
|
|
1725
1784
|
end: () => null,
|
|
1726
1785
|
direction: 1,
|
|
1727
1786
|
earlyTerminate: false
|
|
1728
1787
|
},
|
|
1729
1788
|
desc: {
|
|
1730
|
-
start: (
|
|
1731
|
-
end: (
|
|
1789
|
+
start: (r, ops) => rightestNode(ops, r),
|
|
1790
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], -1, comparator),
|
|
1732
1791
|
direction: -1,
|
|
1733
1792
|
earlyTerminate: true
|
|
1734
1793
|
}
|
|
1735
1794
|
},
|
|
1736
1795
|
primaryLt: {
|
|
1737
1796
|
asc: {
|
|
1738
|
-
start: (
|
|
1739
|
-
end: (
|
|
1797
|
+
start: (r, ops) => leftestNode(ops, r),
|
|
1798
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
|
|
1740
1799
|
direction: 1,
|
|
1741
1800
|
earlyTerminate: true
|
|
1742
1801
|
},
|
|
1743
1802
|
desc: {
|
|
1744
|
-
start: (
|
|
1803
|
+
start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
|
|
1745
1804
|
end: () => null,
|
|
1746
1805
|
direction: -1,
|
|
1747
1806
|
earlyTerminate: false
|
|
@@ -1749,13 +1808,13 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1749
1808
|
},
|
|
1750
1809
|
primaryLte: {
|
|
1751
1810
|
asc: {
|
|
1752
|
-
start: (
|
|
1753
|
-
end: (
|
|
1811
|
+
start: (r, ops) => leftestNode(ops, r),
|
|
1812
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
|
|
1754
1813
|
direction: 1,
|
|
1755
1814
|
earlyTerminate: true
|
|
1756
1815
|
},
|
|
1757
1816
|
desc: {
|
|
1758
|
-
start: (
|
|
1817
|
+
start: (r, ops, v) => findUpperBoundLeaf(ops, r, v[0], comparator),
|
|
1759
1818
|
end: () => null,
|
|
1760
1819
|
direction: -1,
|
|
1761
1820
|
earlyTerminate: false
|
|
@@ -1763,27 +1822,27 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1763
1822
|
},
|
|
1764
1823
|
primaryEqual: {
|
|
1765
1824
|
asc: {
|
|
1766
|
-
start: (
|
|
1767
|
-
end: (
|
|
1825
|
+
start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
|
|
1826
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
|
|
1768
1827
|
direction: 1,
|
|
1769
1828
|
earlyTerminate: true
|
|
1770
1829
|
},
|
|
1771
1830
|
desc: {
|
|
1772
|
-
start: (
|
|
1773
|
-
end: (
|
|
1831
|
+
start: (r, ops, v) => findUpperBoundLeaf(ops, r, v[0], comparator),
|
|
1832
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], -1, comparator),
|
|
1774
1833
|
direction: -1,
|
|
1775
1834
|
earlyTerminate: true
|
|
1776
1835
|
}
|
|
1777
1836
|
},
|
|
1778
1837
|
primaryNotEqual: {
|
|
1779
1838
|
asc: {
|
|
1780
|
-
start: (
|
|
1839
|
+
start: (r, ops) => leftestNode(ops, r),
|
|
1781
1840
|
end: () => null,
|
|
1782
1841
|
direction: 1,
|
|
1783
1842
|
earlyTerminate: false
|
|
1784
1843
|
},
|
|
1785
1844
|
desc: {
|
|
1786
|
-
start: (
|
|
1845
|
+
start: (r, ops) => rightestNode(ops, r),
|
|
1787
1846
|
end: () => null,
|
|
1788
1847
|
direction: -1,
|
|
1789
1848
|
earlyTerminate: false
|
|
@@ -1791,176 +1850,1186 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1791
1850
|
},
|
|
1792
1851
|
primaryOr: {
|
|
1793
1852
|
asc: {
|
|
1794
|
-
start: (
|
|
1795
|
-
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),
|
|
1796
1855
|
direction: 1,
|
|
1797
1856
|
earlyTerminate: false
|
|
1798
1857
|
},
|
|
1799
1858
|
desc: {
|
|
1800
|
-
start: (
|
|
1801
|
-
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),
|
|
1802
1861
|
direction: -1,
|
|
1803
1862
|
earlyTerminate: false
|
|
1804
1863
|
}
|
|
1805
1864
|
},
|
|
1806
1865
|
like: {
|
|
1807
1866
|
asc: {
|
|
1808
|
-
start: (
|
|
1867
|
+
start: (r, ops) => leftestNode(ops, r),
|
|
1809
1868
|
end: () => null,
|
|
1810
1869
|
direction: 1,
|
|
1811
1870
|
earlyTerminate: false
|
|
1812
1871
|
},
|
|
1813
1872
|
desc: {
|
|
1814
|
-
start: (
|
|
1873
|
+
start: (r, ops) => rightestNode(ops, r),
|
|
1815
1874
|
end: () => null,
|
|
1816
1875
|
direction: -1,
|
|
1817
1876
|
earlyTerminate: false
|
|
1818
1877
|
}
|
|
1819
1878
|
}
|
|
1820
1879
|
};
|
|
1821
|
-
|
|
1822
|
-
|
|
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
|
-
if (candidates.length === 0) return null;
|
|
1861
|
-
if (candidates.length === 1) return candidates[0];
|
|
1862
|
-
let best = candidates[0];
|
|
1863
|
-
let bestScore = 0;
|
|
1864
|
-
for (const candidate of candidates) {
|
|
1865
|
-
let score = 0;
|
|
1866
|
-
for (const key in candidate.condition) {
|
|
1867
|
-
const condKey = key;
|
|
1868
|
-
const priority = _BPTreeTransaction.conditionPriority[condKey] ?? 0;
|
|
1869
|
-
if (priority > score) {
|
|
1870
|
-
score = priority;
|
|
1871
|
-
}
|
|
1872
|
-
}
|
|
1873
|
-
if (score > bestScore) {
|
|
1874
|
-
bestScore = score;
|
|
1875
|
-
best = candidate;
|
|
1876
|
-
}
|
|
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;
|
|
1877
1919
|
}
|
|
1878
|
-
return best;
|
|
1879
1920
|
}
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
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
|
+
}
|
|
1888
1928
|
}
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
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
|
+
}
|
|
1895
1938
|
}
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
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}`);
|
|
1902
1977
|
}
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
* @param nodeValue The value to verify.
|
|
1907
|
-
* @param condition The condition to verify against.
|
|
1908
|
-
* @returns Returns true if the value satisfies the condition.
|
|
1909
|
-
*/
|
|
1910
|
-
verify(nodeValue, condition) {
|
|
1911
|
-
for (const key in condition) {
|
|
1912
|
-
const verify = this.verifierMap[key];
|
|
1913
|
-
const condValue = condition[key];
|
|
1914
|
-
if (!verify(nodeValue, condValue)) {
|
|
1915
|
-
return false;
|
|
1916
|
-
}
|
|
1917
|
-
}
|
|
1918
|
-
return true;
|
|
1978
|
+
const guessNode = insertableNode[key];
|
|
1979
|
+
if (!guessNode) {
|
|
1980
|
+
return null;
|
|
1919
1981
|
}
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
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];
|
|
1932
2013
|
}
|
|
1933
|
-
leaf.keys[index].push(key);
|
|
1934
|
-
return true;
|
|
1935
2014
|
}
|
|
1936
|
-
leaf.values.splice(index, 0, value);
|
|
1937
|
-
leaf.keys.splice(index, 0, [key]);
|
|
1938
|
-
return true;
|
|
1939
2015
|
} else {
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
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
|
+
}
|
|
1943
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;
|
|
1944
2069
|
}
|
|
1945
|
-
|
|
1946
|
-
|
|
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
|
+
}
|
|
1947
2176
|
}
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
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 = [];
|
|
1964
3033
|
let endValues = [];
|
|
1965
3034
|
for (let i = 0, len = startCandidates.length; i < len; i++) {
|
|
1966
3035
|
const key = startCandidates[i];
|
|
@@ -2095,6 +3164,10 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
2095
3164
|
|
|
2096
3165
|
// src/transaction/BPTreeSyncTransaction.ts
|
|
2097
3166
|
var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
3167
|
+
_ops;
|
|
3168
|
+
_ctx;
|
|
3169
|
+
_verifierMapCached;
|
|
3170
|
+
_searchConfigsCached;
|
|
2098
3171
|
constructor(rootTx, mvccRoot, mvcc, strategy, comparator, option) {
|
|
2099
3172
|
super(
|
|
2100
3173
|
rootTx,
|
|
@@ -2104,248 +3177,113 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2104
3177
|
comparator,
|
|
2105
3178
|
option
|
|
2106
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);
|
|
2107
3238
|
}
|
|
3239
|
+
// ─── Legacy protected methods (delegating to ops) ────────────────
|
|
2108
3240
|
getNode(id) {
|
|
2109
|
-
return this.
|
|
3241
|
+
return this._ops.getNode(id);
|
|
2110
3242
|
}
|
|
2111
|
-
/**
|
|
2112
|
-
* Create a new node with a unique ID.
|
|
2113
|
-
*/
|
|
2114
3243
|
_createNode(leaf, keys, values, parent = null, next = null, prev = null) {
|
|
2115
|
-
|
|
2116
|
-
const node = {
|
|
2117
|
-
id,
|
|
2118
|
-
keys,
|
|
2119
|
-
values,
|
|
2120
|
-
leaf,
|
|
2121
|
-
parent,
|
|
2122
|
-
next,
|
|
2123
|
-
prev
|
|
2124
|
-
};
|
|
2125
|
-
this.mvcc.create(id, node);
|
|
2126
|
-
return node;
|
|
3244
|
+
return this._ops.createNode(leaf, keys, values, parent, next, prev);
|
|
2127
3245
|
}
|
|
2128
3246
|
_updateNode(node) {
|
|
2129
|
-
|
|
2130
|
-
return;
|
|
2131
|
-
}
|
|
2132
|
-
this.mvcc.write(node.id, node);
|
|
3247
|
+
this._ops.updateNode(node);
|
|
2133
3248
|
}
|
|
2134
3249
|
_deleteNode(node) {
|
|
2135
|
-
|
|
2136
|
-
return;
|
|
2137
|
-
}
|
|
2138
|
-
this.mvcc.delete(node.id);
|
|
3250
|
+
this._ops.deleteNode(node);
|
|
2139
3251
|
}
|
|
2140
3252
|
_readHead() {
|
|
2141
|
-
return this.
|
|
3253
|
+
return this._ops.readHead();
|
|
2142
3254
|
}
|
|
2143
3255
|
_writeHead(head) {
|
|
2144
|
-
|
|
2145
|
-
this.mvcc.create("__HEAD__", head);
|
|
2146
|
-
} else {
|
|
2147
|
-
this.mvcc.write("__HEAD__", head);
|
|
2148
|
-
}
|
|
2149
|
-
this.rootId = head.root;
|
|
3256
|
+
this._ops.writeHead(head);
|
|
2150
3257
|
}
|
|
3258
|
+
// ─── Tree traversal (delegating to algorithm) ────────────────────
|
|
2151
3259
|
_insertAtLeaf(node, key, value) {
|
|
2152
|
-
|
|
2153
|
-
if (leaf.values.length) {
|
|
2154
|
-
for (let i = 0, len = leaf.values.length; i < len; i++) {
|
|
2155
|
-
const nValue = leaf.values[i];
|
|
2156
|
-
if (this.comparator.isSame(value, nValue)) {
|
|
2157
|
-
const keys = leaf.keys[i];
|
|
2158
|
-
if (keys.includes(key)) {
|
|
2159
|
-
break;
|
|
2160
|
-
}
|
|
2161
|
-
leaf = this._cloneNode(leaf);
|
|
2162
|
-
leaf.keys[i].push(key);
|
|
2163
|
-
this._updateNode(leaf);
|
|
2164
|
-
return leaf;
|
|
2165
|
-
} else if (this.comparator.isLower(value, nValue)) {
|
|
2166
|
-
leaf = this._cloneNode(leaf);
|
|
2167
|
-
leaf.values.splice(i, 0, value);
|
|
2168
|
-
leaf.keys.splice(i, 0, [key]);
|
|
2169
|
-
this._updateNode(leaf);
|
|
2170
|
-
return leaf;
|
|
2171
|
-
} else if (i + 1 === leaf.values.length) {
|
|
2172
|
-
leaf = this._cloneNode(leaf);
|
|
2173
|
-
leaf.values.push(value);
|
|
2174
|
-
leaf.keys.push([key]);
|
|
2175
|
-
this._updateNode(leaf);
|
|
2176
|
-
return leaf;
|
|
2177
|
-
}
|
|
2178
|
-
}
|
|
2179
|
-
} else {
|
|
2180
|
-
leaf = this._cloneNode(leaf);
|
|
2181
|
-
leaf.values = [value];
|
|
2182
|
-
leaf.keys = [[key]];
|
|
2183
|
-
this._updateNode(leaf);
|
|
2184
|
-
return leaf;
|
|
2185
|
-
}
|
|
2186
|
-
return leaf;
|
|
3260
|
+
return insertAtLeaf(this._ops, node, key, value, this.comparator);
|
|
2187
3261
|
}
|
|
2188
3262
|
_insertInParent(node, value, newSiblingNode) {
|
|
2189
|
-
|
|
2190
|
-
node = this._cloneNode(node);
|
|
2191
|
-
newSiblingNode = this._cloneNode(newSiblingNode);
|
|
2192
|
-
const root = this._createNode(false, [node.id, newSiblingNode.id], [value]);
|
|
2193
|
-
this.rootId = root.id;
|
|
2194
|
-
node.parent = root.id;
|
|
2195
|
-
newSiblingNode.parent = root.id;
|
|
2196
|
-
if (newSiblingNode.leaf) {
|
|
2197
|
-
node.next = newSiblingNode.id;
|
|
2198
|
-
newSiblingNode.prev = node.id;
|
|
2199
|
-
}
|
|
2200
|
-
this._writeHead({
|
|
2201
|
-
root: root.id,
|
|
2202
|
-
order: this.order,
|
|
2203
|
-
data: this.strategy.head.data
|
|
2204
|
-
});
|
|
2205
|
-
this._updateNode(node);
|
|
2206
|
-
this._updateNode(newSiblingNode);
|
|
2207
|
-
return;
|
|
2208
|
-
}
|
|
2209
|
-
const parentNode = this._cloneNode(this.getNode(node.parent));
|
|
2210
|
-
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
2211
|
-
if (nodeIndex === -1) {
|
|
2212
|
-
throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
|
|
2213
|
-
}
|
|
2214
|
-
parentNode.values.splice(nodeIndex, 0, value);
|
|
2215
|
-
parentNode.keys.splice(nodeIndex + 1, 0, newSiblingNode.id);
|
|
2216
|
-
newSiblingNode = this._cloneNode(newSiblingNode);
|
|
2217
|
-
newSiblingNode.parent = parentNode.id;
|
|
2218
|
-
if (newSiblingNode.leaf) {
|
|
2219
|
-
const leftSibling = this._cloneNode(node);
|
|
2220
|
-
const oldNextId = leftSibling.next;
|
|
2221
|
-
newSiblingNode.prev = leftSibling.id;
|
|
2222
|
-
newSiblingNode.next = oldNextId;
|
|
2223
|
-
leftSibling.next = newSiblingNode.id;
|
|
2224
|
-
this._updateNode(leftSibling);
|
|
2225
|
-
if (oldNextId) {
|
|
2226
|
-
const oldNext = this._cloneNode(this.getNode(oldNextId));
|
|
2227
|
-
oldNext.prev = newSiblingNode.id;
|
|
2228
|
-
this._updateNode(oldNext);
|
|
2229
|
-
}
|
|
2230
|
-
}
|
|
2231
|
-
this._updateNode(parentNode);
|
|
2232
|
-
this._updateNode(newSiblingNode);
|
|
2233
|
-
if (parentNode.keys.length > this.order) {
|
|
2234
|
-
const newSiblingNodeRecursive = this._createNode(false, [], []);
|
|
2235
|
-
newSiblingNodeRecursive.parent = parentNode.parent;
|
|
2236
|
-
const mid = Math.ceil(this.order / 2) - 1;
|
|
2237
|
-
newSiblingNodeRecursive.values = parentNode.values.slice(mid + 1);
|
|
2238
|
-
newSiblingNodeRecursive.keys = parentNode.keys.slice(mid + 1);
|
|
2239
|
-
const midValue = parentNode.values[mid];
|
|
2240
|
-
parentNode.values = parentNode.values.slice(0, mid);
|
|
2241
|
-
parentNode.keys = parentNode.keys.slice(0, mid + 1);
|
|
2242
|
-
for (let i = 0, len = newSiblingNodeRecursive.keys.length; i < len; i++) {
|
|
2243
|
-
const k = newSiblingNodeRecursive.keys[i];
|
|
2244
|
-
const n = this._cloneNode(this.getNode(k));
|
|
2245
|
-
n.parent = newSiblingNodeRecursive.id;
|
|
2246
|
-
this._updateNode(n);
|
|
2247
|
-
}
|
|
2248
|
-
this._updateNode(parentNode);
|
|
2249
|
-
this._insertInParent(parentNode, midValue, newSiblingNodeRecursive);
|
|
2250
|
-
}
|
|
3263
|
+
insertInParent(this._ops, this._ctx, node, value, newSiblingNode);
|
|
2251
3264
|
}
|
|
2252
3265
|
locateLeaf(value) {
|
|
2253
|
-
|
|
2254
|
-
while (!node.leaf) {
|
|
2255
|
-
const { index } = this._binarySearchValues(node.values, value, false, true);
|
|
2256
|
-
node = this.getNode(node.keys[index]);
|
|
2257
|
-
}
|
|
2258
|
-
return node;
|
|
3266
|
+
return locateLeaf(this._ops, this._ctx.rootId, value, this.comparator);
|
|
2259
3267
|
}
|
|
2260
3268
|
findLowerBoundLeaf(value) {
|
|
2261
|
-
|
|
2262
|
-
while (!node.leaf) {
|
|
2263
|
-
const { index } = this._binarySearchValues(node.values, value, true, false);
|
|
2264
|
-
node = this.getNode(node.keys[index]);
|
|
2265
|
-
}
|
|
2266
|
-
return node;
|
|
3269
|
+
return findLowerBoundLeaf(this._ops, this._ctx.rootId, value, this.comparator);
|
|
2267
3270
|
}
|
|
2268
3271
|
findUpperBoundLeaf(value) {
|
|
2269
|
-
|
|
2270
|
-
while (!node.leaf) {
|
|
2271
|
-
const { index } = this._binarySearchValues(node.values, value, true, true);
|
|
2272
|
-
node = this.getNode(node.keys[index]);
|
|
2273
|
-
}
|
|
2274
|
-
return node;
|
|
3272
|
+
return findUpperBoundLeaf(this._ops, this._ctx.rootId, value, this.comparator);
|
|
2275
3273
|
}
|
|
2276
3274
|
findOuterBoundaryLeaf(value, direction) {
|
|
2277
|
-
|
|
2278
|
-
let key;
|
|
2279
|
-
switch (direction) {
|
|
2280
|
-
case -1:
|
|
2281
|
-
key = "prev";
|
|
2282
|
-
break;
|
|
2283
|
-
case 1:
|
|
2284
|
-
key = "next";
|
|
2285
|
-
break;
|
|
2286
|
-
default:
|
|
2287
|
-
throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
|
|
2288
|
-
}
|
|
2289
|
-
const guessNode = insertableNode[key];
|
|
2290
|
-
if (!guessNode) {
|
|
2291
|
-
return null;
|
|
2292
|
-
}
|
|
2293
|
-
return this.getNode(guessNode);
|
|
3275
|
+
return findOuterBoundaryLeaf(this._ops, this._ctx.rootId, value, direction, this.comparator);
|
|
2294
3276
|
}
|
|
2295
3277
|
leftestNode() {
|
|
2296
|
-
|
|
2297
|
-
if (node === null) {
|
|
2298
|
-
debugger;
|
|
2299
|
-
}
|
|
2300
|
-
while (!node.leaf) {
|
|
2301
|
-
const keys = node.keys;
|
|
2302
|
-
node = this.getNode(keys[0]);
|
|
2303
|
-
}
|
|
2304
|
-
return node;
|
|
3278
|
+
return leftestNode(this._ops, this._ctx.rootId);
|
|
2305
3279
|
}
|
|
2306
3280
|
rightestNode() {
|
|
2307
|
-
|
|
2308
|
-
while (!node.leaf) {
|
|
2309
|
-
const keys = node.keys;
|
|
2310
|
-
node = this.getNode(keys[keys.length - 1]);
|
|
2311
|
-
}
|
|
2312
|
-
return node;
|
|
3281
|
+
return rightestNode(this._ops, this._ctx.rootId);
|
|
2313
3282
|
}
|
|
2314
3283
|
*getPairsGenerator(startNode, endNode, direction) {
|
|
2315
|
-
|
|
2316
|
-
while (true) {
|
|
2317
|
-
if (endNode && node.id === endNode.id) {
|
|
2318
|
-
break;
|
|
2319
|
-
}
|
|
2320
|
-
const len = node.values.length;
|
|
2321
|
-
if (direction === 1) {
|
|
2322
|
-
for (let i = 0; i < len; i++) {
|
|
2323
|
-
const nValue = node.values[i];
|
|
2324
|
-
const keys = node.keys[i];
|
|
2325
|
-
for (let j = 0, len2 = keys.length; j < len2; j++) {
|
|
2326
|
-
yield [keys[j], nValue];
|
|
2327
|
-
}
|
|
2328
|
-
}
|
|
2329
|
-
} else {
|
|
2330
|
-
let i = len;
|
|
2331
|
-
while (i--) {
|
|
2332
|
-
const nValue = node.values[i];
|
|
2333
|
-
const keys = node.keys[i];
|
|
2334
|
-
let j = keys.length;
|
|
2335
|
-
while (j--) {
|
|
2336
|
-
yield [keys[j], nValue];
|
|
2337
|
-
}
|
|
2338
|
-
}
|
|
2339
|
-
}
|
|
2340
|
-
if (direction === 1) {
|
|
2341
|
-
if (!node.next) break;
|
|
2342
|
-
node = this.getNode(node.next);
|
|
2343
|
-
} else {
|
|
2344
|
-
if (!node.prev) break;
|
|
2345
|
-
node = this.getNode(node.prev);
|
|
2346
|
-
}
|
|
2347
|
-
}
|
|
3284
|
+
yield* getPairsGenerator(this._ops, startNode, endNode, direction);
|
|
2348
3285
|
}
|
|
3286
|
+
// ─── Lifecycle ───────────────────────────────────────────────────
|
|
2349
3287
|
init() {
|
|
2350
3288
|
if (this.rootTx !== this) {
|
|
2351
3289
|
throw new Error("Cannot call init on a nested transaction");
|
|
@@ -2362,534 +3300,92 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2362
3300
|
this.isInitialized = true;
|
|
2363
3301
|
try {
|
|
2364
3302
|
this._clearCache();
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
this.
|
|
2368
|
-
|
|
2369
|
-
this.
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
data: this.strategy.head.data
|
|
2373
|
-
});
|
|
2374
|
-
} else {
|
|
2375
|
-
const { root, order } = head;
|
|
2376
|
-
this.strategy.head = head;
|
|
2377
|
-
this.order = order;
|
|
2378
|
-
this.rootId = root;
|
|
2379
|
-
}
|
|
2380
|
-
if (this.order < 3) {
|
|
2381
|
-
throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
|
|
2382
|
-
}
|
|
2383
|
-
} catch (e) {
|
|
2384
|
-
this.isInitialized = false;
|
|
2385
|
-
throw e;
|
|
2386
|
-
}
|
|
2387
|
-
}
|
|
2388
|
-
reload() {
|
|
2389
|
-
if (this.rootTx !== this) {
|
|
2390
|
-
throw new Error("Cannot call reload on a nested transaction");
|
|
2391
|
-
}
|
|
2392
|
-
this._reloadInternal();
|
|
2393
|
-
}
|
|
2394
|
-
_reloadInternal() {
|
|
2395
|
-
this._resetForReload();
|
|
2396
|
-
this._initInternal();
|
|
2397
|
-
}
|
|
2398
|
-
exists(key, value) {
|
|
2399
|
-
const node = this.locateLeaf(value);
|
|
2400
|
-
const { index, found } = this._binarySearchValues(node.values, value);
|
|
2401
|
-
if (found) {
|
|
2402
|
-
const keys = node.keys[index];
|
|
2403
|
-
if (keys.includes(key)) {
|
|
2404
|
-
return true;
|
|
2405
|
-
}
|
|
2406
|
-
}
|
|
2407
|
-
return false;
|
|
2408
|
-
}
|
|
2409
|
-
get(key) {
|
|
2410
|
-
let node = this.leftestNode();
|
|
2411
|
-
while (true) {
|
|
2412
|
-
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
2413
|
-
const keys = node.keys[i];
|
|
2414
|
-
for (let j = 0, len2 = keys.length; j < len2; j++) {
|
|
2415
|
-
if (keys[j] === key) {
|
|
2416
|
-
return node.values[i];
|
|
2417
|
-
}
|
|
2418
|
-
}
|
|
2419
|
-
}
|
|
2420
|
-
if (!node.next) break;
|
|
2421
|
-
node = this.getNode(node.next);
|
|
2422
|
-
}
|
|
2423
|
-
return void 0;
|
|
2424
|
-
}
|
|
2425
|
-
*keysStream(condition, options) {
|
|
2426
|
-
const { filterValues, limit, order = "asc" } = options ?? {};
|
|
2427
|
-
const stream = this.whereStream(condition, options);
|
|
2428
|
-
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
2429
|
-
let count = 0;
|
|
2430
|
-
for (const [key] of stream) {
|
|
2431
|
-
if (intersection && !intersection.has(key)) {
|
|
2432
|
-
continue;
|
|
2433
|
-
}
|
|
2434
|
-
yield key;
|
|
2435
|
-
count++;
|
|
2436
|
-
if (limit !== void 0 && count >= limit) {
|
|
2437
|
-
break;
|
|
2438
|
-
}
|
|
2439
|
-
}
|
|
2440
|
-
}
|
|
2441
|
-
*whereStream(condition, options) {
|
|
2442
|
-
const { filterValues, limit, order = "asc" } = options ?? {};
|
|
2443
|
-
const conditionKeys = Object.keys(condition);
|
|
2444
|
-
if (conditionKeys.length === 0) return;
|
|
2445
|
-
const resolved = this.resolveStartEndConfigs(condition, order);
|
|
2446
|
-
const direction = resolved.direction;
|
|
2447
|
-
let startNode;
|
|
2448
|
-
if (resolved.startKey) {
|
|
2449
|
-
const startConfig = this.searchConfigs[resolved.startKey][order];
|
|
2450
|
-
startNode = startConfig.start(this, resolved.startValues);
|
|
2451
|
-
} else {
|
|
2452
|
-
startNode = order === "asc" ? this.leftestNode() : this.rightestNode();
|
|
2453
|
-
}
|
|
2454
|
-
let endNode = null;
|
|
2455
|
-
if (resolved.endKey) {
|
|
2456
|
-
const endConfig = this.searchConfigs[resolved.endKey][order];
|
|
2457
|
-
endNode = endConfig.end(this, resolved.endValues);
|
|
2458
|
-
}
|
|
2459
|
-
if (!startNode) return;
|
|
2460
|
-
const generator = this.getPairsGenerator(
|
|
2461
|
-
startNode,
|
|
2462
|
-
endNode,
|
|
2463
|
-
direction
|
|
2464
|
-
);
|
|
2465
|
-
let count = 0;
|
|
2466
|
-
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
2467
|
-
for (const pair of generator) {
|
|
2468
|
-
const [k, v] = pair;
|
|
2469
|
-
if (intersection && !intersection.has(k)) {
|
|
2470
|
-
continue;
|
|
2471
|
-
}
|
|
2472
|
-
if (this.verify(v, condition)) {
|
|
2473
|
-
yield pair;
|
|
2474
|
-
count++;
|
|
2475
|
-
if (limit !== void 0 && count >= limit) {
|
|
2476
|
-
break;
|
|
2477
|
-
}
|
|
2478
|
-
}
|
|
2479
|
-
}
|
|
2480
|
-
}
|
|
2481
|
-
keys(condition, options) {
|
|
2482
|
-
const set = /* @__PURE__ */ new Set();
|
|
2483
|
-
for (const key of this.keysStream(condition, options)) {
|
|
2484
|
-
set.add(key);
|
|
2485
|
-
}
|
|
2486
|
-
return set;
|
|
2487
|
-
}
|
|
2488
|
-
where(condition, options) {
|
|
2489
|
-
const map = /* @__PURE__ */ new Map();
|
|
2490
|
-
for (const [key, value] of this.whereStream(condition, options)) {
|
|
2491
|
-
map.set(key, value);
|
|
2492
|
-
}
|
|
2493
|
-
return map;
|
|
2494
|
-
}
|
|
2495
|
-
insert(key, value) {
|
|
2496
|
-
let before = this.locateLeaf(value);
|
|
2497
|
-
before = this._insertAtLeaf(before, key, value);
|
|
2498
|
-
if (before.values.length === this.order) {
|
|
2499
|
-
let after = this._createNode(
|
|
2500
|
-
true,
|
|
2501
|
-
[],
|
|
2502
|
-
[],
|
|
2503
|
-
before.parent,
|
|
2504
|
-
null,
|
|
2505
|
-
null
|
|
2506
|
-
);
|
|
2507
|
-
const mid = Math.ceil(this.order / 2) - 1;
|
|
2508
|
-
after = this._cloneNode(after);
|
|
2509
|
-
after.values = before.values.slice(mid + 1);
|
|
2510
|
-
after.keys = before.keys.slice(mid + 1);
|
|
2511
|
-
before.values = before.values.slice(0, mid + 1);
|
|
2512
|
-
before.keys = before.keys.slice(0, mid + 1);
|
|
2513
|
-
this._updateNode(before);
|
|
2514
|
-
this._updateNode(after);
|
|
2515
|
-
this._insertInParent(before, after.values[0], after);
|
|
2516
|
-
}
|
|
2517
|
-
}
|
|
2518
|
-
batchInsert(entries) {
|
|
2519
|
-
if (entries.length === 0) return;
|
|
2520
|
-
const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
|
|
2521
|
-
let currentLeaf = null;
|
|
2522
|
-
let modified = false;
|
|
2523
|
-
let cachedLeafId = null;
|
|
2524
|
-
let cachedLeafMaxValue = null;
|
|
2525
|
-
for (let i = 0, len = sorted.length; i < len; i++) {
|
|
2526
|
-
const [key, value] = sorted[i];
|
|
2527
|
-
let targetLeaf;
|
|
2528
|
-
if (cachedLeafId !== null && cachedLeafMaxValue !== null && currentLeaf !== null && (this.comparator.isLower(value, cachedLeafMaxValue) || this.comparator.isSame(value, cachedLeafMaxValue))) {
|
|
2529
|
-
targetLeaf = currentLeaf;
|
|
2530
|
-
} else {
|
|
2531
|
-
targetLeaf = this.locateLeaf(value);
|
|
2532
|
-
}
|
|
2533
|
-
if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
|
|
2534
|
-
} else {
|
|
2535
|
-
if (currentLeaf !== null && modified) {
|
|
2536
|
-
this._updateNode(currentLeaf);
|
|
2537
|
-
}
|
|
2538
|
-
currentLeaf = this._cloneNode(targetLeaf);
|
|
2539
|
-
modified = false;
|
|
2540
|
-
}
|
|
2541
|
-
cachedLeafId = currentLeaf.id;
|
|
2542
|
-
const changed = this._insertValueIntoLeaf(currentLeaf, key, value);
|
|
2543
|
-
modified = modified || changed;
|
|
2544
|
-
cachedLeafMaxValue = currentLeaf.values[currentLeaf.values.length - 1];
|
|
2545
|
-
if (currentLeaf.values.length === this.order) {
|
|
2546
|
-
this._updateNode(currentLeaf);
|
|
2547
|
-
let after = this._createNode(
|
|
2548
|
-
true,
|
|
2549
|
-
[],
|
|
2550
|
-
[],
|
|
2551
|
-
currentLeaf.parent,
|
|
2552
|
-
null,
|
|
2553
|
-
null
|
|
2554
|
-
);
|
|
2555
|
-
const mid = Math.ceil(this.order / 2) - 1;
|
|
2556
|
-
after = this._cloneNode(after);
|
|
2557
|
-
after.values = currentLeaf.values.slice(mid + 1);
|
|
2558
|
-
after.keys = currentLeaf.keys.slice(mid + 1);
|
|
2559
|
-
currentLeaf.values = currentLeaf.values.slice(0, mid + 1);
|
|
2560
|
-
currentLeaf.keys = currentLeaf.keys.slice(0, mid + 1);
|
|
2561
|
-
this._updateNode(currentLeaf);
|
|
2562
|
-
this._updateNode(after);
|
|
2563
|
-
this._insertInParent(currentLeaf, after.values[0], after);
|
|
2564
|
-
currentLeaf = null;
|
|
2565
|
-
cachedLeafId = null;
|
|
2566
|
-
cachedLeafMaxValue = null;
|
|
2567
|
-
modified = false;
|
|
2568
|
-
}
|
|
2569
|
-
}
|
|
2570
|
-
if (currentLeaf !== null && modified) {
|
|
2571
|
-
this._updateNode(currentLeaf);
|
|
2572
|
-
}
|
|
2573
|
-
}
|
|
2574
|
-
bulkLoad(entries) {
|
|
2575
|
-
if (entries.length === 0) return;
|
|
2576
|
-
const root = this.getNode(this.rootId);
|
|
2577
|
-
if (!root.leaf || root.values.length > 0) {
|
|
2578
|
-
throw new Error("bulkLoad can only be called on an empty tree. Use batchInsert for non-empty trees.");
|
|
2579
|
-
}
|
|
2580
|
-
const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
|
|
2581
|
-
const grouped = [];
|
|
2582
|
-
for (let i = 0, len = sorted.length; i < len; i++) {
|
|
2583
|
-
const [key, value] = sorted[i];
|
|
2584
|
-
const last = grouped[grouped.length - 1];
|
|
2585
|
-
if (last && this.comparator.isSame(last.value, value)) {
|
|
2586
|
-
if (!last.keys.includes(key)) {
|
|
2587
|
-
last.keys.push(key);
|
|
2588
|
-
}
|
|
2589
|
-
} else {
|
|
2590
|
-
grouped.push({ keys: [key], value });
|
|
2591
|
-
}
|
|
2592
|
-
}
|
|
2593
|
-
this._deleteNode(root);
|
|
2594
|
-
const maxLeafSize = this.order - 1;
|
|
2595
|
-
const leaves = [];
|
|
2596
|
-
for (let i = 0, len = grouped.length; i < len; i += maxLeafSize) {
|
|
2597
|
-
const chunk = grouped.slice(i, i + maxLeafSize);
|
|
2598
|
-
const leafKeys = chunk.map((g) => g.keys);
|
|
2599
|
-
const leafValues = chunk.map((g) => g.value);
|
|
2600
|
-
const leaf = this._createNode(
|
|
2601
|
-
true,
|
|
2602
|
-
leafKeys,
|
|
2603
|
-
leafValues,
|
|
2604
|
-
null,
|
|
2605
|
-
null,
|
|
2606
|
-
null
|
|
2607
|
-
);
|
|
2608
|
-
leaves.push(leaf);
|
|
2609
|
-
}
|
|
2610
|
-
for (let i = 0, len = leaves.length; i < len; i++) {
|
|
2611
|
-
if (i > 0) {
|
|
2612
|
-
leaves[i].prev = leaves[i - 1].id;
|
|
2613
|
-
}
|
|
2614
|
-
if (i < len - 1) {
|
|
2615
|
-
leaves[i].next = leaves[i + 1].id;
|
|
2616
|
-
}
|
|
2617
|
-
this._updateNode(leaves[i]);
|
|
2618
|
-
}
|
|
2619
|
-
let currentLevel = leaves;
|
|
2620
|
-
while (currentLevel.length > 1) {
|
|
2621
|
-
const nextLevel = [];
|
|
2622
|
-
for (let i = 0, len = currentLevel.length; i < len; i += this.order) {
|
|
2623
|
-
const children = currentLevel.slice(i, i + this.order);
|
|
2624
|
-
const childIds = children.map((c) => c.id);
|
|
2625
|
-
const separators = [];
|
|
2626
|
-
for (let j = 1, len2 = children.length; j < len2; j++) {
|
|
2627
|
-
separators.push(children[j].values[0]);
|
|
2628
|
-
}
|
|
2629
|
-
const internalNode = this._createNode(
|
|
2630
|
-
false,
|
|
2631
|
-
childIds,
|
|
2632
|
-
separators,
|
|
2633
|
-
null,
|
|
2634
|
-
null,
|
|
2635
|
-
null
|
|
2636
|
-
);
|
|
2637
|
-
for (let j = 0, len2 = children.length; j < len2; j++) {
|
|
2638
|
-
const child = children[j];
|
|
2639
|
-
child.parent = internalNode.id;
|
|
2640
|
-
this._updateNode(child);
|
|
2641
|
-
}
|
|
2642
|
-
nextLevel.push(internalNode);
|
|
2643
|
-
}
|
|
2644
|
-
currentLevel = nextLevel;
|
|
2645
|
-
}
|
|
2646
|
-
const newRoot = currentLevel[0];
|
|
2647
|
-
this._writeHead({
|
|
2648
|
-
root: newRoot.id,
|
|
2649
|
-
order: this.order,
|
|
2650
|
-
data: this.strategy.head.data
|
|
2651
|
-
});
|
|
2652
|
-
}
|
|
2653
|
-
_deleteEntry(node, key) {
|
|
2654
|
-
if (!node.leaf) {
|
|
2655
|
-
let keyIndex = -1;
|
|
2656
|
-
for (let i = 0, len = node.keys.length; i < len; i++) {
|
|
2657
|
-
if (node.keys[i] === key) {
|
|
2658
|
-
keyIndex = i;
|
|
2659
|
-
break;
|
|
2660
|
-
}
|
|
2661
|
-
}
|
|
2662
|
-
if (keyIndex !== -1) {
|
|
2663
|
-
node = this._cloneNode(node);
|
|
2664
|
-
node.keys.splice(keyIndex, 1);
|
|
2665
|
-
const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
|
|
2666
|
-
node.values.splice(valueIndex, 1);
|
|
2667
|
-
this._updateNode(node);
|
|
2668
|
-
}
|
|
2669
|
-
}
|
|
2670
|
-
if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
|
|
2671
|
-
const keys = node.keys;
|
|
2672
|
-
this._deleteNode(node);
|
|
2673
|
-
const newRoot = this._cloneNode(this.getNode(keys[0]));
|
|
2674
|
-
newRoot.parent = null;
|
|
2675
|
-
this._updateNode(newRoot);
|
|
2676
|
-
this._writeHead({
|
|
2677
|
-
root: newRoot.id,
|
|
2678
|
-
order: this.order,
|
|
2679
|
-
data: this.strategy.head.data
|
|
2680
|
-
});
|
|
2681
|
-
return node;
|
|
2682
|
-
} else if (this.rootId === node.id) {
|
|
2683
|
-
this._writeHead({
|
|
2684
|
-
root: node.id,
|
|
2685
|
-
order: this.order,
|
|
2686
|
-
data: this.strategy.head.data
|
|
2687
|
-
});
|
|
2688
|
-
return node;
|
|
2689
|
-
} else if (node.keys.length < Math.ceil(this.order / 2) && !node.leaf || node.values.length < Math.ceil((this.order - 1) / 2) && node.leaf) {
|
|
2690
|
-
if (node.parent === null) {
|
|
2691
|
-
return node;
|
|
2692
|
-
}
|
|
2693
|
-
let isPredecessor = false;
|
|
2694
|
-
let parentNode = this.getNode(node.parent);
|
|
2695
|
-
let prevNode = null;
|
|
2696
|
-
let nextNode = null;
|
|
2697
|
-
let prevValue = null;
|
|
2698
|
-
let postValue = null;
|
|
2699
|
-
for (let i = 0, len = parentNode.keys.length; i < len; i++) {
|
|
2700
|
-
const nKey = parentNode.keys[i];
|
|
2701
|
-
if (nKey === node.id) {
|
|
2702
|
-
if (i > 0) {
|
|
2703
|
-
prevNode = this.getNode(parentNode.keys[i - 1]);
|
|
2704
|
-
prevValue = parentNode.values[i - 1];
|
|
2705
|
-
}
|
|
2706
|
-
if (i < parentNode.keys.length - 1) {
|
|
2707
|
-
nextNode = this.getNode(parentNode.keys[i + 1]);
|
|
2708
|
-
postValue = parentNode.values[i];
|
|
2709
|
-
}
|
|
2710
|
-
}
|
|
2711
|
-
}
|
|
2712
|
-
let siblingNode;
|
|
2713
|
-
let guess;
|
|
2714
|
-
if (prevNode === null) {
|
|
2715
|
-
siblingNode = nextNode;
|
|
2716
|
-
guess = postValue;
|
|
2717
|
-
} else if (nextNode === null) {
|
|
2718
|
-
isPredecessor = true;
|
|
2719
|
-
siblingNode = prevNode;
|
|
2720
|
-
guess = prevValue;
|
|
2721
|
-
} else {
|
|
2722
|
-
if (node.values.length + nextNode.values.length < this.order) {
|
|
2723
|
-
siblingNode = nextNode;
|
|
2724
|
-
guess = postValue;
|
|
2725
|
-
} else {
|
|
2726
|
-
isPredecessor = true;
|
|
2727
|
-
siblingNode = prevNode;
|
|
2728
|
-
guess = prevValue;
|
|
2729
|
-
}
|
|
2730
|
-
}
|
|
2731
|
-
if (!siblingNode) {
|
|
2732
|
-
return node;
|
|
2733
|
-
}
|
|
2734
|
-
node = this._cloneNode(node);
|
|
2735
|
-
siblingNode = this._cloneNode(siblingNode);
|
|
2736
|
-
if (node.values.length + siblingNode.values.length < this.order) {
|
|
2737
|
-
if (!isPredecessor) {
|
|
2738
|
-
const pTemp = siblingNode;
|
|
2739
|
-
siblingNode = node;
|
|
2740
|
-
node = pTemp;
|
|
2741
|
-
}
|
|
2742
|
-
siblingNode.keys.push(...node.keys);
|
|
2743
|
-
if (!node.leaf) {
|
|
2744
|
-
siblingNode.values.push(guess);
|
|
2745
|
-
} else {
|
|
2746
|
-
siblingNode.next = node.next;
|
|
2747
|
-
if (siblingNode.next) {
|
|
2748
|
-
const n = this._cloneNode(this.getNode(siblingNode.next));
|
|
2749
|
-
n.prev = siblingNode.id;
|
|
2750
|
-
this._updateNode(n);
|
|
2751
|
-
}
|
|
2752
|
-
}
|
|
2753
|
-
siblingNode.values.push(...node.values);
|
|
2754
|
-
if (!siblingNode.leaf) {
|
|
2755
|
-
const keys = siblingNode.keys;
|
|
2756
|
-
for (let i = 0, len = keys.length; i < len; i++) {
|
|
2757
|
-
const key2 = keys[i];
|
|
2758
|
-
const node2 = this._cloneNode(this.getNode(key2));
|
|
2759
|
-
node2.parent = siblingNode.id;
|
|
2760
|
-
this._updateNode(node2);
|
|
2761
|
-
}
|
|
2762
|
-
}
|
|
2763
|
-
this._deleteNode(node);
|
|
2764
|
-
this._updateNode(siblingNode);
|
|
2765
|
-
this._deleteEntry(this.getNode(node.parent), node.id);
|
|
2766
|
-
} else {
|
|
2767
|
-
if (isPredecessor) {
|
|
2768
|
-
let pointerPm;
|
|
2769
|
-
let pointerKm;
|
|
2770
|
-
if (!node.leaf) {
|
|
2771
|
-
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
2772
|
-
pointerKm = siblingNode.values.splice(-1)[0];
|
|
2773
|
-
node.keys = [pointerPm, ...node.keys];
|
|
2774
|
-
node.values = [guess, ...node.values];
|
|
2775
|
-
parentNode = this._cloneNode(this.getNode(node.parent));
|
|
2776
|
-
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
2777
|
-
if (nodeIndex > 0) {
|
|
2778
|
-
parentNode.values[nodeIndex - 1] = pointerKm;
|
|
2779
|
-
this._updateNode(parentNode);
|
|
2780
|
-
}
|
|
2781
|
-
} else {
|
|
2782
|
-
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
2783
|
-
pointerKm = siblingNode.values.splice(-1)[0];
|
|
2784
|
-
node.keys = [pointerPm, ...node.keys];
|
|
2785
|
-
node.values = [pointerKm, ...node.values];
|
|
2786
|
-
parentNode = this._cloneNode(this.getNode(node.parent));
|
|
2787
|
-
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
2788
|
-
if (nodeIndex > 0) {
|
|
2789
|
-
parentNode.values[nodeIndex - 1] = pointerKm;
|
|
2790
|
-
this._updateNode(parentNode);
|
|
2791
|
-
}
|
|
2792
|
-
}
|
|
2793
|
-
this._updateNode(node);
|
|
2794
|
-
this._updateNode(siblingNode);
|
|
2795
|
-
} else {
|
|
2796
|
-
let pointerP0;
|
|
2797
|
-
let pointerK0;
|
|
2798
|
-
if (!node.leaf) {
|
|
2799
|
-
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
2800
|
-
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
2801
|
-
node.keys = [...node.keys, pointerP0];
|
|
2802
|
-
node.values = [...node.values, guess];
|
|
2803
|
-
parentNode = this._cloneNode(this.getNode(node.parent));
|
|
2804
|
-
const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
|
|
2805
|
-
if (pointerIndex > 0) {
|
|
2806
|
-
parentNode.values[pointerIndex - 1] = pointerK0;
|
|
2807
|
-
this._updateNode(parentNode);
|
|
2808
|
-
}
|
|
2809
|
-
} else {
|
|
2810
|
-
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
2811
|
-
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
2812
|
-
node.keys = [...node.keys, pointerP0];
|
|
2813
|
-
node.values = [...node.values, pointerK0];
|
|
2814
|
-
parentNode = this._cloneNode(this.getNode(node.parent));
|
|
2815
|
-
const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
|
|
2816
|
-
if (pointerIndex > 0) {
|
|
2817
|
-
parentNode.values[pointerIndex - 1] = siblingNode.values[0];
|
|
2818
|
-
this._updateNode(parentNode);
|
|
2819
|
-
}
|
|
2820
|
-
}
|
|
2821
|
-
this._updateNode(node);
|
|
2822
|
-
this._updateNode(siblingNode);
|
|
2823
|
-
}
|
|
2824
|
-
if (!siblingNode.leaf) {
|
|
2825
|
-
for (let i = 0, len = siblingNode.keys.length; i < len; i++) {
|
|
2826
|
-
const key2 = siblingNode.keys[i];
|
|
2827
|
-
const n = this._cloneNode(this.getNode(key2));
|
|
2828
|
-
n.parent = siblingNode.id;
|
|
2829
|
-
this._updateNode(n);
|
|
2830
|
-
}
|
|
2831
|
-
}
|
|
2832
|
-
if (!node.leaf) {
|
|
2833
|
-
for (let i = 0, len = node.keys.length; i < len; i++) {
|
|
2834
|
-
const key2 = node.keys[i];
|
|
2835
|
-
const n = this._cloneNode(this.getNode(key2));
|
|
2836
|
-
n.parent = node.id;
|
|
2837
|
-
this._updateNode(n);
|
|
2838
|
-
}
|
|
2839
|
-
}
|
|
2840
|
-
if (!parentNode.leaf) {
|
|
2841
|
-
for (let i = 0, len = parentNode.keys.length; i < len; i++) {
|
|
2842
|
-
const key2 = parentNode.keys[i];
|
|
2843
|
-
const n = this._cloneNode(this.getNode(key2));
|
|
2844
|
-
n.parent = parentNode.id;
|
|
2845
|
-
this._updateNode(n);
|
|
2846
|
-
}
|
|
3303
|
+
initOp(
|
|
3304
|
+
this._ops,
|
|
3305
|
+
this._ctx,
|
|
3306
|
+
this.strategy.order,
|
|
3307
|
+
this.strategy.head,
|
|
3308
|
+
(head) => {
|
|
3309
|
+
this.strategy.head = head;
|
|
2847
3310
|
}
|
|
2848
|
-
|
|
2849
|
-
}
|
|
2850
|
-
this.
|
|
3311
|
+
);
|
|
3312
|
+
} catch (e) {
|
|
3313
|
+
this.isInitialized = false;
|
|
3314
|
+
throw e;
|
|
2851
3315
|
}
|
|
2852
|
-
return node;
|
|
2853
3316
|
}
|
|
2854
|
-
|
|
2855
|
-
if (
|
|
2856
|
-
|
|
3317
|
+
reload() {
|
|
3318
|
+
if (this.rootTx !== this) {
|
|
3319
|
+
throw new Error("Cannot call reload on a nested transaction");
|
|
2857
3320
|
}
|
|
2858
|
-
|
|
2859
|
-
|
|
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);
|
|
2860
3362
|
}
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
if (this.comparator.isSame(value, nValue)) {
|
|
2868
|
-
const keys = node.keys[i];
|
|
2869
|
-
const keyIndex = keys.indexOf(key);
|
|
2870
|
-
if (keyIndex !== -1) {
|
|
2871
|
-
node = this._cloneNode(node);
|
|
2872
|
-
const freshKeys = node.keys[i];
|
|
2873
|
-
freshKeys.splice(keyIndex, 1);
|
|
2874
|
-
if (freshKeys.length === 0) {
|
|
2875
|
-
node.keys.splice(i, 1);
|
|
2876
|
-
node.values.splice(i, 1);
|
|
2877
|
-
}
|
|
2878
|
-
this._updateNode(node);
|
|
2879
|
-
node = this._deleteEntry(node, key);
|
|
2880
|
-
found = true;
|
|
2881
|
-
break;
|
|
2882
|
-
}
|
|
2883
|
-
}
|
|
2884
|
-
}
|
|
2885
|
-
if (found) break;
|
|
2886
|
-
if (node.next) {
|
|
2887
|
-
node = this.getNode(node.next);
|
|
2888
|
-
continue;
|
|
2889
|
-
}
|
|
2890
|
-
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);
|
|
2891
3369
|
}
|
|
3370
|
+
return map;
|
|
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);
|
|
2892
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 ───────────────────────────────────────────────────
|
|
2893
3389
|
getHeadData() {
|
|
2894
3390
|
const head = this._readHead();
|
|
2895
3391
|
if (head === null) {
|
|
@@ -2908,6 +3404,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2908
3404
|
data
|
|
2909
3405
|
});
|
|
2910
3406
|
}
|
|
3407
|
+
// ─── Transaction ─────────────────────────────────────────────────
|
|
2911
3408
|
commit(label) {
|
|
2912
3409
|
let result = this.mvcc.commit(label);
|
|
2913
3410
|
if (result.success) {
|
|
@@ -3227,71 +3724,878 @@ var Ryoiki2 = class _Ryoiki2 {
|
|
|
3227
3724
|
rangeTask: [Array, Function],
|
|
3228
3725
|
rangeTaskTimeout: [Array, Function, Number]
|
|
3229
3726
|
}
|
|
3230
|
-
);
|
|
3231
|
-
return this._lock(
|
|
3232
|
-
this.readQueue,
|
|
3233
|
-
range,
|
|
3234
|
-
timeout,
|
|
3235
|
-
task,
|
|
3236
|
-
() => !this.rangeOverlapping(this.writings, range)
|
|
3237
|
-
);
|
|
3238
|
-
}
|
|
3239
|
-
/**
|
|
3240
|
-
* Internal implementation of the write lock. Handles both overloads.
|
|
3241
|
-
* @template T - The return type of the task.
|
|
3242
|
-
* @param arg0 - Either a range or a task callback.
|
|
3243
|
-
* If a range is provided, the task is the second argument.
|
|
3244
|
-
* @param arg1 - The task to execute, required if a range is provided.
|
|
3245
|
-
* @param arg2 - The timeout for acquiring the lock.
|
|
3246
|
-
* If the lock cannot be acquired within this period, an error will be thrown.
|
|
3247
|
-
* If this value is not provided, no timeout will be set.
|
|
3248
|
-
* @returns A promise resolving to the result of the task execution.
|
|
3249
|
-
*/
|
|
3250
|
-
writeLock(arg0, arg1, arg2) {
|
|
3251
|
-
const [range, task, timeout] = this._handleOverload(
|
|
3252
|
-
[arg0, arg1, arg2],
|
|
3253
|
-
{
|
|
3254
|
-
rangeTask: (range2, task2) => [range2, task2, -1],
|
|
3255
|
-
rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
|
|
3256
|
-
task: (task2) => [[-Infinity, Infinity], task2, -1],
|
|
3257
|
-
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
|
|
3258
3998
|
},
|
|
3259
|
-
{
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3999
|
+
desc: {
|
|
4000
|
+
start: (r, ops) => rightestNodeAsync(ops, r),
|
|
4001
|
+
end: async () => null,
|
|
4002
|
+
direction: -1,
|
|
4003
|
+
earlyTerminate: false
|
|
3264
4004
|
}
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
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
|
+
}
|
|
3273
4071
|
}
|
|
3274
|
-
|
|
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
|
+
}
|
|
3275
4089
|
}
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
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;
|
|
3282
4122
|
}
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
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
|
+
}
|
|
3289
4215
|
}
|
|
3290
|
-
|
|
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
|
+
}
|
|
3291
4591
|
|
|
3292
4592
|
// src/transaction/BPTreeAsyncTransaction.ts
|
|
3293
4593
|
var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
3294
4594
|
lock;
|
|
4595
|
+
_ops;
|
|
4596
|
+
_ctx;
|
|
4597
|
+
_verifierMapCached;
|
|
4598
|
+
_searchConfigsCached;
|
|
3295
4599
|
constructor(rootTx, mvccRoot, mvcc, strategy, comparator, option) {
|
|
3296
4600
|
super(
|
|
3297
4601
|
rootTx,
|
|
@@ -3302,6 +4606,64 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3302
4606
|
option
|
|
3303
4607
|
);
|
|
3304
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);
|
|
3305
4667
|
}
|
|
3306
4668
|
async writeLock(id, fn) {
|
|
3307
4669
|
let lockId;
|
|
@@ -3312,256 +4674,54 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3312
4674
|
this.lock.writeUnlock(lockId);
|
|
3313
4675
|
});
|
|
3314
4676
|
}
|
|
4677
|
+
// ─── Legacy protected methods (delegating to ops) ────────────────
|
|
3315
4678
|
async getNode(id) {
|
|
3316
|
-
return
|
|
4679
|
+
return this._ops.getNode(id);
|
|
3317
4680
|
}
|
|
3318
|
-
/**
|
|
3319
|
-
* Create a new node with a unique ID.
|
|
3320
|
-
*/
|
|
3321
4681
|
async _createNode(leaf, keys, values, parent = null, next = null, prev = null) {
|
|
3322
|
-
|
|
3323
|
-
const node = {
|
|
3324
|
-
id,
|
|
3325
|
-
keys,
|
|
3326
|
-
values,
|
|
3327
|
-
leaf,
|
|
3328
|
-
parent,
|
|
3329
|
-
next,
|
|
3330
|
-
prev
|
|
3331
|
-
};
|
|
3332
|
-
await this.mvcc.create(id, node);
|
|
3333
|
-
return node;
|
|
4682
|
+
return this._ops.createNode(leaf, keys, values, parent, next, prev);
|
|
3334
4683
|
}
|
|
3335
4684
|
async _updateNode(node) {
|
|
3336
|
-
|
|
3337
|
-
return;
|
|
3338
|
-
}
|
|
3339
|
-
await this.mvcc.write(node.id, node);
|
|
4685
|
+
await this._ops.updateNode(node);
|
|
3340
4686
|
}
|
|
3341
4687
|
async _deleteNode(node) {
|
|
3342
|
-
|
|
3343
|
-
return;
|
|
3344
|
-
}
|
|
3345
|
-
await this.mvcc.delete(node.id);
|
|
4688
|
+
await this._ops.deleteNode(node);
|
|
3346
4689
|
}
|
|
3347
4690
|
async _readHead() {
|
|
3348
|
-
return
|
|
4691
|
+
return this._ops.readHead();
|
|
3349
4692
|
}
|
|
3350
4693
|
async _writeHead(head) {
|
|
3351
|
-
|
|
3352
|
-
await this.mvcc.create("__HEAD__", head);
|
|
3353
|
-
} else {
|
|
3354
|
-
await this.mvcc.write("__HEAD__", head);
|
|
3355
|
-
}
|
|
3356
|
-
this.rootId = head.root;
|
|
4694
|
+
await this._ops.writeHead(head);
|
|
3357
4695
|
}
|
|
4696
|
+
// ─── Tree traversal (delegating to algorithm) ────────────────────
|
|
3358
4697
|
async _insertAtLeaf(node, key, value) {
|
|
3359
|
-
|
|
3360
|
-
if (leaf.values.length) {
|
|
3361
|
-
for (let i = 0, len = leaf.values.length; i < len; i++) {
|
|
3362
|
-
const nValue = leaf.values[i];
|
|
3363
|
-
if (this.comparator.isSame(value, nValue)) {
|
|
3364
|
-
const keys = leaf.keys[i];
|
|
3365
|
-
if (keys.includes(key)) {
|
|
3366
|
-
break;
|
|
3367
|
-
}
|
|
3368
|
-
leaf = this._cloneNode(leaf);
|
|
3369
|
-
leaf.keys[i].push(key);
|
|
3370
|
-
await this._updateNode(leaf);
|
|
3371
|
-
return leaf;
|
|
3372
|
-
} else if (this.comparator.isLower(value, nValue)) {
|
|
3373
|
-
leaf = this._cloneNode(leaf);
|
|
3374
|
-
leaf.values.splice(i, 0, value);
|
|
3375
|
-
leaf.keys.splice(i, 0, [key]);
|
|
3376
|
-
await this._updateNode(leaf);
|
|
3377
|
-
return leaf;
|
|
3378
|
-
} else if (i + 1 === leaf.values.length) {
|
|
3379
|
-
leaf = this._cloneNode(leaf);
|
|
3380
|
-
leaf.values.push(value);
|
|
3381
|
-
leaf.keys.push([key]);
|
|
3382
|
-
await this._updateNode(leaf);
|
|
3383
|
-
return leaf;
|
|
3384
|
-
}
|
|
3385
|
-
}
|
|
3386
|
-
} else {
|
|
3387
|
-
leaf = this._cloneNode(leaf);
|
|
3388
|
-
leaf.values = [value];
|
|
3389
|
-
leaf.keys = [[key]];
|
|
3390
|
-
await this._updateNode(leaf);
|
|
3391
|
-
return leaf;
|
|
3392
|
-
}
|
|
3393
|
-
return leaf;
|
|
4698
|
+
return insertAtLeafAsync(this._ops, node, key, value, this.comparator);
|
|
3394
4699
|
}
|
|
3395
4700
|
async _insertInParent(node, value, newSiblingNode) {
|
|
3396
|
-
|
|
3397
|
-
node = this._cloneNode(node);
|
|
3398
|
-
newSiblingNode = this._cloneNode(newSiblingNode);
|
|
3399
|
-
const root = await this._createNode(false, [node.id, newSiblingNode.id], [value]);
|
|
3400
|
-
this.rootId = root.id;
|
|
3401
|
-
node.parent = root.id;
|
|
3402
|
-
newSiblingNode.parent = root.id;
|
|
3403
|
-
if (newSiblingNode.leaf) {
|
|
3404
|
-
node.next = newSiblingNode.id;
|
|
3405
|
-
newSiblingNode.prev = node.id;
|
|
3406
|
-
}
|
|
3407
|
-
await this._writeHead({
|
|
3408
|
-
root: root.id,
|
|
3409
|
-
order: this.order,
|
|
3410
|
-
data: this.strategy.head.data
|
|
3411
|
-
});
|
|
3412
|
-
await this._updateNode(node);
|
|
3413
|
-
await this._updateNode(newSiblingNode);
|
|
3414
|
-
return;
|
|
3415
|
-
}
|
|
3416
|
-
const parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
3417
|
-
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
3418
|
-
if (nodeIndex === -1) {
|
|
3419
|
-
throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
|
|
3420
|
-
}
|
|
3421
|
-
parentNode.values.splice(nodeIndex, 0, value);
|
|
3422
|
-
parentNode.keys.splice(nodeIndex + 1, 0, newSiblingNode.id);
|
|
3423
|
-
newSiblingNode = this._cloneNode(newSiblingNode);
|
|
3424
|
-
newSiblingNode.parent = parentNode.id;
|
|
3425
|
-
if (newSiblingNode.leaf) {
|
|
3426
|
-
const leftSibling = this._cloneNode(node);
|
|
3427
|
-
const oldNextId = leftSibling.next;
|
|
3428
|
-
newSiblingNode.prev = leftSibling.id;
|
|
3429
|
-
newSiblingNode.next = oldNextId;
|
|
3430
|
-
leftSibling.next = newSiblingNode.id;
|
|
3431
|
-
await this._updateNode(leftSibling);
|
|
3432
|
-
if (oldNextId) {
|
|
3433
|
-
const oldNext = this._cloneNode(await this.getNode(oldNextId));
|
|
3434
|
-
oldNext.prev = newSiblingNode.id;
|
|
3435
|
-
await this._updateNode(oldNext);
|
|
3436
|
-
}
|
|
3437
|
-
}
|
|
3438
|
-
await this._updateNode(parentNode);
|
|
3439
|
-
await this._updateNode(newSiblingNode);
|
|
3440
|
-
if (parentNode.keys.length > this.order) {
|
|
3441
|
-
const newSiblingNodeRecursive = await this._createNode(false, [], []);
|
|
3442
|
-
newSiblingNodeRecursive.parent = parentNode.parent;
|
|
3443
|
-
const mid = Math.ceil(this.order / 2) - 1;
|
|
3444
|
-
newSiblingNodeRecursive.values = parentNode.values.slice(mid + 1);
|
|
3445
|
-
newSiblingNodeRecursive.keys = parentNode.keys.slice(mid + 1);
|
|
3446
|
-
const midValue = parentNode.values[mid];
|
|
3447
|
-
parentNode.values = parentNode.values.slice(0, mid);
|
|
3448
|
-
parentNode.keys = parentNode.keys.slice(0, mid + 1);
|
|
3449
|
-
for (let i = 0, len = newSiblingNodeRecursive.keys.length; i < len; i++) {
|
|
3450
|
-
const k = newSiblingNodeRecursive.keys[i];
|
|
3451
|
-
const n = this._cloneNode(await this.getNode(k));
|
|
3452
|
-
n.parent = newSiblingNodeRecursive.id;
|
|
3453
|
-
await this._updateNode(n);
|
|
3454
|
-
}
|
|
3455
|
-
await this._updateNode(parentNode);
|
|
3456
|
-
await this._insertInParent(parentNode, midValue, newSiblingNodeRecursive);
|
|
3457
|
-
}
|
|
4701
|
+
await insertInParentAsync(this._ops, this._ctx, node, value, newSiblingNode);
|
|
3458
4702
|
}
|
|
3459
4703
|
async locateLeaf(value) {
|
|
3460
|
-
|
|
3461
|
-
while (!node.leaf) {
|
|
3462
|
-
const { index } = this._binarySearchValues(node.values, value, false, true);
|
|
3463
|
-
node = await this.getNode(node.keys[index]);
|
|
3464
|
-
}
|
|
3465
|
-
return node;
|
|
4704
|
+
return locateLeafAsync(this._ops, this._ctx.rootId, value, this.comparator);
|
|
3466
4705
|
}
|
|
3467
4706
|
async findLowerBoundLeaf(value) {
|
|
3468
|
-
|
|
3469
|
-
while (!node.leaf) {
|
|
3470
|
-
const { index } = this._binarySearchValues(node.values, value, true, false);
|
|
3471
|
-
node = await this.getNode(node.keys[index]);
|
|
3472
|
-
}
|
|
3473
|
-
return node;
|
|
4707
|
+
return findLowerBoundLeafAsync(this._ops, this._ctx.rootId, value, this.comparator);
|
|
3474
4708
|
}
|
|
3475
4709
|
async findUpperBoundLeaf(value) {
|
|
3476
|
-
|
|
3477
|
-
while (!node.leaf) {
|
|
3478
|
-
const { index } = this._binarySearchValues(node.values, value, true, true);
|
|
3479
|
-
node = await this.getNode(node.keys[index]);
|
|
3480
|
-
}
|
|
3481
|
-
return node;
|
|
4710
|
+
return findUpperBoundLeafAsync(this._ops, this._ctx.rootId, value, this.comparator);
|
|
3482
4711
|
}
|
|
3483
4712
|
async findOuterBoundaryLeaf(value, direction) {
|
|
3484
|
-
|
|
3485
|
-
let key;
|
|
3486
|
-
switch (direction) {
|
|
3487
|
-
case -1:
|
|
3488
|
-
key = "prev";
|
|
3489
|
-
break;
|
|
3490
|
-
case 1:
|
|
3491
|
-
key = "next";
|
|
3492
|
-
break;
|
|
3493
|
-
default:
|
|
3494
|
-
throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
|
|
3495
|
-
}
|
|
3496
|
-
const guessNode = insertableNode[key];
|
|
3497
|
-
if (!guessNode) {
|
|
3498
|
-
return null;
|
|
3499
|
-
}
|
|
3500
|
-
return await this.getNode(guessNode);
|
|
4713
|
+
return findOuterBoundaryLeafAsync(this._ops, this._ctx.rootId, value, direction, this.comparator);
|
|
3501
4714
|
}
|
|
3502
4715
|
async leftestNode() {
|
|
3503
|
-
|
|
3504
|
-
if (node === null) {
|
|
3505
|
-
debugger;
|
|
3506
|
-
}
|
|
3507
|
-
while (!node.leaf) {
|
|
3508
|
-
const keys = node.keys;
|
|
3509
|
-
node = await this.getNode(keys[0]);
|
|
3510
|
-
}
|
|
3511
|
-
return node;
|
|
4716
|
+
return leftestNodeAsync(this._ops, this._ctx.rootId);
|
|
3512
4717
|
}
|
|
3513
4718
|
async rightestNode() {
|
|
3514
|
-
|
|
3515
|
-
while (!node.leaf) {
|
|
3516
|
-
const keys = node.keys;
|
|
3517
|
-
node = await this.getNode(keys[keys.length - 1]);
|
|
3518
|
-
}
|
|
3519
|
-
return node;
|
|
4719
|
+
return rightestNodeAsync(this._ops, this._ctx.rootId);
|
|
3520
4720
|
}
|
|
3521
4721
|
async *getPairsGenerator(startNode, endNode, direction) {
|
|
3522
|
-
|
|
3523
|
-
let nextNodePromise = null;
|
|
3524
|
-
while (true) {
|
|
3525
|
-
if (endNode && node.id === endNode.id) {
|
|
3526
|
-
break;
|
|
3527
|
-
}
|
|
3528
|
-
if (direction === 1) {
|
|
3529
|
-
if (node.next) {
|
|
3530
|
-
nextNodePromise = this.getNode(node.next);
|
|
3531
|
-
}
|
|
3532
|
-
} else {
|
|
3533
|
-
if (node.prev) {
|
|
3534
|
-
nextNodePromise = this.getNode(node.prev);
|
|
3535
|
-
}
|
|
3536
|
-
}
|
|
3537
|
-
const len = node.values.length;
|
|
3538
|
-
if (direction === 1) {
|
|
3539
|
-
for (let i = 0; i < len; i++) {
|
|
3540
|
-
const nValue = node.values[i];
|
|
3541
|
-
const keys = node.keys[i];
|
|
3542
|
-
for (let j = 0, len2 = keys.length; j < len2; j++) {
|
|
3543
|
-
yield [keys[j], nValue];
|
|
3544
|
-
}
|
|
3545
|
-
}
|
|
3546
|
-
} else {
|
|
3547
|
-
let i = len;
|
|
3548
|
-
while (i--) {
|
|
3549
|
-
const nValue = node.values[i];
|
|
3550
|
-
const keys = node.keys[i];
|
|
3551
|
-
let j = keys.length;
|
|
3552
|
-
while (j--) {
|
|
3553
|
-
yield [keys[j], nValue];
|
|
3554
|
-
}
|
|
3555
|
-
}
|
|
3556
|
-
}
|
|
3557
|
-
if (nextNodePromise) {
|
|
3558
|
-
node = await nextNodePromise;
|
|
3559
|
-
nextNodePromise = null;
|
|
3560
|
-
} else {
|
|
3561
|
-
break;
|
|
3562
|
-
}
|
|
3563
|
-
}
|
|
4722
|
+
yield* getPairsGeneratorAsync(this._ops, startNode, endNode, direction);
|
|
3564
4723
|
}
|
|
4724
|
+
// ─── Lifecycle ───────────────────────────────────────────────────
|
|
3565
4725
|
async init() {
|
|
3566
4726
|
if (this.rootTx !== this) {
|
|
3567
4727
|
throw new Error("Cannot call init on a nested transaction");
|
|
@@ -3578,24 +4738,15 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3578
4738
|
this.isInitialized = true;
|
|
3579
4739
|
try {
|
|
3580
4740
|
this._clearCache();
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
this.
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
} else {
|
|
3591
|
-
const { root, order } = head;
|
|
3592
|
-
this.strategy.head = head;
|
|
3593
|
-
this.order = order;
|
|
3594
|
-
this.rootId = root;
|
|
3595
|
-
}
|
|
3596
|
-
if (this.order < 3) {
|
|
3597
|
-
throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
|
|
3598
|
-
}
|
|
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
|
+
);
|
|
3599
4750
|
} catch (e) {
|
|
3600
4751
|
this.isInitialized = false;
|
|
3601
4752
|
throw e;
|
|
@@ -3611,88 +4762,36 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3611
4762
|
this._resetForReload();
|
|
3612
4763
|
await this._initInternal();
|
|
3613
4764
|
}
|
|
4765
|
+
// ─── Query (delegating to algorithm) ─────────────────────────────
|
|
3614
4766
|
async exists(key, value) {
|
|
3615
|
-
|
|
3616
|
-
const { index, found } = this._binarySearchValues(node.values, value);
|
|
3617
|
-
if (found) {
|
|
3618
|
-
const keys = node.keys[index];
|
|
3619
|
-
if (keys.includes(key)) {
|
|
3620
|
-
return true;
|
|
3621
|
-
}
|
|
3622
|
-
}
|
|
3623
|
-
return false;
|
|
4767
|
+
return existsOpAsync(this._ops, this._ctx.rootId, key, value, this.comparator);
|
|
3624
4768
|
}
|
|
3625
4769
|
async get(key) {
|
|
3626
|
-
|
|
3627
|
-
while (true) {
|
|
3628
|
-
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
3629
|
-
const keys = node.keys[i];
|
|
3630
|
-
for (let j = 0, len2 = keys.length; j < len2; j++) {
|
|
3631
|
-
if (keys[j] === key) {
|
|
3632
|
-
return node.values[i];
|
|
3633
|
-
}
|
|
3634
|
-
}
|
|
3635
|
-
}
|
|
3636
|
-
if (!node.next) break;
|
|
3637
|
-
node = await this.getNode(node.next);
|
|
3638
|
-
}
|
|
3639
|
-
return void 0;
|
|
4770
|
+
return getOpAsync(this._ops, this._ctx.rootId, key);
|
|
3640
4771
|
}
|
|
3641
4772
|
async *keysStream(condition, options) {
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
if (limit !== void 0 && count >= limit) {
|
|
3653
|
-
break;
|
|
3654
|
-
}
|
|
3655
|
-
}
|
|
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
|
+
);
|
|
3656
4783
|
}
|
|
3657
4784
|
async *whereStream(condition, options) {
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
} else {
|
|
3668
|
-
startNode = order === "asc" ? await this.leftestNode() : await this.rightestNode();
|
|
3669
|
-
}
|
|
3670
|
-
let endNode = null;
|
|
3671
|
-
if (resolved.endKey) {
|
|
3672
|
-
const endConfig = this.searchConfigs[resolved.endKey][order];
|
|
3673
|
-
endNode = await endConfig.end(this, resolved.endValues);
|
|
3674
|
-
}
|
|
3675
|
-
if (!startNode) return;
|
|
3676
|
-
const generator = this.getPairsGenerator(
|
|
3677
|
-
startNode,
|
|
3678
|
-
endNode,
|
|
3679
|
-
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
|
|
3680
4794
|
);
|
|
3681
|
-
let count = 0;
|
|
3682
|
-
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
3683
|
-
for await (const pair of generator) {
|
|
3684
|
-
const [k, v] = pair;
|
|
3685
|
-
if (intersection && !intersection.has(k)) {
|
|
3686
|
-
continue;
|
|
3687
|
-
}
|
|
3688
|
-
if (this.verify(v, condition)) {
|
|
3689
|
-
yield pair;
|
|
3690
|
-
count++;
|
|
3691
|
-
if (limit !== void 0 && count >= limit) {
|
|
3692
|
-
break;
|
|
3693
|
-
}
|
|
3694
|
-
}
|
|
3695
|
-
}
|
|
3696
4795
|
}
|
|
3697
4796
|
async keys(condition, options) {
|
|
3698
4797
|
const set = /* @__PURE__ */ new Set();
|
|
@@ -3708,412 +4807,33 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3708
4807
|
}
|
|
3709
4808
|
return map;
|
|
3710
4809
|
}
|
|
4810
|
+
// ─── Mutation (delegating to algorithm) ──────────────────────────
|
|
3711
4811
|
async insert(key, value) {
|
|
3712
4812
|
return this.writeLock(0, async () => {
|
|
3713
|
-
|
|
3714
|
-
before = await this._insertAtLeaf(before, key, value);
|
|
3715
|
-
if (before.values.length === this.order) {
|
|
3716
|
-
let after = await this._createNode(
|
|
3717
|
-
true,
|
|
3718
|
-
[],
|
|
3719
|
-
[],
|
|
3720
|
-
before.parent,
|
|
3721
|
-
null,
|
|
3722
|
-
null
|
|
3723
|
-
);
|
|
3724
|
-
const mid = Math.ceil(this.order / 2) - 1;
|
|
3725
|
-
after = this._cloneNode(after);
|
|
3726
|
-
after.values = before.values.slice(mid + 1);
|
|
3727
|
-
after.keys = before.keys.slice(mid + 1);
|
|
3728
|
-
before.values = before.values.slice(0, mid + 1);
|
|
3729
|
-
before.keys = before.keys.slice(0, mid + 1);
|
|
3730
|
-
await this._updateNode(before);
|
|
3731
|
-
await this._updateNode(after);
|
|
3732
|
-
await this._insertInParent(before, after.values[0], after);
|
|
3733
|
-
}
|
|
4813
|
+
await insertOpAsync(this._ops, this._ctx, key, value, this.comparator);
|
|
3734
4814
|
});
|
|
3735
4815
|
}
|
|
3736
4816
|
async batchInsert(entries) {
|
|
3737
4817
|
if (entries.length === 0) return;
|
|
3738
4818
|
return this.writeLock(0, async () => {
|
|
3739
|
-
|
|
3740
|
-
let currentLeaf = null;
|
|
3741
|
-
let modified = false;
|
|
3742
|
-
let cachedLeafId = null;
|
|
3743
|
-
let cachedLeafMaxValue = null;
|
|
3744
|
-
for (let i = 0, len = sorted.length; i < len; i++) {
|
|
3745
|
-
const [key, value] = sorted[i];
|
|
3746
|
-
let targetLeaf;
|
|
3747
|
-
if (cachedLeafId !== null && cachedLeafMaxValue !== null && currentLeaf !== null && (this.comparator.isLower(value, cachedLeafMaxValue) || this.comparator.isSame(value, cachedLeafMaxValue))) {
|
|
3748
|
-
targetLeaf = currentLeaf;
|
|
3749
|
-
} else {
|
|
3750
|
-
targetLeaf = await this.locateLeaf(value);
|
|
3751
|
-
}
|
|
3752
|
-
if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
|
|
3753
|
-
} else {
|
|
3754
|
-
if (currentLeaf !== null && modified) {
|
|
3755
|
-
await this._updateNode(currentLeaf);
|
|
3756
|
-
}
|
|
3757
|
-
currentLeaf = this._cloneNode(targetLeaf);
|
|
3758
|
-
modified = false;
|
|
3759
|
-
}
|
|
3760
|
-
cachedLeafId = currentLeaf.id;
|
|
3761
|
-
const changed = this._insertValueIntoLeaf(currentLeaf, key, value);
|
|
3762
|
-
modified = modified || changed;
|
|
3763
|
-
cachedLeafMaxValue = currentLeaf.values[currentLeaf.values.length - 1];
|
|
3764
|
-
if (currentLeaf.values.length === this.order) {
|
|
3765
|
-
await this._updateNode(currentLeaf);
|
|
3766
|
-
let after = await this._createNode(
|
|
3767
|
-
true,
|
|
3768
|
-
[],
|
|
3769
|
-
[],
|
|
3770
|
-
currentLeaf.parent,
|
|
3771
|
-
null,
|
|
3772
|
-
null
|
|
3773
|
-
);
|
|
3774
|
-
const mid = Math.ceil(this.order / 2) - 1;
|
|
3775
|
-
after = this._cloneNode(after);
|
|
3776
|
-
after.values = currentLeaf.values.slice(mid + 1);
|
|
3777
|
-
after.keys = currentLeaf.keys.slice(mid + 1);
|
|
3778
|
-
currentLeaf.values = currentLeaf.values.slice(0, mid + 1);
|
|
3779
|
-
currentLeaf.keys = currentLeaf.keys.slice(0, mid + 1);
|
|
3780
|
-
await this._updateNode(currentLeaf);
|
|
3781
|
-
await this._updateNode(after);
|
|
3782
|
-
await this._insertInParent(currentLeaf, after.values[0], after);
|
|
3783
|
-
currentLeaf = null;
|
|
3784
|
-
cachedLeafId = null;
|
|
3785
|
-
cachedLeafMaxValue = null;
|
|
3786
|
-
modified = false;
|
|
3787
|
-
}
|
|
3788
|
-
}
|
|
3789
|
-
if (currentLeaf !== null && modified) {
|
|
3790
|
-
await this._updateNode(currentLeaf);
|
|
3791
|
-
}
|
|
4819
|
+
await batchInsertOpAsync(this._ops, this._ctx, entries, this.comparator);
|
|
3792
4820
|
});
|
|
3793
4821
|
}
|
|
3794
4822
|
async bulkLoad(entries) {
|
|
3795
4823
|
if (entries.length === 0) return;
|
|
3796
4824
|
return this.writeLock(0, async () => {
|
|
3797
|
-
|
|
3798
|
-
if (!root.leaf || root.values.length > 0) {
|
|
3799
|
-
throw new Error("bulkLoad can only be called on an empty tree. Use batchInsert for non-empty trees.");
|
|
3800
|
-
}
|
|
3801
|
-
const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
|
|
3802
|
-
const grouped = [];
|
|
3803
|
-
for (let i = 0, len = sorted.length; i < len; i++) {
|
|
3804
|
-
const [key, value] = sorted[i];
|
|
3805
|
-
const last = grouped[grouped.length - 1];
|
|
3806
|
-
if (last && this.comparator.isSame(last.value, value)) {
|
|
3807
|
-
if (!last.keys.includes(key)) {
|
|
3808
|
-
last.keys.push(key);
|
|
3809
|
-
}
|
|
3810
|
-
} else {
|
|
3811
|
-
grouped.push({ keys: [key], value });
|
|
3812
|
-
}
|
|
3813
|
-
}
|
|
3814
|
-
await this._deleteNode(root);
|
|
3815
|
-
const maxLeafSize = this.order - 1;
|
|
3816
|
-
const leaves = [];
|
|
3817
|
-
for (let i = 0, len = grouped.length; i < len; i += maxLeafSize) {
|
|
3818
|
-
const chunk = grouped.slice(i, i + maxLeafSize);
|
|
3819
|
-
const leafKeys = chunk.map((g) => g.keys);
|
|
3820
|
-
const leafValues = chunk.map((g) => g.value);
|
|
3821
|
-
const leaf = await this._createNode(
|
|
3822
|
-
true,
|
|
3823
|
-
leafKeys,
|
|
3824
|
-
leafValues,
|
|
3825
|
-
null,
|
|
3826
|
-
null,
|
|
3827
|
-
null
|
|
3828
|
-
);
|
|
3829
|
-
leaves.push(leaf);
|
|
3830
|
-
}
|
|
3831
|
-
for (let i = 0, len = leaves.length; i < len; i++) {
|
|
3832
|
-
if (i > 0) {
|
|
3833
|
-
leaves[i].prev = leaves[i - 1].id;
|
|
3834
|
-
}
|
|
3835
|
-
if (i < len - 1) {
|
|
3836
|
-
leaves[i].next = leaves[i + 1].id;
|
|
3837
|
-
}
|
|
3838
|
-
await this._updateNode(leaves[i]);
|
|
3839
|
-
}
|
|
3840
|
-
let currentLevel = leaves;
|
|
3841
|
-
while (currentLevel.length > 1) {
|
|
3842
|
-
const nextLevel = [];
|
|
3843
|
-
for (let i = 0, len = currentLevel.length; i < len; i += this.order) {
|
|
3844
|
-
const children = currentLevel.slice(i, i + this.order);
|
|
3845
|
-
const childIds = children.map((c) => c.id);
|
|
3846
|
-
const separators = [];
|
|
3847
|
-
for (let j = 1, len2 = children.length; j < len2; j++) {
|
|
3848
|
-
separators.push(children[j].values[0]);
|
|
3849
|
-
}
|
|
3850
|
-
const internalNode = await this._createNode(
|
|
3851
|
-
false,
|
|
3852
|
-
childIds,
|
|
3853
|
-
separators,
|
|
3854
|
-
null,
|
|
3855
|
-
null,
|
|
3856
|
-
null
|
|
3857
|
-
);
|
|
3858
|
-
for (let j = 0, len2 = children.length; j < len2; j++) {
|
|
3859
|
-
const child = children[j];
|
|
3860
|
-
child.parent = internalNode.id;
|
|
3861
|
-
await this._updateNode(child);
|
|
3862
|
-
}
|
|
3863
|
-
nextLevel.push(internalNode);
|
|
3864
|
-
}
|
|
3865
|
-
currentLevel = nextLevel;
|
|
3866
|
-
}
|
|
3867
|
-
const newRoot = currentLevel[0];
|
|
3868
|
-
await this._writeHead({
|
|
3869
|
-
root: newRoot.id,
|
|
3870
|
-
order: this.order,
|
|
3871
|
-
data: this.strategy.head.data
|
|
3872
|
-
});
|
|
4825
|
+
await bulkLoadOpAsync(this._ops, this._ctx, entries, this.comparator);
|
|
3873
4826
|
});
|
|
3874
4827
|
}
|
|
3875
4828
|
async _deleteEntry(node, key) {
|
|
3876
|
-
|
|
3877
|
-
let keyIndex = -1;
|
|
3878
|
-
for (let i = 0, len = node.keys.length; i < len; i++) {
|
|
3879
|
-
if (node.keys[i] === key) {
|
|
3880
|
-
keyIndex = i;
|
|
3881
|
-
break;
|
|
3882
|
-
}
|
|
3883
|
-
}
|
|
3884
|
-
if (keyIndex !== -1) {
|
|
3885
|
-
node = this._cloneNode(node);
|
|
3886
|
-
node.keys.splice(keyIndex, 1);
|
|
3887
|
-
const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
|
|
3888
|
-
node.values.splice(valueIndex, 1);
|
|
3889
|
-
await this._updateNode(node);
|
|
3890
|
-
}
|
|
3891
|
-
}
|
|
3892
|
-
if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
|
|
3893
|
-
const keys = node.keys;
|
|
3894
|
-
this._deleteNode(node);
|
|
3895
|
-
const newRoot = this._cloneNode(await this.getNode(keys[0]));
|
|
3896
|
-
newRoot.parent = null;
|
|
3897
|
-
await this._updateNode(newRoot);
|
|
3898
|
-
await this._writeHead({
|
|
3899
|
-
root: newRoot.id,
|
|
3900
|
-
order: this.order,
|
|
3901
|
-
data: this.strategy.head.data
|
|
3902
|
-
});
|
|
3903
|
-
return node;
|
|
3904
|
-
} else if (this.rootId === node.id) {
|
|
3905
|
-
await this._writeHead({
|
|
3906
|
-
root: node.id,
|
|
3907
|
-
order: this.order,
|
|
3908
|
-
data: this.strategy.head.data
|
|
3909
|
-
});
|
|
3910
|
-
return node;
|
|
3911
|
-
} else if (node.keys.length < Math.ceil(this.order / 2) && !node.leaf || node.values.length < Math.ceil((this.order - 1) / 2) && node.leaf) {
|
|
3912
|
-
if (node.parent === null) {
|
|
3913
|
-
return node;
|
|
3914
|
-
}
|
|
3915
|
-
let isPredecessor = false;
|
|
3916
|
-
let parentNode = await this.getNode(node.parent);
|
|
3917
|
-
let prevNode = null;
|
|
3918
|
-
let nextNode = null;
|
|
3919
|
-
let prevValue = null;
|
|
3920
|
-
let postValue = null;
|
|
3921
|
-
for (let i = 0, len = parentNode.keys.length; i < len; i++) {
|
|
3922
|
-
const nKey = parentNode.keys[i];
|
|
3923
|
-
if (nKey === node.id) {
|
|
3924
|
-
if (i > 0) {
|
|
3925
|
-
prevNode = await this.getNode(parentNode.keys[i - 1]);
|
|
3926
|
-
prevValue = parentNode.values[i - 1];
|
|
3927
|
-
}
|
|
3928
|
-
if (i < parentNode.keys.length - 1) {
|
|
3929
|
-
nextNode = await this.getNode(parentNode.keys[i + 1]);
|
|
3930
|
-
postValue = parentNode.values[i];
|
|
3931
|
-
}
|
|
3932
|
-
}
|
|
3933
|
-
}
|
|
3934
|
-
let siblingNode;
|
|
3935
|
-
let guess;
|
|
3936
|
-
if (prevNode === null) {
|
|
3937
|
-
siblingNode = nextNode;
|
|
3938
|
-
guess = postValue;
|
|
3939
|
-
} else if (nextNode === null) {
|
|
3940
|
-
isPredecessor = true;
|
|
3941
|
-
siblingNode = prevNode;
|
|
3942
|
-
guess = prevValue;
|
|
3943
|
-
} else {
|
|
3944
|
-
if (node.values.length + nextNode.values.length < this.order) {
|
|
3945
|
-
siblingNode = nextNode;
|
|
3946
|
-
guess = postValue;
|
|
3947
|
-
} else {
|
|
3948
|
-
isPredecessor = true;
|
|
3949
|
-
siblingNode = prevNode;
|
|
3950
|
-
guess = prevValue;
|
|
3951
|
-
}
|
|
3952
|
-
}
|
|
3953
|
-
if (!siblingNode) {
|
|
3954
|
-
return node;
|
|
3955
|
-
}
|
|
3956
|
-
node = this._cloneNode(node);
|
|
3957
|
-
siblingNode = this._cloneNode(siblingNode);
|
|
3958
|
-
if (node.values.length + siblingNode.values.length < this.order) {
|
|
3959
|
-
if (!isPredecessor) {
|
|
3960
|
-
const pTemp = siblingNode;
|
|
3961
|
-
siblingNode = node;
|
|
3962
|
-
node = pTemp;
|
|
3963
|
-
}
|
|
3964
|
-
siblingNode.keys.push(...node.keys);
|
|
3965
|
-
if (!node.leaf) {
|
|
3966
|
-
siblingNode.values.push(guess);
|
|
3967
|
-
} else {
|
|
3968
|
-
siblingNode.next = node.next;
|
|
3969
|
-
if (siblingNode.next) {
|
|
3970
|
-
const n = this._cloneNode(await this.getNode(siblingNode.next));
|
|
3971
|
-
n.prev = siblingNode.id;
|
|
3972
|
-
await this._updateNode(n);
|
|
3973
|
-
}
|
|
3974
|
-
}
|
|
3975
|
-
siblingNode.values.push(...node.values);
|
|
3976
|
-
if (!siblingNode.leaf) {
|
|
3977
|
-
const keys = siblingNode.keys;
|
|
3978
|
-
for (let i = 0, len = keys.length; i < len; i++) {
|
|
3979
|
-
const key2 = keys[i];
|
|
3980
|
-
const node2 = this._cloneNode(await this.getNode(key2));
|
|
3981
|
-
node2.parent = siblingNode.id;
|
|
3982
|
-
await this._updateNode(node2);
|
|
3983
|
-
}
|
|
3984
|
-
}
|
|
3985
|
-
this._deleteNode(node);
|
|
3986
|
-
await this._updateNode(siblingNode);
|
|
3987
|
-
await this._deleteEntry(await this.getNode(node.parent), node.id);
|
|
3988
|
-
} else {
|
|
3989
|
-
if (isPredecessor) {
|
|
3990
|
-
let pointerPm;
|
|
3991
|
-
let pointerKm;
|
|
3992
|
-
if (!node.leaf) {
|
|
3993
|
-
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
3994
|
-
pointerKm = siblingNode.values.splice(-1)[0];
|
|
3995
|
-
node.keys = [pointerPm, ...node.keys];
|
|
3996
|
-
node.values = [guess, ...node.values];
|
|
3997
|
-
parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
3998
|
-
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
3999
|
-
if (nodeIndex > 0) {
|
|
4000
|
-
parentNode.values[nodeIndex - 1] = pointerKm;
|
|
4001
|
-
await this._updateNode(parentNode);
|
|
4002
|
-
}
|
|
4003
|
-
} else {
|
|
4004
|
-
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
4005
|
-
pointerKm = siblingNode.values.splice(-1)[0];
|
|
4006
|
-
node.keys = [pointerPm, ...node.keys];
|
|
4007
|
-
node.values = [pointerKm, ...node.values];
|
|
4008
|
-
parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
4009
|
-
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
4010
|
-
if (nodeIndex > 0) {
|
|
4011
|
-
parentNode.values[nodeIndex - 1] = pointerKm;
|
|
4012
|
-
await this._updateNode(parentNode);
|
|
4013
|
-
}
|
|
4014
|
-
}
|
|
4015
|
-
await this._updateNode(node);
|
|
4016
|
-
await this._updateNode(siblingNode);
|
|
4017
|
-
} else {
|
|
4018
|
-
let pointerP0;
|
|
4019
|
-
let pointerK0;
|
|
4020
|
-
if (!node.leaf) {
|
|
4021
|
-
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
4022
|
-
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
4023
|
-
node.keys = [...node.keys, pointerP0];
|
|
4024
|
-
node.values = [...node.values, guess];
|
|
4025
|
-
parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
4026
|
-
const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
|
|
4027
|
-
if (pointerIndex > 0) {
|
|
4028
|
-
parentNode.values[pointerIndex - 1] = pointerK0;
|
|
4029
|
-
await this._updateNode(parentNode);
|
|
4030
|
-
}
|
|
4031
|
-
} else {
|
|
4032
|
-
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
4033
|
-
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
4034
|
-
node.keys = [...node.keys, pointerP0];
|
|
4035
|
-
node.values = [...node.values, pointerK0];
|
|
4036
|
-
parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
4037
|
-
const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
|
|
4038
|
-
if (pointerIndex > 0) {
|
|
4039
|
-
parentNode.values[pointerIndex - 1] = siblingNode.values[0];
|
|
4040
|
-
await this._updateNode(parentNode);
|
|
4041
|
-
}
|
|
4042
|
-
}
|
|
4043
|
-
await this._updateNode(node);
|
|
4044
|
-
await this._updateNode(siblingNode);
|
|
4045
|
-
}
|
|
4046
|
-
if (!siblingNode.leaf) {
|
|
4047
|
-
for (let i = 0, len = siblingNode.keys.length; i < len; i++) {
|
|
4048
|
-
const key2 = siblingNode.keys[i];
|
|
4049
|
-
const n = this._cloneNode(await this.getNode(key2));
|
|
4050
|
-
n.parent = siblingNode.id;
|
|
4051
|
-
await this._updateNode(n);
|
|
4052
|
-
}
|
|
4053
|
-
}
|
|
4054
|
-
if (!node.leaf) {
|
|
4055
|
-
for (let i = 0, len = node.keys.length; i < len; i++) {
|
|
4056
|
-
const key2 = node.keys[i];
|
|
4057
|
-
const n = this._cloneNode(await this.getNode(key2));
|
|
4058
|
-
n.parent = node.id;
|
|
4059
|
-
await this._updateNode(n);
|
|
4060
|
-
}
|
|
4061
|
-
}
|
|
4062
|
-
if (!parentNode.leaf) {
|
|
4063
|
-
for (let i = 0, len = parentNode.keys.length; i < len; i++) {
|
|
4064
|
-
const key2 = parentNode.keys[i];
|
|
4065
|
-
const n = this._cloneNode(await this.getNode(key2));
|
|
4066
|
-
n.parent = parentNode.id;
|
|
4067
|
-
await this._updateNode(n);
|
|
4068
|
-
}
|
|
4069
|
-
}
|
|
4070
|
-
}
|
|
4071
|
-
} else {
|
|
4072
|
-
await this._updateNode(this._cloneNode(node));
|
|
4073
|
-
}
|
|
4074
|
-
return node;
|
|
4829
|
+
return deleteEntryAsync(this._ops, this._ctx, node, key, this.comparator);
|
|
4075
4830
|
}
|
|
4076
4831
|
async delete(key, value) {
|
|
4077
4832
|
return this.writeLock(0, async () => {
|
|
4078
|
-
|
|
4079
|
-
value = await this.get(key);
|
|
4080
|
-
}
|
|
4081
|
-
if (value === void 0) {
|
|
4082
|
-
return;
|
|
4083
|
-
}
|
|
4084
|
-
let node = await this.findLowerBoundLeaf(value);
|
|
4085
|
-
let found = false;
|
|
4086
|
-
while (true) {
|
|
4087
|
-
let i = node.values.length;
|
|
4088
|
-
while (i--) {
|
|
4089
|
-
const nValue = node.values[i];
|
|
4090
|
-
if (this.comparator.isSame(value, nValue)) {
|
|
4091
|
-
const keys = node.keys[i];
|
|
4092
|
-
const keyIndex = keys.indexOf(key);
|
|
4093
|
-
if (keyIndex !== -1) {
|
|
4094
|
-
node = this._cloneNode(node);
|
|
4095
|
-
const freshKeys = node.keys[i];
|
|
4096
|
-
freshKeys.splice(keyIndex, 1);
|
|
4097
|
-
if (freshKeys.length === 0) {
|
|
4098
|
-
node.keys.splice(i, 1);
|
|
4099
|
-
node.values.splice(i, 1);
|
|
4100
|
-
}
|
|
4101
|
-
await this._updateNode(node);
|
|
4102
|
-
node = await this._deleteEntry(node, key);
|
|
4103
|
-
found = true;
|
|
4104
|
-
break;
|
|
4105
|
-
}
|
|
4106
|
-
}
|
|
4107
|
-
}
|
|
4108
|
-
if (found) break;
|
|
4109
|
-
if (node.next) {
|
|
4110
|
-
node = await this.getNode(node.next);
|
|
4111
|
-
continue;
|
|
4112
|
-
}
|
|
4113
|
-
break;
|
|
4114
|
-
}
|
|
4833
|
+
await deleteOpAsync(this._ops, this._ctx, key, this.comparator, value);
|
|
4115
4834
|
});
|
|
4116
4835
|
}
|
|
4836
|
+
// ─── Head Data ───────────────────────────────────────────────────
|
|
4117
4837
|
async getHeadData() {
|
|
4118
4838
|
const head = await this._readHead();
|
|
4119
4839
|
if (head === null) {
|
|
@@ -4132,6 +4852,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
4132
4852
|
data
|
|
4133
4853
|
});
|
|
4134
4854
|
}
|
|
4855
|
+
// ─── Transaction ─────────────────────────────────────────────────
|
|
4135
4856
|
async commit(label) {
|
|
4136
4857
|
let result = await this.mvcc.commit(label);
|
|
4137
4858
|
if (result.success) {
|
|
@@ -4263,6 +4984,327 @@ var BPTreeAsync = class extends BPTreeAsyncTransaction {
|
|
|
4263
4984
|
}
|
|
4264
4985
|
};
|
|
4265
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
|
+
|
|
4266
5308
|
// src/base/SerializeStrategy.ts
|
|
4267
5309
|
var SerializeStrategy = class {
|
|
4268
5310
|
order;
|