@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,1283 @@
|
|
|
1
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
2
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
3
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
4
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
5
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
6
|
+
var _, done = false;
|
|
7
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
8
|
+
var context = {};
|
|
9
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
10
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
11
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
12
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
13
|
+
if (kind === "accessor") {
|
|
14
|
+
if (result === void 0) continue;
|
|
15
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
16
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
17
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
18
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
19
|
+
}
|
|
20
|
+
else if (_ = accept(result)) {
|
|
21
|
+
if (kind === "field") initializers.unshift(_);
|
|
22
|
+
else descriptor[key] = _;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
26
|
+
done = true;
|
|
27
|
+
};
|
|
28
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
29
|
+
var useValue = arguments.length > 2;
|
|
30
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
31
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
32
|
+
}
|
|
33
|
+
return useValue ? value : void 0;
|
|
34
|
+
};
|
|
35
|
+
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
36
|
+
if (value !== null && value !== void 0) {
|
|
37
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
38
|
+
var dispose, inner;
|
|
39
|
+
if (async) {
|
|
40
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
41
|
+
dispose = value[Symbol.asyncDispose];
|
|
42
|
+
}
|
|
43
|
+
if (dispose === void 0) {
|
|
44
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
45
|
+
dispose = value[Symbol.dispose];
|
|
46
|
+
if (async) inner = dispose;
|
|
47
|
+
}
|
|
48
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
49
|
+
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
|
|
50
|
+
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
51
|
+
}
|
|
52
|
+
else if (async) {
|
|
53
|
+
env.stack.push({ async: true });
|
|
54
|
+
}
|
|
55
|
+
return value;
|
|
56
|
+
};
|
|
57
|
+
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
58
|
+
return function (env) {
|
|
59
|
+
function fail(e) {
|
|
60
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
61
|
+
env.hasError = true;
|
|
62
|
+
}
|
|
63
|
+
var r, s = 0;
|
|
64
|
+
function next() {
|
|
65
|
+
while (r = env.stack.pop()) {
|
|
66
|
+
try {
|
|
67
|
+
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
68
|
+
if (r.dispose) {
|
|
69
|
+
var result = r.dispose.call(r.value);
|
|
70
|
+
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
71
|
+
}
|
|
72
|
+
else s |= 1;
|
|
73
|
+
}
|
|
74
|
+
catch (e) {
|
|
75
|
+
fail(e);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
79
|
+
if (env.hasError) throw env.error;
|
|
80
|
+
}
|
|
81
|
+
return next();
|
|
82
|
+
};
|
|
83
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
84
|
+
var e = new Error(message);
|
|
85
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
86
|
+
});
|
|
87
|
+
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
88
|
+
import { withErrno } from 'kerium';
|
|
89
|
+
import { alert, crit, debug, err } from 'kerium/log';
|
|
90
|
+
import { array, offsetof, sizeof } from 'memium';
|
|
91
|
+
import { BPlusTree } from 'memium/bplustree';
|
|
92
|
+
import { $from, field, struct, types as t } from 'memium/decorators';
|
|
93
|
+
import { EpochTable, Mutex } from 'memium/locks';
|
|
94
|
+
import { types as primitive } from 'memium/primitives';
|
|
95
|
+
import { Void } from 'memium/types';
|
|
96
|
+
import { _throw } from 'utilium';
|
|
97
|
+
import { BufferView } from 'utilium/buffer';
|
|
98
|
+
import { crc32c } from 'utilium/checksum';
|
|
99
|
+
import { decodeUUID, encodeUUID } from 'utilium/string';
|
|
100
|
+
import { _inode_version, Inode } from '../../internal/inode.js';
|
|
101
|
+
import { SyncMapTransaction } from '../store/map.js';
|
|
102
|
+
import { sb_magic } from './v1.js';
|
|
103
|
+
const hex = (value) => '0x' + value.toString(16).padStart(8, '0');
|
|
104
|
+
const default_epoch_slots = 64;
|
|
105
|
+
const default_block_size = 4096;
|
|
106
|
+
/** Most spare blocks for tree nodes when a file system is created */
|
|
107
|
+
const initial_spares = 16;
|
|
108
|
+
/** Offsets are 32 bits */
|
|
109
|
+
const max_size = 0xffffffff;
|
|
110
|
+
/** Highest ID that fits in an inode */
|
|
111
|
+
const max_id = 0xffffffffn;
|
|
112
|
+
/** A range of bytes */
|
|
113
|
+
let Extent = (() => {
|
|
114
|
+
var _a, _b;
|
|
115
|
+
let _classDecorators = [struct.packed()];
|
|
116
|
+
let _classDescriptor;
|
|
117
|
+
let _classExtraInitializers = [];
|
|
118
|
+
let _classThis;
|
|
119
|
+
let _classSuper = $from(BufferView);
|
|
120
|
+
let _offset_decorators;
|
|
121
|
+
let _offset_initializers = [];
|
|
122
|
+
let _offset_extraInitializers = [];
|
|
123
|
+
let _size_decorators;
|
|
124
|
+
let _size_initializers = [];
|
|
125
|
+
let _size_extraInitializers = [];
|
|
126
|
+
var Extent = class extends _classSuper {
|
|
127
|
+
static { _classThis = this; }
|
|
128
|
+
static {
|
|
129
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
130
|
+
_offset_decorators = [(_a = t).uint32.bind(_a)];
|
|
131
|
+
_size_decorators = [(_b = t).uint32.bind(_b)];
|
|
132
|
+
__esDecorate(this, null, _offset_decorators, { kind: "accessor", name: "offset", static: false, private: false, access: { has: obj => "offset" in obj, get: obj => obj.offset, set: (obj, value) => { obj.offset = value; } }, metadata: _metadata }, _offset_initializers, _offset_extraInitializers);
|
|
133
|
+
__esDecorate(this, null, _size_decorators, { kind: "accessor", name: "size", static: false, private: false, access: { has: obj => "size" in obj, get: obj => obj.size, set: (obj, value) => { obj.size = value; } }, metadata: _metadata }, _size_initializers, _size_extraInitializers);
|
|
134
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
135
|
+
Extent = _classThis = _classDescriptor.value;
|
|
136
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
137
|
+
}
|
|
138
|
+
static name = 'sbfs.Extent';
|
|
139
|
+
#offset_accessor_storage = __runInitializers(this, _offset_initializers, void 0);
|
|
140
|
+
get offset() { return this.#offset_accessor_storage; }
|
|
141
|
+
set offset(value) { this.#offset_accessor_storage = value; }
|
|
142
|
+
#size_accessor_storage = (__runInitializers(this, _offset_extraInitializers), __runInitializers(this, _size_initializers, void 0));
|
|
143
|
+
get size() { return this.#size_accessor_storage; }
|
|
144
|
+
set size(value) { this.#size_accessor_storage = value; }
|
|
145
|
+
constructor() {
|
|
146
|
+
super(...arguments);
|
|
147
|
+
__runInitializers(this, _size_extraInitializers);
|
|
148
|
+
}
|
|
149
|
+
static {
|
|
150
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
return Extent = _classThis;
|
|
154
|
+
})();
|
|
155
|
+
export { Extent };
|
|
156
|
+
/** Where the data for an ID is stored */
|
|
157
|
+
let DataExtent = (() => {
|
|
158
|
+
var _a;
|
|
159
|
+
let _classDecorators = [struct.packed()];
|
|
160
|
+
let _classDescriptor;
|
|
161
|
+
let _classExtraInitializers = [];
|
|
162
|
+
let _classThis;
|
|
163
|
+
let _classSuper = Extent;
|
|
164
|
+
let _capacity_decorators;
|
|
165
|
+
let _capacity_initializers = [];
|
|
166
|
+
let _capacity_extraInitializers = [];
|
|
167
|
+
var DataExtent = class extends _classSuper {
|
|
168
|
+
static { _classThis = this; }
|
|
169
|
+
static {
|
|
170
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
171
|
+
_capacity_decorators = [(_a = t).uint32.bind(_a)];
|
|
172
|
+
__esDecorate(this, null, _capacity_decorators, { kind: "accessor", name: "capacity", static: false, private: false, access: { has: obj => "capacity" in obj, get: obj => obj.capacity, set: (obj, value) => { obj.capacity = value; } }, metadata: _metadata }, _capacity_initializers, _capacity_extraInitializers);
|
|
173
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
174
|
+
DataExtent = _classThis = _classDescriptor.value;
|
|
175
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
176
|
+
}
|
|
177
|
+
static name = 'sbfs.DataExtent';
|
|
178
|
+
#capacity_accessor_storage = __runInitializers(this, _capacity_initializers, void 0);
|
|
179
|
+
/** Bytes allocated, which can exceed `size` so data can grow in place */
|
|
180
|
+
get capacity() { return this.#capacity_accessor_storage; }
|
|
181
|
+
set capacity(value) { this.#capacity_accessor_storage = value; }
|
|
182
|
+
constructor() {
|
|
183
|
+
super(...arguments);
|
|
184
|
+
__runInitializers(this, _capacity_extraInitializers);
|
|
185
|
+
}
|
|
186
|
+
static {
|
|
187
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
return DataExtent = _classThis;
|
|
191
|
+
})();
|
|
192
|
+
export { DataExtent };
|
|
193
|
+
/** The roots and allocator state written by a transaction */
|
|
194
|
+
let Commit = (() => {
|
|
195
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
196
|
+
let _classDecorators = [struct.packed()];
|
|
197
|
+
let _classDescriptor;
|
|
198
|
+
let _classExtraInitializers = [];
|
|
199
|
+
let _classThis;
|
|
200
|
+
let _classSuper = $from(BufferView);
|
|
201
|
+
let _checksum_decorators;
|
|
202
|
+
let _checksum_initializers = [];
|
|
203
|
+
let _checksum_extraInitializers = [];
|
|
204
|
+
let _generation_decorators;
|
|
205
|
+
let _generation_initializers = [];
|
|
206
|
+
let _generation_extraInitializers = [];
|
|
207
|
+
let _index_root_decorators;
|
|
208
|
+
let _index_root_initializers = [];
|
|
209
|
+
let _index_root_extraInitializers = [];
|
|
210
|
+
let _index_count_decorators;
|
|
211
|
+
let _index_count_initializers = [];
|
|
212
|
+
let _index_count_extraInitializers = [];
|
|
213
|
+
let _free_root_decorators;
|
|
214
|
+
let _free_root_initializers = [];
|
|
215
|
+
let _free_root_extraInitializers = [];
|
|
216
|
+
let _size_root_decorators;
|
|
217
|
+
let _size_root_initializers = [];
|
|
218
|
+
let _size_root_extraInitializers = [];
|
|
219
|
+
let _free_count_decorators;
|
|
220
|
+
let _free_count_initializers = [];
|
|
221
|
+
let _free_count_extraInitializers = [];
|
|
222
|
+
let _free_bytes_decorators;
|
|
223
|
+
let _free_bytes_initializers = [];
|
|
224
|
+
let _free_bytes_extraInitializers = [];
|
|
225
|
+
let _spare_head_decorators;
|
|
226
|
+
let _spare_head_initializers = [];
|
|
227
|
+
let _spare_head_extraInitializers = [];
|
|
228
|
+
let _spare_count_decorators;
|
|
229
|
+
let _spare_count_initializers = [];
|
|
230
|
+
let _spare_count_extraInitializers = [];
|
|
231
|
+
let _spare_total_decorators;
|
|
232
|
+
let _spare_total_initializers = [];
|
|
233
|
+
let _spare_total_extraInitializers = [];
|
|
234
|
+
let _pending_head_decorators;
|
|
235
|
+
let _pending_head_initializers = [];
|
|
236
|
+
let _pending_head_extraInitializers = [];
|
|
237
|
+
let _pending_tail_decorators;
|
|
238
|
+
let _pending_tail_initializers = [];
|
|
239
|
+
let _pending_tail_extraInitializers = [];
|
|
240
|
+
let _pending_bytes_decorators;
|
|
241
|
+
let _pending_bytes_initializers = [];
|
|
242
|
+
let _pending_bytes_extraInitializers = [];
|
|
243
|
+
var Commit = class extends _classSuper {
|
|
244
|
+
static { _classThis = this; }
|
|
245
|
+
static {
|
|
246
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
247
|
+
_checksum_decorators = [(_a = t).uint32.bind(_a)];
|
|
248
|
+
_generation_decorators = [(_b = t).uint64.bind(_b)];
|
|
249
|
+
_index_root_decorators = [(_c = t).uint32.bind(_c)];
|
|
250
|
+
_index_count_decorators = [(_d = t).uint32.bind(_d)];
|
|
251
|
+
_free_root_decorators = [(_e = t).uint32.bind(_e)];
|
|
252
|
+
_size_root_decorators = [(_f = t).uint32.bind(_f)];
|
|
253
|
+
_free_count_decorators = [(_g = t).uint32.bind(_g)];
|
|
254
|
+
_free_bytes_decorators = [(_h = t).uint32.bind(_h)];
|
|
255
|
+
_spare_head_decorators = [(_j = t).uint32.bind(_j)];
|
|
256
|
+
_spare_count_decorators = [(_k = t).uint32.bind(_k)];
|
|
257
|
+
_spare_total_decorators = [(_l = t).uint32.bind(_l)];
|
|
258
|
+
_pending_head_decorators = [(_m = t).uint32.bind(_m)];
|
|
259
|
+
_pending_tail_decorators = [(_o = t).uint32.bind(_o)];
|
|
260
|
+
_pending_bytes_decorators = [(_p = t).uint32.bind(_p)];
|
|
261
|
+
__esDecorate(this, null, _checksum_decorators, { kind: "accessor", name: "checksum", static: false, private: false, access: { has: obj => "checksum" in obj, get: obj => obj.checksum, set: (obj, value) => { obj.checksum = value; } }, metadata: _metadata }, _checksum_initializers, _checksum_extraInitializers);
|
|
262
|
+
__esDecorate(this, null, _generation_decorators, { kind: "accessor", name: "generation", static: false, private: false, access: { has: obj => "generation" in obj, get: obj => obj.generation, set: (obj, value) => { obj.generation = value; } }, metadata: _metadata }, _generation_initializers, _generation_extraInitializers);
|
|
263
|
+
__esDecorate(this, null, _index_root_decorators, { kind: "accessor", name: "index_root", static: false, private: false, access: { has: obj => "index_root" in obj, get: obj => obj.index_root, set: (obj, value) => { obj.index_root = value; } }, metadata: _metadata }, _index_root_initializers, _index_root_extraInitializers);
|
|
264
|
+
__esDecorate(this, null, _index_count_decorators, { kind: "accessor", name: "index_count", static: false, private: false, access: { has: obj => "index_count" in obj, get: obj => obj.index_count, set: (obj, value) => { obj.index_count = value; } }, metadata: _metadata }, _index_count_initializers, _index_count_extraInitializers);
|
|
265
|
+
__esDecorate(this, null, _free_root_decorators, { kind: "accessor", name: "free_root", static: false, private: false, access: { has: obj => "free_root" in obj, get: obj => obj.free_root, set: (obj, value) => { obj.free_root = value; } }, metadata: _metadata }, _free_root_initializers, _free_root_extraInitializers);
|
|
266
|
+
__esDecorate(this, null, _size_root_decorators, { kind: "accessor", name: "size_root", static: false, private: false, access: { has: obj => "size_root" in obj, get: obj => obj.size_root, set: (obj, value) => { obj.size_root = value; } }, metadata: _metadata }, _size_root_initializers, _size_root_extraInitializers);
|
|
267
|
+
__esDecorate(this, null, _free_count_decorators, { kind: "accessor", name: "free_count", static: false, private: false, access: { has: obj => "free_count" in obj, get: obj => obj.free_count, set: (obj, value) => { obj.free_count = value; } }, metadata: _metadata }, _free_count_initializers, _free_count_extraInitializers);
|
|
268
|
+
__esDecorate(this, null, _free_bytes_decorators, { kind: "accessor", name: "free_bytes", static: false, private: false, access: { has: obj => "free_bytes" in obj, get: obj => obj.free_bytes, set: (obj, value) => { obj.free_bytes = value; } }, metadata: _metadata }, _free_bytes_initializers, _free_bytes_extraInitializers);
|
|
269
|
+
__esDecorate(this, null, _spare_head_decorators, { kind: "accessor", name: "spare_head", static: false, private: false, access: { has: obj => "spare_head" in obj, get: obj => obj.spare_head, set: (obj, value) => { obj.spare_head = value; } }, metadata: _metadata }, _spare_head_initializers, _spare_head_extraInitializers);
|
|
270
|
+
__esDecorate(this, null, _spare_count_decorators, { kind: "accessor", name: "spare_count", static: false, private: false, access: { has: obj => "spare_count" in obj, get: obj => obj.spare_count, set: (obj, value) => { obj.spare_count = value; } }, metadata: _metadata }, _spare_count_initializers, _spare_count_extraInitializers);
|
|
271
|
+
__esDecorate(this, null, _spare_total_decorators, { kind: "accessor", name: "spare_total", static: false, private: false, access: { has: obj => "spare_total" in obj, get: obj => obj.spare_total, set: (obj, value) => { obj.spare_total = value; } }, metadata: _metadata }, _spare_total_initializers, _spare_total_extraInitializers);
|
|
272
|
+
__esDecorate(this, null, _pending_head_decorators, { kind: "accessor", name: "pending_head", static: false, private: false, access: { has: obj => "pending_head" in obj, get: obj => obj.pending_head, set: (obj, value) => { obj.pending_head = value; } }, metadata: _metadata }, _pending_head_initializers, _pending_head_extraInitializers);
|
|
273
|
+
__esDecorate(this, null, _pending_tail_decorators, { kind: "accessor", name: "pending_tail", static: false, private: false, access: { has: obj => "pending_tail" in obj, get: obj => obj.pending_tail, set: (obj, value) => { obj.pending_tail = value; } }, metadata: _metadata }, _pending_tail_initializers, _pending_tail_extraInitializers);
|
|
274
|
+
__esDecorate(this, null, _pending_bytes_decorators, { kind: "accessor", name: "pending_bytes", static: false, private: false, access: { has: obj => "pending_bytes" in obj, get: obj => obj.pending_bytes, set: (obj, value) => { obj.pending_bytes = value; } }, metadata: _metadata }, _pending_bytes_initializers, _pending_bytes_extraInitializers);
|
|
275
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
276
|
+
Commit = _classThis = _classDescriptor.value;
|
|
277
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
278
|
+
}
|
|
279
|
+
static name = 'sbfs.Commit';
|
|
280
|
+
#checksum_accessor_storage = __runInitializers(this, _checksum_initializers, void 0);
|
|
281
|
+
/** crc32c of the rest of the commit */
|
|
282
|
+
get checksum() { return this.#checksum_accessor_storage; }
|
|
283
|
+
set checksum(value) { this.#checksum_accessor_storage = value; }
|
|
284
|
+
#generation_accessor_storage = (__runInitializers(this, _checksum_extraInitializers), __runInitializers(this, _generation_initializers, void 0));
|
|
285
|
+
get generation() { return this.#generation_accessor_storage; }
|
|
286
|
+
set generation(value) { this.#generation_accessor_storage = value; }
|
|
287
|
+
#index_root_accessor_storage = (__runInitializers(this, _generation_extraInitializers), __runInitializers(this, _index_root_initializers, void 0));
|
|
288
|
+
/** ID to extent */
|
|
289
|
+
get index_root() { return this.#index_root_accessor_storage; }
|
|
290
|
+
set index_root(value) { this.#index_root_accessor_storage = value; }
|
|
291
|
+
#index_count_accessor_storage = (__runInitializers(this, _index_root_extraInitializers), __runInitializers(this, _index_count_initializers, void 0));
|
|
292
|
+
get index_count() { return this.#index_count_accessor_storage; }
|
|
293
|
+
set index_count(value) { this.#index_count_accessor_storage = value; }
|
|
294
|
+
#free_root_accessor_storage = (__runInitializers(this, _index_count_extraInitializers), __runInitializers(this, _free_root_initializers, void 0));
|
|
295
|
+
/** Free extents by offset */
|
|
296
|
+
get free_root() { return this.#free_root_accessor_storage; }
|
|
297
|
+
set free_root(value) { this.#free_root_accessor_storage = value; }
|
|
298
|
+
#size_root_accessor_storage = (__runInitializers(this, _free_root_extraInitializers), __runInitializers(this, _size_root_initializers, void 0));
|
|
299
|
+
/** Free extents by size then offset */
|
|
300
|
+
get size_root() { return this.#size_root_accessor_storage; }
|
|
301
|
+
set size_root(value) { this.#size_root_accessor_storage = value; }
|
|
302
|
+
#free_count_accessor_storage = (__runInitializers(this, _size_root_extraInitializers), __runInitializers(this, _free_count_initializers, void 0));
|
|
303
|
+
get free_count() { return this.#free_count_accessor_storage; }
|
|
304
|
+
set free_count(value) { this.#free_count_accessor_storage = value; }
|
|
305
|
+
#free_bytes_accessor_storage = (__runInitializers(this, _free_count_extraInitializers), __runInitializers(this, _free_bytes_initializers, void 0));
|
|
306
|
+
get free_bytes() { return this.#free_bytes_accessor_storage; }
|
|
307
|
+
set free_bytes(value) { this.#free_bytes_accessor_storage = value; }
|
|
308
|
+
#spare_head_accessor_storage = (__runInitializers(this, _free_bytes_extraInitializers), __runInitializers(this, _spare_head_initializers, void 0));
|
|
309
|
+
/** The newest block in the list of spare blocks for tree nodes */
|
|
310
|
+
get spare_head() { return this.#spare_head_accessor_storage; }
|
|
311
|
+
set spare_head(value) { this.#spare_head_accessor_storage = value; }
|
|
312
|
+
#spare_count_accessor_storage = (__runInitializers(this, _spare_head_extraInitializers), __runInitializers(this, _spare_count_initializers, void 0));
|
|
313
|
+
/** Spare blocks listed by `spare_head` */
|
|
314
|
+
get spare_count() { return this.#spare_count_accessor_storage; }
|
|
315
|
+
set spare_count(value) { this.#spare_count_accessor_storage = value; }
|
|
316
|
+
#spare_total_accessor_storage = (__runInitializers(this, _spare_count_extraInitializers), __runInitializers(this, _spare_total_initializers, void 0));
|
|
317
|
+
/** Spare blocks in the entire list */
|
|
318
|
+
get spare_total() { return this.#spare_total_accessor_storage; }
|
|
319
|
+
set spare_total(value) { this.#spare_total_accessor_storage = value; }
|
|
320
|
+
#pending_head_accessor_storage = (__runInitializers(this, _spare_total_extraInitializers), __runInitializers(this, _pending_head_initializers, void 0));
|
|
321
|
+
/** Blocks listing extents that are free once no reader can see them */
|
|
322
|
+
get pending_head() { return this.#pending_head_accessor_storage; }
|
|
323
|
+
set pending_head(value) { this.#pending_head_accessor_storage = value; }
|
|
324
|
+
#pending_tail_accessor_storage = (__runInitializers(this, _pending_head_extraInitializers), __runInitializers(this, _pending_tail_initializers, void 0));
|
|
325
|
+
get pending_tail() { return this.#pending_tail_accessor_storage; }
|
|
326
|
+
set pending_tail(value) { this.#pending_tail_accessor_storage = value; }
|
|
327
|
+
#pending_bytes_accessor_storage = (__runInitializers(this, _pending_tail_extraInitializers), __runInitializers(this, _pending_bytes_initializers, void 0));
|
|
328
|
+
get pending_bytes() { return this.#pending_bytes_accessor_storage; }
|
|
329
|
+
set pending_bytes(value) { this.#pending_bytes_accessor_storage = value; }
|
|
330
|
+
computeChecksum() {
|
|
331
|
+
return crc32c(new Uint8Array(this.buffer, this.byteOffset + 4, sizeof(Commit) - 4));
|
|
332
|
+
}
|
|
333
|
+
update() {
|
|
334
|
+
this.checksum = this.computeChecksum();
|
|
335
|
+
}
|
|
336
|
+
isValid(generation) {
|
|
337
|
+
return this.generation === generation && this.checksum == this.computeChecksum();
|
|
338
|
+
}
|
|
339
|
+
constructor() {
|
|
340
|
+
super(...arguments);
|
|
341
|
+
__runInitializers(this, _pending_bytes_extraInitializers);
|
|
342
|
+
}
|
|
343
|
+
static {
|
|
344
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
return Commit = _classThis;
|
|
348
|
+
})();
|
|
349
|
+
export { Commit };
|
|
350
|
+
/** State shared by every thread using a file system, which is followed by an epoch table */
|
|
351
|
+
let State = (() => {
|
|
352
|
+
var _a, _b, _c;
|
|
353
|
+
let _classDecorators = [struct.packed()];
|
|
354
|
+
let _classDescriptor;
|
|
355
|
+
let _classExtraInitializers = [];
|
|
356
|
+
let _classThis;
|
|
357
|
+
let _classSuper = $from(BufferView);
|
|
358
|
+
let _lock_decorators;
|
|
359
|
+
let _lock_initializers = [];
|
|
360
|
+
let _lock_extraInitializers = [];
|
|
361
|
+
let _generation_decorators;
|
|
362
|
+
let _generation_initializers = [];
|
|
363
|
+
let _generation_extraInitializers = [];
|
|
364
|
+
let _next_id_decorators;
|
|
365
|
+
let _next_id_initializers = [];
|
|
366
|
+
let _next_id_extraInitializers = [];
|
|
367
|
+
let _commits_decorators;
|
|
368
|
+
let _commits_initializers = [];
|
|
369
|
+
let _commits_extraInitializers = [];
|
|
370
|
+
var State = class extends _classSuper {
|
|
371
|
+
static { _classThis = this; }
|
|
372
|
+
static {
|
|
373
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
374
|
+
_lock_decorators = [(_a = t).uint64.bind(_a)];
|
|
375
|
+
_generation_decorators = [(_b = t).uint64.bind(_b)];
|
|
376
|
+
_next_id_decorators = [(_c = t).uint64.bind(_c)];
|
|
377
|
+
_commits_decorators = [field(array(Commit, 2))];
|
|
378
|
+
__esDecorate(this, null, _lock_decorators, { kind: "accessor", name: "lock", static: false, private: false, access: { has: obj => "lock" in obj, get: obj => obj.lock, set: (obj, value) => { obj.lock = value; } }, metadata: _metadata }, _lock_initializers, _lock_extraInitializers);
|
|
379
|
+
__esDecorate(this, null, _generation_decorators, { kind: "accessor", name: "generation", static: false, private: false, access: { has: obj => "generation" in obj, get: obj => obj.generation, set: (obj, value) => { obj.generation = value; } }, metadata: _metadata }, _generation_initializers, _generation_extraInitializers);
|
|
380
|
+
__esDecorate(this, null, _next_id_decorators, { kind: "accessor", name: "next_id", static: false, private: false, access: { has: obj => "next_id" in obj, get: obj => obj.next_id, set: (obj, value) => { obj.next_id = value; } }, metadata: _metadata }, _next_id_initializers, _next_id_extraInitializers);
|
|
381
|
+
__esDecorate(this, null, _commits_decorators, { kind: "accessor", name: "commits", static: false, private: false, access: { has: obj => "commits" in obj, get: obj => obj.commits, set: (obj, value) => { obj.commits = value; } }, metadata: _metadata }, _commits_initializers, _commits_extraInitializers);
|
|
382
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
383
|
+
State = _classThis = _classDescriptor.value;
|
|
384
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
385
|
+
}
|
|
386
|
+
static name = 'sbfs.State';
|
|
387
|
+
#lock_accessor_storage = __runInitializers(this, _lock_initializers, void 0);
|
|
388
|
+
/** Held by writers */
|
|
389
|
+
get lock() { return this.#lock_accessor_storage; }
|
|
390
|
+
set lock(value) { this.#lock_accessor_storage = value; }
|
|
391
|
+
#generation_accessor_storage = (__runInitializers(this, _lock_extraInitializers), __runInitializers(this, _generation_initializers, void 0));
|
|
392
|
+
/** The generation of the current commit */
|
|
393
|
+
get generation() { return this.#generation_accessor_storage; }
|
|
394
|
+
set generation(value) { this.#generation_accessor_storage = value; }
|
|
395
|
+
#next_id_accessor_storage = (__runInitializers(this, _generation_extraInitializers), __runInitializers(this, _next_id_initializers, void 0));
|
|
396
|
+
get next_id() { return this.#next_id_accessor_storage; }
|
|
397
|
+
set next_id(value) { this.#next_id_accessor_storage = value; }
|
|
398
|
+
#commits_accessor_storage = (__runInitializers(this, _next_id_extraInitializers), __runInitializers(this, _commits_initializers, void 0));
|
|
399
|
+
/** The current and previous commits, at their generation modulo 2 */
|
|
400
|
+
get commits() { return this.#commits_accessor_storage; }
|
|
401
|
+
set commits(value) { this.#commits_accessor_storage = value; }
|
|
402
|
+
constructor() {
|
|
403
|
+
super(...arguments);
|
|
404
|
+
__runInitializers(this, _commits_extraInitializers);
|
|
405
|
+
}
|
|
406
|
+
static {
|
|
407
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
return State = _classThis;
|
|
411
|
+
})();
|
|
412
|
+
export { State };
|
|
413
|
+
/** The start of a block listing extents retired by a generation, which is followed by the extents */
|
|
414
|
+
let PendingHeader = (() => {
|
|
415
|
+
var _a, _b, _c;
|
|
416
|
+
let _classDecorators = [struct.packed()];
|
|
417
|
+
let _classDescriptor;
|
|
418
|
+
let _classExtraInitializers = [];
|
|
419
|
+
let _classThis;
|
|
420
|
+
let _classSuper = $from(BufferView);
|
|
421
|
+
let _next_decorators;
|
|
422
|
+
let _next_initializers = [];
|
|
423
|
+
let _next_extraInitializers = [];
|
|
424
|
+
let _count_decorators;
|
|
425
|
+
let _count_initializers = [];
|
|
426
|
+
let _count_extraInitializers = [];
|
|
427
|
+
let _generation_decorators;
|
|
428
|
+
let _generation_initializers = [];
|
|
429
|
+
let _generation_extraInitializers = [];
|
|
430
|
+
var PendingHeader = class extends _classSuper {
|
|
431
|
+
static { _classThis = this; }
|
|
432
|
+
static {
|
|
433
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
434
|
+
_next_decorators = [(_a = t).uint32.bind(_a)];
|
|
435
|
+
_count_decorators = [(_b = t).uint32.bind(_b)];
|
|
436
|
+
_generation_decorators = [(_c = t).uint64.bind(_c)];
|
|
437
|
+
__esDecorate(this, null, _next_decorators, { kind: "accessor", name: "next", static: false, private: false, access: { has: obj => "next" in obj, get: obj => obj.next, set: (obj, value) => { obj.next = value; } }, metadata: _metadata }, _next_initializers, _next_extraInitializers);
|
|
438
|
+
__esDecorate(this, null, _count_decorators, { kind: "accessor", name: "count", static: false, private: false, access: { has: obj => "count" in obj, get: obj => obj.count, set: (obj, value) => { obj.count = value; } }, metadata: _metadata }, _count_initializers, _count_extraInitializers);
|
|
439
|
+
__esDecorate(this, null, _generation_decorators, { kind: "accessor", name: "generation", static: false, private: false, access: { has: obj => "generation" in obj, get: obj => obj.generation, set: (obj, value) => { obj.generation = value; } }, metadata: _metadata }, _generation_initializers, _generation_extraInitializers);
|
|
440
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
441
|
+
PendingHeader = _classThis = _classDescriptor.value;
|
|
442
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
443
|
+
}
|
|
444
|
+
static name = 'sbfs.PendingHeader';
|
|
445
|
+
#next_accessor_storage = __runInitializers(this, _next_initializers, void 0);
|
|
446
|
+
get next() { return this.#next_accessor_storage; }
|
|
447
|
+
set next(value) { this.#next_accessor_storage = value; }
|
|
448
|
+
#count_accessor_storage = (__runInitializers(this, _next_extraInitializers), __runInitializers(this, _count_initializers, void 0));
|
|
449
|
+
get count() { return this.#count_accessor_storage; }
|
|
450
|
+
set count(value) { this.#count_accessor_storage = value; }
|
|
451
|
+
#generation_accessor_storage = (__runInitializers(this, _count_extraInitializers), __runInitializers(this, _generation_initializers, void 0));
|
|
452
|
+
get generation() { return this.#generation_accessor_storage; }
|
|
453
|
+
set generation(value) { this.#generation_accessor_storage = value; }
|
|
454
|
+
constructor() {
|
|
455
|
+
super(...arguments);
|
|
456
|
+
__runInitializers(this, _generation_extraInitializers);
|
|
457
|
+
}
|
|
458
|
+
static {
|
|
459
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
460
|
+
}
|
|
461
|
+
};
|
|
462
|
+
return PendingHeader = _classThis;
|
|
463
|
+
})();
|
|
464
|
+
export { PendingHeader };
|
|
465
|
+
/**
|
|
466
|
+
* The start of a block listing spare blocks, which is followed by their offsets.
|
|
467
|
+
* The newest block's count is in the commit instead.
|
|
468
|
+
*/
|
|
469
|
+
let SpareHeader = (() => {
|
|
470
|
+
var _a, _b;
|
|
471
|
+
let _classDecorators = [struct.packed()];
|
|
472
|
+
let _classDescriptor;
|
|
473
|
+
let _classExtraInitializers = [];
|
|
474
|
+
let _classThis;
|
|
475
|
+
let _classSuper = $from(BufferView);
|
|
476
|
+
let _next_decorators;
|
|
477
|
+
let _next_initializers = [];
|
|
478
|
+
let _next_extraInitializers = [];
|
|
479
|
+
let _count_decorators;
|
|
480
|
+
let _count_initializers = [];
|
|
481
|
+
let _count_extraInitializers = [];
|
|
482
|
+
var SpareHeader = class extends _classSuper {
|
|
483
|
+
static { _classThis = this; }
|
|
484
|
+
static {
|
|
485
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
486
|
+
_next_decorators = [(_a = t).uint32.bind(_a)];
|
|
487
|
+
_count_decorators = [(_b = t).uint32.bind(_b)];
|
|
488
|
+
__esDecorate(this, null, _next_decorators, { kind: "accessor", name: "next", static: false, private: false, access: { has: obj => "next" in obj, get: obj => obj.next, set: (obj, value) => { obj.next = value; } }, metadata: _metadata }, _next_initializers, _next_extraInitializers);
|
|
489
|
+
__esDecorate(this, null, _count_decorators, { kind: "accessor", name: "count", static: false, private: false, access: { has: obj => "count" in obj, get: obj => obj.count, set: (obj, value) => { obj.count = value; } }, metadata: _metadata }, _count_initializers, _count_extraInitializers);
|
|
490
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
491
|
+
SpareHeader = _classThis = _classDescriptor.value;
|
|
492
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
493
|
+
}
|
|
494
|
+
static name = 'sbfs.SpareHeader';
|
|
495
|
+
#next_accessor_storage = __runInitializers(this, _next_initializers, void 0);
|
|
496
|
+
get next() { return this.#next_accessor_storage; }
|
|
497
|
+
set next(value) { this.#next_accessor_storage = value; }
|
|
498
|
+
#count_accessor_storage = (__runInitializers(this, _next_extraInitializers), __runInitializers(this, _count_initializers, void 0));
|
|
499
|
+
get count() { return this.#count_accessor_storage; }
|
|
500
|
+
set count(value) { this.#count_accessor_storage = value; }
|
|
501
|
+
constructor() {
|
|
502
|
+
super(...arguments);
|
|
503
|
+
__runInitializers(this, _count_extraInitializers);
|
|
504
|
+
}
|
|
505
|
+
static {
|
|
506
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
507
|
+
}
|
|
508
|
+
};
|
|
509
|
+
return SpareHeader = _classThis;
|
|
510
|
+
})();
|
|
511
|
+
export { SpareHeader };
|
|
512
|
+
/**
|
|
513
|
+
* The super block for version 2 of the single-buffer format.
|
|
514
|
+
* Bytes 0 through 12 have the same layout in every version.
|
|
515
|
+
*/
|
|
516
|
+
let SuperBlock = (() => {
|
|
517
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
518
|
+
let _classDecorators = [struct.packed()];
|
|
519
|
+
let _classDescriptor;
|
|
520
|
+
let _classExtraInitializers = [];
|
|
521
|
+
let _classThis;
|
|
522
|
+
let _classSuper = $from(BufferView);
|
|
523
|
+
let _checksum_decorators;
|
|
524
|
+
let _checksum_initializers = [];
|
|
525
|
+
let _checksum_extraInitializers = [];
|
|
526
|
+
let _magic_decorators;
|
|
527
|
+
let _magic_initializers = [];
|
|
528
|
+
let _magic_extraInitializers = [];
|
|
529
|
+
let _version_decorators;
|
|
530
|
+
let _version_initializers = [];
|
|
531
|
+
let _version_extraInitializers = [];
|
|
532
|
+
let _inode_format_decorators;
|
|
533
|
+
let _inode_format_initializers = [];
|
|
534
|
+
let _inode_format_extraInitializers = [];
|
|
535
|
+
let _required_features_decorators;
|
|
536
|
+
let _required_features_initializers = [];
|
|
537
|
+
let _required_features_extraInitializers = [];
|
|
538
|
+
let _optional_features_decorators;
|
|
539
|
+
let _optional_features_initializers = [];
|
|
540
|
+
let _optional_features_extraInitializers = [];
|
|
541
|
+
let _block_size_decorators;
|
|
542
|
+
let _block_size_initializers = [];
|
|
543
|
+
let _block_size_extraInitializers = [];
|
|
544
|
+
let _total_bytes_decorators;
|
|
545
|
+
let _total_bytes_initializers = [];
|
|
546
|
+
let _total_bytes_extraInitializers = [];
|
|
547
|
+
let _uuid_decorators;
|
|
548
|
+
let _uuid_initializers = [];
|
|
549
|
+
let _uuid_extraInitializers = [];
|
|
550
|
+
let _state_offset_decorators;
|
|
551
|
+
let _state_offset_initializers = [];
|
|
552
|
+
let _state_offset_extraInitializers = [];
|
|
553
|
+
let _epoch_slots_decorators;
|
|
554
|
+
let _epoch_slots_initializers = [];
|
|
555
|
+
let _epoch_slots_extraInitializers = [];
|
|
556
|
+
let _label_decorators;
|
|
557
|
+
let _label_initializers = [];
|
|
558
|
+
let _label_extraInitializers = [];
|
|
559
|
+
let __padding_decorators;
|
|
560
|
+
let __padding_initializers = [];
|
|
561
|
+
let __padding_extraInitializers = [];
|
|
562
|
+
let _lock_decorators;
|
|
563
|
+
let _lock_initializers = [];
|
|
564
|
+
let _lock_extraInitializers = [];
|
|
565
|
+
var SuperBlock = class extends _classSuper {
|
|
566
|
+
static { _classThis = this; }
|
|
567
|
+
static {
|
|
568
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
569
|
+
_checksum_decorators = [(_a = t).uint32.bind(_a)];
|
|
570
|
+
_magic_decorators = [(_b = t).uint32.bind(_b)];
|
|
571
|
+
_version_decorators = [(_c = t).uint16.bind(_c)];
|
|
572
|
+
_inode_format_decorators = [(_d = t).uint16.bind(_d)];
|
|
573
|
+
_required_features_decorators = [(_e = t).uint32.bind(_e)];
|
|
574
|
+
_optional_features_decorators = [(_f = t).uint32.bind(_f)];
|
|
575
|
+
_block_size_decorators = [(_g = t).uint32.bind(_g)];
|
|
576
|
+
_total_bytes_decorators = [(_h = t).uint64.bind(_h)];
|
|
577
|
+
_uuid_decorators = [t.uint8(16)];
|
|
578
|
+
_state_offset_decorators = [(_j = t).uint32.bind(_j)];
|
|
579
|
+
_epoch_slots_decorators = [(_k = t).uint32.bind(_k)];
|
|
580
|
+
_label_decorators = [t.char(64)];
|
|
581
|
+
__padding_decorators = [t.char(128)];
|
|
582
|
+
_lock_decorators = [(_l = t).uint64.bind(_l)];
|
|
583
|
+
__esDecorate(this, null, _checksum_decorators, { kind: "accessor", name: "checksum", static: false, private: false, access: { has: obj => "checksum" in obj, get: obj => obj.checksum, set: (obj, value) => { obj.checksum = value; } }, metadata: _metadata }, _checksum_initializers, _checksum_extraInitializers);
|
|
584
|
+
__esDecorate(this, null, _magic_decorators, { kind: "accessor", name: "magic", static: false, private: false, access: { has: obj => "magic" in obj, get: obj => obj.magic, set: (obj, value) => { obj.magic = value; } }, metadata: _metadata }, _magic_initializers, _magic_extraInitializers);
|
|
585
|
+
__esDecorate(this, null, _version_decorators, { kind: "accessor", name: "version", static: false, private: false, access: { has: obj => "version" in obj, get: obj => obj.version, set: (obj, value) => { obj.version = value; } }, metadata: _metadata }, _version_initializers, _version_extraInitializers);
|
|
586
|
+
__esDecorate(this, null, _inode_format_decorators, { kind: "accessor", name: "inode_format", static: false, private: false, access: { has: obj => "inode_format" in obj, get: obj => obj.inode_format, set: (obj, value) => { obj.inode_format = value; } }, metadata: _metadata }, _inode_format_initializers, _inode_format_extraInitializers);
|
|
587
|
+
__esDecorate(this, null, _required_features_decorators, { kind: "accessor", name: "required_features", static: false, private: false, access: { has: obj => "required_features" in obj, get: obj => obj.required_features, set: (obj, value) => { obj.required_features = value; } }, metadata: _metadata }, _required_features_initializers, _required_features_extraInitializers);
|
|
588
|
+
__esDecorate(this, null, _optional_features_decorators, { kind: "accessor", name: "optional_features", static: false, private: false, access: { has: obj => "optional_features" in obj, get: obj => obj.optional_features, set: (obj, value) => { obj.optional_features = value; } }, metadata: _metadata }, _optional_features_initializers, _optional_features_extraInitializers);
|
|
589
|
+
__esDecorate(this, null, _block_size_decorators, { kind: "accessor", name: "block_size", static: false, private: false, access: { has: obj => "block_size" in obj, get: obj => obj.block_size, set: (obj, value) => { obj.block_size = value; } }, metadata: _metadata }, _block_size_initializers, _block_size_extraInitializers);
|
|
590
|
+
__esDecorate(this, null, _total_bytes_decorators, { kind: "accessor", name: "total_bytes", static: false, private: false, access: { has: obj => "total_bytes" in obj, get: obj => obj.total_bytes, set: (obj, value) => { obj.total_bytes = value; } }, metadata: _metadata }, _total_bytes_initializers, _total_bytes_extraInitializers);
|
|
591
|
+
__esDecorate(this, null, _uuid_decorators, { kind: "accessor", name: "uuid", static: false, private: false, access: { has: obj => "uuid" in obj, get: obj => obj.uuid, set: (obj, value) => { obj.uuid = value; } }, metadata: _metadata }, _uuid_initializers, _uuid_extraInitializers);
|
|
592
|
+
__esDecorate(this, null, _state_offset_decorators, { kind: "accessor", name: "state_offset", static: false, private: false, access: { has: obj => "state_offset" in obj, get: obj => obj.state_offset, set: (obj, value) => { obj.state_offset = value; } }, metadata: _metadata }, _state_offset_initializers, _state_offset_extraInitializers);
|
|
593
|
+
__esDecorate(this, null, _epoch_slots_decorators, { kind: "accessor", name: "epoch_slots", static: false, private: false, access: { has: obj => "epoch_slots" in obj, get: obj => obj.epoch_slots, set: (obj, value) => { obj.epoch_slots = value; } }, metadata: _metadata }, _epoch_slots_initializers, _epoch_slots_extraInitializers);
|
|
594
|
+
__esDecorate(this, null, _label_decorators, { kind: "accessor", name: "label", static: false, private: false, access: { has: obj => "label" in obj, get: obj => obj.label, set: (obj, value) => { obj.label = value; } }, metadata: _metadata }, _label_initializers, _label_extraInitializers);
|
|
595
|
+
__esDecorate(this, null, __padding_decorators, { kind: "accessor", name: "_padding", static: false, private: false, access: { has: obj => "_padding" in obj, get: obj => obj._padding, set: (obj, value) => { obj._padding = value; } }, metadata: _metadata }, __padding_initializers, __padding_extraInitializers);
|
|
596
|
+
__esDecorate(this, null, _lock_decorators, { kind: "accessor", name: "lock", static: false, private: false, access: { has: obj => "lock" in obj, get: obj => obj.lock, set: (obj, value) => { obj.lock = value; } }, metadata: _metadata }, _lock_initializers, _lock_extraInitializers);
|
|
597
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
598
|
+
SuperBlock = _classThis = _classDescriptor.value;
|
|
599
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
600
|
+
}
|
|
601
|
+
static name = 'SuperBlockV2';
|
|
602
|
+
#checksum_accessor_storage = __runInitializers(this, _checksum_initializers, void 0);
|
|
603
|
+
/** crc32c of the bytes from 4 up to `lock` */
|
|
604
|
+
get checksum() { return this.#checksum_accessor_storage; }
|
|
605
|
+
set checksum(value) { this.#checksum_accessor_storage = value; }
|
|
606
|
+
#magic_accessor_storage = (__runInitializers(this, _checksum_extraInitializers), __runInitializers(this, _magic_initializers, void 0));
|
|
607
|
+
get magic() { return this.#magic_accessor_storage; }
|
|
608
|
+
set magic(value) { this.#magic_accessor_storage = value; }
|
|
609
|
+
#version_accessor_storage = (__runInitializers(this, _magic_extraInitializers), __runInitializers(this, _version_initializers, void 0));
|
|
610
|
+
/**
|
|
611
|
+
* The version of the on-disk format
|
|
612
|
+
* 1: v1.10.0+, append-only metadata blocks
|
|
613
|
+
* 2: copy-on-write B+ trees
|
|
614
|
+
*/
|
|
615
|
+
get version() { return this.#version_accessor_storage; }
|
|
616
|
+
set version(value) { this.#version_accessor_storage = value; }
|
|
617
|
+
#inode_format_accessor_storage = (__runInitializers(this, _version_extraInitializers), __runInitializers(this, _inode_format_initializers, void 0));
|
|
618
|
+
/** Which format of `Inode` is used */
|
|
619
|
+
get inode_format() { return this.#inode_format_accessor_storage; }
|
|
620
|
+
set inode_format(value) { this.#inode_format_accessor_storage = value; }
|
|
621
|
+
#required_features_accessor_storage = (__runInitializers(this, _inode_format_extraInitializers), __runInitializers(this, _required_features_initializers, void 0));
|
|
622
|
+
/** Features that must be supported to mount the file system. None are defined. */
|
|
623
|
+
get required_features() { return this.#required_features_accessor_storage; }
|
|
624
|
+
set required_features(value) { this.#required_features_accessor_storage = value; }
|
|
625
|
+
#optional_features_accessor_storage = (__runInitializers(this, _required_features_extraInitializers), __runInitializers(this, _optional_features_initializers, void 0));
|
|
626
|
+
/** Features that may be ignored. None are defined. */
|
|
627
|
+
get optional_features() { return this.#optional_features_accessor_storage; }
|
|
628
|
+
set optional_features(value) { this.#optional_features_accessor_storage = value; }
|
|
629
|
+
#block_size_accessor_storage = (__runInitializers(this, _optional_features_extraInitializers), __runInitializers(this, _block_size_initializers, void 0));
|
|
630
|
+
/** Size of tree nodes and other metadata blocks */
|
|
631
|
+
get block_size() { return this.#block_size_accessor_storage; }
|
|
632
|
+
set block_size(value) { this.#block_size_accessor_storage = value; }
|
|
633
|
+
#total_bytes_accessor_storage = (__runInitializers(this, _block_size_extraInitializers), __runInitializers(this, _total_bytes_initializers, void 0));
|
|
634
|
+
/** The size of the entire file system, including the super block */
|
|
635
|
+
get total_bytes() { return this.#total_bytes_accessor_storage; }
|
|
636
|
+
set total_bytes(value) { this.#total_bytes_accessor_storage = value; }
|
|
637
|
+
#uuid_accessor_storage = (__runInitializers(this, _total_bytes_extraInitializers), __runInitializers(this, _uuid_initializers, void 0));
|
|
638
|
+
get uuid() { return this.#uuid_accessor_storage; }
|
|
639
|
+
set uuid(value) { this.#uuid_accessor_storage = value; }
|
|
640
|
+
#state_offset_accessor_storage = (__runInitializers(this, _uuid_extraInitializers), __runInitializers(this, _state_offset_initializers, void 0));
|
|
641
|
+
/** Byte offset of the shared state */
|
|
642
|
+
get state_offset() { return this.#state_offset_accessor_storage; }
|
|
643
|
+
set state_offset(value) { this.#state_offset_accessor_storage = value; }
|
|
644
|
+
#epoch_slots_accessor_storage = (__runInitializers(this, _state_offset_extraInitializers), __runInitializers(this, _epoch_slots_initializers, void 0));
|
|
645
|
+
get epoch_slots() { return this.#epoch_slots_accessor_storage; }
|
|
646
|
+
set epoch_slots(value) { this.#epoch_slots_accessor_storage = value; }
|
|
647
|
+
#label_accessor_storage = (__runInitializers(this, _epoch_slots_extraInitializers), __runInitializers(this, _label_initializers, void 0));
|
|
648
|
+
/** An optional label for the file system */
|
|
649
|
+
get label() { return this.#label_accessor_storage; }
|
|
650
|
+
set label(value) { this.#label_accessor_storage = value; }
|
|
651
|
+
#_padding_accessor_storage = (__runInitializers(this, _label_extraInitializers), __runInitializers(this, __padding_initializers, void 0));
|
|
652
|
+
get _padding() { return this.#_padding_accessor_storage; }
|
|
653
|
+
set _padding(value) { this.#_padding_accessor_storage = value; }
|
|
654
|
+
#lock_accessor_storage = (__runInitializers(this, __padding_extraInitializers), __runInitializers(this, _lock_initializers, void 0));
|
|
655
|
+
/** Held while the file system is created or upgraded. Not covered by the checksum. */
|
|
656
|
+
get lock() { return this.#lock_accessor_storage; }
|
|
657
|
+
set lock(value) { this.#lock_accessor_storage = value; }
|
|
658
|
+
computeChecksum() {
|
|
659
|
+
return crc32c(new Uint8Array(this.buffer, this.byteOffset + 4, offsetof(SuperBlock, 'lock') - 4));
|
|
660
|
+
}
|
|
661
|
+
update() {
|
|
662
|
+
this.checksum = this.computeChecksum();
|
|
663
|
+
}
|
|
664
|
+
/** Checks that a file system of `byteLength` bytes can be mounted using this super block */
|
|
665
|
+
validate(byteLength) {
|
|
666
|
+
const { block_size } = this;
|
|
667
|
+
if (this.version != 2)
|
|
668
|
+
throw crit(withErrno('EIO', `sbfs: unsupported version ${this.version}`));
|
|
669
|
+
if (this.checksum != this.computeChecksum())
|
|
670
|
+
throw crit(withErrno('EIO', 'sbfs: checksum mismatch for super block'));
|
|
671
|
+
if (this.required_features)
|
|
672
|
+
throw crit(withErrno('EIO', `sbfs: unsupported features 0x${this.required_features.toString(16)}`));
|
|
673
|
+
if (this.inode_format != _inode_version)
|
|
674
|
+
throw crit(withErrno('EIO', 'sbfs: inode format mismatch'));
|
|
675
|
+
if (this.total_bytes > BigInt(Math.min(byteLength, max_size)))
|
|
676
|
+
throw crit(withErrno('EIO', 'sbfs: buffer is smaller than the file system'));
|
|
677
|
+
if (block_size < 512 || block_size > 0x10000 || block_size & (block_size - 1))
|
|
678
|
+
throw crit(withErrno('EIO', `sbfs: invalid block size ${block_size}`));
|
|
679
|
+
if (!this.epoch_slots)
|
|
680
|
+
throw crit(withErrno('EIO', 'sbfs: no epoch slots'));
|
|
681
|
+
if ((this.byteOffset + this.state_offset) % 8)
|
|
682
|
+
throw crit(withErrno('EIO', 'sbfs: misaligned shared state'));
|
|
683
|
+
}
|
|
684
|
+
constructor() {
|
|
685
|
+
super(...arguments);
|
|
686
|
+
__runInitializers(this, _lock_extraInitializers);
|
|
687
|
+
}
|
|
688
|
+
static {
|
|
689
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
return SuperBlock = _classThis;
|
|
693
|
+
})();
|
|
694
|
+
export { SuperBlock };
|
|
695
|
+
/** Key for the free tree ordered by size */
|
|
696
|
+
const sizeKey = (size, offset) => (BigInt(size) << 32n) | BigInt(offset);
|
|
697
|
+
/** Thrown when the free trees need more blocks than there are spares */
|
|
698
|
+
const sparesExhausted = withErrno('ENOSPC', 'sbfs: no spare blocks');
|
|
699
|
+
/**
|
|
700
|
+
* A transaction that changes a file system, which is built from copies of the blocks it changes.
|
|
701
|
+
* Nothing it does is visible until it is committed.
|
|
702
|
+
*/
|
|
703
|
+
export class WriteTransaction {
|
|
704
|
+
store;
|
|
705
|
+
spareScale;
|
|
706
|
+
buffer;
|
|
707
|
+
pageSize;
|
|
708
|
+
generation;
|
|
709
|
+
/** ID to extent */
|
|
710
|
+
index;
|
|
711
|
+
/** Free extents by offset */
|
|
712
|
+
byOffset;
|
|
713
|
+
/** Free extents by size then offset */
|
|
714
|
+
bySize;
|
|
715
|
+
freeBytes;
|
|
716
|
+
spareHead;
|
|
717
|
+
spareCount;
|
|
718
|
+
spareTotal;
|
|
719
|
+
/** Spare blocks listed by the base commit in the newest list block, which can not be overwritten */
|
|
720
|
+
spareFloor;
|
|
721
|
+
spareCapacity;
|
|
722
|
+
pendingHead;
|
|
723
|
+
pendingTail;
|
|
724
|
+
pendingBytes;
|
|
725
|
+
/** Blocks allocated by this transaction */
|
|
726
|
+
fresh = new Set();
|
|
727
|
+
/** Blocks no commit references, which can be reused immediately */
|
|
728
|
+
recycled = [];
|
|
729
|
+
/** Extents that become free once no reader can see them */
|
|
730
|
+
retired = [];
|
|
731
|
+
/** Whether the free trees are being changed, during which spares are not refilled */
|
|
732
|
+
changingFreeTrees = false;
|
|
733
|
+
/**
|
|
734
|
+
* @param base The commit this transaction starts from
|
|
735
|
+
* @param spareScale Multiplies the number of spare blocks to keep
|
|
736
|
+
*/
|
|
737
|
+
constructor(store, base, spareScale) {
|
|
738
|
+
this.store = store;
|
|
739
|
+
this.spareScale = spareScale;
|
|
740
|
+
this.buffer = store.buffer;
|
|
741
|
+
this.pageSize = store.blockSize;
|
|
742
|
+
this.generation = base.generation + 1n;
|
|
743
|
+
this.freeBytes = base.free_bytes;
|
|
744
|
+
this.spareHead = base.spare_head;
|
|
745
|
+
this.spareCount = this.spareFloor = base.spare_count;
|
|
746
|
+
this.spareTotal = base.spare_total;
|
|
747
|
+
this.spareCapacity = (this.pageSize - sizeof(SpareHeader)) / 4;
|
|
748
|
+
this.pendingHead = base.pending_head;
|
|
749
|
+
this.pendingTail = base.pending_tail;
|
|
750
|
+
this.pendingBytes = base.pending_bytes;
|
|
751
|
+
this.index = new BPlusTree(this, { key: primitive.uint64, value: DataExtent }, base.index_root, base.index_count);
|
|
752
|
+
this.byOffset = new BPlusTree(this, { key: primitive.uint32, value: primitive.uint32 }, base.free_root, base.free_count);
|
|
753
|
+
this.bySize = new BPlusTree(this, { key: primitive.uint64, value: Void }, base.size_root, base.free_count);
|
|
754
|
+
this.releasePending(store.epochs.oldest());
|
|
755
|
+
}
|
|
756
|
+
offsetOf(block) {
|
|
757
|
+
return this.store.byteOffset + block;
|
|
758
|
+
}
|
|
759
|
+
alloc() {
|
|
760
|
+
let block = this.recycled.pop();
|
|
761
|
+
if (block === undefined) {
|
|
762
|
+
this.refillSpares();
|
|
763
|
+
block = this.popSpare();
|
|
764
|
+
}
|
|
765
|
+
if (block === undefined) {
|
|
766
|
+
if (this.changingFreeTrees)
|
|
767
|
+
throw sparesExhausted;
|
|
768
|
+
throw err(withErrno('ENOSPC', 'sbfs: no space for metadata'));
|
|
769
|
+
}
|
|
770
|
+
this.fresh.add(block);
|
|
771
|
+
return block;
|
|
772
|
+
}
|
|
773
|
+
free(block) {
|
|
774
|
+
if (this.fresh.delete(block))
|
|
775
|
+
this.recycled.push(block);
|
|
776
|
+
else
|
|
777
|
+
this.retired.push([block, this.pageSize]);
|
|
778
|
+
}
|
|
779
|
+
// Spare blocks
|
|
780
|
+
/** Minimum blocks available for tree nodes, enough to copy and split a path in both free trees */
|
|
781
|
+
lowWater() {
|
|
782
|
+
return 4 * (Math.max(this.byOffset.height, this.bySize.height) + 1) * this.spareScale;
|
|
783
|
+
}
|
|
784
|
+
/** Blocks that can be allocated without changing the free trees */
|
|
785
|
+
availableBlocks() {
|
|
786
|
+
return this.spareTotal + this.recycled.length;
|
|
787
|
+
}
|
|
788
|
+
/** Takes a spare block, if there are any */
|
|
789
|
+
popSpare() {
|
|
790
|
+
while (this.spareHead && !this.spareCount) {
|
|
791
|
+
const next = this.store.getUint32(this.spareHead + offsetof(SpareHeader, 'next'), true);
|
|
792
|
+
this.free(this.spareHead);
|
|
793
|
+
this.spareHead = next;
|
|
794
|
+
this.spareCount = this.spareFloor = next && this.store.getUint32(next + offsetof(SpareHeader, 'count'), true);
|
|
795
|
+
}
|
|
796
|
+
if (!this.spareCount)
|
|
797
|
+
return;
|
|
798
|
+
this.spareCount--;
|
|
799
|
+
this.spareTotal--;
|
|
800
|
+
return this.store.getUint32(this.spareHead + sizeof(SpareHeader) + this.spareCount * 4, true);
|
|
801
|
+
}
|
|
802
|
+
/** Adds a free block to the spare blocks */
|
|
803
|
+
pushSpare(block) {
|
|
804
|
+
if (this.spareHead && this.spareCount >= this.spareFloor && this.spareCount < this.spareCapacity) {
|
|
805
|
+
this.store.setUint32(this.spareHead + sizeof(SpareHeader) + this.spareCount * 4, block, true);
|
|
806
|
+
this.spareCount++;
|
|
807
|
+
this.spareTotal++;
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
810
|
+
// The block becomes the newest list block
|
|
811
|
+
if (this.spareHead)
|
|
812
|
+
this.store.setUint32(this.spareHead + offsetof(SpareHeader, 'count'), this.spareCount, true);
|
|
813
|
+
this.store.setUint32(block + offsetof(SpareHeader, 'next'), this.spareHead, true);
|
|
814
|
+
this.spareHead = block;
|
|
815
|
+
this.spareCount = this.spareFloor = 0;
|
|
816
|
+
this.fresh.add(block);
|
|
817
|
+
}
|
|
818
|
+
/** Refills the spare blocks if they are below the low-water mark */
|
|
819
|
+
refillSpares() {
|
|
820
|
+
if (this.changingFreeTrees)
|
|
821
|
+
return;
|
|
822
|
+
const low = this.lowWater();
|
|
823
|
+
if (this.availableBlocks() >= low)
|
|
824
|
+
return;
|
|
825
|
+
this.changeFreeTrees(() => {
|
|
826
|
+
const total = Math.floor(this.store.byteLength / this.pageSize);
|
|
827
|
+
for (let blocks = Math.min(low * 2, total); blocks >= 1 && this.availableBlocks() < low;) {
|
|
828
|
+
try {
|
|
829
|
+
const offset = this.takeBestFit(blocks * this.pageSize);
|
|
830
|
+
for (let i = 0; i < blocks; i++)
|
|
831
|
+
this.pushSpare(offset + i * this.pageSize);
|
|
832
|
+
}
|
|
833
|
+
catch (e) {
|
|
834
|
+
if (e === sparesExhausted || e.code != 'ENOSPC')
|
|
835
|
+
throw e;
|
|
836
|
+
blocks >>= 1;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
// Free space
|
|
842
|
+
changeFreeTrees(change) {
|
|
843
|
+
this.changingFreeTrees = true;
|
|
844
|
+
try {
|
|
845
|
+
return change();
|
|
846
|
+
}
|
|
847
|
+
finally {
|
|
848
|
+
this.changingFreeTrees = false;
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
/** Removes the free extent at `offset`, then returns everything after its first `size` bytes to free space */
|
|
852
|
+
split(offset, length, size) {
|
|
853
|
+
this.bySize.delete(sizeKey(length, offset));
|
|
854
|
+
this.byOffset.delete(offset);
|
|
855
|
+
if (length > size) {
|
|
856
|
+
this.byOffset.set(offset + size, length - size);
|
|
857
|
+
this.bySize.set(sizeKey(length - size, offset + size), undefined);
|
|
858
|
+
}
|
|
859
|
+
this.freeBytes -= size;
|
|
860
|
+
}
|
|
861
|
+
/** Takes the smallest free extent that fits `size` bytes */
|
|
862
|
+
takeBestFit(size) {
|
|
863
|
+
const found = this.bySize.ceiling(sizeKey(size, 0));
|
|
864
|
+
if (!found)
|
|
865
|
+
throw withErrno('ENOSPC', 'sbfs: no free extent is large enough');
|
|
866
|
+
const offset = Number(found[0] & 0xffffffffn);
|
|
867
|
+
this.split(offset, Number(found[0] >> 32n), size);
|
|
868
|
+
return offset;
|
|
869
|
+
}
|
|
870
|
+
/** Allocates `size` bytes for data, leaving enough blocks to change the free trees */
|
|
871
|
+
allocate(size) {
|
|
872
|
+
this.refillSpares();
|
|
873
|
+
if (this.availableBlocks() < this.lowWater())
|
|
874
|
+
throw withErrno('ENOSPC', 'sbfs: no space left');
|
|
875
|
+
return this.changeFreeTrees(() => this.takeBestFit(size));
|
|
876
|
+
}
|
|
877
|
+
/** Frees an extent no reader can see, merging it with adjacent free extents */
|
|
878
|
+
freeExtent(offset, size) {
|
|
879
|
+
if (!size)
|
|
880
|
+
return;
|
|
881
|
+
this.refillSpares();
|
|
882
|
+
this.changeFreeTrees(() => {
|
|
883
|
+
let start = offset, length = size;
|
|
884
|
+
const prev = this.byOffset.floor(offset);
|
|
885
|
+
if (prev && prev[0] + prev[1] > offset)
|
|
886
|
+
throw crit(withErrno('EIO', `sbfs: extent at ${hex(offset)} was freed twice`));
|
|
887
|
+
if (prev && prev[0] + prev[1] == offset) {
|
|
888
|
+
start = prev[0];
|
|
889
|
+
length += prev[1];
|
|
890
|
+
this.bySize.delete(sizeKey(prev[1], prev[0]));
|
|
891
|
+
}
|
|
892
|
+
const next = this.byOffset.ceiling(offset);
|
|
893
|
+
if (next && next[0] < offset + size)
|
|
894
|
+
throw crit(withErrno('EIO', `sbfs: extent at ${hex(offset)} was freed twice`));
|
|
895
|
+
if (next && next[0] == offset + size) {
|
|
896
|
+
length += next[1];
|
|
897
|
+
this.byOffset.delete(next[0]);
|
|
898
|
+
this.bySize.delete(sizeKey(next[1], next[0]));
|
|
899
|
+
}
|
|
900
|
+
this.byOffset.set(start, length);
|
|
901
|
+
this.bySize.set(sizeKey(length, start), undefined);
|
|
902
|
+
this.freeBytes += size;
|
|
903
|
+
});
|
|
904
|
+
}
|
|
905
|
+
/** Frees an extent once no reader can see this transaction's base */
|
|
906
|
+
retire(offset, size) {
|
|
907
|
+
if (size)
|
|
908
|
+
this.retired.push([offset, size]);
|
|
909
|
+
}
|
|
910
|
+
// Pending extents
|
|
911
|
+
/** Frees extents retired by generations that readers no longer see */
|
|
912
|
+
releasePending(oldest) {
|
|
913
|
+
const { store } = this;
|
|
914
|
+
while (this.pendingHead) {
|
|
915
|
+
const block = this.pendingHead;
|
|
916
|
+
if (oldest !== undefined && store.getBigUint64(block + offsetof(PendingHeader, 'generation'), true) > oldest)
|
|
917
|
+
break;
|
|
918
|
+
// Released blocks become spares, up to twice the low-water mark
|
|
919
|
+
for (let i = 0; i < store.getUint32(block + offsetof(PendingHeader, 'count'), true); i++) {
|
|
920
|
+
const entry = block + sizeof(PendingHeader) + i * sizeof(Extent);
|
|
921
|
+
const offset = store.getUint32(entry + offsetof(Extent, 'offset'), true);
|
|
922
|
+
const size = store.getUint32(entry + offsetof(Extent, 'size'), true);
|
|
923
|
+
this.pendingBytes -= size;
|
|
924
|
+
if (size == this.pageSize && this.availableBlocks() < 2 * this.lowWater())
|
|
925
|
+
this.pushSpare(offset);
|
|
926
|
+
else
|
|
927
|
+
this.freeExtent(offset, size);
|
|
928
|
+
}
|
|
929
|
+
const last = block == this.pendingTail;
|
|
930
|
+
this.pendingHead = last ? 0 : store.getUint32(block + offsetof(PendingHeader, 'next'), true);
|
|
931
|
+
if (last)
|
|
932
|
+
this.pendingTail = 0;
|
|
933
|
+
// The base commit still lists this block
|
|
934
|
+
this.retire(block, this.pageSize);
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
appendPending(offset, size) {
|
|
938
|
+
const { store } = this;
|
|
939
|
+
let tail = this.pendingTail;
|
|
940
|
+
if (!tail
|
|
941
|
+
|| store.getBigUint64(tail + offsetof(PendingHeader, 'generation'), true) !== this.generation
|
|
942
|
+
|| store.getUint32(tail + offsetof(PendingHeader, 'count'), true) >= Math.floor((this.pageSize - sizeof(PendingHeader)) / sizeof(Extent))) {
|
|
943
|
+
const block = this.alloc();
|
|
944
|
+
store.setUint32(block + offsetof(PendingHeader, 'next'), 0, true);
|
|
945
|
+
store.setUint32(block + offsetof(PendingHeader, 'count'), 0, true);
|
|
946
|
+
store.setBigUint64(block + offsetof(PendingHeader, 'generation'), this.generation, true);
|
|
947
|
+
// Earlier commits stop at their own tail
|
|
948
|
+
if (tail)
|
|
949
|
+
store.setUint32(tail + offsetof(PendingHeader, 'next'), block, true);
|
|
950
|
+
else
|
|
951
|
+
this.pendingHead = block;
|
|
952
|
+
this.pendingTail = tail = block;
|
|
953
|
+
}
|
|
954
|
+
const count = store.getUint32(tail + offsetof(PendingHeader, 'count'), true);
|
|
955
|
+
const entry = tail + sizeof(PendingHeader) + count * sizeof(Extent);
|
|
956
|
+
store.setUint32(entry + offsetof(Extent, 'offset'), offset, true);
|
|
957
|
+
store.setUint32(entry + offsetof(Extent, 'size'), size, true);
|
|
958
|
+
store.setUint32(tail + offsetof(PendingHeader, 'count'), count + 1, true);
|
|
959
|
+
this.pendingBytes += size;
|
|
960
|
+
}
|
|
961
|
+
/** Records retired extents in the pending list, then writes this transaction's roots and allocator state to `commit` */
|
|
962
|
+
commit(commit) {
|
|
963
|
+
while (this.retired.length) {
|
|
964
|
+
const batch = this.retired;
|
|
965
|
+
this.retired = [];
|
|
966
|
+
for (const [offset, size] of batch)
|
|
967
|
+
this.appendPending(offset, size);
|
|
968
|
+
}
|
|
969
|
+
for (const block of this.recycled)
|
|
970
|
+
this.pushSpare(block);
|
|
971
|
+
this.recycled = [];
|
|
972
|
+
Object.assign(commit, {
|
|
973
|
+
generation: this.generation,
|
|
974
|
+
index_root: this.index.root,
|
|
975
|
+
index_count: this.index.size,
|
|
976
|
+
free_root: this.byOffset.root,
|
|
977
|
+
size_root: this.bySize.root,
|
|
978
|
+
free_count: this.byOffset.size,
|
|
979
|
+
free_bytes: this.freeBytes,
|
|
980
|
+
spare_head: this.spareHead,
|
|
981
|
+
spare_count: this.spareCount,
|
|
982
|
+
spare_total: this.spareTotal,
|
|
983
|
+
pending_head: this.pendingHead,
|
|
984
|
+
pending_tail: this.pendingTail,
|
|
985
|
+
pending_bytes: this.pendingBytes,
|
|
986
|
+
});
|
|
987
|
+
commit.update();
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
const defaultStateSize = sizeof(State) + EpochTable.sizeOf(default_epoch_slots);
|
|
991
|
+
/**
|
|
992
|
+
* A store for version 2 of the single-buffer format.
|
|
993
|
+
*
|
|
994
|
+
* Every change is a transaction that copies what it modifies.
|
|
995
|
+
* Readers never block, and an interrupted writer does not change the file system.
|
|
996
|
+
* @category Stores and Transactions
|
|
997
|
+
*/
|
|
998
|
+
export class SingleBufferStore extends DataView {
|
|
999
|
+
flags = ['partial'];
|
|
1000
|
+
name = 'sbfs';
|
|
1001
|
+
type = 0x73626673; // 'sbfs'
|
|
1002
|
+
get uuid() {
|
|
1003
|
+
return decodeUUID(this.superblock.uuid);
|
|
1004
|
+
}
|
|
1005
|
+
superblock;
|
|
1006
|
+
/**
|
|
1007
|
+
* The entire file system
|
|
1008
|
+
* @internal
|
|
1009
|
+
*/
|
|
1010
|
+
bytes;
|
|
1011
|
+
/** @internal */
|
|
1012
|
+
blockSize;
|
|
1013
|
+
/** @internal */
|
|
1014
|
+
epochs;
|
|
1015
|
+
mutex;
|
|
1016
|
+
generation;
|
|
1017
|
+
nextId;
|
|
1018
|
+
commits;
|
|
1019
|
+
/** The index of the version being read */
|
|
1020
|
+
index;
|
|
1021
|
+
/**
|
|
1022
|
+
* Opens a file system, or creates one if `format` is set.
|
|
1023
|
+
* When creating one, byte ranges in `used` are kept, and the first transaction runs `populate` after making everything else free.
|
|
1024
|
+
*/
|
|
1025
|
+
constructor(buffer, byteOffset = 0, byteLength, options = {}) {
|
|
1026
|
+
if (ArrayBuffer.isView(buffer))
|
|
1027
|
+
super(buffer.buffer, buffer.byteOffset + byteOffset, byteLength ?? buffer.byteLength - byteOffset);
|
|
1028
|
+
else
|
|
1029
|
+
super(buffer, byteOffset, byteLength);
|
|
1030
|
+
if (this.byteOffset % 8)
|
|
1031
|
+
throw crit(withErrno('EINVAL', 'sbfs: buffer must be 8-byte aligned'));
|
|
1032
|
+
if (this.byteLength < sizeof(SuperBlock))
|
|
1033
|
+
throw crit(withErrno('EINVAL', 'sbfs: buffer is too small for a file system'));
|
|
1034
|
+
this.bytes = new Uint8Array(this.buffer, this.byteOffset, this.byteLength);
|
|
1035
|
+
this.superblock = new SuperBlock(this.buffer, this.byteOffset);
|
|
1036
|
+
const format = options.format === true ? {} : options.format;
|
|
1037
|
+
let { superblock } = this;
|
|
1038
|
+
const gaps = [];
|
|
1039
|
+
let spares = 0, spareBlocks = 0;
|
|
1040
|
+
if (!format)
|
|
1041
|
+
this.superblock.validate(this.byteLength);
|
|
1042
|
+
else {
|
|
1043
|
+
if (this.byteLength > max_size)
|
|
1044
|
+
throw crit(withErrno('EINVAL', 'sbfs: buffers larger than 4 GiB are not supported'));
|
|
1045
|
+
const used = [[0, sizeof(SuperBlock)], ...(format.used ?? [])];
|
|
1046
|
+
used.sort(([a], [b]) => a - b);
|
|
1047
|
+
let cursor = 0;
|
|
1048
|
+
for (const [start, end] of used) {
|
|
1049
|
+
if (start > cursor)
|
|
1050
|
+
gaps.push([cursor, start]);
|
|
1051
|
+
cursor = Math.max(cursor, end);
|
|
1052
|
+
}
|
|
1053
|
+
if (cursor < this.byteLength)
|
|
1054
|
+
gaps.push([cursor, this.byteLength]);
|
|
1055
|
+
const take = (size, alignment) => {
|
|
1056
|
+
const align = (start) => Math.ceil((this.byteOffset + start) / alignment) * alignment - this.byteOffset;
|
|
1057
|
+
const index = gaps.findIndex(([start, end]) => align(start) + size <= end);
|
|
1058
|
+
if (index == -1)
|
|
1059
|
+
throw crit(withErrno('ENOSPC', 'sbfs: buffer is too small for a file system'));
|
|
1060
|
+
const [start, end] = gaps[index];
|
|
1061
|
+
const aligned = align(start);
|
|
1062
|
+
const rest = [
|
|
1063
|
+
[start, aligned],
|
|
1064
|
+
[aligned + size, end],
|
|
1065
|
+
];
|
|
1066
|
+
gaps.splice(index, 1, ...rest.filter(([s, e]) => e > s));
|
|
1067
|
+
return aligned;
|
|
1068
|
+
};
|
|
1069
|
+
superblock = new SuperBlock();
|
|
1070
|
+
Object.assign(superblock, {
|
|
1071
|
+
magic: sb_magic,
|
|
1072
|
+
version: 2,
|
|
1073
|
+
inode_format: _inode_version,
|
|
1074
|
+
block_size: default_block_size,
|
|
1075
|
+
epoch_slots: default_epoch_slots,
|
|
1076
|
+
total_bytes: BigInt(this.byteLength),
|
|
1077
|
+
uuid: format.uuid ?? encodeUUID(crypto.randomUUID()),
|
|
1078
|
+
state_offset: take(defaultStateSize, 8),
|
|
1079
|
+
});
|
|
1080
|
+
if (format.label)
|
|
1081
|
+
superblock.label = format.label;
|
|
1082
|
+
const free = gaps.reduce((total, [start, end]) => total + end - start, 0);
|
|
1083
|
+
spareBlocks = Math.min(initial_spares, Math.floor(free / superblock.block_size / 4));
|
|
1084
|
+
if (spareBlocks < 4)
|
|
1085
|
+
throw crit(withErrno('EINVAL', 'sbfs: buffer is too small for a file system'));
|
|
1086
|
+
spares = take(spareBlocks * superblock.block_size, 1);
|
|
1087
|
+
}
|
|
1088
|
+
const { block_size, state_offset, epoch_slots } = superblock;
|
|
1089
|
+
const state = this.byteOffset + state_offset;
|
|
1090
|
+
const commits = state + offsetof(State, 'commits');
|
|
1091
|
+
this.blockSize = block_size;
|
|
1092
|
+
this.mutex = new Mutex(this.buffer, state + offsetof(State, 'lock'));
|
|
1093
|
+
this.generation = new BigInt64Array(this.buffer, state + offsetof(State, 'generation'), 1);
|
|
1094
|
+
this.nextId = new BigInt64Array(this.buffer, state + offsetof(State, 'next_id'), 1);
|
|
1095
|
+
this.commits = [new Commit(this.buffer, commits), new Commit(this.buffer, commits + sizeof(Commit))];
|
|
1096
|
+
this.epochs = new EpochTable(this.buffer, state + sizeof(State), epoch_slots);
|
|
1097
|
+
const readOnly = {
|
|
1098
|
+
buffer: this.buffer,
|
|
1099
|
+
pageSize: this.blockSize,
|
|
1100
|
+
offsetOf: block => this.byteOffset + block,
|
|
1101
|
+
alloc: () => _throw(withErrno('EROFS', 'sbfs: snapshots are read-only')),
|
|
1102
|
+
free: () => _throw(withErrno('EROFS', 'sbfs: snapshots are read-only')),
|
|
1103
|
+
};
|
|
1104
|
+
this.index = new BPlusTree(readOnly, { key: primitive.uint64, value: DataExtent });
|
|
1105
|
+
if (!format) {
|
|
1106
|
+
if (!this.withCurrentCommit((commit, generation) => commit.isValid(generation)))
|
|
1107
|
+
throw crit(withErrno('EIO', 'sbfs: the current commit is corrupt'));
|
|
1108
|
+
return;
|
|
1109
|
+
}
|
|
1110
|
+
this.bytes.fill(0, state_offset, state_offset + defaultStateSize);
|
|
1111
|
+
Atomics.store(this.nextId, 0, format.nextId ?? 2n);
|
|
1112
|
+
this.setUint32(spares + offsetof(SpareHeader, 'next'), 0, true);
|
|
1113
|
+
for (let i = 1; i < spareBlocks; i++)
|
|
1114
|
+
this.setUint32(spares + sizeof(SpareHeader) + (i - 1) * 4, spares + i * block_size, true);
|
|
1115
|
+
Object.assign(this.commits[0], { spare_head: spares, spare_count: spareBlocks - 1, spare_total: spareBlocks - 1 });
|
|
1116
|
+
this.commits[0].update();
|
|
1117
|
+
this.write(tx => {
|
|
1118
|
+
for (const [start, end] of gaps)
|
|
1119
|
+
tx.freeExtent(start, end - start);
|
|
1120
|
+
format.populate?.(tx);
|
|
1121
|
+
});
|
|
1122
|
+
superblock.lock = Atomics.load(new BigInt64Array(this.buffer, this.byteOffset + offsetof(SuperBlock, 'lock'), 1), 0);
|
|
1123
|
+
superblock.update();
|
|
1124
|
+
this.bytes.set(new Uint8Array(superblock.buffer, superblock.byteOffset, sizeof(SuperBlock)), 0);
|
|
1125
|
+
}
|
|
1126
|
+
/** Reads the current commit, retrying if a writer replaces it while reading */
|
|
1127
|
+
withCurrentCommit(read) {
|
|
1128
|
+
for (;;) {
|
|
1129
|
+
const generation = Atomics.load(this.generation, 0);
|
|
1130
|
+
const result = read(this.commits[Number(generation & 1n)], generation);
|
|
1131
|
+
if (Atomics.load(this.generation, 0) === generation)
|
|
1132
|
+
return result;
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
/** Runs `read` against the current version, which stays valid until `read` returns */
|
|
1136
|
+
read(read) {
|
|
1137
|
+
for (;;) {
|
|
1138
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
1139
|
+
try {
|
|
1140
|
+
const generation = Atomics.load(this.generation, 0);
|
|
1141
|
+
const _ = __addDisposableResource(env_1, this.epochs.pin(generation), false);
|
|
1142
|
+
const { index_root, index_count } = this.commits[Number(generation & 1n)];
|
|
1143
|
+
if (Atomics.load(this.generation, 0) !== generation)
|
|
1144
|
+
continue;
|
|
1145
|
+
this.index.reset(index_root, index_count);
|
|
1146
|
+
return read(this.index);
|
|
1147
|
+
}
|
|
1148
|
+
catch (e_1) {
|
|
1149
|
+
env_1.error = e_1;
|
|
1150
|
+
env_1.hasError = true;
|
|
1151
|
+
}
|
|
1152
|
+
finally {
|
|
1153
|
+
__disposeResources(env_1);
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
/** Runs `change` in a write transaction, retrying with more spare blocks if the free trees run out of them */
|
|
1158
|
+
write(change) {
|
|
1159
|
+
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
1160
|
+
try {
|
|
1161
|
+
const lock = __addDisposableResource(env_2, this.mutex.lock(), false);
|
|
1162
|
+
for (let attempt = 0;; attempt++) {
|
|
1163
|
+
try {
|
|
1164
|
+
const generation = Atomics.load(this.generation, 0);
|
|
1165
|
+
const base = this.commits[Number(generation & 1n)];
|
|
1166
|
+
if (!base.isValid(generation))
|
|
1167
|
+
throw crit(withErrno('EIO', `sbfs: commit for generation ${generation} is corrupt`));
|
|
1168
|
+
const tx = new WriteTransaction(this, base, 2 ** attempt);
|
|
1169
|
+
const result = change(tx);
|
|
1170
|
+
tx.commit(this.commits[Number(tx.generation & 1n)]);
|
|
1171
|
+
if (!lock.renew())
|
|
1172
|
+
throw crit(withErrno('EBUSY', 'sbfs: lost the write lock before committing'));
|
|
1173
|
+
Atomics.store(this.generation, 0, tx.generation);
|
|
1174
|
+
return result;
|
|
1175
|
+
}
|
|
1176
|
+
catch (e) {
|
|
1177
|
+
if (e !== sparesExhausted || attempt >= 3)
|
|
1178
|
+
throw e;
|
|
1179
|
+
debug('sbfs: retrying transaction with more spare blocks');
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
catch (e_2) {
|
|
1184
|
+
env_2.error = e_2;
|
|
1185
|
+
env_2.hasError = true;
|
|
1186
|
+
}
|
|
1187
|
+
finally {
|
|
1188
|
+
__disposeResources(env_2);
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
// Store
|
|
1192
|
+
keys() {
|
|
1193
|
+
return this.read(index => Array.from(index.keys(), Number));
|
|
1194
|
+
}
|
|
1195
|
+
get(id, offset = 0, end) {
|
|
1196
|
+
return this.read(index => {
|
|
1197
|
+
const extent = index.get(BigInt(id));
|
|
1198
|
+
if (!extent)
|
|
1199
|
+
return;
|
|
1200
|
+
const start = this.byteOffset + extent.offset;
|
|
1201
|
+
return new Uint8Array(this.buffer.slice(start + Math.min(offset, extent.size), start + Math.min(end ?? extent.size, extent.size)));
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1204
|
+
set(id, data, offset) {
|
|
1205
|
+
if (id === 0 && offset === undefined && data.length < sizeof(Inode))
|
|
1206
|
+
throw alert(withErrno('EIO', `sbfs: tried to set ${data.length} bytes for id 0!`));
|
|
1207
|
+
const key = BigInt(id);
|
|
1208
|
+
this.write(tx => {
|
|
1209
|
+
const old = tx.index.get(key);
|
|
1210
|
+
const kept = offset === undefined ? 0 : (old?.size ?? 0);
|
|
1211
|
+
const start = offset ?? 0;
|
|
1212
|
+
const extent = Object.assign(new DataExtent(), { size: Math.max(kept, start + data.length) });
|
|
1213
|
+
// Bytes past the old size are not visible to readers of older versions
|
|
1214
|
+
if (old && offset !== undefined && start >= old.size && extent.size <= old.capacity) {
|
|
1215
|
+
extent.offset = old.offset;
|
|
1216
|
+
extent.capacity = old.capacity;
|
|
1217
|
+
}
|
|
1218
|
+
else {
|
|
1219
|
+
// Partial writes keep the old capacity, and data that outgrows it gets room to keep growing
|
|
1220
|
+
const capacity = offset === undefined ? 0 : (old?.capacity ?? 0);
|
|
1221
|
+
if (extent.size <= capacity)
|
|
1222
|
+
extent.capacity = capacity;
|
|
1223
|
+
else if (capacity)
|
|
1224
|
+
extent.capacity = Math.max(extent.size, Math.floor(capacity * 1.5));
|
|
1225
|
+
else
|
|
1226
|
+
extent.capacity = extent.size;
|
|
1227
|
+
try {
|
|
1228
|
+
extent.offset = extent.capacity ? tx.allocate(extent.capacity) : 0;
|
|
1229
|
+
}
|
|
1230
|
+
catch (e) {
|
|
1231
|
+
if (e === sparesExhausted || e.code != 'ENOSPC' || extent.capacity == extent.size)
|
|
1232
|
+
throw e;
|
|
1233
|
+
extent.capacity = extent.size;
|
|
1234
|
+
extent.offset = tx.allocate(extent.size);
|
|
1235
|
+
}
|
|
1236
|
+
if (old) {
|
|
1237
|
+
this.bytes.copyWithin(extent.offset, old.offset, old.offset + kept);
|
|
1238
|
+
tx.retire(old.offset, old.capacity);
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
this.bytes.fill(0, extent.offset + kept, extent.offset + start);
|
|
1242
|
+
this.bytes.set(data, extent.offset + start);
|
|
1243
|
+
tx.index.set(key, extent);
|
|
1244
|
+
});
|
|
1245
|
+
}
|
|
1246
|
+
delete(id) {
|
|
1247
|
+
const key = BigInt(id);
|
|
1248
|
+
this.write(tx => {
|
|
1249
|
+
const old = tx.index.get(key);
|
|
1250
|
+
if (!old)
|
|
1251
|
+
return;
|
|
1252
|
+
tx.index.delete(key);
|
|
1253
|
+
tx.retire(old.offset, old.capacity);
|
|
1254
|
+
});
|
|
1255
|
+
}
|
|
1256
|
+
allocId() {
|
|
1257
|
+
const id = Atomics.add(this.nextId, 0, 2n);
|
|
1258
|
+
if (id + 1n > max_id)
|
|
1259
|
+
throw err(withErrno('ENOSPC', 'sbfs: no IDs available'));
|
|
1260
|
+
return [Number(id), Number(id + 1n)];
|
|
1261
|
+
}
|
|
1262
|
+
usage() {
|
|
1263
|
+
return {
|
|
1264
|
+
totalSpace: Number(this.superblock.total_bytes),
|
|
1265
|
+
freeSpace: this.withCurrentCommit(commit => commit.free_bytes + commit.spare_total * this.blockSize + commit.pending_bytes),
|
|
1266
|
+
};
|
|
1267
|
+
}
|
|
1268
|
+
_fs;
|
|
1269
|
+
get fs() {
|
|
1270
|
+
return this._fs;
|
|
1271
|
+
}
|
|
1272
|
+
set fs(fs) {
|
|
1273
|
+
if (this.buffer.constructor.name === 'SharedArrayBuffer')
|
|
1274
|
+
fs?.attributes.set('no_id_tables', true);
|
|
1275
|
+
this._fs = fs;
|
|
1276
|
+
}
|
|
1277
|
+
sync() {
|
|
1278
|
+
return Promise.resolve();
|
|
1279
|
+
}
|
|
1280
|
+
transaction() {
|
|
1281
|
+
return new SyncMapTransaction(this);
|
|
1282
|
+
}
|
|
1283
|
+
}
|