@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
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import type { ArrayOf } from 'memium';
|
|
2
|
+
import { BPlusTree, type BPlusTreeStorage } from 'memium/bplustree';
|
|
3
|
+
import { EpochTable, Mutex } from 'memium/locks';
|
|
4
|
+
import type { UUID } from 'node:crypto';
|
|
5
|
+
import { BufferView } from 'utilium/buffer';
|
|
6
|
+
import type { UsageInfo } from '../../internal/filesystem.js';
|
|
7
|
+
import type { StoreFS } from '../store/fs.js';
|
|
8
|
+
import { SyncMapTransaction, type SyncMapStore } from '../store/map.js';
|
|
9
|
+
import type { Store } from '../store/store.js';
|
|
10
|
+
declare const Extent_base: import("memium").StructConstructor<BufferView<any>>;
|
|
11
|
+
/** A range of bytes */
|
|
12
|
+
export declare class Extent extends Extent_base {
|
|
13
|
+
static name: string;
|
|
14
|
+
accessor offset: number;
|
|
15
|
+
accessor size: number;
|
|
16
|
+
}
|
|
17
|
+
/** Where the data for an ID is stored */
|
|
18
|
+
export declare class DataExtent extends Extent {
|
|
19
|
+
static name: string;
|
|
20
|
+
/** Bytes allocated, which can exceed `size` so data can grow in place */
|
|
21
|
+
accessor capacity: number;
|
|
22
|
+
}
|
|
23
|
+
declare const Commit_base: import("memium").StructConstructor<BufferView<any>>;
|
|
24
|
+
/** The roots and allocator state written by a transaction */
|
|
25
|
+
export declare class Commit extends Commit_base {
|
|
26
|
+
static name: string;
|
|
27
|
+
/** crc32c of the rest of the commit */
|
|
28
|
+
accessor checksum: number;
|
|
29
|
+
accessor generation: bigint;
|
|
30
|
+
/** ID to extent */
|
|
31
|
+
accessor index_root: number;
|
|
32
|
+
accessor index_count: number;
|
|
33
|
+
/** Free extents by offset */
|
|
34
|
+
accessor free_root: number;
|
|
35
|
+
/** Free extents by size then offset */
|
|
36
|
+
accessor size_root: number;
|
|
37
|
+
accessor free_count: number;
|
|
38
|
+
accessor free_bytes: number;
|
|
39
|
+
/** The newest block in the list of spare blocks for tree nodes */
|
|
40
|
+
accessor spare_head: number;
|
|
41
|
+
/** Spare blocks listed by `spare_head` */
|
|
42
|
+
accessor spare_count: number;
|
|
43
|
+
/** Spare blocks in the entire list */
|
|
44
|
+
accessor spare_total: number;
|
|
45
|
+
/** Blocks listing extents that are free once no reader can see them */
|
|
46
|
+
accessor pending_head: number;
|
|
47
|
+
accessor pending_tail: number;
|
|
48
|
+
accessor pending_bytes: number;
|
|
49
|
+
protected computeChecksum(): number;
|
|
50
|
+
update(): void;
|
|
51
|
+
isValid(generation: bigint): boolean;
|
|
52
|
+
}
|
|
53
|
+
declare const State_base: import("memium").StructConstructor<BufferView<any>>;
|
|
54
|
+
/** State shared by every thread using a file system, which is followed by an epoch table */
|
|
55
|
+
export declare class State extends State_base {
|
|
56
|
+
static name: string;
|
|
57
|
+
/** Held by writers */
|
|
58
|
+
accessor lock: bigint;
|
|
59
|
+
/** The generation of the current commit */
|
|
60
|
+
accessor generation: bigint;
|
|
61
|
+
accessor next_id: bigint;
|
|
62
|
+
/** The current and previous commits, at their generation modulo 2 */
|
|
63
|
+
accessor commits: ArrayOf<Commit>;
|
|
64
|
+
}
|
|
65
|
+
declare const PendingHeader_base: import("memium").StructConstructor<BufferView<any>>;
|
|
66
|
+
/** The start of a block listing extents retired by a generation, which is followed by the extents */
|
|
67
|
+
export declare class PendingHeader extends PendingHeader_base {
|
|
68
|
+
static name: string;
|
|
69
|
+
accessor next: number;
|
|
70
|
+
accessor count: number;
|
|
71
|
+
accessor generation: bigint;
|
|
72
|
+
}
|
|
73
|
+
declare const SpareHeader_base: import("memium").StructConstructor<BufferView<any>>;
|
|
74
|
+
/**
|
|
75
|
+
* The start of a block listing spare blocks, which is followed by their offsets.
|
|
76
|
+
* The newest block's count is in the commit instead.
|
|
77
|
+
*/
|
|
78
|
+
export declare class SpareHeader extends SpareHeader_base {
|
|
79
|
+
static name: string;
|
|
80
|
+
accessor next: number;
|
|
81
|
+
accessor count: number;
|
|
82
|
+
}
|
|
83
|
+
declare const SuperBlock_base: import("memium").StructConstructor<BufferView<any>>;
|
|
84
|
+
/**
|
|
85
|
+
* The super block for version 2 of the single-buffer format.
|
|
86
|
+
* Bytes 0 through 12 have the same layout in every version.
|
|
87
|
+
*/
|
|
88
|
+
export declare class SuperBlock extends SuperBlock_base {
|
|
89
|
+
static name: string;
|
|
90
|
+
/** crc32c of the bytes from 4 up to `lock` */
|
|
91
|
+
accessor checksum: number;
|
|
92
|
+
accessor magic: number;
|
|
93
|
+
/**
|
|
94
|
+
* The version of the on-disk format
|
|
95
|
+
* 1: v1.10.0+, append-only metadata blocks
|
|
96
|
+
* 2: copy-on-write B+ trees
|
|
97
|
+
*/
|
|
98
|
+
accessor version: number;
|
|
99
|
+
/** Which format of `Inode` is used */
|
|
100
|
+
accessor inode_format: number;
|
|
101
|
+
/** Features that must be supported to mount the file system. None are defined. */
|
|
102
|
+
accessor required_features: number;
|
|
103
|
+
/** Features that may be ignored. None are defined. */
|
|
104
|
+
accessor optional_features: number;
|
|
105
|
+
/** Size of tree nodes and other metadata blocks */
|
|
106
|
+
accessor block_size: number;
|
|
107
|
+
/** The size of the entire file system, including the super block */
|
|
108
|
+
accessor total_bytes: bigint;
|
|
109
|
+
accessor uuid: Uint8Array;
|
|
110
|
+
/** Byte offset of the shared state */
|
|
111
|
+
accessor state_offset: number;
|
|
112
|
+
accessor epoch_slots: number;
|
|
113
|
+
/** An optional label for the file system */
|
|
114
|
+
accessor label: Uint8Array;
|
|
115
|
+
protected accessor _padding: Uint8Array;
|
|
116
|
+
/** Held while the file system is created or upgraded. Not covered by the checksum. */
|
|
117
|
+
accessor lock: bigint;
|
|
118
|
+
protected computeChecksum(): number;
|
|
119
|
+
update(): void;
|
|
120
|
+
/** Checks that a file system of `byteLength` bytes can be mounted using this super block */
|
|
121
|
+
validate(byteLength: number): void;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* A transaction that changes a file system, which is built from copies of the blocks it changes.
|
|
125
|
+
* Nothing it does is visible until it is committed.
|
|
126
|
+
*/
|
|
127
|
+
export declare class WriteTransaction implements BPlusTreeStorage {
|
|
128
|
+
protected readonly store: SingleBufferStore;
|
|
129
|
+
protected readonly spareScale: number;
|
|
130
|
+
readonly buffer: ArrayBufferLike;
|
|
131
|
+
readonly pageSize: number;
|
|
132
|
+
readonly generation: bigint;
|
|
133
|
+
/** ID to extent */
|
|
134
|
+
readonly index: BPlusTree<bigint, DataExtent>;
|
|
135
|
+
/** Free extents by offset */
|
|
136
|
+
protected readonly byOffset: BPlusTree<number, number>;
|
|
137
|
+
/** Free extents by size then offset */
|
|
138
|
+
protected readonly bySize: BPlusTree<bigint, void>;
|
|
139
|
+
protected freeBytes: number;
|
|
140
|
+
protected spareHead: number;
|
|
141
|
+
protected spareCount: number;
|
|
142
|
+
protected spareTotal: number;
|
|
143
|
+
/** Spare blocks listed by the base commit in the newest list block, which can not be overwritten */
|
|
144
|
+
protected spareFloor: number;
|
|
145
|
+
protected readonly spareCapacity: number;
|
|
146
|
+
protected pendingHead: number;
|
|
147
|
+
protected pendingTail: number;
|
|
148
|
+
protected pendingBytes: number;
|
|
149
|
+
/** Blocks allocated by this transaction */
|
|
150
|
+
protected readonly fresh: Set<number>;
|
|
151
|
+
/** Blocks no commit references, which can be reused immediately */
|
|
152
|
+
protected recycled: number[];
|
|
153
|
+
/** Extents that become free once no reader can see them */
|
|
154
|
+
protected retired: [offset: number, size: number][];
|
|
155
|
+
/** Whether the free trees are being changed, during which spares are not refilled */
|
|
156
|
+
protected changingFreeTrees: boolean;
|
|
157
|
+
/**
|
|
158
|
+
* @param base The commit this transaction starts from
|
|
159
|
+
* @param spareScale Multiplies the number of spare blocks to keep
|
|
160
|
+
*/
|
|
161
|
+
constructor(store: SingleBufferStore, base: Commit, spareScale: number);
|
|
162
|
+
offsetOf(block: number): number;
|
|
163
|
+
alloc(): number;
|
|
164
|
+
free(block: number): void;
|
|
165
|
+
/** Minimum blocks available for tree nodes, enough to copy and split a path in both free trees */
|
|
166
|
+
protected lowWater(): number;
|
|
167
|
+
/** Blocks that can be allocated without changing the free trees */
|
|
168
|
+
protected availableBlocks(): number;
|
|
169
|
+
/** Takes a spare block, if there are any */
|
|
170
|
+
protected popSpare(): number | undefined;
|
|
171
|
+
/** Adds a free block to the spare blocks */
|
|
172
|
+
protected pushSpare(block: number): void;
|
|
173
|
+
/** Refills the spare blocks if they are below the low-water mark */
|
|
174
|
+
protected refillSpares(): void;
|
|
175
|
+
protected changeFreeTrees<T>(change: () => T): T;
|
|
176
|
+
/** Removes the free extent at `offset`, then returns everything after its first `size` bytes to free space */
|
|
177
|
+
protected split(offset: number, length: number, size: number): void;
|
|
178
|
+
/** Takes the smallest free extent that fits `size` bytes */
|
|
179
|
+
protected takeBestFit(size: number): number;
|
|
180
|
+
/** Allocates `size` bytes for data, leaving enough blocks to change the free trees */
|
|
181
|
+
allocate(size: number): number;
|
|
182
|
+
/** Frees an extent no reader can see, merging it with adjacent free extents */
|
|
183
|
+
freeExtent(offset: number, size: number): void;
|
|
184
|
+
/** Frees an extent once no reader can see this transaction's base */
|
|
185
|
+
retire(offset: number, size: number): void;
|
|
186
|
+
/** Frees extents retired by generations that readers no longer see */
|
|
187
|
+
protected releasePending(oldest: bigint | undefined): void;
|
|
188
|
+
protected appendPending(offset: number, size: number): void;
|
|
189
|
+
/** Records retired extents in the pending list, then writes this transaction's roots and allocator state to `commit` */
|
|
190
|
+
commit(commit: Commit): void;
|
|
191
|
+
}
|
|
192
|
+
export interface FormatOptions {
|
|
193
|
+
/** Byte ranges that are already in use */
|
|
194
|
+
used?: [start: number, end: number][];
|
|
195
|
+
uuid?: Uint8Array;
|
|
196
|
+
label?: Uint8Array;
|
|
197
|
+
/** The first ID to allocate */
|
|
198
|
+
nextId?: bigint;
|
|
199
|
+
/** Adds existing data in the first transaction */
|
|
200
|
+
populate?(tx: WriteTransaction): void;
|
|
201
|
+
}
|
|
202
|
+
export interface SingleBufferStoreOptions {
|
|
203
|
+
/** Erases the buffer and creates a new file system */
|
|
204
|
+
format?: boolean | FormatOptions;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* A store for version 2 of the single-buffer format.
|
|
208
|
+
*
|
|
209
|
+
* Every change is a transaction that copies what it modifies.
|
|
210
|
+
* Readers never block, and an interrupted writer does not change the file system.
|
|
211
|
+
* @category Stores and Transactions
|
|
212
|
+
*/
|
|
213
|
+
export declare class SingleBufferStore extends DataView<ArrayBufferLike> implements SyncMapStore {
|
|
214
|
+
readonly flags: readonly ["partial"];
|
|
215
|
+
readonly name = "sbfs";
|
|
216
|
+
readonly type = 1935828595;
|
|
217
|
+
get uuid(): UUID;
|
|
218
|
+
protected readonly superblock: SuperBlock;
|
|
219
|
+
/**
|
|
220
|
+
* The entire file system
|
|
221
|
+
* @internal
|
|
222
|
+
*/
|
|
223
|
+
readonly bytes: Uint8Array;
|
|
224
|
+
/** @internal */
|
|
225
|
+
readonly blockSize: number;
|
|
226
|
+
/** @internal */
|
|
227
|
+
readonly epochs: EpochTable;
|
|
228
|
+
protected readonly mutex: Mutex;
|
|
229
|
+
protected readonly generation: BigInt64Array;
|
|
230
|
+
protected readonly nextId: BigInt64Array;
|
|
231
|
+
protected readonly commits: [Commit, Commit];
|
|
232
|
+
/** The index of the version being read */
|
|
233
|
+
protected readonly index: BPlusTree<bigint, DataExtent>;
|
|
234
|
+
/**
|
|
235
|
+
* Opens a file system, or creates one if `format` is set.
|
|
236
|
+
* When creating one, byte ranges in `used` are kept, and the first transaction runs `populate` after making everything else free.
|
|
237
|
+
*/
|
|
238
|
+
constructor(buffer: ArrayBufferLike | ArrayBufferView, byteOffset?: number, byteLength?: number, options?: SingleBufferStoreOptions);
|
|
239
|
+
/** Reads the current commit, retrying if a writer replaces it while reading */
|
|
240
|
+
protected withCurrentCommit<T>(read: (commit: Commit, generation: bigint) => T): T;
|
|
241
|
+
/** Runs `read` against the current version, which stays valid until `read` returns */
|
|
242
|
+
protected read<T>(read: (index: BPlusTree<bigint, DataExtent>) => T): T;
|
|
243
|
+
/** Runs `change` in a write transaction, retrying with more spare blocks if the free trees run out of them */
|
|
244
|
+
write<T>(change: (tx: WriteTransaction) => T): T;
|
|
245
|
+
keys(): number[];
|
|
246
|
+
get(id: number, offset?: number, end?: number): Uint8Array | undefined;
|
|
247
|
+
set(id: number, data: Uint8Array, offset?: number): void;
|
|
248
|
+
delete(id: number): void;
|
|
249
|
+
allocId(): [ino: number, data: number];
|
|
250
|
+
usage(): UsageInfo;
|
|
251
|
+
protected _fs?: StoreFS<Store> | undefined;
|
|
252
|
+
get fs(): StoreFS<Store> | undefined;
|
|
253
|
+
set fs(fs: StoreFS<Store> | undefined);
|
|
254
|
+
sync(): Promise<void>;
|
|
255
|
+
transaction(): SyncMapTransaction;
|
|
256
|
+
}
|
|
257
|
+
export {};
|