1use serde::Deserialize;
2use serde::Serialize;
3use serde_json::Map;
4use serde_json::Value;
5use ursula_proto::ColdChunkRefV1;
6use ursula_proto::ExternalPayloadRefV1;
7use ursula_proto::ProducerRequestV1;
8use ursula_shard::BucketStreamId;
9
10pub const COLD_INDEX_PAGE_SPAN_BYTES: u64 = 64 * 1024 * 1024;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
13pub enum StreamStatus {
14 Open,
15 Closed,
16 SoftDeleted,
17}
18
19#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
20pub struct StreamMetadata {
21 pub stream_id: BucketStreamId,
22 pub content_type: String,
23 pub status: StreamStatus,
24 pub tail_offset: u64,
25 pub last_stream_seq: Option<String>,
26 pub stream_ttl_seconds: Option<u64>,
27 pub stream_expires_at_ms: Option<u64>,
28 pub created_at_ms: u64,
29 pub last_ttl_touch_at_ms: u64,
30 pub forked_from: Option<BucketStreamId>,
31 pub fork_offset: Option<u64>,
32 pub fork_ref_count: u64,
33}
34
35pub const MAX_STREAM_ATTRS_BYTES: usize = 16 * 1024;
39
40#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
41pub struct StreamAttrs {
42 #[serde(default, skip_serializing_if = "Option::is_none")]
43 pub title: Option<String>,
44 #[serde(default, skip_serializing_if = "Map::is_empty")]
45 pub metadata: Map<String, Value>,
46}
47
48impl StreamAttrs {
49 pub fn is_empty(&self) -> bool {
50 self.title.is_none() && self.metadata.is_empty()
51 }
52}
53
54pub type ProducerRequest = ProducerRequestV1;
55
56#[derive(Debug)]
57pub struct AppendStreamInput<'a> {
58 pub stream_id: BucketStreamId,
59 pub content_type: Option<&'a str>,
60 pub payload: &'a [u8],
61 pub close_after: bool,
62 pub stream_seq: Option<String>,
63 pub producer: Option<ProducerRequest>,
64 pub now_ms: u64,
65}
66
67#[derive(Debug)]
68pub(crate) struct AppendExternalInput<'a> {
69 pub(crate) stream_id: BucketStreamId,
70 pub(crate) content_type: Option<&'a str>,
71 pub(crate) payload: ExternalPayloadRef,
72 pub(crate) close_after: bool,
73 pub(crate) stream_seq: Option<String>,
74 pub(crate) producer: Option<ProducerRequest>,
75 pub(crate) now_ms: u64,
76}
77
78#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
79pub struct ProducerSnapshot {
80 pub producer_id: String,
81 pub producer_epoch: u64,
82 pub producer_seq: u64,
83 pub last_start_offset: u64,
84 pub last_next_offset: u64,
85 pub last_closed: bool,
86 pub last_items: Vec<ProducerAppendRecord>,
87}
88
89#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
90pub struct ProducerAppendRecord {
91 pub start_offset: u64,
92 pub next_offset: u64,
93 pub closed: bool,
94}
95
96#[derive(Debug, Clone, PartialEq, Eq)]
97pub(crate) struct ProducerState {
98 pub(crate) producer_epoch: u64,
99 pub(crate) producer_seq: u64,
100 pub(crate) last_start_offset: u64,
101 pub(crate) last_next_offset: u64,
102 pub(crate) last_closed: bool,
103 pub(crate) last_items: Vec<ProducerAppendRecord>,
104}
105
106#[derive(Debug, Clone, PartialEq, Eq)]
107pub struct StreamBatchAppend {
108 pub items: Vec<StreamBatchAppendItem>,
109 pub deduplicated: bool,
110}
111
112#[derive(Debug, Clone, PartialEq, Eq)]
113pub struct StreamBatchAppendItem {
114 pub offset: u64,
115 pub next_offset: u64,
116 pub closed: bool,
117 pub deduplicated: bool,
118}
119
120#[derive(Debug, Clone, PartialEq, Eq)]
121pub struct StreamRead {
122 pub offset: u64,
123 pub next_offset: u64,
124 pub content_type: String,
125 pub payload: Vec<u8>,
126 pub up_to_date: bool,
127 pub closed: bool,
128}
129
130pub type ColdChunkRef = ColdChunkRefV1;
131
132#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
133pub struct ObjectPayloadRef {
134 pub start_offset: u64,
135 pub end_offset: u64,
136 pub s3_path: String,
137 pub object_size: u64,
138}
139
140impl From<&ColdChunkRef> for ObjectPayloadRef {
141 fn from(chunk: &ColdChunkRef) -> Self {
142 Self {
143 start_offset: chunk.start_offset,
144 end_offset: chunk.end_offset,
145 s3_path: chunk.s3_path.clone(),
146 object_size: chunk.object_size,
147 }
148 }
149}
150
151pub type ExternalPayloadRef = ExternalPayloadRefV1;
152
153#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
157pub struct ColdGcEntry {
158 pub seq: u64,
159 pub target: ColdGcTarget,
160}
161
162#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
163pub enum ColdGcTarget {
164 Stream(BucketStreamId),
168 Paths(Vec<String>),
171}
172
173#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
174pub struct HotPayloadSegment {
175 pub start_offset: u64,
176 pub end_offset: u64,
177 pub payload_start: usize,
178 pub payload_end: usize,
179}
180
181#[derive(Debug, Clone, PartialEq, Eq)]
182pub struct ColdFlushCandidate {
183 pub stream_id: BucketStreamId,
184 pub start_offset: u64,
185 pub end_offset: u64,
186 pub payload: Vec<u8>,
187}
188
189#[derive(Debug, Clone, PartialEq, Eq)]
190pub struct StreamReadColdSegment {
191 pub chunk: ColdChunkRef,
192 pub read_start_offset: u64,
193 pub len: usize,
194}
195
196#[derive(Debug, Clone, PartialEq, Eq)]
197pub struct StreamReadObjectSegment {
198 pub object: ObjectPayloadRef,
199 pub read_start_offset: u64,
200 pub len: usize,
201}
202
203#[derive(Debug, Clone, PartialEq, Eq)]
204pub struct StreamReadColdIndexSegment {
205 pub generation: u64,
206 pub page_id: u64,
207 pub read_start_offset: u64,
208 pub len: usize,
209}
210
211#[derive(Debug, Clone, PartialEq, Eq)]
212pub enum StreamReadSegment {
213 ColdIndex(StreamReadColdIndexSegment),
214 Object(StreamReadObjectSegment),
215 Hot(Vec<u8>),
216}
217
218#[derive(Debug, Clone, PartialEq, Eq)]
219pub struct StreamReadPlan {
220 pub offset: u64,
221 pub next_offset: u64,
222 pub content_type: String,
223 pub segments: Vec<StreamReadSegment>,
224 pub up_to_date: bool,
225 pub closed: bool,
226}
227
228#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
229pub struct StreamMessageRecord {
230 pub start_offset: u64,
231 pub end_offset: u64,
232}
233
234#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
235pub struct StreamVisibleSnapshot {
236 pub offset: u64,
237 pub content_type: String,
238 pub payload: Vec<u8>,
239}
240
241#[derive(Debug, Clone, PartialEq, Eq)]
242pub struct StreamBootstrapPlan {
243 pub snapshot: Option<StreamVisibleSnapshot>,
244 pub updates: Vec<StreamMessageRecord>,
245 pub next_offset: u64,
246 pub content_type: String,
247 pub up_to_date: bool,
248 pub closed: bool,
249}