serializable-bptree 8.4.2 → 9.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2
- package/dist/cjs/index.cjs +2843 -1661
- package/dist/esm/index.mjs +2843 -1661
- package/dist/types/BPTreePureAsync.d.ts +38 -0
- package/dist/types/BPTreePureSync.d.ts +44 -0
- package/dist/types/base/BPTreeAlgorithmAsync.d.ts +33 -0
- package/dist/types/base/BPTreeAlgorithmSync.d.ts +47 -0
- package/dist/types/base/BPTreeNodeOps.d.ts +34 -0
- package/dist/types/base/BPTreeTransaction.d.ts +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/transaction/BPTreeAsyncTransaction.d.ts +8 -5
- package/dist/types/transaction/BPTreeSyncTransaction.d.ts +8 -5
- package/package.json +2 -2
package/dist/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,84 +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
|
-
|
|
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)),
|
|
1561
1612
|
like: (nv, v) => {
|
|
1562
|
-
const nodeValue =
|
|
1613
|
+
const nodeValue = comparator.match(nv);
|
|
1563
1614
|
const value = v;
|
|
1564
|
-
if (!
|
|
1615
|
+
if (!cachedRegexp.has(value)) {
|
|
1565
1616
|
const pattern = value.replace(/%/g, ".*").replace(/_/g, ".");
|
|
1566
1617
|
const regexp2 = new RegExp(`^${pattern}$`, "i");
|
|
1567
|
-
|
|
1618
|
+
cachedRegexp.set(value, regexp2);
|
|
1568
1619
|
}
|
|
1569
|
-
const regexp =
|
|
1620
|
+
const regexp = cachedRegexp.get(value);
|
|
1570
1621
|
return regexp.test(nodeValue);
|
|
1571
1622
|
}
|
|
1572
1623
|
};
|
|
1573
|
-
|
|
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 {
|
|
1574
1631
|
gt: {
|
|
1575
1632
|
asc: {
|
|
1576
|
-
start: (
|
|
1633
|
+
start: (r, ops, v) => findUpperBoundLeaf(ops, r, v[0], comparator),
|
|
1577
1634
|
end: () => null,
|
|
1578
1635
|
direction: 1,
|
|
1579
1636
|
earlyTerminate: false
|
|
1580
1637
|
},
|
|
1581
1638
|
desc: {
|
|
1582
|
-
start: (
|
|
1583
|
-
end: (
|
|
1639
|
+
start: (r, ops) => rightestNode(ops, r),
|
|
1640
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], -1, comparator),
|
|
1584
1641
|
direction: -1,
|
|
1585
1642
|
earlyTerminate: true
|
|
1586
1643
|
}
|
|
1587
1644
|
},
|
|
1588
1645
|
gte: {
|
|
1589
1646
|
asc: {
|
|
1590
|
-
start: (
|
|
1647
|
+
start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
|
|
1591
1648
|
end: () => null,
|
|
1592
1649
|
direction: 1,
|
|
1593
1650
|
earlyTerminate: false
|
|
1594
1651
|
},
|
|
1595
1652
|
desc: {
|
|
1596
|
-
start: (
|
|
1597
|
-
end: (
|
|
1653
|
+
start: (r, ops) => rightestNode(ops, r),
|
|
1654
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], -1, comparator),
|
|
1598
1655
|
direction: -1,
|
|
1599
1656
|
earlyTerminate: true
|
|
1600
1657
|
}
|
|
1601
1658
|
},
|
|
1602
1659
|
lt: {
|
|
1603
1660
|
asc: {
|
|
1604
|
-
start: (
|
|
1605
|
-
end: (
|
|
1661
|
+
start: (r, ops) => leftestNode(ops, r),
|
|
1662
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
|
|
1606
1663
|
direction: 1,
|
|
1607
1664
|
earlyTerminate: true
|
|
1608
1665
|
},
|
|
1609
1666
|
desc: {
|
|
1610
|
-
start: (
|
|
1667
|
+
start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
|
|
1611
1668
|
end: () => null,
|
|
1612
1669
|
direction: -1,
|
|
1613
1670
|
earlyTerminate: false
|
|
@@ -1615,13 +1672,13 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1615
1672
|
},
|
|
1616
1673
|
lte: {
|
|
1617
1674
|
asc: {
|
|
1618
|
-
start: (
|
|
1619
|
-
end: (
|
|
1675
|
+
start: (r, ops) => leftestNode(ops, r),
|
|
1676
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
|
|
1620
1677
|
direction: 1,
|
|
1621
1678
|
earlyTerminate: true
|
|
1622
1679
|
},
|
|
1623
1680
|
desc: {
|
|
1624
|
-
start: (
|
|
1681
|
+
start: (r, ops, v) => findUpperBoundLeaf(ops, r, v[0], comparator),
|
|
1625
1682
|
end: () => null,
|
|
1626
1683
|
direction: -1,
|
|
1627
1684
|
earlyTerminate: false
|
|
@@ -1629,27 +1686,27 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1629
1686
|
},
|
|
1630
1687
|
equal: {
|
|
1631
1688
|
asc: {
|
|
1632
|
-
start: (
|
|
1633
|
-
end: (
|
|
1689
|
+
start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
|
|
1690
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
|
|
1634
1691
|
direction: 1,
|
|
1635
1692
|
earlyTerminate: true
|
|
1636
1693
|
},
|
|
1637
1694
|
desc: {
|
|
1638
|
-
start: (
|
|
1639
|
-
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),
|
|
1640
1697
|
direction: -1,
|
|
1641
1698
|
earlyTerminate: true
|
|
1642
1699
|
}
|
|
1643
1700
|
},
|
|
1644
1701
|
notEqual: {
|
|
1645
1702
|
asc: {
|
|
1646
|
-
start: (
|
|
1703
|
+
start: (r, ops) => leftestNode(ops, r),
|
|
1647
1704
|
end: () => null,
|
|
1648
1705
|
direction: 1,
|
|
1649
1706
|
earlyTerminate: false
|
|
1650
1707
|
},
|
|
1651
1708
|
desc: {
|
|
1652
|
-
start: (
|
|
1709
|
+
start: (r, ops) => rightestNode(ops, r),
|
|
1653
1710
|
end: () => null,
|
|
1654
1711
|
direction: -1,
|
|
1655
1712
|
earlyTerminate: false
|
|
@@ -1657,55 +1714,55 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1657
1714
|
},
|
|
1658
1715
|
or: {
|
|
1659
1716
|
asc: {
|
|
1660
|
-
start: (
|
|
1661
|
-
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),
|
|
1662
1719
|
direction: 1,
|
|
1663
1720
|
earlyTerminate: false
|
|
1664
1721
|
},
|
|
1665
1722
|
desc: {
|
|
1666
|
-
start: (
|
|
1667
|
-
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),
|
|
1668
1725
|
direction: -1,
|
|
1669
1726
|
earlyTerminate: false
|
|
1670
1727
|
}
|
|
1671
1728
|
},
|
|
1672
1729
|
primaryGt: {
|
|
1673
1730
|
asc: {
|
|
1674
|
-
start: (
|
|
1731
|
+
start: (r, ops, v) => findUpperBoundLeaf(ops, r, v[0], comparator),
|
|
1675
1732
|
end: () => null,
|
|
1676
1733
|
direction: 1,
|
|
1677
1734
|
earlyTerminate: false
|
|
1678
1735
|
},
|
|
1679
1736
|
desc: {
|
|
1680
|
-
start: (
|
|
1681
|
-
end: (
|
|
1737
|
+
start: (r, ops) => rightestNode(ops, r),
|
|
1738
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], -1, comparator),
|
|
1682
1739
|
direction: -1,
|
|
1683
1740
|
earlyTerminate: true
|
|
1684
1741
|
}
|
|
1685
1742
|
},
|
|
1686
1743
|
primaryGte: {
|
|
1687
1744
|
asc: {
|
|
1688
|
-
start: (
|
|
1745
|
+
start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
|
|
1689
1746
|
end: () => null,
|
|
1690
1747
|
direction: 1,
|
|
1691
1748
|
earlyTerminate: false
|
|
1692
1749
|
},
|
|
1693
1750
|
desc: {
|
|
1694
|
-
start: (
|
|
1695
|
-
end: (
|
|
1751
|
+
start: (r, ops) => rightestNode(ops, r),
|
|
1752
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], -1, comparator),
|
|
1696
1753
|
direction: -1,
|
|
1697
1754
|
earlyTerminate: true
|
|
1698
1755
|
}
|
|
1699
1756
|
},
|
|
1700
1757
|
primaryLt: {
|
|
1701
1758
|
asc: {
|
|
1702
|
-
start: (
|
|
1703
|
-
end: (
|
|
1759
|
+
start: (r, ops) => leftestNode(ops, r),
|
|
1760
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
|
|
1704
1761
|
direction: 1,
|
|
1705
1762
|
earlyTerminate: true
|
|
1706
1763
|
},
|
|
1707
1764
|
desc: {
|
|
1708
|
-
start: (
|
|
1765
|
+
start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
|
|
1709
1766
|
end: () => null,
|
|
1710
1767
|
direction: -1,
|
|
1711
1768
|
earlyTerminate: false
|
|
@@ -1713,13 +1770,13 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1713
1770
|
},
|
|
1714
1771
|
primaryLte: {
|
|
1715
1772
|
asc: {
|
|
1716
|
-
start: (
|
|
1717
|
-
end: (
|
|
1773
|
+
start: (r, ops) => leftestNode(ops, r),
|
|
1774
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
|
|
1718
1775
|
direction: 1,
|
|
1719
1776
|
earlyTerminate: true
|
|
1720
1777
|
},
|
|
1721
1778
|
desc: {
|
|
1722
|
-
start: (
|
|
1779
|
+
start: (r, ops, v) => findUpperBoundLeaf(ops, r, v[0], comparator),
|
|
1723
1780
|
end: () => null,
|
|
1724
1781
|
direction: -1,
|
|
1725
1782
|
earlyTerminate: false
|
|
@@ -1727,27 +1784,27 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1727
1784
|
},
|
|
1728
1785
|
primaryEqual: {
|
|
1729
1786
|
asc: {
|
|
1730
|
-
start: (
|
|
1731
|
-
end: (
|
|
1787
|
+
start: (r, ops, v) => findLowerBoundLeaf(ops, r, v[0], comparator),
|
|
1788
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], 1, comparator),
|
|
1732
1789
|
direction: 1,
|
|
1733
1790
|
earlyTerminate: true
|
|
1734
1791
|
},
|
|
1735
1792
|
desc: {
|
|
1736
|
-
start: (
|
|
1737
|
-
end: (
|
|
1793
|
+
start: (r, ops, v) => findUpperBoundLeaf(ops, r, v[0], comparator),
|
|
1794
|
+
end: (r, ops, v) => findOuterBoundaryLeaf(ops, r, v[0], -1, comparator),
|
|
1738
1795
|
direction: -1,
|
|
1739
1796
|
earlyTerminate: true
|
|
1740
1797
|
}
|
|
1741
1798
|
},
|
|
1742
1799
|
primaryNotEqual: {
|
|
1743
1800
|
asc: {
|
|
1744
|
-
start: (
|
|
1801
|
+
start: (r, ops) => leftestNode(ops, r),
|
|
1745
1802
|
end: () => null,
|
|
1746
1803
|
direction: 1,
|
|
1747
1804
|
earlyTerminate: false
|
|
1748
1805
|
},
|
|
1749
1806
|
desc: {
|
|
1750
|
-
start: (
|
|
1807
|
+
start: (r, ops) => rightestNode(ops, r),
|
|
1751
1808
|
end: () => null,
|
|
1752
1809
|
direction: -1,
|
|
1753
1810
|
earlyTerminate: false
|
|
@@ -1755,176 +1812,1186 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
1755
1812
|
},
|
|
1756
1813
|
primaryOr: {
|
|
1757
1814
|
asc: {
|
|
1758
|
-
start: (
|
|
1759
|
-
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),
|
|
1760
1817
|
direction: 1,
|
|
1761
1818
|
earlyTerminate: false
|
|
1762
1819
|
},
|
|
1763
1820
|
desc: {
|
|
1764
|
-
start: (
|
|
1765
|
-
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),
|
|
1766
1823
|
direction: -1,
|
|
1767
1824
|
earlyTerminate: false
|
|
1768
1825
|
}
|
|
1769
1826
|
},
|
|
1770
1827
|
like: {
|
|
1771
1828
|
asc: {
|
|
1772
|
-
start: (
|
|
1829
|
+
start: (r, ops) => leftestNode(ops, r),
|
|
1773
1830
|
end: () => null,
|
|
1774
1831
|
direction: 1,
|
|
1775
1832
|
earlyTerminate: false
|
|
1776
1833
|
},
|
|
1777
1834
|
desc: {
|
|
1778
|
-
start: (
|
|
1835
|
+
start: (r, ops) => rightestNode(ops, r),
|
|
1779
1836
|
end: () => null,
|
|
1780
1837
|
direction: -1,
|
|
1781
1838
|
earlyTerminate: false
|
|
1782
1839
|
}
|
|
1783
1840
|
}
|
|
1784
1841
|
};
|
|
1785
|
-
|
|
1786
|
-
|
|
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
|
-
if (candidates.length === 0) return null;
|
|
1825
|
-
if (candidates.length === 1) return candidates[0];
|
|
1826
|
-
let best = candidates[0];
|
|
1827
|
-
let bestScore = 0;
|
|
1828
|
-
for (const candidate of candidates) {
|
|
1829
|
-
let score = 0;
|
|
1830
|
-
for (const key in candidate.condition) {
|
|
1831
|
-
const condKey = key;
|
|
1832
|
-
const priority = _BPTreeTransaction.conditionPriority[condKey] ?? 0;
|
|
1833
|
-
if (priority > score) {
|
|
1834
|
-
score = priority;
|
|
1835
|
-
}
|
|
1836
|
-
}
|
|
1837
|
-
if (score > bestScore) {
|
|
1838
|
-
bestScore = score;
|
|
1839
|
-
best = candidate;
|
|
1840
|
-
}
|
|
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;
|
|
1841
1881
|
}
|
|
1842
|
-
return best;
|
|
1843
1882
|
}
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
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
|
+
}
|
|
1852
1890
|
}
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
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
|
+
}
|
|
1859
1900
|
}
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
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}`);
|
|
1866
1939
|
}
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
* @param nodeValue The value to verify.
|
|
1871
|
-
* @param condition The condition to verify against.
|
|
1872
|
-
* @returns Returns true if the value satisfies the condition.
|
|
1873
|
-
*/
|
|
1874
|
-
verify(nodeValue, condition) {
|
|
1875
|
-
for (const key in condition) {
|
|
1876
|
-
const verify = this.verifierMap[key];
|
|
1877
|
-
const condValue = condition[key];
|
|
1878
|
-
if (!verify(nodeValue, condValue)) {
|
|
1879
|
-
return false;
|
|
1880
|
-
}
|
|
1881
|
-
}
|
|
1882
|
-
return true;
|
|
1940
|
+
const guessNode = insertableNode[key];
|
|
1941
|
+
if (!guessNode) {
|
|
1942
|
+
return null;
|
|
1883
1943
|
}
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
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];
|
|
1896
1975
|
}
|
|
1897
|
-
leaf.keys[index].push(key);
|
|
1898
|
-
return true;
|
|
1899
1976
|
}
|
|
1900
|
-
leaf.values.splice(index, 0, value);
|
|
1901
|
-
leaf.keys.splice(index, 0, [key]);
|
|
1902
|
-
return true;
|
|
1903
1977
|
} else {
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
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
|
+
}
|
|
1907
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;
|
|
1908
2031
|
}
|
|
1909
|
-
|
|
1910
|
-
|
|
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
|
+
}
|
|
1911
2138
|
}
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
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 = [];
|
|
1928
2995
|
let endValues = [];
|
|
1929
2996
|
for (let i = 0, len = startCandidates.length; i < len; i++) {
|
|
1930
2997
|
const key = startCandidates[i];
|
|
@@ -2059,6 +3126,10 @@ var BPTreeTransaction = class _BPTreeTransaction {
|
|
|
2059
3126
|
|
|
2060
3127
|
// src/transaction/BPTreeSyncTransaction.ts
|
|
2061
3128
|
var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
3129
|
+
_ops;
|
|
3130
|
+
_ctx;
|
|
3131
|
+
_verifierMapCached;
|
|
3132
|
+
_searchConfigsCached;
|
|
2062
3133
|
constructor(rootTx, mvccRoot, mvcc, strategy, comparator, option) {
|
|
2063
3134
|
super(
|
|
2064
3135
|
rootTx,
|
|
@@ -2068,248 +3139,113 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2068
3139
|
comparator,
|
|
2069
3140
|
option
|
|
2070
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);
|
|
2071
3200
|
}
|
|
3201
|
+
// ─── Legacy protected methods (delegating to ops) ────────────────
|
|
2072
3202
|
getNode(id) {
|
|
2073
|
-
return this.
|
|
3203
|
+
return this._ops.getNode(id);
|
|
2074
3204
|
}
|
|
2075
|
-
/**
|
|
2076
|
-
* Create a new node with a unique ID.
|
|
2077
|
-
*/
|
|
2078
3205
|
_createNode(leaf, keys, values, parent = null, next = null, prev = null) {
|
|
2079
|
-
|
|
2080
|
-
const node = {
|
|
2081
|
-
id,
|
|
2082
|
-
keys,
|
|
2083
|
-
values,
|
|
2084
|
-
leaf,
|
|
2085
|
-
parent,
|
|
2086
|
-
next,
|
|
2087
|
-
prev
|
|
2088
|
-
};
|
|
2089
|
-
this.mvcc.create(id, node);
|
|
2090
|
-
return node;
|
|
3206
|
+
return this._ops.createNode(leaf, keys, values, parent, next, prev);
|
|
2091
3207
|
}
|
|
2092
3208
|
_updateNode(node) {
|
|
2093
|
-
|
|
2094
|
-
return;
|
|
2095
|
-
}
|
|
2096
|
-
this.mvcc.write(node.id, node);
|
|
3209
|
+
this._ops.updateNode(node);
|
|
2097
3210
|
}
|
|
2098
3211
|
_deleteNode(node) {
|
|
2099
|
-
|
|
2100
|
-
return;
|
|
2101
|
-
}
|
|
2102
|
-
this.mvcc.delete(node.id);
|
|
3212
|
+
this._ops.deleteNode(node);
|
|
2103
3213
|
}
|
|
2104
3214
|
_readHead() {
|
|
2105
|
-
return this.
|
|
3215
|
+
return this._ops.readHead();
|
|
2106
3216
|
}
|
|
2107
3217
|
_writeHead(head) {
|
|
2108
|
-
|
|
2109
|
-
this.mvcc.create("__HEAD__", head);
|
|
2110
|
-
} else {
|
|
2111
|
-
this.mvcc.write("__HEAD__", head);
|
|
2112
|
-
}
|
|
2113
|
-
this.rootId = head.root;
|
|
3218
|
+
this._ops.writeHead(head);
|
|
2114
3219
|
}
|
|
3220
|
+
// ─── Tree traversal (delegating to algorithm) ────────────────────
|
|
2115
3221
|
_insertAtLeaf(node, key, value) {
|
|
2116
|
-
|
|
2117
|
-
if (leaf.values.length) {
|
|
2118
|
-
for (let i = 0, len = leaf.values.length; i < len; i++) {
|
|
2119
|
-
const nValue = leaf.values[i];
|
|
2120
|
-
if (this.comparator.isSame(value, nValue)) {
|
|
2121
|
-
const keys = leaf.keys[i];
|
|
2122
|
-
if (keys.includes(key)) {
|
|
2123
|
-
break;
|
|
2124
|
-
}
|
|
2125
|
-
leaf = this._cloneNode(leaf);
|
|
2126
|
-
leaf.keys[i].push(key);
|
|
2127
|
-
this._updateNode(leaf);
|
|
2128
|
-
return leaf;
|
|
2129
|
-
} else if (this.comparator.isLower(value, nValue)) {
|
|
2130
|
-
leaf = this._cloneNode(leaf);
|
|
2131
|
-
leaf.values.splice(i, 0, value);
|
|
2132
|
-
leaf.keys.splice(i, 0, [key]);
|
|
2133
|
-
this._updateNode(leaf);
|
|
2134
|
-
return leaf;
|
|
2135
|
-
} else if (i + 1 === leaf.values.length) {
|
|
2136
|
-
leaf = this._cloneNode(leaf);
|
|
2137
|
-
leaf.values.push(value);
|
|
2138
|
-
leaf.keys.push([key]);
|
|
2139
|
-
this._updateNode(leaf);
|
|
2140
|
-
return leaf;
|
|
2141
|
-
}
|
|
2142
|
-
}
|
|
2143
|
-
} else {
|
|
2144
|
-
leaf = this._cloneNode(leaf);
|
|
2145
|
-
leaf.values = [value];
|
|
2146
|
-
leaf.keys = [[key]];
|
|
2147
|
-
this._updateNode(leaf);
|
|
2148
|
-
return leaf;
|
|
2149
|
-
}
|
|
2150
|
-
return leaf;
|
|
3222
|
+
return insertAtLeaf(this._ops, node, key, value, this.comparator);
|
|
2151
3223
|
}
|
|
2152
3224
|
_insertInParent(node, value, newSiblingNode) {
|
|
2153
|
-
|
|
2154
|
-
node = this._cloneNode(node);
|
|
2155
|
-
newSiblingNode = this._cloneNode(newSiblingNode);
|
|
2156
|
-
const root = this._createNode(false, [node.id, newSiblingNode.id], [value]);
|
|
2157
|
-
this.rootId = root.id;
|
|
2158
|
-
node.parent = root.id;
|
|
2159
|
-
newSiblingNode.parent = root.id;
|
|
2160
|
-
if (newSiblingNode.leaf) {
|
|
2161
|
-
node.next = newSiblingNode.id;
|
|
2162
|
-
newSiblingNode.prev = node.id;
|
|
2163
|
-
}
|
|
2164
|
-
this._writeHead({
|
|
2165
|
-
root: root.id,
|
|
2166
|
-
order: this.order,
|
|
2167
|
-
data: this.strategy.head.data
|
|
2168
|
-
});
|
|
2169
|
-
this._updateNode(node);
|
|
2170
|
-
this._updateNode(newSiblingNode);
|
|
2171
|
-
return;
|
|
2172
|
-
}
|
|
2173
|
-
const parentNode = this._cloneNode(this.getNode(node.parent));
|
|
2174
|
-
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
2175
|
-
if (nodeIndex === -1) {
|
|
2176
|
-
throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
|
|
2177
|
-
}
|
|
2178
|
-
parentNode.values.splice(nodeIndex, 0, value);
|
|
2179
|
-
parentNode.keys.splice(nodeIndex + 1, 0, newSiblingNode.id);
|
|
2180
|
-
newSiblingNode = this._cloneNode(newSiblingNode);
|
|
2181
|
-
newSiblingNode.parent = parentNode.id;
|
|
2182
|
-
if (newSiblingNode.leaf) {
|
|
2183
|
-
const leftSibling = this._cloneNode(node);
|
|
2184
|
-
const oldNextId = leftSibling.next;
|
|
2185
|
-
newSiblingNode.prev = leftSibling.id;
|
|
2186
|
-
newSiblingNode.next = oldNextId;
|
|
2187
|
-
leftSibling.next = newSiblingNode.id;
|
|
2188
|
-
this._updateNode(leftSibling);
|
|
2189
|
-
if (oldNextId) {
|
|
2190
|
-
const oldNext = this._cloneNode(this.getNode(oldNextId));
|
|
2191
|
-
oldNext.prev = newSiblingNode.id;
|
|
2192
|
-
this._updateNode(oldNext);
|
|
2193
|
-
}
|
|
2194
|
-
}
|
|
2195
|
-
this._updateNode(parentNode);
|
|
2196
|
-
this._updateNode(newSiblingNode);
|
|
2197
|
-
if (parentNode.keys.length > this.order) {
|
|
2198
|
-
const newSiblingNodeRecursive = this._createNode(false, [], []);
|
|
2199
|
-
newSiblingNodeRecursive.parent = parentNode.parent;
|
|
2200
|
-
const mid = Math.ceil(this.order / 2) - 1;
|
|
2201
|
-
newSiblingNodeRecursive.values = parentNode.values.slice(mid + 1);
|
|
2202
|
-
newSiblingNodeRecursive.keys = parentNode.keys.slice(mid + 1);
|
|
2203
|
-
const midValue = parentNode.values[mid];
|
|
2204
|
-
parentNode.values = parentNode.values.slice(0, mid);
|
|
2205
|
-
parentNode.keys = parentNode.keys.slice(0, mid + 1);
|
|
2206
|
-
for (let i = 0, len = newSiblingNodeRecursive.keys.length; i < len; i++) {
|
|
2207
|
-
const k = newSiblingNodeRecursive.keys[i];
|
|
2208
|
-
const n = this._cloneNode(this.getNode(k));
|
|
2209
|
-
n.parent = newSiblingNodeRecursive.id;
|
|
2210
|
-
this._updateNode(n);
|
|
2211
|
-
}
|
|
2212
|
-
this._updateNode(parentNode);
|
|
2213
|
-
this._insertInParent(parentNode, midValue, newSiblingNodeRecursive);
|
|
2214
|
-
}
|
|
3225
|
+
insertInParent(this._ops, this._ctx, node, value, newSiblingNode);
|
|
2215
3226
|
}
|
|
2216
3227
|
locateLeaf(value) {
|
|
2217
|
-
|
|
2218
|
-
while (!node.leaf) {
|
|
2219
|
-
const { index } = this._binarySearchValues(node.values, value, false, true);
|
|
2220
|
-
node = this.getNode(node.keys[index]);
|
|
2221
|
-
}
|
|
2222
|
-
return node;
|
|
3228
|
+
return locateLeaf(this._ops, this._ctx.rootId, value, this.comparator);
|
|
2223
3229
|
}
|
|
2224
3230
|
findLowerBoundLeaf(value) {
|
|
2225
|
-
|
|
2226
|
-
while (!node.leaf) {
|
|
2227
|
-
const { index } = this._binarySearchValues(node.values, value, true, false);
|
|
2228
|
-
node = this.getNode(node.keys[index]);
|
|
2229
|
-
}
|
|
2230
|
-
return node;
|
|
3231
|
+
return findLowerBoundLeaf(this._ops, this._ctx.rootId, value, this.comparator);
|
|
2231
3232
|
}
|
|
2232
3233
|
findUpperBoundLeaf(value) {
|
|
2233
|
-
|
|
2234
|
-
while (!node.leaf) {
|
|
2235
|
-
const { index } = this._binarySearchValues(node.values, value, true, true);
|
|
2236
|
-
node = this.getNode(node.keys[index]);
|
|
2237
|
-
}
|
|
2238
|
-
return node;
|
|
3234
|
+
return findUpperBoundLeaf(this._ops, this._ctx.rootId, value, this.comparator);
|
|
2239
3235
|
}
|
|
2240
3236
|
findOuterBoundaryLeaf(value, direction) {
|
|
2241
|
-
|
|
2242
|
-
let key;
|
|
2243
|
-
switch (direction) {
|
|
2244
|
-
case -1:
|
|
2245
|
-
key = "prev";
|
|
2246
|
-
break;
|
|
2247
|
-
case 1:
|
|
2248
|
-
key = "next";
|
|
2249
|
-
break;
|
|
2250
|
-
default:
|
|
2251
|
-
throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
|
|
2252
|
-
}
|
|
2253
|
-
const guessNode = insertableNode[key];
|
|
2254
|
-
if (!guessNode) {
|
|
2255
|
-
return null;
|
|
2256
|
-
}
|
|
2257
|
-
return this.getNode(guessNode);
|
|
3237
|
+
return findOuterBoundaryLeaf(this._ops, this._ctx.rootId, value, direction, this.comparator);
|
|
2258
3238
|
}
|
|
2259
3239
|
leftestNode() {
|
|
2260
|
-
|
|
2261
|
-
if (node === null) {
|
|
2262
|
-
debugger;
|
|
2263
|
-
}
|
|
2264
|
-
while (!node.leaf) {
|
|
2265
|
-
const keys = node.keys;
|
|
2266
|
-
node = this.getNode(keys[0]);
|
|
2267
|
-
}
|
|
2268
|
-
return node;
|
|
3240
|
+
return leftestNode(this._ops, this._ctx.rootId);
|
|
2269
3241
|
}
|
|
2270
3242
|
rightestNode() {
|
|
2271
|
-
|
|
2272
|
-
while (!node.leaf) {
|
|
2273
|
-
const keys = node.keys;
|
|
2274
|
-
node = this.getNode(keys[keys.length - 1]);
|
|
2275
|
-
}
|
|
2276
|
-
return node;
|
|
3243
|
+
return rightestNode(this._ops, this._ctx.rootId);
|
|
2277
3244
|
}
|
|
2278
3245
|
*getPairsGenerator(startNode, endNode, direction) {
|
|
2279
|
-
|
|
2280
|
-
while (true) {
|
|
2281
|
-
if (endNode && node.id === endNode.id) {
|
|
2282
|
-
break;
|
|
2283
|
-
}
|
|
2284
|
-
const len = node.values.length;
|
|
2285
|
-
if (direction === 1) {
|
|
2286
|
-
for (let i = 0; i < len; i++) {
|
|
2287
|
-
const nValue = node.values[i];
|
|
2288
|
-
const keys = node.keys[i];
|
|
2289
|
-
for (let j = 0, len2 = keys.length; j < len2; j++) {
|
|
2290
|
-
yield [keys[j], nValue];
|
|
2291
|
-
}
|
|
2292
|
-
}
|
|
2293
|
-
} else {
|
|
2294
|
-
let i = len;
|
|
2295
|
-
while (i--) {
|
|
2296
|
-
const nValue = node.values[i];
|
|
2297
|
-
const keys = node.keys[i];
|
|
2298
|
-
let j = keys.length;
|
|
2299
|
-
while (j--) {
|
|
2300
|
-
yield [keys[j], nValue];
|
|
2301
|
-
}
|
|
2302
|
-
}
|
|
2303
|
-
}
|
|
2304
|
-
if (direction === 1) {
|
|
2305
|
-
if (!node.next) break;
|
|
2306
|
-
node = this.getNode(node.next);
|
|
2307
|
-
} else {
|
|
2308
|
-
if (!node.prev) break;
|
|
2309
|
-
node = this.getNode(node.prev);
|
|
2310
|
-
}
|
|
2311
|
-
}
|
|
3246
|
+
yield* getPairsGenerator(this._ops, startNode, endNode, direction);
|
|
2312
3247
|
}
|
|
3248
|
+
// ─── Lifecycle ───────────────────────────────────────────────────
|
|
2313
3249
|
init() {
|
|
2314
3250
|
if (this.rootTx !== this) {
|
|
2315
3251
|
throw new Error("Cannot call init on a nested transaction");
|
|
@@ -2326,24 +3262,15 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2326
3262
|
this.isInitialized = true;
|
|
2327
3263
|
try {
|
|
2328
3264
|
this._clearCache();
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
this.
|
|
2332
|
-
|
|
2333
|
-
this.
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
} else {
|
|
2339
|
-
const { root, order } = head;
|
|
2340
|
-
this.strategy.head = head;
|
|
2341
|
-
this.order = order;
|
|
2342
|
-
this.rootId = root;
|
|
2343
|
-
}
|
|
2344
|
-
if (this.order < 3) {
|
|
2345
|
-
throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
|
|
2346
|
-
}
|
|
3265
|
+
initOp(
|
|
3266
|
+
this._ops,
|
|
3267
|
+
this._ctx,
|
|
3268
|
+
this.strategy.order,
|
|
3269
|
+
this.strategy.head,
|
|
3270
|
+
(head) => {
|
|
3271
|
+
this.strategy.head = head;
|
|
3272
|
+
}
|
|
3273
|
+
);
|
|
2347
3274
|
} catch (e) {
|
|
2348
3275
|
this.isInitialized = false;
|
|
2349
3276
|
throw e;
|
|
@@ -2359,501 +3286,68 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2359
3286
|
this._resetForReload();
|
|
2360
3287
|
this._initInternal();
|
|
2361
3288
|
}
|
|
3289
|
+
// ─── Query (delegating to algorithm) ─────────────────────────────
|
|
2362
3290
|
exists(key, value) {
|
|
2363
|
-
|
|
2364
|
-
const { index, found } = this._binarySearchValues(node.values, value);
|
|
2365
|
-
if (found) {
|
|
2366
|
-
const keys = node.keys[index];
|
|
2367
|
-
if (keys.includes(key)) {
|
|
2368
|
-
return true;
|
|
2369
|
-
}
|
|
2370
|
-
}
|
|
2371
|
-
return false;
|
|
3291
|
+
return existsOp(this._ops, this._ctx.rootId, key, value, this.comparator);
|
|
2372
3292
|
}
|
|
2373
3293
|
get(key) {
|
|
2374
|
-
|
|
2375
|
-
while (true) {
|
|
2376
|
-
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
2377
|
-
const keys = node.keys[i];
|
|
2378
|
-
for (let j = 0, len2 = keys.length; j < len2; j++) {
|
|
2379
|
-
if (keys[j] === key) {
|
|
2380
|
-
return node.values[i];
|
|
2381
|
-
}
|
|
2382
|
-
}
|
|
2383
|
-
}
|
|
2384
|
-
if (!node.next) break;
|
|
2385
|
-
node = this.getNode(node.next);
|
|
2386
|
-
}
|
|
2387
|
-
return void 0;
|
|
3294
|
+
return getOp(this._ops, this._ctx.rootId, key);
|
|
2388
3295
|
}
|
|
2389
3296
|
*keysStream(condition, options) {
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
if (limit !== void 0 && count >= limit) {
|
|
2401
|
-
break;
|
|
2402
|
-
}
|
|
2403
|
-
}
|
|
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
|
+
);
|
|
2404
3307
|
}
|
|
2405
3308
|
*whereStream(condition, options) {
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
} else {
|
|
2416
|
-
startNode = order === "asc" ? this.leftestNode() : this.rightestNode();
|
|
2417
|
-
}
|
|
2418
|
-
let endNode = null;
|
|
2419
|
-
if (resolved.endKey) {
|
|
2420
|
-
const endConfig = this.searchConfigs[resolved.endKey][order];
|
|
2421
|
-
endNode = endConfig.end(this, resolved.endValues);
|
|
2422
|
-
}
|
|
2423
|
-
if (!startNode) return;
|
|
2424
|
-
const generator = this.getPairsGenerator(
|
|
2425
|
-
startNode,
|
|
2426
|
-
endNode,
|
|
2427
|
-
direction
|
|
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
|
|
2428
3318
|
);
|
|
2429
|
-
let count = 0;
|
|
2430
|
-
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
2431
|
-
for (const pair of generator) {
|
|
2432
|
-
const [k, v] = pair;
|
|
2433
|
-
if (intersection && !intersection.has(k)) {
|
|
2434
|
-
continue;
|
|
2435
|
-
}
|
|
2436
|
-
if (this.verify(v, condition)) {
|
|
2437
|
-
yield pair;
|
|
2438
|
-
count++;
|
|
2439
|
-
if (limit !== void 0 && count >= limit) {
|
|
2440
|
-
break;
|
|
2441
|
-
}
|
|
2442
|
-
}
|
|
2443
|
-
}
|
|
2444
3319
|
}
|
|
2445
3320
|
keys(condition, options) {
|
|
2446
3321
|
const set = /* @__PURE__ */ new Set();
|
|
2447
3322
|
for (const key of this.keysStream(condition, options)) {
|
|
2448
|
-
set.add(key);
|
|
2449
|
-
}
|
|
2450
|
-
return set;
|
|
2451
|
-
}
|
|
2452
|
-
where(condition, options) {
|
|
2453
|
-
const map = /* @__PURE__ */ new Map();
|
|
2454
|
-
for (const [key, value] of this.whereStream(condition, options)) {
|
|
2455
|
-
map.set(key, value);
|
|
2456
|
-
}
|
|
2457
|
-
return map;
|
|
2458
|
-
}
|
|
2459
|
-
insert(key, value) {
|
|
2460
|
-
let before = this.locateLeaf(value);
|
|
2461
|
-
before = this._insertAtLeaf(before, key, value);
|
|
2462
|
-
if (before.values.length === this.order) {
|
|
2463
|
-
let after = this._createNode(
|
|
2464
|
-
true,
|
|
2465
|
-
[],
|
|
2466
|
-
[],
|
|
2467
|
-
before.parent,
|
|
2468
|
-
null,
|
|
2469
|
-
null
|
|
2470
|
-
);
|
|
2471
|
-
const mid = Math.ceil(this.order / 2) - 1;
|
|
2472
|
-
after = this._cloneNode(after);
|
|
2473
|
-
after.values = before.values.slice(mid + 1);
|
|
2474
|
-
after.keys = before.keys.slice(mid + 1);
|
|
2475
|
-
before.values = before.values.slice(0, mid + 1);
|
|
2476
|
-
before.keys = before.keys.slice(0, mid + 1);
|
|
2477
|
-
this._updateNode(before);
|
|
2478
|
-
this._updateNode(after);
|
|
2479
|
-
this._insertInParent(before, after.values[0], after);
|
|
2480
|
-
}
|
|
2481
|
-
}
|
|
2482
|
-
batchInsert(entries) {
|
|
2483
|
-
if (entries.length === 0) return;
|
|
2484
|
-
const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
|
|
2485
|
-
let currentLeaf = null;
|
|
2486
|
-
let modified = false;
|
|
2487
|
-
let cachedLeafId = null;
|
|
2488
|
-
let cachedLeafMaxValue = null;
|
|
2489
|
-
for (let i = 0, len = sorted.length; i < len; i++) {
|
|
2490
|
-
const [key, value] = sorted[i];
|
|
2491
|
-
let targetLeaf;
|
|
2492
|
-
if (cachedLeafId !== null && cachedLeafMaxValue !== null && currentLeaf !== null && (this.comparator.isLower(value, cachedLeafMaxValue) || this.comparator.isSame(value, cachedLeafMaxValue))) {
|
|
2493
|
-
targetLeaf = currentLeaf;
|
|
2494
|
-
} else {
|
|
2495
|
-
targetLeaf = this.locateLeaf(value);
|
|
2496
|
-
}
|
|
2497
|
-
if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
|
|
2498
|
-
} else {
|
|
2499
|
-
if (currentLeaf !== null && modified) {
|
|
2500
|
-
this._updateNode(currentLeaf);
|
|
2501
|
-
}
|
|
2502
|
-
currentLeaf = this._cloneNode(targetLeaf);
|
|
2503
|
-
modified = false;
|
|
2504
|
-
}
|
|
2505
|
-
cachedLeafId = currentLeaf.id;
|
|
2506
|
-
const changed = this._insertValueIntoLeaf(currentLeaf, key, value);
|
|
2507
|
-
modified = modified || changed;
|
|
2508
|
-
cachedLeafMaxValue = currentLeaf.values[currentLeaf.values.length - 1];
|
|
2509
|
-
if (currentLeaf.values.length === this.order) {
|
|
2510
|
-
this._updateNode(currentLeaf);
|
|
2511
|
-
let after = this._createNode(
|
|
2512
|
-
true,
|
|
2513
|
-
[],
|
|
2514
|
-
[],
|
|
2515
|
-
currentLeaf.parent,
|
|
2516
|
-
null,
|
|
2517
|
-
null
|
|
2518
|
-
);
|
|
2519
|
-
const mid = Math.ceil(this.order / 2) - 1;
|
|
2520
|
-
after = this._cloneNode(after);
|
|
2521
|
-
after.values = currentLeaf.values.slice(mid + 1);
|
|
2522
|
-
after.keys = currentLeaf.keys.slice(mid + 1);
|
|
2523
|
-
currentLeaf.values = currentLeaf.values.slice(0, mid + 1);
|
|
2524
|
-
currentLeaf.keys = currentLeaf.keys.slice(0, mid + 1);
|
|
2525
|
-
this._updateNode(currentLeaf);
|
|
2526
|
-
this._updateNode(after);
|
|
2527
|
-
this._insertInParent(currentLeaf, after.values[0], after);
|
|
2528
|
-
currentLeaf = null;
|
|
2529
|
-
cachedLeafId = null;
|
|
2530
|
-
cachedLeafMaxValue = null;
|
|
2531
|
-
modified = false;
|
|
2532
|
-
}
|
|
2533
|
-
}
|
|
2534
|
-
if (currentLeaf !== null && modified) {
|
|
2535
|
-
this._updateNode(currentLeaf);
|
|
2536
|
-
}
|
|
2537
|
-
}
|
|
2538
|
-
bulkLoad(entries) {
|
|
2539
|
-
if (entries.length === 0) return;
|
|
2540
|
-
const root = this.getNode(this.rootId);
|
|
2541
|
-
if (!root.leaf || root.values.length > 0) {
|
|
2542
|
-
throw new Error("bulkLoad can only be called on an empty tree. Use batchInsert for non-empty trees.");
|
|
2543
|
-
}
|
|
2544
|
-
const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
|
|
2545
|
-
const grouped = [];
|
|
2546
|
-
for (let i = 0, len = sorted.length; i < len; i++) {
|
|
2547
|
-
const [key, value] = sorted[i];
|
|
2548
|
-
const last = grouped[grouped.length - 1];
|
|
2549
|
-
if (last && this.comparator.isSame(last.value, value)) {
|
|
2550
|
-
if (!last.keys.includes(key)) {
|
|
2551
|
-
last.keys.push(key);
|
|
2552
|
-
}
|
|
2553
|
-
} else {
|
|
2554
|
-
grouped.push({ keys: [key], value });
|
|
2555
|
-
}
|
|
2556
|
-
}
|
|
2557
|
-
this._deleteNode(root);
|
|
2558
|
-
const maxLeafSize = this.order - 1;
|
|
2559
|
-
const leaves = [];
|
|
2560
|
-
for (let i = 0, len = grouped.length; i < len; i += maxLeafSize) {
|
|
2561
|
-
const chunk = grouped.slice(i, i + maxLeafSize);
|
|
2562
|
-
const leafKeys = chunk.map((g) => g.keys);
|
|
2563
|
-
const leafValues = chunk.map((g) => g.value);
|
|
2564
|
-
const leaf = this._createNode(
|
|
2565
|
-
true,
|
|
2566
|
-
leafKeys,
|
|
2567
|
-
leafValues,
|
|
2568
|
-
null,
|
|
2569
|
-
null,
|
|
2570
|
-
null
|
|
2571
|
-
);
|
|
2572
|
-
leaves.push(leaf);
|
|
2573
|
-
}
|
|
2574
|
-
for (let i = 0, len = leaves.length; i < len; i++) {
|
|
2575
|
-
if (i > 0) {
|
|
2576
|
-
leaves[i].prev = leaves[i - 1].id;
|
|
2577
|
-
}
|
|
2578
|
-
if (i < len - 1) {
|
|
2579
|
-
leaves[i].next = leaves[i + 1].id;
|
|
2580
|
-
}
|
|
2581
|
-
this._updateNode(leaves[i]);
|
|
2582
|
-
}
|
|
2583
|
-
let currentLevel = leaves;
|
|
2584
|
-
while (currentLevel.length > 1) {
|
|
2585
|
-
const nextLevel = [];
|
|
2586
|
-
for (let i = 0, len = currentLevel.length; i < len; i += this.order) {
|
|
2587
|
-
const children = currentLevel.slice(i, i + this.order);
|
|
2588
|
-
const childIds = children.map((c) => c.id);
|
|
2589
|
-
const separators = [];
|
|
2590
|
-
for (let j = 1, len2 = children.length; j < len2; j++) {
|
|
2591
|
-
separators.push(children[j].values[0]);
|
|
2592
|
-
}
|
|
2593
|
-
const internalNode = this._createNode(
|
|
2594
|
-
false,
|
|
2595
|
-
childIds,
|
|
2596
|
-
separators,
|
|
2597
|
-
null,
|
|
2598
|
-
null,
|
|
2599
|
-
null
|
|
2600
|
-
);
|
|
2601
|
-
for (let j = 0, len2 = children.length; j < len2; j++) {
|
|
2602
|
-
const child = children[j];
|
|
2603
|
-
child.parent = internalNode.id;
|
|
2604
|
-
this._updateNode(child);
|
|
2605
|
-
}
|
|
2606
|
-
nextLevel.push(internalNode);
|
|
2607
|
-
}
|
|
2608
|
-
currentLevel = nextLevel;
|
|
2609
|
-
}
|
|
2610
|
-
const newRoot = currentLevel[0];
|
|
2611
|
-
this._writeHead({
|
|
2612
|
-
root: newRoot.id,
|
|
2613
|
-
order: this.order,
|
|
2614
|
-
data: this.strategy.head.data
|
|
2615
|
-
});
|
|
2616
|
-
}
|
|
2617
|
-
_deleteEntry(node, key) {
|
|
2618
|
-
if (!node.leaf) {
|
|
2619
|
-
let keyIndex = -1;
|
|
2620
|
-
for (let i = 0, len = node.keys.length; i < len; i++) {
|
|
2621
|
-
if (node.keys[i] === key) {
|
|
2622
|
-
keyIndex = i;
|
|
2623
|
-
break;
|
|
2624
|
-
}
|
|
2625
|
-
}
|
|
2626
|
-
if (keyIndex !== -1) {
|
|
2627
|
-
node = this._cloneNode(node);
|
|
2628
|
-
node.keys.splice(keyIndex, 1);
|
|
2629
|
-
const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
|
|
2630
|
-
node.values.splice(valueIndex, 1);
|
|
2631
|
-
this._updateNode(node);
|
|
2632
|
-
}
|
|
2633
|
-
}
|
|
2634
|
-
if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
|
|
2635
|
-
const keys = node.keys;
|
|
2636
|
-
this._deleteNode(node);
|
|
2637
|
-
const newRoot = this._cloneNode(this.getNode(keys[0]));
|
|
2638
|
-
newRoot.parent = null;
|
|
2639
|
-
this._updateNode(newRoot);
|
|
2640
|
-
this._writeHead({
|
|
2641
|
-
root: newRoot.id,
|
|
2642
|
-
order: this.order,
|
|
2643
|
-
data: this.strategy.head.data
|
|
2644
|
-
});
|
|
2645
|
-
return node;
|
|
2646
|
-
} else if (this.rootId === node.id) {
|
|
2647
|
-
this._writeHead({
|
|
2648
|
-
root: node.id,
|
|
2649
|
-
order: this.order,
|
|
2650
|
-
data: this.strategy.head.data
|
|
2651
|
-
});
|
|
2652
|
-
return node;
|
|
2653
|
-
} else if (node.keys.length < Math.ceil(this.order / 2) && !node.leaf || node.values.length < Math.ceil((this.order - 1) / 2) && node.leaf) {
|
|
2654
|
-
if (node.parent === null) {
|
|
2655
|
-
return node;
|
|
2656
|
-
}
|
|
2657
|
-
let isPredecessor = false;
|
|
2658
|
-
let parentNode = this.getNode(node.parent);
|
|
2659
|
-
let prevNode = null;
|
|
2660
|
-
let nextNode = null;
|
|
2661
|
-
let prevValue = null;
|
|
2662
|
-
let postValue = null;
|
|
2663
|
-
for (let i = 0, len = parentNode.keys.length; i < len; i++) {
|
|
2664
|
-
const nKey = parentNode.keys[i];
|
|
2665
|
-
if (nKey === node.id) {
|
|
2666
|
-
if (i > 0) {
|
|
2667
|
-
prevNode = this.getNode(parentNode.keys[i - 1]);
|
|
2668
|
-
prevValue = parentNode.values[i - 1];
|
|
2669
|
-
}
|
|
2670
|
-
if (i < parentNode.keys.length - 1) {
|
|
2671
|
-
nextNode = this.getNode(parentNode.keys[i + 1]);
|
|
2672
|
-
postValue = parentNode.values[i];
|
|
2673
|
-
}
|
|
2674
|
-
}
|
|
2675
|
-
}
|
|
2676
|
-
let siblingNode;
|
|
2677
|
-
let guess;
|
|
2678
|
-
if (prevNode === null) {
|
|
2679
|
-
siblingNode = nextNode;
|
|
2680
|
-
guess = postValue;
|
|
2681
|
-
} else if (nextNode === null) {
|
|
2682
|
-
isPredecessor = true;
|
|
2683
|
-
siblingNode = prevNode;
|
|
2684
|
-
guess = prevValue;
|
|
2685
|
-
} else {
|
|
2686
|
-
if (node.values.length + nextNode.values.length < this.order) {
|
|
2687
|
-
siblingNode = nextNode;
|
|
2688
|
-
guess = postValue;
|
|
2689
|
-
} else {
|
|
2690
|
-
isPredecessor = true;
|
|
2691
|
-
siblingNode = prevNode;
|
|
2692
|
-
guess = prevValue;
|
|
2693
|
-
}
|
|
2694
|
-
}
|
|
2695
|
-
if (!siblingNode) {
|
|
2696
|
-
return node;
|
|
2697
|
-
}
|
|
2698
|
-
node = this._cloneNode(node);
|
|
2699
|
-
siblingNode = this._cloneNode(siblingNode);
|
|
2700
|
-
if (node.values.length + siblingNode.values.length < this.order) {
|
|
2701
|
-
if (!isPredecessor) {
|
|
2702
|
-
const pTemp = siblingNode;
|
|
2703
|
-
siblingNode = node;
|
|
2704
|
-
node = pTemp;
|
|
2705
|
-
}
|
|
2706
|
-
siblingNode.keys.push(...node.keys);
|
|
2707
|
-
if (!node.leaf) {
|
|
2708
|
-
siblingNode.values.push(guess);
|
|
2709
|
-
} else {
|
|
2710
|
-
siblingNode.next = node.next;
|
|
2711
|
-
if (siblingNode.next) {
|
|
2712
|
-
const n = this._cloneNode(this.getNode(siblingNode.next));
|
|
2713
|
-
n.prev = siblingNode.id;
|
|
2714
|
-
this._updateNode(n);
|
|
2715
|
-
}
|
|
2716
|
-
}
|
|
2717
|
-
siblingNode.values.push(...node.values);
|
|
2718
|
-
if (!siblingNode.leaf) {
|
|
2719
|
-
const keys = siblingNode.keys;
|
|
2720
|
-
for (let i = 0, len = keys.length; i < len; i++) {
|
|
2721
|
-
const key2 = keys[i];
|
|
2722
|
-
const node2 = this._cloneNode(this.getNode(key2));
|
|
2723
|
-
node2.parent = siblingNode.id;
|
|
2724
|
-
this._updateNode(node2);
|
|
2725
|
-
}
|
|
2726
|
-
}
|
|
2727
|
-
this._deleteNode(node);
|
|
2728
|
-
this._updateNode(siblingNode);
|
|
2729
|
-
this._deleteEntry(this.getNode(node.parent), node.id);
|
|
2730
|
-
} else {
|
|
2731
|
-
if (isPredecessor) {
|
|
2732
|
-
let pointerPm;
|
|
2733
|
-
let pointerKm;
|
|
2734
|
-
if (!node.leaf) {
|
|
2735
|
-
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
2736
|
-
pointerKm = siblingNode.values.splice(-1)[0];
|
|
2737
|
-
node.keys = [pointerPm, ...node.keys];
|
|
2738
|
-
node.values = [guess, ...node.values];
|
|
2739
|
-
parentNode = this._cloneNode(this.getNode(node.parent));
|
|
2740
|
-
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
2741
|
-
if (nodeIndex > 0) {
|
|
2742
|
-
parentNode.values[nodeIndex - 1] = pointerKm;
|
|
2743
|
-
this._updateNode(parentNode);
|
|
2744
|
-
}
|
|
2745
|
-
} else {
|
|
2746
|
-
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
2747
|
-
pointerKm = siblingNode.values.splice(-1)[0];
|
|
2748
|
-
node.keys = [pointerPm, ...node.keys];
|
|
2749
|
-
node.values = [pointerKm, ...node.values];
|
|
2750
|
-
parentNode = this._cloneNode(this.getNode(node.parent));
|
|
2751
|
-
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
2752
|
-
if (nodeIndex > 0) {
|
|
2753
|
-
parentNode.values[nodeIndex - 1] = pointerKm;
|
|
2754
|
-
this._updateNode(parentNode);
|
|
2755
|
-
}
|
|
2756
|
-
}
|
|
2757
|
-
this._updateNode(node);
|
|
2758
|
-
this._updateNode(siblingNode);
|
|
2759
|
-
} else {
|
|
2760
|
-
let pointerP0;
|
|
2761
|
-
let pointerK0;
|
|
2762
|
-
if (!node.leaf) {
|
|
2763
|
-
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
2764
|
-
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
2765
|
-
node.keys = [...node.keys, pointerP0];
|
|
2766
|
-
node.values = [...node.values, guess];
|
|
2767
|
-
parentNode = this._cloneNode(this.getNode(node.parent));
|
|
2768
|
-
const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
|
|
2769
|
-
if (pointerIndex > 0) {
|
|
2770
|
-
parentNode.values[pointerIndex - 1] = pointerK0;
|
|
2771
|
-
this._updateNode(parentNode);
|
|
2772
|
-
}
|
|
2773
|
-
} else {
|
|
2774
|
-
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
2775
|
-
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
2776
|
-
node.keys = [...node.keys, pointerP0];
|
|
2777
|
-
node.values = [...node.values, pointerK0];
|
|
2778
|
-
parentNode = this._cloneNode(this.getNode(node.parent));
|
|
2779
|
-
const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
|
|
2780
|
-
if (pointerIndex > 0) {
|
|
2781
|
-
parentNode.values[pointerIndex - 1] = siblingNode.values[0];
|
|
2782
|
-
this._updateNode(parentNode);
|
|
2783
|
-
}
|
|
2784
|
-
}
|
|
2785
|
-
this._updateNode(node);
|
|
2786
|
-
this._updateNode(siblingNode);
|
|
2787
|
-
}
|
|
2788
|
-
if (!siblingNode.leaf) {
|
|
2789
|
-
for (let i = 0, len = siblingNode.keys.length; i < len; i++) {
|
|
2790
|
-
const key2 = siblingNode.keys[i];
|
|
2791
|
-
const n = this._cloneNode(this.getNode(key2));
|
|
2792
|
-
n.parent = siblingNode.id;
|
|
2793
|
-
this._updateNode(n);
|
|
2794
|
-
}
|
|
2795
|
-
}
|
|
2796
|
-
if (!node.leaf) {
|
|
2797
|
-
for (let i = 0, len = node.keys.length; i < len; i++) {
|
|
2798
|
-
const key2 = node.keys[i];
|
|
2799
|
-
const n = this._cloneNode(this.getNode(key2));
|
|
2800
|
-
n.parent = node.id;
|
|
2801
|
-
this._updateNode(n);
|
|
2802
|
-
}
|
|
2803
|
-
}
|
|
2804
|
-
if (!parentNode.leaf) {
|
|
2805
|
-
for (let i = 0, len = parentNode.keys.length; i < len; i++) {
|
|
2806
|
-
const key2 = parentNode.keys[i];
|
|
2807
|
-
const n = this._cloneNode(this.getNode(key2));
|
|
2808
|
-
n.parent = parentNode.id;
|
|
2809
|
-
this._updateNode(n);
|
|
2810
|
-
}
|
|
2811
|
-
}
|
|
2812
|
-
}
|
|
2813
|
-
} else {
|
|
2814
|
-
this._updateNode(this._cloneNode(node));
|
|
3323
|
+
set.add(key);
|
|
2815
3324
|
}
|
|
2816
|
-
return
|
|
3325
|
+
return set;
|
|
2817
3326
|
}
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
if (value === void 0) {
|
|
2823
|
-
return;
|
|
2824
|
-
}
|
|
2825
|
-
let node = this.findLowerBoundLeaf(value);
|
|
2826
|
-
let found = false;
|
|
2827
|
-
while (true) {
|
|
2828
|
-
let i = node.values.length;
|
|
2829
|
-
while (i--) {
|
|
2830
|
-
const nValue = node.values[i];
|
|
2831
|
-
if (this.comparator.isSame(value, nValue)) {
|
|
2832
|
-
const keys = node.keys[i];
|
|
2833
|
-
const keyIndex = keys.indexOf(key);
|
|
2834
|
-
if (keyIndex !== -1) {
|
|
2835
|
-
node = this._cloneNode(node);
|
|
2836
|
-
const freshKeys = node.keys[i];
|
|
2837
|
-
freshKeys.splice(keyIndex, 1);
|
|
2838
|
-
if (freshKeys.length === 0) {
|
|
2839
|
-
node.keys.splice(i, 1);
|
|
2840
|
-
node.values.splice(i, 1);
|
|
2841
|
-
}
|
|
2842
|
-
this._updateNode(node);
|
|
2843
|
-
node = this._deleteEntry(node, key);
|
|
2844
|
-
found = true;
|
|
2845
|
-
break;
|
|
2846
|
-
}
|
|
2847
|
-
}
|
|
2848
|
-
}
|
|
2849
|
-
if (found) break;
|
|
2850
|
-
if (node.next) {
|
|
2851
|
-
node = this.getNode(node.next);
|
|
2852
|
-
continue;
|
|
2853
|
-
}
|
|
2854
|
-
break;
|
|
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);
|
|
2855
3331
|
}
|
|
3332
|
+
return map;
|
|
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);
|
|
2856
3349
|
}
|
|
3350
|
+
// ─── Head Data ───────────────────────────────────────────────────
|
|
2857
3351
|
getHeadData() {
|
|
2858
3352
|
const head = this._readHead();
|
|
2859
3353
|
if (head === null) {
|
|
@@ -2872,6 +3366,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
|
|
|
2872
3366
|
data
|
|
2873
3367
|
});
|
|
2874
3368
|
}
|
|
3369
|
+
// ─── Transaction ─────────────────────────────────────────────────
|
|
2875
3370
|
commit(label) {
|
|
2876
3371
|
let result = this.mvcc.commit(label);
|
|
2877
3372
|
if (result.success) {
|
|
@@ -3226,36 +3721,843 @@ var Ryoiki2 = class _Ryoiki2 {
|
|
|
3226
3721
|
rangeTask: [Array, Function],
|
|
3227
3722
|
rangeTaskTimeout: [Array, Function, Number]
|
|
3228
3723
|
}
|
|
3229
|
-
);
|
|
3230
|
-
return this._lock(
|
|
3231
|
-
this.writeQueue,
|
|
3232
|
-
range,
|
|
3233
|
-
timeout,
|
|
3234
|
-
task,
|
|
3235
|
-
() => {
|
|
3236
|
-
return !this.rangeOverlapping(this.writings, range) && !this.rangeOverlapping(this.readings, range);
|
|
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
|
|
3960
|
+
},
|
|
3961
|
+
desc: {
|
|
3962
|
+
start: (r, ops) => rightestNodeAsync(ops, r),
|
|
3963
|
+
end: async () => null,
|
|
3964
|
+
direction: -1,
|
|
3965
|
+
earlyTerminate: false
|
|
3966
|
+
}
|
|
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
|
+
}
|
|
4033
|
+
}
|
|
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
|
+
}
|
|
4051
|
+
}
|
|
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;
|
|
4084
|
+
}
|
|
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
|
+
}
|
|
4177
|
+
}
|
|
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
|
+
}
|
|
3237
4256
|
}
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
}
|
|
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
|
+
}
|
|
3255
4553
|
|
|
3256
4554
|
// src/transaction/BPTreeAsyncTransaction.ts
|
|
3257
4555
|
var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
3258
4556
|
lock;
|
|
4557
|
+
_ops;
|
|
4558
|
+
_ctx;
|
|
4559
|
+
_verifierMapCached;
|
|
4560
|
+
_searchConfigsCached;
|
|
3259
4561
|
constructor(rootTx, mvccRoot, mvcc, strategy, comparator, option) {
|
|
3260
4562
|
super(
|
|
3261
4563
|
rootTx,
|
|
@@ -3266,6 +4568,64 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3266
4568
|
option
|
|
3267
4569
|
);
|
|
3268
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);
|
|
3269
4629
|
}
|
|
3270
4630
|
async writeLock(id, fn) {
|
|
3271
4631
|
let lockId;
|
|
@@ -3276,256 +4636,54 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3276
4636
|
this.lock.writeUnlock(lockId);
|
|
3277
4637
|
});
|
|
3278
4638
|
}
|
|
4639
|
+
// ─── Legacy protected methods (delegating to ops) ────────────────
|
|
3279
4640
|
async getNode(id) {
|
|
3280
|
-
return
|
|
4641
|
+
return this._ops.getNode(id);
|
|
3281
4642
|
}
|
|
3282
|
-
/**
|
|
3283
|
-
* Create a new node with a unique ID.
|
|
3284
|
-
*/
|
|
3285
4643
|
async _createNode(leaf, keys, values, parent = null, next = null, prev = null) {
|
|
3286
|
-
|
|
3287
|
-
const node = {
|
|
3288
|
-
id,
|
|
3289
|
-
keys,
|
|
3290
|
-
values,
|
|
3291
|
-
leaf,
|
|
3292
|
-
parent,
|
|
3293
|
-
next,
|
|
3294
|
-
prev
|
|
3295
|
-
};
|
|
3296
|
-
await this.mvcc.create(id, node);
|
|
3297
|
-
return node;
|
|
4644
|
+
return this._ops.createNode(leaf, keys, values, parent, next, prev);
|
|
3298
4645
|
}
|
|
3299
4646
|
async _updateNode(node) {
|
|
3300
|
-
|
|
3301
|
-
return;
|
|
3302
|
-
}
|
|
3303
|
-
await this.mvcc.write(node.id, node);
|
|
4647
|
+
await this._ops.updateNode(node);
|
|
3304
4648
|
}
|
|
3305
4649
|
async _deleteNode(node) {
|
|
3306
|
-
|
|
3307
|
-
return;
|
|
3308
|
-
}
|
|
3309
|
-
await this.mvcc.delete(node.id);
|
|
4650
|
+
await this._ops.deleteNode(node);
|
|
3310
4651
|
}
|
|
3311
4652
|
async _readHead() {
|
|
3312
|
-
return
|
|
4653
|
+
return this._ops.readHead();
|
|
3313
4654
|
}
|
|
3314
4655
|
async _writeHead(head) {
|
|
3315
|
-
|
|
3316
|
-
await this.mvcc.create("__HEAD__", head);
|
|
3317
|
-
} else {
|
|
3318
|
-
await this.mvcc.write("__HEAD__", head);
|
|
3319
|
-
}
|
|
3320
|
-
this.rootId = head.root;
|
|
4656
|
+
await this._ops.writeHead(head);
|
|
3321
4657
|
}
|
|
4658
|
+
// ─── Tree traversal (delegating to algorithm) ────────────────────
|
|
3322
4659
|
async _insertAtLeaf(node, key, value) {
|
|
3323
|
-
|
|
3324
|
-
if (leaf.values.length) {
|
|
3325
|
-
for (let i = 0, len = leaf.values.length; i < len; i++) {
|
|
3326
|
-
const nValue = leaf.values[i];
|
|
3327
|
-
if (this.comparator.isSame(value, nValue)) {
|
|
3328
|
-
const keys = leaf.keys[i];
|
|
3329
|
-
if (keys.includes(key)) {
|
|
3330
|
-
break;
|
|
3331
|
-
}
|
|
3332
|
-
leaf = this._cloneNode(leaf);
|
|
3333
|
-
leaf.keys[i].push(key);
|
|
3334
|
-
await this._updateNode(leaf);
|
|
3335
|
-
return leaf;
|
|
3336
|
-
} else if (this.comparator.isLower(value, nValue)) {
|
|
3337
|
-
leaf = this._cloneNode(leaf);
|
|
3338
|
-
leaf.values.splice(i, 0, value);
|
|
3339
|
-
leaf.keys.splice(i, 0, [key]);
|
|
3340
|
-
await this._updateNode(leaf);
|
|
3341
|
-
return leaf;
|
|
3342
|
-
} else if (i + 1 === leaf.values.length) {
|
|
3343
|
-
leaf = this._cloneNode(leaf);
|
|
3344
|
-
leaf.values.push(value);
|
|
3345
|
-
leaf.keys.push([key]);
|
|
3346
|
-
await this._updateNode(leaf);
|
|
3347
|
-
return leaf;
|
|
3348
|
-
}
|
|
3349
|
-
}
|
|
3350
|
-
} else {
|
|
3351
|
-
leaf = this._cloneNode(leaf);
|
|
3352
|
-
leaf.values = [value];
|
|
3353
|
-
leaf.keys = [[key]];
|
|
3354
|
-
await this._updateNode(leaf);
|
|
3355
|
-
return leaf;
|
|
3356
|
-
}
|
|
3357
|
-
return leaf;
|
|
4660
|
+
return insertAtLeafAsync(this._ops, node, key, value, this.comparator);
|
|
3358
4661
|
}
|
|
3359
4662
|
async _insertInParent(node, value, newSiblingNode) {
|
|
3360
|
-
|
|
3361
|
-
node = this._cloneNode(node);
|
|
3362
|
-
newSiblingNode = this._cloneNode(newSiblingNode);
|
|
3363
|
-
const root = await this._createNode(false, [node.id, newSiblingNode.id], [value]);
|
|
3364
|
-
this.rootId = root.id;
|
|
3365
|
-
node.parent = root.id;
|
|
3366
|
-
newSiblingNode.parent = root.id;
|
|
3367
|
-
if (newSiblingNode.leaf) {
|
|
3368
|
-
node.next = newSiblingNode.id;
|
|
3369
|
-
newSiblingNode.prev = node.id;
|
|
3370
|
-
}
|
|
3371
|
-
await this._writeHead({
|
|
3372
|
-
root: root.id,
|
|
3373
|
-
order: this.order,
|
|
3374
|
-
data: this.strategy.head.data
|
|
3375
|
-
});
|
|
3376
|
-
await this._updateNode(node);
|
|
3377
|
-
await this._updateNode(newSiblingNode);
|
|
3378
|
-
return;
|
|
3379
|
-
}
|
|
3380
|
-
const parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
3381
|
-
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
3382
|
-
if (nodeIndex === -1) {
|
|
3383
|
-
throw new Error(`Node ${node.id} not found in parent ${parentNode.id}`);
|
|
3384
|
-
}
|
|
3385
|
-
parentNode.values.splice(nodeIndex, 0, value);
|
|
3386
|
-
parentNode.keys.splice(nodeIndex + 1, 0, newSiblingNode.id);
|
|
3387
|
-
newSiblingNode = this._cloneNode(newSiblingNode);
|
|
3388
|
-
newSiblingNode.parent = parentNode.id;
|
|
3389
|
-
if (newSiblingNode.leaf) {
|
|
3390
|
-
const leftSibling = this._cloneNode(node);
|
|
3391
|
-
const oldNextId = leftSibling.next;
|
|
3392
|
-
newSiblingNode.prev = leftSibling.id;
|
|
3393
|
-
newSiblingNode.next = oldNextId;
|
|
3394
|
-
leftSibling.next = newSiblingNode.id;
|
|
3395
|
-
await this._updateNode(leftSibling);
|
|
3396
|
-
if (oldNextId) {
|
|
3397
|
-
const oldNext = this._cloneNode(await this.getNode(oldNextId));
|
|
3398
|
-
oldNext.prev = newSiblingNode.id;
|
|
3399
|
-
await this._updateNode(oldNext);
|
|
3400
|
-
}
|
|
3401
|
-
}
|
|
3402
|
-
await this._updateNode(parentNode);
|
|
3403
|
-
await this._updateNode(newSiblingNode);
|
|
3404
|
-
if (parentNode.keys.length > this.order) {
|
|
3405
|
-
const newSiblingNodeRecursive = await this._createNode(false, [], []);
|
|
3406
|
-
newSiblingNodeRecursive.parent = parentNode.parent;
|
|
3407
|
-
const mid = Math.ceil(this.order / 2) - 1;
|
|
3408
|
-
newSiblingNodeRecursive.values = parentNode.values.slice(mid + 1);
|
|
3409
|
-
newSiblingNodeRecursive.keys = parentNode.keys.slice(mid + 1);
|
|
3410
|
-
const midValue = parentNode.values[mid];
|
|
3411
|
-
parentNode.values = parentNode.values.slice(0, mid);
|
|
3412
|
-
parentNode.keys = parentNode.keys.slice(0, mid + 1);
|
|
3413
|
-
for (let i = 0, len = newSiblingNodeRecursive.keys.length; i < len; i++) {
|
|
3414
|
-
const k = newSiblingNodeRecursive.keys[i];
|
|
3415
|
-
const n = this._cloneNode(await this.getNode(k));
|
|
3416
|
-
n.parent = newSiblingNodeRecursive.id;
|
|
3417
|
-
await this._updateNode(n);
|
|
3418
|
-
}
|
|
3419
|
-
await this._updateNode(parentNode);
|
|
3420
|
-
await this._insertInParent(parentNode, midValue, newSiblingNodeRecursive);
|
|
3421
|
-
}
|
|
4663
|
+
await insertInParentAsync(this._ops, this._ctx, node, value, newSiblingNode);
|
|
3422
4664
|
}
|
|
3423
4665
|
async locateLeaf(value) {
|
|
3424
|
-
|
|
3425
|
-
while (!node.leaf) {
|
|
3426
|
-
const { index } = this._binarySearchValues(node.values, value, false, true);
|
|
3427
|
-
node = await this.getNode(node.keys[index]);
|
|
3428
|
-
}
|
|
3429
|
-
return node;
|
|
4666
|
+
return locateLeafAsync(this._ops, this._ctx.rootId, value, this.comparator);
|
|
3430
4667
|
}
|
|
3431
4668
|
async findLowerBoundLeaf(value) {
|
|
3432
|
-
|
|
3433
|
-
while (!node.leaf) {
|
|
3434
|
-
const { index } = this._binarySearchValues(node.values, value, true, false);
|
|
3435
|
-
node = await this.getNode(node.keys[index]);
|
|
3436
|
-
}
|
|
3437
|
-
return node;
|
|
4669
|
+
return findLowerBoundLeafAsync(this._ops, this._ctx.rootId, value, this.comparator);
|
|
3438
4670
|
}
|
|
3439
4671
|
async findUpperBoundLeaf(value) {
|
|
3440
|
-
|
|
3441
|
-
while (!node.leaf) {
|
|
3442
|
-
const { index } = this._binarySearchValues(node.values, value, true, true);
|
|
3443
|
-
node = await this.getNode(node.keys[index]);
|
|
3444
|
-
}
|
|
3445
|
-
return node;
|
|
4672
|
+
return findUpperBoundLeafAsync(this._ops, this._ctx.rootId, value, this.comparator);
|
|
3446
4673
|
}
|
|
3447
4674
|
async findOuterBoundaryLeaf(value, direction) {
|
|
3448
|
-
|
|
3449
|
-
let key;
|
|
3450
|
-
switch (direction) {
|
|
3451
|
-
case -1:
|
|
3452
|
-
key = "prev";
|
|
3453
|
-
break;
|
|
3454
|
-
case 1:
|
|
3455
|
-
key = "next";
|
|
3456
|
-
break;
|
|
3457
|
-
default:
|
|
3458
|
-
throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
|
|
3459
|
-
}
|
|
3460
|
-
const guessNode = insertableNode[key];
|
|
3461
|
-
if (!guessNode) {
|
|
3462
|
-
return null;
|
|
3463
|
-
}
|
|
3464
|
-
return await this.getNode(guessNode);
|
|
4675
|
+
return findOuterBoundaryLeafAsync(this._ops, this._ctx.rootId, value, direction, this.comparator);
|
|
3465
4676
|
}
|
|
3466
4677
|
async leftestNode() {
|
|
3467
|
-
|
|
3468
|
-
if (node === null) {
|
|
3469
|
-
debugger;
|
|
3470
|
-
}
|
|
3471
|
-
while (!node.leaf) {
|
|
3472
|
-
const keys = node.keys;
|
|
3473
|
-
node = await this.getNode(keys[0]);
|
|
3474
|
-
}
|
|
3475
|
-
return node;
|
|
4678
|
+
return leftestNodeAsync(this._ops, this._ctx.rootId);
|
|
3476
4679
|
}
|
|
3477
4680
|
async rightestNode() {
|
|
3478
|
-
|
|
3479
|
-
while (!node.leaf) {
|
|
3480
|
-
const keys = node.keys;
|
|
3481
|
-
node = await this.getNode(keys[keys.length - 1]);
|
|
3482
|
-
}
|
|
3483
|
-
return node;
|
|
4681
|
+
return rightestNodeAsync(this._ops, this._ctx.rootId);
|
|
3484
4682
|
}
|
|
3485
4683
|
async *getPairsGenerator(startNode, endNode, direction) {
|
|
3486
|
-
|
|
3487
|
-
let nextNodePromise = null;
|
|
3488
|
-
while (true) {
|
|
3489
|
-
if (endNode && node.id === endNode.id) {
|
|
3490
|
-
break;
|
|
3491
|
-
}
|
|
3492
|
-
if (direction === 1) {
|
|
3493
|
-
if (node.next) {
|
|
3494
|
-
nextNodePromise = this.getNode(node.next);
|
|
3495
|
-
}
|
|
3496
|
-
} else {
|
|
3497
|
-
if (node.prev) {
|
|
3498
|
-
nextNodePromise = this.getNode(node.prev);
|
|
3499
|
-
}
|
|
3500
|
-
}
|
|
3501
|
-
const len = node.values.length;
|
|
3502
|
-
if (direction === 1) {
|
|
3503
|
-
for (let i = 0; i < len; i++) {
|
|
3504
|
-
const nValue = node.values[i];
|
|
3505
|
-
const keys = node.keys[i];
|
|
3506
|
-
for (let j = 0, len2 = keys.length; j < len2; j++) {
|
|
3507
|
-
yield [keys[j], nValue];
|
|
3508
|
-
}
|
|
3509
|
-
}
|
|
3510
|
-
} else {
|
|
3511
|
-
let i = len;
|
|
3512
|
-
while (i--) {
|
|
3513
|
-
const nValue = node.values[i];
|
|
3514
|
-
const keys = node.keys[i];
|
|
3515
|
-
let j = keys.length;
|
|
3516
|
-
while (j--) {
|
|
3517
|
-
yield [keys[j], nValue];
|
|
3518
|
-
}
|
|
3519
|
-
}
|
|
3520
|
-
}
|
|
3521
|
-
if (nextNodePromise) {
|
|
3522
|
-
node = await nextNodePromise;
|
|
3523
|
-
nextNodePromise = null;
|
|
3524
|
-
} else {
|
|
3525
|
-
break;
|
|
3526
|
-
}
|
|
3527
|
-
}
|
|
4684
|
+
yield* getPairsGeneratorAsync(this._ops, startNode, endNode, direction);
|
|
3528
4685
|
}
|
|
4686
|
+
// ─── Lifecycle ───────────────────────────────────────────────────
|
|
3529
4687
|
async init() {
|
|
3530
4688
|
if (this.rootTx !== this) {
|
|
3531
4689
|
throw new Error("Cannot call init on a nested transaction");
|
|
@@ -3542,24 +4700,15 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3542
4700
|
this.isInitialized = true;
|
|
3543
4701
|
try {
|
|
3544
4702
|
this._clearCache();
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
this.
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
} else {
|
|
3555
|
-
const { root, order } = head;
|
|
3556
|
-
this.strategy.head = head;
|
|
3557
|
-
this.order = order;
|
|
3558
|
-
this.rootId = root;
|
|
3559
|
-
}
|
|
3560
|
-
if (this.order < 3) {
|
|
3561
|
-
throw new Error(`The 'order' parameter must be greater than 2. but got a '${this.order}'.`);
|
|
3562
|
-
}
|
|
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
|
+
);
|
|
3563
4712
|
} catch (e) {
|
|
3564
4713
|
this.isInitialized = false;
|
|
3565
4714
|
throw e;
|
|
@@ -3575,88 +4724,36 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3575
4724
|
this._resetForReload();
|
|
3576
4725
|
await this._initInternal();
|
|
3577
4726
|
}
|
|
4727
|
+
// ─── Query (delegating to algorithm) ─────────────────────────────
|
|
3578
4728
|
async exists(key, value) {
|
|
3579
|
-
|
|
3580
|
-
const { index, found } = this._binarySearchValues(node.values, value);
|
|
3581
|
-
if (found) {
|
|
3582
|
-
const keys = node.keys[index];
|
|
3583
|
-
if (keys.includes(key)) {
|
|
3584
|
-
return true;
|
|
3585
|
-
}
|
|
3586
|
-
}
|
|
3587
|
-
return false;
|
|
4729
|
+
return existsOpAsync(this._ops, this._ctx.rootId, key, value, this.comparator);
|
|
3588
4730
|
}
|
|
3589
4731
|
async get(key) {
|
|
3590
|
-
|
|
3591
|
-
while (true) {
|
|
3592
|
-
for (let i = 0, len = node.values.length; i < len; i++) {
|
|
3593
|
-
const keys = node.keys[i];
|
|
3594
|
-
for (let j = 0, len2 = keys.length; j < len2; j++) {
|
|
3595
|
-
if (keys[j] === key) {
|
|
3596
|
-
return node.values[i];
|
|
3597
|
-
}
|
|
3598
|
-
}
|
|
3599
|
-
}
|
|
3600
|
-
if (!node.next) break;
|
|
3601
|
-
node = await this.getNode(node.next);
|
|
3602
|
-
}
|
|
3603
|
-
return void 0;
|
|
4732
|
+
return getOpAsync(this._ops, this._ctx.rootId, key);
|
|
3604
4733
|
}
|
|
3605
4734
|
async *keysStream(condition, options) {
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
if (limit !== void 0 && count >= limit) {
|
|
3617
|
-
break;
|
|
3618
|
-
}
|
|
3619
|
-
}
|
|
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
|
+
);
|
|
3620
4745
|
}
|
|
3621
4746
|
async *whereStream(condition, options) {
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
} else {
|
|
3632
|
-
startNode = order === "asc" ? await this.leftestNode() : await this.rightestNode();
|
|
3633
|
-
}
|
|
3634
|
-
let endNode = null;
|
|
3635
|
-
if (resolved.endKey) {
|
|
3636
|
-
const endConfig = this.searchConfigs[resolved.endKey][order];
|
|
3637
|
-
endNode = await endConfig.end(this, resolved.endValues);
|
|
3638
|
-
}
|
|
3639
|
-
if (!startNode) return;
|
|
3640
|
-
const generator = this.getPairsGenerator(
|
|
3641
|
-
startNode,
|
|
3642
|
-
endNode,
|
|
3643
|
-
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
|
|
3644
4756
|
);
|
|
3645
|
-
let count = 0;
|
|
3646
|
-
const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
|
|
3647
|
-
for await (const pair of generator) {
|
|
3648
|
-
const [k, v] = pair;
|
|
3649
|
-
if (intersection && !intersection.has(k)) {
|
|
3650
|
-
continue;
|
|
3651
|
-
}
|
|
3652
|
-
if (this.verify(v, condition)) {
|
|
3653
|
-
yield pair;
|
|
3654
|
-
count++;
|
|
3655
|
-
if (limit !== void 0 && count >= limit) {
|
|
3656
|
-
break;
|
|
3657
|
-
}
|
|
3658
|
-
}
|
|
3659
|
-
}
|
|
3660
4757
|
}
|
|
3661
4758
|
async keys(condition, options) {
|
|
3662
4759
|
const set = /* @__PURE__ */ new Set();
|
|
@@ -3668,416 +4765,37 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
3668
4765
|
async where(condition, options) {
|
|
3669
4766
|
const map = /* @__PURE__ */ new Map();
|
|
3670
4767
|
for await (const [key, value] of this.whereStream(condition, options)) {
|
|
3671
|
-
map.set(key, value);
|
|
3672
|
-
}
|
|
3673
|
-
return map;
|
|
3674
|
-
}
|
|
3675
|
-
async insert(key, value) {
|
|
3676
|
-
return this.writeLock(0, async () => {
|
|
3677
|
-
let before = await this.locateLeaf(value);
|
|
3678
|
-
before = await this._insertAtLeaf(before, key, value);
|
|
3679
|
-
if (before.values.length === this.order) {
|
|
3680
|
-
let after = await this._createNode(
|
|
3681
|
-
true,
|
|
3682
|
-
[],
|
|
3683
|
-
[],
|
|
3684
|
-
before.parent,
|
|
3685
|
-
null,
|
|
3686
|
-
null
|
|
3687
|
-
);
|
|
3688
|
-
const mid = Math.ceil(this.order / 2) - 1;
|
|
3689
|
-
after = this._cloneNode(after);
|
|
3690
|
-
after.values = before.values.slice(mid + 1);
|
|
3691
|
-
after.keys = before.keys.slice(mid + 1);
|
|
3692
|
-
before.values = before.values.slice(0, mid + 1);
|
|
3693
|
-
before.keys = before.keys.slice(0, mid + 1);
|
|
3694
|
-
await this._updateNode(before);
|
|
3695
|
-
await this._updateNode(after);
|
|
3696
|
-
await this._insertInParent(before, after.values[0], after);
|
|
3697
|
-
}
|
|
3698
|
-
});
|
|
3699
|
-
}
|
|
3700
|
-
async batchInsert(entries) {
|
|
3701
|
-
if (entries.length === 0) return;
|
|
3702
|
-
return this.writeLock(0, async () => {
|
|
3703
|
-
const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
|
|
3704
|
-
let currentLeaf = null;
|
|
3705
|
-
let modified = false;
|
|
3706
|
-
let cachedLeafId = null;
|
|
3707
|
-
let cachedLeafMaxValue = null;
|
|
3708
|
-
for (let i = 0, len = sorted.length; i < len; i++) {
|
|
3709
|
-
const [key, value] = sorted[i];
|
|
3710
|
-
let targetLeaf;
|
|
3711
|
-
if (cachedLeafId !== null && cachedLeafMaxValue !== null && currentLeaf !== null && (this.comparator.isLower(value, cachedLeafMaxValue) || this.comparator.isSame(value, cachedLeafMaxValue))) {
|
|
3712
|
-
targetLeaf = currentLeaf;
|
|
3713
|
-
} else {
|
|
3714
|
-
targetLeaf = await this.locateLeaf(value);
|
|
3715
|
-
}
|
|
3716
|
-
if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
|
|
3717
|
-
} else {
|
|
3718
|
-
if (currentLeaf !== null && modified) {
|
|
3719
|
-
await this._updateNode(currentLeaf);
|
|
3720
|
-
}
|
|
3721
|
-
currentLeaf = this._cloneNode(targetLeaf);
|
|
3722
|
-
modified = false;
|
|
3723
|
-
}
|
|
3724
|
-
cachedLeafId = currentLeaf.id;
|
|
3725
|
-
const changed = this._insertValueIntoLeaf(currentLeaf, key, value);
|
|
3726
|
-
modified = modified || changed;
|
|
3727
|
-
cachedLeafMaxValue = currentLeaf.values[currentLeaf.values.length - 1];
|
|
3728
|
-
if (currentLeaf.values.length === this.order) {
|
|
3729
|
-
await this._updateNode(currentLeaf);
|
|
3730
|
-
let after = await this._createNode(
|
|
3731
|
-
true,
|
|
3732
|
-
[],
|
|
3733
|
-
[],
|
|
3734
|
-
currentLeaf.parent,
|
|
3735
|
-
null,
|
|
3736
|
-
null
|
|
3737
|
-
);
|
|
3738
|
-
const mid = Math.ceil(this.order / 2) - 1;
|
|
3739
|
-
after = this._cloneNode(after);
|
|
3740
|
-
after.values = currentLeaf.values.slice(mid + 1);
|
|
3741
|
-
after.keys = currentLeaf.keys.slice(mid + 1);
|
|
3742
|
-
currentLeaf.values = currentLeaf.values.slice(0, mid + 1);
|
|
3743
|
-
currentLeaf.keys = currentLeaf.keys.slice(0, mid + 1);
|
|
3744
|
-
await this._updateNode(currentLeaf);
|
|
3745
|
-
await this._updateNode(after);
|
|
3746
|
-
await this._insertInParent(currentLeaf, after.values[0], after);
|
|
3747
|
-
currentLeaf = null;
|
|
3748
|
-
cachedLeafId = null;
|
|
3749
|
-
cachedLeafMaxValue = null;
|
|
3750
|
-
modified = false;
|
|
3751
|
-
}
|
|
3752
|
-
}
|
|
3753
|
-
if (currentLeaf !== null && modified) {
|
|
3754
|
-
await this._updateNode(currentLeaf);
|
|
3755
|
-
}
|
|
3756
|
-
});
|
|
3757
|
-
}
|
|
3758
|
-
async bulkLoad(entries) {
|
|
3759
|
-
if (entries.length === 0) return;
|
|
3760
|
-
return this.writeLock(0, async () => {
|
|
3761
|
-
const root = await this.getNode(this.rootId);
|
|
3762
|
-
if (!root.leaf || root.values.length > 0) {
|
|
3763
|
-
throw new Error("bulkLoad can only be called on an empty tree. Use batchInsert for non-empty trees.");
|
|
3764
|
-
}
|
|
3765
|
-
const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
|
|
3766
|
-
const grouped = [];
|
|
3767
|
-
for (let i = 0, len = sorted.length; i < len; i++) {
|
|
3768
|
-
const [key, value] = sorted[i];
|
|
3769
|
-
const last = grouped[grouped.length - 1];
|
|
3770
|
-
if (last && this.comparator.isSame(last.value, value)) {
|
|
3771
|
-
if (!last.keys.includes(key)) {
|
|
3772
|
-
last.keys.push(key);
|
|
3773
|
-
}
|
|
3774
|
-
} else {
|
|
3775
|
-
grouped.push({ keys: [key], value });
|
|
3776
|
-
}
|
|
3777
|
-
}
|
|
3778
|
-
await this._deleteNode(root);
|
|
3779
|
-
const maxLeafSize = this.order - 1;
|
|
3780
|
-
const leaves = [];
|
|
3781
|
-
for (let i = 0, len = grouped.length; i < len; i += maxLeafSize) {
|
|
3782
|
-
const chunk = grouped.slice(i, i + maxLeafSize);
|
|
3783
|
-
const leafKeys = chunk.map((g) => g.keys);
|
|
3784
|
-
const leafValues = chunk.map((g) => g.value);
|
|
3785
|
-
const leaf = await this._createNode(
|
|
3786
|
-
true,
|
|
3787
|
-
leafKeys,
|
|
3788
|
-
leafValues,
|
|
3789
|
-
null,
|
|
3790
|
-
null,
|
|
3791
|
-
null
|
|
3792
|
-
);
|
|
3793
|
-
leaves.push(leaf);
|
|
3794
|
-
}
|
|
3795
|
-
for (let i = 0, len = leaves.length; i < len; i++) {
|
|
3796
|
-
if (i > 0) {
|
|
3797
|
-
leaves[i].prev = leaves[i - 1].id;
|
|
3798
|
-
}
|
|
3799
|
-
if (i < len - 1) {
|
|
3800
|
-
leaves[i].next = leaves[i + 1].id;
|
|
3801
|
-
}
|
|
3802
|
-
await this._updateNode(leaves[i]);
|
|
3803
|
-
}
|
|
3804
|
-
let currentLevel = leaves;
|
|
3805
|
-
while (currentLevel.length > 1) {
|
|
3806
|
-
const nextLevel = [];
|
|
3807
|
-
for (let i = 0, len = currentLevel.length; i < len; i += this.order) {
|
|
3808
|
-
const children = currentLevel.slice(i, i + this.order);
|
|
3809
|
-
const childIds = children.map((c) => c.id);
|
|
3810
|
-
const separators = [];
|
|
3811
|
-
for (let j = 1, len2 = children.length; j < len2; j++) {
|
|
3812
|
-
separators.push(children[j].values[0]);
|
|
3813
|
-
}
|
|
3814
|
-
const internalNode = await this._createNode(
|
|
3815
|
-
false,
|
|
3816
|
-
childIds,
|
|
3817
|
-
separators,
|
|
3818
|
-
null,
|
|
3819
|
-
null,
|
|
3820
|
-
null
|
|
3821
|
-
);
|
|
3822
|
-
for (let j = 0, len2 = children.length; j < len2; j++) {
|
|
3823
|
-
const child = children[j];
|
|
3824
|
-
child.parent = internalNode.id;
|
|
3825
|
-
await this._updateNode(child);
|
|
3826
|
-
}
|
|
3827
|
-
nextLevel.push(internalNode);
|
|
3828
|
-
}
|
|
3829
|
-
currentLevel = nextLevel;
|
|
3830
|
-
}
|
|
3831
|
-
const newRoot = currentLevel[0];
|
|
3832
|
-
await this._writeHead({
|
|
3833
|
-
root: newRoot.id,
|
|
3834
|
-
order: this.order,
|
|
3835
|
-
data: this.strategy.head.data
|
|
3836
|
-
});
|
|
3837
|
-
});
|
|
3838
|
-
}
|
|
3839
|
-
async _deleteEntry(node, key) {
|
|
3840
|
-
if (!node.leaf) {
|
|
3841
|
-
let keyIndex = -1;
|
|
3842
|
-
for (let i = 0, len = node.keys.length; i < len; i++) {
|
|
3843
|
-
if (node.keys[i] === key) {
|
|
3844
|
-
keyIndex = i;
|
|
3845
|
-
break;
|
|
3846
|
-
}
|
|
3847
|
-
}
|
|
3848
|
-
if (keyIndex !== -1) {
|
|
3849
|
-
node = this._cloneNode(node);
|
|
3850
|
-
node.keys.splice(keyIndex, 1);
|
|
3851
|
-
const valueIndex = keyIndex > 0 ? keyIndex - 1 : 0;
|
|
3852
|
-
node.values.splice(valueIndex, 1);
|
|
3853
|
-
await this._updateNode(node);
|
|
3854
|
-
}
|
|
3855
|
-
}
|
|
3856
|
-
if (this.rootId === node.id && node.keys.length === 1 && !node.leaf) {
|
|
3857
|
-
const keys = node.keys;
|
|
3858
|
-
this._deleteNode(node);
|
|
3859
|
-
const newRoot = this._cloneNode(await this.getNode(keys[0]));
|
|
3860
|
-
newRoot.parent = null;
|
|
3861
|
-
await this._updateNode(newRoot);
|
|
3862
|
-
await this._writeHead({
|
|
3863
|
-
root: newRoot.id,
|
|
3864
|
-
order: this.order,
|
|
3865
|
-
data: this.strategy.head.data
|
|
3866
|
-
});
|
|
3867
|
-
return node;
|
|
3868
|
-
} else if (this.rootId === node.id) {
|
|
3869
|
-
await this._writeHead({
|
|
3870
|
-
root: node.id,
|
|
3871
|
-
order: this.order,
|
|
3872
|
-
data: this.strategy.head.data
|
|
3873
|
-
});
|
|
3874
|
-
return node;
|
|
3875
|
-
} else if (node.keys.length < Math.ceil(this.order / 2) && !node.leaf || node.values.length < Math.ceil((this.order - 1) / 2) && node.leaf) {
|
|
3876
|
-
if (node.parent === null) {
|
|
3877
|
-
return node;
|
|
3878
|
-
}
|
|
3879
|
-
let isPredecessor = false;
|
|
3880
|
-
let parentNode = await this.getNode(node.parent);
|
|
3881
|
-
let prevNode = null;
|
|
3882
|
-
let nextNode = null;
|
|
3883
|
-
let prevValue = null;
|
|
3884
|
-
let postValue = null;
|
|
3885
|
-
for (let i = 0, len = parentNode.keys.length; i < len; i++) {
|
|
3886
|
-
const nKey = parentNode.keys[i];
|
|
3887
|
-
if (nKey === node.id) {
|
|
3888
|
-
if (i > 0) {
|
|
3889
|
-
prevNode = await this.getNode(parentNode.keys[i - 1]);
|
|
3890
|
-
prevValue = parentNode.values[i - 1];
|
|
3891
|
-
}
|
|
3892
|
-
if (i < parentNode.keys.length - 1) {
|
|
3893
|
-
nextNode = await this.getNode(parentNode.keys[i + 1]);
|
|
3894
|
-
postValue = parentNode.values[i];
|
|
3895
|
-
}
|
|
3896
|
-
}
|
|
3897
|
-
}
|
|
3898
|
-
let siblingNode;
|
|
3899
|
-
let guess;
|
|
3900
|
-
if (prevNode === null) {
|
|
3901
|
-
siblingNode = nextNode;
|
|
3902
|
-
guess = postValue;
|
|
3903
|
-
} else if (nextNode === null) {
|
|
3904
|
-
isPredecessor = true;
|
|
3905
|
-
siblingNode = prevNode;
|
|
3906
|
-
guess = prevValue;
|
|
3907
|
-
} else {
|
|
3908
|
-
if (node.values.length + nextNode.values.length < this.order) {
|
|
3909
|
-
siblingNode = nextNode;
|
|
3910
|
-
guess = postValue;
|
|
3911
|
-
} else {
|
|
3912
|
-
isPredecessor = true;
|
|
3913
|
-
siblingNode = prevNode;
|
|
3914
|
-
guess = prevValue;
|
|
3915
|
-
}
|
|
3916
|
-
}
|
|
3917
|
-
if (!siblingNode) {
|
|
3918
|
-
return node;
|
|
3919
|
-
}
|
|
3920
|
-
node = this._cloneNode(node);
|
|
3921
|
-
siblingNode = this._cloneNode(siblingNode);
|
|
3922
|
-
if (node.values.length + siblingNode.values.length < this.order) {
|
|
3923
|
-
if (!isPredecessor) {
|
|
3924
|
-
const pTemp = siblingNode;
|
|
3925
|
-
siblingNode = node;
|
|
3926
|
-
node = pTemp;
|
|
3927
|
-
}
|
|
3928
|
-
siblingNode.keys.push(...node.keys);
|
|
3929
|
-
if (!node.leaf) {
|
|
3930
|
-
siblingNode.values.push(guess);
|
|
3931
|
-
} else {
|
|
3932
|
-
siblingNode.next = node.next;
|
|
3933
|
-
if (siblingNode.next) {
|
|
3934
|
-
const n = this._cloneNode(await this.getNode(siblingNode.next));
|
|
3935
|
-
n.prev = siblingNode.id;
|
|
3936
|
-
await this._updateNode(n);
|
|
3937
|
-
}
|
|
3938
|
-
}
|
|
3939
|
-
siblingNode.values.push(...node.values);
|
|
3940
|
-
if (!siblingNode.leaf) {
|
|
3941
|
-
const keys = siblingNode.keys;
|
|
3942
|
-
for (let i = 0, len = keys.length; i < len; i++) {
|
|
3943
|
-
const key2 = keys[i];
|
|
3944
|
-
const node2 = this._cloneNode(await this.getNode(key2));
|
|
3945
|
-
node2.parent = siblingNode.id;
|
|
3946
|
-
await this._updateNode(node2);
|
|
3947
|
-
}
|
|
3948
|
-
}
|
|
3949
|
-
this._deleteNode(node);
|
|
3950
|
-
await this._updateNode(siblingNode);
|
|
3951
|
-
await this._deleteEntry(await this.getNode(node.parent), node.id);
|
|
3952
|
-
} else {
|
|
3953
|
-
if (isPredecessor) {
|
|
3954
|
-
let pointerPm;
|
|
3955
|
-
let pointerKm;
|
|
3956
|
-
if (!node.leaf) {
|
|
3957
|
-
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
3958
|
-
pointerKm = siblingNode.values.splice(-1)[0];
|
|
3959
|
-
node.keys = [pointerPm, ...node.keys];
|
|
3960
|
-
node.values = [guess, ...node.values];
|
|
3961
|
-
parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
3962
|
-
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
3963
|
-
if (nodeIndex > 0) {
|
|
3964
|
-
parentNode.values[nodeIndex - 1] = pointerKm;
|
|
3965
|
-
await this._updateNode(parentNode);
|
|
3966
|
-
}
|
|
3967
|
-
} else {
|
|
3968
|
-
pointerPm = siblingNode.keys.splice(-1)[0];
|
|
3969
|
-
pointerKm = siblingNode.values.splice(-1)[0];
|
|
3970
|
-
node.keys = [pointerPm, ...node.keys];
|
|
3971
|
-
node.values = [pointerKm, ...node.values];
|
|
3972
|
-
parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
3973
|
-
const nodeIndex = parentNode.keys.indexOf(node.id);
|
|
3974
|
-
if (nodeIndex > 0) {
|
|
3975
|
-
parentNode.values[nodeIndex - 1] = pointerKm;
|
|
3976
|
-
await this._updateNode(parentNode);
|
|
3977
|
-
}
|
|
3978
|
-
}
|
|
3979
|
-
await this._updateNode(node);
|
|
3980
|
-
await this._updateNode(siblingNode);
|
|
3981
|
-
} else {
|
|
3982
|
-
let pointerP0;
|
|
3983
|
-
let pointerK0;
|
|
3984
|
-
if (!node.leaf) {
|
|
3985
|
-
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
3986
|
-
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
3987
|
-
node.keys = [...node.keys, pointerP0];
|
|
3988
|
-
node.values = [...node.values, guess];
|
|
3989
|
-
parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
3990
|
-
const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
|
|
3991
|
-
if (pointerIndex > 0) {
|
|
3992
|
-
parentNode.values[pointerIndex - 1] = pointerK0;
|
|
3993
|
-
await this._updateNode(parentNode);
|
|
3994
|
-
}
|
|
3995
|
-
} else {
|
|
3996
|
-
pointerP0 = siblingNode.keys.splice(0, 1)[0];
|
|
3997
|
-
pointerK0 = siblingNode.values.splice(0, 1)[0];
|
|
3998
|
-
node.keys = [...node.keys, pointerP0];
|
|
3999
|
-
node.values = [...node.values, pointerK0];
|
|
4000
|
-
parentNode = this._cloneNode(await this.getNode(node.parent));
|
|
4001
|
-
const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
|
|
4002
|
-
if (pointerIndex > 0) {
|
|
4003
|
-
parentNode.values[pointerIndex - 1] = siblingNode.values[0];
|
|
4004
|
-
await this._updateNode(parentNode);
|
|
4005
|
-
}
|
|
4006
|
-
}
|
|
4007
|
-
await this._updateNode(node);
|
|
4008
|
-
await this._updateNode(siblingNode);
|
|
4009
|
-
}
|
|
4010
|
-
if (!siblingNode.leaf) {
|
|
4011
|
-
for (let i = 0, len = siblingNode.keys.length; i < len; i++) {
|
|
4012
|
-
const key2 = siblingNode.keys[i];
|
|
4013
|
-
const n = this._cloneNode(await this.getNode(key2));
|
|
4014
|
-
n.parent = siblingNode.id;
|
|
4015
|
-
await this._updateNode(n);
|
|
4016
|
-
}
|
|
4017
|
-
}
|
|
4018
|
-
if (!node.leaf) {
|
|
4019
|
-
for (let i = 0, len = node.keys.length; i < len; i++) {
|
|
4020
|
-
const key2 = node.keys[i];
|
|
4021
|
-
const n = this._cloneNode(await this.getNode(key2));
|
|
4022
|
-
n.parent = node.id;
|
|
4023
|
-
await this._updateNode(n);
|
|
4024
|
-
}
|
|
4025
|
-
}
|
|
4026
|
-
if (!parentNode.leaf) {
|
|
4027
|
-
for (let i = 0, len = parentNode.keys.length; i < len; i++) {
|
|
4028
|
-
const key2 = parentNode.keys[i];
|
|
4029
|
-
const n = this._cloneNode(await this.getNode(key2));
|
|
4030
|
-
n.parent = parentNode.id;
|
|
4031
|
-
await this._updateNode(n);
|
|
4032
|
-
}
|
|
4033
|
-
}
|
|
4034
|
-
}
|
|
4035
|
-
} else {
|
|
4036
|
-
await this._updateNode(this._cloneNode(node));
|
|
4768
|
+
map.set(key, value);
|
|
4037
4769
|
}
|
|
4038
|
-
return
|
|
4770
|
+
return map;
|
|
4771
|
+
}
|
|
4772
|
+
// ─── Mutation (delegating to algorithm) ──────────────────────────
|
|
4773
|
+
async insert(key, value) {
|
|
4774
|
+
return this.writeLock(0, async () => {
|
|
4775
|
+
await insertOpAsync(this._ops, this._ctx, key, value, this.comparator);
|
|
4776
|
+
});
|
|
4777
|
+
}
|
|
4778
|
+
async batchInsert(entries) {
|
|
4779
|
+
if (entries.length === 0) return;
|
|
4780
|
+
return this.writeLock(0, async () => {
|
|
4781
|
+
await batchInsertOpAsync(this._ops, this._ctx, entries, this.comparator);
|
|
4782
|
+
});
|
|
4783
|
+
}
|
|
4784
|
+
async bulkLoad(entries) {
|
|
4785
|
+
if (entries.length === 0) return;
|
|
4786
|
+
return this.writeLock(0, async () => {
|
|
4787
|
+
await bulkLoadOpAsync(this._ops, this._ctx, entries, this.comparator);
|
|
4788
|
+
});
|
|
4789
|
+
}
|
|
4790
|
+
async _deleteEntry(node, key) {
|
|
4791
|
+
return deleteEntryAsync(this._ops, this._ctx, node, key, this.comparator);
|
|
4039
4792
|
}
|
|
4040
4793
|
async delete(key, value) {
|
|
4041
4794
|
return this.writeLock(0, async () => {
|
|
4042
|
-
|
|
4043
|
-
value = await this.get(key);
|
|
4044
|
-
}
|
|
4045
|
-
if (value === void 0) {
|
|
4046
|
-
return;
|
|
4047
|
-
}
|
|
4048
|
-
let node = await this.findLowerBoundLeaf(value);
|
|
4049
|
-
let found = false;
|
|
4050
|
-
while (true) {
|
|
4051
|
-
let i = node.values.length;
|
|
4052
|
-
while (i--) {
|
|
4053
|
-
const nValue = node.values[i];
|
|
4054
|
-
if (this.comparator.isSame(value, nValue)) {
|
|
4055
|
-
const keys = node.keys[i];
|
|
4056
|
-
const keyIndex = keys.indexOf(key);
|
|
4057
|
-
if (keyIndex !== -1) {
|
|
4058
|
-
node = this._cloneNode(node);
|
|
4059
|
-
const freshKeys = node.keys[i];
|
|
4060
|
-
freshKeys.splice(keyIndex, 1);
|
|
4061
|
-
if (freshKeys.length === 0) {
|
|
4062
|
-
node.keys.splice(i, 1);
|
|
4063
|
-
node.values.splice(i, 1);
|
|
4064
|
-
}
|
|
4065
|
-
await this._updateNode(node);
|
|
4066
|
-
node = await this._deleteEntry(node, key);
|
|
4067
|
-
found = true;
|
|
4068
|
-
break;
|
|
4069
|
-
}
|
|
4070
|
-
}
|
|
4071
|
-
}
|
|
4072
|
-
if (found) break;
|
|
4073
|
-
if (node.next) {
|
|
4074
|
-
node = await this.getNode(node.next);
|
|
4075
|
-
continue;
|
|
4076
|
-
}
|
|
4077
|
-
break;
|
|
4078
|
-
}
|
|
4795
|
+
await deleteOpAsync(this._ops, this._ctx, key, this.comparator, value);
|
|
4079
4796
|
});
|
|
4080
4797
|
}
|
|
4798
|
+
// ─── Head Data ───────────────────────────────────────────────────
|
|
4081
4799
|
async getHeadData() {
|
|
4082
4800
|
const head = await this._readHead();
|
|
4083
4801
|
if (head === null) {
|
|
@@ -4096,6 +4814,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
|
|
|
4096
4814
|
data
|
|
4097
4815
|
});
|
|
4098
4816
|
}
|
|
4817
|
+
// ─── Transaction ─────────────────────────────────────────────────
|
|
4099
4818
|
async commit(label) {
|
|
4100
4819
|
let result = await this.mvcc.commit(label);
|
|
4101
4820
|
if (result.success) {
|
|
@@ -4227,6 +4946,467 @@ var BPTreeAsync = class extends BPTreeAsyncTransaction {
|
|
|
4227
4946
|
}
|
|
4228
4947
|
};
|
|
4229
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
|
+
return node;
|
|
4980
|
+
},
|
|
4981
|
+
updateNode() {
|
|
4982
|
+
},
|
|
4983
|
+
deleteNode() {
|
|
4984
|
+
},
|
|
4985
|
+
readHead() {
|
|
4986
|
+
return strategy.readHead();
|
|
4987
|
+
},
|
|
4988
|
+
writeHead() {
|
|
4989
|
+
}
|
|
4990
|
+
};
|
|
4991
|
+
}
|
|
4992
|
+
_createBufferedOps() {
|
|
4993
|
+
const strategy = this.strategy;
|
|
4994
|
+
const writeBuffer = /* @__PURE__ */ new Map();
|
|
4995
|
+
const deleteBuffer = /* @__PURE__ */ new Set();
|
|
4996
|
+
let headBuffer = null;
|
|
4997
|
+
const ops = {
|
|
4998
|
+
getNode(id) {
|
|
4999
|
+
const buffered = writeBuffer.get(id);
|
|
5000
|
+
if (buffered) return buffered;
|
|
5001
|
+
return strategy.read(id);
|
|
5002
|
+
},
|
|
5003
|
+
createNode(leaf, keys, values, parent = null, next = null, prev = null) {
|
|
5004
|
+
const id = strategy.id(leaf);
|
|
5005
|
+
const node = { id, keys, values, leaf, parent, next, prev };
|
|
5006
|
+
writeBuffer.set(id, node);
|
|
5007
|
+
return node;
|
|
5008
|
+
},
|
|
5009
|
+
updateNode(node) {
|
|
5010
|
+
writeBuffer.set(node.id, node);
|
|
5011
|
+
},
|
|
5012
|
+
deleteNode(node) {
|
|
5013
|
+
deleteBuffer.add(node.id);
|
|
5014
|
+
writeBuffer.delete(node.id);
|
|
5015
|
+
},
|
|
5016
|
+
readHead() {
|
|
5017
|
+
if (headBuffer) return headBuffer;
|
|
5018
|
+
return strategy.readHead();
|
|
5019
|
+
},
|
|
5020
|
+
writeHead(head) {
|
|
5021
|
+
headBuffer = head;
|
|
5022
|
+
}
|
|
5023
|
+
};
|
|
5024
|
+
function flush() {
|
|
5025
|
+
for (const id of deleteBuffer) {
|
|
5026
|
+
strategy.delete(id);
|
|
5027
|
+
}
|
|
5028
|
+
for (const [id, node] of writeBuffer) {
|
|
5029
|
+
strategy.write(id, node);
|
|
5030
|
+
}
|
|
5031
|
+
if (headBuffer) {
|
|
5032
|
+
strategy.writeHead(headBuffer);
|
|
5033
|
+
}
|
|
5034
|
+
}
|
|
5035
|
+
return { ops, flush };
|
|
5036
|
+
}
|
|
5037
|
+
init() {
|
|
5038
|
+
const { ops, flush } = this._createBufferedOps();
|
|
5039
|
+
this._ctx = {
|
|
5040
|
+
rootId: "",
|
|
5041
|
+
order: this.strategy.order,
|
|
5042
|
+
headData: () => this.strategy.head.data
|
|
5043
|
+
};
|
|
5044
|
+
initOp(
|
|
5045
|
+
ops,
|
|
5046
|
+
this._ctx,
|
|
5047
|
+
this.strategy.order,
|
|
5048
|
+
this.strategy.head,
|
|
5049
|
+
(head) => {
|
|
5050
|
+
this.strategy.head = head;
|
|
5051
|
+
}
|
|
5052
|
+
);
|
|
5053
|
+
flush();
|
|
5054
|
+
this._ops = this._createOps();
|
|
5055
|
+
}
|
|
5056
|
+
/**
|
|
5057
|
+
* Returns the ID of the root node.
|
|
5058
|
+
*/
|
|
5059
|
+
getRootId() {
|
|
5060
|
+
return this._ctx.rootId;
|
|
5061
|
+
}
|
|
5062
|
+
/**
|
|
5063
|
+
* Returns the order of the B+Tree.
|
|
5064
|
+
*/
|
|
5065
|
+
getOrder() {
|
|
5066
|
+
return this._ctx.order;
|
|
5067
|
+
}
|
|
5068
|
+
/**
|
|
5069
|
+
* Verified if the value satisfies the condition.
|
|
5070
|
+
*/
|
|
5071
|
+
verify(nodeValue, condition) {
|
|
5072
|
+
for (const key in condition) {
|
|
5073
|
+
const verifyFn = this._verifierMap[key];
|
|
5074
|
+
const condValue = condition[key];
|
|
5075
|
+
if (!verifyFn(nodeValue, condValue)) {
|
|
5076
|
+
return false;
|
|
5077
|
+
}
|
|
5078
|
+
}
|
|
5079
|
+
return true;
|
|
5080
|
+
}
|
|
5081
|
+
// ─── Query ───────────────────────────────────────────────────────
|
|
5082
|
+
get(key) {
|
|
5083
|
+
return getOp(this._ops, this._ctx.rootId, key);
|
|
5084
|
+
}
|
|
5085
|
+
exists(key, value) {
|
|
5086
|
+
return existsOp(this._ops, this._ctx.rootId, key, value, this.comparator);
|
|
5087
|
+
}
|
|
5088
|
+
*keysStream(condition, options) {
|
|
5089
|
+
yield* keysStreamOp(
|
|
5090
|
+
this._ops,
|
|
5091
|
+
this._ctx.rootId,
|
|
5092
|
+
condition,
|
|
5093
|
+
this.comparator,
|
|
5094
|
+
this._verifierMap,
|
|
5095
|
+
this._searchConfigs,
|
|
5096
|
+
this._ensureValues,
|
|
5097
|
+
options
|
|
5098
|
+
);
|
|
5099
|
+
}
|
|
5100
|
+
*whereStream(condition, options) {
|
|
5101
|
+
yield* whereStreamOp(
|
|
5102
|
+
this._ops,
|
|
5103
|
+
this._ctx.rootId,
|
|
5104
|
+
condition,
|
|
5105
|
+
this.comparator,
|
|
5106
|
+
this._verifierMap,
|
|
5107
|
+
this._searchConfigs,
|
|
5108
|
+
this._ensureValues,
|
|
5109
|
+
options
|
|
5110
|
+
);
|
|
5111
|
+
}
|
|
5112
|
+
keys(condition, options) {
|
|
5113
|
+
const set = /* @__PURE__ */ new Set();
|
|
5114
|
+
for (const key of this.keysStream(condition, options)) {
|
|
5115
|
+
set.add(key);
|
|
5116
|
+
}
|
|
5117
|
+
return set;
|
|
5118
|
+
}
|
|
5119
|
+
where(condition, options) {
|
|
5120
|
+
const map = /* @__PURE__ */ new Map();
|
|
5121
|
+
for (const [key, value] of this.whereStream(condition, options)) {
|
|
5122
|
+
map.set(key, value);
|
|
5123
|
+
}
|
|
5124
|
+
return map;
|
|
5125
|
+
}
|
|
5126
|
+
// ─── Mutation ────────────────────────────────────────────────────
|
|
5127
|
+
insert(key, value) {
|
|
5128
|
+
const { ops, flush } = this._createBufferedOps();
|
|
5129
|
+
insertOp(ops, this._ctx, key, value, this.comparator);
|
|
5130
|
+
flush();
|
|
5131
|
+
}
|
|
5132
|
+
delete(key, value) {
|
|
5133
|
+
const { ops, flush } = this._createBufferedOps();
|
|
5134
|
+
deleteOp(ops, this._ctx, key, this.comparator, value);
|
|
5135
|
+
flush();
|
|
5136
|
+
}
|
|
5137
|
+
batchInsert(entries) {
|
|
5138
|
+
const { ops, flush } = this._createBufferedOps();
|
|
5139
|
+
batchInsertOp(ops, this._ctx, entries, this.comparator);
|
|
5140
|
+
flush();
|
|
5141
|
+
}
|
|
5142
|
+
bulkLoad(entries) {
|
|
5143
|
+
const { ops, flush } = this._createBufferedOps();
|
|
5144
|
+
bulkLoadOp(ops, this._ctx, entries, this.comparator);
|
|
5145
|
+
flush();
|
|
5146
|
+
}
|
|
5147
|
+
// ─── Head Data ───────────────────────────────────────────────────
|
|
5148
|
+
getHeadData() {
|
|
5149
|
+
const head = this._ops.readHead();
|
|
5150
|
+
if (head === null) {
|
|
5151
|
+
throw new Error("Head not found");
|
|
5152
|
+
}
|
|
5153
|
+
return head.data;
|
|
5154
|
+
}
|
|
5155
|
+
setHeadData(data) {
|
|
5156
|
+
const { ops, flush } = this._createBufferedOps();
|
|
5157
|
+
const head = ops.readHead();
|
|
5158
|
+
if (head === null) {
|
|
5159
|
+
throw new Error("Head not found");
|
|
5160
|
+
}
|
|
5161
|
+
ops.writeHead({
|
|
5162
|
+
root: head.root,
|
|
5163
|
+
order: head.order,
|
|
5164
|
+
data
|
|
5165
|
+
});
|
|
5166
|
+
flush();
|
|
5167
|
+
}
|
|
5168
|
+
// ─── Static utilities ────────────────────────────────────────────
|
|
5169
|
+
static ChooseDriver = BPTreeTransaction.ChooseDriver;
|
|
5170
|
+
};
|
|
5171
|
+
|
|
5172
|
+
// src/BPTreePureAsync.ts
|
|
5173
|
+
var BPTreePureAsync = class {
|
|
5174
|
+
strategy;
|
|
5175
|
+
comparator;
|
|
5176
|
+
option;
|
|
5177
|
+
lock = new Ryoiki2();
|
|
5178
|
+
_cachedRegexp = /* @__PURE__ */ new Map();
|
|
5179
|
+
_ctx;
|
|
5180
|
+
_ops;
|
|
5181
|
+
_verifierMap;
|
|
5182
|
+
_searchConfigs;
|
|
5183
|
+
constructor(strategy, comparator, option) {
|
|
5184
|
+
this.strategy = strategy;
|
|
5185
|
+
this.comparator = comparator;
|
|
5186
|
+
this.option = option ?? {};
|
|
5187
|
+
const ensureValues = (v) => Array.isArray(v) ? v : [v];
|
|
5188
|
+
this._verifierMap = createVerifierMap(comparator, this._cachedRegexp, ensureValues);
|
|
5189
|
+
this._searchConfigs = createSearchConfigsAsync(comparator, ensureValues);
|
|
5190
|
+
}
|
|
5191
|
+
_ensureValues(v) {
|
|
5192
|
+
return Array.isArray(v) ? v : [v];
|
|
5193
|
+
}
|
|
5194
|
+
_createOps() {
|
|
5195
|
+
const strategy = this.strategy;
|
|
5196
|
+
return {
|
|
5197
|
+
async getNode(id) {
|
|
5198
|
+
return await strategy.read(id);
|
|
5199
|
+
},
|
|
5200
|
+
async createNode(leaf, keys, values, parent = null, next = null, prev = null) {
|
|
5201
|
+
const id = await strategy.id(leaf);
|
|
5202
|
+
const node = { id, keys, values, leaf, parent, next, prev };
|
|
5203
|
+
return node;
|
|
5204
|
+
},
|
|
5205
|
+
async updateNode() {
|
|
5206
|
+
},
|
|
5207
|
+
async deleteNode() {
|
|
5208
|
+
},
|
|
5209
|
+
async readHead() {
|
|
5210
|
+
return await strategy.readHead();
|
|
5211
|
+
},
|
|
5212
|
+
async writeHead() {
|
|
5213
|
+
}
|
|
5214
|
+
};
|
|
5215
|
+
}
|
|
5216
|
+
_createBufferedOps() {
|
|
5217
|
+
const strategy = this.strategy;
|
|
5218
|
+
const writeBuffer = /* @__PURE__ */ new Map();
|
|
5219
|
+
const deleteBuffer = /* @__PURE__ */ new Set();
|
|
5220
|
+
let headBuffer = null;
|
|
5221
|
+
const ops = {
|
|
5222
|
+
async getNode(id) {
|
|
5223
|
+
const buffered = writeBuffer.get(id);
|
|
5224
|
+
if (buffered) return buffered;
|
|
5225
|
+
return await strategy.read(id);
|
|
5226
|
+
},
|
|
5227
|
+
async createNode(leaf, keys, values, parent = null, next = null, prev = null) {
|
|
5228
|
+
const id = await strategy.id(leaf);
|
|
5229
|
+
const node = { id, keys, values, leaf, parent, next, prev };
|
|
5230
|
+
writeBuffer.set(id, node);
|
|
5231
|
+
return node;
|
|
5232
|
+
},
|
|
5233
|
+
async updateNode(node) {
|
|
5234
|
+
writeBuffer.set(node.id, node);
|
|
5235
|
+
},
|
|
5236
|
+
async deleteNode(node) {
|
|
5237
|
+
deleteBuffer.add(node.id);
|
|
5238
|
+
writeBuffer.delete(node.id);
|
|
5239
|
+
},
|
|
5240
|
+
async readHead() {
|
|
5241
|
+
if (headBuffer) return headBuffer;
|
|
5242
|
+
return await strategy.readHead();
|
|
5243
|
+
},
|
|
5244
|
+
async writeHead(head) {
|
|
5245
|
+
headBuffer = head;
|
|
5246
|
+
}
|
|
5247
|
+
};
|
|
5248
|
+
async function flush() {
|
|
5249
|
+
for (const id of deleteBuffer) {
|
|
5250
|
+
await strategy.delete(id);
|
|
5251
|
+
}
|
|
5252
|
+
for (const [id, node] of writeBuffer) {
|
|
5253
|
+
await strategy.write(id, node);
|
|
5254
|
+
}
|
|
5255
|
+
if (headBuffer) {
|
|
5256
|
+
await strategy.writeHead(headBuffer);
|
|
5257
|
+
}
|
|
5258
|
+
}
|
|
5259
|
+
return { ops, flush };
|
|
5260
|
+
}
|
|
5261
|
+
async writeLock(fn) {
|
|
5262
|
+
let lockId;
|
|
5263
|
+
return this.lock.writeLock(async (_lockId) => {
|
|
5264
|
+
lockId = _lockId;
|
|
5265
|
+
return fn();
|
|
5266
|
+
}).finally(() => {
|
|
5267
|
+
this.lock.writeUnlock(lockId);
|
|
5268
|
+
});
|
|
5269
|
+
}
|
|
5270
|
+
async init() {
|
|
5271
|
+
return this.writeLock(async () => {
|
|
5272
|
+
const { ops, flush } = this._createBufferedOps();
|
|
5273
|
+
this._ctx = {
|
|
5274
|
+
rootId: "",
|
|
5275
|
+
order: this.strategy.order,
|
|
5276
|
+
headData: () => this.strategy.head.data
|
|
5277
|
+
};
|
|
5278
|
+
await initOpAsync(
|
|
5279
|
+
ops,
|
|
5280
|
+
this._ctx,
|
|
5281
|
+
this.strategy.order,
|
|
5282
|
+
this.strategy.head,
|
|
5283
|
+
(head) => {
|
|
5284
|
+
this.strategy.head = head;
|
|
5285
|
+
}
|
|
5286
|
+
);
|
|
5287
|
+
await flush();
|
|
5288
|
+
this._ops = this._createOps();
|
|
5289
|
+
});
|
|
5290
|
+
}
|
|
5291
|
+
getRootId() {
|
|
5292
|
+
return this._ctx.rootId;
|
|
5293
|
+
}
|
|
5294
|
+
getOrder() {
|
|
5295
|
+
return this._ctx.order;
|
|
5296
|
+
}
|
|
5297
|
+
verify(nodeValue, condition) {
|
|
5298
|
+
for (const key in condition) {
|
|
5299
|
+
const verifyFn = this._verifierMap[key];
|
|
5300
|
+
const condValue = condition[key];
|
|
5301
|
+
if (!verifyFn(nodeValue, condValue)) return false;
|
|
5302
|
+
}
|
|
5303
|
+
return true;
|
|
5304
|
+
}
|
|
5305
|
+
// ─── Query ───────────────────────────────────────────────────────
|
|
5306
|
+
async get(key) {
|
|
5307
|
+
return getOpAsync(this._ops, this._ctx.rootId, key);
|
|
5308
|
+
}
|
|
5309
|
+
async exists(key, value) {
|
|
5310
|
+
return existsOpAsync(this._ops, this._ctx.rootId, key, value, this.comparator);
|
|
5311
|
+
}
|
|
5312
|
+
async *keysStream(condition, options) {
|
|
5313
|
+
let lockId;
|
|
5314
|
+
try {
|
|
5315
|
+
lockId = await this.lock.readLock([0, 0.1], async (id) => id);
|
|
5316
|
+
yield* keysStreamOpAsync(
|
|
5317
|
+
this._ops,
|
|
5318
|
+
this._ctx.rootId,
|
|
5319
|
+
condition,
|
|
5320
|
+
this.comparator,
|
|
5321
|
+
this._verifierMap,
|
|
5322
|
+
this._searchConfigs,
|
|
5323
|
+
this._ensureValues,
|
|
5324
|
+
options
|
|
5325
|
+
);
|
|
5326
|
+
} finally {
|
|
5327
|
+
if (lockId) this.lock.readUnlock(lockId);
|
|
5328
|
+
}
|
|
5329
|
+
}
|
|
5330
|
+
async *whereStream(condition, options) {
|
|
5331
|
+
let lockId;
|
|
5332
|
+
try {
|
|
5333
|
+
lockId = await this.lock.readLock([0, 0.1], async (id) => id);
|
|
5334
|
+
yield* whereStreamOpAsync(
|
|
5335
|
+
this._ops,
|
|
5336
|
+
this._ctx.rootId,
|
|
5337
|
+
condition,
|
|
5338
|
+
this.comparator,
|
|
5339
|
+
this._verifierMap,
|
|
5340
|
+
this._searchConfigs,
|
|
5341
|
+
this._ensureValues,
|
|
5342
|
+
options
|
|
5343
|
+
);
|
|
5344
|
+
} finally {
|
|
5345
|
+
if (lockId) this.lock.readUnlock(lockId);
|
|
5346
|
+
}
|
|
5347
|
+
}
|
|
5348
|
+
async keys(condition, options) {
|
|
5349
|
+
const set = /* @__PURE__ */ new Set();
|
|
5350
|
+
for await (const key of this.keysStream(condition, options)) {
|
|
5351
|
+
set.add(key);
|
|
5352
|
+
}
|
|
5353
|
+
return set;
|
|
5354
|
+
}
|
|
5355
|
+
async where(condition, options) {
|
|
5356
|
+
const map = /* @__PURE__ */ new Map();
|
|
5357
|
+
for await (const [key, value] of this.whereStream(condition, options)) {
|
|
5358
|
+
map.set(key, value);
|
|
5359
|
+
}
|
|
5360
|
+
return map;
|
|
5361
|
+
}
|
|
5362
|
+
// ─── Mutation ────────────────────────────────────────────────────
|
|
5363
|
+
async insert(key, value) {
|
|
5364
|
+
return this.writeLock(async () => {
|
|
5365
|
+
const { ops, flush } = this._createBufferedOps();
|
|
5366
|
+
await insertOpAsync(ops, this._ctx, key, value, this.comparator);
|
|
5367
|
+
await flush();
|
|
5368
|
+
});
|
|
5369
|
+
}
|
|
5370
|
+
async delete(key, value) {
|
|
5371
|
+
return this.writeLock(async () => {
|
|
5372
|
+
const { ops, flush } = this._createBufferedOps();
|
|
5373
|
+
await deleteOpAsync(ops, this._ctx, key, this.comparator, value);
|
|
5374
|
+
await flush();
|
|
5375
|
+
});
|
|
5376
|
+
}
|
|
5377
|
+
async batchInsert(entries) {
|
|
5378
|
+
return this.writeLock(async () => {
|
|
5379
|
+
const { ops, flush } = this._createBufferedOps();
|
|
5380
|
+
await batchInsertOpAsync(ops, this._ctx, entries, this.comparator);
|
|
5381
|
+
await flush();
|
|
5382
|
+
});
|
|
5383
|
+
}
|
|
5384
|
+
async bulkLoad(entries) {
|
|
5385
|
+
return this.writeLock(async () => {
|
|
5386
|
+
const { ops, flush } = this._createBufferedOps();
|
|
5387
|
+
await bulkLoadOpAsync(ops, this._ctx, entries, this.comparator);
|
|
5388
|
+
await flush();
|
|
5389
|
+
});
|
|
5390
|
+
}
|
|
5391
|
+
// ─── Head Data ───────────────────────────────────────────────────
|
|
5392
|
+
async getHeadData() {
|
|
5393
|
+
const head = await this._ops.readHead();
|
|
5394
|
+
if (head === null) throw new Error("Head not found");
|
|
5395
|
+
return head.data;
|
|
5396
|
+
}
|
|
5397
|
+
async setHeadData(data) {
|
|
5398
|
+
return this.writeLock(async () => {
|
|
5399
|
+
const { ops, flush } = this._createBufferedOps();
|
|
5400
|
+
const head = await ops.readHead();
|
|
5401
|
+
if (head === null) throw new Error("Head not found");
|
|
5402
|
+
await ops.writeHead({ root: head.root, order: head.order, data });
|
|
5403
|
+
await flush();
|
|
5404
|
+
});
|
|
5405
|
+
}
|
|
5406
|
+
// ─── Static utilities ────────────────────────────────────────────
|
|
5407
|
+
static ChooseDriver = BPTreeTransaction.ChooseDriver;
|
|
5408
|
+
};
|
|
5409
|
+
|
|
4230
5410
|
// src/base/SerializeStrategy.ts
|
|
4231
5411
|
var SerializeStrategy = class {
|
|
4232
5412
|
order;
|
|
@@ -4357,6 +5537,8 @@ var InMemoryStoreStrategyAsync = class extends SerializeStrategyAsync {
|
|
|
4357
5537
|
export {
|
|
4358
5538
|
BPTreeAsync,
|
|
4359
5539
|
BPTreeAsyncTransaction,
|
|
5540
|
+
BPTreePureAsync,
|
|
5541
|
+
BPTreePureSync,
|
|
4360
5542
|
BPTreeSync,
|
|
4361
5543
|
BPTreeSyncTransaction,
|
|
4362
5544
|
InMemoryStoreStrategyAsync,
|