9template <
typename BufferType>
12 using BufferType::BufferType;
26 if (this->is_processing()) {
27 for (
auto& m_pending_op : m_pending_ops) {
28 bool expected =
false;
29 if (m_pending_op.active.compare_exchange_strong(expected,
true, std::memory_order_acquire, std::memory_order_relaxed)) {
30 m_pending_op.buffer =
buffer;
31 m_pending_op.is_addition =
true;
32 m_pending_count.fetch_add(1, std::memory_order_relaxed);
39 add_child_buffer_direct(
buffer);
53 if (!is_buffer_acceptable(
buffer, rejection_reason)) {
67 if (this->is_processing()) {
68 for (
auto& m_pending_op : m_pending_ops) {
69 bool expected =
false;
70 if (m_pending_op.active.compare_exchange_strong(expected,
true, std::memory_order_acquire, std::memory_order_relaxed)) {
71 m_pending_op.buffer =
buffer;
72 m_pending_op.is_addition =
false;
73 m_pending_count.fetch_add(1, std::memory_order_relaxed);
81 remove_child_buffer_direct(
buffer);
96 return m_child_buffers;
108 for (
auto& child : m_child_buffers) {
171 auto default_processor =
buffer->get_default_processor();
172 if (!default_processor) {
176 ProcessingToken child_token = default_processor->get_processing_token();
178 switch (m_token_enforcement_strategy) {
179 case TokenEnforcementStrategy::STRICT:
180 if (child_token != m_preferred_processing_token) {
181 if (rejection_reason) {
182 *rejection_reason =
"Child buffer's default processor token does not match preferred processing token (STRICT mode)";
188 case TokenEnforcementStrategy::FILTERED:
190 if (rejection_reason) {
191 *rejection_reason =
"Child buffer's default processor token is not compatible with preferred processing token (FILTERED mode)";
197 case TokenEnforcementStrategy::OVERRIDE_SKIP:
199 if (rejection_reason) {
200 *rejection_reason =
"Child buffer token is incompatible but will be conditionally processed (OVERRIDE_SKIP mode)";
205 case TokenEnforcementStrategy::OVERRIDE_REJECT:
207 if (rejection_reason) {
208 *rejection_reason =
"Child buffer token is incompatible and will be removed later (OVERRIDE_REJECT mode)";
213 case TokenEnforcementStrategy::IGNORE:
222 return m_pending_count.load(std::memory_order_relaxed) > 0;
228 std::string rejection_reason;
229 if (!is_buffer_acceptable(
buffer, &rejection_reason)) {
230 error<std::runtime_error>(Journal::Component::Buffers, Journal::Context::BufferManagement, std::source_location::current(),
"Cannot add child buffer: {}", rejection_reason);
233 m_child_buffers.push_back(
buffer);
235 if (!
buffer->get_processing_chain() && this->get_processing_chain()) {
236 buffer->set_processing_chain(this->get_processing_chain());
242 auto it = std::find(m_child_buffers.begin(), m_child_buffers.end(),
buffer);
243 if (it != m_child_buffers.end()) {
244 m_child_buffers.erase(it);
253 for (
auto& m_pending_op : m_pending_ops) {
254 if (m_pending_op.active.load(std::memory_order_acquire)) {
255 auto& op = m_pending_op;
257 if (op.is_addition) {
258 add_child_buffer_direct(op.buffer);
260 remove_child_buffer_direct(op.buffer);
265 op.active.store(
false, std::memory_order_release);
266 m_pending_count.fetch_sub(1, std::memory_order_relaxed);
312 std::atomic<uint32_t> m_pending_count { 0 };
314 static constexpr size_t MAX_PENDING = 64;
323 std::atomic<bool> active {
false };
325 bool is_addition {
true };
326 } m_pending_ops[MAX_PENDING];
std::shared_ptr< NetworkGeometryBuffer > buffer
virtual void remove_child_buffer(const std::shared_ptr< BufferType > &buffer)
Removes a tributary buffer from this root buffer.
virtual void add_child_buffer(const std::shared_ptr< BufferType > &buffer)
Adds a tributary buffer to this root buffer.
virtual void set_processing_rate_hint(uint32_t tick_rate)
Sets processing rate hint for the buffer.
bool m_cross_modal_sharing
Whether this buffer allows cross-modal data sharing.
const std::vector< std::shared_ptr< BufferType > > & get_child_buffers() const
Gets all tributary buffers in the aggregation hierarchy.
virtual void enable_cross_modal_sharing(bool enabled)
Enables cross-modal data sharing.
void add_child_buffer_direct(const std::shared_ptr< BufferType > &buffer)
bool is_buffer_acceptable(const std::shared_ptr< BufferType > &buffer, std::string *rejection_reason=nullptr) const
Validates if a buffer is acceptable based on current token enforcement strategy.
void process_pending_buffer_operations()
Process pending operations - call this at start of processing cycles.
virtual uint32_t get_processing_rate_hint() const
Gets the processing rate hint.
bool has_pending_operations() const
virtual bool is_token_active() const =0
Checks if the buffer is active for its assigned token.
void clear() override
Resets all data values in this buffer and its tributaries.
uint32_t m_processing_rate_hint
Processing rate hint for this buffer.
virtual bool try_add_child_buffer(const std::shared_ptr< BufferType > &buffer, std::string *rejection_reason=nullptr)
Attempts to add a child buffer without throwing exceptions.
ProcessingToken m_preferred_processing_token
Preferred processing token for this root buffer.
void remove_child_buffer_direct(const std::shared_ptr< BufferType > &buffer)
std::vector< std::shared_ptr< BufferType > > m_child_buffers
Vector of tributary buffers that contribute to this root buffer.
size_t get_num_children() const
Gets the number of tributary buffers in the aggregation hierarchy.
virtual void set_token_active(bool active)=0
Activates/deactivates processing for the current token.
virtual bool is_cross_modal_sharing_enabled() const
Checks if cross-modal sharing is enabled.
ProcessingToken
Bitfield enum defining processing characteristics and backend requirements for buffer operations.
bool are_tokens_compatible(ProcessingToken preferred, ProcessingToken current)
Determines if two processing tokens are compatible for joint execution.
TokenEnforcementStrategy
Defines how strictly processing token requirements are enforced in buffer processing chains.
std::shared_ptr< BufferType > buffer
Structure for storing pending buffer add/remove operations.