1use std::sync::Arc;
16
17use async_stream::try_stream;
18use common_error::ext::BoxedError;
19use futures::stream::BoxStream;
20use snafu::ResultExt;
21use store_api::logstore::LogStore;
22use store_api::logstore::entry::Entry;
23use store_api::logstore::provider::Provider;
24use store_api::storage::RegionId;
25use tokio_stream::StreamExt;
26
27use crate::error::{self, Result};
28use crate::wal::EntryId;
29
30pub type EntryStream<'a> = BoxStream<'a, Result<Entry>>;
32
33pub(crate) trait RawEntryReader: Send + Sync {
35 fn read(&self, provider: &Provider, start_id: EntryId) -> Result<EntryStream<'static>>;
36}
37
38pub struct LogStoreRawEntryReader<S> {
40 store: Arc<S>,
41}
42
43impl<S> LogStoreRawEntryReader<S> {
44 pub fn new(store: Arc<S>) -> Self {
45 Self { store }
46 }
47}
48
49impl<S: LogStore> RawEntryReader for LogStoreRawEntryReader<S> {
50 fn read(&self, provider: &Provider, start_id: EntryId) -> Result<EntryStream<'static>> {
51 let store = self.store.clone();
52 let provider = provider.clone();
53 let stream = try_stream!({
54 let mut stream = store
55 .read(&provider, start_id)
56 .await
57 .map_err(BoxedError::new)
58 .with_context(|_| error::ReadWalSnafu {
59 provider: provider.clone(),
60 })?;
61
62 while let Some(entries) = stream.next().await {
63 let entries =
64 entries
65 .map_err(BoxedError::new)
66 .with_context(|_| error::ReadWalSnafu {
67 provider: provider.clone(),
68 })?;
69
70 for entry in entries {
71 yield entry
72 }
73 }
74 });
75
76 Ok(Box::pin(stream))
77 }
78}
79
80pub struct RegionRawEntryReader<R> {
82 reader: R,
83 region_id: RegionId,
84}
85
86impl<R> RegionRawEntryReader<R>
87where
88 R: RawEntryReader,
89{
90 pub fn new(reader: R, region_id: RegionId) -> Self {
91 Self { reader, region_id }
92 }
93}
94
95impl<R> RawEntryReader for RegionRawEntryReader<R>
96where
97 R: RawEntryReader,
98{
99 fn read(&self, ctx: &Provider, start_id: EntryId) -> Result<EntryStream<'static>> {
100 let mut stream = self.reader.read(ctx, start_id)?;
101 let region_id = self.region_id;
102
103 let stream = try_stream!({
104 while let Some(entry) = stream.next().await {
105 let entry = entry?;
106 if entry.region_id() == region_id {
107 yield entry
108 }
109 }
110 });
111
112 Ok(Box::pin(stream))
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use std::sync::Arc;
119
120 use futures::{TryStreamExt, stream};
121 use store_api::logstore::entry::{Entry, NaiveEntry};
122 use store_api::logstore::{AppendBatchResponse, EntryId, LogStore, SendableEntryStream};
123 use store_api::storage::RegionId;
124
125 use super::*;
126 use crate::error;
127
128 #[derive(Debug)]
129 struct MockLogStore {
130 entries: Vec<Entry>,
131 }
132
133 #[async_trait::async_trait]
134 impl LogStore for MockLogStore {
135 type Error = error::Error;
136
137 async fn stop(&self) -> Result<(), Self::Error> {
138 unreachable!()
139 }
140
141 async fn append_batch(
142 &self,
143 _entries: Vec<Entry>,
144 ) -> Result<AppendBatchResponse, Self::Error> {
145 unreachable!()
146 }
147
148 async fn read(
149 &self,
150 _provider: &Provider,
151 _id: EntryId,
152 ) -> Result<SendableEntryStream<'static, Entry, Self::Error>, Self::Error> {
153 Ok(Box::pin(stream::iter(vec![Ok(self.entries.clone())])))
154 }
155
156 async fn create_namespace(&self, _ns: &Provider) -> Result<(), Self::Error> {
157 unreachable!()
158 }
159
160 async fn delete_namespace(&self, _ns: &Provider) -> Result<(), Self::Error> {
161 unreachable!()
162 }
163
164 async fn list_namespaces(&self) -> Result<Vec<Provider>, Self::Error> {
165 unreachable!()
166 }
167
168 async fn obsolete(
169 &self,
170 _provider: &Provider,
171 _region_id: RegionId,
172 _entry_id: EntryId,
173 ) -> Result<(), Self::Error> {
174 unreachable!()
175 }
176
177 async fn obsolete_all(
178 &self,
179 _provider: &Provider,
180 _region_id: RegionId,
181 ) -> Result<(), Self::Error> {
182 unreachable!()
183 }
184
185 fn entry(
186 &self,
187 _data: Vec<u8>,
188 _entry_id: EntryId,
189 _region_id: RegionId,
190 _provider: &Provider,
191 ) -> Result<Entry, Self::Error> {
192 unreachable!()
193 }
194
195 fn latest_entry_id(&self, _provider: &Provider) -> Result<EntryId, Self::Error> {
196 unreachable!()
197 }
198 }
199
200 #[tokio::test]
201 async fn test_raw_entry_reader() {
202 let provider = Provider::raft_engine_provider(RegionId::new(1024, 1).as_u64());
203 let expected_entries = vec![Entry::Naive(NaiveEntry {
204 provider: provider.clone(),
205 region_id: RegionId::new(1024, 1),
206 entry_id: 1,
207 data: vec![1],
208 })];
209 let store = MockLogStore {
210 entries: expected_entries.clone(),
211 };
212
213 let reader = LogStoreRawEntryReader::new(Arc::new(store));
214 let entries = reader
215 .read(&provider, 0)
216 .unwrap()
217 .try_collect::<Vec<_>>()
218 .await
219 .unwrap();
220 assert_eq!(expected_entries, entries);
221 }
222
223 #[tokio::test]
224 async fn test_raw_entry_reader_filter() {
225 let provider = Provider::raft_engine_provider(RegionId::new(1024, 1).as_u64());
226 let all_entries = vec![
227 Entry::Naive(NaiveEntry {
228 provider: provider.clone(),
229 region_id: RegionId::new(1024, 1),
230 entry_id: 1,
231 data: vec![1],
232 }),
233 Entry::Naive(NaiveEntry {
234 provider: provider.clone(),
235 region_id: RegionId::new(1024, 2),
236 entry_id: 2,
237 data: vec![2],
238 }),
239 Entry::Naive(NaiveEntry {
240 provider: provider.clone(),
241 region_id: RegionId::new(1024, 3),
242 entry_id: 3,
243 data: vec![3],
244 }),
245 ];
246 let store = MockLogStore {
247 entries: all_entries.clone(),
248 };
249
250 let expected_region_id = RegionId::new(1024, 3);
251 let reader = RegionRawEntryReader::new(
252 LogStoreRawEntryReader::new(Arc::new(store)),
253 expected_region_id,
254 );
255 let entries = reader
256 .read(&provider, 0)
257 .unwrap()
258 .try_collect::<Vec<_>>()
259 .await
260 .unwrap();
261 assert_eq!(
262 all_entries
263 .into_iter()
264 .filter(|entry| entry.region_id() == expected_region_id)
265 .collect::<Vec<_>>(),
266 entries
267 );
268 }
269}