1use std::sync::Arc;
16use std::sync::atomic::{AtomicU64, Ordering};
17use std::time::Instant;
18
19use common_datasource::compression::CompressionType;
20use common_telemetry::{debug, info};
21use futures::TryStreamExt;
22use object_store::ObjectStore;
23use snafu::{OptionExt, ResultExt, ensure};
24use store_api::metadata::RegionMetadataRef;
25use store_api::{MAX_VERSION, MIN_VERSION, ManifestVersion};
26
27use crate::cache::manifest_cache::ManifestCache;
28use crate::config::MitoConfig;
29use crate::error::{
30 self, InstallManifestToSnafu, NoCheckpointSnafu, NoManifestsSnafu, RegionStoppedSnafu, Result,
31};
32use crate::manifest::action::{
33 RegionChange, RegionCheckpoint, RegionEdit, RegionManifest, RegionManifestBuilder,
34 RegionMetaAction, RegionMetaActionList, RemovedFile,
35};
36use crate::manifest::checkpointer::Checkpointer;
37use crate::manifest::storage::{
38 ManifestObjectStore, file_version, is_checkpoint_file, is_delta_file, list_start_after,
39 manifest_compress_type, manifest_dir,
40};
41use crate::metrics::MANIFEST_OP_ELAPSED;
42use crate::region::{ManifestStats, RegionLeaderState, RegionRoleState};
43use crate::sst::FormatType;
44
45#[derive(Debug, Clone)]
47pub struct RegionManifestOptions {
48 pub manifest_dir: String,
50 pub object_store: ObjectStore,
51 pub compress_type: CompressionType,
52 pub checkpoint_distance: u64,
55 pub remove_file_options: RemoveFileOptions,
56 pub manifest_cache: Option<ManifestCache>,
58}
59
60impl RegionManifestOptions {
61 pub fn new(config: &MitoConfig, region_dir: &str, object_store: &ObjectStore) -> Self {
63 RegionManifestOptions {
64 manifest_dir: manifest_dir(region_dir),
65 object_store: object_store.clone(),
66 compress_type: manifest_compress_type(config.compress_manifest),
69 checkpoint_distance: config.manifest_checkpoint_distance,
70 remove_file_options: RemoveFileOptions {
71 enable_gc: config.gc.enable,
72 },
73 manifest_cache: None,
74 }
75 }
76}
77
78#[derive(Debug, Clone)]
80#[cfg_attr(any(test, feature = "test"), derive(Default))]
81pub struct RemoveFileOptions {
82 pub enable_gc: bool,
84}
85
86#[cfg_attr(doc, aquamarine::aquamarine)]
92#[derive(Debug)]
153pub struct RegionManifestManager {
154 store: ManifestObjectStore,
155 last_version: Arc<AtomicU64>,
156 checkpointer: Checkpointer,
157 manifest: Arc<RegionManifest>,
158 staging_manifest: Option<Arc<RegionManifest>>,
162 stats: ManifestStats,
163 stopped: bool,
164}
165
166impl RegionManifestManager {
167 pub async fn new(
169 metadata: RegionMetadataRef,
170 flushed_entry_id: u64,
171 options: RegionManifestOptions,
172 sst_format: FormatType,
173 append_mode: bool,
174 stats: &ManifestStats,
175 ) -> Result<Self> {
176 let mut store = ManifestObjectStore::new(
178 &options.manifest_dir,
179 options.object_store.clone(),
180 options.compress_type,
181 stats.total_manifest_size.clone(),
182 options.manifest_cache.clone(),
183 );
184 let manifest_version = stats.manifest_version.clone();
185
186 info!(
187 "Creating region manifest in {} with metadata {:?}, flushed_entry_id: {}",
188 options.manifest_dir, metadata, flushed_entry_id
189 );
190
191 let version = MIN_VERSION;
192 let mut manifest_builder = RegionManifestBuilder::default();
193 manifest_builder.apply_change(
195 version,
196 RegionChange {
197 metadata: metadata.clone(),
198 sst_format,
199 append_mode: Some(append_mode),
200 },
201 );
202 let manifest = manifest_builder.try_build()?;
203 let region_id = metadata.region_id;
204
205 debug!(
206 "Build region manifest in {}, manifest: {:?}",
207 options.manifest_dir, manifest
208 );
209
210 let mut actions = vec![RegionMetaAction::Change(RegionChange {
211 metadata,
212 sst_format,
213 append_mode: Some(append_mode),
214 })];
215 if flushed_entry_id > 0 {
216 actions.push(RegionMetaAction::Edit(RegionEdit {
217 files_to_add: vec![],
218 files_to_remove: vec![],
219 timestamp_ms: None,
220 compaction_time_window: None,
221 flushed_entry_id: Some(flushed_entry_id),
222 flushed_sequence: None,
223 committed_sequence: None,
224 }));
225 }
226
227 let action_list = RegionMetaActionList::new(actions);
229
230 store.save(version, &action_list.encode()?, false).await?;
233
234 let checkpointer = Checkpointer::new(region_id, options, store.clone(), MIN_VERSION);
235 manifest_version.store(version, Ordering::Relaxed);
236 manifest
237 .removed_files
238 .update_file_removed_cnt_to_stats(stats);
239 Ok(Self {
240 store,
241 last_version: manifest_version,
242 checkpointer,
243 manifest: Arc::new(manifest),
244 staging_manifest: None,
245 stats: stats.clone(),
246 stopped: false,
247 })
248 }
249
250 pub async fn open(
254 options: RegionManifestOptions,
255 stats: &ManifestStats,
256 ) -> Result<Option<Self>> {
257 let _t = MANIFEST_OP_ELAPSED
258 .with_label_values(&["open"])
259 .start_timer();
260 let open_start = Instant::now();
261
262 let mut store = ManifestObjectStore::new(
264 &options.manifest_dir,
265 options.object_store.clone(),
266 options.compress_type,
267 stats.total_manifest_size.clone(),
268 options.manifest_cache.clone(),
269 );
270 let manifest_version = stats.manifest_version.clone();
271
272 let mut version = MIN_VERSION;
276 let checkpoint = Self::last_checkpoint(&mut store).await?;
277 let last_checkpoint_version = checkpoint
278 .as_ref()
279 .map(|(checkpoint, _)| checkpoint.last_version)
280 .unwrap_or(MIN_VERSION);
281 let mut manifest_builder = if let Some((checkpoint, _)) = checkpoint {
282 info!(
283 "Recover region manifest {} from checkpoint version {}",
284 options.manifest_dir, checkpoint.last_version
285 );
286 version = version.max(checkpoint.last_version + 1);
287 RegionManifestBuilder::with_checkpoint(checkpoint.checkpoint)
288 } else {
289 info!(
290 "Checkpoint not found in {}, build manifest from scratch",
291 options.manifest_dir
292 );
293 RegionManifestBuilder::default()
294 };
295
296 let replay_start_version = version;
297 info!(
298 "Replaying region manifest {} from version {}, last checkpoint version: {}",
299 options.manifest_dir, replay_start_version, last_checkpoint_version,
300 );
301
302 let manifests = store.fetch_manifests(version, MAX_VERSION).await?;
304 let replayed_deltas = manifests.len();
305
306 for (manifest_version, raw_action_list) in manifests {
307 let action_list = RegionMetaActionList::decode(&raw_action_list)?;
308 store.set_delta_file_size(manifest_version, raw_action_list.len() as u64);
310 for action in action_list.actions {
311 match action {
312 RegionMetaAction::Change(action) => {
313 manifest_builder.apply_change(manifest_version, action);
314 }
315 RegionMetaAction::PartitionExprChange(action) => {
316 manifest_builder.apply_partition_expr_change(manifest_version, action);
317 }
318 RegionMetaAction::Edit(action) => {
319 manifest_builder.apply_edit(manifest_version, action);
320 }
321 RegionMetaAction::Remove(_) => {
322 debug!(
323 "Unhandled action in {}, action: {:?}",
324 options.manifest_dir, action
325 );
326 }
327 RegionMetaAction::Truncate(action) => {
328 manifest_builder.apply_truncate(manifest_version, action);
329 }
330 }
331 }
332 }
333
334 if !manifest_builder.contains_metadata() {
336 debug!("No region manifest in {}", options.manifest_dir);
337 return Ok(None);
338 }
339
340 let manifest = manifest_builder.try_build()?;
341 debug!(
342 "Recovered region manifest from {}, manifest: {:?}",
343 options.manifest_dir, manifest
344 );
345 let version = manifest.manifest_version;
346
347 let manifest_dir = options.manifest_dir.clone();
348 let checkpointer = Checkpointer::new(
349 manifest.metadata.region_id,
350 options,
351 store.clone(),
352 last_checkpoint_version,
353 );
354 manifest_version.store(version, Ordering::Relaxed);
355 manifest
356 .removed_files
357 .update_file_removed_cnt_to_stats(stats);
358 info!(
359 "Opened region manifest {}, region_id: {}, start_version: {}, last_checkpoint_version: {}, replayed_deltas: {}, final_version: {}, cost: {:?}",
360 manifest_dir,
361 manifest.metadata.region_id,
362 replay_start_version,
363 last_checkpoint_version,
364 replayed_deltas,
365 version,
366 open_start.elapsed(),
367 );
368 Ok(Some(Self {
369 store,
370 last_version: manifest_version,
371 checkpointer,
372 manifest: Arc::new(manifest),
373 staging_manifest: None,
375 stats: stats.clone(),
376 stopped: false,
377 }))
378 }
379
380 pub async fn stop(&mut self) {
382 self.stopped = true;
383 }
384
385 pub(crate) fn is_stopped(&self) -> bool {
387 self.stopped
388 }
389
390 pub async fn install_manifest_to(
396 &mut self,
397 target_version: ManifestVersion,
398 ) -> Result<ManifestVersion> {
399 let _t = MANIFEST_OP_ELAPSED
400 .with_label_values(&["install_manifest_to"])
401 .start_timer();
402
403 let last_version = self.last_version();
404 if last_version >= target_version {
406 debug!(
407 "Target version {} is less than or equal to the current version {}, region: {}, skip install",
408 target_version, last_version, self.manifest.metadata.region_id
409 );
410 return Ok(last_version);
411 }
412
413 ensure!(
414 !self.stopped,
415 RegionStoppedSnafu {
416 region_id: self.manifest.metadata.region_id,
417 }
418 );
419
420 let region_id = self.manifest.metadata.region_id;
421 let mut manifests = self
423 .store
424 .fetch_manifests_strict_from(last_version + 1, target_version + 1, region_id)
426 .await?;
427
428 if manifests.is_empty() {
435 info!(
436 "Manifests are not strict from {}, region: {}, tries to install the last checkpoint",
437 last_version, self.manifest.metadata.region_id
438 );
439 let last_version = self.install_last_checkpoint().await?;
440 if last_version >= target_version {
442 return Ok(last_version);
443 }
444
445 manifests = self
447 .store
448 .fetch_manifests_strict_from(last_version + 1, target_version + 1, region_id)
450 .await?;
451 }
452
453 if manifests.is_empty() {
454 return NoManifestsSnafu {
455 region_id: self.manifest.metadata.region_id,
456 start_version: last_version + 1,
457 end_version: target_version + 1,
458 last_version,
459 }
460 .fail();
461 }
462
463 debug_assert_eq!(manifests.first().unwrap().0, last_version + 1);
464 let mut manifest_builder =
465 RegionManifestBuilder::with_checkpoint(Some(self.manifest.as_ref().clone()));
466
467 for (manifest_version, raw_action_list) in manifests {
468 self.store
469 .set_delta_file_size(manifest_version, raw_action_list.len() as u64);
470 let action_list = RegionMetaActionList::decode(&raw_action_list)?;
471 for action in action_list.actions {
472 match action {
473 RegionMetaAction::Change(action) => {
474 manifest_builder.apply_change(manifest_version, action);
475 }
476 RegionMetaAction::PartitionExprChange(action) => {
477 manifest_builder.apply_partition_expr_change(manifest_version, action);
478 }
479 RegionMetaAction::Edit(action) => {
480 manifest_builder.apply_edit(manifest_version, action);
481 }
482 RegionMetaAction::Remove(_) => {
483 debug!(
484 "Unhandled action for region {}, action: {:?}",
485 self.manifest.metadata.region_id, action
486 );
487 }
488 RegionMetaAction::Truncate(action) => {
489 manifest_builder.apply_truncate(manifest_version, action);
490 }
491 }
492 }
493 }
494
495 let new_manifest = manifest_builder.try_build()?;
496 ensure!(
497 new_manifest.manifest_version >= target_version,
498 InstallManifestToSnafu {
499 region_id: self.manifest.metadata.region_id,
500 target_version,
501 available_version: new_manifest.manifest_version,
502 last_version,
503 }
504 );
505
506 let version = self.last_version();
507 new_manifest
508 .removed_files
509 .update_file_removed_cnt_to_stats(&self.stats);
510 self.manifest = Arc::new(new_manifest);
511 let last_version = self.set_version(self.manifest.manifest_version);
512 info!(
513 "Install manifest changes from {} to {}, region: {}",
514 version, last_version, self.manifest.metadata.region_id
515 );
516
517 Ok(last_version)
518 }
519
520 pub(crate) async fn install_last_checkpoint(&mut self) -> Result<ManifestVersion> {
522 let last_version = self.last_version();
523 let Some((checkpoint, checkpoint_size)) = Self::last_checkpoint(&mut self.store).await?
524 else {
525 return NoCheckpointSnafu {
526 region_id: self.manifest.metadata.region_id,
527 last_version,
528 }
529 .fail();
530 };
531 self.store.reset_manifest_size();
532 self.store
533 .set_checkpoint_file_size(checkpoint.last_version, checkpoint_size);
534 let builder = RegionManifestBuilder::with_checkpoint(checkpoint.checkpoint);
535 let manifest = builder.try_build()?;
536 let last_version = self.set_version(manifest.manifest_version);
537 manifest
538 .removed_files
539 .update_file_removed_cnt_to_stats(&self.stats);
540 self.manifest = Arc::new(manifest);
541 info!(
542 "Installed region manifest from checkpoint: {}, region: {}",
543 checkpoint.last_version, self.manifest.metadata.region_id
544 );
545
546 Ok(last_version)
547 }
548
549 pub async fn update(
551 &mut self,
552 action_list: RegionMetaActionList,
553 is_staging: bool,
554 ) -> Result<ManifestVersion> {
555 self.update_inner(action_list, is_staging, !is_staging)
556 .await
557 }
558
559 pub(crate) async fn update_normal_without_checkpoint(
565 &mut self,
566 action_list: RegionMetaActionList,
567 ) -> Result<ManifestVersion> {
568 self.update_inner(action_list, false, false).await
569 }
570
571 async fn update_inner(
572 &mut self,
573 action_list: RegionMetaActionList,
574 is_staging: bool,
575 allow_checkpoint: bool,
576 ) -> Result<ManifestVersion> {
577 let _t = MANIFEST_OP_ELAPSED
578 .with_label_values(&["update"])
579 .start_timer();
580
581 ensure!(
582 !self.stopped,
583 RegionStoppedSnafu {
584 region_id: self.manifest.metadata.region_id,
585 }
586 );
587
588 let version = self.increase_version();
589 self.store
590 .save(version, &action_list.encode()?, is_staging)
591 .await?;
592
593 let mut manifest_builder =
596 if is_staging && let Some(staging_manifest) = self.staging_manifest.as_ref() {
597 RegionManifestBuilder::with_checkpoint(Some(staging_manifest.as_ref().clone()))
598 } else {
599 RegionManifestBuilder::with_checkpoint(Some(self.manifest.as_ref().clone()))
600 };
601
602 for action in action_list.actions {
603 match action {
604 RegionMetaAction::Change(action) => {
605 manifest_builder.apply_change(version, action);
606 }
607 RegionMetaAction::PartitionExprChange(action) => {
608 manifest_builder.apply_partition_expr_change(version, action);
609 }
610 RegionMetaAction::Edit(action) => {
611 manifest_builder.apply_edit(version, action);
612 }
613 RegionMetaAction::Remove(_) => {
614 debug!(
615 "Unhandled action for region {}, action: {:?}",
616 self.manifest.metadata.region_id, action
617 );
618 }
619 RegionMetaAction::Truncate(action) => {
620 manifest_builder.apply_truncate(version, action);
621 }
622 }
623 }
624
625 if is_staging {
626 let new_manifest = manifest_builder.try_build()?;
627 self.staging_manifest = Some(Arc::new(new_manifest));
628
629 info!(
630 "Skipping checkpoint for region {} in staging mode, manifest version: {}",
631 self.manifest.metadata.region_id, self.manifest.manifest_version
632 );
633 } else {
634 let new_manifest = manifest_builder.try_build()?;
635 new_manifest
636 .removed_files
637 .update_file_removed_cnt_to_stats(&self.stats);
638 let updated_manifest = self
639 .checkpointer
640 .update_manifest_removed_files(new_manifest)?;
641 self.manifest = Arc::new(updated_manifest);
642 if allow_checkpoint {
643 self.checkpointer
644 .maybe_do_checkpoint(self.manifest.as_ref())
645 .await;
646 }
647 }
648
649 Ok(version)
650 }
651
652 pub(crate) async fn wait_for_pending_checkpoint(&mut self) {
654 self.checkpointer.wait_for_pending_checkpoint().await;
655 }
656
657 pub fn clear_deleted_files(&mut self, deleted_files: Vec<RemovedFile>) {
659 let mut manifest = (*self.manifest()).clone();
660 manifest.removed_files.clear_deleted_files(deleted_files);
661 self.set_manifest(Arc::new(manifest));
662 }
663
664 pub(crate) fn set_manifest(&mut self, manifest: Arc<RegionManifest>) {
665 self.manifest = manifest;
666 }
667
668 pub fn manifest(&self) -> Arc<RegionManifest> {
670 self.manifest.clone()
671 }
672
673 pub fn staging_manifest(&self) -> Option<Arc<RegionManifest>> {
675 self.staging_manifest.clone()
676 }
677
678 pub fn manifest_usage(&self) -> u64 {
680 self.store.total_manifest_size()
681 }
682
683 pub async fn has_update(&self) -> Result<bool> {
689 let last_version = self.last_version();
690
691 let start_after = list_start_after(self.store.manifest_dir(), last_version);
695 let streamer = self
696 .store
697 .manifest_lister(false, Some(&start_after))
698 .await?
699 .context(error::EmptyManifestDirSnafu {
700 manifest_dir: self.store.manifest_dir(),
701 })?;
702
703 let need_update = streamer
704 .try_any(|entry| async move {
705 let file_name = entry.name();
706 if is_delta_file(file_name) || is_checkpoint_file(file_name) {
707 let version = file_version(file_name);
708 if version > last_version {
709 return true;
710 }
711 }
712 false
713 })
714 .await
715 .context(error::OpenDalSnafu)?;
716
717 Ok(need_update)
718 }
719
720 fn increase_version(&mut self) -> ManifestVersion {
722 let previous = self.last_version.fetch_add(1, Ordering::Relaxed);
723 previous + 1
724 }
725
726 fn set_version(&mut self, version: ManifestVersion) -> ManifestVersion {
728 self.last_version.store(version, Ordering::Relaxed);
729 version
730 }
731
732 pub fn last_version(&self) -> ManifestVersion {
733 self.last_version.load(Ordering::Relaxed)
734 }
735
736 pub(crate) async fn last_checkpoint(
741 store: &mut ManifestObjectStore,
742 ) -> Result<Option<(RegionCheckpoint, u64)>> {
743 let last_checkpoint = store.load_last_checkpoint().await?;
744
745 if let Some((_, bytes)) = last_checkpoint {
746 let checkpoint = RegionCheckpoint::decode(&bytes)?;
747 Ok(Some((checkpoint, bytes.len() as u64)))
748 } else {
749 Ok(None)
750 }
751 }
752
753 pub fn store(&self) -> ManifestObjectStore {
754 self.store.clone()
755 }
756
757 #[cfg(test)]
758 pub(crate) fn checkpointer(&self) -> &Checkpointer {
759 &self.checkpointer
760 }
761
762 pub(crate) async fn merge_staged_actions(
765 &mut self,
766 region_state: RegionRoleState,
767 ) -> Result<Option<RegionMetaActionList>> {
768 if region_state != RegionRoleState::Leader(RegionLeaderState::Staging) {
770 return Ok(None);
771 }
772
773 let staging_manifests = self.store.fetch_staging_manifests().await?;
775
776 if staging_manifests.is_empty() {
777 info!(
778 "No staging manifests to merge for region {}",
779 self.manifest.metadata.region_id
780 );
781 return Ok(None);
782 }
783
784 info!(
785 "Merging {} staging manifests for region {}",
786 staging_manifests.len(),
787 self.manifest.metadata.region_id
788 );
789
790 let mut merged_actions = Vec::new();
792 let mut latest_version = self.last_version();
793
794 for (manifest_version, raw_action_list) in staging_manifests {
796 let action_list = RegionMetaActionList::decode(&raw_action_list)?;
797
798 for action in action_list.actions {
799 merged_actions.push(action);
800 }
801
802 latest_version = latest_version.max(manifest_version);
803 }
804
805 if merged_actions.is_empty() {
806 return Ok(None);
807 }
808
809 info!(
810 "Successfully merged {} actions from staging manifests for region {}, latest version: {}",
811 merged_actions.len(),
812 self.manifest.metadata.region_id,
813 latest_version
814 );
815
816 Ok(Some(RegionMetaActionList::new(merged_actions)))
817 }
818
819 pub(crate) fn unset_staging_manifest(&mut self) {
821 self.staging_manifest = None;
822 }
823
824 pub(crate) async fn clear_staging_manifest_and_dir(&mut self) -> Result<()> {
826 self.staging_manifest = None;
827 self.store.clear_staging_manifests().await?;
828 info!(
829 "Cleared all staging manifests for region {}",
830 self.manifest.metadata.region_id
831 );
832 Ok(())
833 }
834}
835
836#[cfg(test)]
837impl RegionManifestManager {
838 fn validate_manifest(&self, expect: &RegionMetadataRef, last_version: ManifestVersion) {
839 let manifest = self.manifest();
840 assert_eq!(manifest.metadata, *expect);
841 assert_eq!(self.manifest.manifest_version, self.last_version());
842 assert_eq!(last_version, self.last_version());
843 }
844}
845
846#[cfg(test)]
847mod test {
848 use std::time::Duration;
849
850 use api::v1::SemanticType;
851 use common_datasource::compression::CompressionType;
852 use common_test_util::temp_dir::create_temp_dir;
853 use datatypes::prelude::ConcreteDataType;
854 use datatypes::schema::ColumnSchema;
855 use store_api::metadata::{ColumnMetadata, RegionMetadataBuilder};
856
857 use super::*;
858 use crate::manifest::action::{RegionChange, RegionEdit};
859 use crate::manifest::tests::utils::basic_region_metadata;
860 use crate::test_util::TestEnv;
861
862 #[tokio::test]
863 async fn create_manifest_manager() {
864 let metadata = Arc::new(basic_region_metadata());
865 let env = TestEnv::new().await;
866 let manager = env
867 .create_manifest_manager(CompressionType::Uncompressed, 10, Some(metadata.clone()))
868 .await
869 .unwrap()
870 .unwrap();
871
872 manager.validate_manifest(&metadata, 0);
873 }
874
875 #[tokio::test]
876 async fn open_manifest_manager() {
877 let env = TestEnv::new().await;
878 assert!(
880 env.create_manifest_manager(CompressionType::Uncompressed, 10, None)
881 .await
882 .unwrap()
883 .is_none()
884 );
885
886 let metadata = Arc::new(basic_region_metadata());
888 let mut manager = env
889 .create_manifest_manager(CompressionType::Uncompressed, 10, Some(metadata.clone()))
890 .await
891 .unwrap()
892 .unwrap();
893 manager.stop().await;
895
896 let manager = env
898 .create_manifest_manager(CompressionType::Uncompressed, 10, None)
899 .await
900 .unwrap()
901 .unwrap();
902
903 manager.validate_manifest(&metadata, 0);
904 }
905
906 #[tokio::test]
907 async fn manifest_with_partition_expr_roundtrip() {
908 let env = TestEnv::new().await;
909 let expr_json =
910 r#"{"Expr":{"lhs":{"Column":"a"},"op":"GtEq","rhs":{"Value":{"UInt32":10}}}}"#;
911 let mut metadata = basic_region_metadata();
912 metadata.set_partition_expr(Some(expr_json.to_string()));
913 let metadata = Arc::new(metadata);
914 let mut manager = env
915 .create_manifest_manager(CompressionType::Uncompressed, 10, Some(metadata.clone()))
916 .await
917 .unwrap()
918 .unwrap();
919
920 let manifest = manager.manifest();
922 assert_eq!(manifest.metadata.partition_expr.as_deref(), Some(expr_json));
923
924 manager.stop().await;
925
926 let manager = env
928 .create_manifest_manager(CompressionType::Uncompressed, 10, None)
929 .await
930 .unwrap()
931 .unwrap();
932 let manifest = manager.manifest();
933 assert_eq!(manifest.metadata.partition_expr.as_deref(), Some(expr_json));
934 }
935
936 #[tokio::test]
937 async fn region_change_add_column() {
938 let metadata = Arc::new(basic_region_metadata());
939 let env = TestEnv::new().await;
940 let mut manager = env
941 .create_manifest_manager(CompressionType::Uncompressed, 10, Some(metadata.clone()))
942 .await
943 .unwrap()
944 .unwrap();
945
946 let mut new_metadata_builder = RegionMetadataBuilder::from_existing((*metadata).clone());
947 new_metadata_builder.push_column_metadata(ColumnMetadata {
948 column_schema: ColumnSchema::new("val2", ConcreteDataType::float64_datatype(), false),
949 semantic_type: SemanticType::Field,
950 column_id: 252,
951 });
952 let new_metadata = Arc::new(new_metadata_builder.build().unwrap());
953
954 let action_list =
955 RegionMetaActionList::with_action(RegionMetaAction::Change(RegionChange {
956 metadata: new_metadata.clone(),
957 sst_format: FormatType::PrimaryKey,
958 append_mode: None,
959 }));
960
961 let current_version = manager.update(action_list, false).await.unwrap();
962 assert_eq!(current_version, 1);
963 manager.validate_manifest(&new_metadata, 1);
964
965 manager.stop().await;
967 let manager = env
968 .create_manifest_manager(CompressionType::Uncompressed, 10, None)
969 .await
970 .unwrap()
971 .unwrap();
972 manager.validate_manifest(&new_metadata, 1);
973 }
974
975 async fn manifest_dir_usage(path: &str) -> u64 {
977 let mut size = 0;
978 let mut read_dir = tokio::fs::read_dir(path).await.unwrap();
979 while let Ok(dir_entry) = read_dir.next_entry().await {
980 let Some(entry) = dir_entry else {
981 break;
982 };
983 if entry.file_type().await.unwrap().is_file() {
984 let file_name = entry.file_name().into_string().unwrap();
985 if file_name.contains(".checkpoint") || file_name.contains(".json") {
986 let file_size = entry.metadata().await.unwrap().len() as usize;
987 debug!("File: {file_name:?}, size: {file_size}");
988 size += file_size;
989 }
990 }
991 }
992 size as u64
993 }
994
995 #[tokio::test]
996 async fn test_manifest_size() {
997 let metadata = Arc::new(basic_region_metadata());
998 let data_home = create_temp_dir("");
999 let data_home_path = data_home.path().to_str().unwrap().to_string();
1000 let env = TestEnv::with_data_home(data_home).await;
1001
1002 let manifest_dir = format!("{}/manifest", data_home_path);
1003
1004 let mut manager = env
1005 .create_manifest_manager(CompressionType::Uncompressed, 10, Some(metadata.clone()))
1006 .await
1007 .unwrap()
1008 .unwrap();
1009
1010 let mut new_metadata_builder = RegionMetadataBuilder::from_existing((*metadata).clone());
1011 new_metadata_builder.push_column_metadata(ColumnMetadata {
1012 column_schema: ColumnSchema::new("val2", ConcreteDataType::float64_datatype(), false),
1013 semantic_type: SemanticType::Field,
1014 column_id: 252,
1015 });
1016 let new_metadata = Arc::new(new_metadata_builder.build().unwrap());
1017
1018 let action_list =
1019 RegionMetaActionList::with_action(RegionMetaAction::Change(RegionChange {
1020 metadata: new_metadata.clone(),
1021 sst_format: FormatType::PrimaryKey,
1022 append_mode: None,
1023 }));
1024
1025 let current_version = manager.update(action_list, false).await.unwrap();
1026 assert_eq!(current_version, 1);
1027 manager.validate_manifest(&new_metadata, 1);
1028
1029 let manifest_size = manager.manifest_usage();
1031 assert_eq!(manifest_size, manifest_dir_usage(&manifest_dir).await);
1032
1033 for _ in 0..10 {
1035 manager
1036 .update(
1037 RegionMetaActionList::new(vec![RegionMetaAction::Edit(RegionEdit {
1038 files_to_add: vec![],
1039 files_to_remove: vec![],
1040 timestamp_ms: None,
1041 compaction_time_window: None,
1042 flushed_entry_id: None,
1043 flushed_sequence: None,
1044 committed_sequence: None,
1045 })]),
1046 false,
1047 )
1048 .await
1049 .unwrap();
1050 }
1051
1052 while manager.checkpointer.is_doing_checkpoint() {
1053 tokio::time::sleep(Duration::from_millis(10)).await;
1054 }
1055
1056 let manifest_size = manager.manifest_usage();
1058 assert_eq!(manifest_size, manifest_dir_usage(&manifest_dir).await);
1059
1060 manager.stop().await;
1063 let manager = env
1064 .create_manifest_manager(CompressionType::Uncompressed, 10, None)
1065 .await
1066 .unwrap()
1067 .unwrap();
1068 manager.validate_manifest(&new_metadata, 11);
1069
1070 let manifest_size = manager.manifest_usage();
1072 assert_eq!(manifest_size, 1398);
1073 }
1074}