LavinMQ::Persister
Makes confirmed publishes durable before they are confirmed. A single Persister is created per Server and shared between all VHosts.
Only the files a confirm depends on are synced (msync of the segments written by confirmed publishes, plus the directories of newly created files), not the whole filesystem: a syncfs would also flush every ack file that consumers append to, writing the same pages again and again. When many files are dirty, or a transaction is committed (which must also persist its acks), one syncfs is cheaper and simpler than many msyncs.
It also unlinks the segments that the message stores have emptied, after a drain (see #unlink_after_sync): the broker moves messages between queues (dead-lettering, delays, retries) by writing a copy and acking the original, and the unlink of the original's segment must not become durable before the copy. The stores only mark the copies dirty and hand over the files, so the order is kept here, in one place, for as long as the process lives, whatever happens to the store that emptied them.
Constants
Constructors
Instance methods
Every confirm — sync, no-sync, and clustered alike — is routed through the
publish confirm loop so each target has exactly one producer of ack
frames. sync is a runtime-mutable INI option (SIGHUP reloads it); taking
a shortcut here when it is disabled would let a later direct ack overtake
an earlier batched one after a mid-stream flip, sending cumulative
Basic.Ack frames out of delivery-tag order (see #2078). The loop skips the
actual sync while sync is disabled (see drain), so no-sync only pays a
single hop to the loop, not a disk flush.
Blocks until what was handed to #unlink_after_sync in dir, and below it, is unlinked. Before a store loads a directory, or a declared queue reuses one, that another store instance emptied segments in: they are unlinked by their paths. Unlinks elsewhere aren't waited for.
Register a file whose written data a later confirm depends on. Must be called after the write is dispatched to the replicator, so the fsync request that the drain sends to followers is behind it in the stream.
Like mark_dirty(MFile), for regular (non-mmapped) files and for directories with new entries. Marks are deduplicated until the next drain, so many new entries in one directory cost one fsync.
Block until everything written so far is durable, on the leader and on the in-sync followers. Used by transaction commits, which also have to persist their acks, so it syncs the whole filesystem.
Blocks until everything marked dirty so far is durable and the files handed to #unlink_after_sync so far are unlinked. Unlike #sync it only syncs the whole filesystem when there can be unmarked writes.
Makes mfile and path durable in a drain of their own, without waiting for a confirm to request one. A stream calls it when a segment is finished: confirms only sync the segments they wrote to, so an unconfirmed segment could otherwise stay unsynced while later ones become durable, and a power loss would leave a hole in the offsets. The directory is synced too, so the entry of the segment opened after it is durable with the meta file.
Unlinks an emptied segment and its ack file once everything marked dirty so far is durable, here and on the in-sync followers, without blocking the caller. The caller must have dropped its references to the files, a delivery can still hold a lease on the mapping.