document-dataply 0.0.9-alpha.5 → 0.0.9-alpha.6

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.
Files changed (2) hide show
  1. package/dist/cjs/index.js +284 -107
  2. package/package.json +2 -2
package/dist/cjs/index.js CHANGED
@@ -1580,83 +1580,217 @@ var require_cjs = __commonJS({
1580
1580
  return regexp.test(nodeValue);
1581
1581
  }
1582
1582
  };
1583
- verifierStartNode = {
1584
- gt: (v) => this.insertableNodeByPrimary(v),
1585
- gte: (v) => this.insertableNodeByPrimary(v),
1586
- lt: (v) => this.insertableNodeByPrimary(v),
1587
- lte: (v) => this.insertableRightestNodeByPrimary(v),
1588
- equal: (v) => this.insertableNodeByPrimary(v),
1589
- notEqual: (v) => this.leftestNode(),
1590
- or: (v) => this.insertableNodeByPrimary(this.lowestPrimaryValue(this.ensureValues(v))),
1591
- primaryGt: (v) => this.insertableNodeByPrimary(v),
1592
- primaryGte: (v) => this.insertableNodeByPrimary(v),
1593
- primaryLt: (v) => this.insertableNodeByPrimary(v),
1594
- primaryLte: (v) => this.insertableRightestNodeByPrimary(v),
1595
- primaryEqual: (v) => this.insertableNodeByPrimary(v),
1596
- primaryNotEqual: (v) => this.leftestNode(),
1597
- primaryOr: (v) => this.insertableNodeByPrimary(this.lowestPrimaryValue(this.ensureValues(v))),
1598
- like: (v) => this.leftestNode()
1599
- };
1600
- verifierEndNode = {
1601
- gt: (v) => null,
1602
- gte: (v) => null,
1603
- lt: (v) => null,
1604
- lte: (v) => null,
1605
- equal: (v) => this.insertableEndNode(v, this.verifierDirection.equal),
1606
- notEqual: (v) => null,
1607
- or: (v) => this.insertableEndNode(
1608
- this.highestValue(this.ensureValues(v)),
1609
- this.verifierDirection.or
1610
- ),
1611
- primaryGt: (v) => null,
1612
- primaryGte: (v) => null,
1613
- primaryLt: (v) => null,
1614
- primaryLte: (v) => null,
1615
- primaryEqual: (v) => this.insertableRightestEndNodeByPrimary(v),
1616
- primaryNotEqual: (v) => null,
1617
- primaryOr: (v) => this.insertableRightestEndNodeByPrimary(
1618
- this.highestPrimaryValue(this.ensureValues(v))
1619
- ),
1620
- like: (v) => null
1621
- };
1622
- verifierDirection = {
1623
- gt: 1,
1624
- gte: 1,
1625
- lt: -1,
1626
- lte: -1,
1627
- equal: 1,
1628
- notEqual: 1,
1629
- or: 1,
1630
- primaryGt: 1,
1631
- primaryGte: 1,
1632
- primaryLt: -1,
1633
- primaryLte: -1,
1634
- primaryEqual: 1,
1635
- primaryNotEqual: 1,
1636
- primaryOr: 1,
1637
- like: 1
1638
- };
1639
- /**
1640
- * Determines whether early termination is allowed for each condition.
1641
- * When true, the search will stop once a match is found and then a non-match is encountered.
1642
- * Only applicable for conditions that guarantee contiguous matches in a sorted B+Tree.
1643
- */
1644
- verifierEarlyTerminate = {
1645
- gt: false,
1646
- gte: false,
1647
- lt: false,
1648
- lte: false,
1649
- equal: true,
1650
- notEqual: false,
1651
- or: false,
1652
- primaryGt: false,
1653
- primaryGte: false,
1654
- primaryLt: false,
1655
- primaryLte: false,
1656
- primaryEqual: true,
1657
- primaryNotEqual: false,
1658
- primaryOr: false,
1659
- like: false
1583
+ searchConfigs = {
1584
+ gt: {
1585
+ asc: {
1586
+ start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
1587
+ end: () => null,
1588
+ direction: 1,
1589
+ earlyTerminate: false
1590
+ },
1591
+ desc: {
1592
+ start: (tx) => tx.rightestNode(),
1593
+ end: (tx, v) => tx.insertableEndNode(v[0], -1),
1594
+ direction: -1,
1595
+ earlyTerminate: true
1596
+ }
1597
+ },
1598
+ gte: {
1599
+ asc: {
1600
+ start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
1601
+ end: () => null,
1602
+ direction: 1,
1603
+ earlyTerminate: false
1604
+ },
1605
+ desc: {
1606
+ start: (tx) => tx.rightestNode(),
1607
+ end: (tx, v) => tx.insertableEndNode(v[0], -1),
1608
+ direction: -1,
1609
+ earlyTerminate: true
1610
+ }
1611
+ },
1612
+ lt: {
1613
+ asc: {
1614
+ start: (tx) => tx.leftestNode(),
1615
+ end: (tx, v) => tx.insertableEndNode(v[0], 1),
1616
+ direction: 1,
1617
+ earlyTerminate: true
1618
+ },
1619
+ desc: {
1620
+ start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
1621
+ end: () => null,
1622
+ direction: -1,
1623
+ earlyTerminate: false
1624
+ }
1625
+ },
1626
+ lte: {
1627
+ asc: {
1628
+ start: (tx) => tx.leftestNode(),
1629
+ end: (tx, v) => tx.insertableEndNode(v[0], 1),
1630
+ direction: 1,
1631
+ earlyTerminate: true
1632
+ },
1633
+ desc: {
1634
+ start: (tx, v) => tx.insertableRightestNodeByPrimary(v[0]),
1635
+ end: () => null,
1636
+ direction: -1,
1637
+ earlyTerminate: false
1638
+ }
1639
+ },
1640
+ equal: {
1641
+ asc: {
1642
+ start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
1643
+ end: (tx, v) => tx.insertableEndNode(v[0], 1),
1644
+ direction: 1,
1645
+ earlyTerminate: true
1646
+ },
1647
+ desc: {
1648
+ start: (tx, v) => tx.insertableEndNode(v[0], 1),
1649
+ end: (tx, v) => tx.insertableEndNode(v[0], -1),
1650
+ direction: -1,
1651
+ earlyTerminate: true
1652
+ }
1653
+ },
1654
+ notEqual: {
1655
+ asc: {
1656
+ start: (tx) => tx.leftestNode(),
1657
+ end: () => null,
1658
+ direction: 1,
1659
+ earlyTerminate: false
1660
+ },
1661
+ desc: {
1662
+ start: (tx) => tx.rightestNode(),
1663
+ end: () => null,
1664
+ direction: -1,
1665
+ earlyTerminate: false
1666
+ }
1667
+ },
1668
+ or: {
1669
+ asc: {
1670
+ start: (tx, v) => tx.insertableNodeByPrimary(tx.lowestValue(v)),
1671
+ end: (tx, v) => tx.insertableEndNode(tx.highestValue(v), 1),
1672
+ direction: 1,
1673
+ earlyTerminate: false
1674
+ },
1675
+ desc: {
1676
+ start: (tx, v) => tx.insertableEndNode(tx.highestValue(v), 1),
1677
+ end: (tx, v) => tx.insertableEndNode(tx.lowestValue(v), -1),
1678
+ direction: -1,
1679
+ earlyTerminate: false
1680
+ }
1681
+ },
1682
+ primaryGt: {
1683
+ asc: {
1684
+ start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
1685
+ end: () => null,
1686
+ direction: 1,
1687
+ earlyTerminate: false
1688
+ },
1689
+ desc: {
1690
+ start: (tx) => tx.rightestNode(),
1691
+ end: (tx, v) => tx.insertableEndNode(v[0], -1),
1692
+ direction: -1,
1693
+ earlyTerminate: true
1694
+ }
1695
+ },
1696
+ primaryGte: {
1697
+ asc: {
1698
+ start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
1699
+ end: () => null,
1700
+ direction: 1,
1701
+ earlyTerminate: false
1702
+ },
1703
+ desc: {
1704
+ start: (tx) => tx.rightestNode(),
1705
+ end: (tx, v) => tx.insertableEndNode(v[0], -1),
1706
+ direction: -1,
1707
+ earlyTerminate: true
1708
+ }
1709
+ },
1710
+ primaryLt: {
1711
+ asc: {
1712
+ start: (tx) => tx.leftestNode(),
1713
+ end: (tx, v) => tx.insertableEndNode(v[0], 1),
1714
+ direction: 1,
1715
+ earlyTerminate: true
1716
+ },
1717
+ desc: {
1718
+ start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
1719
+ end: () => null,
1720
+ direction: -1,
1721
+ earlyTerminate: false
1722
+ }
1723
+ },
1724
+ primaryLte: {
1725
+ asc: {
1726
+ start: (tx) => tx.leftestNode(),
1727
+ end: (tx, v) => tx.insertableEndNode(v[0], 1),
1728
+ direction: 1,
1729
+ earlyTerminate: true
1730
+ },
1731
+ desc: {
1732
+ start: (tx, v) => tx.insertableRightestNodeByPrimary(v[0]),
1733
+ end: () => null,
1734
+ direction: -1,
1735
+ earlyTerminate: false
1736
+ }
1737
+ },
1738
+ primaryEqual: {
1739
+ asc: {
1740
+ start: (tx, v) => tx.insertableNodeByPrimary(v[0]),
1741
+ end: (tx, v) => tx.insertableRightestEndNodeByPrimary(v[0]),
1742
+ direction: 1,
1743
+ earlyTerminate: true
1744
+ },
1745
+ desc: {
1746
+ start: (tx, v) => tx.insertableRightestEndNodeByPrimary(v[0]),
1747
+ end: (tx, v) => tx.insertableEndNode(v[0], -1),
1748
+ direction: -1,
1749
+ earlyTerminate: true
1750
+ }
1751
+ },
1752
+ primaryNotEqual: {
1753
+ asc: {
1754
+ start: (tx) => tx.leftestNode(),
1755
+ end: () => null,
1756
+ direction: 1,
1757
+ earlyTerminate: false
1758
+ },
1759
+ desc: {
1760
+ start: (tx) => tx.rightestNode(),
1761
+ end: () => null,
1762
+ direction: -1,
1763
+ earlyTerminate: false
1764
+ }
1765
+ },
1766
+ primaryOr: {
1767
+ asc: {
1768
+ start: (tx, v) => tx.insertableNodeByPrimary(tx.lowestPrimaryValue(v)),
1769
+ end: (tx, v) => tx.insertableRightestEndNodeByPrimary(tx.highestPrimaryValue(v)),
1770
+ direction: 1,
1771
+ earlyTerminate: false
1772
+ },
1773
+ desc: {
1774
+ start: (tx, v) => tx.insertableRightestEndNodeByPrimary(tx.highestPrimaryValue(v)),
1775
+ end: (tx, v) => tx.insertableEndNode(tx.lowestPrimaryValue(v), -1),
1776
+ direction: -1,
1777
+ earlyTerminate: false
1778
+ }
1779
+ },
1780
+ like: {
1781
+ asc: {
1782
+ start: (tx) => tx.leftestNode(),
1783
+ end: () => null,
1784
+ direction: 1,
1785
+ earlyTerminate: false
1786
+ },
1787
+ desc: {
1788
+ start: (tx) => tx.rightestNode(),
1789
+ end: () => null,
1790
+ direction: -1,
1791
+ earlyTerminate: false
1792
+ }
1793
+ }
1660
1794
  };
1661
1795
  /**
1662
1796
  * Priority map for condition types.
@@ -2267,16 +2401,20 @@ var require_cjs = __commonJS({
2267
2401
  const driverKey = this.getDriverKey(condition);
2268
2402
  if (!driverKey) return;
2269
2403
  const value = condition[driverKey];
2270
- let startNode = this.verifierStartNode[driverKey](value);
2271
- let endNode = this.verifierEndNode[driverKey](value);
2272
- let direction = this.verifierDirection[driverKey];
2404
+ const v = this.ensureValues(value);
2405
+ const config = this.searchConfigs[driverKey][order];
2406
+ let startNode = config.start(this, v);
2407
+ let endNode = config.end(this, v);
2408
+ const direction = config.direction;
2409
+ const earlyTerminate = config.earlyTerminate;
2410
+ if (order === "desc" && !startNode) {
2411
+ startNode = this.rightestNode();
2412
+ }
2413
+ if (order === "asc" && !startNode) {
2414
+ startNode = this.leftestNode();
2415
+ }
2416
+ if (!startNode) return;
2273
2417
  const comparator = this.verifierMap[driverKey];
2274
- const earlyTerminate = this.verifierEarlyTerminate[driverKey];
2275
- if (order === "desc") {
2276
- startNode = endNode ?? this.rightestNode();
2277
- endNode = null;
2278
- direction *= -1;
2279
- }
2280
2418
  const generator = this.getPairsGenerator(
2281
2419
  value,
2282
2420
  startNode,
@@ -2288,7 +2426,7 @@ var require_cjs = __commonJS({
2288
2426
  let count = 0;
2289
2427
  const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
2290
2428
  for (const pair of generator) {
2291
- const [k, v] = pair;
2429
+ const [k, v2] = pair;
2292
2430
  if (intersection && !intersection.has(k)) {
2293
2431
  continue;
2294
2432
  }
@@ -2297,7 +2435,7 @@ var require_cjs = __commonJS({
2297
2435
  if (key === driverKey) continue;
2298
2436
  const verify = this.verifierMap[key];
2299
2437
  const condValue = condition[key];
2300
- if (!verify(v, condValue)) {
2438
+ if (!verify(v2, condValue)) {
2301
2439
  isMatch = false;
2302
2440
  break;
2303
2441
  }
@@ -3397,16 +3535,20 @@ var require_cjs = __commonJS({
3397
3535
  const driverKey = this.getDriverKey(condition);
3398
3536
  if (!driverKey) return;
3399
3537
  const value = condition[driverKey];
3400
- let startNode = await this.verifierStartNode[driverKey](value);
3401
- let endNode = await this.verifierEndNode[driverKey](value);
3402
- let direction = this.verifierDirection[driverKey];
3538
+ const v = this.ensureValues(value);
3539
+ const config = this.searchConfigs[driverKey][order];
3540
+ let startNode = await config.start(this, v);
3541
+ let endNode = await config.end(this, v);
3542
+ const direction = config.direction;
3543
+ const earlyTerminate = config.earlyTerminate;
3544
+ if (order === "desc" && !startNode) {
3545
+ startNode = await this.rightestNode();
3546
+ }
3547
+ if (order === "asc" && !startNode) {
3548
+ startNode = await this.leftestNode();
3549
+ }
3550
+ if (!startNode) return;
3403
3551
  const comparator = this.verifierMap[driverKey];
3404
- const earlyTerminate = this.verifierEarlyTerminate[driverKey];
3405
- if (order === "desc") {
3406
- startNode = endNode ?? await this.rightestNode();
3407
- endNode = null;
3408
- direction *= -1;
3409
- }
3410
3552
  const generator = this.getPairsGenerator(
3411
3553
  value,
3412
3554
  startNode,
@@ -3418,7 +3560,7 @@ var require_cjs = __commonJS({
3418
3560
  let count = 0;
3419
3561
  const intersection = filterValues && filterValues.size > 0 ? filterValues : null;
3420
3562
  for await (const pair of generator) {
3421
- const [k, v] = pair;
3563
+ const [k, v2] = pair;
3422
3564
  if (intersection && !intersection.has(k)) {
3423
3565
  continue;
3424
3566
  }
@@ -3427,7 +3569,7 @@ var require_cjs = __commonJS({
3427
3569
  if (key === driverKey) continue;
3428
3570
  const verify = this.verifierMap[key];
3429
3571
  const condValue = condition[key];
3430
- if (!verify(v, condValue)) {
3572
+ if (!verify(v2, condValue)) {
3431
3573
  isMatch = false;
3432
3574
  break;
3433
3575
  }
@@ -8342,7 +8484,7 @@ var require_cjs = __commonJS({
8342
8484
  /**
8343
8485
  * Appends and inserts a new page.
8344
8486
  * If a free page is available in the free list, it reuses it.
8345
- * Otherwise, it appends a new page to the end of the file.
8487
+ * Otherwise, it preallocates `pagePreallocationCount` pages to support sequential reads.
8346
8488
  * @returns Created or reused page ID
8347
8489
  */
8348
8490
  async appendNewPage(pageType = PageManager.CONSTANT.PAGE_TYPE_EMPTY, tx) {
@@ -8363,12 +8505,26 @@ var require_cjs = __commonJS({
8363
8505
  await this.setPage(reusedPageId, newPage2, tx);
8364
8506
  return reusedPageId;
8365
8507
  }
8508
+ const preallocationCount = this.options.pagePreallocationCount;
8366
8509
  const pageCount = metadataManager.getPageCount(metadata);
8367
8510
  const newPageIndex = pageCount;
8368
- const newTotalCount = pageCount + 1;
8511
+ const newTotalCount = pageCount + preallocationCount;
8369
8512
  const manager = this.pageFactory.getManagerFromType(pageType);
8370
8513
  const newPage = manager.create(this.pageSize, newPageIndex);
8371
8514
  await this.setPage(newPageIndex, newPage, tx);
8515
+ const emptyManager = this.pageFactory.getManagerFromType(PageManager.CONSTANT.PAGE_TYPE_EMPTY);
8516
+ const firstFreeIndex = newPageIndex + 1;
8517
+ const lastFreeIndex = newPageIndex + preallocationCount - 1;
8518
+ for (let i = firstFreeIndex; i <= lastFreeIndex; i++) {
8519
+ const emptyPage = emptyManager.create(this.pageSize, i);
8520
+ const nextId = i < lastFreeIndex ? i + 1 : -1;
8521
+ emptyManager.setNextPageId(emptyPage, nextId);
8522
+ await this.setPage(i, emptyPage, tx);
8523
+ await this.updateBitmap(i, true, tx);
8524
+ }
8525
+ if (preallocationCount > 1) {
8526
+ metadataManager.setFreePageId(metadata, firstFreeIndex);
8527
+ }
8372
8528
  metadataManager.setPageCount(metadata, newTotalCount);
8373
8529
  await this.setPage(0, metadata, tx);
8374
8530
  return newPageIndex;
@@ -8452,7 +8608,8 @@ var require_cjs = __commonJS({
8452
8608
  }
8453
8609
  /**
8454
8610
  * Frees the page and marks it as available in the bitmap.
8455
- * It also adds the page to the linked list of free pages in metadata.
8611
+ * Inserts the page into the free list in ascending order by page ID
8612
+ * to support HDD sequential reads.
8456
8613
  * @param pageId Page ID
8457
8614
  * @param tx Transaction
8458
8615
  */
@@ -8462,13 +8619,30 @@ var require_cjs = __commonJS({
8462
8619
  await tx.__acquireWriteLock(pageId);
8463
8620
  const metadata = await this.getMetadata(tx);
8464
8621
  const metadataManager = this.pageFactory.getManager(metadata);
8465
- const currentHeadFreePageId = metadataManager.getFreePageId(metadata);
8466
8622
  const emptyPageManager = this.pageFactory.getManagerFromType(PageManager.CONSTANT.PAGE_TYPE_EMPTY);
8467
8623
  const emptyPage = emptyPageManager.create(this.pageSize, pageId);
8468
- emptyPageManager.setNextPageId(emptyPage, currentHeadFreePageId);
8469
- await this.setPage(pageId, emptyPage, tx);
8624
+ const headFreePageId = metadataManager.getFreePageId(metadata);
8625
+ if (headFreePageId === -1 || pageId < headFreePageId) {
8626
+ emptyPageManager.setNextPageId(emptyPage, headFreePageId);
8627
+ await this.setPage(pageId, emptyPage, tx);
8628
+ metadataManager.setFreePageId(metadata, pageId);
8629
+ } else {
8630
+ let prevPageId = headFreePageId;
8631
+ let prevPage = await this.get(prevPageId, tx);
8632
+ let prevManager = this.pageFactory.getManager(prevPage);
8633
+ let nextPageId = prevManager.getNextPageId(prevPage);
8634
+ while (nextPageId !== -1 && nextPageId < pageId) {
8635
+ prevPageId = nextPageId;
8636
+ prevPage = await this.get(prevPageId, tx);
8637
+ prevManager = this.pageFactory.getManager(prevPage);
8638
+ nextPageId = prevManager.getNextPageId(prevPage);
8639
+ }
8640
+ emptyPageManager.setNextPageId(emptyPage, nextPageId);
8641
+ await this.setPage(pageId, emptyPage, tx);
8642
+ prevManager.setNextPageId(prevPage, pageId);
8643
+ await this.setPage(prevPageId, prevPage, tx);
8644
+ }
8470
8645
  await this.updateBitmap(pageId, true, tx);
8471
- metadataManager.setFreePageId(metadata, pageId);
8472
8646
  await this.setPage(0, metadata, tx);
8473
8647
  }
8474
8648
  /**
@@ -9168,7 +9342,9 @@ var require_cjs = __commonJS({
9168
9342
  }
9169
9343
  pageGroupMap.get(pageId).push({ pk: pair.pk, slotIndex, index: pair.index });
9170
9344
  }
9171
- await Promise.all(Array.from(pageGroupMap).map(async ([pageId, items]) => {
9345
+ const sortedPageIds = Array.from(pageGroupMap.keys()).sort((a, b) => a - b);
9346
+ await Promise.all(sortedPageIds.map(async (pageId) => {
9347
+ const items = pageGroupMap.get(pageId);
9172
9348
  const page = await this.pfs.get(pageId, tx);
9173
9349
  if (!this.factory.isDataPage(page)) {
9174
9350
  throw new Error(`Page ${pageId} is not a data page`);
@@ -9519,6 +9695,7 @@ var require_cjs = __commonJS({
9519
9695
  return Object.assign({
9520
9696
  pageSize: 8192,
9521
9697
  pageCacheCapacity: 1e4,
9698
+ pagePreallocationCount: 1e3,
9522
9699
  wal: null,
9523
9700
  walCheckpointThreshold: 1e3
9524
9701
  }, options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "document-dataply",
3
- "version": "0.0.9-alpha.5",
3
+ "version": "0.0.9-alpha.6",
4
4
  "description": "Simple and powerful JSON document database supporting complex queries and flexible indexing policies.",
5
5
  "license": "MIT",
6
6
  "author": "izure <admin@izure.org>",
@@ -42,7 +42,7 @@
42
42
  "dataply"
43
43
  ],
44
44
  "dependencies": {
45
- "dataply": "^0.0.24-alpha.1"
45
+ "dataply": "^0.0.24-alpha.2"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/jest": "^30.0.0",