blob: 86382927c59a96fe2fb453193b0f3a63667971f3 [file]
use super::message_batch::{RetainedMessageBatch, RETAINED_BATCH_OVERHEAD};
use crate::streaming::{models::messages::RetainedMessage, sizeable::Sizeable};
use bytes::BytesMut;
use std::sync::Arc;
#[derive(Debug)]
pub struct BatchAccumulator {
base_offset: u64,
current_size: u64,
current_offset: u64,
current_timestamp: u64,
capacity: u64,
messages: Vec<Arc<RetainedMessage>>,
}
impl BatchAccumulator {
pub fn new(base_offset: u64, capacity: usize) -> Self {
Self {
base_offset,
current_size: 0,
current_offset: 0,
current_timestamp: 0,
capacity: capacity as u64,
messages: Vec::with_capacity(capacity),
}
}
pub fn append(&mut self, batch_size: u64, items: &[Arc<RetainedMessage>]) {
assert!(!items.is_empty());
self.current_size += batch_size;
self.current_offset = items.last().unwrap().offset;
self.current_timestamp = items.last().unwrap().timestamp;
self.messages.extend(items.iter().cloned());
}
pub fn get_messages_by_offset(
&self,
start_offset: u64,
end_offset: u64,
) -> Vec<Arc<RetainedMessage>> {
self.messages
.iter()
.filter(|msg| msg.offset >= start_offset && msg.offset <= end_offset)
.cloned()
.collect()
}
pub fn is_empty(&self) -> bool {
self.messages.is_empty()
}
pub fn unsaved_messages_count(&self) -> usize {
self.messages.len()
}
pub fn batch_max_offset(&self) -> u64 {
self.current_offset
}
pub fn batch_max_timestamp(&self) -> u64 {
self.current_timestamp
}
pub fn batch_base_offset(&self) -> u64 {
self.base_offset
}
pub fn get_size_bytes(&self) -> u64 {
self.current_size + RETAINED_BATCH_OVERHEAD as u64
}
pub fn materialize_batch_and_maybe_update_state(&mut self) -> (bool, RetainedMessageBatch) {
let batch_base_offset = self.base_offset;
let batch_last_offset_delta = (self.current_offset - self.base_offset) as u32;
let batch_max_timestamp = self.messages.last().unwrap().timestamp;
let split_point = std::cmp::min(self.capacity as usize, self.messages.len());
let (batch, remainder) = self.messages.as_slice().split_at(split_point);
let mut bytes = BytesMut::with_capacity(self.current_size as usize);
for message in batch {
message.extend(&mut bytes);
}
let mut remaining_messages = Vec::with_capacity(remainder.len());
let has_remainder = !remainder.is_empty();
if has_remainder {
self.base_offset = remainder.first().unwrap().offset;
self.current_size = remainder
.iter()
.map(|msg| msg.get_size_bytes() as u64)
.sum();
self.current_offset = remainder.last().unwrap().offset;
self.current_timestamp = remainder.last().unwrap().timestamp;
for message in remainder {
remaining_messages.push(message.clone());
}
self.messages = remaining_messages;
}
let batch_payload = bytes.freeze();
let batch_payload_len = batch_payload.len() as u32;
let batch = RetainedMessageBatch::new(
batch_base_offset,
batch_last_offset_delta,
batch_max_timestamp,
batch_payload_len,
batch_payload,
);
(has_remainder, batch)
}
}