rocketmq_client_rust/consumer/store/
offset_store.rs1use std::collections::HashMap;
16use std::collections::HashSet;
17#[cfg(test)]
18use std::sync::atomic::AtomicUsize;
19#[cfg(test)]
20use std::sync::atomic::Ordering;
21#[cfg(test)]
22use std::sync::Arc;
23#[cfg(test)]
24use std::sync::Mutex;
25
26use rocketmq_common::common::message::message_queue::MessageQueue;
27
28use crate::consumer::store::local_file_offset_store::LocalFileOffsetStore;
29use crate::consumer::store::read_offset_type::ReadOffsetType;
30use crate::consumer::store::remote_broker_offset_store::RemoteBrokerOffsetStore;
31
32pub enum OffsetStore {
40 Remote(RemoteBrokerOffsetStore),
42 Local(LocalFileOffsetStore),
44 #[cfg(test)]
45 Test(TestOffsetStore),
46}
47
48#[cfg(test)]
49#[derive(Clone, Default)]
50pub struct TestOffsetStore {
51 offsets: Arc<Mutex<HashMap<MessageQueue, i64>>>,
52 persisted_offsets: Arc<Mutex<HashMap<MessageQueue, i64>>>,
53 persist_all_count: Arc<AtomicUsize>,
54}
55
56impl OffsetStore {
57 pub fn new_with_remote(remote_broker_offset_store: RemoteBrokerOffsetStore) -> Self {
59 Self::Remote(remote_broker_offset_store)
60 }
61
62 pub fn new_with_local(local_file_offset_store: LocalFileOffsetStore) -> Self {
64 Self::Local(local_file_offset_store)
65 }
66
67 #[cfg(test)]
68 pub(crate) fn new_test() -> Self {
69 Self::Test(TestOffsetStore::default())
70 }
71
72 #[cfg(test)]
73 pub(crate) fn test_persist_all_count(&self) -> usize {
74 match self {
75 Self::Test(store) => store.persist_all_count.load(Ordering::Acquire),
76 Self::Remote(_) | Self::Local(_) => 0,
77 }
78 }
79
80 #[cfg(test)]
81 pub(crate) fn test_persisted_offset(&self, mq: &MessageQueue) -> Option<i64> {
82 match self {
83 Self::Test(store) => store.persisted_offset(mq),
84 Self::Remote(_) | Self::Local(_) => None,
85 }
86 }
87
88 pub async fn load(&self) -> rocketmq_error::RocketMQResult<()> {
95 match self {
96 Self::Remote(store) => store.load().await,
97 Self::Local(store) => store.load().await,
98 #[cfg(test)]
99 Self::Test(_) => Ok(()),
100 }
101 }
102
103 pub async fn update_offset(&self, mq: &MessageQueue, offset: i64, increase_only: bool) {
108 match self {
109 Self::Remote(store) => store.update_offset(mq, offset, increase_only).await,
110 Self::Local(store) => store.update_offset(mq, offset, increase_only).await,
111 #[cfg(test)]
112 Self::Test(store) => store.update_offset(mq, offset, increase_only),
113 }
114 }
115
116 pub async fn update_and_freeze_offset(&self, mq: &MessageQueue, offset: i64) {
119 match self {
120 Self::Remote(store) => store.update_and_freeze_offset(mq, offset).await,
121 Self::Local(store) => store.update_and_freeze_offset(mq, offset).await,
122 #[cfg(test)]
123 Self::Test(store) => store.update_offset(mq, offset, false),
124 }
125 }
126
127 pub async fn read_offset(&self, mq: &MessageQueue, type_: ReadOffsetType) -> i64 {
132 match self {
133 Self::Remote(store) => store.read_offset(mq, type_).await,
134 Self::Local(store) => store.read_offset(mq, type_).await,
135 #[cfg(test)]
136 Self::Test(store) => store.read_offset(mq),
137 }
138 }
139
140 pub async fn persist_all(&mut self, mqs: &HashSet<MessageQueue>) {
143 match self {
144 Self::Remote(store) => store.persist_all(mqs).await,
145 Self::Local(store) => store.persist_all(mqs).await,
146 #[cfg(test)]
147 Self::Test(store) => store.persist_all(mqs),
148 }
149 }
150
151 pub async fn persist(&mut self, mq: &MessageQueue) {
154 match self {
155 Self::Remote(store) => store.persist(mq).await,
156 Self::Local(store) => store.persist(mq).await,
157 #[cfg(test)]
158 Self::Test(store) => store.persist(mq),
159 }
160 }
161
162 pub async fn remove_offset(&self, mq: &MessageQueue) {
164 match self {
165 Self::Remote(store) => store.remove_offset(mq).await,
166 Self::Local(store) => store.remove_offset(mq).await,
167 #[cfg(test)]
168 Self::Test(store) => store.remove_offset(mq),
169 }
170 }
171
172 pub async fn clone_offset_table(&self, topic: &str) -> HashMap<MessageQueue, i64> {
174 match self {
175 Self::Remote(store) => store.clone_offset_table(topic).await,
176 Self::Local(store) => store.clone_offset_table(topic).await,
177 #[cfg(test)]
178 Self::Test(store) => store.clone_offset_table(topic),
179 }
180 }
181
182 pub async fn update_consume_offset_to_broker(
190 &mut self,
191 mq: &MessageQueue,
192 offset: i64,
193 is_oneway: bool,
194 ) -> rocketmq_error::RocketMQResult<()> {
195 match self {
196 Self::Remote(store) => store.update_consume_offset_to_broker(mq, offset, is_oneway).await,
197 Self::Local(store) => store.update_consume_offset_to_broker(mq, offset, is_oneway).await,
198 #[cfg(test)]
199 Self::Test(store) => {
200 store.update_offset(mq, offset, false);
201 Ok(())
202 }
203 }
204 }
205}
206
207#[cfg(test)]
208impl TestOffsetStore {
209 fn update_offset(&self, mq: &MessageQueue, offset: i64, increase_only: bool) {
210 let mut offsets = self.offsets.lock().expect("test offset store lock");
211 if increase_only {
212 offsets
213 .entry(mq.clone())
214 .and_modify(|current| {
215 if offset > *current {
216 *current = offset;
217 }
218 })
219 .or_insert(offset);
220 } else {
221 offsets.insert(mq.clone(), offset);
222 }
223 }
224
225 fn read_offset(&self, mq: &MessageQueue) -> i64 {
226 self.offsets
227 .lock()
228 .expect("test offset store lock")
229 .get(mq)
230 .copied()
231 .unwrap_or(-1)
232 }
233
234 fn persist_all(&self, mqs: &HashSet<MessageQueue>) {
235 let offsets = self.offsets.lock().expect("test offset store lock");
236 let mut persisted_offsets = self.persisted_offsets.lock().expect("test persisted offset store lock");
237 for mq in mqs {
238 if let Some(offset) = offsets.get(mq) {
239 persisted_offsets.insert(mq.clone(), *offset);
240 }
241 }
242 self.persist_all_count.fetch_add(1, Ordering::AcqRel);
243 }
244
245 fn persist(&self, mq: &MessageQueue) {
246 self.persist_all(&HashSet::from([mq.clone()]));
247 }
248
249 fn remove_offset(&self, mq: &MessageQueue) {
250 self.offsets.lock().expect("test offset store lock").remove(mq);
251 }
252
253 fn persisted_offset(&self, mq: &MessageQueue) -> Option<i64> {
254 self.persisted_offsets
255 .lock()
256 .expect("test persisted offset store lock")
257 .get(mq)
258 .copied()
259 }
260
261 fn clone_offset_table(&self, topic: &str) -> HashMap<MessageQueue, i64> {
262 self.offsets
263 .lock()
264 .expect("test offset store lock")
265 .iter()
266 .filter(|(mq, _)| mq.topic() == topic)
267 .map(|(mq, offset)| (mq.clone(), *offset))
268 .collect()
269 }
270}
271
272pub(crate) trait OffsetStoreTrait {
278 async fn load(&self) -> rocketmq_error::RocketMQResult<()>;
285
286 async fn update_offset(&self, mq: &MessageQueue, offset: i64, increase_only: bool);
291
292 async fn update_and_freeze_offset(&self, mq: &MessageQueue, offset: i64);
295
296 async fn read_offset(&self, mq: &MessageQueue, type_: ReadOffsetType) -> i64;
301
302 async fn persist_all(&mut self, mqs: &HashSet<MessageQueue>);
304
305 async fn persist(&mut self, mq: &MessageQueue);
307
308 async fn remove_offset(&self, mq: &MessageQueue);
310
311 async fn clone_offset_table(&self, topic: &str) -> HashMap<MessageQueue, i64>;
313
314 async fn update_consume_offset_to_broker(
322 &mut self,
323 mq: &MessageQueue,
324 offset: i64,
325 is_oneway: bool,
326 ) -> rocketmq_error::RocketMQResult<()>;
327}