Interni
Questa pagina descrive i componenti privati nella directory src/
della libreria, rilevanti per tutti coloro che collaborano al suo sviluppo o
desiderano comprenderne il comportamento fino al livello dei byte. Le
definizioni del wire format si trovano nella
specifica OSF.
Panoramica dei componenti privati
| Componente | File | Utilizzato da |
|---|---|---|
| Encoder di blocchi | blockencode_p.{h,cpp} | entrambi i writer |
| Parti comuni dei writer (chunking, assemblaggio del metablock) | writercommon_p.{h,cpp} | entrambi i writer |
| I/O di file durevole | durablefile_p.{h,cpp} | solo StreamingWriter |
| Helper little-endian | binaryio_p.h | Encoder |
| Streambuf di decompressione | compression.cpp (classe DecompressingIStream::Streambuf) | Percorso di lettura |
| Macchina a stati del builder | manager.cpp (struct ChannelBuilder) | DataManager |
Encoder di blocchi (osf::detail::encode*)
L'encoder scrive frame di blocco completi
[u16 indice canale][campo lunghezza][payload] in un vettore di byte
(sempre little-endian):
| Funzione | Blocco | Layout del payload |
|---|---|---|
encodeStartData<T> | bcStartData (6) | [u8 ctrl][i64 start_ts][f64 rate][u32 N][N × T] |
encodeContinuedData<T> | bcContinuedData (5) | [u8 ctrl][u32 N][N × T] |
encodeAbsTimestampData<T> | bcAbsTimeStampData (8) | [u8 ctrl][u32 N][N × (i64 ts + T)] |
encodeAbsTimestampDataGps | idem per GPS | Valore = 3 × f64 (lat, lon, alt) = 24 byte |
| Overload String/Binary | idem, campione singolo | [u8 ctrl][i64 ts][byte] — bit 7 = 0, nessun terminatore 0x00 (OSF5) |
Convenzioni: il bit 7 del control byte viene impostato solo se viene usata la
forma multi-campione (prefisso u32 N); con count == 1
il prefisso viene omesso (risparmia 4 byte per ogni blocco a campione singolo,
revisione della specifica 2026-05-24). I writer chiamano l'encoder esclusivamente con
quantità di campioni conformi alla capacità, calcolate in anticipo tramite writercommon_p.
Matematica del chunking (writercommon_p)
Il campo lunghezza di un blocco ha una larghezza di sizeOfLengthValue (2 o 4) byte;
ne deriva il payload massimo per blocco:
maxPayloadForSov(2) == 0xFFFF; // 65 535 Bytes
maxPayloadForSov(4) == 0x7FFFFFFF - 1024; // soft-cap, vermeidet i32-Überlauf
Da qui tre helper derivano il numero massimo di campioni per tipo di blocco
(overhead: bcStartData 21 byte = ctrl + ts + rate + N;
bcContinuedData/bcAbsTimeStampData 5 byte = ctrl + N; nei blocchi
timestamped ogni campione richiede 8 byte aggiuntivi di timestamp). Per
i blocchi variabili a campione singolo vale
variableSampleCapacity(sov) = max_payload - 9 (ctrl + ts).
Queste funzioni sono l'unico punto in cui vengono calcolate le dimensioni dei blocchi:
lo streaming writer e il block writer eseguono il chunking in modo identico.
buildMetablock(FileInfoDraft, ChannelDefs) assembla il metablock OSF5:
indici sequenziali 0..N, channeltype normalizzato
(equidistant resta, tutto il resto diventa scalar — la convenzione consolidata
dei file di riferimento OSF) e vengono applicati i valori predefiniti automatici
dei metadati (created_utc = ora UTC corrente come
YYYY-MM-DDTHH:MM:SSZ, fallback di creator osf-cpp/<version>,
fallback di tag default; reason/tripla GPS vengono omessi
anziché null).
DurableFile — semantica fsync dello streaming writer
Wrapper RAII attorno a un handle di file nativo con tre operazioni:
write (completa o errore), force (Windows:
FlushFileBuffers, POSIX: fsync) e close. Lo
StreamingWriter chiama force dopo ogni blocco: per questo «la chiamata
ritorna con successo» equivale a «il blocco è sul
supporto». Gli errori di write/force portano il writer nello
stato Broken (sticky error).
Streambuf di decompressione (percorso di lettura)
DecompressingIStream nasconde uno std::streambuf personalizzato dietro
un PIMPL, in modo che l'header pubblico resti privo di zlib:
- Classificazione tramite i primi due byte (
detectCompression, non consumante tramite read + seek-back: la sorgente deve essere seekable). underflow()decomprime su richiesta in un buffer fisso: memoria costante indipendentemente dalla dimensione del file.inflateInit2(MAX_WBITS | 32)attiva il riconoscimento automatico dell'header gzip/zlib da parte di zlib stessa.- I flussi compressi troncati restituiscono EOF anziché un errore (best effort, coerente con il resto del percorso di lettura).
- Con
CompressionFormat::Nonei byte vengono passati 1:1:DataManagerpuò quindi anteporre la facciata in modo incondizionato.