@ai-ecoverse/slicc-kernel 1.166.4 → 1.167.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/dist/node.js CHANGED
@@ -3684,7 +3684,7 @@ function satisfies(version, range2) {
3684
3684
  }
3685
3685
 
3686
3686
  // src/version.ts
3687
- var KERNEL_VERSION = true ? "1.166.4" : "0.0.0-dev";
3687
+ var KERNEL_VERSION = true ? "1.167.0" : "0.0.0-dev";
3688
3688
  var OS_RELEASE = "6.0.0-slicc";
3689
3689
  function procVersion() {
3690
3690
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -4648,8 +4648,41 @@ var within2 = (path, target) => path === target || target === "/" || path.starts
4648
4648
  var TOUCHED_MAX = 4096;
4649
4649
  var parentOf2 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
4650
4650
  var PEER_RM_MS = 1e3;
4651
+ var SHARED_ACK_MS = 24 * 60 * 60 * 1e3;
4652
+ var delay = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
4651
4653
  var PEER_RENAME_MS = 1e4;
4652
4654
  var PEER_GATE_MS = PEER_RENAME_MS + 5e3;
4655
+ var SHARED_PREFIX = "shared.";
4656
+ var keptLock = (hidden) => `slicc-kept:${hidden}`;
4657
+ function sharedKept(hidden) {
4658
+ const at = `/${UNLINKED_DIR}/${SHARED_PREFIX}`;
4659
+ return hidden.startsWith(at) && /^[0-9a-f]+$/.test(hidden.slice(at.length));
4660
+ }
4661
+ function holdShared(locks, name2) {
4662
+ if (!locks) return Promise.resolve(async () => void 0);
4663
+ return new Promise((resolve2) => {
4664
+ const settled = locks.request(name2, { mode: "shared" }, () => {
4665
+ const { promise, resolve: done4 } = Promise.withResolvers();
4666
+ resolve2(async () => {
4667
+ done4();
4668
+ await settled.catch(() => void 0);
4669
+ });
4670
+ return promise;
4671
+ });
4672
+ });
4673
+ }
4674
+ async function whenLast(locks, name2, op) {
4675
+ if (!locks) {
4676
+ await op();
4677
+ return true;
4678
+ }
4679
+ let free = false;
4680
+ await locks.request(name2, { mode: "exclusive", ifAvailable: true }, async (lock) => {
4681
+ free = lock !== null;
4682
+ if (free) await op();
4683
+ });
4684
+ return free;
4685
+ }
4653
4686
  var lockName = (instance) => `slicc-unlinked:${instance}`;
4654
4687
  var dirOf = (root) => root === "/" ? `/${UNLINKED_DIR}` : `${root}/${UNLINKED_DIR}`;
4655
4688
  var PathGate = class {
@@ -4965,52 +4998,124 @@ var UnlinkedKeeper = class {
4965
4998
  void peers.ask(tab, { kept: { items: [], paths } }, PEER_RM_MS);
4966
4999
  throw fsError("EBUSY", `${target}: open in another tab that did not answer`);
4967
5000
  }
4968
- const { whole, sends } = await this.setAside(target, asked);
4969
- return { whole, undoing: (op) => this.undoing(op, peers, sends, heard) };
5001
+ const { whole, sends, shared } = await this.setAside(target, asked);
5002
+ return { whole, undoing: (op) => this.undoing(op, peers, sends, heard, shared) };
4970
5003
  }
4971
5004
  async setAside(target, asked) {
4972
5005
  const mine = this.heldWithin(target);
4973
- const taken = /* @__PURE__ */ new Set();
4974
- let whole = false;
5006
+ const tabsOf = /* @__PURE__ */ new Map();
5007
+ for (const { holders } of asked)
5008
+ for (const { path } of holders) tabsOf.set(path, (tabsOf.get(path) ?? 0) + 1);
5009
+ const done4 = /* @__PURE__ */ new Map();
5010
+ const shared = [];
4975
5011
  const sends = [];
4976
5012
  for (const { tab, holders, paths } of asked) {
4977
5013
  const items = [];
4978
5014
  for (const holder of holders) {
4979
- const free = !mine.has(holder.path) && !taken.has(holder.path);
4980
- const hidden = free ? await this.asideFor(holder.path, holder.instance) : void 0;
4981
- if (hidden !== void 0) {
4982
- taken.add(holder.path);
4983
- if (holder.path === target) whole = true;
5015
+ if (!done4.has(holder.path)) {
5016
+ const many = mine.has(holder.path) || (tabsOf.get(holder.path) ?? 0) > 1;
5017
+ done4.set(holder.path, await this.asideOne(holder, many, mine, shared));
4984
5018
  }
4985
- items.push({ path: holder.path, hidden, fid: holder.fid });
5019
+ items.push({ path: holder.path, hidden: done4.get(holder.path), fid: holder.fid });
4986
5020
  }
4987
5021
  sends.push({ tab, items, paths });
4988
5022
  }
4989
- return { whole, sends };
5023
+ return { whole: done4.get(target) !== void 0, sends, shared };
5024
+ }
5025
+ async asideOne(holder, many, mine, shared) {
5026
+ if (!many) return this.asideFor(holder.path, holder.instance);
5027
+ const one = await this.sharedAside(holder.path, mine);
5028
+ if (one) shared.push(one);
5029
+ return one?.hidden;
5030
+ }
5031
+ async sharedAside(path, mine) {
5032
+ const hidden = `${dirOf("/")}/${SHARED_PREFIX}${crypto.randomUUID().replaceAll("-", "")}`;
5033
+ const release = await holdShared(this.sharedLocks(), keptLock(hidden));
5034
+ const moved2 = await this.serial(async () => {
5035
+ try {
5036
+ const owner = this.dirOwner;
5037
+ await this.fs.mkdir(dirOf("/"), { recursive: true, ...owner ? { owner } : {} });
5038
+ await this.fs.rename(path, hidden);
5039
+ return true;
5040
+ } catch {
5041
+ return false;
5042
+ }
5043
+ });
5044
+ if (!moved2) {
5045
+ await release();
5046
+ return void 0;
5047
+ }
5048
+ const local2 = mine.get(path) ?? [];
5049
+ const file = local2.length > 0 ? await this.sharedFile(hidden, local2.length) : void 0;
5050
+ if (file) for (const holder of local2) holder.keep(path, file);
5051
+ return { path, hidden, release, local: local2, file };
5052
+ }
5053
+ async sharedFile(hidden, refs) {
5054
+ const locks = this.sharedLocks();
5055
+ const mine = await holdShared(locks, keptLock(hidden));
5056
+ let left = refs;
5057
+ return {
5058
+ hidden,
5059
+ release: () => {
5060
+ if (--left > 0) return;
5061
+ void mine().then(() => this.dropIfLast(hidden));
5062
+ }
5063
+ };
5064
+ }
5065
+ dropIfLast(hidden) {
5066
+ return this.serial(
5067
+ () => whenLast(this.sharedLocks(), keptLock(hidden), () => this.drop(hidden))
5068
+ );
5069
+ }
5070
+ sharedLocks() {
5071
+ return this.locks;
4990
5072
  }
4991
- async undoing(op, peers, sends, heard) {
5073
+ async undoing(op, peers, sends, heard, shared = []) {
4992
5074
  let failed3;
4993
5075
  let out;
4994
5076
  try {
4995
5077
  out = await op();
4996
5078
  } catch (err) {
4997
5079
  failed3 = err ?? new Error("failed");
4998
- for (const send2 of sends) {
4999
- for (const item of send2.items) {
5000
- const { hidden, path } = item;
5001
- if (hidden !== void 0 && await this.moveBack(hidden, path)) item.hidden = void 0;
5002
- }
5003
- }
5080
+ await this.rollBackAsides(sends, shared);
5004
5081
  }
5082
+ const hiddenShared = new Set(shared.map((one) => one.hidden));
5083
+ const answers2 = sends.map(({ tab, items, paths }) => {
5084
+ const keeps = items.some((item) => item.hidden && hiddenShared.has(item.hidden));
5085
+ return {
5086
+ keeps,
5087
+ told: peers.ask(tab, { kept: { items, paths } }, keeps ? SHARED_ACK_MS : PEER_RM_MS)
5088
+ };
5089
+ });
5005
5090
  await Promise.all(
5006
- sends.map(({ tab, items, paths }, i) => {
5007
- const told = peers.ask(tab, { kept: { items, paths } }, PEER_RM_MS);
5008
- return heard[i] ? told : void 0;
5009
- })
5091
+ answers2.map(({ told }, i) => heard[i] ? Promise.race([told, delay(PEER_RM_MS)]) : void 0)
5010
5092
  );
5093
+ for (const one of shared) {
5094
+ const waits = answers2.filter(
5095
+ ({ keeps }, i) => keeps && sends[i]?.items.some((item) => item.hidden === one.hidden)
5096
+ );
5097
+ const done4 = () => one.release().then(() => this.dropIfLast(one.hidden));
5098
+ void Promise.all(waits.map(({ told }) => told)).then(done4, done4);
5099
+ }
5011
5100
  if (failed3 !== void 0) throw failed3;
5012
5101
  return out;
5013
5102
  }
5103
+ async rollBackAsides(sends, shared) {
5104
+ const back = /* @__PURE__ */ new Map();
5105
+ for (const item of sends.flatMap((send2) => send2.items)) {
5106
+ const { hidden, path } = item;
5107
+ if (hidden === void 0) continue;
5108
+ if (!back.has(hidden)) back.set(hidden, await this.moveBack(hidden, path));
5109
+ if (back.get(hidden)) item.hidden = void 0;
5110
+ }
5111
+ for (const { hidden, path, local: local2, file } of shared) {
5112
+ if (!back.get(hidden) || !file) continue;
5113
+ for (const holder of local2) {
5114
+ holder.unkeep(path, file);
5115
+ file.release();
5116
+ }
5117
+ }
5118
+ }
5014
5119
  moveBack(hidden, path) {
5015
5120
  return this.serial(async () => {
5016
5121
  if (await this.present(path)) return false;
@@ -5119,6 +5224,15 @@ var UnlinkedKeeper = class {
5119
5224
  for (const name2 of names2) {
5120
5225
  const id2 = name2.slice(0, name2.lastIndexOf("."));
5121
5226
  const at = id2.indexOf("~");
5227
+ if (name2.startsWith(SHARED_PREFIX)) {
5228
+ const at2 = `${dir}/${name2}`;
5229
+ await whenLast(
5230
+ this.sharedLocks(),
5231
+ keptLock(at2),
5232
+ () => this.fs.rm(at2, { recursive: true }).catch(() => void 0)
5233
+ );
5234
+ continue;
5235
+ }
5122
5236
  const dead = id2 !== this.instance && (at < 0 ? held !== void 0 && !held.has(lockName(id2)) : owner?.alive(id2.slice(0, at)) === false);
5123
5237
  if (dead) await this.fs.rm(`${dir}/${name2}`, { recursive: true }).catch(() => void 0);
5124
5238
  }
@@ -20273,13 +20387,13 @@ var VfsNode = class {
20273
20387
  this.recount();
20274
20388
  if (!this.orphaned) this.onDirty?.();
20275
20389
  if (this.writeBack !== void 0 || this.orphaned) return;
20276
- const delay = Math.max(WRITEBACK_MS, this.writeBackCost * WRITEBACK_COST_FACTOR);
20390
+ const delay2 = Math.max(WRITEBACK_MS, this.writeBackCost * WRITEBACK_COST_FACTOR);
20277
20391
  this.writeBack = setTimeout(() => {
20278
20392
  this.writeBack = void 0;
20279
20393
  this.serial(() => this.flush()).catch(() => {
20280
20394
  this.failed = true;
20281
20395
  });
20282
- }, delay);
20396
+ }, delay2);
20283
20397
  }
20284
20398
  ensure(need2) {
20285
20399
  const cur = this.data ?? new Uint8Array(0);
@@ -23955,6 +24069,7 @@ var RemoteWatch = class {
23955
24069
  };
23956
24070
  const left = /* @__PURE__ */ new Set([to]);
23957
24071
  const timer = setTimeout(done4, cap);
24072
+ timer.unref?.();
23958
24073
  this.waiting.set(seq2, { left, done: done4 });
23959
24074
  });
23960
24075
  }
@@ -23996,6 +24111,9 @@ var RemoteWatch = class {
23996
24111
  this.keeps?.left(tab);
23997
24112
  this.ackers.delete(tab);
23998
24113
  this.holders.delete(tab);
24114
+ for (const wait2 of [...this.waiting.values()]) {
24115
+ if (wait2.left.delete(tab) && wait2.left.size === 0) wait2.done();
24116
+ }
23999
24117
  }
24000
24118
  }
24001
24119
  this.rebuild();
@@ -25550,9 +25668,9 @@ async function unlocked(name2, op) {
25550
25668
  return await op();
25551
25669
  } catch (err) {
25552
25670
  if (!LOCKED.has(err?.name)) throw err;
25553
- const delay = SYNC_BACKOFF_MS[attempt];
25554
- if (delay === void 0) throw fsError("EBUSY", name2);
25555
- await new Promise((resolve2) => setTimeout(resolve2, delay));
25671
+ const delay2 = SYNC_BACKOFF_MS[attempt];
25672
+ if (delay2 === void 0) throw fsError("EBUSY", name2);
25673
+ await new Promise((resolve2) => setTimeout(resolve2, delay2));
25556
25674
  }
25557
25675
  }
25558
25676
  }
