class

LavinMQ::Persister

Inherits Reference < Object

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

Log = LavinMQ::Log.for("persister")

Constructors

new(data_dir : String, replicator : Clustering::Replicator | Nil = nil)
Source

Instance methods

close
Source
drain_soon

Requests a drain of what is marked dirty, without waiting for it

Source
enqueue_ack(target : ConfirmTarget, id : UInt64)

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.

Source
last_sync
Source
mark_dirty(mfile : MFile) : Nil

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.

Source
mark_dirty(path : String) : Nil

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.

Source
sync

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.

Source
sync_marked

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.

Source
sync_soon(mfile : MFile, path : String) : Nil

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.

Source
syncs
Source

Nested types