serializable-bptree 8.3.0 → 8.3.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.
@@ -1696,6 +1696,39 @@ var BPTreeTransaction = class _BPTreeTransaction {
1696
1696
  }
1697
1697
  return true;
1698
1698
  }
1699
+ /**
1700
+ * Inserts a key-value pair into an already-cloned leaf node in-place.
1701
+ * Unlike _insertAtLeaf, this does NOT clone or update the node via MVCC.
1702
+ * Used by batchInsert to batch multiple insertions with a single clone/update.
1703
+ * @returns true if the leaf was modified, false if the key already exists.
1704
+ */
1705
+ _insertValueIntoLeaf(leaf, key, value) {
1706
+ if (leaf.values.length) {
1707
+ for (let i = 0, len = leaf.values.length; i < len; i++) {
1708
+ const nValue = leaf.values[i];
1709
+ if (this.comparator.isSame(value, nValue)) {
1710
+ if (leaf.keys[i].includes(key)) {
1711
+ return false;
1712
+ }
1713
+ leaf.keys[i].push(key);
1714
+ return true;
1715
+ } else if (this.comparator.isLower(value, nValue)) {
1716
+ leaf.values.splice(i, 0, value);
1717
+ leaf.keys.splice(i, 0, [key]);
1718
+ return true;
1719
+ } else if (i + 1 === leaf.values.length) {
1720
+ leaf.values.push(value);
1721
+ leaf.keys.push([key]);
1722
+ return true;
1723
+ }
1724
+ }
1725
+ } else {
1726
+ leaf.values = [value];
1727
+ leaf.keys = [[key]];
1728
+ return true;
1729
+ }
1730
+ return false;
1731
+ }
1699
1732
  _cloneNode(node) {
1700
1733
  return JSON.parse(JSON.stringify(node));
1701
1734
  }
@@ -2259,29 +2292,46 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2259
2292
  batchInsert(entries) {
2260
2293
  if (entries.length === 0) return;
2261
2294
  const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
2295
+ let currentLeaf = null;
2296
+ let modified = false;
2262
2297
  for (const [key, value] of sorted) {
2263
- let before = this.insertableNode(value);
2264
- before = this._insertAtLeaf(before, key, value);
2265
- if (before.values.length === this.order) {
2298
+ const targetLeaf = this.insertableNode(value);
2299
+ if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
2300
+ } else {
2301
+ if (currentLeaf !== null && modified) {
2302
+ this._updateNode(currentLeaf);
2303
+ }
2304
+ currentLeaf = this._cloneNode(targetLeaf);
2305
+ modified = false;
2306
+ }
2307
+ const changed = this._insertValueIntoLeaf(currentLeaf, key, value);
2308
+ modified = modified || changed;
2309
+ if (currentLeaf.values.length === this.order) {
2310
+ this._updateNode(currentLeaf);
2266
2311
  let after = this._createNode(
2267
2312
  true,
2268
2313
  [],
2269
2314
  [],
2270
- before.parent,
2315
+ currentLeaf.parent,
2271
2316
  null,
2272
2317
  null
2273
2318
  );
2274
2319
  const mid = Math.ceil(this.order / 2) - 1;
2275
2320
  after = this._cloneNode(after);
2276
- after.values = before.values.slice(mid + 1);
2277
- after.keys = before.keys.slice(mid + 1);
2278
- before.values = before.values.slice(0, mid + 1);
2279
- before.keys = before.keys.slice(0, mid + 1);
2280
- this._updateNode(before);
2321
+ after.values = currentLeaf.values.slice(mid + 1);
2322
+ after.keys = currentLeaf.keys.slice(mid + 1);
2323
+ currentLeaf.values = currentLeaf.values.slice(0, mid + 1);
2324
+ currentLeaf.keys = currentLeaf.keys.slice(0, mid + 1);
2325
+ this._updateNode(currentLeaf);
2281
2326
  this._updateNode(after);
2282
- this._insertInParent(before, after.values[0], after);
2327
+ this._insertInParent(currentLeaf, after.values[0], after);
2328
+ currentLeaf = null;
2329
+ modified = false;
2283
2330
  }
2284
2331
  }
2332
+ if (currentLeaf !== null && modified) {
2333
+ this._updateNode(currentLeaf);
2334
+ }
2285
2335
  }
