Files
Jungfraujoch/receiver/RugnuxLiveStatus.cpp
T
leonarski_fandClaude Opus 5.5 cf2e0f7995 broker rugnux live: an END too large for the pushers' buffer goes without the result blocks
Every image pusher serialises END into its fixed MESSAGE_SIZE_FOR_START_END (256 MiB) buffer, and an
overflow there throws out of SendEndMessage: the writer never gets END and the collection errors. The
try in AddToEndMessage only covered filling the message. AddToEndMessage now serialises the finished
END once into a scratch buffer of the same size (uninitialised, so only the bytes written are
touched) and, where it does not fit, drops the merged data, map coefficients and placed model, with
an error in the log and a warning in the live status (RugnuxLiveStatus::Warning). The pusher then
serialises exactly the message that was checked.

The receiving side already takes an END this large: the TCP puller accepts payloads up to
JFJOCH_TCP_MAX_PAYLOAD_SIZE (1 GiB), the ZMQ sockets set no ZMQ_MAXMSGSIZE, and the puller's ring
buffer serves a message larger than its capacity from the heap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 20:36:23 +02:00

101 lines
2.8 KiB
C++

// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#include "RugnuxLiveStatus.h"
double RugnuxLiveStatus::Now() const {
return std::chrono::duration<double>(std::chrono::steady_clock::now() - start).count();
}
void RugnuxLiveStatus::CloseStep() {
if (!s.steps.empty() && !s.steps.back().duration_s)
s.steps.back().duration_s = Now() - s.steps.back().started_s;
}
void RugnuxLiveStatus::Start(int64_t images_expected) {
std::unique_lock ul(m);
s = RugnuxLiveSnapshot{};
s.state = RugnuxLiveState::Running;
s.images_expected = images_expected;
start = std::chrono::steady_clock::now();
}
void RugnuxLiveStatus::ImageReceived() {
std::unique_lock ul(m);
++s.images_received;
}
void RugnuxLiveStatus::Step(const std::string &title) {
std::unique_lock ul(m);
CloseStep();
s.steps.push_back(RugnuxLiveStep{.title = title, .started_s = Now()});
s.step_progress.reset();
}
void RugnuxLiveStatus::Note(const std::string &text) {
std::unique_lock ul(m);
if (s.steps.empty())
s.steps.push_back(RugnuxLiveStep{.title = "", .started_s = Now()});
s.steps.back().notes.push_back(text);
}
void RugnuxLiveStatus::Progress(uint64_t done, uint64_t total) {
std::unique_lock ul(m);
if (total > 0)
s.step_progress = static_cast<float>(done) / static_cast<float>(total);
}
void RugnuxLiveStatus::Finish(RugnuxLiveState state, const std::string &message) {
std::unique_lock ul(m);
CloseStep();
s.elapsed_s = Now();
s.state = state;
s.message = message;
s.step_progress.reset();
}
void RugnuxLiveStatus::Result(const std::string &verdict, const std::string &verdict_text,
const std::vector<std::pair<std::string, std::string>> &summary,
const std::vector<std::string> &warnings) {
std::unique_lock ul(m);
s.verdict = verdict;
s.verdict_text = verdict_text;
s.summary = summary;
s.warnings = warnings;
}
void RugnuxLiveStatus::Latency(double last_image_to_written_s) {
std::unique_lock ul(m);
s.last_image_to_written_s = last_image_to_written_s;
}
void RugnuxLiveStatus::LastImage() {
std::unique_lock ul(m);
s.last_image_s = Now();
}
void RugnuxLiveStatus::Cut(const std::string &reason) {
std::unique_lock ul(m);
s.cut = reason;
s.cut_s = Now();
}
void RugnuxLiveStatus::Probe(const std::string &text) {
std::unique_lock ul(m);
s.probe = text;
s.probe_s = Now();
}
void RugnuxLiveStatus::Warning(const std::string &text) {
std::unique_lock ul(m);
s.warnings.push_back(text);
}
RugnuxLiveSnapshot RugnuxLiveStatus::Get() const {
std::unique_lock ul(m);
RugnuxLiveSnapshot ret = s;
if (s.state == RugnuxLiveState::Running)
ret.elapsed_s = Now();
return ret;
}