indexbus_abi/layouts/journal.rs
1use crate::{caps, IndexbusAtomicU32, IndexbusAtomicU64, LayoutHeader};
2
3/// Journal segment metadata for one journal segment.
4///
5/// Kept 64B-aligned so per-segment metadata can be read without false sharing.
6#[repr(C, align(64))]
7pub struct SegmentMeta {
8 /// Segment identifier (implementation-defined).
9 pub segment_id: IndexbusAtomicU32,
10 /// Segment length in bytes.
11 pub segment_len: IndexbusAtomicU32,
12 /// Tail cursor within the segment.
13 pub tail: IndexbusAtomicU64,
14 /// Padding to keep segment metadata in a cache line.
15 pub pad_to_64: [u8; 48],
16}
17
18/// Concrete v1 journal layout:
19/// - 3 segments
20/// - 64KiB per segment
21/// - 4 subscriber positions
22///
23/// This is a **new region layout** (v1 append-only) and must not reinterpret any existing region.
24#[repr(C, align(64))]
25pub struct JournalLayout4 {
26 /// Common region header (magic/version/capabilities/layout size).
27 pub header: LayoutHeader,
28
29 /// 0 = uninitialized, 1 = initializing, 2 = initialized
30 pub initialized: IndexbusAtomicU32,
31 /// Padding (reserved).
32 pub pad0: u32,
33
34 /// Pad to 64 so the first counter starts at offset 64.
35 pub pad_to_64: [u8; 40],
36
37 /// Global publication position (monotonic bytes/records position; interpretation is lane-specific).
38 pub pub_pos: IndexbusAtomicU64,
39 /// Padding to keep `pub_pos` in its own cache line.
40 pub pad_pub_pos: [u8; 56],
41
42 /// Current active segment index (0..3).
43 pub active_segment: IndexbusAtomicU32,
44 /// Padding to keep `active_segment` in its own cache line.
45 pub pad_active_segment: [u8; 60],
46
47 /// Per-segment metadata.
48 pub segments: [SegmentMeta; crate::INDEXBUS_JOURNAL_SEGMENTS],
49
50 /// Per-subscriber positions.
51 pub sub_pos: [IndexbusAtomicU64; crate::INDEXBUS_JOURNAL_SUBSCRIBERS_DEFAULT],
52
53 /// Pad so `segment_bufs` starts 64B-aligned.
54 pub pad_after_sub_pos: [u8; 32],
55
56 /// Segment buffers (64KiB each).
57 pub segment_bufs:
58 [[u8; crate::INDEXBUS_JOURNAL_SEGMENT_BYTES]; crate::INDEXBUS_JOURNAL_SEGMENTS],
59}
60
61impl JournalLayout4 {
62 /// Capabilities required for this region to be considered compatible.
63 pub const REQUIRED_CAPS: u32 = caps::INDEXBUS_CAP_SUPPORTS_JOURNAL;
64}
65
66/// Optional appended stats/counters section for a journal region.
67///
68/// v1 policy: this section is append-only and only present when
69/// `caps::INDEXBUS_CAP_SUPPORTS_JOURNAL_STATS` is set and `LayoutHeader.layout_bytes` covers it.
70#[repr(C, align(64))]
71pub struct JournalStatsSection4 {
72 /// Total payload bytes committed by the publisher.
73 pub pub_payload_bytes: IndexbusAtomicU64,
74 /// Total committed records (non-PAD).
75 pub pub_records: IndexbusAtomicU64,
76 /// Total committed PAD records.
77 pub pad_records: IndexbusAtomicU64,
78 /// Total segment rotations performed.
79 pub rotations: IndexbusAtomicU64,
80
81 /// Publisher hit configured boundedness (would overrun).
82 pub pub_would_overrun: IndexbusAtomicU64,
83 /// Publisher forced subscribers forward (catch-up policy).
84 pub pub_forced_catchup: IndexbusAtomicU64,
85
86 /// Subscriber-detected overruns (best-effort).
87 pub sub_overruns: [IndexbusAtomicU64; crate::INDEXBUS_JOURNAL_SUBSCRIBERS_DEFAULT],
88 /// Padding to 128 bytes (reserved for future appended stats).
89 pub pad_to_128: [u8; 48],
90}
91
92#[allow(dead_code)]
93const _JOURNAL_STATS_SECTION_64B_ALIGN_CHECK: () = {
94 use core::mem::align_of;
95 assert!(align_of::<JournalStatsSection4>() == 64);
96};