mod append;
pub use append::{
Append, AppendBatch, AppendBatchSummary, AppendRecord, AppendSummary, Carry, HeldPosition,
RecordPosition, Release, ReleaseKey, ResolvedAppend, Schedule,
};
use super::OperationCodecError;
use ozzy_proto::{
ConsumerGroupId, ConsumerMemberId, GroupId, Offset, OperationId, OwnerEpoch, PartitionId,
PartitionIncarnation, ProducerEpoch, ProducerId, ProducerSequence, SubscriptionId,
};
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,
ResolvedAppend = 10,
DedupWatermark = 11,
GroupPlan = 12,
GroupDelete = 13,
RetireProducer = 14,
Schedule = 15,
Release = 16,
Carry = 17,
}
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),
10 => Ok(Self::ResolvedAppend),
11 => Ok(Self::DedupWatermark),
12 => Ok(Self::GroupPlan),
13 => Ok(Self::GroupDelete),
14 => Ok(Self::RetireProducer),
15 => Ok(Self::Schedule),
16 => Ok(Self::Release),
17 => Ok(Self::Carry),
other => Err(OperationCodecError::UnsupportedOperationKind(other)),
}
}
}
impl OperationKind {
pub const fn has_operation_id(self) -> bool {
!matches!(
self,
Self::CreatePartition
| Self::Append
| Self::Progress
| Self::ResolvedAppend
| Self::DedupWatermark
| Self::RetireProducer
| Self::Schedule
| Self::Release
| Self::Carry
)
}
}
#[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 dedup_window_millis: Option<NonZeroU64>,
pub delay_max_millis: Option<NonZeroU64>,
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, Copy, PartialEq, Eq)]
pub enum ProgressOwner {
Subscription(SubscriptionId),
ConsumerGroup(ConsumerGroupId),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ProgressAssignment {
pub epoch: u64,
pub member: ConsumerMemberId,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Progress {
pub owner: ProgressOwner,
pub partition: PartitionIncarnation,
pub assignment: Option<ProgressAssignment>,
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 plan_revision: u64,
pub resume_cursor: Offset,
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, Copy, PartialEq, Eq)]
pub struct DedupWatermark {
pub partition: PartitionIncarnation,
pub owner_epoch: OwnerEpoch,
pub logical_time: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RetireProducer {
pub partition: PartitionIncarnation,
pub producer_id: ProducerId,
pub producer_epoch: ProducerEpoch,
pub next_sequence: ProducerSequence,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum OperationBody<'a> {
CreatePartition(CreatePartition<'a>),
OpenProducer(OpenProducer),
Append(Append<'a>),
ResolvedAppend(ResolvedAppend<'a>),
Progress(Progress),
Assign(Assign),
Trim(Trim),
PartitionPolicy(PartitionPolicy),
Barrier(Barrier),
ProducerResultFloor(ProducerResultFloor),
DedupWatermark(DedupWatermark),
GroupPlan(super::GroupPlan<'a>),
GroupDelete(super::GroupDelete),
RetireProducer(RetireProducer),
Schedule(Schedule<'a>),
Release(Release<'a>),
Carry(Carry<'a>),
}
impl OperationBody<'_> {
pub const fn operation_id(&self) -> Option<OperationId> {
match self {
Self::CreatePartition(_)
| Self::Append(_)
| Self::Progress(_)
| Self::ResolvedAppend(_)
| Self::DedupWatermark(_)
| Self::RetireProducer(_)
| Self::Schedule(_)
| Self::Release(_)
| Self::Carry(_) => None,
Self::OpenProducer(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),
Self::GroupPlan(value) => Some(value.operation_id),
Self::GroupDelete(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::ResolvedAppend(_) => OperationKind::ResolvedAppend,
Self::Progress(_) => OperationKind::Progress,
Self::Assign(_) => OperationKind::Assign,
Self::Trim(_) => OperationKind::Trim,
Self::PartitionPolicy(_) => OperationKind::PartitionPolicy,
Self::Barrier(_) => OperationKind::Barrier,
Self::ProducerResultFloor(_) => OperationKind::ProducerResultFloor,
Self::DedupWatermark(_) => OperationKind::DedupWatermark,
Self::GroupPlan(_) => OperationKind::GroupPlan,
Self::GroupDelete(_) => OperationKind::GroupDelete,
Self::RetireProducer(_) => OperationKind::RetireProducer,
Self::Schedule(_) => OperationKind::Schedule,
Self::Release(_) => OperationKind::Release,
Self::Carry(_) => OperationKind::Carry,
}
}
}
#[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,
pub max_group_members: usize,
pub max_group_partitions: 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,
max_group_members: 256,
max_group_partitions: 1024,
}
}
}