@@ -25563,10 +25681,10 @@ async function openSync(handle) {
25563
25681
  try {
25564
25682
  return await sync.call(handle, { mode: "readwrite-unsafe" });
25565
25683
  } catch (err) {
25566
- const delay = SYNC_BACKOFF_MS[attempt];
25684
+ const delay2 = SYNC_BACKOFF_MS[attempt];
25567
25685
  if (!LOCKED.has(err?.name)) throw err;
25568
- if (delay === void 0) return void 0;
25569
- await new Promise((resolve2) => setTimeout(resolve2, delay));
25686
+ if (delay2 === void 0) return void 0;
25687
+ await new Promise((resolve2) => setTimeout(resolve2, delay2));
25570
25688
  }
25571
25689
  }
25572
25690
  }
@@ -27571,9 +27689,9 @@ var OpfsFs = class {
27571
27689
  if (!failed3) return true;
27572
27690
  const error = failed3.err?.name;
27573
27691
  if (handle.kind !== "file" || !LOCKED.has(error)) return false;
27574
- const delay = SYNC_BACKOFF_MS[attempt];
27575
- if (delay === void 0) throw fsError("EBUSY", name2);
27576
- await new Promise((resolve2) => setTimeout(resolve2, delay));
27692
+ const delay2 = SYNC_BACKOFF_MS[attempt];
27693
+ if (delay2 === void 0) throw fsError("EBUSY", name2);
27694
+ await new Promise((resolve2) => setTimeout(resolve2, delay2));
27577
27695
  }
