serializable-bptree 8.3.5 → 8.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1924,30 +1924,22 @@ var BPTreeTransaction = class _BPTreeTransaction {
1924
1924
  */
1925
1925
  _insertValueIntoLeaf(leaf, key, value) {
1926
1926
  if (leaf.values.length) {
1927
- for (let i = 0, len = leaf.values.length; i < len; i++) {
1928
- const nValue = leaf.values[i];
1929
- if (this.comparator.isSame(value, nValue)) {
1930
- if (leaf.keys[i].includes(key)) {
1931
- return false;
1932
- }
1933
- leaf.keys[i].push(key);
1934
- return true;
1935
- } else if (this.comparator.isLower(value, nValue)) {
1936
- leaf.values.splice(i, 0, value);
1937
- leaf.keys.splice(i, 0, [key]);
1938
- return true;
1939
- } else if (i + 1 === leaf.values.length) {
1940
- leaf.values.push(value);
1941
- leaf.keys.push([key]);
1942
- return true;
1927
+ const { index, found } = this._binarySearchValues(leaf.values, value);
1928
+ if (found) {
1929
+ if (leaf.keys[index].includes(key)) {
1930
+ return false;
1943
1931
  }
1932
+ leaf.keys[index].push(key);
1933
+ return true;
1944
1934
  }
1935
+ leaf.values.splice(index, 0, value);
1936
+ leaf.keys.splice(index, 0, [key]);
1937
+ return true;
1945
1938
  } else {
1946
1939
  leaf.values = [value];
1947
1940
  leaf.keys = [[key]];
1948
1941
  return true;
1949
1942
  }
1950
- return false;
1951
1943
  }
1952
1944
  _cloneNode(node) {
1953
1945
  return JSON.parse(JSON.stringify(node));
@@ -2240,12 +2232,8 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2240
2232
  const midValue = parentNode.values[mid];
2241
2233
  parentNode.values = parentNode.values.slice(0, mid);
2242
2234
  parentNode.keys = parentNode.keys.slice(0, mid + 1);
2243
- for (const k of parentNode.keys) {
2244
- const n = this._cloneNode(this.getNode(k));
2245
- n.parent = parentNode.id;
2246
- this._updateNode(n);
2247
- }
2248
- for (const k of newSiblingNodeRecursive.keys) {
2235
+ for (let i = 0, len = newSiblingNodeRecursive.keys.length; i < len; i++) {
2236
+ const k = newSiblingNodeRecursive.keys[i];
2249
2237
  const n = this._cloneNode(this.getNode(k));
2250
2238
  n.parent = newSiblingNodeRecursive.id;
2251
2239
  this._updateNode(n);
@@ -2327,7 +2315,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2327
2315
  for (let i = 0; i < len; i++) {
2328
2316
  const nValue = node.values[i];
2329
2317
  const keys = node.keys[i];
2330
- for (let j = 0, kLen = keys.length; j < kLen; j++) {
2318
+ for (let j = 0, len2 = keys.length; j < len2; j++) {
2331
2319
  yield [keys[j], nValue];
2332
2320
  }
2333
2321
  }
@@ -2406,7 +2394,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2406
2394
  while (true) {
2407
2395
  for (let i = 0, len = node.values.length; i < len; i++) {
2408
2396
  const keys = node.keys[i];
2409
- for (let j = 0, kLen = keys.length; j < kLen; j++) {
2397
+ for (let j = 0, len2 = keys.length; j < len2; j++) {
2410
2398
  if (keys[j] === key) {
2411
2399
  return node.values[i];
2412
2400
  }
@@ -2515,8 +2503,16 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2515
2503
  const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
2516
2504
  let currentLeaf = null;
2517
2505
  let modified = false;
2518
- for (const [key, value] of sorted) {
2519
- const targetLeaf = this.locateLeaf(value);
2506
+ let cachedLeafId = null;
2507
+ let cachedLeafMaxValue = null;
2508
+ for (let i = 0, len = sorted.length; i < len; i++) {
2509
+ const [key, value] = sorted[i];
2510
+ let targetLeaf;
2511
+ if (cachedLeafId !== null && cachedLeafMaxValue !== null && currentLeaf !== null && (this.comparator.isLower(value, cachedLeafMaxValue) || this.comparator.isSame(value, cachedLeafMaxValue))) {
2512
+ targetLeaf = currentLeaf;
2513
+ } else {
2514
+ targetLeaf = this.locateLeaf(value);
2515
+ }
2520
2516
  if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
2521
2517
  } else {
2522
2518
  if (currentLeaf !== null && modified) {
@@ -2525,8 +2521,10 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2525
2521
  currentLeaf = this._cloneNode(targetLeaf);
2526
2522
  modified = false;
2527
2523
  }
2524
+ cachedLeafId = currentLeaf.id;
2528
2525
  const changed = this._insertValueIntoLeaf(currentLeaf, key, value);
2529
2526
  modified = modified || changed;
2527
+ cachedLeafMaxValue = currentLeaf.values[currentLeaf.values.length - 1];
2530
2528
  if (currentLeaf.values.length === this.order) {
2531
2529
  this._updateNode(currentLeaf);
2532
2530
  let after = this._createNode(
@@ -2547,6 +2545,8 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2547
2545
  this._updateNode(after);
2548
2546
  this._insertInParent(currentLeaf, after.values[0], after);
2549
2547
  currentLeaf = null;
2548
+ cachedLeafId = null;
2549
+ cachedLeafMaxValue = null;
2550
2550
  modified = false;
2551
2551
  }
2552
2552
  }
@@ -2554,6 +2554,85 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2554
2554
  this._updateNode(currentLeaf);
2555
2555
  }
2556
2556
  }
2557
+ bulkLoad(entries) {
2558
+ if (entries.length === 0) return;
2559
+ const root = this.getNode(this.rootId);
2560
+ if (!root.leaf || root.values.length > 0) {
2561
+ throw new Error("bulkLoad can only be called on an empty tree. Use batchInsert for non-empty trees.");
2562
+ }
2563
+ const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
2564
+ const grouped = [];
2565
+ for (let i = 0, len = sorted.length; i < len; i++) {
2566
+ const [key, value] = sorted[i];
2567
+ const last = grouped[grouped.length - 1];
2568
+ if (last && this.comparator.isSame(last.value, value)) {
2569
+ if (!last.keys.includes(key)) {
2570
+ last.keys.push(key);
2571
+ }
2572
+ } else {
2573
+ grouped.push({ keys: [key], value });
2574
+ }
2575
+ }
2576
+ this._deleteNode(root);
2577
+ const maxLeafSize = this.order - 1;
2578
+ const leaves = [];
2579
+ for (let i = 0, len = grouped.length; i < len; i += maxLeafSize) {
2580
+ const chunk = grouped.slice(i, i + maxLeafSize);
2581
+ const leafKeys = chunk.map((g) => g.keys);
2582
+ const leafValues = chunk.map((g) => g.value);
2583
+ const leaf = this._createNode(
2584
+ true,
2585
+ leafKeys,
2586
+ leafValues,
2587
+ null,
2588
+ null,
2589
+ null
2590
+ );
2591
+ leaves.push(leaf);
2592
+ }
2593
+ for (let i = 0, len = leaves.length; i < len; i++) {
2594
+ if (i > 0) {
2595
+ leaves[i].prev = leaves[i - 1].id;
2596
+ }
2597
+ if (i < len - 1) {
2598
+ leaves[i].next = leaves[i + 1].id;
2599
+ }
2600
+ this._updateNode(leaves[i]);
2601
+ }
2602
+ let currentLevel = leaves;
2603
+ while (currentLevel.length > 1) {
2604
+ const nextLevel = [];
2605
+ for (let i = 0, len = currentLevel.length; i < len; i += this.order) {
2606
+ const children = currentLevel.slice(i, i + this.order);
2607
+ const childIds = children.map((c) => c.id);
2608
+ const separators = [];
2609
+ for (let j = 1, len2 = children.length; j < len2; j++) {
2610
+ separators.push(children[j].values[0]);
2611
+ }
2612
+ const internalNode = this._createNode(
2613
+ false,
2614
+ childIds,
2615
+ separators,
2616
+ null,
2617
+ null,
2618
+ null
2619
+ );
2620
+ for (let j = 0, len2 = children.length; j < len2; j++) {
2621
+ const child = children[j];
2622
+ child.parent = internalNode.id;
2623
+ this._updateNode(child);
2624
+ }
2625
+ nextLevel.push(internalNode);
2626
+ }
2627
+ currentLevel = nextLevel;
2628
+ }
2629
+ const newRoot = currentLevel[0];
2630
+ this._writeHead({
2631
+ root: newRoot.id,
2632
+ order: this.order,
2633
+ data: this.strategy.head.data
2634
+ });
2635
+ }
2557
2636
  _deleteEntry(node, key) {
2558
2637
  if (!node.leaf) {
2559
2638
  let keyIndex = -1;
@@ -2657,7 +2736,8 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2657
2736
  siblingNode.values.push(...node.values);
2658
2737
  if (!siblingNode.leaf) {
2659
2738
  const keys = siblingNode.keys;
2660
- for (const key2 of keys) {
2739
+ for (let i = 0, len = keys.length; i < len; i++) {
2740
+ const key2 = keys[i];
2661
2741
  const node2 = this._cloneNode(this.getNode(key2));
2662
2742
  node2.parent = siblingNode.id;
2663
2743
  this._updateNode(node2);
@@ -2725,21 +2805,24 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2725
2805
  this._updateNode(siblingNode);
2726
2806
  }
2727
2807
  if (!siblingNode.leaf) {
2728
- for (const key2 of siblingNode.keys) {
2808
+ for (let i = 0, len = siblingNode.keys.length; i < len; i++) {
2809
+ const key2 = siblingNode.keys[i];
2729
2810
  const n = this._cloneNode(this.getNode(key2));
2730
2811
  n.parent = siblingNode.id;
2731
2812
  this._updateNode(n);
2732
2813
  }
2733
2814
  }
2734
2815
  if (!node.leaf) {
2735
- for (const key2 of node.keys) {
2816
+ for (let i = 0, len = node.keys.length; i < len; i++) {
2817
+ const key2 = node.keys[i];
2736
2818
  const n = this._cloneNode(this.getNode(key2));
2737
2819
  n.parent = node.id;
2738
2820
  this._updateNode(n);
2739
2821
  }
2740
2822
  }
2741
2823
  if (!parentNode.leaf) {
2742
- for (const key2 of parentNode.keys) {
2824
+ for (let i = 0, len = parentNode.keys.length; i < len; i++) {
2825
+ const key2 = parentNode.keys[i];
2743
2826
  const n = this._cloneNode(this.getNode(key2));
2744
2827
  n.parent = parentNode.id;
2745
2828
  this._updateNode(n);
@@ -2917,6 +3000,14 @@ var BPTreeSync = class extends BPTreeSyncTransaction {
2917
3000
  throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
2918
3001
  }
2919
3002
  }
3003
+ bulkLoad(entries) {
3004
+ const tx = this.createTransaction();
3005
+ tx.bulkLoad(entries);
3006
+ const result = tx.commit();
3007
+ if (!result.success) {
3008
+ throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
3009
+ }
3010
+ }
2920
3011
  };
2921
3012
 
2922
3013
  // node_modules/ryoiki/dist/esm/index.mjs
@@ -3334,12 +3425,8 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3334
3425
  const midValue = parentNode.values[mid];
3335
3426
  parentNode.values = parentNode.values.slice(0, mid);
3336
3427
  parentNode.keys = parentNode.keys.slice(0, mid + 1);
3337
- for (const k of parentNode.keys) {
3338
- const n = this._cloneNode(await this.getNode(k));
3339
- n.parent = parentNode.id;
3340
- await this._updateNode(n);
3341
- }
3342
- for (const k of newSiblingNodeRecursive.keys) {
3428
+ for (let i = 0, len = newSiblingNodeRecursive.keys.length; i < len; i++) {
3429
+ const k = newSiblingNodeRecursive.keys[i];
3343
3430
  const n = this._cloneNode(await this.getNode(k));
3344
3431
  n.parent = newSiblingNodeRecursive.id;
3345
3432
  await this._updateNode(n);
@@ -3431,7 +3518,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3431
3518
  for (let i = 0; i < len; i++) {
3432
3519
  const nValue = node.values[i];
3433
3520
  const keys = node.keys[i];
3434
- for (let j = 0, kLen = keys.length; j < kLen; j++) {
3521
+ for (let j = 0, len2 = keys.length; j < len2; j++) {
3435
3522
  yield [keys[j], nValue];
3436
3523
  }
3437
3524
  }
@@ -3509,7 +3596,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3509
3596
  while (true) {
3510
3597
  for (let i = 0, len = node.values.length; i < len; i++) {
3511
3598
  const keys = node.keys[i];
3512
- for (let j = 0, kLen = keys.length; j < kLen; j++) {
3599
+ for (let j = 0, len2 = keys.length; j < len2; j++) {
3513
3600
  if (keys[j] === key) {
3514
3601
  return node.values[i];
3515
3602
  }
@@ -3621,8 +3708,16 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3621
3708
  const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
3622
3709
  let currentLeaf = null;
3623
3710
  let modified = false;
3624
- for (const [key, value] of sorted) {
3625
- const targetLeaf = await this.locateLeaf(value);
3711
+ let cachedLeafId = null;
3712
+ let cachedLeafMaxValue = null;
3713
+ for (let i = 0, len = sorted.length; i < len; i++) {
3714
+ const [key, value] = sorted[i];
3715
+ let targetLeaf;
3716
+ if (cachedLeafId !== null && cachedLeafMaxValue !== null && currentLeaf !== null && (this.comparator.isLower(value, cachedLeafMaxValue) || this.comparator.isSame(value, cachedLeafMaxValue))) {
3717
+ targetLeaf = currentLeaf;
3718
+ } else {
3719
+ targetLeaf = await this.locateLeaf(value);
3720
+ }
3626
3721
  if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
3627
3722
  } else {
3628
3723
  if (currentLeaf !== null && modified) {
@@ -3631,8 +3726,10 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3631
3726
  currentLeaf = this._cloneNode(targetLeaf);
3632
3727
  modified = false;
3633
3728
  }
3729
+ cachedLeafId = currentLeaf.id;
3634
3730
  const changed = this._insertValueIntoLeaf(currentLeaf, key, value);
3635
3731
  modified = modified || changed;
3732
+ cachedLeafMaxValue = currentLeaf.values[currentLeaf.values.length - 1];
3636
3733
  if (currentLeaf.values.length === this.order) {
3637
3734
  await this._updateNode(currentLeaf);
3638
3735
  let after = await this._createNode(
@@ -3653,6 +3750,8 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3653
3750
  await this._updateNode(after);
3654
3751
  await this._insertInParent(currentLeaf, after.values[0], after);
3655
3752
  currentLeaf = null;
3753
+ cachedLeafId = null;
3754
+ cachedLeafMaxValue = null;
3656
3755
  modified = false;
3657
3756
  }
3658
3757
  }
@@ -3661,6 +3760,87 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3661
3760
  }
3662
3761
  });
3663
3762
  }
3763
+ async bulkLoad(entries) {
3764
+ if (entries.length === 0) return;
3765
+ return this.writeLock(0, async () => {
3766
+ const root = await this.getNode(this.rootId);
3767
+ if (!root.leaf || root.values.length > 0) {
3768
+ throw new Error("bulkLoad can only be called on an empty tree. Use batchInsert for non-empty trees.");
3769
+ }
3770
+ const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
3771
+ const grouped = [];
3772
+ for (let i = 0, len = sorted.length; i < len; i++) {
3773
+ const [key, value] = sorted[i];
3774
+ const last = grouped[grouped.length - 1];
3775
+ if (last && this.comparator.isSame(last.value, value)) {
3776
+ if (!last.keys.includes(key)) {
3777
+ last.keys.push(key);
3778
+ }
3779
+ } else {
3780
+ grouped.push({ keys: [key], value });
3781
+ }
3782
+ }
3783
+ await this._deleteNode(root);
3784
+ const maxLeafSize = this.order - 1;
3785
+ const leaves = [];
3786
+ for (let i = 0, len = grouped.length; i < len; i += maxLeafSize) {
3787
+ const chunk = grouped.slice(i, i + maxLeafSize);
3788
+ const leafKeys = chunk.map((g) => g.keys);
3789
+ const leafValues = chunk.map((g) => g.value);
3790
+ const leaf = await this._createNode(
3791
+ true,
3792
+ leafKeys,
3793
+ leafValues,
3794
+ null,
3795
+ null,
3796
+ null
3797
+ );
3798
+ leaves.push(leaf);
3799
+ }
3800
+ for (let i = 0, len = leaves.length; i < len; i++) {
3801
+ if (i > 0) {
3802
+ leaves[i].prev = leaves[i - 1].id;
3803
+ }
3804
+ if (i < len - 1) {
3805
+ leaves[i].next = leaves[i + 1].id;
3806
+ }
3807
+ await this._updateNode(leaves[i]);
3808
+ }
3809
+ let currentLevel = leaves;
3810
+ while (currentLevel.length > 1) {
3811
+ const nextLevel = [];
3812
+ for (let i = 0, len = currentLevel.length; i < len; i += this.order) {
3813
+ const children = currentLevel.slice(i, i + this.order);
3814
+ const childIds = children.map((c) => c.id);
3815
+ const separators = [];
3816
+ for (let j = 1, len2 = children.length; j < len2; j++) {
3817
+ separators.push(children[j].values[0]);
3818
+ }
3819
+ const internalNode = await this._createNode(
3820
+ false,
3821
+ childIds,
3822
+ separators,
3823
+ null,
3824
+ null,
3825
+ null
3826
+ );
3827
+ for (let j = 0, len2 = children.length; j < len2; j++) {
3828
+ const child = children[j];
3829
+ child.parent = internalNode.id;
3830
+ await this._updateNode(child);
3831
+ }
3832
+ nextLevel.push(internalNode);
3833
+ }
3834
+ currentLevel = nextLevel;
3835
+ }
3836
+ const newRoot = currentLevel[0];
3837
+ await this._writeHead({
3838
+ root: newRoot.id,
3839
+ order: this.order,
3840
+ data: this.strategy.head.data
3841
+ });
3842
+ });
3843
+ }
3664
3844
  async _deleteEntry(node, key) {
3665
3845
  if (!node.leaf) {
3666
3846
  let keyIndex = -1;
@@ -3764,7 +3944,8 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3764
3944
  siblingNode.values.push(...node.values);
3765
3945
  if (!siblingNode.leaf) {
3766
3946
  const keys = siblingNode.keys;
3767
- for (const key2 of keys) {
3947
+ for (let i = 0, len = keys.length; i < len; i++) {
3948
+ const key2 = keys[i];
3768
3949
  const node2 = this._cloneNode(await this.getNode(key2));
3769
3950
  node2.parent = siblingNode.id;
3770
3951
  await this._updateNode(node2);
@@ -3832,21 +4013,24 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3832
4013
  await this._updateNode(siblingNode);
3833
4014
  }
3834
4015
  if (!siblingNode.leaf) {
3835
- for (const key2 of siblingNode.keys) {
4016
+ for (let i = 0, len = siblingNode.keys.length; i < len; i++) {
4017
+ const key2 = siblingNode.keys[i];
3836
4018
  const n = this._cloneNode(await this.getNode(key2));
3837
4019
  n.parent = siblingNode.id;
3838
4020
  await this._updateNode(n);
3839
4021
  }
3840
4022
  }
3841
4023
  if (!node.leaf) {
3842
- for (const key2 of node.keys) {
4024
+ for (let i = 0, len = node.keys.length; i < len; i++) {
4025
+ const key2 = node.keys[i];
3843
4026
  const n = this._cloneNode(await this.getNode(key2));
3844
4027
  n.parent = node.id;
3845
4028
  await this._updateNode(n);
3846
4029
  }
3847
4030
  }
3848
4031
  if (!parentNode.leaf) {
3849
- for (const key2 of parentNode.keys) {
4032
+ for (let i = 0, len = parentNode.keys.length; i < len; i++) {
4033
+ const key2 = parentNode.keys[i];
3850
4034
  const n = this._cloneNode(await this.getNode(key2));
3851
4035
  n.parent = parentNode.id;
3852
4036
  await this._updateNode(n);
@@ -4032,6 +4216,16 @@ var BPTreeAsync = class extends BPTreeAsyncTransaction {
4032
4216
  }
4033
4217
  });
4034
4218
  }
4219
+ async bulkLoad(entries) {
4220
+ return this.writeLock(1, async () => {
4221
+ const tx = await this.createTransaction();
4222
+ await tx.bulkLoad(entries);
4223
+ const result = await tx.commit();
4224
+ if (!result.success) {
4225
+ throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
4226
+ }
4227
+ });
4228
+ }
4035
4229
  };
4036
4230
 
4037
4231
  // src/base/SerializeStrategy.ts
@@ -1888,30 +1888,22 @@ var BPTreeTransaction = class _BPTreeTransaction {
1888
1888
  */
1889
1889
  _insertValueIntoLeaf(leaf, key, value) {
1890
1890
  if (leaf.values.length) {
1891
- for (let i = 0, len = leaf.values.length; i < len; i++) {
1892
- const nValue = leaf.values[i];
1893
- if (this.comparator.isSame(value, nValue)) {
1894
- if (leaf.keys[i].includes(key)) {
1895
- return false;
1896
- }
1897
- leaf.keys[i].push(key);
1898
- return true;
1899
- } else if (this.comparator.isLower(value, nValue)) {
1900
- leaf.values.splice(i, 0, value);
1901
- leaf.keys.splice(i, 0, [key]);
1902
- return true;
1903
- } else if (i + 1 === leaf.values.length) {
1904
- leaf.values.push(value);
1905
- leaf.keys.push([key]);
1906
- return true;
1891
+ const { index, found } = this._binarySearchValues(leaf.values, value);
1892
+ if (found) {
1893
+ if (leaf.keys[index].includes(key)) {
1894
+ return false;
1907
1895
  }
1896
+ leaf.keys[index].push(key);
1897
+ return true;
1908
1898
  }
1899
+ leaf.values.splice(index, 0, value);
1900
+ leaf.keys.splice(index, 0, [key]);
1901
+ return true;
1909
1902
  } else {
1910
1903
  leaf.values = [value];
1911
1904
  leaf.keys = [[key]];
1912
1905
  return true;
1913
1906
  }
1914
- return false;
1915
1907
  }
1916
1908
  _cloneNode(node) {
1917
1909
  return JSON.parse(JSON.stringify(node));
@@ -2204,12 +2196,8 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2204
2196
  const midValue = parentNode.values[mid];
2205
2197
  parentNode.values = parentNode.values.slice(0, mid);
2206
2198
  parentNode.keys = parentNode.keys.slice(0, mid + 1);
2207
- for (const k of parentNode.keys) {
2208
- const n = this._cloneNode(this.getNode(k));
2209
- n.parent = parentNode.id;
2210
- this._updateNode(n);
2211
- }
2212
- for (const k of newSiblingNodeRecursive.keys) {
2199
+ for (let i = 0, len = newSiblingNodeRecursive.keys.length; i < len; i++) {
2200
+ const k = newSiblingNodeRecursive.keys[i];
2213
2201
  const n = this._cloneNode(this.getNode(k));
2214
2202
  n.parent = newSiblingNodeRecursive.id;
2215
2203
  this._updateNode(n);
@@ -2291,7 +2279,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2291
2279
  for (let i = 0; i < len; i++) {
2292
2280
  const nValue = node.values[i];
2293
2281
  const keys = node.keys[i];
2294
- for (let j = 0, kLen = keys.length; j < kLen; j++) {
2282
+ for (let j = 0, len2 = keys.length; j < len2; j++) {
2295
2283
  yield [keys[j], nValue];
2296
2284
  }
2297
2285
  }
@@ -2370,7 +2358,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2370
2358
  while (true) {
2371
2359
  for (let i = 0, len = node.values.length; i < len; i++) {
2372
2360
  const keys = node.keys[i];
2373
- for (let j = 0, kLen = keys.length; j < kLen; j++) {
2361
+ for (let j = 0, len2 = keys.length; j < len2; j++) {
2374
2362
  if (keys[j] === key) {
2375
2363
  return node.values[i];
2376
2364
  }
@@ -2479,8 +2467,16 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2479
2467
  const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
2480
2468
  let currentLeaf = null;
2481
2469
  let modified = false;
2482
- for (const [key, value] of sorted) {
2483
- const targetLeaf = this.locateLeaf(value);
2470
+ let cachedLeafId = null;
2471
+ let cachedLeafMaxValue = null;
2472
+ for (let i = 0, len = sorted.length; i < len; i++) {
2473
+ const [key, value] = sorted[i];
2474
+ let targetLeaf;
2475
+ if (cachedLeafId !== null && cachedLeafMaxValue !== null && currentLeaf !== null && (this.comparator.isLower(value, cachedLeafMaxValue) || this.comparator.isSame(value, cachedLeafMaxValue))) {
2476
+ targetLeaf = currentLeaf;
2477
+ } else {
2478
+ targetLeaf = this.locateLeaf(value);
2479
+ }
2484
2480
  if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
2485
2481
  } else {
2486
2482
  if (currentLeaf !== null && modified) {
@@ -2489,8 +2485,10 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2489
2485
  currentLeaf = this._cloneNode(targetLeaf);
2490
2486
  modified = false;
2491
2487
  }
2488
+ cachedLeafId = currentLeaf.id;
2492
2489
  const changed = this._insertValueIntoLeaf(currentLeaf, key, value);
2493
2490
  modified = modified || changed;
2491
+ cachedLeafMaxValue = currentLeaf.values[currentLeaf.values.length - 1];
2494
2492
  if (currentLeaf.values.length === this.order) {
2495
2493
  this._updateNode(currentLeaf);
2496
2494
  let after = this._createNode(
@@ -2511,6 +2509,8 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2511
2509
  this._updateNode(after);
2512
2510
  this._insertInParent(currentLeaf, after.values[0], after);
2513
2511
  currentLeaf = null;
2512
+ cachedLeafId = null;
2513
+ cachedLeafMaxValue = null;
2514
2514
  modified = false;
2515
2515
  }
2516
2516
  }
@@ -2518,6 +2518,85 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2518
2518
  this._updateNode(currentLeaf);
2519
2519
  }
2520
2520
  }
2521
+ bulkLoad(entries) {
2522
+ if (entries.length === 0) return;
2523
+ const root = this.getNode(this.rootId);
2524
+ if (!root.leaf || root.values.length > 0) {
2525
+ throw new Error("bulkLoad can only be called on an empty tree. Use batchInsert for non-empty trees.");
2526
+ }
2527
+ const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
2528
+ const grouped = [];
2529
+ for (let i = 0, len = sorted.length; i < len; i++) {
2530
+ const [key, value] = sorted[i];
2531
+ const last = grouped[grouped.length - 1];
2532
+ if (last && this.comparator.isSame(last.value, value)) {
2533
+ if (!last.keys.includes(key)) {
2534
+ last.keys.push(key);
2535
+ }
2536
+ } else {
2537
+ grouped.push({ keys: [key], value });
2538
+ }
2539
+ }
2540
+ this._deleteNode(root);
2541
+ const maxLeafSize = this.order - 1;
2542
+ const leaves = [];
2543
+ for (let i = 0, len = grouped.length; i < len; i += maxLeafSize) {
2544
+ const chunk = grouped.slice(i, i + maxLeafSize);
2545
+ const leafKeys = chunk.map((g) => g.keys);
2546
+ const leafValues = chunk.map((g) => g.value);
2547
+ const leaf = this._createNode(
2548
+ true,
2549
+ leafKeys,
2550
+ leafValues,
2551
+ null,
2552
+ null,
2553
+ null
2554
+ );
2555
+ leaves.push(leaf);
2556
+ }
2557
+ for (let i = 0, len = leaves.length; i < len; i++) {
2558
+ if (i > 0) {
2559
+ leaves[i].prev = leaves[i - 1].id;
2560
+ }
2561
+ if (i < len - 1) {
2562
+ leaves[i].next = leaves[i + 1].id;
2563
+ }
2564
+ this._updateNode(leaves[i]);
2565
+ }
2566
+ let currentLevel = leaves;
2567
+ while (currentLevel.length > 1) {
2568
+ const nextLevel = [];
2569
+ for (let i = 0, len = currentLevel.length; i < len; i += this.order) {
2570
+ const children = currentLevel.slice(i, i + this.order);
2571
+ const childIds = children.map((c) => c.id);
2572
+ const separators = [];
2573
+ for (let j = 1, len2 = children.length; j < len2; j++) {
2574
+ separators.push(children[j].values[0]);
2575
+ }
2576
+ const internalNode = this._createNode(
2577
+ false,
2578
+ childIds,
2579
+ separators,
2580
+ null,
2581
+ null,
2582
+ null
2583
+ );
2584
+ for (let j = 0, len2 = children.length; j < len2; j++) {
2585
+ const child = children[j];
2586
+ child.parent = internalNode.id;
2587
+ this._updateNode(child);
2588
+ }
2589
+ nextLevel.push(internalNode);
2590
+ }
2591
+ currentLevel = nextLevel;
2592
+ }
2593
+ const newRoot = currentLevel[0];
2594
+ this._writeHead({
2595
+ root: newRoot.id,
2596
+ order: this.order,
2597
+ data: this.strategy.head.data
2598
+ });
2599
+ }
2521
2600
  _deleteEntry(node, key) {
2522
2601
  if (!node.leaf) {
2523
2602
  let keyIndex = -1;
@@ -2621,7 +2700,8 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2621
2700
  siblingNode.values.push(...node.values);
2622
2701
  if (!siblingNode.leaf) {
2623
2702
  const keys = siblingNode.keys;
2624
- for (const key2 of keys) {
2703
+ for (let i = 0, len = keys.length; i < len; i++) {
2704
+ const key2 = keys[i];
2625
2705
  const node2 = this._cloneNode(this.getNode(key2));
2626
2706
  node2.parent = siblingNode.id;
2627
2707
  this._updateNode(node2);
@@ -2689,21 +2769,24 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2689
2769
  this._updateNode(siblingNode);
2690
2770
  }
2691
2771
  if (!siblingNode.leaf) {
2692
- for (const key2 of siblingNode.keys) {
2772
+ for (let i = 0, len = siblingNode.keys.length; i < len; i++) {
2773
+ const key2 = siblingNode.keys[i];
2693
2774
  const n = this._cloneNode(this.getNode(key2));
2694
2775
  n.parent = siblingNode.id;
2695
2776
  this._updateNode(n);
2696
2777
  }
2697
2778
  }
2698
2779
  if (!node.leaf) {
2699
- for (const key2 of node.keys) {
2780
+ for (let i = 0, len = node.keys.length; i < len; i++) {
2781
+ const key2 = node.keys[i];
2700
2782
  const n = this._cloneNode(this.getNode(key2));
2701
2783
  n.parent = node.id;
2702
2784
  this._updateNode(n);
2703
2785
  }
2704
2786
  }
2705
2787
  if (!parentNode.leaf) {
2706
- for (const key2 of parentNode.keys) {
2788
+ for (let i = 0, len = parentNode.keys.length; i < len; i++) {
2789
+ const key2 = parentNode.keys[i];
2707
2790
  const n = this._cloneNode(this.getNode(key2));
2708
2791
  n.parent = parentNode.id;
2709
2792
  this._updateNode(n);
@@ -2881,6 +2964,14 @@ var BPTreeSync = class extends BPTreeSyncTransaction {
2881
2964
  throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
2882
2965
  }
2883
2966
  }
2967
+ bulkLoad(entries) {
2968
+ const tx = this.createTransaction();
2969
+ tx.bulkLoad(entries);
2970
+ const result = tx.commit();
2971
+ if (!result.success) {
2972
+ throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
2973
+ }
2974
+ }
2884
2975
  };
2885
2976
 
2886
2977
  // node_modules/ryoiki/dist/esm/index.mjs
@@ -3298,12 +3389,8 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3298
3389
  const midValue = parentNode.values[mid];
3299
3390
  parentNode.values = parentNode.values.slice(0, mid);
3300
3391
  parentNode.keys = parentNode.keys.slice(0, mid + 1);
3301
- for (const k of parentNode.keys) {
3302
- const n = this._cloneNode(await this.getNode(k));
3303
- n.parent = parentNode.id;
3304
- await this._updateNode(n);
3305
- }
3306
- for (const k of newSiblingNodeRecursive.keys) {
3392
+ for (let i = 0, len = newSiblingNodeRecursive.keys.length; i < len; i++) {
3393
+ const k = newSiblingNodeRecursive.keys[i];
3307
3394
  const n = this._cloneNode(await this.getNode(k));
3308
3395
  n.parent = newSiblingNodeRecursive.id;
3309
3396
  await this._updateNode(n);
@@ -3395,7 +3482,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3395
3482
  for (let i = 0; i < len; i++) {
3396
3483
  const nValue = node.values[i];
3397
3484
  const keys = node.keys[i];
3398
- for (let j = 0, kLen = keys.length; j < kLen; j++) {
3485
+ for (let j = 0, len2 = keys.length; j < len2; j++) {
3399
3486
  yield [keys[j], nValue];
3400
3487
  }
3401
3488
  }
@@ -3473,7 +3560,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3473
3560
  while (true) {
3474
3561
  for (let i = 0, len = node.values.length; i < len; i++) {
3475
3562
  const keys = node.keys[i];
3476
- for (let j = 0, kLen = keys.length; j < kLen; j++) {
3563
+ for (let j = 0, len2 = keys.length; j < len2; j++) {
3477
3564
  if (keys[j] === key) {
3478
3565
  return node.values[i];
3479
3566
  }
@@ -3585,8 +3672,16 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3585
3672
  const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
3586
3673
  let currentLeaf = null;
3587
3674
  let modified = false;
3588
- for (const [key, value] of sorted) {
3589
- const targetLeaf = await this.locateLeaf(value);
3675
+ let cachedLeafId = null;
3676
+ let cachedLeafMaxValue = null;
3677
+ for (let i = 0, len = sorted.length; i < len; i++) {
3678
+ const [key, value] = sorted[i];
3679
+ let targetLeaf;
3680
+ if (cachedLeafId !== null && cachedLeafMaxValue !== null && currentLeaf !== null && (this.comparator.isLower(value, cachedLeafMaxValue) || this.comparator.isSame(value, cachedLeafMaxValue))) {
3681
+ targetLeaf = currentLeaf;
3682
+ } else {
3683
+ targetLeaf = await this.locateLeaf(value);
3684
+ }
3590
3685
  if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
3591
3686
  } else {
3592
3687
  if (currentLeaf !== null && modified) {
@@ -3595,8 +3690,10 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3595
3690
  currentLeaf = this._cloneNode(targetLeaf);
3596
3691
  modified = false;
3597
3692
  }
3693
+ cachedLeafId = currentLeaf.id;
3598
3694
  const changed = this._insertValueIntoLeaf(currentLeaf, key, value);
3599
3695
  modified = modified || changed;
3696
+ cachedLeafMaxValue = currentLeaf.values[currentLeaf.values.length - 1];
3600
3697
  if (currentLeaf.values.length === this.order) {
3601
3698
  await this._updateNode(currentLeaf);
3602
3699
  let after = await this._createNode(
@@ -3617,6 +3714,8 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3617
3714
  await this._updateNode(after);
3618
3715
  await this._insertInParent(currentLeaf, after.values[0], after);
3619
3716
  currentLeaf = null;
3717
+ cachedLeafId = null;
3718
+ cachedLeafMaxValue = null;
3620
3719
  modified = false;
3621
3720
  }
3622
3721
  }
@@ -3625,6 +3724,87 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3625
3724
  }
3626
3725
  });
3627
3726
  }
3727
+ async bulkLoad(entries) {
3728
+ if (entries.length === 0) return;
3729
+ return this.writeLock(0, async () => {
3730
+ const root = await this.getNode(this.rootId);
3731
+ if (!root.leaf || root.values.length > 0) {
3732
+ throw new Error("bulkLoad can only be called on an empty tree. Use batchInsert for non-empty trees.");
3733
+ }
3734
+ const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
3735
+ const grouped = [];
3736
+ for (let i = 0, len = sorted.length; i < len; i++) {
3737
+ const [key, value] = sorted[i];
3738
+ const last = grouped[grouped.length - 1];
3739
+ if (last && this.comparator.isSame(last.value, value)) {
3740
+ if (!last.keys.includes(key)) {
3741
+ last.keys.push(key);
3742
+ }
3743
+ } else {
3744
+ grouped.push({ keys: [key], value });
3745
+ }
3746
+ }
3747
+ await this._deleteNode(root);
3748
+ const maxLeafSize = this.order - 1;
3749
+ const leaves = [];
3750
+ for (let i = 0, len = grouped.length; i < len; i += maxLeafSize) {
3751
+ const chunk = grouped.slice(i, i + maxLeafSize);
3752
+ const leafKeys = chunk.map((g) => g.keys);
3753
+ const leafValues = chunk.map((g) => g.value);
3754
+ const leaf = await this._createNode(
3755
+ true,
3756
+ leafKeys,
3757
+ leafValues,
3758
+ null,
3759
+ null,
3760
+ null
3761
+ );
3762
+ leaves.push(leaf);
3763
+ }
3764
+ for (let i = 0, len = leaves.length; i < len; i++) {
3765
+ if (i > 0) {
3766
+ leaves[i].prev = leaves[i - 1].id;
3767
+ }
3768
+ if (i < len - 1) {
3769
+ leaves[i].next = leaves[i + 1].id;
3770
+ }
3771
+ await this._updateNode(leaves[i]);
3772
+ }
3773
+ let currentLevel = leaves;
3774
+ while (currentLevel.length > 1) {
3775
+ const nextLevel = [];
3776
+ for (let i = 0, len = currentLevel.length; i < len; i += this.order) {
3777
+ const children = currentLevel.slice(i, i + this.order);
3778
+ const childIds = children.map((c) => c.id);
3779
+ const separators = [];
3780
+ for (let j = 1, len2 = children.length; j < len2; j++) {
3781
+ separators.push(children[j].values[0]);
3782
+ }
3783
+ const internalNode = await this._createNode(
3784
+ false,
3785
+ childIds,
3786
+ separators,
3787
+ null,
3788
+ null,
3789
+ null
3790
+ );
3791
+ for (let j = 0, len2 = children.length; j < len2; j++) {
3792
+ const child = children[j];
3793
+ child.parent = internalNode.id;
3794
+ await this._updateNode(child);
3795
+ }
3796
+ nextLevel.push(internalNode);
3797
+ }
3798
+ currentLevel = nextLevel;
3799
+ }
3800
+ const newRoot = currentLevel[0];
3801
+ await this._writeHead({
3802
+ root: newRoot.id,
3803
+ order: this.order,
3804
+ data: this.strategy.head.data
3805
+ });
3806
+ });
3807
+ }
3628
3808
  async _deleteEntry(node, key) {
3629
3809
  if (!node.leaf) {
3630
3810
  let keyIndex = -1;
@@ -3728,7 +3908,8 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3728
3908
  siblingNode.values.push(...node.values);
3729
3909
  if (!siblingNode.leaf) {
3730
3910
  const keys = siblingNode.keys;
3731
- for (const key2 of keys) {
3911
+ for (let i = 0, len = keys.length; i < len; i++) {
3912
+ const key2 = keys[i];
3732
3913
  const node2 = this._cloneNode(await this.getNode(key2));
3733
3914
  node2.parent = siblingNode.id;
3734
3915
  await this._updateNode(node2);
@@ -3796,21 +3977,24 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3796
3977
  await this._updateNode(siblingNode);
3797
3978
  }
3798
3979
  if (!siblingNode.leaf) {
3799
- for (const key2 of siblingNode.keys) {
3980
+ for (let i = 0, len = siblingNode.keys.length; i < len; i++) {
3981
+ const key2 = siblingNode.keys[i];
3800
3982
  const n = this._cloneNode(await this.getNode(key2));
3801
3983
  n.parent = siblingNode.id;
3802
3984
  await this._updateNode(n);
3803
3985
  }
3804
3986
  }
3805
3987
  if (!node.leaf) {
3806
- for (const key2 of node.keys) {
3988
+ for (let i = 0, len = node.keys.length; i < len; i++) {
3989
+ const key2 = node.keys[i];
3807
3990
  const n = this._cloneNode(await this.getNode(key2));
3808
3991
  n.parent = node.id;
3809
3992
  await this._updateNode(n);
3810
3993
  }
3811
3994
  }
3812
3995
  if (!parentNode.leaf) {
3813
- for (const key2 of parentNode.keys) {
3996
+ for (let i = 0, len = parentNode.keys.length; i < len; i++) {
3997
+ const key2 = parentNode.keys[i];
3814
3998
  const n = this._cloneNode(await this.getNode(key2));
3815
3999
  n.parent = parentNode.id;
3816
4000
  await this._updateNode(n);
@@ -3996,6 +4180,16 @@ var BPTreeAsync = class extends BPTreeAsyncTransaction {
3996
4180
  }
3997
4181
  });
3998
4182
  }
4183
+ async bulkLoad(entries) {
4184
+ return this.writeLock(1, async () => {
4185
+ const tx = await this.createTransaction();
4186
+ await tx.bulkLoad(entries);
4187
+ const result = await tx.commit();
4188
+ if (!result.success) {
4189
+ throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
4190
+ }
4191
+ });
4192
+ }
3999
4193
  };
4000
4194
 
4001
4195
  // src/base/SerializeStrategy.ts
@@ -12,4 +12,5 @@ export declare class BPTreeAsync<K, V> extends BPTreeAsyncTransaction<K, V> {
12
12
  insert(key: K, value: V): Promise<void>;
13
13
  delete(key: K, value?: V): Promise<void>;
14
14
  batchInsert(entries: [K, V][]): Promise<void>;
15
+ bulkLoad(entries: [K, V][]): Promise<void>;
15
16
  }
@@ -12,4 +12,5 @@ export declare class BPTreeSync<K, V> extends BPTreeSyncTransaction<K, V> {
12
12
  insert(key: K, value: V): void;
13
13
  delete(key: K, value?: V): void;
14
14
  batchInsert(entries: [K, V][]): void;
15
+ bulkLoad(entries: [K, V][]): void;
15
16
  }
@@ -173,6 +173,18 @@ export declare abstract class BPTreeTransaction<K, V> {
173
173
  * @param entries Array of [key, value] pairs to insert.
174
174
  */
175
175
  abstract batchInsert(entries: [K, V][]): Deferred<void>;
176
+ /**
177
+ * Builds a B+Tree from scratch using bulk loading (bottom-up construction).
178
+ * This is significantly faster than batchInsert for initial tree construction,
179
+ * as it avoids top-down traversal and creates nodes directly.
180
+ *
181
+ * **Precondition**: The tree must be empty. If the tree already contains data,
182
+ * an error will be thrown. Use batchInsert for adding data to an existing tree.
183
+ *
184
+ * @param entries Array of [key, value] pairs to bulk load.
185
+ * @throws Error if the tree is not empty.
186
+ */
187
+ abstract bulkLoad(entries: [K, V][]): Deferred<void>;
176
188
  /**
177
189
  * Deletes the pair that matches the key and value.
178
190
  * @param key The key of the pair. This key must be unique.
@@ -42,6 +42,7 @@ export declare class BPTreeAsyncTransaction<K, V> extends BPTreeTransaction<K, V
42
42
  where(condition: BPTreeCondition<V>, options?: BPTreeSearchOption<K>): Promise<BPTreePair<K, V>>;
43
43
  insert(key: K, value: V): Promise<void>;
44
44
  batchInsert(entries: [K, V][]): Promise<void>;
45
+ bulkLoad(entries: [K, V][]): Promise<void>;
45
46
  protected _deleteEntry(node: BPTreeUnknownNode<K, V>, key: BPTreeNodeKey<K>): Promise<BPTreeUnknownNode<K, V>>;
46
47
  delete(key: K, value?: V): Promise<void>;
47
48
  getHeadData(): Promise<SerializableData>;
@@ -39,6 +39,7 @@ export declare class BPTreeSyncTransaction<K, V> extends BPTreeTransaction<K, V>
39
39
  where(condition: BPTreeCondition<V>, options?: BPTreeSearchOption<K>): BPTreePair<K, V>;
40
40
  insert(key: K, value: V): void;
41
41
  batchInsert(entries: [K, V][]): void;
42
+ bulkLoad(entries: [K, V][]): void;
42
43
  protected _deleteEntry(node: BPTreeUnknownNode<K, V>, key: BPTreeNodeKey<K>): BPTreeUnknownNode<K, V>;
43
44
  delete(key: K, value?: V): void;
44
45
  getHeadData(): SerializableData;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "serializable-bptree",
3
- "version": "8.3.5",
3
+ "version": "8.4.0",
4
4
  "description": "Store the B+tree flexibly, not only in-memory.",
5
5
  "types": "./dist/types/index.d.ts",
6
6
  "main": "./dist/cjs/index.cjs",