Skip to content

(index): continuation scan loops forever when the stored and stat mtimes round to different milliseconds #891

Closed

Description

@devsuitup

Found in the review of #890 (pre-existing on main), CONFIRMED by a local probe (Node 22, Windows).

What happens. scanContinuationFile (session-cache.js ~98-110) can loop forever on a transcript larger than one 1 MiB continuation chunk.

Why. Two rounding rules disagree on the millisecond:

  • scanCachedContinuation (session-cache.js ~180-181) stores index.mtime by rounding the BigInt mtimeNs.
  • scanContinuationIndex (session-continuations.js ~36-37) reuses the saved cursor only if index.mtime === stat.mtime.toISOString(). stat.mtime comes from the floating-point mtimeMs, whose precision step is about 244 ns at current dates.

When the sub-millisecond part sits just under .5 ms, the two land on different milliseconds. The cursor is then never reused. Each pass restarts from offset 0 with the same 1 MiB budget, bytes < size stays true, and the do…while never exits; it re-reads 1 MiB per setImmediate until the file changes.

Probe. Same fixture as the D2 test, mtime set to an exact tick with SetLastWriteTimeUtc:

  • mtimeNs …499900 (bigint rounding .000Z, stat.mtime .001Z): prepareContinuationRefresh still not done after 4 s, after 1926 opens of the file.
  • …499800: done after 8 opens.

Impact.

Fix. Compare stamps (mtimeNs, or the same BigInt-derived value) instead of ISO dates, or derive both values with the same rounding. Red first: a test with an mtime on the ns boundary that hangs before the fix and finishes after.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions