@@ -18,7 +18,7 @@ use common_meta::instruction::{
1818 FlushErrorStrategy , FlushRegionReply , FlushRegions , FlushStrategy , InstructionReply ,
1919} ;
2020use common_telemetry:: { debug, warn} ;
21- use store_api:: region_request:: { RegionFlushRequest , RegionRequest } ;
21+ use store_api:: region_request:: { RegionFlushReason , RegionFlushRequest , RegionRequest } ;
2222use store_api:: storage:: RegionId ;
2323
2424use crate :: error:: { self , RegionNotFoundSnafu , RegionNotReadySnafu , Result , UnexpectedSnafu } ;
@@ -39,14 +39,17 @@ impl InstructionHandler for FlushRegionsHandler {
3939 let strategy = flush_regions. strategy ;
4040 let region_ids = flush_regions. region_ids ;
4141 let error_strategy = flush_regions. error_strategy ;
42+ let reason = flush_regions. reason ;
4243
4344 let reply = if matches ! ( strategy, FlushStrategy :: Async ) {
4445 // Asynchronous hint mode: fire-and-forget, no reply expected
45- ctx. handle_flush_hint ( region_ids) . await ;
46+ ctx. handle_flush_hint ( region_ids, reason ) . await ;
4647 None
4748 } else {
4849 // Synchronous mode: return reply with results
49- let reply = ctx. handle_flush_sync ( region_ids, error_strategy) . await ;
50+ let reply = ctx
51+ . handle_flush_sync ( region_ids, error_strategy, reason)
52+ . await ;
5053 Some ( InstructionReply :: FlushRegions ( reply) )
5154 } ;
5255
@@ -62,9 +65,14 @@ impl InstructionHandler for FlushRegionsHandler {
6265
6366impl HandlerContext {
6467 /// Performs the actual region flush operation.
65- async fn perform_region_flush ( & self , region_id : RegionId ) -> Result < ( ) > {
68+ async fn perform_region_flush (
69+ & self ,
70+ region_id : RegionId ,
71+ reason : Option < RegionFlushReason > ,
72+ ) -> Result < ( ) > {
6673 let request = RegionRequest :: Flush ( RegionFlushRequest {
67- row_group_size : None ,
74+ reason,
75+ ..Default :: default ( )
6876 } ) ;
6977 self . region_server
7078 . handle_request ( region_id, request)
@@ -73,10 +81,14 @@ impl HandlerContext {
7381 }
7482
7583 /// Handles asynchronous flush hints (fire-and-forget).
76- async fn handle_flush_hint ( & self , region_ids : Vec < RegionId > ) {
84+ async fn handle_flush_hint (
85+ & self ,
86+ region_ids : Vec < RegionId > ,
87+ reason : Option < RegionFlushReason > ,
88+ ) {
7789 let start_time = Instant :: now ( ) ;
7890 for region_id in & region_ids {
79- let result = self . perform_region_flush ( * region_id) . await ;
91+ let result = self . perform_region_flush ( * region_id, reason ) . await ;
8092 match result {
8193 Ok ( _) => { }
8294 Err ( error:: Error :: RegionNotFound { .. } ) => {
@@ -102,11 +114,12 @@ impl HandlerContext {
102114 & self ,
103115 region_ids : Vec < RegionId > ,
104116 error_strategy : FlushErrorStrategy ,
117+ reason : Option < RegionFlushReason > ,
105118 ) -> FlushRegionReply {
106119 let mut results = Vec :: with_capacity ( region_ids. len ( ) ) ;
107120
108121 for region_id in region_ids {
109- let result = self . flush_single_region_sync ( region_id) . await ;
122+ let result = self . flush_single_region_sync ( region_id, reason ) . await ;
110123
111124 match & result {
112125 Ok ( _) => results. push ( ( region_id, Ok ( ( ) ) ) ) ,
@@ -127,7 +140,11 @@ impl HandlerContext {
127140 }
128141
129142 /// Flushes a single region synchronously with proper error handling.
130- async fn flush_single_region_sync ( & self , region_id : RegionId ) -> Result < ( ) > {
143+ async fn flush_single_region_sync (
144+ & self ,
145+ region_id : RegionId ,
146+ reason : Option < RegionFlushReason > ,
147+ ) -> Result < ( ) > {
131148 // Check if region is leader and writable
132149 let Some ( writable) = self . region_server . is_region_leader ( region_id) else {
133150 return Err ( RegionNotFoundSnafu { region_id } . build ( ) ) ;
@@ -148,7 +165,8 @@ impl HandlerContext {
148165 . handle_request (
149166 region_id,
150167 RegionRequest :: Flush ( RegionFlushRequest {
151- row_group_size : None ,
168+ reason,
169+ ..Default :: default ( )
152170 } ) ,
153171 )
154172 . await ?;
@@ -184,19 +202,27 @@ mod tests {
184202 use super :: * ;
185203 use crate :: tests:: { MockRegionEngine , mock_region_server} ;
186204
205+ type FlushedRequests = Arc < RwLock < Vec < ( RegionId , Option < RegionFlushReason > ) > > > ;
206+
187207 #[ tokio:: test]
188208 async fn test_handle_flush_region_hint ( ) {
189- let flushed_region_ids : Arc < RwLock < Vec < RegionId > > > = Arc :: new ( RwLock :: new ( Vec :: new ( ) ) ) ;
209+ let flushed_requests : FlushedRequests = Arc :: new ( RwLock :: new ( Vec :: new ( ) ) ) ;
190210
191211 let mock_region_server = mock_region_server ( ) ;
192212 let region_ids = ( 0 ..16 ) . map ( |i| RegionId :: new ( 1024 , i) ) . collect :: < Vec < _ > > ( ) ;
193213 for region_id in & region_ids {
194- let flushed_region_ids_ref = flushed_region_ids . clone ( ) ;
214+ let flushed_requests_ref = flushed_requests . clone ( ) ;
195215 let ( mock_engine, _) =
196216 MockRegionEngine :: with_custom_apply_fn ( MITO_ENGINE_NAME , move |region_engine| {
197217 region_engine. handle_request_mock_fn =
198- Some ( Box :: new ( move |region_id, _request| {
199- flushed_region_ids_ref. write ( ) . unwrap ( ) . push ( region_id) ;
218+ Some ( Box :: new ( move |region_id, request| {
219+ let RegionRequest :: Flush ( request) = request else {
220+ panic ! ( "Expected flush request" ) ;
221+ } ;
222+ flushed_requests_ref
223+ . write ( )
224+ . unwrap ( )
225+ . push ( ( region_id, request. reason ) ) ;
200226 Ok ( 0 )
201227 } ) )
202228 } ) ;
@@ -206,44 +232,56 @@ mod tests {
206232 let handler_context = HandlerContext :: new_for_test ( mock_region_server, kv_backend) ;
207233
208234 // Async hint mode
209- let flush_instruction = FlushRegions :: async_batch ( region_ids. clone ( ) ) ;
235+ let flush_instruction = FlushRegions :: async_batch ( region_ids. clone ( ) )
236+ . with_reason ( RegionFlushReason :: RemoteWalPrune ) ;
210237 let reply = FlushRegionsHandler
211238 . handle ( & handler_context, flush_instruction)
212239 . await ;
213240 assert ! ( reply. is_none( ) ) ; // Hint mode returns no reply
214- assert_eq ! ( * flushed_region_ids. read( ) . unwrap( ) , region_ids) ;
241+ let expected = region_ids
242+ . iter ( )
243+ . map ( |region_id| ( * region_id, Some ( RegionFlushReason :: RemoteWalPrune ) ) )
244+ . collect :: < Vec < _ > > ( ) ;
245+ assert_eq ! ( * flushed_requests. read( ) . unwrap( ) , expected) ;
215246
216247 // Non-existent regions
217- flushed_region_ids . write ( ) . unwrap ( ) . clear ( ) ;
248+ flushed_requests . write ( ) . unwrap ( ) . clear ( ) ;
218249 let not_found_region_ids = ( 0 ..2 ) . map ( |i| RegionId :: new ( 2048 , i) ) . collect :: < Vec < _ > > ( ) ;
219250 let flush_instruction = FlushRegions :: async_batch ( not_found_region_ids) ;
220251 let reply = FlushRegionsHandler
221252 . handle ( & handler_context, flush_instruction)
222253 . await ;
223254 assert ! ( reply. is_none( ) ) ;
224- assert ! ( flushed_region_ids . read( ) . unwrap( ) . is_empty( ) ) ;
255+ assert ! ( flushed_requests . read( ) . unwrap( ) . is_empty( ) ) ;
225256 }
226257
227258 #[ tokio:: test]
228259 async fn test_handle_flush_region_sync_single ( ) {
229- let flushed_region_ids : Arc < RwLock < Vec < RegionId > > > = Arc :: new ( RwLock :: new ( Vec :: new ( ) ) ) ;
260+ let flushed_requests : FlushedRequests = Arc :: new ( RwLock :: new ( Vec :: new ( ) ) ) ;
230261
231262 let mock_region_server = mock_region_server ( ) ;
232263 let region_id = RegionId :: new ( 1024 , 1 ) ;
233264
234- let flushed_region_ids_ref = flushed_region_ids . clone ( ) ;
265+ let flushed_requests_ref = flushed_requests . clone ( ) ;
235266 let ( mock_engine, _) =
236267 MockRegionEngine :: with_custom_apply_fn ( MITO_ENGINE_NAME , move |region_engine| {
237- region_engine. handle_request_mock_fn = Some ( Box :: new ( move |region_id, _request| {
238- flushed_region_ids_ref. write ( ) . unwrap ( ) . push ( region_id) ;
268+ region_engine. handle_request_mock_fn = Some ( Box :: new ( move |region_id, request| {
269+ let RegionRequest :: Flush ( request) = request else {
270+ panic ! ( "Expected flush request" ) ;
271+ } ;
272+ flushed_requests_ref
273+ . write ( )
274+ . unwrap ( )
275+ . push ( ( region_id, request. reason ) ) ;
239276 Ok ( 0 )
240277 } ) )
241278 } ) ;
242279 mock_region_server. register_test_region ( region_id, mock_engine) ;
243280 let kv_backend = Arc :: new ( MemoryKvBackend :: new ( ) ) ;
244281 let handler_context = HandlerContext :: new_for_test ( mock_region_server, kv_backend) ;
245282
246- let flush_instruction = FlushRegions :: sync_single ( region_id) ;
283+ let flush_instruction =
284+ FlushRegions :: sync_single ( region_id) . with_reason ( RegionFlushReason :: Repartition ) ;
247285 let reply = FlushRegionsHandler
248286 . handle ( & handler_context, flush_instruction)
249287 . await ;
@@ -252,7 +290,10 @@ mod tests {
252290 assert_eq ! ( flush_reply. results. len( ) , 1 ) ;
253291 assert_eq ! ( flush_reply. results[ 0 ] . 0 , region_id) ;
254292 assert ! ( flush_reply. results[ 0 ] . 1 . is_ok( ) ) ;
255- assert_eq ! ( * flushed_region_ids. read( ) . unwrap( ) , vec![ region_id] ) ;
293+ assert_eq ! (
294+ * flushed_requests. read( ) . unwrap( ) ,
295+ vec![ ( region_id, Some ( RegionFlushReason :: Repartition ) ) ]
296+ ) ;
256297 }
257298
258299 #[ tokio:: test]
@@ -333,7 +374,7 @@ mod tests {
333374 let display = format ! ( "{}" , flush_regions) ;
334375 assert_eq ! (
335376 display,
336- "FlushRegions(region_ids=[4398046511105(1024, 1)], strategy=Sync, error_strategy=FailFast)"
377+ "FlushRegions(region_ids=[4398046511105(1024, 1)], strategy=Sync, error_strategy=FailFast, reason=None )"
337378 ) ;
338379 }
339380}
0 commit comments