Line data Source code
1 : #ifndef HEADER_fd_src_disco_gui_fd_gui_hist_h
2 : #define HEADER_fd_src_disco_gui_fd_gui_hist_h
3 :
4 : /* fd_gui_hist is the GUI's historical event store semantics layer. It
5 : sits on top of fd_gui_store and owns everything GUI-specific about
6 : the monitoring history: the named DBs (FD_GUI_HIST_* below), their
7 : key/value structs, fixed record sizes, the eviction policy, and the
8 : query API.
9 :
10 : There are two kinds of DB:
11 :
12 : - TIME-SERIES (TS) DBs are append-only streams tagged by a
13 : wallclock window. Written by fd_gui_hist_ts_append, read by
14 : time-window range scan.
15 : - KEY-VALUE (KV) DBs hold one record per key. Written/read by
16 : point key (fd_gui_hist_kv_get_or_create / _get / _get_any).
17 : */
18 :
19 : #include "../../util/fd_util_base.h"
20 : #include "fd_gui_store.h"
21 : #include "../../flamenco/leaders/fd_leaders_base.h" /* MAX_SLOTS_PER_EPOCH */
22 : #include "../../flamenco/runtime/fd_slot_params.h" /* FD_SLOT_PARAMS_200MS */
23 :
24 : struct fd_gui;
25 : typedef struct fd_gui fd_gui_t;
26 :
27 0 : #define FD_GUI_HIST_MAGIC (0xf17e6d09147802UL)
28 :
29 0 : #define FD_GUI_HIST_RES_1S_NS (1000000000L)
30 :
31 0 : #define FD_GUI_HIST_MAX_LEADER_SLOTS_PER_EPOCH (43200UL) /* 10% capacity should be enough for mainnet/testnet */
32 :
33 0 : #define FD_GUI_HIST_MAX_EPOCHS (64UL) /* Comfortably above typical time between restarts */
34 :
35 : /* Minimum number of epochs of slot, leader slot and epoch records the
36 : store always retains, regardless of pressure from other DBs. */
37 0 : #define FD_GUI_HIST_MIN_EPOCHS (3UL)
38 :
39 : /* Bounds the per-tile CPU day records retained (per tile). Two months
40 : of calendar days, about the span of FD_GUI_HIST_MAX_EPOCHS epochs. */
41 0 : #define FD_GUI_HIST_MAX_TIMELINE_DAYS (64UL)
42 :
43 0 : #define FD_GUI_HIST_SCHEDULER_COUNTS (0) /* (ts, type) */
44 0 : #define FD_GUI_HIST_TILE_TIMERS (1) /* (ts, type) */
45 0 : #define FD_GUI_HIST_SHRED_EVENTS (2)
46 0 : #define FD_GUI_HIST_TXN_START (3) /* (ts, type, bank, txn) */
47 0 : #define FD_GUI_HIST_TXN_END (4) /* (ts, type, bank, txn) */
48 0 : #define FD_GUI_HIST_SLOT (5) /* (slot, bank_seq) */
49 0 : #define FD_GUI_HIST_LEADER_SLOT (6) /* (slot, bank_seq) */
50 0 : #define FD_GUI_HIST_EPOCH (7) /* (epoch) */
51 0 : #define FD_GUI_HIST_TILE_STATS (8) /* (ts, type) */
52 0 : #define FD_GUI_HIST_TXN_WATERFALL (9) /* (ts, type) */
53 0 : #define FD_GUI_HIST_TIMELINE_DAY (10)
54 0 : #define FD_GUI_HIST_REPLAY_TXN (11)
55 0 : #define FD_GUI_HIST_TIMELINE_TILE_DAY (12) /* (day_idx, tile_idx) */
56 0 : #define FD_GUI_HIST_FEC_EVENTS (13) /* (FEC event key) */
57 0 : #define FD_GUI_HIST_FEC_EVENT_ARCHIVE (14) /* (ts, ...) */
58 0 : #define FD_GUI_HIST_CNT (15)
59 :
60 : struct fd_gui_hist_metrics {
61 : /* Writes dropped after exhausting region or KV index capacity. */
62 : ulong map_full[ FD_GUI_HIST_CNT ];
63 : /* Writes that evicted records before succeeding. */
64 : ulong reserves [ FD_GUI_HIST_CNT ];
65 : };
66 : typedef struct fd_gui_hist_metrics fd_gui_hist_metrics_t;
67 :
68 : struct fd_gui_hist_slot_key { ulong slot; ulong bank_seq; };
69 : struct fd_gui_hist_leader_slot_key { ulong slot; ulong bank_seq; };
70 : struct fd_gui_hist_epoch_key { ulong epoch; };
71 : struct fd_gui_hist_tile_day_key { ulong day_idx; ulong tile_idx; };
72 : typedef struct fd_gui_hist_slot_key fd_gui_hist_slot_key_t;
73 : typedef struct fd_gui_hist_leader_slot_key fd_gui_hist_leader_slot_key_t;
74 : typedef struct fd_gui_hist_epoch_key fd_gui_hist_epoch_key_t;
75 : typedef struct fd_gui_hist_tile_day_key fd_gui_hist_tile_day_key_t;
76 :
77 : struct fd_gui_hist_private;
78 : typedef struct fd_gui_hist_private fd_gui_hist_t;
79 :
80 : /* fd_gui_hist_kv_slot_iter_t iterates every record for `slot` (every
81 : fork's block) in a slot-keyed KV DB. Used to enumerate the
82 : equivocating forks of a slot. */
83 : struct fd_gui_hist_kv_slot_iter {
84 : void const * rec; /* current record; NULL when done */
85 : ulong bank_seq; /* current record's bank_seq */
86 : fd_gui_store_kv_iter_t _it;
87 : };
88 : typedef struct fd_gui_hist_kv_slot_iter fd_gui_hist_kv_slot_iter_t;
89 :
90 : /* fd_gui_hist_range_filter_fn is an optional per-record predicate
91 : evaluated during a range scan: called with a pointer to the DB's
92 : record and the caller's `ctx`, it returns non-zero to emit the record
93 : or zero to skip it. A NULL filter emits every record in the window
94 : range. */
95 :
96 : typedef int (*fd_gui_hist_range_filter_fn)( void const * rec, void * ctx );
97 :
98 : /* fd_gui_hist_iter_t iterates the records produced by a time-window
99 : range query.
100 :
101 : Records are emitted oldest-window-first, but the backend does not
102 : strictly order records within a window.
103 : */
104 : struct fd_gui_hist_iter {
105 : void const * rec;
106 : ulong rec_sz;
107 :
108 : int _dbi;
109 : int _emitted;
110 : fd_gui_hist_range_filter_fn _filter;
111 : void * _filter_ctx;
112 : fd_gui_store_ts_iter_t _it;
113 : };
114 :
115 : typedef struct fd_gui_hist_iter fd_gui_hist_iter_t;
116 :
117 : FD_PROTOTYPES_BEGIN
118 :
119 : FD_FN_CONST ulong
120 : fd_gui_hist_align( void );
121 :
122 : FD_FN_CONST ulong
123 : fd_gui_hist_footprint( void );
124 :
125 : /* fd_gui_hist_new formats the workspace region `mem`
126 : (>= fd_gui_hist_footprint bytes, fd_gui_hist_align aligned) as the
127 : history semantics layer over the store `db`. Returns `mem` on success
128 : or NULL on failure (logged). */
129 :
130 : void *
131 : fd_gui_hist_new( void * mem,
132 : fd_gui_store_t const * db );
133 :
134 : /* fd_gui_hist_join joins a region formatted by fd_gui_hist_new,
135 : returning a usable handle (mem may be NULL -> NULL). */
136 :
137 : fd_gui_hist_t *
138 : fd_gui_hist_join( void * mem );
139 :
140 : void *
141 : fd_gui_hist_leave( fd_gui_hist_t * hist );
142 :
143 : void *
144 : fd_gui_hist_delete( void * mem );
145 :
146 : /* fd_gui_hist_db_descs fills descs with the FD_GUI_HIST_CNT DB
147 : descriptors for a store of store_bytes, and returns descs. */
148 :
149 : fd_gui_store_desc_t *
150 : fd_gui_hist_db_descs( fd_gui_store_desc_t descs[ static FD_GUI_HIST_CNT ],
151 : ulong store_bytes );
152 :
153 : FD_FN_CONST static inline ulong
154 0 : fd_gui_hist_db_cnt( void ) { return FD_GUI_HIST_CNT; }
155 :
156 : /* fd_gui_hist_store_footprint returns the footprint of a store of
157 : store_bytes holding the history DBs, or 0 if store_bytes is too
158 : small. */
159 :
160 : ulong
161 : fd_gui_hist_store_footprint( ulong store_bytes );
162 :
163 : /* fd_gui_hist_store_new formats mem as a store of store_bytes backed
164 : by path, holding the history DBs. The result is ready to join and
165 : pass to fd_gui_hist_new. Returns mem on success or NULL on failure
166 : (logged, see fd_gui_store_new). */
167 :
168 : void *
169 : fd_gui_hist_store_new( void * mem,
170 : char const * path,
171 : ulong store_bytes,
172 : ulong seed );
173 :
174 : fd_gui_hist_metrics_t const *
175 : fd_gui_hist_metrics( fd_gui_t const * gui );
176 :
177 : /* ---- TS read/write -------------------------------------------------- */
178 :
179 : /* fd_gui_hist_ts_append copies the record at val into time-series DB
180 : dbi, preserving its contents. The timestamp at the DB's configured
181 : offset must be >= the timestamp of the last successful append.
182 :
183 : Returns 0 on success, -1 for an invalid DB, a decreasing timestamp,
184 : or a store append failure. */
185 :
186 : int
187 : fd_gui_hist_ts_append( fd_gui_t * gui,
188 : int dbi,
189 : void const * val );
190 :
191 : /* fd_gui_hist_ts_emplace is fd_gui_hist_ts_append without the copy: it
192 : appends a record whose timestamp field is stored_ts and returns a
193 : pointer to it in the store, or NULL on the same failures. */
194 :
195 : void *
196 : fd_gui_hist_ts_emplace( fd_gui_t * gui,
197 : int dbi,
198 : long stored_ts );
199 :
200 : int
201 : fd_gui_hist_range_begin( fd_gui_t * gui,
202 : fd_gui_hist_iter_t * iter,
203 : int dbi,
204 : long lo_ns,
205 : long hi_ns,
206 : fd_gui_hist_range_filter_fn filter,
207 : void * filter_ctx );
208 :
209 : int
210 : fd_gui_hist_range_next( fd_gui_hist_iter_t * iter );
211 :
212 : void
213 : fd_gui_hist_range_end( fd_gui_hist_iter_t * iter );
214 :
215 :
216 : /* ---- KV read/write -------------------------------------------------- */
217 :
218 : /* fd_gui_hist_kv_get_or_create reserves (creating if absent) the record
219 : for `*key` in a KV DB and returns a mutable pointer to the record's
220 : value, or NULL on failure.
221 :
222 : Will evict old entries to make room if necessary. Returns the value
223 : pointer on success, or NULL on error. */
224 :
225 : void *
226 : fd_gui_hist_kv_get_or_create( fd_gui_t * gui,
227 : int dbi,
228 : void const * key );
229 :
230 : /* fd_gui_hist_kv_get is like fd_gui_hist_kv_get_or_create, but returns
231 : NULL when the record is not found instead of creating one. */
232 :
233 : void *
234 : fd_gui_hist_kv_get( fd_gui_t * gui,
235 : int dbi,
236 : void const * key );
237 :
238 : /* fd_gui_hist_kv_get_slot_any looks up the slot record for the first
239 : key matching (slot, *) and returns a pointer to its value. */
240 :
241 : void *
242 : fd_gui_hist_kv_get_slot_any( fd_gui_t * gui,
243 : int dbi,
244 : ulong slot );
245 :
246 : fd_gui_hist_kv_slot_iter_t *
247 : fd_gui_hist_kv_iter_begin( fd_gui_t * gui,
248 : fd_gui_hist_kv_slot_iter_t * iter,
249 : int dbi,
250 : ulong slot );
251 :
252 : int
253 : fd_gui_hist_kv_iter_next( fd_gui_hist_kv_slot_iter_t * iter );
254 :
255 : /* ---- Eviction ------------------------------------------------------- */
256 :
257 : /* fd_gui_hist_evict_step reclaims at most FD_GUI_HIST_EVICT_BATCH
258 : records from an oldest excess region once at most one shared region
259 : remains free. Every DB's newest base_regions regions are protected
260 : (see fd_gui_hist_db_descs). FEC staging is never evicted; it only
261 : drains through fd_gui_fec_archive. Returns 1 for actual progress, 0
262 : when idle or all candidates pinned. Writes retry on pressure, then
263 : recycle only their own eligible history if no excess candidate
264 : remains. */
265 :
266 : int
267 : fd_gui_hist_evict_step( fd_gui_t * gui );
268 :
269 : FD_PROTOTYPES_END
270 :
271 : #endif /* HEADER_fd_src_disco_gui_fd_gui_hist_h */
|