dataply 0.0.26-alpha.9 → 0.0.26

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/dist/cjs/index.js CHANGED
@@ -2191,13 +2191,7 @@ function insertOp(ops, ctx, key, value, comparator) {
2191
2191
  }
2192
2192
  function deleteEntry(ops, ctx, node, key, comparator) {
2193
2193
  if (!node.leaf) {
2194
- let keyIndex = -1;
2195
- for (let i = 0, len = node.keys.length; i < len; i++) {
2196
- if (node.keys[i] === key) {
2197
- keyIndex = i;
2198
- break;
2199
- }
2200
- }
2194
+ let keyIndex = node.keys.indexOf(key);
2201
2195
  if (keyIndex !== -1) {
2202
2196
  node = cloneNode(node);
2203
2197
  node.keys.splice(keyIndex, 1);
@@ -2236,17 +2230,15 @@ function deleteEntry(ops, ctx, node, key, comparator) {
2236
2230
  let nextNode = null;
2237
2231
  let prevValue = null;
2238
2232
  let postValue = null;
2239
- for (let i = 0, len = parentNode.keys.length; i < len; i++) {
2240
- const nKey = parentNode.keys[i];
2241
- if (nKey === node.id) {
2242
- if (i > 0) {
2243
- prevNode = ops.getNode(parentNode.keys[i - 1]);
2244
- prevValue = parentNode.values[i - 1];
2245
- }
2246
- if (i < parentNode.keys.length - 1) {
2247
- nextNode = ops.getNode(parentNode.keys[i + 1]);
2248
- postValue = parentNode.values[i];
2249
- }
2233
+ let keyIndex = parentNode.keys.indexOf(node.id);
2234
+ if (keyIndex !== -1) {
2235
+ if (keyIndex > 0) {
2236
+ prevNode = ops.getNode(parentNode.keys[keyIndex - 1]);
2237
+ prevValue = parentNode.values[keyIndex - 1];
2238
+ }
2239
+ if (keyIndex < parentNode.keys.length - 1) {
2240
+ nextNode = ops.getNode(parentNode.keys[keyIndex + 1]);
2241
+ postValue = parentNode.values[keyIndex];
2250
2242
  }
2251
2243
  }
2252
2244
  let siblingNode;
@@ -2279,7 +2271,7 @@ function deleteEntry(ops, ctx, node, key, comparator) {
2279
2271
  siblingNode = node;
2280
2272
  node = pTemp;
2281
2273
  }
2282
- siblingNode.keys.push(...node.keys);
2274
+ siblingNode.keys = siblingNode.keys.concat(node.keys);
2283
2275
  if (!node.leaf) {
2284
2276
  siblingNode.values.push(guess);
2285
2277
  } else {
@@ -2290,7 +2282,7 @@ function deleteEntry(ops, ctx, node, key, comparator) {
2290
2282
  ops.updateNode(n);
2291
2283
  }
2292
2284
  }
2293
- siblingNode.values.push(...node.values);
2285
+ siblingNode.values = siblingNode.values.concat(node.values);
2294
2286
  if (!siblingNode.leaf) {
2295
2287
  const keys = siblingNode.keys;
2296
2288
  for (let i = 0, len = keys.length; i < len; i++) {
@@ -2338,8 +2330,8 @@ function deleteEntry(ops, ctx, node, key, comparator) {
2338
2330
  if (!node.leaf) {
2339
2331
  pointerP0 = siblingNode.keys.splice(0, 1)[0];
2340
2332
  pointerK0 = siblingNode.values.splice(0, 1)[0];
2341
- node.keys = [...node.keys, pointerP0];
2342
- node.values = [...node.values, guess];
2333
+ node.keys = node.keys.concat(pointerP0);
2334
+ node.values = node.values.concat(guess);
2343
2335
  parentNode = cloneNode(ops.getNode(node.parent));
2344
2336
  const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
2345
2337
  if (pointerIndex > 0) {
@@ -2430,6 +2422,13 @@ function deleteOp(ops, ctx, key, comparator, value) {
2430
2422
  break;
2431
2423
  }
2432
2424
  }
2425
+ function batchDeleteOp(ops, ctx, entries, comparator) {
2426
+ if (entries.length === 0) return;
2427
+ for (let i = 0, len = entries.length; i < len; i++) {
2428
+ const [key, value] = entries[i];
2429
+ deleteOp(ops, ctx, key, comparator, value);
2430
+ }
2431
+ }
2433
2432
  function batchInsertOp(ops, ctx, entries, comparator) {
2434
2433
  if (entries.length === 0) return;
2435
2434
  const sorted = [...entries].sort((a, b) => comparator.asc(a[1], b[1]));
@@ -2985,27 +2984,12 @@ var BPTreeTransaction = class _BPTreeTransaction {
2985
2984
  static CheckConflicts(transactions) {
2986
2985
  return MVCCTransaction.CheckConflicts(transactions.map((tx) => tx.mvcc));
2987
2986
  }
2988
- /**
2989
- * Returns the ID of the root node.
2990
- * @returns The root node ID.
2991
- */
2992
2987
  getRootId() {
2993
2988
  return this.rootId;
2994
2989
  }
2995
- /**
2996
- * Returns the order of the B+Tree.
2997
- * @returns The order of the tree.
2998
- */
2999
2990
  getOrder() {
3000
2991
  return this.order;
3001
2992
  }
3002
- /**
3003
- * Verified if the value satisfies the condition.
3004
- *
3005
- * @param nodeValue The value to verify.
3006
- * @param condition The condition to verify against.
3007
- * @returns Returns true if the value satisfies the condition.
3008
- */
3009
2993
  verify(nodeValue, condition) {
3010
2994
  for (const key in condition) {
3011
2995
  const verify2 = this.verifierMap[key];
@@ -3264,6 +3248,9 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
3264
3248
  this._verifierMapCached = createVerifierMap(this.comparator, this._cachedRegexp, ensureValues);
3265
3249
  this._searchConfigsCached = createSearchConfigs(this.comparator, ensureValues);
3266
3250
  }
3251
+ getRootNode() {
3252
+ return this.getNode(this.rootId);
3253
+ }
3267
3254
  // ─── Legacy protected methods (delegating to ops) ────────────────
3268
3255
  getNode(id) {
3269
3256
  return this._ops.getNode(id);
@@ -3413,6 +3400,9 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
3413
3400
  delete(key, value) {
3414
3401
  deleteOp(this._ops, this._ctx, key, this.comparator, value);
3415
3402
  }
3403
+ batchDelete(entries) {
3404
+ batchDeleteOp(this._ops, this._ctx, entries, this.comparator);
3405
+ }
3416
3406
  // ─── Head Data ───────────────────────────────────────────────────
3417
3407
  getHeadData() {
3418
3408
  const head = this._readHead();
@@ -3534,6 +3524,14 @@ var BPTreeSync = class extends BPTreeSyncTransaction {
3534
3524
  throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
3535
3525
  }
3536
3526
  }
3527
+ batchDelete(entries) {
3528
+ const tx = this.createTransaction();
3529
+ tx.batchDelete(entries);
3530
+ const result = tx.commit();
3531
+ if (!result.success) {
3532
+ throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
3533
+ }
3534
+ }
3537
3535
  batchInsert(entries) {
3538
3536
  const tx = this.createTransaction();
3539
3537
  tx.batchInsert(entries);
@@ -4218,13 +4216,7 @@ async function insertOpAsync(ops, ctx, key, value, comparator) {
4218
4216
  }
4219
4217
  async function deleteEntryAsync(ops, ctx, node, key, comparator) {
4220
4218
  if (!node.leaf) {
4221
- let keyIndex = -1;
4222
- for (let i = 0, len = node.keys.length; i < len; i++) {
4223
- if (node.keys[i] === key) {
4224
- keyIndex = i;
4225
- break;
4226
- }
4227
- }
4219
+ let keyIndex = node.keys.indexOf(key);
4228
4220
  if (keyIndex !== -1) {
4229
4221
  node = cloneNode(node);
4230
4222
  node.keys.splice(keyIndex, 1);
@@ -4253,16 +4245,15 @@ async function deleteEntryAsync(ops, ctx, node, key, comparator) {
4253
4245
  let nextNode = null;
4254
4246
  let prevValue = null;
4255
4247
  let postValue = null;
4256
- for (let i = 0, len = parentNode.keys.length; i < len; i++) {
4257
- if (parentNode.keys[i] === node.id) {
4258
- if (i > 0) {
4259
- prevNode = await ops.getNode(parentNode.keys[i - 1]);
4260
- prevValue = parentNode.values[i - 1];
4261
- }
4262
- if (i < parentNode.keys.length - 1) {
4263
- nextNode = await ops.getNode(parentNode.keys[i + 1]);
4264
- postValue = parentNode.values[i];
4265
- }
4248
+ let keyIndex = parentNode.keys.indexOf(node.id);
4249
+ if (keyIndex !== -1) {
4250
+ if (keyIndex > 0) {
4251
+ prevNode = await ops.getNode(parentNode.keys[keyIndex - 1]);
4252
+ prevValue = parentNode.values[keyIndex - 1];
4253
+ }
4254
+ if (keyIndex < parentNode.keys.length - 1) {
4255
+ nextNode = await ops.getNode(parentNode.keys[keyIndex + 1]);
4256
+ postValue = parentNode.values[keyIndex];
4266
4257
  }
4267
4258
  }
4268
4259
  let siblingNode;
@@ -4289,11 +4280,11 @@ async function deleteEntryAsync(ops, ctx, node, key, comparator) {
4289
4280
  siblingNode = cloneNode(siblingNode);
4290
4281
  if (node.values.length + siblingNode.values.length < ctx.order) {
4291
4282
  if (!isPredecessor) {
4292
- const t = siblingNode;
4283
+ const pTemp = siblingNode;
4293
4284
  siblingNode = node;
4294
- node = t;
4285
+ node = pTemp;
4295
4286
  }
4296
- siblingNode.keys.push(...node.keys);
4287
+ siblingNode.keys = siblingNode.keys.concat(node.keys);
4297
4288
  if (!node.leaf) {
4298
4289
  siblingNode.values.push(guess);
4299
4290
  } else {
@@ -4304,7 +4295,7 @@ async function deleteEntryAsync(ops, ctx, node, key, comparator) {
4304
4295
  await ops.updateNode(n);
4305
4296
  }
4306
4297
  }
4307
- siblingNode.values.push(...node.values);
4298
+ siblingNode.values = siblingNode.values.concat(node.values);
4308
4299
  if (!siblingNode.leaf) {
4309
4300
  for (let i = 0, len = siblingNode.keys.length; i < len; i++) {
4310
4301
  const n = cloneNode(await ops.getNode(siblingNode.keys[i]));
@@ -4348,8 +4339,8 @@ async function deleteEntryAsync(ops, ctx, node, key, comparator) {
4348
4339
  if (!node.leaf) {
4349
4340
  pointerP0 = siblingNode.keys.splice(0, 1)[0];
4350
4341
  pointerK0 = siblingNode.values.splice(0, 1)[0];
4351
- node.keys = [...node.keys, pointerP0];
4352
- node.values = [...node.values, guess];
4342
+ node.keys = node.keys.concat(pointerP0);
4343
+ node.values = node.values.concat(guess);
4353
4344
  parentNode = cloneNode(await ops.getNode(node.parent));
4354
4345
  const pi = parentNode.keys.indexOf(siblingNode.id);
4355
4346
  if (pi > 0) {
@@ -4432,6 +4423,13 @@ async function deleteOpAsync(ops, ctx, key, comparator, value) {
4432
4423
  break;
4433
4424
  }
4434
4425
  }
4426
+ async function batchDeleteOpAsync(ops, ctx, entries, comparator) {
4427
+ if (entries.length === 0) return;
4428
+ for (let i = 0, len = entries.length; i < len; i++) {
4429
+ const [key, value] = entries[i];
4430
+ await deleteOpAsync(ops, ctx, key, comparator, value);
4431
+ }
4432
+ }
4435
4433
  async function batchInsertOpAsync(ops, ctx, entries, comparator) {
4436
4434
  if (entries.length === 0) return;
4437
4435
  const sorted = [...entries].sort((a, b) => comparator.asc(a[1], b[1]));
@@ -4692,6 +4690,9 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
4692
4690
  this.lock.writeUnlock(lockId);
4693
4691
  });
4694
4692
  }
4693
+ async getRootNode() {
4694
+ return this.getNode(this.rootId);
4695
+ }
4695
4696
  // ─── Legacy protected methods (delegating to ops) ────────────────
4696
4697
  async getNode(id) {
4697
4698
  return this._ops.getNode(id);
@@ -4851,6 +4852,12 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
4851
4852
  await deleteOpAsync(this._ops, this._ctx, key, this.comparator, value);
4852
4853
  });
4853
4854
  }
4855
+ async batchDelete(entries) {
4856
+ if (entries.length === 0) return;
4857
+ return this.writeLock(0, async () => {
4858
+ await batchDeleteOpAsync(this._ops, this._ctx, entries, this.comparator);
4859
+ });
4860
+ }
4854
4861
  // ─── Head Data ───────────────────────────────────────────────────
4855
4862
  async getHeadData() {
4856
4863
  const head = await this._readHead();
@@ -4976,6 +4983,16 @@ var BPTreeAsync = class extends BPTreeAsyncTransaction {
4976
4983
  }
4977
4984
  });
4978
4985
  }
4986
+ async batchDelete(entries) {
4987
+ return this.writeLock(1, async () => {
4988
+ const tx = await this.createTransaction();
4989
+ await tx.batchDelete(entries);
4990
+ const result = await tx.commit();
4991
+ if (!result.success) {
4992
+ throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
4993
+ }
4994
+ });
4995
+ }
4979
4996
  async batchInsert(entries) {
4980
4997
  return this.writeLock(1, async () => {
4981
4998
  const tx = await this.createTransaction();
@@ -5017,9 +5034,14 @@ var BPTreePureSync = class {
5017
5034
  }
5018
5035
  _createReadOps() {
5019
5036
  const strategy = this.strategy;
5037
+ const readBuffer = /* @__PURE__ */ new Map();
5020
5038
  return {
5021
5039
  getNode(id) {
5022
- return strategy.read(id);
5040
+ const buffered = readBuffer.get(id);
5041
+ if (buffered) return buffered;
5042
+ const node = strategy.read(id);
5043
+ readBuffer.set(id, node);
5044
+ return node;
5023
5045
  },
5024
5046
  createNode(leaf, keys, values, parent = null, next = null, prev = null) {
5025
5047
  const id = strategy.id(leaf);
@@ -5039,6 +5061,7 @@ var BPTreePureSync = class {
5039
5061
  }
5040
5062
  _createBufferedOps() {
5041
5063
  const strategy = this.strategy;
5064
+ const readBuffer = /* @__PURE__ */ new Map();
5042
5065
  const writeBuffer = /* @__PURE__ */ new Map();
5043
5066
  const deleteBuffer = /* @__PURE__ */ new Set();
5044
5067
  let headBuffer = null;
@@ -5046,7 +5069,11 @@ var BPTreePureSync = class {
5046
5069
  getNode(id) {
5047
5070
  const buffered = writeBuffer.get(id);
5048
5071
  if (buffered) return buffered;
5049
- return strategy.read(id);
5072
+ const read = readBuffer.get(id);
5073
+ if (read) return read;
5074
+ const node = strategy.read(id);
5075
+ readBuffer.set(id, node);
5076
+ return node;
5050
5077
  },
5051
5078
  createNode(leaf, keys, values, parent = null, next = null, prev = null) {
5052
5079
  const id = strategy.id(leaf);
@@ -5071,6 +5098,7 @@ var BPTreePureSync = class {
5071
5098
  };
5072
5099
  function flush() {
5073
5100
  for (const id of deleteBuffer) {
5101
+ writeBuffer.delete(id);
5074
5102
  strategy.delete(id);
5075
5103
  }
5076
5104
  for (const [id, node] of writeBuffer) {
@@ -5079,6 +5107,10 @@ var BPTreePureSync = class {
5079
5107
  if (headBuffer) {
5080
5108
  strategy.writeHead(headBuffer);
5081
5109
  }
5110
+ readBuffer.clear();
5111
+ writeBuffer.clear();
5112
+ deleteBuffer.clear();
5113
+ headBuffer = null;
5082
5114
  }
5083
5115
  return { ops, flush };
5084
5116
  }
@@ -5119,21 +5151,18 @@ var BPTreePureSync = class {
5119
5151
  );
5120
5152
  flush();
5121
5153
  }
5122
- /**
5123
- * Returns the ID of the root node.
5124
- */
5154
+ getRootNode() {
5155
+ const ctx = this._readCtx();
5156
+ return this.strategy.read(ctx.rootId);
5157
+ }
5125
5158
  getRootId() {
5126
- return this._readCtx().rootId;
5159
+ const ctx = this._readCtx();
5160
+ return ctx.rootId;
5127
5161
  }
5128
- /**
5129
- * Returns the order of the B+Tree.
5130
- */
5131
5162
  getOrder() {
5132
- return this._readCtx().order;
5163
+ const ctx = this._readCtx();
5164
+ return ctx.order;
5133
5165
  }
5134
- /**
5135
- * Verified if the value satisfies the condition.
5136
- */
5137
5166
  verify(nodeValue, condition) {
5138
5167
  for (const key in condition) {
5139
5168
  const verifyFn = this._verifierMap[key];
@@ -5146,18 +5175,18 @@ var BPTreePureSync = class {
5146
5175
  }
5147
5176
  // ─── Query ───────────────────────────────────────────────────────
5148
5177
  get(key) {
5149
- const { rootId } = this._readCtx();
5150
- return getOp(this._createReadOps(), rootId, key);
5178
+ const ctx = this._readCtx();
5179
+ return getOp(this._createReadOps(), ctx.rootId, key);
5151
5180
  }
5152
5181
  exists(key, value) {
5153
- const { rootId } = this._readCtx();
5154
- return existsOp(this._createReadOps(), rootId, key, value, this.comparator);
5182
+ const ctx = this._readCtx();
5183
+ return existsOp(this._createReadOps(), ctx.rootId, key, value, this.comparator);
5155
5184
  }
5156
5185
  *keysStream(condition, options) {
5157
- const { rootId } = this._readCtx();
5186
+ const ctx = this._readCtx();
5158
5187
  yield* keysStreamOp(
5159
5188
  this._createReadOps(),
5160
- rootId,
5189
+ ctx.rootId,
5161
5190
  condition,
5162
5191
  this.comparator,
5163
5192
  this._verifierMap,
@@ -5167,10 +5196,10 @@ var BPTreePureSync = class {
5167
5196
  );
5168
5197
  }
5169
5198
  *whereStream(condition, options) {
5170
- const { rootId } = this._readCtx();
5199
+ const ctx = this._readCtx();
5171
5200
  yield* whereStreamOp(
5172
5201
  this._createReadOps(),
5173
- rootId,
5202
+ ctx.rootId,
5174
5203
  condition,
5175
5204
  this.comparator,
5176
5205
  this._verifierMap,
@@ -5206,6 +5235,12 @@ var BPTreePureSync = class {
5206
5235
  deleteOp(ops, ctx, key, this.comparator, value);
5207
5236
  flush();
5208
5237
  }
5238
+ batchDelete(entries) {
5239
+ const { ops, flush } = this._createBufferedOps();
5240
+ const ctx = this._createCtx();
5241
+ batchDeleteOp(ops, ctx, entries, this.comparator);
5242
+ flush();
5243
+ }
5209
5244
  batchInsert(entries) {
5210
5245
  const { ops, flush } = this._createBufferedOps();
5211
5246
  const ctx = this._createCtx();
@@ -5263,6 +5298,7 @@ var BPTreePureAsync = class {
5263
5298
  }
5264
5299
  _createReadOps() {
5265
5300
  const strategy = this.strategy;
5301
+ let headBuffer = null;
5266
5302
  return {
5267
5303
  async getNode(id) {
5268
5304
  return await strategy.read(id);
@@ -5277,9 +5313,12 @@ var BPTreePureAsync = class {
5277
5313
  async deleteNode() {
5278
5314
  },
5279
5315
  async readHead() {
5280
- return await strategy.readHead();
5316
+ if (headBuffer) return headBuffer;
5317
+ headBuffer = await strategy.readHead();
5318
+ return headBuffer;
5281
5319
  },
5282
- async writeHead() {
5320
+ async writeHead(head) {
5321
+ headBuffer = head;
5283
5322
  }
5284
5323
  };
5285
5324
  }
@@ -5309,7 +5348,8 @@ var BPTreePureAsync = class {
5309
5348
  },
5310
5349
  async readHead() {
5311
5350
  if (headBuffer) return headBuffer;
5312
- return await strategy.readHead();
5351
+ headBuffer = await strategy.readHead();
5352
+ return headBuffer;
5313
5353
  },
5314
5354
  async writeHead(head) {
5315
5355
  headBuffer = head;
@@ -5317,6 +5357,7 @@ var BPTreePureAsync = class {
5317
5357
  };
5318
5358
  async function flush() {
5319
5359
  for (const id of deleteBuffer) {
5360
+ writeBuffer.delete(id);
5320
5361
  await strategy.delete(id);
5321
5362
  }
5322
5363
  for (const [id, node] of writeBuffer) {
@@ -5325,6 +5366,9 @@ var BPTreePureAsync = class {
5325
5366
  if (headBuffer) {
5326
5367
  await strategy.writeHead(headBuffer);
5327
5368
  }
5369
+ writeBuffer.clear();
5370
+ deleteBuffer.clear();
5371
+ headBuffer = null;
5328
5372
  }
5329
5373
  return { ops, flush };
5330
5374
  }
@@ -5376,11 +5420,17 @@ var BPTreePureAsync = class {
5376
5420
  await flush();
5377
5421
  });
5378
5422
  }
5423
+ async getRootNode() {
5424
+ const ctx = await this._readCtx();
5425
+ return await this.strategy.read(ctx.rootId);
5426
+ }
5379
5427
  async getRootId() {
5380
- return (await this._readCtx()).rootId;
5428
+ const ctx = await this._readCtx();
5429
+ return ctx.rootId;
5381
5430
  }
5382
5431
  async getOrder() {
5383
- return (await this._readCtx()).order;
5432
+ const ctx = await this._readCtx();
5433
+ return ctx.order;
5384
5434
  }
5385
5435
  verify(nodeValue, condition) {
5386
5436
  for (const key in condition) {
@@ -5392,21 +5442,21 @@ var BPTreePureAsync = class {
5392
5442
  }
5393
5443
  // ─── Query ───────────────────────────────────────────────────────
5394
5444
  async get(key) {
5395
- const { rootId } = await this._readCtx();
5396
- return getOpAsync(this._createReadOps(), rootId, key);
5445
+ const ctx = await this._readCtx();
5446
+ return getOpAsync(this._createReadOps(), ctx.rootId, key);
5397
5447
  }
5398
5448
  async exists(key, value) {
5399
- const { rootId } = await this._readCtx();
5400
- return existsOpAsync(this._createReadOps(), rootId, key, value, this.comparator);
5449
+ const ctx = await this._readCtx();
5450
+ return existsOpAsync(this._createReadOps(), ctx.rootId, key, value, this.comparator);
5401
5451
  }
5402
5452
  async *keysStream(condition, options) {
5403
5453
  let lockId;
5404
5454
  try {
5405
5455
  lockId = await this.lock.readLock([0, 0.1], async (id) => id);
5406
- const { rootId } = await this._readCtx();
5456
+ const ctx = await this._readCtx();
5407
5457
  yield* keysStreamOpAsync(
5408
5458
  this._createReadOps(),
5409
- rootId,
5459
+ ctx.rootId,
5410
5460
  condition,
5411
5461
  this.comparator,
5412
5462
  this._verifierMap,
@@ -5422,10 +5472,10 @@ var BPTreePureAsync = class {
5422
5472
  let lockId;
5423
5473
  try {
5424
5474
  lockId = await this.lock.readLock([0, 0.1], async (id) => id);
5425
- const { rootId } = await this._readCtx();
5475
+ const ctx = await this._readCtx();
5426
5476
  yield* whereStreamOpAsync(
5427
5477
  this._createReadOps(),
5428
- rootId,
5478
+ ctx.rootId,
5429
5479
  condition,
5430
5480
  this.comparator,
5431
5481
  this._verifierMap,
@@ -5476,6 +5526,14 @@ var BPTreePureAsync = class {
5476
5526
  await flush();
5477
5527
  });
5478
5528
  }
5529
+ async batchDelete(entries) {
5530
+ return this.writeLock(async () => {
5531
+ const { ops, flush } = this._createBufferedOps();
5532
+ const ctx = await this._createCtx();
5533
+ await batchDeleteOpAsync(ops, ctx, entries, this.comparator);
5534
+ await flush();
5535
+ });
5536
+ }
5479
5537
  async bulkLoad(entries) {
5480
5538
  return this.writeLock(async () => {
5481
5539
  const { ops, flush } = this._createBufferedOps();
@@ -9907,7 +9965,7 @@ var PageFileSystem = class {
9907
9965
  * @param tx Transaction
9908
9966
  */
9909
9967
  async updateBitmap(pageId, isFree, tx) {
9910
- const metadata = await this.getMetadata(tx);
9968
+ const metadata = await this.getMetadata(false, tx);
9911
9969
  const metadataManager = this.pageFactory.getManager(metadata);
9912
9970
  const bitmapPageId = metadataManager.getBitmapPageId(metadata);
9913
9971
  const headerSize = PageManager.CONSTANT.SIZE_PAGE_HEADER;
@@ -9915,7 +9973,7 @@ var PageFileSystem = class {
9915
9973
  let currentBitmapPageId = bitmapPageId;
9916
9974
  let targetBitIndex = pageId;
9917
9975
  while (targetBitIndex >= capacityPerBitmapPage) {
9918
- const currentBitmapPage = await this.get(currentBitmapPageId, tx);
9976
+ const currentBitmapPage = await this.get(currentBitmapPageId, true, tx);
9919
9977
  const manager = this.pageFactory.getManager(currentBitmapPage);
9920
9978
  targetBitIndex -= capacityPerBitmapPage;
9921
9979
  const nextPageId = manager.getNextPageId(currentBitmapPage);
@@ -9932,7 +9990,7 @@ var PageFileSystem = class {
9932
9990
  }
9933
9991
  }
9934
9992
  await tx.__acquireWriteLock(currentBitmapPageId);
9935
- const targetBitmapPage = await this.get(currentBitmapPageId, tx);
9993
+ const targetBitmapPage = await this.get(currentBitmapPageId, true, tx);
9936
9994
  const bitmapManager = this.pageFactory.getManager(targetBitmapPage);
9937
9995
  bitmapManager.setBit(targetBitmapPage, targetBitIndex, isFree);
9938
9996
  await this.setPage(currentBitmapPageId, targetBitmapPage, tx);
@@ -9951,20 +10009,22 @@ var PageFileSystem = class {
9951
10009
  }
9952
10010
  /**
9953
10011
  * @param pageIndex 페이지 인덱스
10012
+ * @param copy Copy-on-Read
9954
10013
  * @param tx 트랜잭션
9955
10014
  * @returns 페이지 버퍼
9956
10015
  */
9957
- async get(pageIndex, tx) {
9958
- return tx.__readPage(pageIndex);
10016
+ async get(pageIndex, copy, tx) {
10017
+ return tx.__readPage(pageIndex, copy);
9959
10018
  }
9960
10019
  /**
9961
10020
  * Reads the page header.
9962
10021
  * @param pageIndex Page index
10022
+ * @param copy Copy-on-Read
9963
10023
  * @param tx Transaction
9964
10024
  * @returns Page header buffer
9965
10025
  */
9966
- async getHeader(pageIndex, tx) {
9967
- const page = await this.get(pageIndex, tx);
10026
+ async getHeader(pageIndex, copy, tx) {
10027
+ const page = await this.get(pageIndex, copy, tx);
9968
10028
  return page.subarray(0, PageManager.CONSTANT.SIZE_PAGE_HEADER);
9969
10029
  }
9970
10030
  /**
@@ -9975,7 +10035,7 @@ var PageFileSystem = class {
9975
10035
  * @returns Page body buffer
9976
10036
  */
9977
10037
  async getBody(pageIndex, recursive = false, tx) {
9978
- const page = await this.get(pageIndex, tx);
10038
+ const page = await this.get(pageIndex, false, tx);
9979
10039
  const manager = this.pageFactory.getManager(page);
9980
10040
  const fullBody = manager.getBody(page);
9981
10041
  if (!recursive) {
@@ -9993,11 +10053,12 @@ var PageFileSystem = class {
9993
10053
  }
9994
10054
  /**
9995
10055
  * Returns the metadata page.
10056
+ * @param copy Copy-on-Read
9996
10057
  * @param tx Transaction
9997
10058
  * @returns Metadata page
9998
10059
  */
9999
- async getMetadata(tx) {
10000
- const page = await this.get(0, tx);
10060
+ async getMetadata(copy, tx) {
10061
+ const page = await this.get(0, copy, tx);
10001
10062
  if (!MetadataPageManager.IsMetadataPage(page)) {
10002
10063
  throw new Error("Invalid metadata page");
10003
10064
  }
@@ -10009,20 +10070,21 @@ var PageFileSystem = class {
10009
10070
  * @returns Number of pages
10010
10071
  */
10011
10072
  async getPageCount(tx) {
10012
- const metadata = await this.getMetadata(tx);
10073
+ const metadata = await this.getMetadata(false, tx);
10013
10074
  const manager = this.pageFactory.getManager(metadata);
10014
10075
  return manager.getPageCount(metadata);
10015
10076
  }
10016
10077
  /**
10017
10078
  * Returns the root index page.
10079
+ * @param copy Copy-on-Read
10018
10080
  * @param tx Transaction
10019
10081
  * @returns Root index page
10020
10082
  */
10021
- async getRootIndex(tx) {
10022
- const metadata = await this.getMetadata(tx);
10083
+ async getRootIndex(copy, tx) {
10084
+ const metadata = await this.getMetadata(false, tx);
10023
10085
  const manager = this.pageFactory.getManager(metadata);
10024
10086
  const rootIndexPageId = manager.getRootIndexPageId(metadata);
10025
- const rootIndexPage = await this.get(rootIndexPageId, tx);
10087
+ const rootIndexPage = await this.get(rootIndexPageId, copy, tx);
10026
10088
  if (!IndexPageManager.IsIndexPage(rootIndexPage)) {
10027
10089
  throw new Error("Invalid root index page");
10028
10090
  }
@@ -10057,12 +10119,12 @@ var PageFileSystem = class {
10057
10119
  async appendNewPage(pageType = PageManager.CONSTANT.PAGE_TYPE_EMPTY, tx) {
10058
10120
  this.logger.debug(`Appending new page of type ${pageType}`);
10059
10121
  await tx.__acquireWriteLock(0);
10060
- const metadata = await this.getMetadata(tx);
10122
+ const metadata = await this.getMetadata(true, tx);
10061
10123
  const metadataManager = this.pageFactory.getManager(metadata);
10062
10124
  const freePageId = metadataManager.getFreePageId(metadata);
10063
10125
  if (freePageId !== -1) {
10064
10126
  const reusedPageId = freePageId;
10065
- const reusedPage = await this.get(reusedPageId, tx);
10127
+ const reusedPage = await this.get(reusedPageId, false, tx);
10066
10128
  const reusedPageManager = this.pageFactory.getManager(reusedPage);
10067
10129
  const nextFreePageId = reusedPageManager.getNextPageId(reusedPage);
10068
10130
  metadataManager.setFreePageId(metadata, nextFreePageId);
@@ -10107,7 +10169,7 @@ var PageFileSystem = class {
10107
10169
  let currentOffset = offset;
10108
10170
  let dataOffset = 0;
10109
10171
  while (dataOffset < data.length) {
10110
- const page = await this.get(currentPageId, tx);
10172
+ const page = await this.get(currentPageId, true, tx);
10111
10173
  const manager = this.pageFactory.getManager(page);
10112
10174
  const bodyStart = PageManager.CONSTANT.SIZE_PAGE_HEADER;
10113
10175
  const bodySize = this.pageSize - bodyStart;
@@ -10167,7 +10229,7 @@ var PageFileSystem = class {
10167
10229
  break;
10168
10230
  }
10169
10231
  visited.add(currentPageId);
10170
- const page = await this.get(currentPageId, tx);
10232
+ const page = await this.get(currentPageId, false, tx);
10171
10233
  const nextPageId = this.pageFactory.getManager(page).getNextPageId(page);
10172
10234
  await this.setFreePage(currentPageId, tx);
10173
10235
  currentPageId = nextPageId;
@@ -10183,7 +10245,7 @@ var PageFileSystem = class {
10183
10245
  if (pageId <= 0) return;
10184
10246
  await tx.__acquireWriteLock(0);
10185
10247
  await tx.__acquireWriteLock(pageId);
10186
- const metadata = await this.getMetadata(tx);
10248
+ const metadata = await this.getMetadata(true, tx);
10187
10249
  const metadataManager = this.pageFactory.getManager(metadata);
10188
10250
  const currentHeadFreePageId = metadataManager.getFreePageId(metadata);
10189
10251
  const emptyPageManager = this.pageFactory.getManagerFromType(PageManager.CONSTANT.PAGE_TYPE_EMPTY);
@@ -10266,12 +10328,12 @@ var RowIdentifierStrategy = class extends SerializeStrategyAsync {
10266
10328
  async id(isLeaf) {
10267
10329
  const tx = this.txContext.get();
10268
10330
  await tx.__acquireWriteLock(0);
10269
- const metadata = await this.pfs.getMetadata(tx);
10331
+ const metadata = await this.pfs.getMetadata(true, tx);
10270
10332
  const metadataManager = this.factory.getManager(metadata);
10271
10333
  const freePageId = metadataManager.getFreePageId(metadata);
10272
10334
  let pageId;
10273
10335
  if (freePageId !== -1) {
10274
- const freePage = await this.pfs.get(freePageId, tx);
10336
+ const freePage = await this.pfs.get(freePageId, false, tx);
10275
10337
  const freePageManager = this.factory.getManager(freePage);
10276
10338
  const nextFreePageId = freePageManager.getNextPageId(freePage);
10277
10339
  metadataManager.setFreePageId(metadata, nextFreePageId);
@@ -10287,7 +10349,7 @@ var RowIdentifierStrategy = class extends SerializeStrategyAsync {
10287
10349
  async read(id) {
10288
10350
  const tx = this.txContext.get();
10289
10351
  const pageId = +id;
10290
- const page = await this.pfs.get(pageId, tx);
10352
+ const page = await this.pfs.get(pageId, false, tx);
10291
10353
  if (!IndexPageManager.IsIndexPage(page)) {
10292
10354
  throw new Error(`Node ${id} does not exist - not a valid index page`);
10293
10355
  }
@@ -10322,7 +10384,7 @@ var RowIdentifierStrategy = class extends SerializeStrategyAsync {
10322
10384
  async write(id, node) {
10323
10385
  const tx = this.txContext.get();
10324
10386
  const pageId = +id;
10325
- let page = await this.pfs.get(pageId, tx);
10387
+ let page = await this.pfs.get(pageId, true, tx);
10326
10388
  if (!IndexPageManager.IsIndexPage(page)) {
10327
10389
  page = this.indexPageManger.create(this.pfs.pageSize, pageId);
10328
10390
  }
@@ -10370,7 +10432,7 @@ var RowIdentifierStrategy = class extends SerializeStrategyAsync {
10370
10432
  }
10371
10433
  async readHead() {
10372
10434
  const tx = this.txContext.get();
10373
- const metadataPage = await this.pfs.getMetadata(tx);
10435
+ const metadataPage = await this.pfs.getMetadata(false, tx);
10374
10436
  const manager = this.factory.getManager(metadataPage);
10375
10437
  const rootIndexPageId = manager.getRootIndexPageId(metadataPage);
10376
10438
  if (rootIndexPageId === -1) {
@@ -10390,7 +10452,7 @@ var RowIdentifierStrategy = class extends SerializeStrategyAsync {
10390
10452
  if (root === null) {
10391
10453
  throw new Error("");
10392
10454
  }
10393
- const metadataPage = await this.pfs.getMetadata(tx);
10455
+ const metadataPage = await this.pfs.getMetadata(true, tx);
10394
10456
  const manager = this.factory.getManager(metadataPage);
10395
10457
  manager.setRootIndexPageId(metadataPage, +root);
10396
10458
  manager.setRootIndexOrder(metadataPage, order);
@@ -10551,7 +10613,7 @@ var RowTableEngine = class {
10551
10613
  if (!this.initialized) {
10552
10614
  throw new Error("RowTableEngine instance is not initialized");
10553
10615
  }
10554
- const metadataPage = await this.pfs.getMetadata(tx);
10616
+ const metadataPage = await this.pfs.getMetadata(false, tx);
10555
10617
  const manager = this.factory.getManagerFromType(MetadataPageManager.CONSTANT.PAGE_TYPE_METADATA);
10556
10618
  const pageSize = manager.getPageSize(metadataPage);
10557
10619
  const pageCount = manager.getPageCount(metadataPage);
@@ -10579,10 +10641,10 @@ var RowTableEngine = class {
10579
10641
  }
10580
10642
  await tx.__acquireWriteLock(0);
10581
10643
  const pks = [];
10582
- const metadataPage = await this.pfs.getMetadata(tx);
10644
+ const metadataPage = await this.pfs.getMetadata(false, tx);
10583
10645
  let lastPk = this.metadataPageManager.getLastRowPk(metadataPage);
10584
10646
  let lastInsertDataPageId = this.metadataPageManager.getLastInsertPageId(metadataPage);
10585
- let lastInsertDataPage = await this.pfs.get(lastInsertDataPageId, tx);
10647
+ let lastInsertDataPage = await this.pfs.get(lastInsertDataPageId, true, tx);
10586
10648
  if (!this.factory.isDataPage(lastInsertDataPage)) {
10587
10649
  throw new Error(`Last insert page is not data page`);
10588
10650
  }
@@ -10604,7 +10666,7 @@ var RowTableEngine = class {
10604
10666
  await this.pfs.setPage(lastInsertDataPageId, lastInsertDataPage, tx);
10605
10667
  } else {
10606
10668
  const newPageId = await this.pfs.appendNewPage(this.dataPageManager.pageType, tx);
10607
- const newPage = await this.pfs.get(newPageId, tx);
10669
+ const newPage = await this.pfs.get(newPageId, true, tx);
10608
10670
  this.dataPageManager.insert(newPage, row);
10609
10671
  this.setRID(newPageId, 0);
10610
10672
  lastInsertDataPageId = newPageId;
@@ -10619,7 +10681,7 @@ var RowTableEngine = class {
10619
10681
  this.rowManager.setBody(row, data);
10620
10682
  if (slotIndex === -1) {
10621
10683
  const newPageId = await this.pfs.appendNewPage(this.dataPageManager.pageType, tx);
10622
- const newPage = await this.pfs.get(newPageId, tx);
10684
+ const newPage = await this.pfs.get(newPageId, true, tx);
10623
10685
  this.dataPageManager.insert(newPage, row);
10624
10686
  this.setRID(newPageId, 0);
10625
10687
  lastInsertDataPageId = newPageId;
@@ -10635,7 +10697,7 @@ var RowTableEngine = class {
10635
10697
  pks.push(pk);
10636
10698
  }
10637
10699
  await this.bptree.batchInsert(batchInsertData);
10638
- const freshMetadataPage = await this.pfs.getMetadata(tx);
10700
+ const freshMetadataPage = await this.pfs.getMetadata(true, tx);
10639
10701
  this.metadataPageManager.setLastInsertPageId(freshMetadataPage, lastInsertDataPageId);
10640
10702
  this.metadataPageManager.setLastRowPk(freshMetadataPage, lastPk);
10641
10703
  if (incrementRowCount) {
@@ -10681,7 +10743,7 @@ var RowTableEngine = class {
10681
10743
  this.keyManager.setBufferFromKey(rid, this.ridBuffer);
10682
10744
  const pageId = this.keyManager.getPageId(this.ridBuffer);
10683
10745
  const slotIndex = this.keyManager.getSlotIndex(this.ridBuffer);
10684
- const page = await this.pfs.get(pageId, tx);
10746
+ const page = await this.pfs.get(pageId, true, tx);
10685
10747
  if (!this.factory.isDataPage(page)) {
10686
10748
  throw new Error(`RID not found for PK: ${pk}`);
10687
10749
  }
@@ -10717,22 +10779,22 @@ var RowTableEngine = class {
10717
10779
  this.rowManager.setBodySize(newRow, newBodySize);
10718
10780
  this.rowManager.setBody(newRow, data);
10719
10781
  await tx.__acquireWriteLock(0);
10720
- const metadataPage = await this.pfs.getMetadata(tx);
10782
+ const metadataPage = await this.pfs.getMetadata(false, tx);
10721
10783
  let lastInsertDataPageId = this.metadataPageManager.getLastInsertPageId(metadataPage);
10722
- let lastInsertDataPage = await this.pfs.get(lastInsertDataPageId, tx);
10784
+ let lastInsertDataPage = await this.pfs.get(lastInsertDataPageId, true, tx);
10723
10785
  if (!this.factory.isDataPage(lastInsertDataPage)) {
10724
10786
  throw new Error("Last insert page is not data page");
10725
10787
  }
10726
10788
  let newSlotIndex = this.dataPageManager.getNextSlotIndex(lastInsertDataPage, newRow);
10727
10789
  if (newSlotIndex === -1) {
10728
10790
  const newPageId = await this.pfs.appendNewPage(this.dataPageManager.pageType, tx);
10729
- lastInsertDataPage = await this.pfs.get(newPageId, tx);
10791
+ lastInsertDataPage = await this.pfs.get(newPageId, true, tx);
10730
10792
  lastInsertDataPageId = newPageId;
10731
10793
  newSlotIndex = 0;
10732
10794
  }
10733
10795
  this.dataPageManager.insert(lastInsertDataPage, newRow);
10734
10796
  await this.pfs.setPage(lastInsertDataPageId, lastInsertDataPage, tx);
10735
- const targetPage = await this.pfs.get(pageId, tx);
10797
+ const targetPage = await this.pfs.get(pageId, true, tx);
10736
10798
  if (!this.factory.isDataPage(targetPage)) {
10737
10799
  throw new Error("Target page is not data page");
10738
10800
  }
@@ -10745,7 +10807,7 @@ var RowTableEngine = class {
10745
10807
  const newRidNumeric = this.getRID();
10746
10808
  await this.bptree.delete(oldRidNumeric, pk);
10747
10809
  await this.bptree.insert(newRidNumeric, pk);
10748
- const freshMetadataPage = await this.pfs.getMetadata(tx);
10810
+ const freshMetadataPage = await this.pfs.getMetadata(true, tx);
10749
10811
  this.metadataPageManager.setLastInsertPageId(freshMetadataPage, lastInsertDataPageId);
10750
10812
  await this.pfs.setMetadata(freshMetadataPage, tx);
10751
10813
  }
@@ -10765,7 +10827,7 @@ var RowTableEngine = class {
10765
10827
  this.keyManager.setBufferFromKey(rid, this.ridBuffer);
10766
10828
  const pageId = this.keyManager.getPageId(this.ridBuffer);
10767
10829
  const slotIndex = this.keyManager.getSlotIndex(this.ridBuffer);
10768
- const page = await this.pfs.get(pageId, tx);
10830
+ const page = await this.pfs.get(pageId, true, tx);
10769
10831
  if (!this.factory.isDataPage(page)) {
10770
10832
  throw new Error(`RID not found for PK: ${pk}`);
10771
10833
  }
@@ -10781,14 +10843,14 @@ var RowTableEngine = class {
10781
10843
  await this.pfs.setPage(pageId, page, tx);
10782
10844
  await this.bptree.delete(rid, pk);
10783
10845
  if (decrementRowCount) {
10784
- const metadataPage2 = await this.pfs.getMetadata(tx);
10846
+ const metadataPage2 = await this.pfs.getMetadata(true, tx);
10785
10847
  const currentRowCount = this.metadataPageManager.getRowCount(metadataPage2);
10786
10848
  this.metadataPageManager.setRowCount(metadataPage2, currentRowCount - 1);
10787
10849
  await this.pfs.setMetadata(metadataPage2, tx);
10788
10850
  }
10789
10851
  const insertedRowCount = this.dataPageManager.getInsertedRowCount(page);
10790
10852
  let allDeleted = true;
10791
- const metadataPage = await this.pfs.getMetadata(tx);
10853
+ const metadataPage = await this.pfs.getMetadata(false, tx);
10792
10854
  const lastInsertPageId = this.metadataPageManager.getLastInsertPageId(metadataPage);
10793
10855
  if (pageId === lastInsertPageId) {
10794
10856
  allDeleted = false;
@@ -10807,6 +10869,82 @@ var RowTableEngine = class {
10807
10869
  await this.pfs.freeChain(pageId, tx);
10808
10870
  }
10809
10871
  }
10872
+ /**
10873
+ * Deletes multiple data in batch.
10874
+ * @param pks Array of PKs to delete
10875
+ * @param decrementRowCount Whether to decrement the row count to metadata
10876
+ * @param tx Transaction
10877
+ */
10878
+ async deleteBatch(pks, decrementRowCount, tx) {
10879
+ this.logger.debug(`Batch deleting ${pks.length} rows`);
10880
+ if (pks.length === 0) {
10881
+ return;
10882
+ }
10883
+ await tx.__acquireWriteLock(0);
10884
+ const collections = await this.collectItemsByPage(pks, tx);
10885
+ if (collections.size === 0) {
10886
+ return;
10887
+ }
10888
+ const metadataPage = await this.pfs.getMetadata(false, tx);
10889
+ const lastInsertPageId = this.metadataPageManager.getLastInsertPageId(metadataPage);
10890
+ const batchDeleteData = [];
10891
+ const pagesToFree = [];
10892
+ let deletedCount = 0;
10893
+ for (const [pageId, items] of collections) {
10894
+ const page = await this.pfs.get(pageId, true, tx);
10895
+ if (!this.factory.isDataPage(page)) {
10896
+ continue;
10897
+ }
10898
+ let pageModified = false;
10899
+ for (const item of items) {
10900
+ const row = this.dataPageManager.getRow(page, item.slotIndex);
10901
+ if (this.rowManager.getDeletedFlag(row)) {
10902
+ continue;
10903
+ }
10904
+ if (this.rowManager.getOverflowFlag(row)) {
10905
+ const overflowPageId = bytesToNumber(this.rowManager.getBody(row));
10906
+ await this.pfs.freeChain(overflowPageId, tx);
10907
+ }
10908
+ this.rowManager.setDeletedFlag(row, true);
10909
+ pageModified = true;
10910
+ this.setRID(pageId, item.slotIndex);
10911
+ batchDeleteData.push([this.getRID(), item.pk]);
10912
+ deletedCount++;
10913
+ }
10914
+ if (pageModified) {
10915
+ await this.pfs.setPage(pageId, page, tx);
10916
+ }
10917
+ if (pageId !== lastInsertPageId) {
10918
+ const insertedRowCount = this.dataPageManager.getInsertedRowCount(page);
10919
+ let allDeleted = true;
10920
+ let i = 0;
10921
+ while (i < insertedRowCount) {
10922
+ const slotRow = this.dataPageManager.getRow(page, i);
10923
+ if (!this.rowManager.getDeletedFlag(slotRow)) {
10924
+ allDeleted = false;
10925
+ break;
10926
+ }
10927
+ i++;
10928
+ }
10929
+ if (allDeleted) {
10930
+ pagesToFree.push(pageId);
10931
+ }
10932
+ }
10933
+ }
10934
+ if (batchDeleteData.length === 0) {
10935
+ return;
10936
+ }
10937
+ await this.bptree.batchDelete(batchDeleteData);
10938
+ if (decrementRowCount) {
10939
+ const freshMetadataPage = await this.pfs.getMetadata(true, tx);
10940
+ const currentRowCount = this.metadataPageManager.getRowCount(freshMetadataPage);
10941
+ this.metadataPageManager.setRowCount(freshMetadataPage, currentRowCount - deletedCount);
10942
+ await this.pfs.setMetadata(freshMetadataPage, tx);
10943
+ }
10944
+ for (const pageId of pagesToFree) {
10945
+ await this.pfs.freeChain(pageId, tx);
10946
+ }
10947
+ }
10810
10948
  /**
10811
10949
  * Looks up the RID corresponding to the PK in the B+ Tree and returns the actual row.
10812
10950
  * @param pk Primary key of the row
@@ -10894,7 +11032,7 @@ var RowTableEngine = class {
10894
11032
  const sortedPageIds = Array.from(collections.keys()).sort((a, b) => a - b);
10895
11033
  await Promise.all(sortedPageIds.map(async (pageId) => {
10896
11034
  const items = collections.get(pageId);
10897
- const page = await this.pfs.get(pageId, tx);
11035
+ const page = await this.pfs.get(pageId, false, tx);
10898
11036
  if (!this.factory.isDataPage(page)) {
10899
11037
  throw new Error(`Page ${pageId} is not a data page`);
10900
11038
  }
@@ -10919,7 +11057,7 @@ var RowTableEngine = class {
10919
11057
  this.keyManager.setBufferFromKey(rid, this.ridBuffer);
10920
11058
  const pageId = this.keyManager.getPageId(this.ridBuffer);
10921
11059
  const slotIndex = this.keyManager.getSlotIndex(this.ridBuffer);
10922
- const page = await this.pfs.get(pageId, tx);
11060
+ const page = await this.pfs.get(pageId, false, tx);
10923
11061
  if (!this.factory.isDataPage(page)) {
10924
11062
  throw new Error(`RID not found for PK: ${pk}`);
10925
11063
  }
@@ -10929,7 +11067,7 @@ var RowTableEngine = class {
10929
11067
  return null;
10930
11068
  } else if (this.rowManager.getOverflowFlag(row)) {
10931
11069
  const overflowPageId = bytesToNumber(this.rowManager.getBody(row));
10932
- const overflowPage = await this.pfs.get(overflowPageId, tx);
11070
+ const overflowPage = await this.pfs.get(overflowPageId, false, tx);
10933
11071
  if (!this.factory.isOverflowPage(overflowPage)) {
10934
11072
  throw new Error(`Overflow page not found for RID: ${rid}`);
10935
11073
  }
@@ -10943,16 +11081,11 @@ var RowTableEngine = class {
10943
11081
  * @returns Row count
10944
11082
  */
10945
11083
  async getRowCount(tx) {
10946
- const metadataPage = await this.pfs.getMetadata(tx);
11084
+ const metadataPage = await this.pfs.getMetadata(false, tx);
10947
11085
  return this.metadataPageManager.getRowCount(metadataPage);
10948
11086
  }
10949
11087
  };
10950
11088
 
10951
- // src/utils/catchPromise.ts
10952
- async function catchPromise(promise) {
10953
- return promise.then((res) => [void 0, res]).catch((reason) => [reason]);
10954
- }
10955
-
10956
11089
  // src/core/transaction/LockManager.ts
10957
11090
  var LockManager = class {
10958
11091
  lock;
@@ -11054,16 +11187,20 @@ var Transaction = class {
11054
11187
  /**
11055
11188
  * Reads a page through the MVCC transaction.
11056
11189
  * @param pageId Page ID
11190
+ * @param copy Copy-on-Read
11057
11191
  * @returns Page data
11058
11192
  */
11059
- async __readPage(pageId) {
11193
+ async __readPage(pageId, copy) {
11060
11194
  const data = await this.mvccTx.read(pageId);
11061
11195
  if (data === null) {
11062
11196
  return new Uint8Array(this.pfs.pageSize);
11063
11197
  }
11064
- const copy = new Uint8Array(data.length);
11065
- copy.set(data);
11066
- return copy;
11198
+ if (copy) {
11199
+ const copy2 = new Uint8Array(data.length);
11200
+ copy2.set(data);
11201
+ return copy2;
11202
+ }
11203
+ return data;
11067
11204
  }
11068
11205
  /**
11069
11206
  * Writes a page through the MVCC transaction.
@@ -11073,9 +11210,7 @@ var Transaction = class {
11073
11210
  async __writePage(pageId, data) {
11074
11211
  const exists = await this.mvccTx.exists(pageId);
11075
11212
  if (exists) {
11076
- const copy = new Uint8Array(data.length);
11077
- copy.set(data);
11078
- await this.mvccTx.write(pageId, copy);
11213
+ await this.mvccTx.write(pageId, data);
11079
11214
  } else {
11080
11215
  await this.mvccTx.create(pageId, data);
11081
11216
  }
@@ -11481,46 +11616,46 @@ var DataplyAPI = class {
11481
11616
  * @returns The result of the callback.
11482
11617
  */
11483
11618
  async withWriteTransaction(callback, tx) {
11484
- this.logger.debug("Running with default write transaction");
11619
+ this.logger.debug("Running with write transaction");
11485
11620
  if (!tx) {
11486
11621
  const release = await this.acquireWriteLock();
11487
11622
  const internalTx = this.createTransaction();
11488
11623
  internalTx.__setWriteLockRelease(release);
11489
- const [error2, result2] = await catchPromise(this.txContext.run(internalTx, () => callback(internalTx)));
11490
- if (error2) {
11624
+ try {
11625
+ const result = await this.txContext.run(internalTx, () => callback(internalTx));
11626
+ await internalTx.commit();
11627
+ return result;
11628
+ } catch (error) {
11491
11629
  await internalTx.rollback();
11492
- throw error2;
11630
+ throw error;
11493
11631
  }
11494
- await internalTx.commit();
11495
- return result2;
11496
11632
  }
11497
11633
  if (!tx.__hasWriteLockRelease()) {
11498
11634
  const release = await this.acquireWriteLock();
11499
11635
  tx.__setWriteLockRelease(release);
11500
11636
  }
11501
- const [error, result] = await catchPromise(this.txContext.run(tx, () => callback(tx)));
11502
- if (error) {
11503
- throw error;
11637
+ if (this.txContext.get() === tx) {
11638
+ return callback(tx);
11504
11639
  }
11505
- return result;
11640
+ return this.txContext.run(tx, () => callback(tx));
11506
11641
  }
11507
11642
  async withReadTransaction(callback, tx) {
11508
- this.logger.debug("Running with default transaction");
11509
- const isInternalTx = !tx;
11643
+ this.logger.debug("Running with read transaction");
11510
11644
  if (!tx) {
11511
- tx = this.createTransaction();
11512
- }
11513
- const [error, result] = await catchPromise(this.txContext.run(tx, () => callback(tx)));
11514
- if (error) {
11515
- if (isInternalTx) {
11516
- await tx.rollback();
11645
+ const internalTx = this.createTransaction();
11646
+ try {
11647
+ const result = await this.txContext.run(internalTx, () => callback(internalTx));
11648
+ await internalTx.commit();
11649
+ return result;
11650
+ } catch (error) {
11651
+ await internalTx.rollback();
11652
+ throw error;
11517
11653
  }
11518
- throw error;
11519
11654
  }
11520
- if (isInternalTx) {
11521
- await tx.commit();
11655
+ if (this.txContext.get() === tx) {
11656
+ return callback(tx);
11522
11657
  }
11523
- return result;
11658
+ return this.txContext.run(tx, () => callback(tx));
11524
11659
  }
11525
11660
  /**
11526
11661
  * Runs a generator callback function within a transaction context.
@@ -11664,6 +11799,23 @@ var DataplyAPI = class {
11664
11799
  await this.rowTableEngine.delete(pk, decrementRowCount, tx2);
11665
11800
  }, tx);
11666
11801
  }
11802
+ /**
11803
+ * Deletes multiple data in batch.
11804
+ * If a transaction is not provided, it internally creates a single transaction to process.
11805
+ * @param pks Array of PKs to delete
11806
+ * @param decrementRowCount Whether to decrement the row count to metadata
11807
+ * @param tx Transaction
11808
+ */
11809
+ async deleteBatch(pks, decrementRowCount, tx) {
11810
+ this.logger.debug(`Deleting batch data: ${pks.length} items`);
11811
+ if (!this.initialized) {
11812
+ throw new Error("Dataply instance is not initialized");
11813
+ }
11814
+ return this.withWriteTransaction(async (tx2) => {
11815
+ decrementRowCount = decrementRowCount ?? true;
11816
+ await this.rowTableEngine.deleteBatch(pks, decrementRowCount, tx2);
11817
+ }, tx);
11818
+ }
11667
11819
  async select(pk, asRaw = false, tx) {
11668
11820
  this.logger.debug(`Selecting data for PK: ${pk}`);
11669
11821
  if (!this.initialized) {
@@ -11789,6 +11941,15 @@ var Dataply = class {
11789
11941
  async delete(pk, tx) {
11790
11942
  return this.api.delete(pk, true, tx);
11791
11943
  }
11944
+ /**
11945
+ * Deletes multiple data in batch.
11946
+ * If a transaction is not provided, it internally creates a single transaction to process.
11947
+ * @param pks Array of PKs to delete
11948
+ * @param tx Transaction
11949
+ */
11950
+ async deleteBatch(pks, tx) {
11951
+ return this.api.deleteBatch(pks, true, tx);
11952
+ }
11792
11953
  async select(pk, asRaw = false, tx) {
11793
11954
  return this.api.select(pk, asRaw, tx);
11794
11955
  }
@@ -63,6 +63,13 @@ export declare class Dataply {
63
63
  * @param tx Transaction
64
64
  */
65
65
  delete(pk: number, tx?: Transaction): Promise<void>;
66
+ /**
67
+ * Deletes multiple data in batch.
68
+ * If a transaction is not provided, it internally creates a single transaction to process.
69
+ * @param pks Array of PKs to delete
70
+ * @param tx Transaction
71
+ */
72
+ deleteBatch(pks: number[], tx?: Transaction): Promise<void>;
66
73
  /**
67
74
  * Selects data.
68
75
  * @param pk PK of the data to select
@@ -162,6 +162,14 @@ export declare class DataplyAPI {
162
162
  * @param tx Transaction
163
163
  */
164
164
  delete(pk: number, decrementRowCount?: boolean, tx?: Transaction): Promise<void>;
165
+ /**
166
+ * Deletes multiple data in batch.
167
+ * If a transaction is not provided, it internally creates a single transaction to process.
168
+ * @param pks Array of PKs to delete
169
+ * @param decrementRowCount Whether to decrement the row count to metadata
170
+ * @param tx Transaction
171
+ */
172
+ deleteBatch(pks: number[], decrementRowCount?: boolean, tx?: Transaction): Promise<void>;
165
173
  /**
166
174
  * Selects data.
167
175
  * @param pk PK of the data to select
@@ -62,17 +62,19 @@ export declare class PageFileSystem {
62
62
  get strategy(): PageMVCCStrategy;
63
63
  /**
64
64
  * @param pageIndex 페이지 인덱스
65
+ * @param copy Copy-on-Read
65
66
  * @param tx 트랜잭션
66
67
  * @returns 페이지 버퍼
67
68
  */
68
- get(pageIndex: number, tx: Transaction): Promise<Uint8Array>;
69
+ get(pageIndex: number, copy: boolean, tx: Transaction): Promise<Uint8Array>;
69
70
  /**
70
71
  * Reads the page header.
71
72
  * @param pageIndex Page index
73
+ * @param copy Copy-on-Read
72
74
  * @param tx Transaction
73
75
  * @returns Page header buffer
74
76
  */
75
- getHeader(pageIndex: number, tx: Transaction): Promise<Uint8Array>;
77
+ getHeader(pageIndex: number, copy: boolean, tx: Transaction): Promise<Uint8Array>;
76
78
  /**
77
79
  * Reads the page body.
78
80
  * @param pageIndex Page index
@@ -83,10 +85,11 @@ export declare class PageFileSystem {
83
85
  getBody(pageIndex: number, recursive: boolean | undefined, tx: Transaction): Promise<Uint8Array>;
84
86
  /**
85
87
  * Returns the metadata page.
88
+ * @param copy Copy-on-Read
86
89
  * @param tx Transaction
87
90
  * @returns Metadata page
88
91
  */
89
- getMetadata(tx: Transaction): Promise<MetadataPage>;
92
+ getMetadata(copy: boolean, tx: Transaction): Promise<MetadataPage>;
90
93
  /**
91
94
  * Returns the number of pages stored in the database.
92
95
  * @param tx Transaction
@@ -95,10 +98,11 @@ export declare class PageFileSystem {
95
98
  getPageCount(tx: Transaction): Promise<number>;
96
99
  /**
97
100
  * Returns the root index page.
101
+ * @param copy Copy-on-Read
98
102
  * @param tx Transaction
99
103
  * @returns Root index page
100
104
  */
101
- getRootIndex(tx: Transaction): Promise<IndexPage>;
105
+ getRootIndex(copy: boolean, tx: Transaction): Promise<IndexPage>;
102
106
  /**
103
107
  * Sets the metadata page.
104
108
  * @param metadataPage Metadata page
@@ -111,6 +111,13 @@ export declare class RowTableEngine {
111
111
  * @param tx Transaction
112
112
  */
113
113
  delete(pk: number, decrementRowCount: boolean, tx: Transaction): Promise<void>;
114
+ /**
115
+ * Deletes multiple data in batch.
116
+ * @param pks Array of PKs to delete
117
+ * @param decrementRowCount Whether to decrement the row count to metadata
118
+ * @param tx Transaction
119
+ */
120
+ deleteBatch(pks: number[], decrementRowCount: boolean, tx: Transaction): Promise<void>;
114
121
  /**
115
122
  * Looks up the RID corresponding to the PK in the B+ Tree and returns the actual row.
116
123
  * @param pk Primary key of the row
@@ -51,9 +51,10 @@ export declare class Transaction {
51
51
  /**
52
52
  * Reads a page through the MVCC transaction.
53
53
  * @param pageId Page ID
54
+ * @param copy Copy-on-Read
54
55
  * @returns Page data
55
56
  */
56
- __readPage(pageId: number): Promise<Uint8Array>;
57
+ __readPage(pageId: number, copy: boolean): Promise<Uint8Array>;
57
58
  /**
58
59
  * Writes a page through the MVCC transaction.
59
60
  * @param pageId Page ID
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dataply",
3
- "version": "0.0.26-alpha.9",
3
+ "version": "0.0.26",
4
4
  "description": "A lightweight storage engine for Node.js with support for MVCC, WAL.",
5
5
  "license": "MIT",
6
6
  "author": "izure <admin@izure.org>",
@@ -49,6 +49,6 @@
49
49
  "hookall": "^2.2.0",
50
50
  "mvcc-api": "^1.3.7",
51
51
  "ryoiki": "^1.2.0",
52
- "serializable-bptree": "^9.0.2"
52
+ "serializable-bptree": "^9.0.4"
53
53
  }
54
54
  }