Skip to content

Commit 10283ef

Browse files
committed
gui: catchup shred history
1 parent e97dd83 commit 10283ef

File tree

3 files changed

+149
-17
lines changed

3 files changed

+149
-17
lines changed

book/api/websocket.md

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -324,9 +324,11 @@ Frankendancer client will always publish `null` for this message
324324
| *Once* | `CatchUpHistory` | see below |
325325

326326
This validator records a history of all slots that were received from
327-
turbine as well as slots for which a repair request was made while it is
327+
turbine or repair responses, as well as shred events that occurred while
328328
catching up. After catching up, slots are no longer recorded in this
329-
history.
329+
history. For repair and turbine slots, the history is available for the
330+
lifetime of the validator. Shred events are only available if the
331+
validator is in the catching up phase.
330332

331333
::: details Example
332334

@@ -336,13 +338,29 @@ history.
336338
"key": "catch_up_history",
337339
"value": {
338340
"repair": [11, 12, 13, ...],
339-
"turbine": [21, 22, 23, ...]
341+
"turbine": [21, 22, 23, ...],
342+
"shreds": {
343+
"reference_slot": 289245044,
344+
"reference_ts": "1739657041588242791",
345+
"slot_delta": [0, 0],
346+
"shred_idx": [1234, null],
347+
"event": [0, 1],
348+
"event_ts_delta": ["1000000", "2000000"]
349+
}
340350
}
341351
}
342352
```
343353

344354
:::
345355

356+
**`CatchUpHistory`**
357+
| Field | Type | Description |
358+
|------------|---------------|-------------|
359+
| repair | `number[]` | A list of all slots for which a repair shred was received that are older than `summary.caught_up_slot` |
360+
| turbine | `number[]` | A list of all slots for which a turbine shred was received that are older than `summary.caught_up_slot` |
361+
| shreds | `SlotShreds` | A list of shred events which have occurred for this validator in the past 15 seconds. If the validator has already caught up, or has not yet started catching up, then `null` |
362+
363+
346364
#### `summary.startup_time_nanos`
347365
| frequency | type | example |
348366
|-----------|----------|---------------------|
@@ -1594,7 +1612,7 @@ rooted.
15941612
#### `slot.live_shreds`
15951613
| frequency | type | example |
15961614
|-------------|---------------|---------|
1597-
| *10ms* | `SlotShred[]` | below |
1615+
| *10ms* | `SlotShreds` | below |
15981616

15991617
The validator sends a continous stream of update messages with detailed
16001618
information about the time and duration of different shred state
@@ -1620,7 +1638,7 @@ and is broadcast to all WebSocket clients.
16201638

16211639
:::
16221640

1623-
**`SlotShred`**
1641+
**`SlotShreds`**
16241642
| Field | Type | Description |
16251643
|-----------------|--------------------|-------------|
16261644
| reference_slot | `number`   | The smallest slot number across all the shreds in a given message |
@@ -1633,7 +1651,7 @@ and is broadcast to all WebSocket clients.
16331651
#### `slot.query_shreds`
16341652
| frequency | type | example |
16351653
|-------------|---------------|---------|
1636-
| *Request* | `SlotShred[]\null` | below |
1654+
| *Request* | `SlotShreds\|null` | below |
16371655

16381656
| param | type | description |
16391657
|-------|----------|-------------|

src/disco/gui/fd_gui.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1284,7 +1284,7 @@ fd_gui_request_slot_shreds( fd_gui_t * gui,
12841284

12851285
fd_gui_slot_t const * slot = fd_gui_get_slot( gui, _slot );
12861286
if( FD_UNLIKELY( !slot || gui->shreds.history_tail > slot->shreds.end_offset + FD_GUI_SHREDS_HISTORY_SZ ) ) {
1287-
fd_gui_printf_null_query_response( gui->http, "slot", "query_rankings", request_id );
1287+
fd_gui_printf_null_query_response( gui->http, "slot", "query_shreds", request_id );
12881288
FD_TEST( !fd_http_server_ws_send( gui->http, ws_conn_id ) );
12891289
return 0;
12901290
}

src/disco/gui/fd_gui_printf.c

Lines changed: 124 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,112 @@ fd_gui_printf_catch_up_history( fd_gui_t * gui ) {
275275
}
276276
}
277277
jsonp_close_array( gui->http );
278+
279+
if( FD_LIKELY( gui->summary.boot_progress.phase==FD_GUI_BOOT_PROGRESS_TYPE_CATCHING_UP ) ) {
280+
ulong min_slot = ULONG_MAX;
281+
long min_ts = LONG_MAX;
282+
283+
for( ulong i=gui->shreds.staged_tail; i>0UL && i>gui->shreds.staged_head; i-- ) {
284+
long ts = gui->shreds.staged[ (i-1UL) % FD_GUI_SHREDS_STAGING_SZ ].timestamp;
285+
if( FD_UNLIKELY( ts < gui->summary.boot_progress.catching_up_time_nanos - 15000000000 ) ) break;
286+
ulong slot = gui->shreds.staged[ (i-1UL) % FD_GUI_SHREDS_STAGING_SZ ].slot;
287+
min_slot = fd_ulong_min( min_slot, slot );
288+
min_ts = fd_long_min( min_ts, ts );
289+
}
290+
291+
fd_gui_slot_t * s = fd_gui_get_slot( gui, gui->shreds.history_slot );
292+
while( s
293+
&& s->shreds.start_offset!=ULONG_MAX
294+
&& s->shreds.end_offset!=ULONG_MAX
295+
&& gui->shreds.history[ s->shreds.start_offset % FD_GUI_SHREDS_HISTORY_SZ ].timestamp < (gui->summary.boot_progress.catching_up_time_nanos - 15000000000) ) {
296+
min_slot = fd_ulong_min( min_slot, s->slot );
297+
min_ts = fd_long_min( min_ts, gui->shreds.history[ s->shreds.start_offset % FD_GUI_SHREDS_HISTORY_SZ ].timestamp );
298+
s = fd_gui_get_slot( gui, s->parent_slot );
299+
}
300+
301+
jsonp_open_object( gui->http, "shreds" );
302+
jsonp_ulong ( gui->http, "reference_slot", min_slot );
303+
jsonp_long_as_str( gui->http, "reference_ts", min_ts );
304+
305+
jsonp_open_array( gui->http, "slot_delta" );
306+
for( ulong i=gui->shreds.staged_tail; i>0UL && i>gui->shreds.staged_head; i-- ) {
307+
long ts = gui->shreds.staged[ (i-1UL) % FD_GUI_SHREDS_STAGING_SZ ].timestamp;
308+
if( FD_UNLIKELY( ts < gui->summary.boot_progress.catching_up_time_nanos - 15000000000 ) ) break;
309+
jsonp_ulong( gui->http, NULL, gui->shreds.staged[ (i-1UL) % FD_GUI_SHREDS_STAGING_SZ ].slot-min_slot );
310+
}
311+
312+
s = fd_gui_get_slot( gui, gui->shreds.history_slot );
313+
while( s
314+
&& s->shreds.start_offset!=ULONG_MAX
315+
&& s->shreds.end_offset!=ULONG_MAX
316+
&& gui->shreds.history[ s->shreds.start_offset % FD_GUI_SHREDS_HISTORY_SZ ].timestamp < (gui->summary.boot_progress.catching_up_time_nanos - 15000000000) ) {
317+
for( ulong i=s->shreds.start_offset; i<s->shreds.end_offset; i++ ) {
318+
jsonp_ulong( gui->http, NULL, s->slot-min_slot );
319+
}
320+
s = fd_gui_get_slot( gui, s->parent_slot );
321+
}
322+
jsonp_close_array( gui->http );
323+
jsonp_open_array( gui->http, "shred_idx" );
324+
for( ulong i=gui->shreds.staged_tail; i>0UL && i>gui->shreds.staged_head; i-- ) {
325+
long ts = gui->shreds.staged[ (i-1UL) % FD_GUI_SHREDS_STAGING_SZ ].timestamp;
326+
if( FD_UNLIKELY( ts < gui->summary.boot_progress.catching_up_time_nanos - 15000000000 ) ) break;
327+
if( FD_LIKELY( gui->shreds.staged[ (i-1UL) % FD_GUI_SHREDS_STAGING_SZ ].shred_idx!=USHORT_MAX ) ) jsonp_ulong( gui->http, NULL, gui->shreds.staged[ (i-1UL) % FD_GUI_SHREDS_STAGING_SZ ].shred_idx );
328+
else jsonp_null ( gui->http, NULL );
329+
}
330+
331+
s = fd_gui_get_slot( gui, gui->shreds.history_slot );
332+
while( s
333+
&& s->shreds.start_offset!=ULONG_MAX
334+
&& s->shreds.end_offset!=ULONG_MAX
335+
&& gui->shreds.history[ s->shreds.start_offset % FD_GUI_SHREDS_HISTORY_SZ ].timestamp < (gui->summary.boot_progress.catching_up_time_nanos - 15000000000) ) {
336+
for( ulong i=s->shreds.start_offset; i<s->shreds.end_offset; i++ ) {
337+
if( FD_LIKELY( gui->shreds.history[ i % FD_GUI_SHREDS_HISTORY_SZ ].shred_idx!=USHORT_MAX ) ) jsonp_ulong( gui->http, NULL, gui->shreds.history[ i % FD_GUI_SHREDS_HISTORY_SZ ].shred_idx );
338+
else jsonp_null ( gui->http, NULL );
339+
}
340+
s = fd_gui_get_slot( gui, s->parent_slot );
341+
}
342+
jsonp_close_array( gui->http );
343+
jsonp_open_array( gui->http, "event" );
344+
for( ulong i=gui->shreds.staged_tail; i>0UL && i>gui->shreds.staged_head; i-- ) {
345+
long ts = gui->shreds.staged[ (i-1UL) % FD_GUI_SHREDS_STAGING_SZ ].timestamp;
346+
if( FD_UNLIKELY( ts < gui->summary.boot_progress.catching_up_time_nanos - 15000000000 ) ) break;
347+
jsonp_ulong( gui->http, NULL, gui->shreds.staged[ (i-1UL) % FD_GUI_SHREDS_STAGING_SZ ].event );
348+
}
349+
350+
s = fd_gui_get_slot( gui, gui->shreds.history_slot );
351+
while( s
352+
&& s->shreds.start_offset!=ULONG_MAX
353+
&& s->shreds.end_offset!=ULONG_MAX
354+
&& gui->shreds.history[ s->shreds.start_offset % FD_GUI_SHREDS_HISTORY_SZ ].timestamp < (gui->summary.boot_progress.catching_up_time_nanos - 15000000000) ) {
355+
for( ulong i=s->shreds.start_offset; i<s->shreds.end_offset; i++ ) {
356+
jsonp_ulong( gui->http, NULL, gui->shreds.history[ i % FD_GUI_SHREDS_HISTORY_SZ ].event );
357+
}
358+
s = fd_gui_get_slot( gui, s->parent_slot );
359+
}
360+
jsonp_close_array( gui->http );
361+
jsonp_open_array( gui->http, "event_ts_delta" );
362+
for( ulong i=gui->shreds.staged_tail; i>0UL && i>gui->shreds.staged_head; i-- ) {
363+
long ts = gui->shreds.staged[ (i-1UL) % FD_GUI_SHREDS_STAGING_SZ ].timestamp;
364+
if( FD_UNLIKELY( ts < gui->summary.boot_progress.catching_up_time_nanos - 15000000000 ) ) break;
365+
jsonp_long_as_str( gui->http, NULL, gui->shreds.staged[ (i-1UL) % FD_GUI_SHREDS_STAGING_SZ ].timestamp-min_ts );
366+
}
367+
368+
s = fd_gui_get_slot( gui, gui->shreds.history_slot );
369+
while( s
370+
&& s->shreds.start_offset!=ULONG_MAX
371+
&& s->shreds.end_offset!=ULONG_MAX
372+
&& gui->shreds.history[ s->shreds.start_offset % FD_GUI_SHREDS_HISTORY_SZ ].timestamp < (gui->summary.boot_progress.catching_up_time_nanos - 15000000000) ) {
373+
for( ulong i=s->shreds.start_offset; i<s->shreds.end_offset; i++ ) {
374+
jsonp_long_as_str( gui->http, NULL, gui->shreds.history[ i % FD_GUI_SHREDS_HISTORY_SZ ].timestamp-min_ts );
375+
}
376+
s = fd_gui_get_slot( gui, s->parent_slot );
377+
}
378+
jsonp_close_array( gui->http );
379+
jsonp_close_object( gui->http );
380+
} else {
381+
jsonp_null( gui->http, "shreds" );
382+
}
383+
278384
jsonp_close_object( gui->http );
279385
jsonp_close_envelope( gui->http );
280386
}
@@ -2120,37 +2226,45 @@ void
21202226
fd_gui_printf_slot_shred_updates( fd_gui_t * gui,
21212227
ulong _slot,
21222228
ulong id ) {
2123-
ulong _start_offset = gui->slots[ _slot % FD_GUI_SLOTS_CNT ]->shreds.start_offset;
2124-
ulong _end_offset = gui->slots[ _slot % FD_GUI_SLOTS_CNT ]->shreds.end_offset;
2229+
fd_gui_slot_t * slot = fd_gui_get_slot( gui, _slot );
2230+
2231+
if( FD_UNLIKELY( !slot || slot->shreds.end_offset <= gui->shreds.history_tail-FD_GUI_SHREDS_HISTORY_SZ ) ) {
2232+
jsonp_open_envelope( gui->http, "slot", "query_shreds" );
2233+
jsonp_ulong( gui->http, "id", id );
2234+
jsonp_null( gui->http, "value" );
2235+
jsonp_close_envelope( gui->http );
2236+
return;
2237+
}
2238+
2239+
ulong _start_offset = slot->shreds.start_offset;
2240+
ulong _end_offset = slot->shreds.end_offset;
21252241

2126-
ulong min_slot = ULONG_MAX;
21272242
long min_ts = LONG_MAX;
21282243

21292244
for( ulong i=_start_offset; i<_end_offset; i++ ) {
2130-
min_slot = fd_ulong_min( min_slot, gui->shreds.staged[ i % FD_GUI_SHREDS_STAGING_SZ ].slot );
2131-
min_ts = fd_long_min ( min_ts, gui->shreds.staged[ i % FD_GUI_SHREDS_STAGING_SZ ].timestamp );
2245+
min_ts = fd_long_min ( min_ts, gui->shreds.history[ i % FD_GUI_SHREDS_HISTORY_SZ ].timestamp );
21322246
}
21332247

21342248
jsonp_open_envelope( gui->http, "slot", "query_shreds" );
21352249
jsonp_ulong( gui->http, "id", id );
21362250
jsonp_open_object( gui->http, "value" );
2137-
jsonp_ulong ( gui->http, "reference_slot", min_slot );
2251+
jsonp_ulong ( gui->http, "reference_slot", _slot );
21382252
jsonp_long_as_str( gui->http, "reference_ts", min_ts );
21392253

21402254
jsonp_open_array( gui->http, "slot_delta" );
2141-
for( ulong i=_start_offset; i<_end_offset; i++ ) jsonp_ulong( gui->http, NULL, gui->shreds.staged[ i % FD_GUI_SHREDS_STAGING_SZ ].slot-min_slot );
2255+
for( ulong i=_start_offset; i<_end_offset; i++ ) jsonp_ulong( gui->http, NULL, 0UL );
21422256
jsonp_close_array( gui->http );
21432257
jsonp_open_array( gui->http, "shred_idx" );
21442258
for( ulong i=_start_offset; i<_end_offset; i++ ) {
2145-
if( FD_LIKELY( gui->shreds.staged[ i % FD_GUI_SHREDS_STAGING_SZ ].shred_idx!=USHORT_MAX ) ) jsonp_ulong( gui->http, NULL, gui->shreds.staged[ i % FD_GUI_SHREDS_STAGING_SZ ].shred_idx );
2259+
if( FD_LIKELY( gui->shreds.staged[ i % FD_GUI_SHREDS_STAGING_SZ ].shred_idx!=USHORT_MAX ) ) jsonp_ulong( gui->http, NULL, gui->shreds.history[ i % FD_GUI_SHREDS_HISTORY_SZ ].shred_idx );
21462260
else jsonp_null ( gui->http, NULL );
21472261
}
21482262
jsonp_close_array( gui->http );
21492263
jsonp_open_array( gui->http, "event" );
2150-
for( ulong i=_start_offset; i<_end_offset; i++ ) jsonp_ulong( gui->http, NULL, gui->shreds.staged[ i % FD_GUI_SHREDS_STAGING_SZ ].event );
2264+
for( ulong i=_start_offset; i<_end_offset; i++ ) jsonp_ulong( gui->http, NULL, gui->shreds.history[ i % FD_GUI_SHREDS_HISTORY_SZ ].event );
21512265
jsonp_close_array( gui->http );
21522266
jsonp_open_array( gui->http, "event_ts_delta" );
2153-
for( ulong i=_start_offset; i<_end_offset; i++ ) jsonp_long_as_str( gui->http, NULL, gui->shreds.staged[ i % FD_GUI_SHREDS_STAGING_SZ ].timestamp-min_ts );
2267+
for( ulong i=_start_offset; i<_end_offset; i++ ) jsonp_long_as_str( gui->http, NULL, gui->shreds.history[ i % FD_GUI_SHREDS_HISTORY_SZ ].timestamp-min_ts );
21542268
jsonp_close_array( gui->http );
21552269
jsonp_close_object( gui->http );
21562270
jsonp_close_envelope( gui->http );

0 commit comments

Comments
 (0)