Skip to content

dendro v0.2.2

Choose a tag to compare

@github-actions github-actions released this 25 Sep 21:11
· 39 commits to main since this release
82ae816

Added

  • caller_rows floors on retention. ArchiveMut::evict_before_with_floor
    and evict_streams_before_with_floor, and the SourceWriter methods of the
    same names, take a floor function (CallerRowFloor, boxed as
    writer::CallerRowFloorFn). The pass calls it once per name it touches,
    inside its transaction and after the segment and WAL deletes, with the
    oldest row that name still holds, and deletes the name's caller rows only
    below min(floor, cutoff). The existing eviction methods are unchanged.

    Retention cut a stream's caller_rows at the segment cutoff, in the same
    transaction as the segments, with no way for the caller to keep more. For an
    identity log of Full and Delta entries, a cutoff between a Full and
    the deltas after it deleted the Full while the deltas and the rows they
    describe remained, so a reader could not attribute those rows. The caller
    knows which entry is a Full and dendro does not read the blobs, so the
    caller supplies the floor: the latest Full at or before the oldest row the
    stream still holds, or i64::MIN for a stream with none. The oldest row
    rather than the cutoff, because a segment spanning the cutoff is kept with
    rows older than it; and asked inside the pass, because a seal between a
    caller's own query and the pass can create such a segment.

  • SourceWriter::evict_before was documented as fire-and-forget. It waits for
    the pass and returns its result; the doc now says so.

Changed

  • Frame::Rows.seq counts intervals, not frames, and a gap means intervals
    the subscriber did not receive — not "frames lost in transit and nothing
    else", which 0.2.1 said and which no publisher that declines to buffer can
    hold.

    Rule 6 assumed a publisher can always emit. One that refuses to buffer without
    bound for a stalled consumer cannot, and buffering without bound is the worse
    failure. So an interval may legitimately go unserved, and the contract now has
    three states rather than two: served with data, served with nothing (the empty
    frame), and not served (a gap).

    This does not reinstate the interval index. A per-interval counter kept by
    the producer's own loop needs no clock and does not alias; dividing an
    observation timestamp still does.

  • The write feature's description said std::thread::spawn "panics at
    runtime" on wasm32. This crate uses
    std::thread::Builder::spawn, which returns io::Result and is reported by
    name, so the failure is diagnosable rather than a trap. Also records why a
    compile check cannot verify the reader configuration's thread-freedom.