LDMX Software
FragmentBuffer.h
1#ifndef EVENTBUILDER_FRAGMENTBUFFER_H
2#define EVENTBUILDER_FRAGMENTBUFFER_H
3
4#include <map>
5#include <vector>
6#include <mutex>
7#include <chrono>
8#include "Fragment.h"
9#include <set>
10
11namespace eventbuilder {
12
14public:
15 using Timestamp = long long;
16
17 void add_fragment(DataFragment&& fragment) {
18 std::lock_guard<std::mutex> lock(m_mutex);
19
20 // Set reference time on first fragment
21 if (m_fragments.empty()) {
22 m_event_reference_time = fragment.header.timestamp;
23 }
24
25 m_fragments[fragment.header.timestamp].push_back(std::move(fragment));
26 }
27
28 bool has_expired_fragments(Timestamp reference_time, long long coherence_window_ns) {
29 std::lock_guard<std::mutex> lock(m_mutex);
30 if (m_fragments.empty()) {
31 return false;
32 }
33 auto it_oldest = m_fragments.begin();
34 return it_oldest->first < reference_time - coherence_window_ns;
35 }
36
37 Timestamp get_reference_time() const {
38 std::lock_guard<std::mutex> lock(m_mutex);
39 return m_event_reference_time;
40 }
41
42 bool try_build_event(long long coherence_window_ns, int min_subsystems, std::vector<DataFragment>& built_fragments) {
43 std::lock_guard<std::mutex> lock(m_mutex);
44 if (m_fragments.empty()) return false;
45
46 // Use the stored reference time from the first fragment in current collection
47 Timestamp window_ref_time = m_event_reference_time;
48
49 auto it_begin = m_fragments.lower_bound(window_ref_time - coherence_window_ns);
50 auto it_end = m_fragments.upper_bound(window_ref_time + coherence_window_ns);
51
52 if (it_begin == it_end) return false;
53
54 std::set<uint64_t> subsystems_found;
55 std::vector<Timestamp> timestamps_in_window;
56
57 for (auto it = it_begin; it != it_end; ++it) {
58 timestamps_in_window.push_back(it->first);
59 for (const auto& frag : it->second) {
60 subsystems_found.insert(frag.header.subsystem_id);
61 }
62 }
63
64 // Require at least min_subsystems distinct subsystems in the window before
65 // assembling, so we don't emit partial events. Configurable.
66 if (subsystems_found.size() < static_cast<size_t>(min_subsystems)) {
67 return false;
68 }
69
70 // Collect fragments and remove them from buffer
71 for (Timestamp ts : timestamps_in_window) {
72 for (auto& frag : m_fragments[ts]) {
73 built_fragments.push_back(std::move(frag));
74 }
75 m_fragments.erase(ts);
76 }
77
78 // Reset reference time for next event
79 if (!m_fragments.empty()) {
80 m_event_reference_time = m_fragments.begin()->first;
81 }
82
83 return true;
84 }
85
86private:
87 std::map<Timestamp, std::vector<DataFragment>> m_fragments;
88 Timestamp m_event_reference_time = 0;
89 mutable std::mutex m_mutex;
90};
91
92} // namespace eventbuilder
93
94#endif // FRAGMENTBUFFER_H