dataply 0.0.17 → 0.0.18-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cjs/index.js CHANGED
@@ -1857,7 +1857,7 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
1857
1857
  return node;
1858
1858
  }
1859
1859
  _updateNode(node) {
1860
- this.mvcc.write(node.id, JSON.parse(JSON.stringify(node)));
1860
+ this.mvcc.write(node.id, node);
1861
1861
  this.nodes.set(node.id, node);
1862
1862
  }
1863
1863
  _deleteNode(node) {
@@ -2686,7 +2686,7 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
2686
2686
  return node;
2687
2687
  }
2688
2688
  async _updateNode(node) {
2689
- await this.mvcc.write(node.id, JSON.parse(JSON.stringify(node)));
2689
+ await this.mvcc.write(node.id, node);
2690
2690
  this.nodes.set(node.id, node);
2691
2691
  }
2692
2692
  async _deleteNode(node) {
@@ -8359,75 +8359,84 @@ var RowTableEngine = class {
8359
8359
  };
8360
8360
  }
8361
8361
  /**
8362
- * Inserts data.
8363
- * @param data Data
8362
+ * Inserts data (batch insert).
8363
+ * @param dataList Array of data to insert
8364
8364
  * @param incrementRowCount Whether to increment the row count to metadata
8365
+ * @param overflowForcly Force overflow page creation for all data
8365
8366
  * @param tx Transaction
8366
- * @returns PK of the inserted data
8367
+ * @returns Array of PKs of the inserted data
8367
8368
  */
