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