@@ -42,21 +42,12 @@ export function classifyAuditEntryForReplay(
4242}
4343
4444/**
45- * Wraps a transaction-log query iterator so a framing-level corruption error ends
46- * iteration of that log cleanly instead of escaping as an uncaughtException.
47- *
48- * rocksdb-js's txnlog reader throws a bounded `RangeError` when an entry's declared
49- * length overruns the log or its header is truncated (intentional hardening — it would
50- * otherwise OOM on `allocUnsafe(bogusLength)` or deref an undefined buffer). A torn write
51- * at SIGKILL time, or a flipped byte in an unflushed/corrupt log, looks exactly like that.
52- * Once the framing is lost we can't locate the next entry, so the corrupt frame marks the
53- * usable end of this log (torn-write semantics): entries before it have already been
54- * yielded, and startup replay / replication broadcast must continue rather than abort the
55- * boot. The latch means a persistently-corrupt log is reported once, not on every re-poll.
56- *
57- * `onCorruptFrame` is invoked once, with the error, when a corrupt frame is hit — kept as
58- * a callback (rather than logging here) so this module stays free of the Harper module
59- * graph and the behavior is unit-testable. Non-`RangeError` failures propagate unchanged.
45+ * Wraps a transaction-log query iterator so a corrupt/torn frame ends that log's iteration
46+ * cleanly instead of escaping as an uncaughtException. rocksdb-js throws a bounded RangeError
47+ * when an entry's framing is broken; framing loss means the next entry can't be located, so the
48+ * frame marks end-of-log (entries before it were already yielded) and startup replay /
49+ * replication broadcast continue. `onCorruptFrame` fires once, latched — kept a callback (not a
50+ * direct log) so this module stays out of the Harper module graph and is unit-testable.
6051 */
6152export function endIteratorOnCorruptFrame < T > (
6253 iterator : Iterator < T > ,
@@ -72,22 +63,16 @@ export function endIteratorOnCorruptFrame<T>(
7263 try {
7364 return iterator . next ( ) ;
7465 } catch ( error ) {
75- // rocksdb-js's txnlog reader signals frame corruption with a RangeError; the
76- // message wording is version-dependent (1.4.2 added hex offsets), so we key on
77- // the class, not the text. Anything else is unexpected and propagates. Treating
78- // a stray non-framing RangeError as end-of-log is the deliberate tradeoff: on
79- // this cold replay/boot path it still beats an uncaughtException aborting
80- // startup, and onCorruptFrame logs every occurrence so it is never silent.
66+ // Key on the class, not the message: the framing RangeError's wording is
67+ // version-dependent (1.4.2 added hex offsets). Anything else re-throws.
8168 if ( ! ( error instanceof RangeError ) ) throw error ;
8269 stopped = true ;
8370 onCorruptFrame ( error ) ;
8471 return { done : true , value : undefined } ;
8572 }
8673 } ,
87- // Forward early termination so the source iterator's cleanup (e.g. releasing a
88- // rocksdb read handle / lock) still runs when a consumer exits a for-of early via
89- // break/return/throw. Mark stopped first so a later next() can't re-enter. The
90- // current rocksdb-js query iterator implements neither, hence the protocol defaults.
74+ // Forward early termination (for-of break/return/throw) so the source's cleanup runs;
75+ // mark stopped first. Current rocksdb-js implements neither — hence the protocol defaults.
9176 return ( value ?: any ) : IteratorResult < T > {
9277 stopped = true ;
9378 if ( typeof iterator . return === 'function' ) return iterator . return ( value ) ;
0 commit comments