@thi.ng/block-fs 0.4.4 → 0.5.0

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/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2025-06-09T17:24:08Z
3
+ - **Last updated**: 2025-06-18T12:01:21Z
4
4
  - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
5
 
6
6
  All notable changes to this project will be documented in this file.
@@ -11,6 +11,12 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
11
11
  **Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
12
12
  and/or version bumps of transitive dependencies.
13
13
 
14
+ ## [0.5.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/block-fs@0.5.0) (2025-06-18)
15
+
16
+ #### 🚀 Features
17
+
18
+ - update block count estimation, add more logging ([02c8037](https://github.com/thi-ng/umbrella/commit/02c8037))
19
+
14
20
  ### [0.4.1](https://github.com/thi-ng/umbrella/tree/@thi.ng/block-fs@0.4.1) (2025-04-16)
15
21
 
16
22
  #### ♻️ Refactoring
package/README.md CHANGED
@@ -48,6 +48,12 @@ storage providers are included:
48
48
  - [FileBlockStorage](https://docs.thi.ng/umbrella/block-fs/classes/FileBlockStorage.html):
49
49
  Host-filesystem based blocks (one block per file)
50
50
 
51
+ > [IMPORTANT]
52
+ > For browser-compatibility reasons, the `FileBlockStorage` is NOT exposed when
53
+ > using package-level imports. Use the following import to use this class:
54
+ >
55
+ > `import { FileBlockStorage } from "@thi.ng/block-fs/storage/file";
56
+
51
57
  As the name indicates, block storage providers only support block-based
52
58
  read/write/delete access to arbitrary binary data (all ops are async). For
53
59
  file-based storage, blocks are created lazily/dynamically.
@@ -288,7 +294,7 @@ For Node.js REPL:
288
294
  const bf = await import("@thi.ng/block-fs");
289
295
  ```
290
296
 
291
- Package sizes (brotli'd, pre-treeshake): ESM: 4.50 KB
297
+ Package sizes (brotli'd, pre-treeshake): ESM: 4.51 KB
292
298
 
293
299
  ## Dependencies
294
300
 
package/cli.js CHANGED
@@ -10,7 +10,7 @@ import { illegalArgs } from "@thi.ng/errors";
10
10
  import { files, readBinary, readJSON, writeFile } from "@thi.ng/file-io";
11
11
  import { LogLevel } from "@thi.ng/logger";
12
12
  import { statSync } from "node:fs";
13
- import { dirname, join, relative, resolve } from "node:path";
13
+ import { join, relative, resolve } from "node:path";
14
14
  import { Entry } from "./entry.js";
15
15
  import { BlockFS } from "./fs.js";
16
16
  import { MemoryBlockStorage } from "./storage/memory.js";
@@ -28,6 +28,14 @@ const ARG_BLOCKSIZE = {
28
28
  }
29
29
  })
30
30
  };
31
+ const requiredBytes = (x) => align(Math.ceil(Math.log2(x)), 8) >> 3;
32
+ const pathsForFile = (f) => {
33
+ const parts = f.split("/");
34
+ const dirs = [];
35
+ for (let i = 1; i < parts.length; i++)
36
+ dirs.push(parts.slice(0, i).join("/"));
37
+ return dirs;
38
+ };
31
39
  const collectFiles = ({
32
40
  opts: { include, exclude },
33
41
  inputs
@@ -50,24 +58,30 @@ const collectFiles = ({
50
58
  ctime: stats.ctimeMs,
51
59
  mtime: stats.mtimeMs
52
60
  });
53
- dirs.add(dirname(dest));
61
+ for (let d of pathsForFile(dest)) dirs.add(d);
54
62
  total += stats.size;
55
63
  }
56
64
  return { files: filtered, dirs: [...dirs], size: total };
57
65
  };
58
- const computeBlockCount = (collected, blockSize, numBlocks) => {
66
+ const computeBlockCount = (collected, blockSize, logger, numBlocks) => {
59
67
  let blocks = collected.dirs.length;
60
- const blockIDBytes = numBlocks ? align(Math.ceil(Math.log2(numBlocks)), 8) >> 3 : align(Math.ceil(Math.log2(collected.size / blockSize + blocks)), 8) >> 3;
61
- const blockDataSizeBytes = align(Math.ceil(Math.log2(blockSize)), 8) >> 3;
62
- const blockDataSize = blockSize - blockIDBytes - blockDataSizeBytes;
63
- blocks += Math.ceil(
64
- (collected.files.length + collected.dirs.length) * Entry.SIZE / blockDataSize
68
+ const blockIDBytes = requiredBytes(
69
+ numBlocks ?? collected.size / blockSize + blocks
65
70
  );
71
+ const blockDataSizeBytes = requiredBytes(blockSize);
72
+ const blockDataSize = blockSize - blockIDBytes - blockDataSizeBytes;
73
+ const numEntries = collected.files.length + collected.dirs.length;
74
+ const numEntryBlocks = Math.ceil(numEntries * Entry.SIZE / blockDataSize);
75
+ logger.info("num entries:", numEntries);
76
+ logger.info("num entry blocks:", numEntryBlocks);
77
+ blocks += numEntryBlocks;
66
78
  for (let f of collected.files) {
67
- blocks += Math.ceil(f.size / blockDataSize);
79
+ const size = Math.ceil(f.size / blockDataSize);
80
+ logger.debug("file:", f.src, "blocks:", size);
81
+ blocks += size;
68
82
  }
69
- const blockIDBytes2 = align(Math.ceil(Math.log2(blocks)), 8) >> 3;
70
- return blockIDBytes2 > blockIDBytes ? computeBlockCount(collected, blockSize, blocks) : blocks;
83
+ const blockIDBytes2 = requiredBytes(blocks);
84
+ return blockIDBytes2 > blockIDBytes ? computeBlockCount(collected, blockSize, logger, blocks) : blocks;
71
85
  };
72
86
  const CONVERT = {
73
87
  opts: {
@@ -97,7 +111,7 @@ const CONVERT = {
97
111
  fn: async (ctx) => {
98
112
  const collected = collectFiles(ctx);
99
113
  const numBlocks = align(
100
- ctx.opts.numBlocks ?? computeBlockCount(collected, ctx.opts.blockSize),
114
+ ctx.opts.numBlocks ?? computeBlockCount(collected, ctx.opts.blockSize, ctx.logger),
101
115
  8
102
116
  );
103
117
  ctx.logger.info("number of files:", collected.files.length);
@@ -111,9 +125,13 @@ const CONVERT = {
111
125
  });
112
126
  const bfs = new BlockFS(storage, { logger: ctx.logger });
113
127
  await bfs.init();
128
+ ctx.logger.info("root dir block:", bfs.rootDirBlockID);
129
+ ctx.logger.info("first data block:", bfs.dataStartBlockID);
130
+ ctx.logger.info("block data size:", bfs.blockDataSize);
114
131
  for (let f of collected.files) {
115
- ctx.logger.info("writing file:", f.dest);
116
- await bfs.writeFile(f.dest, readBinary(f.src));
132
+ const data = readBinary(f.src, ctx.logger);
133
+ ctx.logger.info("writing file:", f.dest, "size:", data.length);
134
+ await bfs.writeFile(f.dest, data);
117
135
  const entry = await bfs.entryForPath(f.dest);
118
136
  entry.ctime = f.ctime;
119
137
  entry.mtime = f.mtime;
package/fs.js CHANGED
@@ -323,6 +323,7 @@ class BlockFS {
323
323
  async writeBlocks(blocks, data) {
324
324
  const { blockDataOffset, blockDataSize, sentinelID, storage } = this;
325
325
  if (!blocks) blocks = await this.allocateBlocks(data.length);
326
+ this.opts.logger.debug("allocated blocks", blocks.length, blocks);
326
327
  let offset = 0;
327
328
  for (let i = 0, numBlocks = blocks.length - 1; i <= numBlocks; i++) {
328
329
  if (offset >= data.length)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/block-fs",
3
- "version": "0.4.4",
3
+ "version": "0.5.0",
4
4
  "description": "Customizable block-based storage, adapters & file system layer",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -43,16 +43,16 @@
43
43
  },
44
44
  "dependencies": {
45
45
  "@thi.ng/api": "^8.11.29",
46
- "@thi.ng/args": "^2.3.70",
46
+ "@thi.ng/args": "^2.3.71",
47
47
  "@thi.ng/binary": "^3.4.52",
48
- "@thi.ng/bitfield": "^2.4.4",
48
+ "@thi.ng/bitfield": "^2.4.5",
49
49
  "@thi.ng/checks": "^3.7.9",
50
50
  "@thi.ng/errors": "^2.5.35",
51
51
  "@thi.ng/file-io": "^2.1.38",
52
52
  "@thi.ng/logger": "^3.1.10",
53
53
  "@thi.ng/mime": "^2.7.11",
54
54
  "@thi.ng/random": "^4.1.20",
55
- "@thi.ng/strings": "^3.9.14"
55
+ "@thi.ng/strings": "^3.9.15"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@types/node": "^22.15.21",
@@ -132,5 +132,5 @@
132
132
  "status": "alpha",
133
133
  "year": 2024
134
134
  },
135
- "gitHead": "93cdcd8db4d4669561a7f0ebc47697bdbfd04214\n"
135
+ "gitHead": "b076434a497b291ad33e81b1a15f6a71e2c82cc2\n"
136
136
  }