use super::*;
impl BlockSyncReactor {
pub(super) fn emit_block(
&self,
event: &'static str,
build: impl FnOnce(&mut BlockTraceFields),
) {
self.startup
.trace
.emit_event(|| BlockTraceEvent::build(event, build));
}
pub(super) fn trace_floor_watchdog_cancelled(
&self,
claim: &OutstandingClaim,
released: super::super::work_queue::WorkReturnOutcome,
) {
self.emit_block(bs_trace::BLOCK_FLOOR_WATCHDOG_CANCELLED, |row| {
row.peer = Some(peer(&claim.peer));
row.height = Some(super::super::trace::height(claim.height));
row.estimated_bytes = Some(claim.meta.estimated_bytes);
row.released_bytes = Some(released.released_bytes);
row.returned_count = Some(released.returned_count);
row.already_pending_count = Some(released.already_pending_count);
row.released_count = Some(released.released_count);
row.missing_count = Some(released.missing_count);
row.pending_after = Some(u64::from(
self.state.work_queue.pending_contains(claim.height),
));
row.in_flight_after = Some(u64::from(
self.state.work_queue.in_flight_contains(claim.height),
));
});
}
pub(super) fn refresh_throughput(&mut self) {
let now = Instant::now();
if let Ok(mut meter) = self.state.received_throughput.lock() {
meter.sample(now);
}
}
pub(super) fn trace_sync_state(&self, include_diagnostics: bool) {
self.emit_block(bs_trace::BLOCK_SYNC_STATE, |row| {
let floor_gap = include_diagnostics
.then(|| self.floor_gap_diagnostics(Instant::now()))
.flatten();
let slots = include_diagnostics.then(|| self.registry.slot_summary());
let counts = include_diagnostics.then(|| self.registry.direction_status_counts());
let peers_with_status = include_diagnostics.then(|| self.registry.peers_with_status());
let view = self.last_view;
let submitted_applies = view.in_flight_submission_count;
let (received_bytes_per_sec, received_blocks_per_sec) = self
.state
.received_throughput
.lock()
.map(|meter| (meter.bytes_per_sec(), meter.blocks_per_sec()))
.unwrap_or((0, 0));
row.request_floor = Some(height(self.request_floor));
row.body_download_floor = Some(height(view.download_floor));
row.verified_block_tip = Some(height(view.verified_tip));
row.best_header_tip = Some(height(self.state.best_header_tip));
row.body_lag = Some(u64::from(self.body_lag()));
row.applying = Some(view.applying_len);
row.submitted_applies = Some(submitted_applies);
row.reorder = Some(view.reorder_len);
if let Some(slots) = slots {
row.outstanding = Some(saturating_usize(slots.outstanding_requests));
}
if let Some(floor_gap) = floor_gap {
row.floor_gap_height = Some(height(floor_gap.height));
row.floor_gap_state = Some(floor_gap.state);
row.floor_gap_servable_peers = Some(saturating_usize(floor_gap.servable_peers));
row.floor_gap_available_peers = Some(saturating_usize(floor_gap.available_peers));
row.floor_gap_outstanding_peers =
Some(saturating_usize(floor_gap.outstanding_peers));
row.floor_gap_oldest_outstanding_ms = floor_gap.oldest_outstanding_ms;
row.floor_gap_next_deadline_ms = floor_gap.next_deadline_ms;
}
row.budget_available = Some(self.state.budget.available());
row.budget_reserved = Some(self.state.budget.reserved());
let sequencer_input_queued_bytes = self
.sequencer_input_bytes
.load(std::sync::atomic::Ordering::Relaxed);
let sequencer_input_decoded_attributed_memory_bytes = self
.sequencer_input_decoded_attributed_memory_bytes
.load(std::sync::atomic::Ordering::Relaxed);
let sequencer_input_max_capacity = self.sequencer_input.max_capacity();
let sequencer_input_capacity = self.sequencer_input.capacity();
let sequencer_input_queued_blocks =
sequencer_input_max_capacity.saturating_sub(sequencer_input_capacity);
row.sequencer_input_queued_bytes = Some(sequencer_input_queued_bytes);
row.sequencer_input_decoded_attributed_memory_bytes =
Some(sequencer_input_decoded_attributed_memory_bytes);
row.reorder_decoded_attributed_memory_bytes =
Some(view.reorder_decoded_attributed_memory_bytes);
row.applying_decoded_attributed_memory_bytes =
Some(view.applying_decoded_attributed_memory_bytes);
row.active_pipeline_decoded_attributed_memory_bytes = Some(
sequencer_input_decoded_attributed_memory_bytes
.saturating_add(view.reorder_decoded_attributed_memory_bytes)
.saturating_add(view.applying_decoded_attributed_memory_bytes),
);
row.sequencer_input_queued_blocks =
Some(saturating_usize(sequencer_input_queued_blocks));
row.sequencer_input_capacity = Some(saturating_usize(sequencer_input_capacity));
row.sequencer_input_max_capacity = Some(saturating_usize(sequencer_input_max_capacity));
row.reorder_buffered_bytes = Some(view.reorder_buffered_bytes);
row.applying_buffered_bytes = Some(view.applying_buffered_bytes);
row.unsubmitted_applying_count = Some(view.unsubmitted_applying_count);
row.in_flight_submission_bytes = Some(view.in_flight_submission_bytes);
row.retained_pipeline_wire_bytes = Some(
super::super::admission::RetainedPipelineBytes {
reorder_buffered_bytes: view.reorder_buffered_bytes,
applying_buffered_bytes: view.applying_buffered_bytes,
sequencer_input_queued_bytes,
}
.wire_bytes(),
);
row.peers = Some(saturating_usize(self.state.peers.len()));
if let Some(peers_with_status) = peers_with_status {
row.peers_with_status = Some(saturating_usize(peers_with_status));
}
if let (Some(slots), Some(peers_with_status)) = (slots, peers_with_status) {
let peers_wanting_slots = peers_with_status.saturating_sub(slots.saturated_peers);
let download_blocked_on_budget = u64::from(
peers_wanting_slots > 0
&& self.state.budget.available() < BS_PER_BLOCK_WORST_CASE_BYTES,
);
row.peers_wanting_slots = Some(saturating_usize(peers_wanting_slots));
row.download_blocked_on_budget = Some(download_blocked_on_budget);
}
row.received_bytes_per_sec = Some(received_bytes_per_sec);
row.received_blocks_per_sec = Some(received_blocks_per_sec);
row.committed_bytes_per_sec = Some(view.committed_bytes_per_sec);
row.committed_blocks_per_sec = Some(view.committed_blocks_per_sec);
if let Some(counts) = counts {
row.inbound_peers = Some(saturating_usize(counts.inbound));
row.outbound_peers = Some(saturating_usize(counts.outbound));
row.inbound_peers_with_status = Some(saturating_usize(counts.inbound_with_status));
row.outbound_peers_with_status =
Some(saturating_usize(counts.outbound_with_status));
}
if let Some(slots) = slots {
row.request_slot_capacity = Some(saturating_usize(slots.capacity));
row.request_slot_effective_window = Some(saturating_usize(slots.effective_window));
row.request_slot_available = Some(saturating_usize(slots.available));
row.request_slot_saturated_peers = Some(saturating_usize(slots.saturated_peers));
}
if include_diagnostics {
if let Some(min) = self.state.needed_heights.first() {
row.needed_min = Some(height(*min));
}
row.needed_count = Some(saturating_usize(self.state.needed_heights.len()));
row.queue_len = Some(saturating_usize(self.state.work_queue.pending_run_count()));
row.queue_blocks = Some(saturating_usize(self.state.work_queue.pending_len()));
if let Some(start) = self.state.work_queue.min_pending() {
row.queue_min_start = Some(height(start));
}
row.assigned_len = Some(saturating_usize(self.state.work_queue.in_flight_len()));
row.local_body_work = Some(saturating_usize(self.local_body_work_blocks()));
row.refill_low_water = Some(saturating_usize(self.refill_low_water_blocks()));
if let Some(end) = self.state.work_queue.max_in_flight() {
row.covered_max_end = Some(height(end));
}
}
});
}
pub(super) fn trace_status_sent(
&self,
peer: &ZakuraPeerId,
reason: &'static str,
status: BlockSyncStatus,
) {
self.emit_block(bs_trace::BLOCK_STATUS_SENT, |row| {
row.peer = Some(super::super::trace::peer(peer));
row.reason = Some(reason);
status_fields(row, status);
});
}
pub(super) fn trace_status_send_failed(&self, peer: &ZakuraPeerId, reason: &'static str) {
self.emit_block(bs_trace::BLOCK_STATUS_SEND_FAILED, |row| {
row.peer = Some(super::super::trace::peer(peer));
row.reason = Some(reason);
});
}
pub(super) fn trace_queue_send_failed(
&self,
peer: &ZakuraPeerId,
msg: &BlockSyncMessage,
error: &OrderedSendError,
queue_capacity: usize,
queue_max_capacity: usize,
reason: Option<&'static str>,
) {
self.startup.trace.emit_event(|| {
QueueSendFailedEvent::new(peer, msg, error, reason, queue_capacity, queue_max_capacity)
});
}
pub(super) fn trace_peer_connected(
&self,
peer: &ZakuraPeerId,
direction: ServicePeerDirection,
active_connections: usize,
) {
self.emit_block(bs_trace::BLOCK_PEER_CONNECTED, |row| {
row.peer = Some(super::super::trace::peer(peer));
row.direction = Some(direction.trace_label());
row.active_connections = Some(saturating_usize(active_connections));
});
}
pub(super) fn trace_peer_disconnected(
&self,
peer: &ZakuraPeerId,
received_status: bool,
active_connections: usize,
) {
self.emit_block(bs_trace::BLOCK_PEER_DISCONNECTED, |row| {
row.peer = Some(super::super::trace::peer(peer));
row.received_status = Some(BoolOrU64::Bool(received_status));
row.active_connections = Some(saturating_usize(active_connections));
});
}
pub(super) fn trace_message_sent(
&self,
peer: &ZakuraPeerId,
msg: &BlockSyncMessage,
result: &'static str,
elapsed: Duration,
) {
self.emit_block(bs_trace::BLOCK_MESSAGE_SENT, |row| {
row.peer = Some(super::super::trace::peer(peer));
row.kind = Some(block_sync_message_label(msg));
row.result = Some(result);
row.elapsed_ms = Some(elapsed_ms(elapsed));
project_message(row, msg);
});
}
pub(super) fn trace_apply_finished(
&self,
height: block::Height,
token: BlockApplyToken,
result: BlockApplyResult,
budget_reserved_after: u64,
) {
self.emit_block(bs_trace::BLOCK_APPLY_FINISHED, |row| {
row.height = Some(super::super::trace::height(height));
row.apply_token = Some(token);
row.result = Some(block_apply_result_label(result));
row.budget_reserved_after = Some(budget_reserved_after);
});
}
#[allow(clippy::too_many_arguments)]
pub(super) fn trace_sequencer_control_send(
&self,
kind: &'static str,
result: &'static str,
elapsed: Duration,
height: Option<block::Height>,
token: Option<BlockApplyToken>,
capacity: usize,
max_capacity: usize,
) {
self.emit_block(bs_trace::BLOCK_SEQUENCER_CONTROL_SENT, |row| {
row.kind = Some(kind);
row.result = Some(result);
row.elapsed_ms = Some(elapsed_ms(elapsed));
row.height = height.map(super::super::trace::height);
row.apply_token = token;
row.sequencer_input_capacity = Some(saturating_usize(capacity));
row.sequencer_input_max_capacity = Some(saturating_usize(max_capacity));
});
}
pub(super) fn trace_range_response_sent(
&self,
peer: &ZakuraPeerId,
response: RangeResponseTrace,
) {
self.emit_block(bs_trace::BLOCK_RANGE_RESPONSE_SENT, |row| {
row.peer = Some(super::super::trace::peer(peer));
row.range_start = Some(height(response.start_height));
row.range_count = Some(u64::from(response.sent_count));
row.expected_count = Some(u64::from(response.requested_count));
row.serialized_bytes = Some(response.sent_bytes);
row.reason = Some(response.reason);
row.prepare_elapsed_ms = response.prepare_elapsed.map(elapsed_ms);
row.send_elapsed_ms = Some(elapsed_ms(response.send_elapsed));
row.elapsed_ms = response.total_elapsed.map(elapsed_ms);
});
}
pub(super) fn trace_work_extended(&self, inserted: usize) {
if !self.startup.trace.is_enabled() {
return;
}
self.emit_block(bs_trace::BLOCK_WORK_EXTENDED, |row| {
row.range_count = Some(saturating_usize(inserted));
row.queue_blocks = Some(saturating_usize(self.state.work_queue.pending_len()));
});
}
pub(super) fn trace_frontiers_changed(&self, verified_block_tip: block::Height) {
self.emit_block(bs_trace::BLOCK_FRONTIERS_CHANGED, |row| {
row.verified_block_tip = Some(height(verified_block_tip));
row.best_header_tip = Some(height(self.state.best_header_tip));
});
}
pub(super) fn trace_chain_tip_reset(&self, verified_block_tip: block::Height) {
self.emit_block(bs_trace::BLOCK_CHAIN_TIP_RESET, |row| {
row.verified_block_tip = Some(height(verified_block_tip));
});
}
}