@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 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
 
@@ -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
  );