@ai-ecoverse/slicc-kernel 1.21.1 → 1.22.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 +6 -5
- package/dist/driver-worker.js +6 -4
- package/dist/driver-worker.js.map +2 -2
- package/dist/driver.js +6 -4
- package/dist/driver.js.map +2 -2
- package/dist/kernel-worker.js +473 -39
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-driver-worker.js +6 -4
- package/dist/node-driver-worker.js.map +2 -2
- package/dist/node-process-worker.js +387 -33
- package/dist/node-process-worker.js.map +4 -4
- package/dist/node.js +473 -39
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +387 -33
- package/dist/process-worker.js.map +4 -4
- package/package.json +1 -1
package/dist/process-worker.js
CHANGED
|
@@ -87,6 +87,249 @@ var init_signals = __esm({
|
|
|
87
87
|
}
|
|
88
88
|
});
|
|
89
89
|
|
|
90
|
+
// src/fs/pages.ts
|
|
91
|
+
var PAGE, READAHEAD, CLEAN_LIMIT, WRITEBACK, RUN, Pages;
|
|
92
|
+
var init_pages = __esm({
|
|
93
|
+
"src/fs/pages.ts"() {
|
|
94
|
+
"use strict";
|
|
95
|
+
PAGE = 64 * 1024;
|
|
96
|
+
READAHEAD = 1024 * 1024;
|
|
97
|
+
CLEAN_LIMIT = 4 * 1024 * 1024;
|
|
98
|
+
WRITEBACK = 8 * 1024 * 1024;
|
|
99
|
+
RUN = 1024 * 1024;
|
|
100
|
+
Pages = class {
|
|
101
|
+
length;
|
|
102
|
+
stored;
|
|
103
|
+
shrink;
|
|
104
|
+
pages = /* @__PURE__ */ new Map();
|
|
105
|
+
dirty = /* @__PURE__ */ new Set();
|
|
106
|
+
free = [];
|
|
107
|
+
pinned = false;
|
|
108
|
+
constructor(size) {
|
|
109
|
+
this.length = size;
|
|
110
|
+
this.stored = size;
|
|
111
|
+
}
|
|
112
|
+
get dirtyBytes() {
|
|
113
|
+
return this.dirty.size * PAGE;
|
|
114
|
+
}
|
|
115
|
+
get changed() {
|
|
116
|
+
return this.dirty.size > 0 || this.shrink !== void 0 || this.length !== this.stored;
|
|
117
|
+
}
|
|
118
|
+
missing(at, length) {
|
|
119
|
+
this.evict();
|
|
120
|
+
const end = Math.min(this.stored, at + length, this.length);
|
|
121
|
+
const runs = [];
|
|
122
|
+
for (let page = Math.floor(at / PAGE); page * PAGE < end; page++) {
|
|
123
|
+
if (this.pages.has(page)) continue;
|
|
124
|
+
const last2 = runs[runs.length - 1];
|
|
125
|
+
if (last2 && last2[0] + last2[1] === page * PAGE) last2[1] += PAGE;
|
|
126
|
+
else runs.push([page * PAGE, PAGE]);
|
|
127
|
+
}
|
|
128
|
+
const last = runs[runs.length - 1];
|
|
129
|
+
if (last) last[1] = Math.max(last[1], Math.min(READAHEAD, this.stored - last[0]));
|
|
130
|
+
return runs.map(([start, n]) => [start, Math.min(n, this.stored - start)]);
|
|
131
|
+
}
|
|
132
|
+
partial(at, length) {
|
|
133
|
+
if (length === 0) return [];
|
|
134
|
+
this.evict();
|
|
135
|
+
const edges = /* @__PURE__ */ new Set([Math.floor(at / PAGE), Math.floor((at + length - 1) / PAGE)]);
|
|
136
|
+
const runs = [];
|
|
137
|
+
for (const page of edges) {
|
|
138
|
+
const start = page * PAGE;
|
|
139
|
+
const covered = at <= start && at + length >= start + PAGE;
|
|
140
|
+
if (covered || this.pages.has(page) || start >= this.stored) continue;
|
|
141
|
+
runs.push([start, Math.min(PAGE, this.stored - start)]);
|
|
142
|
+
}
|
|
143
|
+
return runs;
|
|
144
|
+
}
|
|
145
|
+
fill(start, bytes) {
|
|
146
|
+
for (let at = 0; at < bytes.length; at += PAGE) {
|
|
147
|
+
const page = (start + at) / PAGE;
|
|
148
|
+
if (this.pages.has(page)) continue;
|
|
149
|
+
const part = bytes.subarray(at, Math.min(at + PAGE, bytes.length));
|
|
150
|
+
const fresh = this.take(part.length);
|
|
151
|
+
fresh.set(part);
|
|
152
|
+
this.pages.set(page, fresh);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
read(at, length) {
|
|
156
|
+
const out = new Uint8Array(Math.max(0, Math.min(this.length, at + length) - at));
|
|
157
|
+
this.readInto(at, out);
|
|
158
|
+
return out;
|
|
159
|
+
}
|
|
160
|
+
readInto(at, out) {
|
|
161
|
+
const end = Math.min(this.length, at + out.length);
|
|
162
|
+
for (let pos = at; pos < end; ) {
|
|
163
|
+
const page = Math.floor(pos / PAGE);
|
|
164
|
+
const from = pos - page * PAGE;
|
|
165
|
+
const n = Math.min(PAGE - from, end - pos);
|
|
166
|
+
const bytes = this.pages.get(page);
|
|
167
|
+
if (bytes) out.set(bytes.subarray(from, from + n), pos - at);
|
|
168
|
+
else out.fill(0, pos - at, pos - at + n);
|
|
169
|
+
pos += n;
|
|
170
|
+
}
|
|
171
|
+
return Math.max(0, end - at);
|
|
172
|
+
}
|
|
173
|
+
write(at, bytes) {
|
|
174
|
+
for (let done = 0; done < bytes.length; ) {
|
|
175
|
+
const pos = at + done;
|
|
176
|
+
const page = Math.floor(pos / PAGE);
|
|
177
|
+
const from = pos - page * PAGE;
|
|
178
|
+
const n = Math.min(PAGE - from, bytes.length - done);
|
|
179
|
+
let target = this.pages.get(page);
|
|
180
|
+
if (!target) {
|
|
181
|
+
target = this.take(0);
|
|
182
|
+
this.pages.set(page, target);
|
|
183
|
+
}
|
|
184
|
+
target.set(bytes.subarray(done, done + n), from);
|
|
185
|
+
this.dirty.add(page);
|
|
186
|
+
done += n;
|
|
187
|
+
}
|
|
188
|
+
this.length = Math.max(this.length, at + bytes.length);
|
|
189
|
+
}
|
|
190
|
+
truncate(size) {
|
|
191
|
+
if (size < this.stored) {
|
|
192
|
+
this.stored = size;
|
|
193
|
+
this.shrink = Math.min(this.shrink ?? size, size);
|
|
194
|
+
}
|
|
195
|
+
if (size < this.length) {
|
|
196
|
+
const edge = Math.floor(size / PAGE);
|
|
197
|
+
for (const page of [...this.pages.keys()]) {
|
|
198
|
+
if (page > edge || page === edge && size === edge * PAGE) this.drop(page);
|
|
199
|
+
}
|
|
200
|
+
this.pages.get(edge)?.fill(0, size - edge * PAGE);
|
|
201
|
+
}
|
|
202
|
+
this.length = size;
|
|
203
|
+
}
|
|
204
|
+
plan() {
|
|
205
|
+
const runs = [];
|
|
206
|
+
const sorted = [...this.dirty].sort((a, b) => a - b);
|
|
207
|
+
for (let i = 0; i < sorted.length; ) {
|
|
208
|
+
let j = i + 1;
|
|
209
|
+
const first = sorted[i];
|
|
210
|
+
while (j < sorted.length && sorted[j] === first + (j - i) && sorted[j] * PAGE % RUN !== 0) {
|
|
211
|
+
j++;
|
|
212
|
+
}
|
|
213
|
+
const start = first * PAGE;
|
|
214
|
+
const end = Math.min(this.length, (first + (j - i)) * PAGE);
|
|
215
|
+
const bytes = new Uint8Array(end - start);
|
|
216
|
+
for (let k = i; k < j; k++) {
|
|
217
|
+
const page = this.pages.get(sorted[k]);
|
|
218
|
+
bytes.set(page.subarray(0, Math.min(PAGE, end - (k - i) * PAGE - start)), (k - i) * PAGE);
|
|
219
|
+
}
|
|
220
|
+
runs.push({ offset: start, bytes });
|
|
221
|
+
i = j;
|
|
222
|
+
}
|
|
223
|
+
const written = Math.max(this.stored, ...runs.map((r) => r.offset + r.bytes.length));
|
|
224
|
+
return {
|
|
225
|
+
...this.shrink !== void 0 ? { shrink: this.shrink } : {},
|
|
226
|
+
runs,
|
|
227
|
+
...this.length > written ? { extend: this.length } : {}
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
flushed() {
|
|
231
|
+
this.dirty.clear();
|
|
232
|
+
this.shrink = void 0;
|
|
233
|
+
this.stored = this.length;
|
|
234
|
+
this.evict();
|
|
235
|
+
}
|
|
236
|
+
pin() {
|
|
237
|
+
this.pinned = true;
|
|
238
|
+
}
|
|
239
|
+
reset(size) {
|
|
240
|
+
if (this.pinned) return;
|
|
241
|
+
for (const page of [...this.pages.keys()]) if (!this.dirty.has(page)) this.drop(page);
|
|
242
|
+
if (this.changed) return;
|
|
243
|
+
this.length = size;
|
|
244
|
+
this.stored = size;
|
|
245
|
+
}
|
|
246
|
+
evict() {
|
|
247
|
+
if (this.pinned) return;
|
|
248
|
+
let clean = (this.pages.size - this.dirty.size) * PAGE;
|
|
249
|
+
for (const page of this.pages.keys()) {
|
|
250
|
+
if (clean <= CLEAN_LIMIT) return;
|
|
251
|
+
if (this.dirty.has(page)) continue;
|
|
252
|
+
this.drop(page);
|
|
253
|
+
clean -= PAGE;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
take(used) {
|
|
257
|
+
const page = this.free.pop();
|
|
258
|
+
if (!page) return new Uint8Array(PAGE);
|
|
259
|
+
page.fill(0, used);
|
|
260
|
+
return page;
|
|
261
|
+
}
|
|
262
|
+
drop(page) {
|
|
263
|
+
const bytes = this.pages.get(page);
|
|
264
|
+
this.pages.delete(page);
|
|
265
|
+
this.dirty.delete(page);
|
|
266
|
+
if (this.free.length < CLEAN_LIMIT / PAGE) this.free.push(bytes);
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
// src/fs/ranged.ts
|
|
273
|
+
var RangedFile;
|
|
274
|
+
var init_ranged = __esm({
|
|
275
|
+
"src/fs/ranged.ts"() {
|
|
276
|
+
"use strict";
|
|
277
|
+
init_pages();
|
|
278
|
+
RangedFile = class {
|
|
279
|
+
pages;
|
|
280
|
+
io;
|
|
281
|
+
pinned = false;
|
|
282
|
+
path;
|
|
283
|
+
constructor(io, path, size) {
|
|
284
|
+
this.io = io;
|
|
285
|
+
this.path = path;
|
|
286
|
+
this.pages = new Pages(size);
|
|
287
|
+
}
|
|
288
|
+
get changed() {
|
|
289
|
+
return this.pages.changed;
|
|
290
|
+
}
|
|
291
|
+
size() {
|
|
292
|
+
return this.pages.length;
|
|
293
|
+
}
|
|
294
|
+
fetch(runs) {
|
|
295
|
+
for (const [start, n] of runs) this.pages.fill(start, this.io.pread(this.path, start, n));
|
|
296
|
+
}
|
|
297
|
+
read(at, length) {
|
|
298
|
+
this.fetch(this.pages.missing(at, length));
|
|
299
|
+
return this.pages.read(at, length);
|
|
300
|
+
}
|
|
301
|
+
readInto(at, out) {
|
|
302
|
+
this.fetch(this.pages.missing(at, out.length));
|
|
303
|
+
return this.pages.readInto(at, out);
|
|
304
|
+
}
|
|
305
|
+
write(at, bytes) {
|
|
306
|
+
this.fetch(this.pages.partial(at, bytes.length));
|
|
307
|
+
this.pages.write(at, bytes);
|
|
308
|
+
if (!this.pinned && this.pages.dirtyBytes >= WRITEBACK) this.flush();
|
|
309
|
+
}
|
|
310
|
+
truncate(size) {
|
|
311
|
+
this.pages.truncate(size);
|
|
312
|
+
}
|
|
313
|
+
flush() {
|
|
314
|
+
if (this.pinned || !this.pages.changed) return;
|
|
315
|
+
const plan = this.pages.plan();
|
|
316
|
+
if (plan.shrink !== void 0) this.io.truncate(this.path, plan.shrink);
|
|
317
|
+
for (const run of plan.runs) this.io.pwrite(this.path, run.offset, run.bytes, true);
|
|
318
|
+
if (plan.extend !== void 0) this.io.truncate(this.path, plan.extend);
|
|
319
|
+
this.pages.flushed();
|
|
320
|
+
}
|
|
321
|
+
pin() {
|
|
322
|
+
this.pinned = true;
|
|
323
|
+
this.pages.pin();
|
|
324
|
+
this.fetch(this.pages.missing(0, this.pages.length));
|
|
325
|
+
}
|
|
326
|
+
reset(size) {
|
|
327
|
+
this.pages.reset(size);
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
|
|
90
333
|
// src/fs/types.ts
|
|
91
334
|
function normalizePath(path) {
|
|
92
335
|
const parts = [];
|
|
@@ -171,7 +414,8 @@ function createHelpers(Fs, ops) {
|
|
|
171
414
|
}
|
|
172
415
|
function statOf(node) {
|
|
173
416
|
if (node.live.orphan) {
|
|
174
|
-
|
|
417
|
+
const size = node.live.ranged?.size() ?? node.live.len;
|
|
418
|
+
return { ...node.live.stat, size };
|
|
175
419
|
}
|
|
176
420
|
if (!node.live.stat) {
|
|
177
421
|
const st = call2(() => bridgeOf(node).lstat(liveNodePath(node)));
|
|
@@ -192,6 +436,20 @@ function createHelpers(Fs, ops) {
|
|
|
192
436
|
s.len = bytes.length;
|
|
193
437
|
s.loaded = true;
|
|
194
438
|
}
|
|
439
|
+
function rangedOf(node) {
|
|
440
|
+
const s = node.live;
|
|
441
|
+
if (s.ranged || !s.ranges) return s.ranged;
|
|
442
|
+
const bridge = bridgeOf(node);
|
|
443
|
+
const path = () => liveNodePath(node);
|
|
444
|
+
const io = {
|
|
445
|
+
pread: (_, at, n) => bridge.pread(path(), at, n),
|
|
446
|
+
pwrite: (_, at, bytes, transfer) => bridge.pwrite(path(), at, bytes, transfer),
|
|
447
|
+
truncate: (_, size) => bridge.truncate(path(), size)
|
|
448
|
+
};
|
|
449
|
+
const st = call2(() => bridge.stat(path()));
|
|
450
|
+
s.ranged = new RangedFile(io, path(), st.size);
|
|
451
|
+
return s.ranged;
|
|
452
|
+
}
|
|
195
453
|
function ensureCapacity(node, need) {
|
|
196
454
|
const s = node.live;
|
|
197
455
|
const cur = s.data ?? new Uint8Array(0);
|
|
@@ -203,9 +461,12 @@ function createHelpers(Fs, ops) {
|
|
|
203
461
|
}
|
|
204
462
|
function flushNode(node) {
|
|
205
463
|
const s = node.live;
|
|
206
|
-
if (!s.dirty || !s.data || s.
|
|
207
|
-
|
|
208
|
-
|
|
464
|
+
if (!s.dirty || s.orphan || !(s.data || s.ranged)) return;
|
|
465
|
+
if (s.ranged) call2(() => s.ranged?.flush());
|
|
466
|
+
else {
|
|
467
|
+
const bytes = s.data.slice(0, s.len);
|
|
468
|
+
call2(() => bridgeOf(node).writeFile(liveNodePath(node), bytes));
|
|
469
|
+
}
|
|
209
470
|
s.dirty = false;
|
|
210
471
|
s.stat = void 0;
|
|
211
472
|
}
|
|
@@ -218,6 +479,12 @@ function createHelpers(Fs, ops) {
|
|
|
218
479
|
throw new Fs.ErrnoError(ERRNO_BY_CODE.EFBIG);
|
|
219
480
|
}
|
|
220
481
|
}
|
|
482
|
+
const ranged = s.openCount > 0 ? rangedOf(node) : void 0;
|
|
483
|
+
if (ranged) {
|
|
484
|
+
ranged.truncate(size);
|
|
485
|
+
s.dirty = true;
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
221
488
|
if (s.openCount > 0) {
|
|
222
489
|
if (size > 0) ensureLoaded(node);
|
|
223
490
|
else s.loaded = true;
|
|
@@ -228,6 +495,12 @@ function createHelpers(Fs, ops) {
|
|
|
228
495
|
return;
|
|
229
496
|
}
|
|
230
497
|
const path = liveNodePath(node);
|
|
498
|
+
const bridge = bridgeOf(node);
|
|
499
|
+
if (statOf(node).ranged && bridge.truncate) {
|
|
500
|
+
call2(() => bridge.truncate?.(path, size));
|
|
501
|
+
s.stat = void 0;
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
231
504
|
const bytes = new Uint8Array(size);
|
|
232
505
|
if (size > 0) {
|
|
233
506
|
const cur = call2(() => bridgeOf(node).readFile(path));
|
|
@@ -246,6 +519,7 @@ function createHelpers(Fs, ops) {
|
|
|
246
519
|
childPath,
|
|
247
520
|
ensureLoaded,
|
|
248
521
|
ensureCapacity,
|
|
522
|
+
rangedOf,
|
|
249
523
|
flushNode,
|
|
250
524
|
truncate
|
|
251
525
|
};
|
|
@@ -257,7 +531,7 @@ function createNodeOps(h) {
|
|
|
257
531
|
getattr(node) {
|
|
258
532
|
const st = statOf(node);
|
|
259
533
|
const s = node.live;
|
|
260
|
-
const size = Fs.isDir(node.mode) ? 4096 : s.loaded ? s.len : st.size;
|
|
534
|
+
const size = Fs.isDir(node.mode) ? 4096 : s.ranged?.size() ?? (s.loaded ? s.len : st.size);
|
|
261
535
|
const mtime = new Date(st.mtimeMs ?? 0);
|
|
262
536
|
return {
|
|
263
537
|
dev: st.dev ?? 1,
|
|
@@ -357,7 +631,9 @@ function createNodeOps(h) {
|
|
|
357
631
|
}
|
|
358
632
|
if (open) {
|
|
359
633
|
statOf(open);
|
|
360
|
-
|
|
634
|
+
const ranged = h.rangedOf(open);
|
|
635
|
+
if (ranged) ranged.pin();
|
|
636
|
+
else ensureLoaded(open);
|
|
361
637
|
}
|
|
362
638
|
call2(() => bridgeOf(parent).unlink(childPath(parent, name)));
|
|
363
639
|
if (open) open.live.orphan = true;
|
|
@@ -390,7 +666,7 @@ function createNodeOps(h) {
|
|
|
390
666
|
};
|
|
391
667
|
}
|
|
392
668
|
function createStreamOps(h) {
|
|
393
|
-
const { Fs, statOf, ensureLoaded, ensureCapacity, flushNode, bridgeOf } = h;
|
|
669
|
+
const { Fs, statOf, ensureLoaded, ensureCapacity, flushNode, bridgeOf, rangedOf } = h;
|
|
394
670
|
const held = (stream, change) => {
|
|
395
671
|
const s = stream.node.live;
|
|
396
672
|
if ((stream.flags & 3) === 0 || s.orphan) return;
|
|
@@ -406,6 +682,11 @@ function createStreamOps(h) {
|
|
|
406
682
|
return {
|
|
407
683
|
open(stream) {
|
|
408
684
|
if (!Fs.isFile(stream.node.mode)) return;
|
|
685
|
+
const s = stream.node.live;
|
|
686
|
+
if (s.openCount === 0 && !s.orphan) {
|
|
687
|
+
const bridge = bridgeOf(stream.node);
|
|
688
|
+
s.ranges = !!(bridge.pread && bridge.pwrite && bridge.truncate && statOf(stream.node).ranged);
|
|
689
|
+
}
|
|
409
690
|
if ((stream.flags & 3) !== 0) {
|
|
410
691
|
try {
|
|
411
692
|
const st = statOf(stream.node);
|
|
@@ -437,6 +718,8 @@ function createStreamOps(h) {
|
|
|
437
718
|
flushNode(node);
|
|
438
719
|
} finally {
|
|
439
720
|
s.data = void 0;
|
|
721
|
+
s.ranged = void 0;
|
|
722
|
+
s.ranges = false;
|
|
440
723
|
s.len = 0;
|
|
441
724
|
s.loaded = false;
|
|
442
725
|
held(stream, -1);
|
|
@@ -445,6 +728,11 @@ function createStreamOps(h) {
|
|
|
445
728
|
read(stream, buffer, offset, length, position) {
|
|
446
729
|
const node = stream.node;
|
|
447
730
|
if (Fs.isDir(node.mode)) throw new Fs.ErrnoError(ERRNO_BY_CODE.EISDIR);
|
|
731
|
+
const ranged = rangedOf(node);
|
|
732
|
+
if (ranged) {
|
|
733
|
+
const out2 = new Uint8Array(buffer.buffer, buffer.byteOffset + offset, Math.max(0, length));
|
|
734
|
+
return h.call(() => ranged.readInto(position, out2));
|
|
735
|
+
}
|
|
448
736
|
ensureLoaded(node);
|
|
449
737
|
const s = node.live;
|
|
450
738
|
if (position >= s.len || length <= 0) return 0;
|
|
@@ -460,6 +748,13 @@ function createStreamOps(h) {
|
|
|
460
748
|
const s = node.live;
|
|
461
749
|
const end = position + length;
|
|
462
750
|
if (s.maxFile !== void 0 && end > s.maxFile) throw new Fs.ErrnoError(ERRNO_BY_CODE.EFBIG);
|
|
751
|
+
const ranged = rangedOf(node);
|
|
752
|
+
if (ranged) {
|
|
753
|
+
const bytes = new Uint8Array(buffer.buffer, buffer.byteOffset + offset, length);
|
|
754
|
+
h.call(() => ranged.write(position, bytes));
|
|
755
|
+
s.dirty = true;
|
|
756
|
+
return length;
|
|
757
|
+
}
|
|
463
758
|
ensureLoaded(node);
|
|
464
759
|
const buf = ensureCapacity(node, end);
|
|
465
760
|
if (position > s.len) buf.fill(0, s.len, position);
|
|
@@ -473,7 +768,7 @@ function createStreamOps(h) {
|
|
|
473
768
|
if (whence === SEEK_CUR) pos += stream.position;
|
|
474
769
|
else if (whence === SEEK_END && Fs.isFile(stream.node.mode)) {
|
|
475
770
|
const s = stream.node.live;
|
|
476
|
-
pos += s.loaded ? s.len : statOf(stream.node).size;
|
|
771
|
+
pos += rangedOf(stream.node)?.size() ?? (s.loaded ? s.len : statOf(stream.node).size);
|
|
477
772
|
}
|
|
478
773
|
if (pos < 0) throw new Fs.ErrnoError(ERRNO_BY_CODE.EINVAL);
|
|
479
774
|
return pos;
|
|
@@ -510,11 +805,15 @@ function ownedBy(plugin, node) {
|
|
|
510
805
|
function flushLiveVfs(Fs, plugin) {
|
|
511
806
|
for (const head of Fs.nameTable ?? []) {
|
|
512
807
|
for (let node = head; node; node = node.name_next ?? null) {
|
|
513
|
-
|
|
808
|
+
const s = node.live;
|
|
809
|
+
if (!ownedBy(plugin, node) || !s.dirty || !(s.data || s.ranged)) continue;
|
|
514
810
|
try {
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
811
|
+
if (s.ranged) s.ranged.flush();
|
|
812
|
+
else {
|
|
813
|
+
const bytes = s.data.slice(0, s.len);
|
|
814
|
+
node.mount.opts.bridge.writeFile(liveNodePath(node), bytes);
|
|
815
|
+
}
|
|
816
|
+
s.dirty = false;
|
|
518
817
|
} catch (err) {
|
|
519
818
|
throw toErrno(Fs, err);
|
|
520
819
|
}
|
|
@@ -532,8 +831,9 @@ function invalidateLiveVfs(Fs, plugin) {
|
|
|
532
831
|
s.listed = void 0;
|
|
533
832
|
if (s.openCount === 0) {
|
|
534
833
|
if (node !== node.mount.root && !node.mounted) drop.push(node);
|
|
535
|
-
} else if (s.
|
|
834
|
+
} else if (!s.dirty && !s.orphan) {
|
|
536
835
|
s.data = void 0;
|
|
836
|
+
s.ranged = void 0;
|
|
537
837
|
s.len = 0;
|
|
538
838
|
s.loaded = false;
|
|
539
839
|
}
|
|
@@ -652,6 +952,7 @@ var ERRNO_BY_CODE, EIO, S_IFDIR, S_IFREG, S_IFLNK, PERM_MASK, DEFAULT_DIR_PERM,
|
|
|
652
952
|
var init_live_vfs_fs = __esm({
|
|
653
953
|
"src/realm/live-vfs-fs.ts"() {
|
|
654
954
|
"use strict";
|
|
955
|
+
init_ranged();
|
|
655
956
|
init_types();
|
|
656
957
|
ERRNO_BY_CODE = {
|
|
657
958
|
EACCES: 2,
|
|
@@ -761,7 +1062,8 @@ function parseSyncFsStat(json) {
|
|
|
761
1062
|
...typeof s.ino === "number" ? { ino: s.ino } : {},
|
|
762
1063
|
...typeof s.dev === "number" ? { dev: s.dev } : {},
|
|
763
1064
|
...s.readonly === true ? { readonly: true } : {},
|
|
764
|
-
...typeof s.maxFile === "number" ? { maxFile: s.maxFile } : {}
|
|
1065
|
+
...typeof s.maxFile === "number" ? { maxFile: s.maxFile } : {},
|
|
1066
|
+
...s.ranged === true ? { ranged: true } : {}
|
|
765
1067
|
};
|
|
766
1068
|
}
|
|
767
1069
|
var SYNC_FS_REQUEST_TIMEOUT_MS;
|
|
@@ -870,7 +1172,7 @@ function createSyncSabTransport(sab, port, deps = {}) {
|
|
|
870
1172
|
}
|
|
871
1173
|
}
|
|
872
1174
|
return {
|
|
873
|
-
call(req, timeoutMs, label) {
|
|
1175
|
+
call(req, timeoutMs, label, transfer = []) {
|
|
874
1176
|
if (deps.memory) publishMemory(sab, deps.memory());
|
|
875
1177
|
const id = ++seq;
|
|
876
1178
|
const deadline = now() + timeoutMs;
|
|
@@ -883,7 +1185,8 @@ function createSyncSabTransport(sab, port, deps = {}) {
|
|
|
883
1185
|
Atomics.store(header, SAB_I_STATE, SAB_STATE_PENDING);
|
|
884
1186
|
const msg = offset === 0 ? { type: SYNC_SAB_REQ_MSG, id, req } : { type: SYNC_SAB_NEXT_MSG, id, offset };
|
|
885
1187
|
try {
|
|
886
|
-
port.postMessage(msg);
|
|
1188
|
+
if (offset === 0 && transfer.length > 0) port.postMessage(msg, transfer);
|
|
1189
|
+
else port.postMessage(msg);
|
|
887
1190
|
} catch {
|
|
888
1191
|
throw syncError("EIO", label);
|
|
889
1192
|
}
|
|
@@ -916,8 +1219,8 @@ function errnoError(code2, path) {
|
|
|
916
1219
|
}
|
|
917
1220
|
function createSyncFsSabBridge(transport, opts = {}) {
|
|
918
1221
|
const timeoutMs = opts.timeoutMs ?? SYNC_FS_REQUEST_TIMEOUT_MS;
|
|
919
|
-
function run(req, path) {
|
|
920
|
-
const result = transport.call(req, timeoutMs, `sync-sab bridge, '${path}'
|
|
1222
|
+
function run(req, path, transfer) {
|
|
1223
|
+
const result = transport.call(req, timeoutMs, `sync-sab bridge, '${path}'`, transfer);
|
|
921
1224
|
if (!result.ok) throw errnoError(result.errno, path);
|
|
922
1225
|
return result;
|
|
923
1226
|
}
|
|
@@ -1001,7 +1304,16 @@ function createSyncFsSabBridge(transport, opts = {}) {
|
|
|
1001
1304
|
hold: (path, held) => {
|
|
1002
1305
|
run({ op: "hold", path, mode: held ? 1 : 0 }, path);
|
|
1003
1306
|
},
|
|
1004
|
-
statfs: (path = "/") => parseSyncFsUsage(json({ op: "statfs", path }, path))
|
|
1307
|
+
statfs: (path = "/") => parseSyncFsUsage(json({ op: "statfs", path }, path)),
|
|
1308
|
+
pread: (path, offset, length) => bytes({ op: "pread", path, offset, length }, path),
|
|
1309
|
+
pwrite: (path, offset, body, transfer) => {
|
|
1310
|
+
const whole = body.byteOffset === 0 && body.byteLength === body.buffer.byteLength;
|
|
1311
|
+
const owned = transfer && whole && body.buffer instanceof ArrayBuffer;
|
|
1312
|
+
run({ op: "pwrite", path, offset, body }, path, owned ? [body.buffer] : []);
|
|
1313
|
+
},
|
|
1314
|
+
truncate: (path, length) => {
|
|
1315
|
+
run({ op: "truncate", path, length }, path);
|
|
1316
|
+
}
|
|
1005
1317
|
};
|
|
1006
1318
|
}
|
|
1007
1319
|
var init_sync_sab_bridge = __esm({
|
|
@@ -3468,6 +3780,11 @@ function cachingBridge(bridge, now = () => performance.now()) {
|
|
|
3468
3780
|
symlink: (target, link) => mutating(() => bridge.symlink(target, link)),
|
|
3469
3781
|
chmod: (p, mode) => mutating(() => bridge.chmod(p, mode)),
|
|
3470
3782
|
utimes: (p, a, m) => mutating(() => bridge.utimes(p, a, m)),
|
|
3783
|
+
...bridge.pread && bridge.pwrite && bridge.truncate ? {
|
|
3784
|
+
pread: bridge.pread.bind(bridge),
|
|
3785
|
+
pwrite: (p, at, bytes, transfer) => mutating(() => bridge.pwrite?.(p, at, bytes, transfer)),
|
|
3786
|
+
truncate: (p, size) => mutating(() => bridge.truncate?.(p, size))
|
|
3787
|
+
} : {},
|
|
3471
3788
|
invalidate
|
|
3472
3789
|
};
|
|
3473
3790
|
}
|
|
@@ -3475,6 +3792,7 @@ var WasiError, FileBuffer, LocalFile, MISS_TTL_MS;
|
|
|
3475
3792
|
var init_wasi_files = __esm({
|
|
3476
3793
|
"src/process/wasi/wasi-files.ts"() {
|
|
3477
3794
|
"use strict";
|
|
3795
|
+
init_ranged();
|
|
3478
3796
|
WasiError = class extends Error {
|
|
3479
3797
|
code;
|
|
3480
3798
|
constructor(code2) {
|
|
@@ -3489,17 +3807,37 @@ var init_wasi_files = __esm({
|
|
|
3489
3807
|
orphaned = false;
|
|
3490
3808
|
opens = 0;
|
|
3491
3809
|
fs;
|
|
3492
|
-
|
|
3810
|
+
where;
|
|
3811
|
+
ranged;
|
|
3493
3812
|
maxFile;
|
|
3494
|
-
constructor(fs, path, empty, maxFile) {
|
|
3813
|
+
constructor(fs, path, empty, maxFile, size) {
|
|
3495
3814
|
this.fs = fs;
|
|
3496
|
-
this.
|
|
3815
|
+
this.where = path;
|
|
3497
3816
|
this.maxFile = maxFile;
|
|
3498
|
-
|
|
3817
|
+
const { pread, pwrite, truncate } = fs;
|
|
3818
|
+
if (size !== void 0 && pread && pwrite && truncate) {
|
|
3819
|
+
const io = { pread: pread.bind(fs), pwrite: pwrite.bind(fs), truncate: truncate.bind(fs) };
|
|
3820
|
+
this.ranged = new RangedFile(io, path, size);
|
|
3821
|
+
if (empty) this.truncate(0);
|
|
3822
|
+
} else if (empty) {
|
|
3499
3823
|
this.data = new Uint8Array(0);
|
|
3500
3824
|
this.dirty = true;
|
|
3501
3825
|
}
|
|
3502
3826
|
}
|
|
3827
|
+
get path() {
|
|
3828
|
+
return this.where;
|
|
3829
|
+
}
|
|
3830
|
+
set path(path) {
|
|
3831
|
+
this.where = path;
|
|
3832
|
+
if (this.ranged) this.ranged.path = path;
|
|
3833
|
+
}
|
|
3834
|
+
get isRanged() {
|
|
3835
|
+
return this.ranged !== void 0;
|
|
3836
|
+
}
|
|
3837
|
+
keep() {
|
|
3838
|
+
if (this.ranged) this.ranged.pin();
|
|
3839
|
+
else this.load();
|
|
3840
|
+
}
|
|
3503
3841
|
load() {
|
|
3504
3842
|
if (!this.data) {
|
|
3505
3843
|
this.data = this.fs.readFile(this.path);
|
|
@@ -3508,10 +3846,12 @@ var init_wasi_files = __esm({
|
|
|
3508
3846
|
return this.data;
|
|
3509
3847
|
}
|
|
3510
3848
|
size() {
|
|
3849
|
+
if (this.ranged) return this.ranged.size();
|
|
3511
3850
|
this.load();
|
|
3512
3851
|
return this.length;
|
|
3513
3852
|
}
|
|
3514
3853
|
pread(max, at) {
|
|
3854
|
+
if (this.ranged) return this.ranged.read(at, max);
|
|
3515
3855
|
const bytes = this.load();
|
|
3516
3856
|
const n = Math.max(0, Math.min(max, this.length - at));
|
|
3517
3857
|
return bytes.subarray(at, at + n);
|
|
@@ -3523,22 +3863,30 @@ var init_wasi_files = __esm({
|
|
|
3523
3863
|
if (bytes.length === 0) return 0;
|
|
3524
3864
|
const end = at + bytes.length;
|
|
3525
3865
|
this.fits(end);
|
|
3866
|
+
this.dirty = true;
|
|
3867
|
+
if (this.ranged) {
|
|
3868
|
+
this.ranged.write(at, bytes);
|
|
3869
|
+
return bytes.length;
|
|
3870
|
+
}
|
|
3526
3871
|
this.load();
|
|
3527
3872
|
this.ensure(end);
|
|
3528
3873
|
const buf = this.data;
|
|
3529
3874
|
if (at > this.length) buf.fill(0, this.length, at);
|
|
3530
3875
|
buf.set(bytes, at);
|
|
3531
3876
|
this.length = Math.max(this.length, end);
|
|
3532
|
-
this.dirty = true;
|
|
3533
3877
|
return bytes.length;
|
|
3534
3878
|
}
|
|
3535
3879
|
truncate(size) {
|
|
3536
3880
|
this.fits(size);
|
|
3881
|
+
this.dirty = true;
|
|
3882
|
+
if (this.ranged) {
|
|
3883
|
+
this.ranged.truncate(size);
|
|
3884
|
+
return;
|
|
3885
|
+
}
|
|
3537
3886
|
this.load();
|
|
3538
3887
|
this.ensure(size);
|
|
3539
3888
|
if (size > this.length) this.data.fill(0, this.length, size);
|
|
3540
3889
|
this.length = size;
|
|
3541
|
-
this.dirty = true;
|
|
3542
3890
|
}
|
|
3543
3891
|
ensure(need) {
|
|
3544
3892
|
const cur = this.data;
|
|
@@ -3549,6 +3897,7 @@ var init_wasi_files = __esm({
|
|
|
3549
3897
|
}
|
|
3550
3898
|
orphan() {
|
|
3551
3899
|
this.orphaned = true;
|
|
3900
|
+
this.ranged?.pin();
|
|
3552
3901
|
}
|
|
3553
3902
|
isOrphan() {
|
|
3554
3903
|
return this.orphaned;
|
|
@@ -3557,11 +3906,14 @@ var init_wasi_files = __esm({
|
|
|
3557
3906
|
return this.dirty;
|
|
3558
3907
|
}
|
|
3559
3908
|
contents() {
|
|
3909
|
+
if (this.ranged) return this.ranged.read(0, this.ranged.size());
|
|
3560
3910
|
return this.load().slice(0, this.length);
|
|
3561
3911
|
}
|
|
3562
3912
|
flush() {
|
|
3563
|
-
if (this.orphaned || !this.dirty
|
|
3564
|
-
|
|
3913
|
+
if (this.orphaned || !this.dirty) return;
|
|
3914
|
+
if (this.ranged) this.ranged.flush();
|
|
3915
|
+
else if (this.data) this.fs.writeFile(this.path, this.data.slice(0, this.length));
|
|
3916
|
+
else return;
|
|
3565
3917
|
this.dirty = false;
|
|
3566
3918
|
}
|
|
3567
3919
|
};
|
|
@@ -3771,7 +4123,8 @@ function openAccess(existing, oflags, rights) {
|
|
|
3771
4123
|
}
|
|
3772
4124
|
function promoteRequest(fd, f, handed) {
|
|
3773
4125
|
const orphan = f.buffer.isOrphan();
|
|
3774
|
-
|
|
4126
|
+
if (!orphan && f.buffer.isRanged) f.buffer.flush();
|
|
4127
|
+
const joins = !orphan && (handed.has(f.buffer) || f.buffer.isRanged);
|
|
3775
4128
|
return {
|
|
3776
4129
|
op: "fd-promote",
|
|
3777
4130
|
fd,
|
|
@@ -4113,7 +4466,7 @@ var init_wasi_fds = __esm({
|
|
|
4113
4466
|
if (this.shared) this.kernel.call({ op: "fd-path-flush", path });
|
|
4114
4467
|
}
|
|
4115
4468
|
unlinking(path) {
|
|
4116
|
-
this.buffers.get(path)?.
|
|
4469
|
+
this.buffers.get(path)?.keep();
|
|
4117
4470
|
if (this.shared) this.kernel.call({ op: "fd-path-unlinking", path });
|
|
4118
4471
|
}
|
|
4119
4472
|
unlinked(path) {
|
|
@@ -4174,7 +4527,8 @@ var init_wasi_fds = __esm({
|
|
|
4174
4527
|
} else {
|
|
4175
4528
|
if (!existing) this.fs.writeFile(path, new Uint8Array(0));
|
|
4176
4529
|
const empty = !existing || (oflags & OFLAGS.TRUNC) !== 0;
|
|
4177
|
-
|
|
4530
|
+
const st = existing ?? this.fs.stat(path);
|
|
4531
|
+
buffer = new FileBuffer(this.fs, path, empty, st.maxFile, st.ranged ? st.size : void 0);
|
|
4178
4532
|
this.buffers.set(path, buffer);
|
|
4179
4533
|
}
|
|
4180
4534
|
buffer.opens++;
|
|
@@ -5486,7 +5840,7 @@ function align(n, to) {
|
|
|
5486
5840
|
return Math.ceil(n / to) * to;
|
|
5487
5841
|
}
|
|
5488
5842
|
function growTo(memory, bytes) {
|
|
5489
|
-
const pages2 = Math.ceil(bytes /
|
|
5843
|
+
const pages2 = Math.ceil(bytes / PAGE2) - memory.buffer.byteLength / PAGE2;
|
|
5490
5844
|
if (pages2 > 0) memory.grow(pages2);
|
|
5491
5845
|
}
|
|
5492
5846
|
function growTable(table, length) {
|
|
@@ -5496,14 +5850,14 @@ function call(instance, name) {
|
|
|
5496
5850
|
const fn = instance.exports[name];
|
|
5497
5851
|
if (typeof fn === "function") fn();
|
|
5498
5852
|
}
|
|
5499
|
-
var TABLE_BASE,
|
|
5853
|
+
var TABLE_BASE, PAGE2, STACK_SIZE, LIBRARY_DIRS, DlError, WasixLinker;
|
|
5500
5854
|
var init_wasix_linker = __esm({
|
|
5501
5855
|
"src/process/wasi/wasix-linker.ts"() {
|
|
5502
5856
|
"use strict";
|
|
5503
5857
|
init_dylink();
|
|
5504
5858
|
init_wasi_files();
|
|
5505
5859
|
TABLE_BASE = 1;
|
|
5506
|
-
|
|
5860
|
+
PAGE2 = 65536;
|
|
5507
5861
|
STACK_SIZE = 8 * 1024 * 1024;
|
|
5508
5862
|
LIBRARY_DIRS = ["/lib", "/usr/lib", "/usr/local/lib"];
|
|
5509
5863
|
DlError = class extends Error {
|