hubcio opened a new pull request, #3970: URL: https://github.com/apache/iggy/pull/3970
Every journal flush issued two serialized fdatasyncs, log then index, so an fsync-gated topic paid two device round trips per ack. Both files now persist under one futures::future::join: 13.4k -> 26.1k msg/s and p50 5.83 -> 3.01 ms on ext4 with enforce_fsync and messages_required_to_save = 1, 8 producers into one partition. The cursors advance only after both saves succeed, so a failed half keeps its slot and the retry overwrites it; MessagesWriter::rewind lost its last caller and is gone. Recovery had to change first. The old order was a barrier only under enforce_fsync = true: with the shipped default the page cache already wrote the two inodes back in any order, and recovery's own pass C truncates the log before the index, so an index holding entries the log does not back was already ordinary. Boot refused it as IndexLogDivergence, and on a single-replica node that refusal was a permanent tombstone for a partition whose log was healthy. An index entry is derived from the log, so it is never evidence the log lacks. Recovery now steps back to the highest entry the log proves and floors the index there; when no entry proves, or the entries contradict each other (out of order, or below the segment start), it drops the index and rebuilds from the log. Nothing a client was promised is lost, since no ack precedes persist, and the walk still runs its residue probe, so a survivor past damage refuses as before. That walk now checksums every batch it accepts, because unordered files mean a durable index entry no longer implies a durable chunk and one chunk can hold several batches. The step-back is async, yields on refills and charges the shared probe budget, so a crafted tail refuses as UnverifiedResidue instead of stalling boot; FileScanner::slice_at anchors its backward moves to keep refills linear. An integration test covers the shape: a three-node cluster, one node SIGKILLed after an eager flush, its log cut behind the last index entry, then restarted. It asserts the floor marker in that node's stdout, the exact floored index length while the log is still exactly the cut length, the surviving prefix served and the node caught up. It is red before the recovery change and green with it. Measuring this needed three benchmark fixes. Reports took min, max and std_dev from the per-bucket moving average series, which averages the extremes away while the percentiles beside them used the raw samples; all three now come from those same sorted samples. The balanced-producer kind refused fewer than two partitions, but one is a legal target and the shape a durability benchmark needs. And --enforce-fsync claimed to fsync every write while the topic's flush threshold (server default 1024) still governed when the journal reached disk, so acks were not durability-gated unless it was also 1; that threshold is now exposed as --messages-required-to-save, plumbed into topic creation, named in the fsync help and shown in an example. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
