Windows: mutation guard rethrows EPERM from a lock dir being deleted, so the ingest-seq reserve skips its retry

Abierto Apto para principiantes
#2,886 2 comentarios 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 1 día

@HypForge ya está trabajando en esto.

Desde el 5/11/2026.

  • #2897 de @HypForge — abierto

Evaluación

Dificultad
2/5
Tiempo estimado
1-3 horas
Aptitud para principiantes
77/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
javascript, node.js

Línea de trabajo

Lee en src/core/util/mutation_guard.js el manejo de errores alrededor de mkdirSync y readdirSync; después, revisa la lógica de reintentos en src/core/cache/ingest-seq.js. Usa como regresión la prueba del asignador en procesos separados que falla y que se menciona en el issue, y ejecútala en Windows. Se considera terminado cuando EPERM o EBUSY durante la liberación siguen la ruta de reintento por recurso ocupado y la prueba de reserva pasa.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

What happens

On Windows, claimPartitionMutation can throw a raw EPERM instead of its busy refusal. The ingest-seq allocator then skips its retry, and a commit that should have waited a few milliseconds fails.

src/core/util/mutation_guard.js (master 135887e3):

  • Line 52: the claim's mkdirSync(directory) fails with EEXIST because another process holds the guard.
  • Line 60: we readdirSync(directory) to find out who holds it.
  • Line 64: only ENOENT from that read becomes the busy refusal, which covers the holder letting go between our mkdir and our read. Any other code is rethrown.

On win32, a directory that another process is deleting stays in a "delete pending" state for a moment. A readdir on it in that window fails with EPERM, not ENOENT. That is the same race the ENOENT arm is there for (the holder is releasing), but it skips the arm and escapes as an ordinary error.

src/core/cache/ingest-seq.js:170 retries reserve only when isPartitionMutationBusy(error) is true (up to RESERVE_RETRY_LIMIT 200 tries, 25 ms apart). So the raw EPERM ends the reserve at once. Storage calls reserve from src/core/cache/storage.js:302 and :416. Per the #2885 review, the chunk then goes back to the spool and is committed on a later tick: a delayed write, not a lost row.

Evidence

  • CI run 41989450420, attempt 2, job 127122055863 (the new test-windows job from #2885, Node v26.13.0).
  • The failing test was allocators in separate processes reserve disjoint runs with no gap and leave no lock behind:
Error: EPERM: operation not permitted, scandir '...\hyp-seq-xproc-FVg4h5\._hyp_ingest_seq.json.mutation-lock'
    at Object.readdirSync (node:fs:1956:26)
    at claimPartitionMutation (file:///D:/a/hypaware/hypaware/src/core/util/mutation_guard.js:60:22)
    at file:///D:/a/hypaware/hypaware/src/core/cache/partition.js:52:21
    at async Object.reserve (file:///D:/a/hypaware/hypaware/src/core/cache/ingest-seq.js:161:16)
  • The code is not new. mutation_guard.js last changed in #2658, and neither #2885 nor #2881 touches it. Until #2885 added Windows CI, nothing ran this test on Windows.
  • POSIX is not affected: Linux and macOS return ENOENT here, and the existing arm handles it.

Proposed fix

On win32, also treat EPERM (and EBUSY) from that readdirSync as the busy refusal. The holder is mid-release, so the caller's normal retry is the right response. POSIX behavior stays as it is.

When fixing it, check whether the line 52 mkdirSync can also fail with EPERM during the same delete-pending window. Today that path would throw rather than report busy.

The test above is the regression: it should pass on test-windows.

Lenguaje dominante
JavaScript
Estrellas
11
Forks
0
Merge medio
2 h 25 min
PR fusionados (30 d)
311

Preparar el entorno

Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de hyparam/hypaware

Todos los issues de hyparam/hypaware

Issues similares

Más issues de JavaScript

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.