2286
2336
  _deleteEntry(node, key) {
2287
2337
  if (!node.leaf) {
@@ -3383,29 +3433,46 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3383
3433
  if (entries.length === 0) return;
3384
3434
  return this.writeLock(0, async () => {
3385
3435
  const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
3436
+ let currentLeaf = null;
3437
+ let modified = false;
3386
3438
  for (const [key, value] of sorted) {
3387
- let before = await this.insertableNode(value);
3388
- before = await this._insertAtLeaf(before, key, value);
3389
- if (before.values.length === this.order) {
3439
+ const targetLeaf = await this.insertableNode(value);
3440
+ if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
3441
+ } else {
3442
+ if (currentLeaf !== null && modified) {
3443
+ await this._updateNode(currentLeaf);
3444
+ }
3445
+ currentLeaf = this._cloneNode(targetLeaf);
3446
+ modified = false;
3447
+ }
3448
+ const changed = this._insertValueIntoLeaf(currentLeaf, key, value);
3449
+ modified = modified || changed;
3450
+ if (currentLeaf.values.length === this.order) {
3451
+ await this._updateNode(currentLeaf);
3390
3452
  let after = await this._createNode(
3391
3453
  true,
3392
3454
  [],
3393
3455
  [],
3394
- before.parent,
3456
+ currentLeaf.parent,
3395
3457
  null,
3396
3458
  null
3397
3459
  );
3398
3460
  const mid = Math.ceil(this.order / 2) - 1;
3399
3461
  after = this._cloneNode(after);
3400
- after.values = before.values.slice(mid + 1);
3401
- after.keys = before.keys.slice(mid + 1);
3402
- before.values = before.values.slice(0, mid + 1);
3403
- before.keys = before.keys.slice(0, mid + 1);
3404
- await this._updateNode(before);
3462
+ after.values = currentLeaf.values.slice(mid + 1);
3463
+ after.keys = currentLeaf.keys.slice(mid + 1);
3464
+ currentLeaf.values = currentLeaf.values.slice(0, mid + 1);
3465
+ currentLeaf.keys = currentLeaf.keys.slice(0, mid + 1);
3466
+ await this._updateNode(currentLeaf);
3405
3467
  await this._updateNode(after);
3406
- await this._insertInParent(before, after.values[0], after);
3468
+ await this._insertInParent(currentLeaf, after.values[0], after);
3469
+ currentLeaf = null;
3470
+ modified = false;
3407
3471
  }
3408
3472
  }
3473
+ if (currentLeaf !== null && modified) {
3474
+ await this._updateNode(currentLeaf);
3475
+ }
3409
3476
  });
3410
3477
  }
3411
3478
  async _deleteEntry(node, key) {
@@ -1660,6 +1660,39 @@ var BPTreeTransaction = class _BPTreeTransaction {
1660
1660
  }
1661
1661
  return true;
1662
1662
  }
1663
+ /**
1664
+ * Inserts a key-value pair into an already-cloned leaf node in-place.
1665
+ * Unlike _insertAtLeaf, this does NOT clone or update the node via MVCC.
1666
+ * Used by batchInsert to batch multiple insertions with a single clone/update.
1667
+ * @returns true if the leaf was modified, false if the key already exists.
1668
+ */
1669
+ _insertValueIntoLeaf(leaf, key, value) {
1670
+ if (leaf.values.length) {
1671
+ for (let i = 0, len = leaf.values.length; i < len; i++) {
1672
+ const nValue = leaf.values[i];
1673
+ if (this.comparator.isSame(value, nValue)) {
1674
+ if (leaf.keys[i].includes(key)) {
1675
+ return false;
1676
+ }
1677
+ leaf.keys[i].push(key);
1678
+ return true;
1679
+ } else if (this.comparator.isLower(value, nValue)) {
1680
+ leaf.values.splice(i, 0, value);
1681
+ leaf.keys.splice(i, 0, [key]);
1682
+ return true;
1683
+ } else if (i + 1 === leaf.values.length) {
1684
+ leaf.values.push(value);
1685
+ leaf.keys.push([key]);
1686
+ return true;
1687
+ }
1688
+ }
1689
+ } else {
1690
+ leaf.values = [value];
1691
+ leaf.keys = [[key]];
1692
+ return true;
1693
+ }
1694
+ return false;
1695
+ }
1663
1696
  _cloneNode(node) {
1664
1697
  return JSON.parse(JSON.stringify(node));
1665
1698
  }
@@ -2223,29 +2256,46 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
2223
2256
  batchInsert(entries) {
2224
2257
  if (entries.length === 0) return;
2225
2258
  const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
2259
+ let currentLeaf = null;
2260
+ let modified = false;
2226
2261
  for (const [key, value] of sorted) {
2227
- let before = this.insertableNode(value);
2228
- before = this._insertAtLeaf(before, key, value);
2229
- if (before.values.length === this.order) {
2262
+ const targetLeaf = this.insertableNode(value);
2263
+ if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
2264
+ } else {
2265
+ if (currentLeaf !== null && modified) {
2266
+ this._updateNode(currentLeaf);
2267
+ }
2268
+ currentLeaf = this._cloneNode(targetLeaf);
2269
+ modified = false;
2270
+ }
2271
+ const changed = this._insertValueIntoLeaf(currentLeaf, key, value);
2272
+ modified = modified || changed;
2273
+ if (currentLeaf.values.length === this.order) {
2274
+ this._updateNode(currentLeaf);
2230
2275
  let after = this._createNode(
2231
2276
  true,
2232
2277
  [],
2233
2278
  [],
2234
- before.parent,
2279
+ currentLeaf.parent,
2235
2280
  null,
2236
2281
  null
2237
2282
  );
2238
2283
  const mid = Math.ceil(this.order / 2) - 1;
2239
2284
  after = this._cloneNode(after);
2240
- after.values = before.values.slice(mid + 1);
2241
- after.keys = before.keys.slice(mid + 1);
2242
- before.values = before.values.slice(0, mid + 1);
2243
- before.keys = before.keys.slice(0, mid + 1);
2244
- this._updateNode(before);
2285
+ after.values = currentLeaf.values.slice(mid + 1);
2286
+ after.keys = currentLeaf.keys.slice(mid + 1);
2287
+ currentLeaf.values = currentLeaf.values.slice(0, mid + 1);
2288
+ currentLeaf.keys = currentLeaf.keys.slice(0, mid + 1);
2289
+ this._updateNode(currentLeaf);
2245
2290
  this._updateNode(after);
2246
- this._insertInParent(before, after.values[0], after);
2291
+ this._insertInParent(currentLeaf, after.values[0], after);
2292
+ currentLeaf = null;
2293
+ modified = false;
2247
2294
  }
2248
2295
  }
2296
+ if (currentLeaf !== null && modified) {
2297
+ this._updateNode(currentLeaf);
2298
+ }
2249
2299
  }
2250
2300
  _deleteEntry(node, key) {
2251
2301
  if (!node.leaf) {
@@ -3347,29 +3397,46 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
3347
3397
  if (entries.length === 0) return;
3348
3398
  return this.writeLock(0, async () => {
3349
3399
  const sorted = [...entries].sort((a, b) => this.comparator.asc(a[1], b[1]));
3400
+ let currentLeaf = null;
3401
+ let modified = false;
3350
3402
  for (const [key, value] of sorted) {
3351
- let before = await this.insertableNode(value);
3352
- before = await this._insertAtLeaf(before, key, value);
3353
- if (before.values.length === this.order) {
3403
+ const targetLeaf = await this.insertableNode(value);
3404
+ if (currentLeaf !== null && currentLeaf.id === targetLeaf.id) {
3405
+ } else {
3406
+ if (currentLeaf !== null && modified) {
3407
+ await this._updateNode(currentLeaf);
3408
+ }
3409
+ currentLeaf = this._cloneNode(targetLeaf);
3410
+ modified = false;
3411
+ }
3412
+ const changed = this._insertValueIntoLeaf(currentLeaf, key, value);
3413
+ modified = modified || changed;
3414
+ if (currentLeaf.values.length === this.order) {
3415
+ await this._updateNode(currentLeaf);
3354
3416
  let after = await this._createNode(
3355
3417
  true,
3356
3418
  [],
3357
3419
  [],
3358
- before.parent,
3420
+ currentLeaf.parent,
3359
3421
  null,
3360
3422
  null
3361
3423
  );
3362
3424
  const mid = Math.ceil(this.order / 2) - 1;
3363
3425
  after = this._cloneNode(after);
3364
- after.values = before.values.slice(mid + 1);
3365
- after.keys = before.keys.slice(mid + 1);
3366
- before.values = before.values.slice(0, mid + 1);
3367
- before.keys = before.keys.slice(0, mid + 1);
3368
- await this._updateNode(before);
3426
+ after.values = currentLeaf.values.slice(mid + 1);
3427
+ after.keys = currentLeaf.keys.slice(mid + 1);
3428
+ currentLeaf.values = currentLeaf.values.slice(0, mid + 1);
3429
+ currentLeaf.keys = currentLeaf.keys.slice(0, mid + 1);
3430
+ await this._updateNode(currentLeaf);
3369
3431
  await this._updateNode(after);
3370
- await this._insertInParent(before, after.values[0], after);
3432
+ await this._insertInParent(currentLeaf, after.values[0], after);
3433
+ currentLeaf = null;
3434
+ modified = false;
3371
3435
  }
3372
3436
  }
3437
+ if (currentLeaf !== null && modified) {
3438
+ await this._updateNode(currentLeaf);
3439
+ }
3373
3440
  });
3374
3441
  }
3375
3442
  async _deleteEntry(node, key) {
@@ -80,6 +80,13 @@ export declare abstract class BPTreeTransaction<K, V> {
80
80
  * @returns Returns true if the value satisfies the condition.
81
81
  */
82
82
  verify(nodeValue: V, condition: BPTreeCondition<V>): boolean;
83
+ /**
84
+ * Inserts a key-value pair into an already-cloned leaf node in-place.
85
+ * Unlike _insertAtLeaf, this does NOT clone or update the node via MVCC.
86
+ * Used by batchInsert to batch multiple insertions with a single clone/update.
87
+ * @returns true if the leaf was modified, false if the key already exists.
88
+ */
89
+ protected _insertValueIntoLeaf(leaf: BPTreeLeafNode<K, V>, key: K, value: V): boolean;
83
90
  protected _cloneNode<T extends BPTreeUnknownNode<K, V>>(node: T): T;
84
91
  /**
85
92
  * Selects the best driver key from a condition object.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "serializable-bptree",
3
- "version": "8.3.0",
3
+ "version": "8.3.1",
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",