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;
25use std::time::Duration;
26
27use rocketmq_model::common::message::message_queue::MessageQueue;
28
29use crate::consumer::store::local_file_offset_store::LocalFileOffsetStore;
30use crate::consumer::store::read_offset_type::ReadOffsetType;
31use crate::consumer::store::remote_broker_offset_store::RemoteBrokerOffsetStore;
32
33pub enum OffsetStore {
41 Remote(RemoteBrokerOffsetStore),
43 Local(LocalFileOffsetStore),
45 #[cfg(test)]
46 Test(TestOffsetStore),
47}
48
49#[cfg(test)]
50#[derive(Clone, Default)]
51pub struct TestOffsetStore {
52 offsets: Arc<Mutex<HashMap<MessageQueue, i64>>>,
53 persisted_offsets: Arc<Mutex<HashMap<MessageQueue, i64>>>,
54 persist_all_count: Arc<AtomicUsize>,
55}
56
57impl OffsetStore {
58 pub fn new_with_remote(remote_broker_offset_store: RemoteBrokerOffsetStore) -> Self {
60 Self::Remote(remote_broker_offset_store)
61 }
62
63 pub fn new_with_local(local_file_offset_store: LocalFileOffsetStore) -> Self {
65 Self::Local(local_file_offset_store)
66 }
67
68 #[cfg(test)]
69 pub(crate) fn new_test() -> Self {
70 Self::Test(TestOffsetStore::default())
71 }
72
73 #[cfg(test)]
74 pub(crate) fn test_persist_all_count(&self) -> usize {
75 match self {
76 Self::Test(store) => store.persist_all_count.load(Ordering::Acquire),
77 Self::Remote(_) | Self::Local(_) => 0,
78 }
79 }
80
81 #[cfg(test)]
82 pub(crate) fn test_persisted_offset(&self, mq: &MessageQueue) -> Option<i64> {
83 match self {
84 Self::Test(store) => store.persisted_offset(mq),
85 Self::Remote(_) | Self::Local(_) => None,
86 }
87 }
88
89 pub async fn load(&self) -> crate::ClientResult<()> {
96 match self {
97 Self::Remote(store) => store.load().await,
98 Self::Local(store) => store.load().await,
99 #[cfg(test)]
100 Self::Test(_) => Ok(()),
101 }
102 }
103
104 pub async fn update_offset(&self, mq: &MessageQueue, offset: i64, increase_only: bool) {
109 match self {
110 Self::Remote(store) => store.update_offset(mq, offset, increase_only).await,
111 Self::Local(store) => store.update_offset(mq, offset, increase_only).await,
112 #[cfg(test)]
113 Self::Test(store) => store.update_offset(mq, offset, increase_only),
114 }
115 }
116
117 pub async fn update_and_freeze_offset(&self, mq: &MessageQueue, offset: i64) {
120 match self {
121 Self::Remote(store) => store.update_and_freeze_offset(mq, offset).await,
122 Self::Local(store) => store.update_and_freeze_offset(mq, offset).await,
123 #[cfg(test)]
124 Self::Test(store) => store.update_offset(mq, offset, false),
125 }
126 }
127
128 pub async fn read_offset(&self, mq: &MessageQueue, type_: ReadOffsetType) -> i64 {
133 match self {
134 Self::Remote(store) => store.read_offset(mq, type_).await,
135 Self::Local(store) => store.read_offset(mq, type_).await,
136 #[cfg(test)]
137 Self::Test(store) => store.read_offset(mq),
138 }
139 }
140
141 pub async fn persist_all(&self, mqs: &HashSet<MessageQueue>) {
144 match self {
145 Self::Remote(store) => store.persist_all(mqs).await,
146 Self::Local(store) => store.persist_all(mqs).await,
147 #[cfg(test)]
148 Self::Test(store) => store.persist_all(mqs),
149 }
150 }
151
152 pub async fn persist(&self, mq: &MessageQueue) {
155 match self {
156 Self::Remote(store) => store.persist(mq).await,
157 Self::Local(store) => store.persist(mq).await,
158 #[cfg(test)]
159 Self::Test(store) => store.persist(mq),
160 }
161 }
162
163 pub async fn remove_offset(&self, mq: &MessageQueue) {
165 match self {
166 Self::Remote(store) => store.remove_offset(mq).await,
167 Self::Local(store) => store.remove_offset(mq).await,
168 #[cfg(test)]
169 Self::Test(store) => store.remove_offset(mq),
170 }
171 }
172
173 pub async fn clone_offset_table(&self, topic: &str) -> HashMap<MessageQueue, i64> {
175 match self {
176 Self::Remote(store) => store.clone_offset_table(topic).await,
177 Self::Local(store) => store.clone_offset_table(topic).await,
178 #[cfg(test)]
179 Self::Test(store) => store.clone_offset_table(topic),
180 }
181 }
182
183 pub async fn update_consume_offset_to_broker(
191 &self,
192 mq: &MessageQueue,
193 offset: i64,
194 is_oneway: bool,
195 ) -> crate::ClientResult<()> {
196 match self {
197 Self::Remote(store) => store.update_consume_offset_to_broker(mq, offset, is_oneway).await,
198 Self::Local(store) => store.update_consume_offset_to_broker(mq, offset, is_oneway).await,
199 #[cfg(test)]
200 Self::Test(store) => {
201 store.update_offset(mq, offset, false);
202 Ok(())
203 }
204 }
205 }
206
207 pub async fn shutdown(&self, timeout: Duration) -> bool {
209 match self {
210 Self::Remote(_) => true,
211 Self::Local(store) => store.shutdown_with_timeout(timeout).await,
212 #[cfg(test)]
213 Self::Test(_) => true,
214 }
215 }
216}
217
218#[cfg(test)]
219impl TestOffsetStore {
220 fn update_offset(&self, mq: &MessageQueue, offset: i64, increase_only: bool) {
221 let mut offsets = self.offsets.lock().expect("test offset store lock");
222 if increase_only {
223 offsets
224 .entry(mq.clone())
225 .and_modify(|current| {
226 if offset > *current {
227 *current = offset;
228 }
229 })
230 .or_insert(offset);
231 } else {
232 offsets.insert(mq.clone(), offset);
233 }
234 }
235
236 fn read_offset(&self, mq: &MessageQueue) -> i64 {
237 self.offsets
238 .lock()
239 .expect("test offset store lock")
240 .get(mq)
241 .copied()
242 .unwrap_or(-1)
243 }
244
245 fn persist_all(&self, mqs: &HashSet<MessageQueue>) {
246 let offsets = self.offsets.lock().expect("test offset store lock");
247 let mut persisted_offsets = self.persisted_offsets.lock().expect("test persisted offset store lock");
248 for mq in mqs {
249 if let Some(offset) = offsets.get(mq) {
250 persisted_offsets.insert(mq.clone(), *offset);
251 }
252 }
253 self.persist_all_count.fetch_add(1, Ordering::AcqRel);
254 }
255
256 fn persist(&self, mq: &MessageQueue) {
257 self.persist_all(&HashSet::from([mq.clone()]));
258 }
259
260 fn remove_offset(&self, mq: &MessageQueue) {
261 self.offsets.lock().expect("test offset store lock").remove(mq);
262 }
263
264 fn persisted_offset(&self, mq: &MessageQueue) -> Option<i64> {
265 self.persisted_offsets
266 .lock()
267 .expect("test persisted offset store lock")
268 .get(mq)
269 .copied()
270 }
271
272 fn clone_offset_table(&self, topic: &str) -> HashMap<MessageQueue, i64> {
273 self.offsets
274 .lock()
275 .expect("test offset store lock")
276 .iter()
277 .filter(|(mq, _)| mq.topic() == topic)
278 .map(|(mq, offset)| (mq.clone(), *offset))
279 .collect()
280 }
281}
282
283pub(crate) trait OffsetStoreTrait {
289 async fn load(&self) -> crate::ClientResult<()>;
296
297 async fn update_offset(&self, mq: &MessageQueue, offset: i64, increase_only: bool);
302
303 async fn update_and_freeze_offset(&self, mq: &MessageQueue, offset: i64);
306
307 async fn read_offset(&self, mq: &MessageQueue, type_: ReadOffsetType) -> i64;
312
313 async fn persist_all(&self, mqs: &HashSet<MessageQueue>);
315
316 async fn persist(&self, mq: &MessageQueue);
318
319 async fn remove_offset(&self, mq: &MessageQueue);
321
322 async fn clone_offset_table(&self, topic: &str) -> HashMap<MessageQueue, i64>;
324
325 async fn update_consume_offset_to_broker(
333 &self,
334 mq: &MessageQueue,
335 offset: i64,
336 is_oneway: bool,
337 ) -> crate::ClientResult<()>;
338}