8368
- async insert(data, incrementRowCount, overflowForcly, tx) {
8369
+ async insert(dataList, incrementRowCount, overflowForcly, tx) {
8370
+ if (dataList.length === 0) {
8371
+ return [];
8372
+ }
8369
8373
  await tx.__acquireWriteLock(0);
8374
+ const btx = await this.getBPTreeTransaction(tx);
8375
+ const pks = [];
8370
8376
  const metadataPage = await this.pfs.getMetadata(tx);
8371
- const pk = this.metadataPageManager.getLastRowPk(metadataPage) + 1;
8377
+ let lastPk = this.metadataPageManager.getLastRowPk(metadataPage);
8372
8378
  let lastInsertDataPageId = this.metadataPageManager.getLastInsertPageId(metadataPage);
8373
8379
  let lastInsertDataPage = await this.pfs.get(lastInsertDataPageId, tx);
8374
8380
  if (!this.factory.isDataPage(lastInsertDataPage)) {
8375
8381
  throw new Error(`Last insert page is not data page`);
8376
8382
  }
8377
- const willRowSize = this.getRequiredRowSize(data);
8378
- if (willRowSize > this.maxBodySize || overflowForcly) {
8379
- const overflowPageId = await this.pfs.appendNewPage(this.overflowPageManager.pageType, tx);
8380
- const row = new Uint8Array(Row.CONSTANT.SIZE_HEADER + 4);
8381
- this.rowManager.setPK(row, pk);
8382
- this.rowManager.setOverflowFlag(row, true);
8383
- this.rowManager.setBodySize(row, 4);
8384
- this.rowManager.setBody(row, numberToBytes(overflowPageId, this.pageIdBuffer));
8385
- const nextSlotIndex = this.dataPageManager.getNextSlotIndex(lastInsertDataPage, row);
8386
- if (nextSlotIndex !== -1) {
8387
- this.setRID(lastInsertDataPageId, nextSlotIndex);
8388
- this.dataPageManager.insert(lastInsertDataPage, row);
8389
- await this.pfs.setPage(lastInsertDataPageId, lastInsertDataPage, tx);
8390
- } else {
8391
- const newPageId = await this.pfs.appendNewPage(this.dataPageManager.pageType, tx);
8392
- const newPage = await this.pfs.get(newPageId, tx);
8393
- this.dataPageManager.insert(newPage, row);
8394
- this.setRID(newPageId, 0);
8395
- lastInsertDataPageId = newPageId;
8396
- lastInsertDataPage = newPage;
8397
- await this.pfs.setPage(newPageId, newPage, tx);
8398
- }
8399
- await this.pfs.writePageContent(overflowPageId, data, 0, tx);
8400
- } else {
8401
- const row = new Uint8Array(Row.CONSTANT.SIZE_HEADER + data.length);
8402
- const slotIndex = this.dataPageManager.getNextSlotIndex(lastInsertDataPage, row);
8403
- this.rowManager.setBodySize(row, data.length);
8404
- this.rowManager.setBody(row, data);
8405
- if (slotIndex === -1) {
8406
- const newPageId = await this.pfs.appendNewPage(this.dataPageManager.pageType, tx);
8407
- const newPage = await this.pfs.get(newPageId, tx);
8408
- this.dataPageManager.insert(newPage, row);
8409
- this.setRID(newPageId, 0);
8410
- lastInsertDataPageId = newPageId;
8411
- lastInsertDataPage = newPage;
8412
- await this.pfs.setPage(newPageId, newPage, tx);
8383
+ for (const data of dataList) {
8384
+ const pk = ++lastPk;
8385
+ const willRowSize = this.getRequiredRowSize(data);
8386
+ if (willRowSize > this.maxBodySize || overflowForcly) {
8387
+ const overflowPageId = await this.pfs.appendNewPage(this.overflowPageManager.pageType, tx);
8388
+ const row = new Uint8Array(Row.CONSTANT.SIZE_HEADER + 4);
8389
+ this.rowManager.setPK(row, pk);
8390
+ this.rowManager.setOverflowFlag(row, true);
8391
+ this.rowManager.setBodySize(row, 4);
8392
+ this.rowManager.setBody(row, numberToBytes(overflowPageId, this.pageIdBuffer));
8393
+ const nextSlotIndex = this.dataPageManager.getNextSlotIndex(lastInsertDataPage, row);
8394
+ if (nextSlotIndex !== -1) {
8395
+ this.setRID(lastInsertDataPageId, nextSlotIndex);
8396
+ this.dataPageManager.insert(lastInsertDataPage, row);
8397
+ await this.pfs.setPage(lastInsertDataPageId, lastInsertDataPage, tx);
8398
+ } else {
8399
+ const newPageId = await this.pfs.appendNewPage(this.dataPageManager.pageType, tx);
8400
+ const newPage = await this.pfs.get(newPageId, tx);
8401
+ this.dataPageManager.insert(newPage, row);
8402
+ this.setRID(newPageId, 0);
8403
+ lastInsertDataPageId = newPageId;
8404
+ lastInsertDataPage = newPage;
8405
+ await this.pfs.setPage(newPageId, newPage, tx);
8406
+ }
8407
+ await this.pfs.writePageContent(overflowPageId, data, 0, tx);
8413
8408
  } else {
8414
- this.dataPageManager.insert(lastInsertDataPage, row);
8415
- this.setRID(lastInsertDataPageId, slotIndex);
8416
- await this.pfs.setPage(lastInsertDataPageId, lastInsertDataPage, tx);
8409
+ const row = new Uint8Array(Row.CONSTANT.SIZE_HEADER + data.length);
8410
+ const slotIndex = this.dataPageManager.getNextSlotIndex(lastInsertDataPage, row);
8411
+ this.rowManager.setBodySize(row, data.length);
8412
+ this.rowManager.setBody(row, data);
8413
+ if (slotIndex === -1) {
8414
+ const newPageId = await this.pfs.appendNewPage(this.dataPageManager.pageType, tx);
8415
+ const newPage = await this.pfs.get(newPageId, tx);
8416
+ this.dataPageManager.insert(newPage, row);
8417
+ this.setRID(newPageId, 0);
8418
+ lastInsertDataPageId = newPageId;
8419
+ lastInsertDataPage = newPage;
8420
+ await this.pfs.setPage(newPageId, newPage, tx);
8421
+ } else {
8422
+ this.dataPageManager.insert(lastInsertDataPage, row);
8423
+ this.setRID(lastInsertDataPageId, slotIndex);
8424
+ await this.pfs.setPage(lastInsertDataPageId, lastInsertDataPage, tx);
8425
+ }
8417
8426
  }
8427
+ await btx.insert(this.getRID(), pk);
8428
+ pks.push(pk);
8418
8429
  }
8430
+ tx.__markBPTreeDirty();
8419
8431
  const freshMetadataPage = await this.pfs.getMetadata(tx);
8420
8432
  this.metadataPageManager.setLastInsertPageId(freshMetadataPage, lastInsertDataPageId);
8421
- this.metadataPageManager.setLastRowPk(freshMetadataPage, pk);
8433
+ this.metadataPageManager.setLastRowPk(freshMetadataPage, lastPk);
8422
8434
  if (incrementRowCount) {
8423
8435
  const currentRowCount = this.metadataPageManager.getRowCount(freshMetadataPage);
8424
- this.metadataPageManager.setRowCount(freshMetadataPage, currentRowCount + 1);
8436
+ this.metadataPageManager.setRowCount(freshMetadataPage, currentRowCount + pks.length);
8425
8437
  }
8426
8438
  await this.pfs.setMetadata(freshMetadataPage, tx);
8427
- const btx = await this.getBPTreeTransaction(tx);
8428
- await btx.insert(this.getRID(), pk);
8429
- tx.__markBPTreeDirty();
8430
- return pk;
8439
+ return pks;
8431
8440
  }
8432
8441
  /**
8433
8442
  * Looks up the RID by PK.
@@ -9099,12 +9108,13 @@ var DataplyAPI = class {
9099
9108
  if (!this.initialized) {
9100
9109
  throw new Error("Dataply instance is not initialized");
9101
9110
  }
9102
- return this.runWithDefault((tx2) => {
9111
+ return this.runWithDefault(async (tx2) => {
9103
9112
  incrementRowCount = incrementRowCount ?? true;
9104
9113
  if (typeof data === "string") {
9105
9114
  data = this.textCodec.encode(data);
9106
9115
  }
9107
- return this.rowTableEngine.insert(data, incrementRowCount, false, tx2);
9116
+ const pks = await this.rowTableEngine.insert([data], incrementRowCount, false, tx2);
9117
+ return pks[0];
9108
9118
  }, tx);
9109
9119
  }
9110
9120
  /**
@@ -9118,12 +9128,13 @@ var DataplyAPI = class {
9118
9128
  if (!this.initialized) {
9119
9129
  throw new Error("Dataply instance is not initialized");
9120
9130
  }
9121
- return this.runWithDefault((tx2) => {
9131
+ return this.runWithDefault(async (tx2) => {
9122
9132
  incrementRowCount = incrementRowCount ?? true;
9123
9133
  if (typeof data === "string") {
9124
9134
  data = this.textCodec.encode(data);
9125
9135
  }
9126
- return this.rowTableEngine.insert(data, incrementRowCount, true, tx2);
9136
+ const pks = await this.rowTableEngine.insert([data], incrementRowCount, true, tx2);
9137
+ return pks[0];
9127
9138
  }, tx);
9128
9139
  }
9129
9140
  /**
@@ -9140,13 +9151,10 @@ var DataplyAPI = class {
9140
9151
  }
9141
9152
  return this.runWithDefault(async (tx2) => {
9142
9153
  incrementRowCount = incrementRowCount ?? true;
9143
- const pks = [];
9144
- for (const data of dataList) {
9145
- const encoded = typeof data === "string" ? this.textCodec.encode(data) : data;
9146
- const pk = await this.rowTableEngine.insert(encoded, incrementRowCount, false, tx2);
9147
- pks.push(pk);
9148
- }
9149
- return pks;
9154
+ const encodedList = dataList.map(
9155
+ (data) => typeof data === "string" ? this.textCodec.encode(data) : data
9156
+ );
9157
+ return this.rowTableEngine.insert(encodedList, incrementRowCount, false, tx2);
9150
9158
  }, tx);
9151
9159
  }
9152
9160
  /**
@@ -69,13 +69,14 @@ export declare class RowTableEngine {
69
69
  */
70
70
  getMetadata(tx: Transaction): Promise<DataplyMetadata>;
71
71
  /**
72
- * Inserts data.
73
- * @param data Data
72
+ * Inserts data (batch insert).
73
+ * @param dataList Array of data to insert
74
74
  * @param incrementRowCount Whether to increment the row count to metadata
75
+ * @param overflowForcly Force overflow page creation for all data
75
76
  * @param tx Transaction
76
- * @returns PK of the inserted data
77
+ * @returns Array of PKs of the inserted data
77
78
  */
78
- insert(data: Uint8Array, incrementRowCount: boolean, overflowForcly: boolean, tx: Transaction): Promise<number>;
79
+ insert(dataList: Uint8Array[], incrementRowCount: boolean, overflowForcly: boolean, tx: Transaction): Promise<number[]>;
79
80
  /**
80
81
  * Looks up the RID by PK.
81
82
  * Checks Pending Updates first if a transaction exists.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dataply",
3
- "version": "0.0.17",
3
+ "version": "0.0.18-alpha.1",
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.2.9",
51
51
  "ryoiki": "^1.2.0",
52
- "serializable-bptree": "^8.0.1"
52
+ "serializable-bptree": "^8.0.2"
53
53
  }
54
54
  }
package/readme.md CHANGED
@@ -283,15 +283,15 @@ Dataply is optimized for high-speed data processing. Below are the results of ba
283
283
 
284
284
  | Test Case | Count | Total Time | OPS (Operations Per Second) |
285
285
  | :--- | :--- | :--- | :--- |
286
- | **Bulk Insert (Batch)** | 10,000 | ~1,477ms | **~7,244 OPS** |
287
- | **Bulk Insert (Individual)** | 100 | ~126ms | **~865 OPS** |
288
- | **Bulk Insert with WAL** | 100 | ~117ms | **~934 OPS** |
289
- | **Medium Row Insert (1KB)** | 100 | ~134ms | **~818 OPS** |
286
+ | **Bulk Insert (Batch)** | 10,000 | ~438ms | **~24,361 OPS** |
287
+ | **Bulk Insert (Individual)** | 100 | ~122ms | **~851 OPS** |
288
+ | **Bulk Insert with WAL** | 100 | ~118ms | **~891 OPS** |
289
+ | **Medium Row Insert (1KB)** | 100 | ~137ms | **~776 OPS** |
290
290
 
291
291
  ### Benchmark Analysis
292
- - **Batching Efficiency**: Grouping operations into a single transaction is approximately **8.4x faster** than individual inserts by minimizing internal transaction management overhead.
293
- - **WAL Trade-off**: Enabling Write-Ahead Logging ensures data durability but results in a significant performance decrease (approximately **15x slower** for individual inserts) due to synchronous I/O operations.
294
- - **Node.js Optimization**: Dataply is designed to provide competitive performance (over **12,000 OPS** in batch mode) for a pure TypeScript Record Store without native dependencies.
292
+ - **Batching Efficiency**: Grouping operations into a single transaction is approximately **28.6x faster** than individual inserts by minimizing internal transaction management overhead.
293
+ - **WAL Trade-off**: Enabling Write-Ahead Logging ensures data durability. In this run, WAL performance was comparable to (and slightly faster than) individual inserts, demonstrating efficient logging overhead.
294
+ - **Node.js Optimization**: Dataply is designed to provide competitive performance (over **24,000 OPS** in batch mode) for a pure TypeScript Record Store without native dependencies.
295
295
 
296
296
  > [!NOTE]
297
297
  > Tests were conducted on a standard local environment (Node.js v25+). Performance may vary depending on hardware specifications (especially SSD/HDD) and system load.