Updates to Swarm Disk

This commit is contained in:
Raven Scott
2026-04-27 19:38:07 -04:00
parent 97ba72f639
commit 12b9c1e200
2 changed files with 86 additions and 20 deletions
@@ -39,6 +39,7 @@ The list below is one **bullet per variable** in the form **name — component
- `BARE_OS_BOOT_TIMEOUT_MS` — Booter — Wall-clock budget for peer wait + network boot (default `60000`) - `BARE_OS_BOOT_TIMEOUT_MS` — Booter — Wall-clock budget for peer wait + network boot (default `60000`)
- `BARE_OS_MBR_READ_TIMEOUT_MS` — Booter (host) — Max wait in milliseconds for replicated **block 0** / MBR before boot fails (**≥ 3000**, hard cap **600000**); when unset, defaults to **60000** unless adaptive mode adjusts it. - `BARE_OS_MBR_READ_TIMEOUT_MS` — Booter (host) — Max wait in milliseconds for replicated **block 0** / MBR before boot fails (**≥ 3000**, hard cap **600000**); when unset, defaults to **60000** unless adaptive mode adjusts it.
- `BARE_OS_MBR_READ_TIMEOUT_ADAPTIVE` — Booter — When **`1`** / **`true`** and **`BARE_OS_MBR_READ_TIMEOUT_MS`** is unset, adjusts the MBR wait from live **peer count** (sparse swarms get a longer budget; multi-peer sessions may use a shorter one). - `BARE_OS_MBR_READ_TIMEOUT_ADAPTIVE` — Booter — When **`1`** / **`true`** and **`BARE_OS_MBR_READ_TIMEOUT_MS`** is unset, adjusts the MBR wait from live **peer count** (sparse swarms get a longer budget; multi-peer sessions may use a shorter one).
- `BARE_OS_MBR_READ_REBROADCAST_MS` — Booter — While waiting for **block 0** / MBR, re-send read requests to all peers on this interval (**default `5000`**, clamp **`2000`****`60000`** **`ms`**). Set **`0`** / **`false`** to disable periodic rebroadcast (initial and per-peer-join sends only).
- `BARE_OS_DISK_OS_SEARCH_THROTTLE_MS` — Booter / **`disk.os`** — Optional **0500** ms delay between scanning the system Hyperdrive and each **`auxiliaryDrives`** entry during peer **`searchLocal`** fan-out (default **0**); softens load on large offline mirrors. - `BARE_OS_DISK_OS_SEARCH_THROTTLE_MS` — Booter / **`disk.os`** — Optional **0500** ms delay between scanning the system Hyperdrive and each **`auxiliaryDrives`** entry during peer **`searchLocal`** fan-out (default **0**); softens load on large offline mirrors.
- `BARE_OS_DISK_OS_PATH_MANIFEST` — Booter / **`disk.os`** — Absolute path on the **system** Hyperdrive to a JSON manifest (**default** **`/etc/bare-os/path-manifest.json`**). The file may be **`{ "schema": 1, "paths": ["/bin/sh", …] }`** or a bare JSON array of path strings. Substring matches from the manifest are merged **before** the primary drives recursive listing. Set to **empty** to disable manifest acceleration (full listing only on the primary drive). - `BARE_OS_DISK_OS_PATH_MANIFEST` — Booter / **`disk.os`** — Absolute path on the **system** Hyperdrive to a JSON manifest (**default** **`/etc/bare-os/path-manifest.json`**). The file may be **`{ "schema": 1, "paths": ["/bin/sh", …] }`** or a bare JSON array of path strings. Substring matches from the manifest are merged **before** the primary drives recursive listing. Set to **empty** to disable manifest acceleration (full listing only on the primary drive).
- `BARE_OS_DISK_OS_SEARCH_MANIFEST_ONLY` — Booter — When **`1`** / **`true`**, `**searchLocal` skips the primary drives recursive `list()` scan** and uses only manifest hits on that drive (auxiliary drives are still listed). For tests and operator-tuned images with a complete manifest. - `BARE_OS_DISK_OS_SEARCH_MANIFEST_ONLY` — Booter — When **`1`** / **`true`**, `**searchLocal` skips the primary drives recursive `list()` scan** and uses only manifest hits on that drive (auxiliary drives are still listed). For tests and operator-tuned images with a complete manifest.
+91 -26
View File
@@ -80,6 +80,23 @@ export function mbrReadTimeoutMsForDisk(disk) {
return MBR_READ_TIMEOUT_MS_DEFAULT return MBR_READ_TIMEOUT_MS_DEFAULT
} }
/**
* Interval (ms) to re-send pending block read requests to all peers while waiting for MBR / block data.
* **`0`** disables periodic rebroadcast (initial + per-connect sends only).
* Override **`BARE_OS_MBR_READ_REBROADCAST_MS`** (defaults **5000**, clamp **2000****60000**).
* @param {Record<string, string | undefined> | null | undefined} env
*/
export function mbrReadRebroadcastMsFromEnv(env) {
const raw = String(env?.BARE_OS_MBR_READ_REBROADCAST_MS ?? '').trim()
if (raw === '0' || raw.toLowerCase() === 'false') return 0
const n = Math.floor(Number(raw))
if (Number.isFinite(n) && n >= 0) {
if (n === 0) return 0
return Math.min(60_000, Math.max(2_000, n))
}
return 5_000
}
export class SwarmDisk { export class SwarmDisk {
constructor() { constructor() {
this.localRAM = new Map() this.localRAM = new Map()
@@ -223,9 +240,22 @@ export class SwarmDisk {
reject(new Error(m.error || 'swarm-disk rpc failed')) reject(new Error(m.error || 'swarm-disk rpc failed'))
} }
}) })
/** @type {{ chan: { messages: { send: (m: unknown) => void }[] } }} */ ( const chan = /** @type {{ chan: { messages: { send: (m: unknown) => void }[] } }} */ (
peer peer
).chan.messages[5].send({ id, module, method, args }) ).chan
void chan.fullyOpened().then((opened) => {
if (!opened) return
if (!this.pendingRpc.has(id)) return
try {
chan.messages[5].send({ id, module, method, args })
} catch (err) {
this.pendingRpc.delete(id)
clearTimeout(to)
reject(
err instanceof Error ? err : new Error((err && err.message) || String(err))
)
}
})
}) })
} }
@@ -595,15 +625,7 @@ export class SwarmDisk {
const pendingIndices = [...this.pendingReads.keys()] const pendingIndices = [...this.pendingReads.keys()]
for (const idx of pendingIndices) { for (const idx of pendingIndices) {
void peer.chan.fullyOpened().then(() => { this._sendReadIndexToPeer(peer, idx)
if (!this.peers.has(peer)) return
if (!this.pendingReads.has(idx)) return
try {
peer.chan.messages[0].send(idx)
} catch {
/* ignore — bad channel; other peers may still satisfy the read */
}
})
} }
const collabNd = const collabNd =
@@ -664,28 +686,63 @@ export class SwarmDisk {
} }
} }
async read(index) { /**
if (this.localRAM.has(index)) return this.localRAM.get(index) * Protomux message 0: request block index (MBR). Only send after channel pairing.
return new Promise((resolve, reject) => { * @param {unknown} peer
const timeoutMs = mbrReadTimeoutMsForDisk(this) * @param {number} index
const timeout = setTimeout(() => { */
this.pendingReads.delete(index) _sendReadIndexToPeer(peer, index) {
reject(new Error('MBR read timeout')) const chan = /** @type {{ chan: { messages: { send: (idx: number) => void }[] } }} */ (
}, timeoutMs) peer
this.pendingReads.set(index, (data) => { ).chan
clearTimeout(timeout) void chan.fullyOpened().then((opened) => {
resolve(data) if (!opened) return
})
for (const peer of this.peers) {
void peer.chan.fullyOpened().then(() => {
if (!this.pendingReads.has(index)) return if (!this.pendingReads.has(index)) return
try { try {
peer.chan.messages[0].send(index) chan.messages[0].send(index)
} catch { } catch {
/* ignore — channel closed or not ready */ /* ignore — channel closed or not ready */
} }
}) })
} }
/**
* Re-broadcast a pending block read to every connected peer (lossy links, slow pairing).
* @param {number} index
*/
_broadcastPendingReadIndex(index) {
for (const p of this.peers) {
this._sendReadIndexToPeer(p, index)
}
}
async read(index) {
if (this.localRAM.has(index)) return this.localRAM.get(index)
return new Promise((resolve, reject) => {
const timeoutMs = mbrReadTimeoutMsForDisk(this)
/** @type {ReturnType<typeof setInterval> | null} */
let rebroadcastIv = null
const timeout = setTimeout(() => {
if (rebroadcastIv) clearInterval(rebroadcastIv)
this.pendingReads.delete(index)
reject(new Error('MBR read timeout'))
}, timeoutMs)
this.pendingReads.set(index, (data) => {
if (rebroadcastIv) clearInterval(rebroadcastIv)
clearTimeout(timeout)
resolve(data)
})
const rbMs = mbrReadRebroadcastMsFromEnv(globalThis.process?.env)
this._broadcastPendingReadIndex(index)
if (rbMs > 0) {
rebroadcastIv = setInterval(() => {
if (!this.pendingReads.has(index)) {
if (rebroadcastIv) clearInterval(rebroadcastIv)
return
}
this._broadcastPendingReadIndex(index)
}, rbMs)
}
}) })
} }
@@ -714,7 +771,15 @@ export class SwarmDisk {
state.timeout = setTimeout(() => state.finish(), 3000) state.timeout = setTimeout(() => state.finish(), 3000)
self.pendingSearches.set(id, state) self.pendingSearches.set(id, state)
for (const peer of peerList) { for (const peer of peerList) {
void peer.chan.fullyOpened().then((opened) => {
if (!opened) return
if (state.settled) return
try {
peer.chan.messages[3].send({ id, query }) peer.chan.messages[3].send({ id, query })
} catch {
/* ignore */
}
})
} }
}) })
} }