krabka_remote_storage_topic/
swappable.rs1use {
23 krabka_ids::LeaderEpoch,
24 krabka_remote_storage::{
25 RemoteLogMetadataManager, RemoteLogSegmentMetadata, RemoteLogSegmentMetadataUpdate,
26 RemotePartitionDeleteMetadata, RemoteStorageError, TopicIdPartition,
27 },
28 std::sync::{Arc, PoisonError, RwLock},
29};
30
31pub struct SwappableRlmm {
33 inner: RwLock<Arc<dyn RemoteLogMetadataManager>>,
34}
35
36impl SwappableRlmm {
37 #[must_use]
40 pub fn new(initial: Arc<dyn RemoteLogMetadataManager>) -> Self {
41 Self {
42 inner: RwLock::new(initial),
43 }
44 }
45
46 pub fn swap(&self, new: Arc<dyn RemoteLogMetadataManager>) {
49 *self.inner.write().unwrap_or_else(PoisonError::into_inner) = new;
50 }
51
52 fn current(&self) -> Arc<dyn RemoteLogMetadataManager> {
55 self.inner
56 .read()
57 .unwrap_or_else(PoisonError::into_inner)
58 .clone()
59 }
60}
61
62impl RemoteLogMetadataManager for SwappableRlmm {
63 fn add_remote_log_segment_metadata(
64 &self,
65 metadata: RemoteLogSegmentMetadata,
66 ) -> Result<(), RemoteStorageError> {
67 self.current().add_remote_log_segment_metadata(metadata)
68 }
69
70 fn update_remote_log_segment_metadata(
71 &self,
72 update: RemoteLogSegmentMetadataUpdate,
73 ) -> Result<(), RemoteStorageError> {
74 self.current().update_remote_log_segment_metadata(update)
75 }
76
77 fn remote_log_segment_metadata(
78 &self,
79 topic_id_partition: &TopicIdPartition,
80 leader_epoch: LeaderEpoch,
81 offset: i64,
82 ) -> Result<Option<RemoteLogSegmentMetadata>, RemoteStorageError> {
83 self.current()
84 .remote_log_segment_metadata(topic_id_partition, leader_epoch, offset)
85 }
86
87 fn highest_offset_for_epoch(
88 &self,
89 topic_id_partition: &TopicIdPartition,
90 leader_epoch: LeaderEpoch,
91 ) -> Result<Option<i64>, RemoteStorageError> {
92 self.current()
93 .highest_offset_for_epoch(topic_id_partition, leader_epoch)
94 }
95
96 fn list_remote_log_segments(
97 &self,
98 topic_id_partition: &TopicIdPartition,
99 ) -> Result<Vec<RemoteLogSegmentMetadata>, RemoteStorageError> {
100 self.current().list_remote_log_segments(topic_id_partition)
101 }
102
103 fn list_remote_log_segments_by_epoch(
104 &self,
105 topic_id_partition: &TopicIdPartition,
106 leader_epoch: LeaderEpoch,
107 ) -> Result<Vec<RemoteLogSegmentMetadata>, RemoteStorageError> {
108 self.current()
109 .list_remote_log_segments_by_epoch(topic_id_partition, leader_epoch)
110 }
111
112 fn put_remote_partition_delete_metadata(
113 &self,
114 metadata: RemotePartitionDeleteMetadata,
115 ) -> Result<(), RemoteStorageError> {
116 self.current()
117 .put_remote_partition_delete_metadata(metadata)
118 }
119
120 fn caught_up(&self, topic_id_partition: &TopicIdPartition) -> Result<bool, RemoteStorageError> {
121 self.current().caught_up(topic_id_partition)
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use {
128 super::*,
129 crate::{
130 NotReadyRlmm,
131 manager::test_support::{started, tp},
132 },
133 assert2::assert,
134 krabka_remote_storage::InmemoryRemoteLogMetadataManager,
135 };
136
137 #[test]
138 fn delegates_to_initial_then_to_swapped() {
139 let first: Arc<dyn RemoteLogMetadataManager> =
140 Arc::new(InmemoryRemoteLogMetadataManager::new());
141 let swap = SwappableRlmm::new(Arc::clone(&first));
142
143 swap.add_remote_log_segment_metadata(started(10, 0, 99))
145 .unwrap();
146 assert!(first.list_remote_log_segments(&tp()).unwrap().len() == 1);
147
148 let second: Arc<dyn RemoteLogMetadataManager> =
151 Arc::new(InmemoryRemoteLogMetadataManager::new());
152 swap.swap(Arc::clone(&second));
153 assert!(swap.list_remote_log_segments(&tp()).unwrap().is_empty());
154 assert!(first.list_remote_log_segments(&tp()).unwrap().len() == 1);
157
158 swap.add_remote_log_segment_metadata(started(11, 100, 199))
160 .unwrap();
161 assert!(second.list_remote_log_segments(&tp()).unwrap().len() == 1);
162 assert!(first.list_remote_log_segments(&tp()).unwrap().len() == 1);
163 }
164
165 #[test]
166 fn caught_up_delegates_to_the_current_inner() {
167 let swap = SwappableRlmm::new(Arc::new(NotReadyRlmm::new()));
168 assert!(let Err(RemoteStorageError::NotReady { .. }) = swap.caught_up(&tp()));
169 swap.swap(Arc::new(InmemoryRemoteLogMetadataManager::new()));
170 assert!(let Ok(true) = swap.caught_up(&tp()));
171 }
172}