mito2/worker/
handle_compaction.rs1use api::v1::region::compact_request;
16use common_telemetry::{debug, error, info};
17use store_api::logstore::LogStore;
18use store_api::region_request::RegionCompactRequest;
19use store_api::storage::RegionId;
20
21use crate::compaction::{CompactionPickFinished, CompactionTransition};
22use crate::config::IndexBuildMode;
23use crate::error::{RegionNotFoundSnafu, StaleCompactionExecutionSnafu};
24use crate::metrics::COMPACTION_REQUEST_COUNT;
25use crate::region::MitoRegionRef;
26use crate::request::{
27 BuildIndexRequest, CompactionCancelled, CompactionFailed, CompactionFinished, OnFailure,
28 OptionOutputTx,
29};
30use crate::sst::index::IndexBuildType;
31use crate::worker::RegionWorkerLoop;
32
33impl<S> RegionWorkerLoop<S> {
34 pub(crate) async fn handle_compaction_pick_finished(
35 &mut self,
36 region_id: RegionId,
37 request: CompactionPickFinished,
38 ) where
39 S: LogStore,
40 {
41 let Some(region) = self.regions.get_region(region_id) else {
42 return;
43 };
44 let transition = self
49 .compaction_scheduler
50 .handle_compaction_pick_finished(
51 request,
52 ®ion.manifest_ctx,
53 self.schema_metadata_manager.clone(),
54 )
55 .await;
56 match transition {
57 CompactionTransition::AutomaticFollowupScheduled => {
58 region.update_schedule_compaction_millis();
61 }
62 CompactionTransition::NoAction => {}
63 CompactionTransition::DdlReady(mut pending_ddls) => {
64 if !pending_ddls.is_empty() {
65 self.listener.on_compaction_result_notified(region_id).await;
68 self.handle_ddl_requests(&mut pending_ddls).await;
69 }
70 }
71 }
72 }
73
74 pub(crate) async fn handle_compaction_request(
76 &mut self,
77 region_id: RegionId,
78 req: RegionCompactRequest,
79 mut sender: OptionOutputTx,
80 ) {
81 let Some(region) = self.regions.writable_region_or(region_id, &mut sender) else {
82 return;
83 };
84 COMPACTION_REQUEST_COUNT.inc();
85 let parallelism = req.parallelism.unwrap_or(1) as usize;
86 match self.compaction_scheduler.schedule_manual_compaction(
87 req.options,
88 ®ion.version_control,
89 ®ion.access_layer,
90 sender,
91 ®ion.manifest_ctx,
92 self.schema_metadata_manager.clone(),
93 parallelism,
94 req.time_range,
95 ) {
96 Ok(true) => info!(
100 "Successfully scheduled compaction task for region: {}",
101 region_id
102 ),
103 Ok(false) => {}
104 Err(e) => {
105 error!(e; "Failed to schedule compaction task for region: {}", region_id);
106 }
107 }
108 }
109
110 pub(crate) async fn handle_compaction_finished(
112 &mut self,
113 region_id: RegionId,
114 mut request: CompactionFinished,
115 ) where
116 S: LogStore,
117 {
118 let region = match self.regions.get_region(region_id) {
119 Some(region) => region,
120 None => {
121 request.on_failure(RegionNotFoundSnafu { region_id }.build());
122 return;
123 }
124 };
125 if !self
127 .compaction_scheduler
128 .is_current_execution(region_id, &request.execution)
129 {
130 request.on_failure(StaleCompactionExecutionSnafu { region_id }.build());
131 return;
132 }
133 let execution = request.execution.clone();
134
135 region.version_control.apply_edit(
136 Some(request.edit.clone()),
137 &[],
138 region.file_purger.clone(),
139 );
140
141 let index_build_file_metas = std::mem::take(&mut request.edit.files_to_add);
142
143 request.on_success();
145 self.listener.on_compaction_result_notified(region_id).await;
146
147 if self.config.index.build_mode == IndexBuildMode::Async
149 && !index_build_file_metas.is_empty()
150 {
151 self.handle_rebuild_index(
152 BuildIndexRequest {
153 region_id,
154 build_type: IndexBuildType::Compact,
155 file_metas: index_build_file_metas,
156 },
157 OptionOutputTx::new(None),
158 )
159 .await;
160 }
161
162 let transition = self
164 .compaction_scheduler
165 .on_execution_finished(
166 region_id,
167 &execution,
168 ®ion.manifest_ctx,
169 self.schema_metadata_manager.clone(),
170 )
171 .await;
172 match transition {
173 CompactionTransition::AutomaticFollowupScheduled => {
174 region.update_schedule_compaction_millis();
175 }
176 CompactionTransition::NoAction => {}
177 CompactionTransition::DdlReady(mut pending_ddls) => {
178 self.handle_ddl_requests(&mut pending_ddls).await;
179 }
180 }
181 }
182
183 pub(crate) async fn handle_compaction_cancelled(
184 &mut self,
185 region_id: RegionId,
186 request: CompactionCancelled,
187 ) where
188 S: LogStore,
189 {
190 let execution = request.execution.clone();
191 let is_current = self.regions.get_region(region_id).is_some_and(|_| {
192 self.compaction_scheduler
193 .is_current_execution(region_id, &execution)
194 });
195 request.on_success();
196
197 if !is_current {
198 return;
199 }
200
201 let mut pending_ddls = self
203 .compaction_scheduler
204 .on_execution_cancelled(region_id, &execution)
205 .await;
206 if !pending_ddls.is_empty() {
207 self.listener.on_compaction_result_notified(region_id).await;
208 }
209
210 self.handle_ddl_requests(&mut pending_ddls).await;
211 }
212
213 pub(crate) async fn handle_compaction_failure(&mut self, req: CompactionFailed) {
215 if self.regions.get_region(req.region_id).is_none() {
216 return;
217 }
218 if !self
219 .compaction_scheduler
220 .is_current_execution(req.region_id, &req.execution)
221 {
222 debug!(
223 "Ignores stale compaction failure for region {}: {:?}",
224 req.region_id, req.err
225 );
226 return;
227 }
228
229 error!(req.err; "Failed to compact region: {}", req.region_id);
230 self.compaction_scheduler
231 .on_execution_failed(req.region_id, &req.execution, req.err);
232 }
233
234 pub(crate) async fn schedule_compaction(&mut self, region: &MitoRegionRef) {
236 if region.is_staging() || region.is_enter_staging() {
237 info!(
238 "Region {} is staging or entering staging, skip compaction",
239 region.region_id
240 );
241 return;
242 }
243 let now = self.time_provider.current_time_millis();
244 if now - region.last_schedule_compaction_millis()
245 >= self.config.min_compaction_interval.as_millis() as i64
246 {
247 debug!(
248 "minimal compaction interval time {:?} has passed, scheduling next compaction",
249 self.config.min_compaction_interval
250 );
251 match self.compaction_scheduler.schedule_automatic_compaction(
252 compact_request::Options::Regular(Default::default()),
253 ®ion.version_control,
254 ®ion.access_layer,
255 ®ion.manifest_ctx,
256 self.schema_metadata_manager.clone(),
257 ) {
258 Ok(true) => region.update_schedule_compaction_millis(),
259 Ok(false) => {}
260 Err(e) => {
261 error!(e; "Failed to schedule compaction for region: {}", region.region_id)
262 }
263 }
264 }
265 }
266}