Skip to content

Blob stream() reader: pre-existing cancel/cleanup hazards (fd not nulled → double-close, untracked open-retry timer, double-onError, slice reads from byte 0) #1457

Closed

Description

@kriszyp

Surfaced by the cross-model review of #1454 / PR #1456, in code that PR does not change. Grouping them here so the targeted patch stays focused.

All in resources/blob.ts FileBackedBlob.stream():

  1. fd not nulled after close → double-close on a reused fd. cancel() (and the success/error paths) call close(fd) but never clear fd. A later cancel() (e.g. GC-driven after a successful read) calls close() again on a descriptor the OS may have reassigned to an unrelated file/socket — silent corruption. Null fd after every close and guard close()/cancel() on it.
  2. cancel() before fd is assigned → close(undefined). If a consumer cancels before the async open() in start() resolves, close(undefined) throws ERR_INVALID_ARG_TYPE. Guard on fd != null.
  3. start() open-retry 20ms timer is untracked. The file-creation retry setTimeout in start() is not saved/cleared; cancelling during the wait leaks an fd (the timer fires, opens a new fd, but pull()/cancel() never run again). Needs its own tracked handle (it is in a different scope than pull()'s timer). (PR fix(blob): bound the stream() incomplete-content wait so a truncated blob can't spin a worker at 100% CPU (#1454) #1456 already tracks the two readMore() backoff timers.)
  4. Double onError. If a slow async read completes with an error after the watcher-timeout already called onError and closed the fd, onError runs twice → second close(fd) + duplicated #onError callbacks. Add a settled guard.
  5. Slice reads sequentially from byte 0 (perf). blob.slice(start, end).stream() / .bytes() reads and discards from offset 0 instead of seeking to HEADER_SIZE + start, allocating a 256KB buffer per discarded chunk. Seek directly.

#1–#4 are reliability/correctness; #5 is performance. None are regressions from #1456 — they predate it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:storageStorage engine, LMDB/RocksDB, compactionbugSomething isn't working

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions