@ai-ecoverse/slicc-kernel 1.26.1 → 1.26.2
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 +2 -2
- package/dist/kernel-worker.js +17 -6
- package/dist/kernel-worker.js.map +2 -2
- package/dist/node-process-worker.js +172 -157
- package/dist/node-process-worker.js.map +4 -4
- package/dist/node.js +18 -6
- package/dist/node.js.map +2 -2
- package/dist/process-worker.js +172 -157
- package/dist/process-worker.js.map +4 -4
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -120,7 +120,7 @@ const { status, stdout } = await kernel.run(['bash', '-c', 'echo hi'], { cwd: '/
|
|
|
120
120
|
kernel.terminate();
|
|
121
121
|
```
|
|
122
122
|
|
|
123
|
-
`createNodeKernel({ root, modules, env, network, worker, processMounts, fstabRetries, cdp })` takes the options of `createKernel` except `metadata`, and `fstabRetries`, the delays in ms between tries of a failing `/etc/fstab` line (default `[1000, 4000, 16000]`). `root` is an in-memory directory by default (`memoryRoot()` makes another), which keeps each file in 1 MiB chunks, and POSIX metadata stays in memory. Processes and threads run on `worker_threads`. The kernel has `run`, `openTerminal` and `terminate` as above, plus `root`, `writeFile(path, data)` (creating the parent directories) and `readFile(path)` to put files in place and read results. `nodeTransport()` is `fetchTransport()` with Node's `fetch`, which no CORS binds (`crossOrigin: 'any'`). `connect()` and `attachKernel` work as in the browser: the port is a `worker_threads` `MessagePort`, which a worker thread can attach with, and `terminate()` ends every attached client.
|
|
123
|
+
`createNodeKernel({ root, modules, env, network, worker, processMounts, fstabRetries, cdp, hostfs })` takes the options of `createKernel` except `metadata`, and `fstabRetries`, the delays in ms between tries of a failing `/etc/fstab` line (default `[1000, 4000, 16000]`). `root` is an in-memory directory by default (`memoryRoot()` makes another), which keeps each file in 1 MiB chunks, and POSIX metadata stays in memory. Processes and threads run on `worker_threads`. The kernel has `run`, `openTerminal` and `terminate` as above, plus `root`, `writeFile(path, data)` (creating the parent directories) and `readFile(path)` to put files in place and read results. `nodeTransport()` is `fetchTransport()` with Node's `fetch`, which no CORS binds (`crossOrigin: 'any'`). `connect()` and `attachKernel` work as in the browser: the port is a `worker_threads` `MessagePort`, which a worker thread can attach with, and `terminate()` ends every attached client.
|
|
124
124
|
|
|
125
125
|
## Commands
|
|
126
126
|
|
|
@@ -282,7 +282,7 @@ A `hostfs` mount is a folder exported by the local proxy ([slicc-node](https://g
|
|
|
282
282
|
- **Options:** `ro` mounts read-only, and `maxfile` caps file size as on any mount. There is no other size limit: reads and writes go in `maxIo` pieces (16 MiB unless the proxy says otherwise), so a file of any size the host can hold works. A proxy that advertises `ranges` in its grant (slicc-node 2.4, slicc-swift 1.4) makes the mount ranged, so programs read and write its files in pages and truncate through `setattr` `size`. With an older proxy files go whole, and a truncate on a ranged mount whose proxy was replaced by an older one is done by rewriting the file.
|
|
283
283
|
- **Changes on the host** arrive as invalidations on a watch stream (`POST /api/hostfs/watch`), so an edit made outside shows up on the next access without a remount.
|
|
284
284
|
- **Proxy loss:** when the watch stream ends, or is silent for 45 s, the kernel reconnects once at once. If that fails, the mount is `nomedium`, as with [removable media](#removable-media-fsa): operations fail with `ENOMEDIUM` (`ENODEV` for WASI), and the kernel keeps reconnecting with backoff (1 s to 30 s), so the folder comes back by itself when the proxy does. A mount made while the proxy is down starts as `nomedium`, and so does one whose grant or first watch takes more than 15 s; it comes up by itself when they arrive.
|
|
285
|
-
- **Consistency:** a file that changes on the host while a program reads it fails with `ESTALE`, and the kernel restarts the whole read (up to 3 times) instead of stitching two versions together. On a ranged mount an open file keeps the version it was opened at (its ETag) until it writes: a page fetched after the host changed the file fails the program's read with `ESTALE` instead of mixing versions.
|
|
285
|
+
- **Consistency:** a file that changes on the host while a program reads it fails with `ESTALE`, and the kernel restarts the whole read (up to 3 times) instead of stitching two versions together. On a ranged mount an open file keeps the version it was opened at (its ETag) until it writes, also when it is handed to a child process: a page fetched after the host changed the file fails the program's read with `ESTALE` ("Stale file handle") instead of mixing versions.
|
|
286
286
|
|
|
287
287
|
### Mounting from a program
|
|
288
288
|
|
package/dist/kernel-worker.js
CHANGED
|
@@ -5103,6 +5103,9 @@ var MountFs = class {
|
|
|
5103
5103
|
truncate: false,
|
|
5104
5104
|
exclusive: false,
|
|
5105
5105
|
...version !== void 0 ? { ifMatch: version } : {}
|
|
5106
|
+
}).catch((err) => {
|
|
5107
|
+
const gone = version !== void 0 && err.code === "ENOENT";
|
|
5108
|
+
throw gone ? errnoError("ESTALE", `${real} is gone from the host`) : err;
|
|
5106
5109
|
});
|
|
5107
5110
|
const chunk2 = mount.caps.maxIo ?? DEFAULT_IO;
|
|
5108
5111
|
const chunks = [];
|
|
@@ -6703,6 +6706,7 @@ function within3(path, root) {
|
|
|
6703
6706
|
var VfsNode = class {
|
|
6704
6707
|
data;
|
|
6705
6708
|
ranged;
|
|
6709
|
+
pin;
|
|
6706
6710
|
length = 0;
|
|
6707
6711
|
dirty = false;
|
|
6708
6712
|
queue = Promise.resolve();
|
|
@@ -6714,8 +6718,9 @@ var VfsNode = class {
|
|
|
6714
6718
|
fs;
|
|
6715
6719
|
path;
|
|
6716
6720
|
orphaned;
|
|
6717
|
-
constructor(fs, path, contents2, orphaned = false, dirty = false) {
|
|
6721
|
+
constructor(fs, path, contents2, orphaned = false, dirty = false, pin) {
|
|
6718
6722
|
this.fs = fs;
|
|
6723
|
+
this.pin = pin;
|
|
6719
6724
|
this.path = path;
|
|
6720
6725
|
this.orphaned = orphaned;
|
|
6721
6726
|
if (contents2 !== void 0) this.data = new Uint8Array(contents2);
|
|
@@ -6739,6 +6744,10 @@ var VfsNode = class {
|
|
|
6739
6744
|
if (this.revoked) throw new KernelError("EIO");
|
|
6740
6745
|
if (this.ranged || this.data) return this.ranged;
|
|
6741
6746
|
const io = rangedOps(this.fs);
|
|
6747
|
+
if (io && this.pin && !this.orphaned) {
|
|
6748
|
+
this.ranged = new AsyncRangedFile(io, this.path, this.pin.size, this.pin.version);
|
|
6749
|
+
return this.ranged;
|
|
6750
|
+
}
|
|
6742
6751
|
const st = io && !this.orphaned ? await this.fs.stat?.(this.path).catch(() => void 0) : void 0;
|
|
6743
6752
|
if (io && st?.ranged) {
|
|
6744
6753
|
this.ranged = new AsyncRangedFile(io, this.path, st.size ?? 0, st.version);
|
|
@@ -6878,10 +6887,10 @@ var VfsNodes = class {
|
|
|
6878
6887
|
constructor(fs) {
|
|
6879
6888
|
this.fs = fs;
|
|
6880
6889
|
}
|
|
6881
|
-
open(path) {
|
|
6890
|
+
open(path, pin) {
|
|
6882
6891
|
let node = this.byPath.get(path);
|
|
6883
6892
|
if (!node) {
|
|
6884
|
-
node = new VfsNode(this.fs, path);
|
|
6893
|
+
node = new VfsNode(this.fs, path, void 0, false, false, pin);
|
|
6885
6894
|
this.byPath.set(path, node);
|
|
6886
6895
|
}
|
|
6887
6896
|
node.opens++;
|
|
@@ -7002,7 +7011,7 @@ function vfsFile(fs, opts, nodes) {
|
|
|
7002
7011
|
const access = opts.flags & O_ACCMODE;
|
|
7003
7012
|
const readable = access !== O_WRONLY;
|
|
7004
7013
|
const writable = access === O_WRONLY || access === O_RDWR;
|
|
7005
|
-
const node = !nodes || opts.orphan ? new VfsNode(fs, opts.path, opts.contents, opts.orphan === true, opts.dirty === true) : opts.contents !== void 0 ? nodes.adopt(opts.path, opts.contents, opts.dirty === true) : nodes.open(opts.path);
|
|
7014
|
+
const node = !nodes || opts.orphan ? new VfsNode(fs, opts.path, opts.contents, opts.orphan === true, opts.dirty === true) : opts.contents !== void 0 ? nodes.adopt(opts.path, opts.contents, opts.dirty === true) : nodes.open(opts.path, opts.pin);
|
|
7006
7015
|
let openError;
|
|
7007
7016
|
const atOpen = (op) => {
|
|
7008
7017
|
void node.serial(op).catch((err) => {
|
|
@@ -7320,7 +7329,8 @@ var WasmProcess = class {
|
|
|
7320
7329
|
...req.contents !== void 0 ? { contents: req.contents } : {},
|
|
7321
7330
|
...req.orphan ? { orphan: true } : {},
|
|
7322
7331
|
...req.truncate ? { truncate: true } : {},
|
|
7323
|
-
...req.create ? { create: true } : {}
|
|
7332
|
+
...req.create ? { create: true } : {},
|
|
7333
|
+
...req.pin ? { pin: req.pin } : {}
|
|
7324
7334
|
},
|
|
7325
7335
|
this.nodes
|
|
7326
7336
|
);
|
|
@@ -7452,7 +7462,8 @@ var WasmProcess = class {
|
|
|
7452
7462
|
position: req.position ?? 0,
|
|
7453
7463
|
...req.contents !== void 0 ? { contents: req.contents } : {},
|
|
7454
7464
|
...req.orphan ? { orphan: true } : {},
|
|
7455
|
-
...req.dirty ? { dirty: true } : {}
|
|
7465
|
+
...req.dirty ? { dirty: true } : {},
|
|
7466
|
+
...req.pin ? { pin: req.pin } : {}
|
|
7456
7467
|
},
|
|
7457
7468
|
this.nodes
|
|
7458
7469
|
);
|