.TH "LogRing" 3 "Version 0.200.1-dev" "QElectroTech" \" -*- nroff -*-
.ad l
.nh
.SH NAME
LogRing \- The \fBLogRing\fP class Fixed-capacity, always-on in-memory ring of the most recent log lines, preallocated once at construction -- \fBappend()\fP never allocates\&.  

.SH SYNOPSIS
.br
.PP
.PP
\fR#include <logring\&.h>\fP
.SS "Classes"

.in +1c
.ti -1c
.RI "struct \fBEntry\fP"
.br
.in -1c
.SS "Public Member Functions"

.in +1c
.ti -1c
.RI "\fBLogRing\fP ()"
.br
.ti -1c
.RI "void \fBappend\fP (const QByteArray &line) noexcept"
.br
.ti -1c
.RI "QVector< QByteArray > \fBsnapshot\fP () const"
.br
.ti -1c
.RI "void \fBdumpToFd\fP (int fd) const noexcept"
.br
.ti -1c
.RI "void \fBclear\fP ()"
.br
.in -1c
.SS "Static Public Attributes"

.in +1c
.ti -1c
.RI "static constexpr int \fBkCapacityEntries\fP = 4096"
.br
.ti -1c
.RI "static constexpr int \fBkEntryBytes\fP = 512"
.br
.in -1c
.SS "Private Attributes"

.in +1c
.ti -1c
.RI "std::vector< \fBEntry\fP > \fBm_entries\fP"
.br
.ti -1c
.RI "std::atomic< quint64 > \fBm_write_cursor\fP {0}"
.br
.in -1c
.SH "Detailed Description"
.PP 
The \fBLogRing\fP class Fixed-capacity, always-on in-memory ring of the most recent log lines, preallocated once at construction -- \fBappend()\fP never allocates\&. 

Lock-free by construction, not just "thread-safe": step 4 (see \fBcrashhandler\&.h\fP) reads this ring from inside a POSIX signal handler, where taking any lock is unsafe -- if the crashing thread happens to be the one that already holds it (or any other thread does and never gets scheduled again), the handler hangs forever, and you lose both the ring dump \fIand\fP the core dump\&. So there is no mutex here at all: \fBappend()\fP claims a slot with a single atomic fetch-add, and \fBdumpToFd()\fP/snapshot() read the preallocated entries directly\&.

.PP
Accepted tradeoff: if \fBdumpToFd()\fP runs while another thread is mid-append into the exact slot being read (only possible in the crash-handler case, and only for at most one slot), that one entry may be read torn -- part old content, part new\&. Every other entry is unaffected\&. This is deliberate: the alternative (a seqlock or similar to detect and retry torn reads) adds real complexity for a window that, per discussion #644, is not worth trading "the handler mustnever block" against\&. 
.SH "Constructor & Destructor Documentation"
.PP 
.SS "LogRing::LogRing ()"

.SH "Member Function Documentation"
.PP 
.SS "void LogRing::append (const QByteArray & line)\fR [noexcept]\fP"
Append one already-formatted, already-truncated log line\&. Bytes beyond kEntryBytes are dropped with a truncation marker\&. Never allocates, never blocks\&. Safe to call from any normal (non-signal) thread concurrently\&. 
.SS "void LogRing::clear ()"

.SS "void LogRing::dumpToFd (int fd) const\fR [noexcept]\fP"
Async-signal-safe: writes every entry currently held to fd via write(2) only -- no allocation, no Qt, no locks\&. May write a torn entry under the rare race described above; never blocks\&. 
.SS "QVector< QByteArray > LogRing::snapshot () const"
Snapshot of the entries currently held, oldest first\&. Normal (non-signal) context only\&. 
.SH "Member Data Documentation"
.PP 
.SS "int LogRing::kCapacityEntries = 4096\fR [static]\fP, \fR [constexpr]\fP"

.SS "int LogRing::kEntryBytes = 512\fR [static]\fP, \fR [constexpr]\fP"

.SS "std::vector<\fBEntry\fP> LogRing::m_entries\fR [private]\fP"

.SS "std::atomic<quint64> LogRing::m_write_cursor {0}\fR [private]\fP"


.SH "Author"
.PP 
Generated automatically by Doxygen for QElectroTech from the source code\&.
