dataply 0.0.18 → 0.0.19

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
@@ -7941,20 +7941,32 @@ var PageFileSystem = class {
7941
7941
  } else {
7942
7942
  let nextPageId = manager.getNextPageId(page);
7943
7943
  if (nextPageId !== -1) {
7944
- let pendingFreePageId = nextPageId;
7945
- while (pendingFreePageId !== -1) {
7946
- const pendingPage = await this.get(pendingFreePageId, tx);
7947
- const pendingManager = this.pageFactory.getManager(pendingPage);
7948
- const next = pendingManager.getNextPageId(pendingPage);
7949
- await this.setFreePage(pendingFreePageId, tx);
7950
- pendingFreePageId = next;
7951
- }
7944
+ await this.freeChain(nextPageId, tx);
7952
7945
  manager.setNextPageId(page, -1);
7953
7946
  await this.setPage(currentPageId, page, tx);
7954
7947
  }
7955
7948
  }
7956
7949
  }
7957
7950
  }
7951
+ /**
7952
+ * Free chain of pages.
7953
+ * @param startPageId Start page ID
7954
+ * @param tx Transaction
7955
+ */
7956
+ async freeChain(startPageId, tx) {
7957
+ let currentPageId = startPageId;
7958
+ const visited = /* @__PURE__ */ new Set();
7959
+ while (currentPageId !== -1 && currentPageId !== 0) {
7960
+ if (visited.has(currentPageId)) {
7961
+ break;
7962
+ }
7963
+ visited.add(currentPageId);
7964
+ const page = await this.get(currentPageId, tx);
7965
+ const nextPageId = this.pageFactory.getManager(page).getNextPageId(page);
7966
+ await this.setFreePage(currentPageId, tx);
7967
+ currentPageId = nextPageId;
7968
+ }
7969
+ }
7958
7970
  /**
7959
7971
  * Frees the page and marks it as available in the bitmap.
7960
7972
  * It also adds the page to the linked list of free pages in metadata.
@@ -7962,6 +7974,7 @@ var PageFileSystem = class {
7962
7974
  * @param tx Transaction
7963
7975
  */
7964
7976
  async setFreePage(pageId, tx) {
7977
+ if (pageId <= 0) return;
7965
7978
  await tx.__acquireWriteLock(0);
7966
7979
  await tx.__acquireWriteLock(pageId);
7967
7980
  const metadata = await this.getMetadata(tx);
@@ -8138,17 +8151,8 @@ var RowIdentifierStrategy = class extends SerializeStrategyAsync {
8138
8151
  }
8139
8152
  async delete(id) {
8140
8153
  const tx = this.txContext.get();
8141
- const manager = this.factory.getManagerFromType(PageManager.CONSTANT.PAGE_TYPE_INDEX);
8142
- let pageId = +id;
8143
- while (true) {
8144
- const page = await this.pfs.get(pageId, tx);
8145
- const nextPageId = manager.getNextPageId(page);
8146
- await this.pfs.setFreePage(pageId, tx);
8147
- if (nextPageId === -1) {
8148
- break;
8149
- }
8150
- pageId = nextPageId;
8151
- }
8154
+ const pageId = +id;
8155
+ await this.pfs.freeChain(pageId, tx);
8152
8156
  }
8153
8157
  async readHead() {
8154
8158
  const tx = this.txContext.get();
@@ -8573,14 +8577,8 @@ var RowTableEngine = class {
8573
8577
  return;
8574
8578
  }
8575
8579
  if (this.rowManager.getOverflowFlag(row)) {
8576
- let overflowPageId = bytesToNumber(this.rowManager.getBody(row));
8577
- while (overflowPageId !== -1) {
8578
- const overflowPage = await this.pfs.get(overflowPageId, tx);
8579
- const manager = this.factory.getManager(overflowPage);
8580
- const nextPageId = manager.getNextPageId(overflowPage);
8581
- await this.pfs.setFreePage(overflowPageId, tx);
8582
- overflowPageId = nextPageId;
8583
- }
8580
+ const overflowPageId = bytesToNumber(this.rowManager.getBody(row));
8581
+ await this.pfs.freeChain(overflowPageId, tx);
8584
8582
  }
8585
8583
  this.rowManager.setDeletedFlag(row, true);
8586
8584
  await this.pfs.setPage(pageId, page, tx);
@@ -8611,7 +8609,7 @@ var RowTableEngine = class {
8611
8609
  }
8612
8610
  }
8613
8611
  if (allDeleted) {
8614
- await this.pfs.setFreePage(pageId, tx);
8612
+ await this.pfs.freeChain(pageId, tx);
8615
8613
  }
8616
8614
  }
8617
8615
  /**
@@ -114,6 +114,12 @@ export declare class PageFileSystem {
114
114
  * @param tx Transaction
115
115
  */
116
116
  writePageContent(pageId: number, data: Uint8Array, offset: number | undefined, tx: Transaction): Promise<void>;
117
+ /**
118
+ * Free chain of pages.
119
+ * @param startPageId Start page ID
120
+ * @param tx Transaction
121
+ */
122
+ freeChain(startPageId: number, tx: Transaction): Promise<void>;
117
123
  /**
118
124
  * Frees the page and marks it as available in the bitmap.
119
125
  * It also adds the page to the linked list of free pages in metadata.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dataply",
3
- "version": "0.0.18",
3
+ "version": "0.0.19",
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>",
package/readme.md CHANGED
@@ -1,4 +1,6 @@
1
1
  ![node.js workflow](https://github.com/izure1/dataply/actions/workflows/node.js.yml/badge.svg)
2
+ ![Performance Benchmark](https://github.com/izure1/dataply/actions/workflows/benchmark.yml/badge.svg)
3
+ ![License](https://img.shields.io/badge/license-MIT-blue.svg)
2
4
 
3
5
  # Dataply
4
6
 
@@ -279,22 +281,14 @@ Dataply uses a **Slotted Page** architecture to manage records efficiently:
279
281
 
280
282
  ## Performance
281
283
 
282
- Dataply is optimized for high-speed data processing. Below are the results of basic benchmark tests conducted on a local environment.
284
+ Dataply is optimized for high-speed data processing. Automated benchmarks are executed on every push to the `main` branch to ensure consistent performance.
283
285
 
284
- | Test Case | Count | Total Time | OPS (Operations Per Second) |
285
- | :--- | :--- | :--- | :--- |
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** |
286
+ ### Performance Trend
290
287
 
291
- ### Benchmark Analysis
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.
288
+ You can view the real-time performance trend and detailed metrics on our [Performance Dashboard](https://izure1.github.io/dataply/dev/bench/).
295
289
 
296
- > [!NOTE]
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.
290
+ > [!TIP]
291
+ > **Continuous Monitoring**: We use `github-action-benchmark` to monitor performance changes. For every PR, a summary of the performance impact is automatically commented to help maintain high efficiency.
298
292
 
299
293
  ## Limitations
300
294