@ai-ecoverse/slicc-kernel 1.119.0 → 1.119.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
@@ -932,7 +932,7 @@ Not covered: hard links (OPFS cannot share contents between names; they work onl
932
932
 
933
933
  Reads retry briefly when a concurrent write has invalidated the OPFS file snapshot (`NotReadableError`).
934
934
 
935
- A kernel caches the directory handles it has walked and the sidecar entries it has read. Its own changes keep both caches current, and the other kernels on the origin hear of them through a `BroadcastChannel` named after the database (one for the sidecar, one for directories). A cached directory is checked against its path (`resolve()`) at most once a second before a lookup goes through it, so a directory moved, removed or replaced by another writer, such as a page using the OPFS API, is found at its new place or reported missing within a second. It also keeps the file handles it has looked up (up to 4,096, the least recently used dropped first) for a second after each lookup. Before it uses one, it reads the file through it, which is the read a `stat` needs anyway, and that read serves the handle's uses of the next 2 ms. So a file another writer removed is missing, and a rewritten one shows its new contents, within 2 ms. The kernel's own writes, truncates, rewrites and renames drop the read at once, and a read that started before an own change isn't kept, so the kernel's own changes always show at once. One replaced by a directory is seen as a directory within a second. Its own changes, and the other kernels' notices, drop the handles they touch at once. A lookup of a directory it has cached and checked within the second is answered from the cache, so a directory replaced by another writer is seen as replaced within a second, as above. A name it has just found missing stays missing for 2 ms, which serves the several checks a single create makes of a name that isn't there yet (about ten per file in a pnpm install); its own creates, renames and links in that directory end that at once, so only a file another kernel or a page using the OPFS API makes in those 2 ms is seen up to 2 ms late.
935
+ A kernel caches the directory handles it has walked and the sidecar entries it has read. Its own changes keep both caches current, and the other kernels on the origin hear of them through a `BroadcastChannel` named after the database (one for the sidecar, one for directories). A cached directory is checked against its path (`resolve()`) at most once a second before a lookup goes through it, so a directory moved, removed or replaced by another writer, such as a page using the OPFS API, is found at its new place or reported missing within a second. It also keeps the file handles it has looked up (up to 4,096, the least recently used dropped first) for a second after each lookup. Before it uses one, it reads the file through it, which is the read a `stat` needs anyway, and that read serves the handle's uses of the next 2 ms. So a file another writer removed is missing, and a rewritten one shows its new contents, within 2 ms. The kernel's own writes, truncates, rewrites and renames drop the read at once, and a read that started before an own change isn't kept, so the kernel's own changes always show at once. One replaced by a directory is seen as a directory within a second. Its own changes, and the other kernels' notices, drop the handles they touch at once. A lookup of a directory it has cached and checked within the second is answered from the cache, so a directory replaced by another writer is seen as replaced within a second, as above. A name it has just found missing stays missing for 2 ms, which serves the several checks a single create makes of a name that isn't there yet (about ten per file in a pnpm install); its own creates, renames and links in that directory end that at once, so only a file another kernel or a page using the OPFS API makes in those 2 ms is seen up to 2 ms late. Both 2 ms windows are off while another kernel shares the root (a second tab on the origin, found through the watch channel's join handshake, and until that handshake is done), so between tabs every look is fresh, as before 1.113.0; only a page writing through the OPFS API itself can still be seen up to 2 ms late ([#945](https://github.com/ai-ecoverse/slicc-kernel/issues/945)). A single tab keeps them.
936
936
 
937
937
  The filesystem is our own rather than [ZenFS](https://github.com/zen-fs/core) (which SLICC uses), because OPFS stays the single source of truth: other writers, such as the BIOS installing packages or a page writing files, need no index to stay consistent with, and nothing is preloaded into memory at mount. POSIX metadata lives in the IndexedDB sidecar described above, which has per-entry transactions instead of one JSON file rewritten on every change.
938
938
 
@@ -872,6 +872,7 @@ var RemoteWatch = class {
872
872
  pruned = 0;
873
873
  joined;
874
874
  met;
875
+ settled = false;
875
876
  quiet;
876
877
  constructor(name2, options = {}) {
877
878
  this.name = name2;
@@ -887,7 +888,9 @@ var RemoteWatch = class {
887
888
  });
888
889
  if (!this.locks) resolve2();
889
890
  });
890
- this.joined = granted2.then(() => this.join());
891
+ this.joined = granted2.then(() => this.join()).then(() => {
892
+ this.settled = true;
893
+ });
891
894
  this.channel.postMessage({ hello: this.tab });
892
895
  }
893
896
  async join() {
@@ -909,6 +912,9 @@ var RemoteWatch = class {
909
912
  await this.joined;
910
913
  return this.peers.size > 0;
911
914
  }
915
+ crowded() {
916
+ return !this.settled || this.peers.size > 0;
917
+ }
912
918
  lockOf(tab) {
913
919
  return `${this.name}:${tab}`;
914
920
  }
@@ -1493,7 +1499,7 @@ var OpfsFs = class {
1493
1499
  const kept = this.dirs.get(path);
1494
1500
  if (kept && await this.current(path, kept)) return kept;
1495
1501
  const gone = this.absent.get(path);
1496
- if (gone !== void 0 && performance.now() - gone < ABSENT_MS) {
1502
+ if (gone !== void 0 && !this.shared() && performance.now() - gone < ABSENT_MS) {
1497
1503
  throw translate({ name: "NotFoundError" }, path);
1498
1504
  }
1499
1505
  const seen = this.changes;
@@ -1680,7 +1686,11 @@ var OpfsFs = class {
1680
1686
  if (this.dirTimes.get(path) === ms) this.dirTimes.delete(path);
1681
1687
  }
1682
1688
  }
1689
+ shared() {
1690
+ return this.remote?.crowded() === true;
1691
+ }
1683
1692
  glanced(handle) {
1693
+ if (this.shared()) return void 0;
1684
1694
  const seen = this.glances.get(handle);
1685
1695
  const fresh2 = seen && seen.changes === this.changes && performance.now() - seen.at < GLANCE_MS;
1686
1696
  return fresh2 ? seen.file : void 0;
@@ -6366,7 +6376,7 @@ function satisfies(version, range2) {
6366
6376
  }
6367
6377
 
6368
6378
  // src/version.ts
6369
- var KERNEL_VERSION = true ? "1.119.0" : "0.0.0-dev";
6379
+ var KERNEL_VERSION = true ? "1.119.2" : "0.0.0-dev";
6370
6380
  var OS_RELEASE = "6.0.0-slicc";
6371
6381
  function procVersion() {
6372
6382
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC