@wxn0brp/db-storage-bin 0.110.0-alpha.0 → 0.110.0-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/README.md CHANGED
@@ -34,6 +34,12 @@ This will reclaim unused space in the binary file.
34
34
  await mgr.optimize();
35
35
  ```
36
36
 
37
+ ### Closing
38
+
39
+ ```typescript
40
+ await db.close();
41
+ ```
42
+
37
43
  ## API
38
44
 
39
45
  ### `createBinValthera(path, opts, init)`
@@ -1,40 +1,77 @@
1
- import { unlink } from "fs/promises";
1
+ import { rename, rm } from "fs/promises";
2
+ import { BinManager } from "./index.js";
3
+ import { ensureCollection } from "./collection.js";
2
4
  import { saveHeaderAndPayload } from "./head.js";
3
- import { HEADER_SIZE, INT_SIZE } from "./static.js";
4
- import { readData, roundUpCapacity, writeData } from "./utils.js";
5
+ import { INT_SIZE } from "./static.js";
6
+ import { readCollectionEof, readData, writeData } from "./utils.js";
5
7
  import { _log } from "../log.js";
8
+ function isRemovedRecord(data) {
9
+ return new Uint8Array(data).every(byte => byte === 0);
10
+ }
11
+ async function appendRawRecord(target, collectionName, recordLengthBuffer, data) {
12
+ const collection = await ensureCollection(target, collectionName, data.length, true);
13
+ const collectionEOF = await readCollectionEof(target.fd, collection.offset);
14
+ const offset = collection.offset + collectionEOF + INT_SIZE;
15
+ await writeData(target.fd, offset, recordLengthBuffer, INT_SIZE);
16
+ await writeData(target.fd, offset + INT_SIZE, data, data.length);
17
+ const newEOF = collectionEOF + INT_SIZE + data.length;
18
+ const collectionLengthBuffer = Buffer.alloc(INT_SIZE);
19
+ collectionLengthBuffer.writeUInt32LE(newEOF, 0);
20
+ await writeData(target.fd, collection.offset, collectionLengthBuffer, INT_SIZE);
21
+ }
22
+ async function copyLiveRecords(source, target, collectionName, sourceOffset, collectionEOF) {
23
+ let readCursor = sourceOffset + INT_SIZE;
24
+ const endOffset = readCursor + collectionEOF;
25
+ while (readCursor < endOffset) {
26
+ const recordLengthBuffer = await readData(source.fd, readCursor, INT_SIZE);
27
+ const recordLength = recordLengthBuffer.readUInt32LE(0);
28
+ readCursor += INT_SIZE;
29
+ const data = await readData(source.fd, readCursor, recordLength);
30
+ readCursor += recordLength;
31
+ if (isRemovedRecord(data))
32
+ continue;
33
+ await appendRawRecord(target, collectionName, recordLengthBuffer, data);
34
+ }
35
+ }
6
36
  export async function optimize(cmp) {
7
37
  await _log(3, "Starting database optimization");
8
- const collections = cmp.meta.collections;
9
- const allData = new Map();
10
- for (const { name, offset } of collections) {
11
- await _log(6, "Reading collection for optimization:", name);
12
- const len = await readData(cmp.fd, offset, 4);
13
- const data = await readData(cmp.fd, offset + 4, len.readInt32LE(0));
14
- allData.set(name, data);
38
+ const collections = [...cmp.meta.collections];
39
+ const tmpPath = `${cmp.path}.tmp`;
40
+ await _log(6, "Removing stale optimization temp file:", tmpPath);
41
+ await rm(tmpPath, { force: true });
42
+ const tmpMgr = new BinManager(tmpPath, cmp.options);
43
+ let tmpOpened = false;
44
+ let originalClosed = false;
45
+ try {
46
+ await tmpMgr.init();
47
+ tmpOpened = true;
48
+ const lengthBuffer = Buffer.alloc(INT_SIZE);
49
+ for (const { name, offset } of collections) {
50
+ await _log(6, "Optimizing collection:", name);
51
+ const collectionEOF = await readCollectionEof(cmp.fd, offset);
52
+ const collectionMeta = await ensureCollection(tmpMgr, name, 0, false);
53
+ lengthBuffer.writeUInt32LE(0, 0);
54
+ await writeData(tmpMgr.fd, collectionMeta.offset, lengthBuffer, INT_SIZE);
55
+ await copyLiveRecords(cmp, tmpMgr, name, offset, collectionEOF);
56
+ }
57
+ await saveHeaderAndPayload(tmpMgr);
58
+ await tmpMgr.close();
59
+ tmpOpened = false;
60
+ await _log(5, "Closing original file for optimization");
61
+ await cmp.close();
62
+ originalClosed = true;
63
+ await _log(5, "Replacing original database with optimized temp file");
64
+ await rename(tmpPath, cmp.path);
65
+ await cmp.init();
66
+ originalClosed = false;
15
67
  }
16
- await _log(5, "Closing file for optimization");
17
- await cmp.close();
18
- await _log(6, "Deleting old database file for optimization");
19
- await unlink(cmp.path);
20
- await new Promise(resolve => setTimeout(resolve, 100));
21
- await _log(5, "Re-opening database file for optimization");
22
- await cmp.init();
23
- let offset = roundUpCapacity(cmp.meta, cmp.meta.payloadLength + HEADER_SIZE) + cmp.meta.blockSize;
24
- const lengthBuffer = Buffer.alloc(INT_SIZE);
25
- for (const [collection, data] of allData) {
26
- await _log(6, "Writing optimized collection:", collection);
27
- const len = roundUpCapacity(cmp.meta, data.length + INT_SIZE);
28
- lengthBuffer.writeInt32LE(data.length, 0);
29
- await writeData(cmp.fd, offset, lengthBuffer, INT_SIZE);
30
- await writeData(cmp.fd, offset + INT_SIZE, data, len);
31
- cmp.meta.collections.push({
32
- name: collection,
33
- offset,
34
- capacity: len
35
- });
36
- offset += len;
68
+ catch (err) {
69
+ if (tmpOpened)
70
+ await tmpMgr.close();
71
+ await rm(tmpPath, { force: true });
72
+ if (originalClosed)
73
+ await cmp.init();
74
+ throw err;
37
75
  }
38
- await saveHeaderAndPayload(cmp);
39
76
  await _log(3, "Database optimization complete");
40
77
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wxn0brp/db-storage-bin",
3
- "version": "0.110.0-alpha.0",
3
+ "version": "0.110.0-alpha.1",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "author": "wxn0brP",
@@ -19,7 +19,7 @@
19
19
  ],
20
20
  "devDependencies": {
21
21
  "@types/bun": "*",
22
- "@wxn0brp/db-core": "^0.11.0-alpha.4",
22
+ "@wxn0brp/db-core": "^0.11.1-alpha.2",
23
23
  "tsc-alias": "^1",
24
24
  "typescript": "^6"
25
25
  },
@@ -27,7 +27,7 @@
27
27
  "@msgpack/msgpack": "^3.1.3"
28
28
  },
29
29
  "peerDependencies": {
30
- "@wxn0brp/db-core": "^0.11.0-alpha.4"
30
+ "@wxn0brp/db-core": "^0.11.1-alpha.2"
31
31
  },
32
32
  "files": [
33
33
  "dist"