sandbox: el merge de deps cae en el store (mismo fs), no en la raíz — desbloquea kio
merge_deps_layer funde las deps en UNA capa overlay por hardlinks (cp -al) para no desbordar el lowerdir de overlayfs (tope ~4096B por página). Pero calculaba la ruta del merge en deps.parent().parent() = <store>/../.dmerge, asumiendo que el store está en <base>/store del MISMO fs. En el worker el store es un VOLUMEN bind-montado (/opt/hammer/store en /dev/sdb, /opt/hammer en /dev/sda1) ⇒ el merge caía en la raíz, cp -al fallaba cross-device, y el fallback apilaba las ~50 deps de kio directo → lowerdir 5315B > 4096B → "bwrap: Can't make overlay mount" → kio (EL keystone, gatea 36) imposible de construir. Por eso estaba clavado. Fix de una línea: el merge va en el padre INMEDIATO de las deps (= el store mismo), garantizado mismo fs. Confirmado en el worker: cp -al a /opt/hammer/.dmerge falla "Invalid cross-device link"; a /opt/hammer/store/.dmerge funciona. En el laptop andaba por casualidad (store y su padre en el mismo fs). `.dmerge` (dot-prefix) es invisible para el store lookup/build-state como .times. cosecha excluye /.dmerge del rsync (es scratch de hardlinks; sin -H rsync lo expandiría a copias reales). Descubierto levantando el worker para poblar tiempos: yupana keystones apuntó a kio, la campaña falló ahí, y el radio de lowerdirs (5315B) destapó la causa. Una "sorpresa de entorno" (infra del sandbox, fuera del grafo) que el frente de timing sacó a la luz. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -209,13 +209,18 @@ impl Sandbox {
|
||||
for d in &self.deps {
|
||||
d.hash(&mut h);
|
||||
}
|
||||
// Junto al store para compartir filesystem (hardlinks no cruzan fs). El store suele estar en
|
||||
// `<base>/store`; ubicamos el merge en `<base>/.dmerge/<id>`. Derivamos <base> del primer dep.
|
||||
// DENTRO del store (el padre INMEDIATO de las deps), no en `<store>/../`: los hardlinks NO
|
||||
// cruzan filesystems, y el store puede ser un mount aparte (en el worker es un VOLUMEN
|
||||
// bind-montado: `/opt/hammer/store` en /dev/sdb, `/opt/hammer` en /dev/sda1). Con
|
||||
// `.parent().parent()` el merge caía en la raíz ⇒ `cp -al` cross-device fallaba ⇒ fallback al
|
||||
// apilado directo ⇒ overflow del lowerdir en kio (5315B > 4096B) y build imposible. El padre
|
||||
// inmediato de un dep ES el store, siempre mismo fs que las deps. `.dmerge` (dot-prefix) no
|
||||
// matchea `<hash>-<name>` ⇒ invisible para el store lookup y build-state, como `.times`.
|
||||
let base = self
|
||||
.deps
|
||||
.first()
|
||||
.and_then(|d| std::fs::canonicalize(d).ok())
|
||||
.and_then(|d| d.parent().and_then(|p| p.parent()).map(|p| p.to_path_buf()))
|
||||
.and_then(|d| d.parent().map(|p| p.to_path_buf()))
|
||||
.unwrap_or_else(|| PathBuf::from("."));
|
||||
let merged = base.join(".dmerge").join(format!("{:x}", h.finish()));
|
||||
let done = merged.join(".done");
|
||||
|
||||
@@ -68,7 +68,7 @@ else
|
||||
continue
|
||||
fi
|
||||
# 2. RECOGE: store sellado worker→laptop (CAS, merge seguro).
|
||||
if rsync -az -e "$SSH" "root@$ip:$REMOTE/store/" "$ROOT/store/" 2>&1 | tail -2; then
|
||||
if rsync -az --exclude /.dmerge -e "$SSH" "root@$ip:$REMOTE/store/" "$ROOT/store/" 2>&1 | tail -2; then
|
||||
echo " cosecha ✓"
|
||||
else
|
||||
echo " ⚠ cosecha falló — sigo"
|
||||
|
||||
Reference in New Issue
Block a user