@zenfs/core 2.7.6 → 2.8.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/README.md +5 -0
- package/dist/backends/index.d.ts +3 -1
- package/dist/backends/index.js +3 -1
- package/dist/backends/single_buffer/backend.d.ts +42 -0
- package/dist/backends/single_buffer/backend.js +204 -0
- package/dist/backends/{single_buffer.d.ts → single_buffer/v1.d.ts} +24 -34
- package/dist/backends/{single_buffer.js → single_buffer/v1.js} +10 -26
- package/dist/backends/single_buffer/v2.d.ts +257 -0
- package/dist/backends/single_buffer/v2.js +1283 -0
- package/dist/backends/store/fs.d.ts +1 -1
- package/dist/backends/store/fs.js +35 -18
- package/dist/backends/store/map.d.ts +6 -6
- package/dist/backends/store/map.js +6 -6
- package/dist/backends/store/store.d.ts +18 -14
- package/dist/backends/store/store.js +12 -14
- package/dist/config.d.ts +7 -0
- package/dist/config.js +9 -3
- package/dist/internal/contexts.d.ts +5 -0
- package/dist/internal/contexts.js +7 -1
- package/dist/internal/error.d.ts +5 -0
- package/dist/internal/error.js +10 -0
- package/dist/internal/inode.d.ts +25 -0
- package/dist/internal/inode.js +75 -10
- package/dist/mixins/async.js +47 -30
- package/dist/node/promises.js +23 -124
- package/dist/node/stats.d.ts +1 -1
- package/dist/node/stats.js +4 -1
- package/dist/node/sync.js +20 -51
- package/dist/polyfills.js +16 -0
- package/dist/vfs/async.d.ts +4 -1
- package/dist/vfs/async.js +149 -69
- package/dist/vfs/config.d.ts +10 -1
- package/dist/vfs/config.js +5 -2
- package/dist/vfs/file.js +10 -4
- package/dist/vfs/ioctl.js +2 -2
- package/dist/vfs/shared.d.ts +2 -0
- package/dist/vfs/shared.js +3 -4
- package/dist/vfs/sync.d.ts +4 -1
- package/dist/vfs/sync.js +142 -64
- package/dist/vfs/vcache.d.ts +14 -14
- package/dist/vfs/vcache.js +65 -57
- package/dist/vfs/watchers.d.ts +1 -0
- package/dist/vfs/watchers.js +2 -4
- package/dist/vfs/xattr.js +18 -17
- package/package.json +3 -4
- package/scripts/make-index.js +1 -1
- package/tests/backend/single-buffer-rotate.worker.js +1 -1
- package/tests/backend/single-buffer-v2.test.ts +342 -0
- package/tests/backend/single-buffer-v2.worker.js +51 -0
- package/tests/backend/single-buffer.test.ts +6 -6
- package/tests/backend/single-buffer.worker.js +1 -0
- package/tests/common/async.test.ts +46 -0
- package/tests/common/config.test.ts +1 -1
- package/tests/common/context.test.ts +30 -0
- package/tests/common/file_index.test.ts +1 -1
- package/tests/common/mounts.test.ts +12 -0
- package/tests/common/vcache.test.ts +13 -0
- package/tests/fs/concurrency.test.ts +3 -3
- package/tests/fs/links.test.ts +76 -0
- package/tests/fs/permissions.test.ts +253 -0
- package/tests/fs/stat.test.ts +1 -1
- package/tests/fs/streams.test.ts +1 -1
- package/tests/fs/watch.test.ts +14 -0
- package/tests/fs/xattr.test.ts +10 -0
- package/tests/perf/config.json +31 -1
- package/tests/perf/single-buffer-random.ts +38 -0
- package/tests/perf/single-buffer-read.ts +28 -0
- package/tests/perf/single-buffer-write.ts +41 -0
- package/tests/setup/single-buffer-v2.ts +10 -0
- package/tests/setup/single-buffer.ts +1 -0
package/README.md
CHANGED
|
@@ -93,3 +93,8 @@ A huge thank you to [deco.cx](https://github.com/deco-cx) for sponsoring ZenFS a
|
|
|
93
93
|
## Contact and Support
|
|
94
94
|
|
|
95
95
|
You can reach out [on Discord](https://zenfs.dev/discord) or by emailing jp@zenfs.dev
|
|
96
|
+
|
|
97
|
+
## License
|
|
98
|
+
|
|
99
|
+
[ZenFS](https://github.com/zen-fs/core) is licensed under the [LGPL 3.0 or later](https://www.gnu.org/licenses/lgpl-3.0.html) and [COPYING.md](https://github.com/zen-fs/core/blob/main/COPYING.md).
|
|
100
|
+
Copyright © James Prevett and other ZenFS contributors.
|
package/dist/backends/index.d.ts
CHANGED
|
@@ -4,7 +4,9 @@ export * from './fetch.js';
|
|
|
4
4
|
export * from './memory.js';
|
|
5
5
|
export * from './passthrough.js';
|
|
6
6
|
export * from './port.js';
|
|
7
|
-
export * from './single_buffer.js';
|
|
7
|
+
export * from './single_buffer/backend.js';
|
|
8
|
+
export { SingleBufferStore } from './single_buffer/v1.js';
|
|
9
|
+
export { SingleBufferStore as SingleBufferStoreV2 } from './single_buffer/v2.js';
|
|
8
10
|
export * from './store/fs.js';
|
|
9
11
|
export * from './store/map.js';
|
|
10
12
|
export * from './store/store.js';
|
package/dist/backends/index.js
CHANGED
|
@@ -5,7 +5,9 @@ export * from './fetch.js';
|
|
|
5
5
|
export * from './memory.js';
|
|
6
6
|
export * from './passthrough.js';
|
|
7
7
|
export * from './port.js';
|
|
8
|
-
export * from './single_buffer.js';
|
|
8
|
+
export * from './single_buffer/backend.js';
|
|
9
|
+
export { SingleBufferStore } from './single_buffer/v1.js';
|
|
10
|
+
export { SingleBufferStore as SingleBufferStoreV2 } from './single_buffer/v2.js';
|
|
9
11
|
export * from './store/fs.js';
|
|
10
12
|
export * from './store/map.js';
|
|
11
13
|
export * from './store/store.js';
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { StoreFS } from '../store/fs.js';
|
|
2
|
+
import * as v1 from './v1.js';
|
|
3
|
+
import * as v2 from './v2.js';
|
|
4
|
+
/**
|
|
5
|
+
* Options for the `SingleBuffer` backend
|
|
6
|
+
* @category Backends and Configuration
|
|
7
|
+
*/
|
|
8
|
+
export interface SingleBufferOptions {
|
|
9
|
+
buffer: ArrayBufferLike | ArrayBufferView;
|
|
10
|
+
/**
|
|
11
|
+
* Create new file systems with version 2 of the format, and upgrade existing ones to it.
|
|
12
|
+
* File systems that already use version 2 always do.
|
|
13
|
+
*/
|
|
14
|
+
v2?: boolean;
|
|
15
|
+
}
|
|
16
|
+
declare const _SingleBuffer: {
|
|
17
|
+
readonly name: "SingleBuffer";
|
|
18
|
+
readonly options: {
|
|
19
|
+
readonly buffer: {
|
|
20
|
+
readonly type: "object";
|
|
21
|
+
readonly required: true;
|
|
22
|
+
};
|
|
23
|
+
readonly v2: {
|
|
24
|
+
readonly type: "boolean";
|
|
25
|
+
readonly required: false;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
readonly create: (opt: SingleBufferOptions) => StoreFS<v1.SingleBufferStore | v2.SingleBufferStore>;
|
|
29
|
+
};
|
|
30
|
+
type _SingleBuffer = typeof _SingleBuffer;
|
|
31
|
+
/**
|
|
32
|
+
* A backend that uses a single buffer for storing data
|
|
33
|
+
* @category Backends and Configuration
|
|
34
|
+
*/
|
|
35
|
+
export interface SingleBuffer extends _SingleBuffer {
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A backend that uses a single buffer for storing data
|
|
39
|
+
* @category Backends and Configuration
|
|
40
|
+
*/
|
|
41
|
+
export declare const SingleBuffer: SingleBuffer;
|
|
42
|
+
export {};
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
2
|
+
if (value !== null && value !== void 0) {
|
|
3
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
4
|
+
var dispose, inner;
|
|
5
|
+
if (async) {
|
|
6
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
7
|
+
dispose = value[Symbol.asyncDispose];
|
|
8
|
+
}
|
|
9
|
+
if (dispose === void 0) {
|
|
10
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
11
|
+
dispose = value[Symbol.dispose];
|
|
12
|
+
if (async) inner = dispose;
|
|
13
|
+
}
|
|
14
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
15
|
+
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
|
|
16
|
+
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
17
|
+
}
|
|
18
|
+
else if (async) {
|
|
19
|
+
env.stack.push({ async: true });
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
};
|
|
23
|
+
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
24
|
+
return function (env) {
|
|
25
|
+
function fail(e) {
|
|
26
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
27
|
+
env.hasError = true;
|
|
28
|
+
}
|
|
29
|
+
var r, s = 0;
|
|
30
|
+
function next() {
|
|
31
|
+
while (r = env.stack.pop()) {
|
|
32
|
+
try {
|
|
33
|
+
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
34
|
+
if (r.dispose) {
|
|
35
|
+
var result = r.dispose.call(r.value);
|
|
36
|
+
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
37
|
+
}
|
|
38
|
+
else s |= 1;
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
fail(e);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
45
|
+
if (env.hasError) throw env.error;
|
|
46
|
+
}
|
|
47
|
+
return next();
|
|
48
|
+
};
|
|
49
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
50
|
+
var e = new Error(message);
|
|
51
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
52
|
+
});
|
|
53
|
+
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
54
|
+
import { withErrno } from 'kerium';
|
|
55
|
+
import { crit, err, info, warn } from 'kerium/log';
|
|
56
|
+
import { offsetof, sizeof } from 'memium';
|
|
57
|
+
import { Mutex } from 'memium/locks';
|
|
58
|
+
import { crc32c } from 'utilium/checksum';
|
|
59
|
+
import { _inode_version } from '../../internal/inode.js';
|
|
60
|
+
import { StoreFS } from '../store/fs.js';
|
|
61
|
+
import * as v1 from './v1.js';
|
|
62
|
+
import * as v2 from './v2.js';
|
|
63
|
+
const hex = (value) => '0x' + value.toString(16).padStart(8, '0');
|
|
64
|
+
/** The lock held while a file system is created or upgraded, which is in the padding of a version 1 super block */
|
|
65
|
+
const lockOffset = offsetof(v2.SuperBlock, 'lock');
|
|
66
|
+
/** Checksum of a version 1 super block, treating the lock as zero */
|
|
67
|
+
function v1Checksum(bytes) {
|
|
68
|
+
const data = bytes.slice(4, sizeof(v1.SuperBlock));
|
|
69
|
+
data.fill(0, lockOffset - 4, lockOffset + 4);
|
|
70
|
+
return crc32c(data);
|
|
71
|
+
}
|
|
72
|
+
/** Locks a file system while it is created or upgraded. Only shared buffers are locked. */
|
|
73
|
+
function lockSetup(bytes, view) {
|
|
74
|
+
const word = new BigInt64Array(bytes.buffer, bytes.byteOffset + lockOffset, 1);
|
|
75
|
+
const garbage = Atomics.load(word, 0);
|
|
76
|
+
const isV1 = view.getUint32(4, true) == v1.sb_magic && view.getUint16(8, true) < 2;
|
|
77
|
+
// The padding of a version 1 super block was never cleared
|
|
78
|
+
if (garbage && isV1 && crc32c(bytes.subarray(4, sizeof(v1.SuperBlock))) == view.getUint32(0, true)) {
|
|
79
|
+
if (Atomics.compareExchange(word, 0, garbage, 0n) === garbage)
|
|
80
|
+
view.setUint32(0, v1Checksum(bytes), true);
|
|
81
|
+
}
|
|
82
|
+
if (typeof SharedArrayBuffer != 'undefined' && bytes.buffer instanceof SharedArrayBuffer)
|
|
83
|
+
return new Mutex(bytes.buffer, bytes.byteOffset + lockOffset).lock();
|
|
84
|
+
Atomics.store(word, 0, 0n);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Upgrades a version 1 file system in place.
|
|
88
|
+
* Existing data is not moved, and the version 1 metadata stays intact until the new super block is written.
|
|
89
|
+
*/
|
|
90
|
+
function upgrade(bytes, view) {
|
|
91
|
+
info('sbfs: upgrading from version 1');
|
|
92
|
+
const field = (name) => offsetof(v1.SuperBlock, name);
|
|
93
|
+
if (v1Checksum(bytes) != view.getUint32(0, true))
|
|
94
|
+
throw crit(withErrno('EIO', 'sbfs: checksum mismatch for version 1 super block'));
|
|
95
|
+
if (view.getUint16(field('inode_format'), true) != _inode_version)
|
|
96
|
+
throw crit(withErrno('EIO', 'sbfs: inode format mismatch'));
|
|
97
|
+
if (view.getUint32(field('metadata_block_size'), true) != sizeof(v1.MetadataBlock))
|
|
98
|
+
throw crit(withErrno('EIO', 'sbfs: metadata block size mismatch'));
|
|
99
|
+
const total = Number(view.getBigUint64(field('total_bytes'), true));
|
|
100
|
+
if (total > bytes.byteLength)
|
|
101
|
+
throw crit(withErrno('EIO', 'sbfs: invalid size in version 1 super block'));
|
|
102
|
+
const used = [];
|
|
103
|
+
const entries = new Map();
|
|
104
|
+
const blocks = [];
|
|
105
|
+
// Version 1 metadata block offsets are relative to the buffer, but data offsets are relative to the file system
|
|
106
|
+
for (let absolute = view.getUint32(field('metadata_offset'), true); absolute;) {
|
|
107
|
+
const offset = absolute - bytes.byteOffset;
|
|
108
|
+
if (offset < sizeof(v1.SuperBlock) || offset + sizeof(v1.MetadataBlock) > total || blocks.includes(offset))
|
|
109
|
+
throw crit(withErrno('EIO', `sbfs: invalid metadata block at ${hex(absolute)}`));
|
|
110
|
+
const block = new v1.MetadataBlock(bytes.buffer, absolute);
|
|
111
|
+
if (block.checksum != v1.checksum(block)) {
|
|
112
|
+
if (!blocks.length)
|
|
113
|
+
throw crit(withErrno('EIO', 'sbfs: checksum mismatch for metadata block'));
|
|
114
|
+
warn(`sbfs: checksum mismatch for metadata block at ${hex(absolute)}`);
|
|
115
|
+
}
|
|
116
|
+
blocks.push(offset);
|
|
117
|
+
used.push([offset, offset + sizeof(v1.MetadataBlock)]);
|
|
118
|
+
for (const entry of block.items) {
|
|
119
|
+
if (!entry.offset || entries.has(entry.id))
|
|
120
|
+
continue;
|
|
121
|
+
if (entry.offset + entry.size > total)
|
|
122
|
+
throw crit(withErrno('EIO', `sbfs: data for ${hex(entry.id)} is out of bounds`));
|
|
123
|
+
entries.set(entry.id, [entry.size ? entry.offset : 0, entry.size]);
|
|
124
|
+
if (entry.size)
|
|
125
|
+
used.push([entry.offset, entry.offset + entry.size]);
|
|
126
|
+
}
|
|
127
|
+
absolute = block.previous_offset;
|
|
128
|
+
}
|
|
129
|
+
let maxId = 0;
|
|
130
|
+
for (const id of entries.keys())
|
|
131
|
+
maxId = Math.max(maxId, id);
|
|
132
|
+
const store = new v2.SingleBufferStore(bytes.buffer, bytes.byteOffset, bytes.byteLength, {
|
|
133
|
+
format: {
|
|
134
|
+
used,
|
|
135
|
+
uuid: bytes.slice(field('uuid'), field('uuid') + 16),
|
|
136
|
+
label: bytes.slice(field('label'), field('label') + 64),
|
|
137
|
+
nextId: BigInt(Math.max(2, maxId + 1)),
|
|
138
|
+
populate(tx) {
|
|
139
|
+
for (const [id, [offset, size]] of entries)
|
|
140
|
+
tx.index.set(BigInt(id), Object.assign(new v2.DataExtent(), { offset, size, capacity: size }));
|
|
141
|
+
for (const block of blocks)
|
|
142
|
+
tx.retire(block, sizeof(v1.MetadataBlock));
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
info(`sbfs: upgraded ${entries.size} entries from version 1`);
|
|
147
|
+
return store;
|
|
148
|
+
}
|
|
149
|
+
const _SingleBuffer = {
|
|
150
|
+
name: 'SingleBuffer',
|
|
151
|
+
options: {
|
|
152
|
+
buffer: { type: 'object', required: true },
|
|
153
|
+
v2: { type: 'boolean', required: false },
|
|
154
|
+
},
|
|
155
|
+
create(opt) {
|
|
156
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
157
|
+
try {
|
|
158
|
+
const [buffer, byteOffset, byteLength] = ArrayBuffer.isView(opt.buffer)
|
|
159
|
+
? [opt.buffer.buffer, opt.buffer.byteOffset, opt.buffer.byteLength]
|
|
160
|
+
: [opt.buffer, 0, opt.buffer.byteLength];
|
|
161
|
+
if (byteLength < sizeof(v1.SuperBlock))
|
|
162
|
+
throw crit(withErrno('EINVAL', 'sbfs: buffer is too small for a file system'));
|
|
163
|
+
const bytes = new Uint8Array(buffer, byteOffset, byteLength);
|
|
164
|
+
const view = new DataView(buffer, byteOffset, byteLength);
|
|
165
|
+
const formatted = view.getUint32(4, true) == v1.sb_magic;
|
|
166
|
+
const _ = __addDisposableResource(env_1, opt.v2 || (!formatted && opt.v2 !== false) ? lockSetup(bytes, view) : undefined, false);
|
|
167
|
+
let store;
|
|
168
|
+
switch (view.getUint32(4, true) == v1.sb_magic ? view.getUint16(8, true) : undefined) {
|
|
169
|
+
case undefined:
|
|
170
|
+
store =
|
|
171
|
+
opt.v2 === false
|
|
172
|
+
? new v1.SingleBufferStore(buffer, byteOffset, byteLength)
|
|
173
|
+
: new v2.SingleBufferStore(buffer, byteOffset, byteLength, { format: true });
|
|
174
|
+
break;
|
|
175
|
+
case 0:
|
|
176
|
+
err('sbfs: got unexpected super block version 0');
|
|
177
|
+
// falls through
|
|
178
|
+
case 1:
|
|
179
|
+
store = opt.v2 ? upgrade(bytes, view) : new v1.SingleBufferStore(buffer, byteOffset, byteLength);
|
|
180
|
+
break;
|
|
181
|
+
case 2:
|
|
182
|
+
store = new v2.SingleBufferStore(buffer, byteOffset, byteLength);
|
|
183
|
+
break;
|
|
184
|
+
default:
|
|
185
|
+
throw crit(withErrno('EIO', 'sbfs: unsupported super block version'));
|
|
186
|
+
}
|
|
187
|
+
const fs = new StoreFS(store);
|
|
188
|
+
fs.checkRootSync();
|
|
189
|
+
return fs;
|
|
190
|
+
}
|
|
191
|
+
catch (e_1) {
|
|
192
|
+
env_1.error = e_1;
|
|
193
|
+
env_1.hasError = true;
|
|
194
|
+
}
|
|
195
|
+
finally {
|
|
196
|
+
__disposeResources(env_1);
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
/**
|
|
201
|
+
* A backend that uses a single buffer for storing data
|
|
202
|
+
* @category Backends and Configuration
|
|
203
|
+
*/
|
|
204
|
+
export const SingleBuffer = _SingleBuffer;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { ArrayOf } from 'memium';
|
|
2
2
|
import type { UUID } from 'node:crypto';
|
|
3
3
|
import { BufferView } from 'utilium/buffer';
|
|
4
|
-
import type { UsageInfo } from '
|
|
5
|
-
import { StoreFS } from '
|
|
6
|
-
import { SyncMapTransaction, type SyncMapStore } from '
|
|
7
|
-
import type { Store } from '
|
|
4
|
+
import type { UsageInfo } from '../../internal/filesystem.js';
|
|
5
|
+
import type { StoreFS } from '../store/fs.js';
|
|
6
|
+
import { SyncMapTransaction, type SyncMapStore } from '../store/map.js';
|
|
7
|
+
import type { Store } from '../store/store.js';
|
|
8
8
|
type SBLock = Disposable & (() => void);
|
|
9
9
|
declare const MetadataEntry_base: import("memium").StructConstructor<BufferView<any>>;
|
|
10
10
|
declare class MetadataEntry extends MetadataEntry_base {
|
|
@@ -54,6 +54,12 @@ export declare class MetadataBlock extends MetadataBlock_base<ArrayBufferLike> {
|
|
|
54
54
|
waitUnlocked(depth?: number): void;
|
|
55
55
|
lock(): SBLock;
|
|
56
56
|
}
|
|
57
|
+
export declare const sb_magic = 1651715706;
|
|
58
|
+
/**
|
|
59
|
+
* Shortcut for minor perf. bump
|
|
60
|
+
* @internal
|
|
61
|
+
*/
|
|
62
|
+
export declare const kUsedBytes = 2;
|
|
57
63
|
declare const SuperBlock_base: import("memium/decorators").StructFromTypedArray<BigUint64Array<ArrayBuffer>>;
|
|
58
64
|
/**
|
|
59
65
|
* The super block structure for a single-buffer file system
|
|
@@ -69,7 +75,10 @@ export declare class SuperBlock extends SuperBlock_base<ArrayBufferLike> {
|
|
|
69
75
|
accessor checksum: number;
|
|
70
76
|
/** Signature for the superblock. */
|
|
71
77
|
accessor magic: number;
|
|
72
|
-
/**
|
|
78
|
+
/**
|
|
79
|
+
* The version of the on-disk format
|
|
80
|
+
* 1: v1.10.0+
|
|
81
|
+
*/
|
|
73
82
|
accessor version: number;
|
|
74
83
|
/** Which format of `Inode` is used */
|
|
75
84
|
accessor inode_format: number;
|
|
@@ -108,6 +117,16 @@ export declare class SuperBlock extends SuperBlock_base<ArrayBufferLike> {
|
|
|
108
117
|
*/
|
|
109
118
|
isUnused(offset: number, length: number): boolean;
|
|
110
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Compute the checksum for a super block or metadata block.
|
|
122
|
+
* Note we don't include the checksum when computing a new one.
|
|
123
|
+
*/
|
|
124
|
+
export declare function checksum(value: SuperBlock | MetadataBlock): number;
|
|
125
|
+
/**
|
|
126
|
+
* Update a block's checksum and timestamp.
|
|
127
|
+
* @internal @hidden
|
|
128
|
+
*/
|
|
129
|
+
export declare function _update(value: SuperBlock | MetadataBlock): void;
|
|
111
130
|
/**
|
|
112
131
|
*
|
|
113
132
|
* @category Stores and Transactions
|
|
@@ -135,33 +154,4 @@ export declare class SingleBufferStore extends BufferView implements SyncMapStor
|
|
|
135
154
|
usage(): UsageInfo;
|
|
136
155
|
transaction(): SyncMapTransaction;
|
|
137
156
|
}
|
|
138
|
-
/**
|
|
139
|
-
* Options for the `SingleBuffer` backend
|
|
140
|
-
* @category Backends and Configuration
|
|
141
|
-
*/
|
|
142
|
-
export interface SingleBufferOptions {
|
|
143
|
-
buffer: ArrayBufferLike | ArrayBufferView;
|
|
144
|
-
}
|
|
145
|
-
declare const _SingleBuffer: {
|
|
146
|
-
readonly name: "SingleBuffer";
|
|
147
|
-
readonly options: {
|
|
148
|
-
readonly buffer: {
|
|
149
|
-
readonly type: "object";
|
|
150
|
-
readonly required: true;
|
|
151
|
-
};
|
|
152
|
-
};
|
|
153
|
-
readonly create: (opt: SingleBufferOptions) => StoreFS<SingleBufferStore>;
|
|
154
|
-
};
|
|
155
|
-
type _SingleBuffer = typeof _SingleBuffer;
|
|
156
|
-
/**
|
|
157
|
-
* A backend that uses a single buffer for storing data
|
|
158
|
-
* @category Backends and Configuration
|
|
159
|
-
*/
|
|
160
|
-
export interface SingleBuffer extends _SingleBuffer {
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* A backend that uses a single buffer for storing data
|
|
164
|
-
* @category Backends and Configuration
|
|
165
|
-
*/
|
|
166
|
-
export declare const SingleBuffer: SingleBuffer;
|
|
167
157
|
export {};
|
|
@@ -92,9 +92,8 @@ import { $from, field, struct, types as t } from 'memium/decorators';
|
|
|
92
92
|
import { BufferView } from 'utilium/buffer';
|
|
93
93
|
import { crc32c } from 'utilium/checksum';
|
|
94
94
|
import { decodeUUID, encodeUUID } from 'utilium/string';
|
|
95
|
-
import { _inode_version, Inode } from '
|
|
96
|
-
import {
|
|
97
|
-
import { SyncMapTransaction } from './store/map.js';
|
|
95
|
+
import { _inode_version, Inode } from '../../internal/inode.js';
|
|
96
|
+
import { SyncMapTransaction } from '../store/map.js';
|
|
98
97
|
const hex = (value) => '0x' + value.toString(16).padStart(8, '0');
|
|
99
98
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
100
99
|
const { format } = new Intl.NumberFormat('en-US', {
|
|
@@ -315,12 +314,12 @@ let MetadataBlock = (() => {
|
|
|
315
314
|
export { MetadataBlock };
|
|
316
315
|
// workaround for https://github.com/microsoft/TypeScript/issues/61862
|
|
317
316
|
Object.assign(MetadataBlock, { lockIndex: offsetof(MetadataBlock, 'locked') / Int32Array.BYTES_PER_ELEMENT });
|
|
318
|
-
const sb_magic = 0x62732e7a; // 'z.sb'
|
|
317
|
+
export const sb_magic = 0x62732e7a; // 'z.sb'
|
|
319
318
|
/**
|
|
320
319
|
* Shortcut for minor perf. bump
|
|
321
320
|
* @internal
|
|
322
321
|
*/
|
|
323
|
-
const kUsedBytes = 2;
|
|
322
|
+
export const kUsedBytes = 2;
|
|
324
323
|
/**
|
|
325
324
|
* The super block structure for a single-buffer file system
|
|
326
325
|
*/
|
|
@@ -448,7 +447,10 @@ let SuperBlock = (() => {
|
|
|
448
447
|
get magic() { return this.#magic_accessor_storage; }
|
|
449
448
|
set magic(value) { this.#magic_accessor_storage = value; }
|
|
450
449
|
#version_accessor_storage = (__runInitializers(this, _magic_extraInitializers), __runInitializers(this, _version_initializers, void 0));
|
|
451
|
-
/**
|
|
450
|
+
/**
|
|
451
|
+
* The version of the on-disk format
|
|
452
|
+
* 1: v1.10.0+
|
|
453
|
+
*/
|
|
452
454
|
get version() { return this.#version_accessor_storage; }
|
|
453
455
|
set version(value) { this.#version_accessor_storage = value; }
|
|
454
456
|
#inode_format_accessor_storage = (__runInitializers(this, _version_extraInitializers), __runInitializers(this, _inode_format_initializers, void 0));
|
|
@@ -572,7 +574,7 @@ const kMetadataOffset = offsetof(SuperBlock, 'metadata_offset') / Uint32Array.BY
|
|
|
572
574
|
* Compute the checksum for a super block or metadata block.
|
|
573
575
|
* Note we don't include the checksum when computing a new one.
|
|
574
576
|
*/
|
|
575
|
-
function checksum(value) {
|
|
577
|
+
export function checksum(value) {
|
|
576
578
|
let length = sizeof(value) - 4;
|
|
577
579
|
if (value instanceof MetadataBlock)
|
|
578
580
|
length -= Int32Array.BYTES_PER_ELEMENT;
|
|
@@ -582,7 +584,7 @@ function checksum(value) {
|
|
|
582
584
|
* Update a block's checksum and timestamp.
|
|
583
585
|
* @internal @hidden
|
|
584
586
|
*/
|
|
585
|
-
function _update(value) {
|
|
587
|
+
export function _update(value) {
|
|
586
588
|
if (value instanceof MetadataBlock)
|
|
587
589
|
value.timestamp = BigInt(Date.now());
|
|
588
590
|
value.checksum = checksum(value);
|
|
@@ -732,21 +734,3 @@ export class SingleBufferStore extends BufferView {
|
|
|
732
734
|
return new SyncMapTransaction(this);
|
|
733
735
|
}
|
|
734
736
|
}
|
|
735
|
-
const _SingleBuffer = {
|
|
736
|
-
name: 'SingleBuffer',
|
|
737
|
-
options: {
|
|
738
|
-
buffer: { type: 'object', required: true },
|
|
739
|
-
},
|
|
740
|
-
create(opt) {
|
|
741
|
-
const fs = new StoreFS(ArrayBuffer.isView(opt.buffer)
|
|
742
|
-
? new SingleBufferStore(opt.buffer.buffer, opt.buffer.byteOffset, opt.buffer.byteLength)
|
|
743
|
-
: new SingleBufferStore(opt.buffer));
|
|
744
|
-
fs.checkRootSync();
|
|
745
|
-
return fs;
|
|
746
|
-
},
|
|
747
|
-
};
|
|
748
|
-
/**
|
|
749
|
-
* A backend that uses a single buffer for storing data
|
|
750
|
-
* @category Backends and Configuration
|
|
751
|
-
*/
|
|
752
|
-
export const SingleBuffer = _SingleBuffer;
|