use super::{AppendRecordList, OperationCodecError};
use ozzy_proto::{
ConsumerGroupId, ConsumerMemberId, GroupId, MessageId, Offset, OperationId, OwnerEpoch,
PartitionId, PartitionIncarnation, ProducerEpoch, ProducerId, ProducerSequence, SubscriptionId,
};
use smallvec::SmallVec;
use std::num::NonZeroU64;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct Digest([u8; 32]);
impl Digest {
pub const ZERO: Self = Self([0; 32]);
pub const fn from_bytes(bytes: [u8; 32]) -> Self {
Self(bytes)
}
pub const fn as_bytes(&self) -> &[u8; 32] {
&self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u16)]
pub enum OperationKind {
CreatePartition = 1,
OpenProducer = 2,
Append = 3,
Progress = 4,
Assign = 5,
Trim = 6,
PartitionPolicy = 7,
Barrier = 8,
ProducerResultFloor = 9,
}
impl TryFrom<u16> for OperationKind {
type Error = OperationCodecError;
fn try_from(value: u16) -> Result<Self, Self::Error> {
match value {
1 => Ok(Self::CreatePartition),
2 => Ok(Self::OpenProducer),
3 => Ok(Self::Append),
4 => Ok(Self::Progress),
5 => Ok(Self::Assign),
6 => Ok(Self::Trim),
7 => Ok(Self::PartitionPolicy),
8 => Ok(Self::Barrier),
9 => Ok(Self::ProducerResultFloor),
other => Err(OperationCodecError::UnsupportedOperationKind(other)),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ChainPosition {
next_op_number: u64,
previous_digest: Digest,
}
impl ChainPosition {
pub const GENESIS: Self = Self {
next_op_number: 1,
previous_digest: Digest::ZERO,
};
pub const fn new(next_op_number: u64, previous_digest: Digest) -> Self {
Self {
next_op_number,
previous_digest,
}
}
pub const fn next_op_number(self) -> u64 {
self.next_op_number
}
pub const fn previous_digest(self) -> Digest {
self.previous_digest
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CanonicalOperation<'a> {
pub group_id: GroupId,
pub configuration_epoch: u64,
pub original_view: u64,
pub op_number: u64,
pub previous_digest: Digest,
pub kind: OperationKind,
pub body: &'a [u8],
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OperationHeader {
pub group_id: GroupId,
pub configuration_epoch: u64,
pub original_view: u64,
pub op_number: u64,
pub previous_digest: Digest,
pub kind: OperationKind,
}
impl CanonicalOperation<'_> {
pub const fn header(&self) -> OperationHeader {
OperationHeader {
group_id: self.group_id,
configuration_epoch: self.configuration_epoch,
original_view: self.original_view,
op_number: self.op_number,
previous_digest: self.previous_digest,
kind: self.kind,
}
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct RetentionPolicy {
pub max_age_millis: Option<NonZeroU64>,
pub max_bytes: Option<NonZeroU64>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CreatePartition<'a> {
pub partition: PartitionIncarnation,
pub stream: &'a str,
pub topic: &'a str,
pub partition_id: PartitionId,
pub owner_epoch: OwnerEpoch,
pub retention: RetentionPolicy,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OpenProducer {
pub partition: PartitionIncarnation,
pub producer_id: ProducerId,
pub expected_epoch: Option<ProducerEpoch>,
pub new_epoch: ProducerEpoch,
pub operation_id: OperationId,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AppendRecord<'a> {
pub encoding: ozzy_proto::data::Encoding,
pub message_id: MessageId,
pub parts: SmallVec<[&'a [u8]; 2]>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AppendBatch<'a> {
pub partition: PartitionIncarnation,
pub owner_epoch: OwnerEpoch,
pub producer_id: ProducerId,
pub producer_epoch: ProducerEpoch,
pub first_sequence: ProducerSequence,
pub first_offset: Offset,
pub append_timestamp_millis: u64,
pub records: AppendRecordList<'a>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Append<'a> {
pub batches: Vec<AppendBatch<'a>>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AppendBatchSummary {
pub partition: PartitionIncarnation,
pub owner_epoch: OwnerEpoch,
pub producer_id: ProducerId,
pub producer_epoch: ProducerEpoch,
pub first_sequence: ProducerSequence,
pub first_offset: Offset,
pub record_count: usize,
pub nonzero_message_ids: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RecordPosition {
pub descriptor: u32,
pub payload: u32,
pub parts: u32,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AppendSummary {
pub(super) batches: SmallVec<[AppendBatchSummary; 4]>,
}
impl AppendSummary {
pub fn single(batch: AppendBatchSummary) -> Self {
Self {
batches: smallvec::smallvec![batch],
}
}
pub fn batches(&self) -> &[AppendBatchSummary] {
&self.batches
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProgressOwner {
Subscription(SubscriptionId),
ConsumerGroup(ConsumerGroupId),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Progress {
pub owner: ProgressOwner,
pub partition: PartitionIncarnation,
pub assignment_epoch: Option<u64>,
pub expected_progress: Option<Offset>,
pub new_progress: Offset,
pub operation_id: OperationId,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Assign {
pub consumer_group_id: ConsumerGroupId,
pub partition: PartitionIncarnation,
pub expected_assignment_epoch: u64,
pub new_assignment_epoch: u64,
pub new_member: Option<ConsumerMemberId>,
pub operation_id: OperationId,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Trim {
pub partition: PartitionIncarnation,
pub expected_floor: Offset,
pub new_floor: Offset,
pub operation_id: OperationId,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PartitionPolicy {
pub partition: PartitionIncarnation,
pub expected_revision: u64,
pub new_revision: u64,
pub retention: RetentionPolicy,
pub operation_id: OperationId,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Barrier {
pub operation_id: OperationId,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ProducerResultFloor {
pub partition: PartitionIncarnation,
pub producer_id: ProducerId,
pub producer_epoch: ProducerEpoch,
pub expected_floor: ProducerSequence,
pub new_floor: ProducerSequence,
pub operation_id: OperationId,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum OperationBody<'a> {
CreatePartition(CreatePartition<'a>),
OpenProducer(OpenProducer),
Append(Append<'a>),
Progress(Progress),
Assign(Assign),
Trim(Trim),
PartitionPolicy(PartitionPolicy),
Barrier(Barrier),
ProducerResultFloor(ProducerResultFloor),
}
impl OperationBody<'_> {
pub const fn operation_id(&self) -> Option<OperationId> {
match self {
Self::CreatePartition(_) | Self::Append(_) => None,
Self::OpenProducer(value) => Some(value.operation_id),
Self::Progress(value) => Some(value.operation_id),
Self::Assign(value) => Some(value.operation_id),
Self::Trim(value) => Some(value.operation_id),
Self::PartitionPolicy(value) => Some(value.operation_id),
Self::Barrier(value) => Some(value.operation_id),
Self::ProducerResultFloor(value) => Some(value.operation_id),
}
}
pub const fn kind(&self) -> OperationKind {
match self {
Self::CreatePartition(_) => OperationKind::CreatePartition,
Self::OpenProducer(_) => OperationKind::OpenProducer,
Self::Append(_) => OperationKind::Append,
Self::Progress(_) => OperationKind::Progress,
Self::Assign(_) => OperationKind::Assign,
Self::Trim(_) => OperationKind::Trim,
Self::PartitionPolicy(_) => OperationKind::PartitionPolicy,
Self::Barrier(_) => OperationKind::Barrier,
Self::ProducerResultFloor(_) => OperationKind::ProducerResultFloor,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OperationLimits {
pub max_body_bytes: usize,
pub max_name_bytes: usize,
pub max_append_batches: usize,
pub max_records: usize,
pub max_parts: usize,
pub max_payload_bytes: usize,
}
impl Default for OperationLimits {
fn default() -> Self {
Self {
max_body_bytes: 64 * 1024 * 1024,
max_name_bytes: 255,
max_append_batches: 1_024,
max_records: 1_024,
max_parts: 65_536,
max_payload_bytes: 64 * 1024 * 1024,
}
}
}