1use reifydb_catalog::catalog::Catalog;
5use reifydb_codec::{
6 key::encoded::EncodedKey,
7 row::{
8 bytes::{EncodedBytes, RowBuilder},
9 ringbuffer::EncodedRingBufferRow,
10 shape::{RowFamily, RowShape},
11 },
12};
13use reifydb_core::{
14 common::CommitVersion,
15 interface::{
16 catalog::{
17 object::ObjectId,
18 ringbuffer::{RingBuffer, RingBufferMetadata},
19 },
20 change::{Change, ChangeOrigin, Diff},
21 },
22 key::{
23 partitioned_row::{PartitionedRowKey, RowLocator},
24 row::RowKey,
25 },
26 partition::{PartitionError, partition_col_indices},
27 row::row_shape_from_columns,
28 value::column::columns::Columns,
29};
30use reifydb_transaction::{
31 interceptor::ringbuffer_row::RingBufferRowInterceptor,
32 transaction::{Transaction, admin::AdminTransaction, command::CommandTransaction},
33};
34use reifydb_value::{
35 util::cowvec::CowVec,
36 value::{Value, datetime::DateTime, partition::Partition, row_number::RowNumber},
37};
38use smallvec::smallvec;
39
40use crate::{Result, partition::partition_values};
41
42fn ringbuffer_key(ringbuffer: &RingBuffer, partition: Option<Partition>, row_number: RowNumber) -> EncodedKey {
43 match partition {
44 None => RowKey::encoded(ringbuffer.id, row_number),
45 Some(partition) => PartitionedRowKey::encoded(
46 ObjectId::ringbuffer(ringbuffer.id),
47 partition,
48 RowLocator::Row(row_number),
49 ),
50 }
51}
52
53fn build_ringbuffer_insert_change(
54 rb: &RingBuffer,
55 shape: &RowShape,
56 row_number: RowNumber,
57 encoded: &EncodedBytes,
58) -> Change {
59 let ids = [row_number];
60 let rows = [encoded.clone()];
61 Change {
62 origin: ChangeOrigin::Object(ObjectId::ringbuffer(rb.id)),
63 version: CommitVersion(0),
64 diffs: smallvec![Diff::insert(Columns::from_encoded_bytes(shape, &ids, &rows))],
65 changed_at: DateTime::default(),
66 }
67}
68
69fn build_ringbuffer_update_change(
70 rb: &RingBuffer,
71 row_number: RowNumber,
72 pre: &EncodedBytes,
73 post: &EncodedBytes,
74) -> Change {
75 let shape = row_shape_from_columns(RowFamily::RingBuffer, &rb.columns);
76 let ids = [row_number];
77 let pres = [pre.clone()];
78 let posts = [post.clone()];
79 Change {
80 origin: ChangeOrigin::Object(ObjectId::ringbuffer(rb.id)),
81 version: CommitVersion(0),
82 diffs: smallvec![Diff::update(
83 Columns::from_encoded_bytes(&shape, &ids, &pres),
84 Columns::from_encoded_bytes(&shape, &ids, &posts),
85 )],
86 changed_at: DateTime::default(),
87 }
88}
89
90fn build_ringbuffer_remove_change(rb: &RingBuffer, row_number: RowNumber, encoded: &EncodedBytes) -> Change {
91 let shape = row_shape_from_columns(RowFamily::RingBuffer, &rb.columns);
92 let ids = [row_number];
93 let rows = [encoded.clone()];
94 Change {
95 origin: ChangeOrigin::Object(ObjectId::ringbuffer(rb.id)),
96 version: CommitVersion(0),
97 diffs: smallvec![Diff::remove(Columns::from_encoded_bytes(&shape, &ids, &rows))],
98 changed_at: DateTime::default(),
99 }
100}
101
102pub fn apply_ringbuffer_partition_metadata_after_delete(
103 catalog: &Catalog,
104 txn: &mut Transaction<'_>,
105 ringbuffer: &RingBuffer,
106 partition_key: &[Value],
107 mut partition: RingBufferMetadata,
108 deleted: u64,
109 min_remaining_row: Option<u64>,
110) -> Result<()> {
111 if deleted == 0 {
112 return Ok(());
113 }
114 let remaining_count = partition.count.saturating_sub(deleted);
115 if remaining_count == 0 {
116 catalog.remove_partition_metadata(txn, ringbuffer, partition_key)
117 } else {
118 partition.count = remaining_count;
119 partition.head = min_remaining_row.unwrap();
120 catalog.save_partition_metadata(txn, ringbuffer, partition_key, &partition)
121 }
122}
123
124pub trait RingBufferOperations {
125 fn insert_ringbuffer(&mut self, ringbuffer: RingBuffer, bytes: EncodedBytes) -> Result<RowNumber>;
126
127 fn insert_ringbuffer_at(
128 &mut self,
129 ringbuffer: &RingBuffer,
130 shape: &RowShape,
131 partition: Option<Partition>,
132 row_number: RowNumber,
133 bytes: EncodedBytes,
134 ) -> Result<EncodedBytes>;
135
136 fn update_ringbuffer(
137 &mut self,
138 ringbuffer: RingBuffer,
139 partition: Option<Partition>,
140 id: RowNumber,
141 bytes: EncodedBytes,
142 ) -> Result<EncodedBytes>;
143
144 fn remove_from_ringbuffer(
145 &mut self,
146 ringbuffer: &RingBuffer,
147 partition: Option<Partition>,
148 id: RowNumber,
149 ) -> Result<EncodedBytes>;
150}
151
152impl RingBufferOperations for CommandTransaction {
153 fn insert_ringbuffer(&mut self, _ringbuffer: RingBuffer, _row: EncodedBytes) -> Result<RowNumber> {
154 unimplemented!(
155 "Ring buffer insert must be called with explicit row_number through insert_ringbuffer_at"
156 )
157 }
158
159 fn insert_ringbuffer_at(
160 &mut self,
161 ringbuffer: &RingBuffer,
162 shape: &RowShape,
163 partition: Option<Partition>,
164 row_number: RowNumber,
165 bytes: EncodedBytes,
166 ) -> Result<EncodedBytes> {
167 let key = ringbuffer_key(ringbuffer, partition, row_number);
168
169 let pre = self.get(&key)?.map(|v| v.bytes);
170
171 if let Some(ref existing) = pre {
172 let ids = [row_number];
173 let existing_rows = [existing.clone()];
174 RingBufferRowInterceptor::pre_delete(self, ringbuffer, &ids)?;
175 RingBufferRowInterceptor::post_delete(self, ringbuffer, &ids, &existing_rows)?;
176 }
177
178 let mut rows_buf = [EncodedRingBufferRow::from(bytes.clone()).thaw()];
179 RingBufferRowInterceptor::pre_insert(self, ringbuffer, &mut rows_buf)?;
180 let [bytes] = rows_buf;
181 let bytes = bytes.freeze_bytes();
182
183 self.set(&key, bytes.clone())?;
184
185 let ids = [row_number];
186 let rows = [bytes.clone()];
187 RingBufferRowInterceptor::post_insert(self, ringbuffer, &ids, &rows)?;
188
189 if let Some(pre_row) = pre.as_ref() {
190 self.track_flow_change(build_ringbuffer_update_change(ringbuffer, row_number, pre_row, &bytes));
191 } else {
192 self.track_flow_change(build_ringbuffer_insert_change(ringbuffer, shape, row_number, &bytes));
193 }
194
195 Ok(bytes)
196 }
197
198 fn update_ringbuffer(
199 &mut self,
200 ringbuffer: RingBuffer,
201 partition: Option<Partition>,
202 id: RowNumber,
203 bytes: EncodedBytes,
204 ) -> Result<EncodedBytes> {
205 let key = ringbuffer_key(&ringbuffer, partition, id);
206
207 let pre = match self.get(&key)? {
208 Some(v) => v.bytes,
209 None => return Ok(bytes),
210 };
211
212 let mut rows_buf = [EncodedRingBufferRow::from(bytes.clone()).thaw()];
213 let ids = [id];
214 RingBufferRowInterceptor::pre_update(self, &ringbuffer, &ids, &mut rows_buf)?;
215 let [bytes] = rows_buf;
216 let bytes = bytes.freeze_bytes();
217
218 if let Some(expected) = partition {
219 let shape = row_shape_from_columns(RowFamily::RingBuffer, &ringbuffer.columns);
220 let indices = partition_col_indices(&ringbuffer.columns, &ringbuffer.partition_by);
221 if Partition::of(&partition_values(&shape, &bytes, &indices)) != expected {
222 return Err(PartitionError::ImmutablePartitionColumn {
223 object: ObjectId::ringbuffer(ringbuffer.id),
224 }
225 .into());
226 }
227 }
228
229 if self.get_committed(&key)?.is_some() {
230 self.mark_preexisting(&key)?;
231 }
232 self.set(&key, bytes.clone())?;
233
234 let posts = [bytes.clone()];
235 let pres = [pre.clone()];
236 RingBufferRowInterceptor::post_update(self, &ringbuffer, &ids, &posts, &pres)?;
237
238 self.track_flow_change(build_ringbuffer_update_change(&ringbuffer, id, &pre, &bytes));
239
240 Ok(bytes)
241 }
242
243 fn remove_from_ringbuffer(
244 &mut self,
245 ringbuffer: &RingBuffer,
246 partition: Option<Partition>,
247 id: RowNumber,
248 ) -> Result<EncodedBytes> {
249 let key = ringbuffer_key(ringbuffer, partition, id);
250
251 let displayed = match self.get(&key)? {
252 Some(v) => v.bytes,
253 None => return Ok(EncodedBytes(CowVec::new(vec![]))),
254 };
255 let committed = self.get_committed(&key)?.map(|v| v.bytes);
256
257 let ids = [id];
258 RingBufferRowInterceptor::pre_delete(self, ringbuffer, &ids)?;
259
260 let pre_for_cdc = committed.clone().unwrap_or_else(|| displayed.clone());
261
262 if committed.is_some() {
263 self.mark_preexisting(&key)?;
264 }
265 self.remove_with_pre(&key, pre_for_cdc.clone())?;
266
267 let pre_rows = [pre_for_cdc.clone()];
268 RingBufferRowInterceptor::post_delete(self, ringbuffer, &ids, &pre_rows)?;
269
270 self.track_flow_change(build_ringbuffer_remove_change(ringbuffer, id, &pre_for_cdc));
271
272 Ok(displayed)
273 }
274}
275
276impl RingBufferOperations for AdminTransaction {
277 fn insert_ringbuffer(&mut self, _ringbuffer: RingBuffer, _row: EncodedBytes) -> Result<RowNumber> {
278 unimplemented!(
279 "Ring buffer insert must be called with explicit row_number through insert_ringbuffer_at"
280 )
281 }
282
283 fn insert_ringbuffer_at(
284 &mut self,
285 ringbuffer: &RingBuffer,
286 shape: &RowShape,
287 partition: Option<Partition>,
288 row_number: RowNumber,
289 bytes: EncodedBytes,
290 ) -> Result<EncodedBytes> {
291 let key = ringbuffer_key(ringbuffer, partition, row_number);
292
293 let pre = self.get(&key)?.map(|v| v.bytes);
294
295 if let Some(ref existing) = pre {
296 let ids = [row_number];
297 let existing_rows = [existing.clone()];
298 RingBufferRowInterceptor::pre_delete(self, ringbuffer, &ids)?;
299 RingBufferRowInterceptor::post_delete(self, ringbuffer, &ids, &existing_rows)?;
300 }
301
302 let mut rows_buf = [EncodedRingBufferRow::from(bytes.clone()).thaw()];
303 RingBufferRowInterceptor::pre_insert(self, ringbuffer, &mut rows_buf)?;
304 let [bytes] = rows_buf;
305 let bytes = bytes.freeze_bytes();
306
307 self.set(&key, bytes.clone())?;
308
309 let ids = [row_number];
310 let rows = [bytes.clone()];
311 RingBufferRowInterceptor::post_insert(self, ringbuffer, &ids, &rows)?;
312
313 if let Some(pre_row) = pre.as_ref() {
314 self.track_flow_change(build_ringbuffer_update_change(ringbuffer, row_number, pre_row, &bytes));
315 } else {
316 self.track_flow_change(build_ringbuffer_insert_change(ringbuffer, shape, row_number, &bytes));
317 }
318
319 Ok(bytes)
320 }
321
322 fn update_ringbuffer(
323 &mut self,
324 ringbuffer: RingBuffer,
325 partition: Option<Partition>,
326 id: RowNumber,
327 bytes: EncodedBytes,
328 ) -> Result<EncodedBytes> {
329 let key = ringbuffer_key(&ringbuffer, partition, id);
330
331 let pre = match self.get(&key)? {
332 Some(v) => v.bytes,
333 None => return Ok(bytes),
334 };
335
336 let mut rows_buf = [EncodedRingBufferRow::from(bytes.clone()).thaw()];
337 let ids = [id];
338 RingBufferRowInterceptor::pre_update(self, &ringbuffer, &ids, &mut rows_buf)?;
339 let [bytes] = rows_buf;
340 let bytes = bytes.freeze_bytes();
341
342 if let Some(expected) = partition {
343 let shape = row_shape_from_columns(RowFamily::RingBuffer, &ringbuffer.columns);
344 let indices = partition_col_indices(&ringbuffer.columns, &ringbuffer.partition_by);
345 if Partition::of(&partition_values(&shape, &bytes, &indices)) != expected {
346 return Err(PartitionError::ImmutablePartitionColumn {
347 object: ObjectId::ringbuffer(ringbuffer.id),
348 }
349 .into());
350 }
351 }
352
353 if self.get_committed(&key)?.is_some() {
354 self.mark_preexisting(&key)?;
355 }
356 self.set(&key, bytes.clone())?;
357
358 let posts = [bytes.clone()];
359 let pres = [pre.clone()];
360 RingBufferRowInterceptor::post_update(self, &ringbuffer, &ids, &posts, &pres)?;
361
362 self.track_flow_change(build_ringbuffer_update_change(&ringbuffer, id, &pre, &bytes));
363
364 Ok(bytes)
365 }
366
367 fn remove_from_ringbuffer(
368 &mut self,
369 ringbuffer: &RingBuffer,
370 partition: Option<Partition>,
371 id: RowNumber,
372 ) -> Result<EncodedBytes> {
373 let key = ringbuffer_key(ringbuffer, partition, id);
374
375 let displayed = match self.get(&key)? {
376 Some(v) => v.bytes,
377 None => return Ok(EncodedBytes(CowVec::new(vec![]))),
378 };
379 let committed = self.get_committed(&key)?.map(|v| v.bytes);
380
381 let ids = [id];
382 RingBufferRowInterceptor::pre_delete(self, ringbuffer, &ids)?;
383
384 let pre_for_cdc = committed.clone().unwrap_or_else(|| displayed.clone());
385
386 if committed.is_some() {
387 self.mark_preexisting(&key)?;
388 }
389 self.remove_with_pre(&key, pre_for_cdc.clone())?;
390
391 let pre_rows = [pre_for_cdc.clone()];
392 RingBufferRowInterceptor::post_delete(self, ringbuffer, &ids, &pre_rows)?;
393
394 self.track_flow_change(build_ringbuffer_remove_change(ringbuffer, id, &pre_for_cdc));
395
396 Ok(displayed)
397 }
398}
399
400impl RingBufferOperations for Transaction<'_> {
401 fn insert_ringbuffer(&mut self, _ringbuffer: RingBuffer, _row: EncodedBytes) -> Result<RowNumber> {
402 unimplemented!(
403 "Ring buffer insert must be called with explicit row_number through insert_ringbuffer_at"
404 )
405 }
406
407 fn insert_ringbuffer_at(
408 &mut self,
409 ringbuffer: &RingBuffer,
410 shape: &RowShape,
411 partition: Option<Partition>,
412 row_number: RowNumber,
413 bytes: EncodedBytes,
414 ) -> Result<EncodedBytes> {
415 match self {
416 Transaction::Command(txn) => {
417 txn.insert_ringbuffer_at(ringbuffer, shape, partition, row_number, bytes)
418 }
419 Transaction::Admin(txn) => {
420 txn.insert_ringbuffer_at(ringbuffer, shape, partition, row_number, bytes)
421 }
422 Transaction::Test(t) => {
423 t.inner.insert_ringbuffer_at(ringbuffer, shape, partition, row_number, bytes)
424 }
425 Transaction::Query(_) => panic!("Write operations not supported on Query transaction"),
426 Transaction::Replica(_) => panic!("Write operations not supported on Replica transaction"),
427 }
428 }
429
430 fn update_ringbuffer(
431 &mut self,
432 ringbuffer: RingBuffer,
433 partition: Option<Partition>,
434 id: RowNumber,
435 bytes: EncodedBytes,
436 ) -> Result<EncodedBytes> {
437 match self {
438 Transaction::Command(txn) => txn.update_ringbuffer(ringbuffer, partition, id, bytes),
439 Transaction::Admin(txn) => txn.update_ringbuffer(ringbuffer, partition, id, bytes),
440 Transaction::Test(t) => t.inner.update_ringbuffer(ringbuffer, partition, id, bytes),
441 Transaction::Query(_) => panic!("Write operations not supported on Query transaction"),
442 Transaction::Replica(_) => panic!("Write operations not supported on Replica transaction"),
443 }
444 }
445
446 fn remove_from_ringbuffer(
447 &mut self,
448 ringbuffer: &RingBuffer,
449 partition: Option<Partition>,
450 id: RowNumber,
451 ) -> Result<EncodedBytes> {
452 match self {
453 Transaction::Command(txn) => txn.remove_from_ringbuffer(ringbuffer, partition, id),
454 Transaction::Admin(txn) => txn.remove_from_ringbuffer(ringbuffer, partition, id),
455 Transaction::Test(t) => t.inner.remove_from_ringbuffer(ringbuffer, partition, id),
456 Transaction::Query(_) => panic!("Write operations not supported on Query transaction"),
457 Transaction::Replica(_) => panic!("Write operations not supported on Replica transaction"),
458 }
459 }
460}