27578
27696
  }
27579
27697
  async copy(handle, dir, name2, copies, rest2 = "") {
@@ -32679,7 +32797,10 @@ var Launcher = class {
32679
32797
  await Promise.all(mine);
32680
32798
  },
32681
32799
  kept: async (tab, items, paths) => {
32682
- for (const { path, hidden, fid } of items) this.adoptKept(path, hidden, fid, ours);
32800
+ for (const { path, hidden, fid } of items) {
32801
+ if (hidden !== void 0 && sharedKept(hidden)) await this.adoptShared(path, hidden, fid);
32802
+ else this.adoptKept(path, hidden, fid, ours);
32803
+ }
32683
32804
  await open(tab, paths);
32684
32805
  },
32685
32806
  left: (tab) => {
@@ -32688,6 +32809,33 @@ var Launcher = class {
32688
32809
  }
32689
32810
  };
32690
32811
  }
32812
+ async adoptShared(path, hidden, fid) {
32813
+ const bound3 = [...this.held].map(
32814
+ (holds2) => [holds2, [...holds2.boundAt(path, fid), ...holds2.boundAt(hidden, fid)]]
32815
+ );
32816
+ const keeping = bound3.filter(([, ids]) => ids.length > 0);
32817
+ const nodes = [...this.openFiles].filter(
32818
+ (open) => [path, hidden].some((at) => open.holdsAt(at))
32819
+ );
32820
+ const refs = keeping.length + nodes.length;
32821
+ if (refs === 0) {
32822
+ this.held.doubt([path]);
32823
+ return;
32824
+ }
32825
+ const file = await this.unlinked.sharedFile(hidden, refs);
32826
+ if (!await this.rootFs.lstat(hidden).then(
32827
+ () => true,
32828
+ () => false
32829
+ )) {
32830
+ for (let i = 0; i < refs; i++) file.release();
32831
+ this.held.doubt([path]);
32832
+ return;
32833
+ }
32834
+ const kept = nodes.filter((open) => open.keepBound([hidden, path], fid, file)).length;
32835
+ for (let i = kept; i < nodes.length; i++) file.release();
32836
+ for (const [holds2, ids] of keeping) holds2.keepBound(ids, path, file);
32837
+ void this.rootFs.announceHolds?.([], [path, hidden], false);
32838
+ }
32691
32839
  adoptKept(path, hidden, fid, ours) {
32692
32840
  if (hidden === void 0 || !ours(hidden)) {
32693
32841
  this.held.doubt([path]);
@@ -32830,7 +32978,6 @@ var Launcher = class {
32830
32978
  moved(from, to, source) {
32831
32979
  this.renameLog.add(from, to);
32832
32980
  for (const holds2 of this.held) holds2.renamed(from, to);
32833
- if (this.mounts.locate(to) === void 0) this.rootFs.rehold?.(from, to);
32834
32981
  if (source) return;
32835
32982
  for (const nodes of this.openFiles) nodes.renamed(from, to);
32836
32983
  this.watchers.moved(from, to);