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 stats: &ManifestStats,
174 ) -> Result<Self> {
175 let mut store = ManifestObjectStore::new(
177 &options.manifest_dir,
178 options.object_store.clone(),
179 options.compress_type,
180 stats.total_manifest_size.clone(),
181 options.manifest_cache.clone(),
182 );
183 let manifest_version = stats.manifest_version.clone();
184
185 info!(
186 "Creating region manifest in {} with metadata {:?}, flushed_entry_id: {}",
187 options.manifest_dir, metadata, flushed_entry_id
188 );
189
190 let version = MIN_VERSION;
191 let mut manifest_builder = RegionManifestBuilder::default();
192 manifest_builder.apply_change(
194 version,
195 RegionChange {
196 metadata: metadata.clone(),
197 sst_format,
198 append_mode: None,
199 },
200 );
201 let manifest = manifest_builder.try_build()?;
202 let region_id = metadata.region_id;
203
204 debug!(
205 "Build region manifest in {}, manifest: {:?}",
206 options.manifest_dir, manifest
207 );
208
209 let mut actions = vec![RegionMetaAction::Change(RegionChange {
210 metadata,
211 sst_format,
212 append_mode: None,
213 })];
214 if flushed_entry_id > 0 {
215 actions.push(RegionMetaAction::Edit(RegionEdit {
216 files_to_add: vec![],
217 files_to_remove: vec![],
218 timestamp_ms: None,
219 compaction_time_window: None,
220 flushed_entry_id: Some(flushed_entry_id),
221 flushed_sequence: None,
222 committed_sequence: None,
223 }));
224 }
225
226 let action_list = RegionMetaActionList::new(actions);
228
229 store.save(version, &action_list.encode()?, false).await?;
232
233 let checkpointer = Checkpointer::new(region_id, options, store.clone(), MIN_VERSION);
234 manifest_version.store(version, Ordering::Relaxed);
235 manifest
236 .removed_files
237 .update_file_removed_cnt_to_stats(stats);
238 Ok(Self {
239 store,
240 last_version: manifest_version,
241 checkpointer,
242 manifest: Arc::new(manifest),
243 staging_manifest: None,
244 stats: stats.clone(),
245 stopped: false,
246 })
247 }
248
249 pub async fn open(
253 options: RegionManifestOptions,
254 stats: &ManifestStats,
255 ) -> Result<Option<Self>> {
256 let _t = MANIFEST_OP_ELAPSED
257 .with_label_values(&["open"])
258 .start_timer();
259 let open_start = Instant::now();
260
261 let mut store = ManifestObjectStore::new(
263 &options.manifest_dir,
264 options.object_store.clone(),
265 options.compress_type,
266 stats.total_manifest_size.clone(),
267 options.manifest_cache.clone(),
268 );
269 let manifest_version = stats.manifest_version.clone();
270
271 let mut version = MIN_VERSION;
275 let checkpoint = Self::last_checkpoint(&mut store).await?;
276 let last_checkpoint_version = checkpoint
277 .as_ref()
278 .map(|(checkpoint, _)| checkpoint.last_version)
279 .unwrap_or(MIN_VERSION);
280 let mut manifest_builder = if let Some((checkpoint, _)) = checkpoint {
281 info!(
282 "Recover region manifest {} from checkpoint version {}",
283 options.manifest_dir, checkpoint.last_version
284 );
285 version = version.max(checkpoint.last_version + 1);
286 RegionManifestBuilder::with_checkpoint(checkpoint.checkpoint)
287 } else {
288 info!(
289 "Checkpoint not found in {}, build manifest from scratch",
290 options.manifest_dir
291 );
292 RegionManifestBuilder::default()
293 };
294
295 let replay_start_version = version;
296 info!(
297 "Replaying region manifest {} from version {}, last checkpoint version: {}",
298 options.manifest_dir, replay_start_version, last_checkpoint_version,
299 );
300
301 let manifests = store.fetch_manifests(version, MAX_VERSION).await?;
303 let replayed_deltas = manifests.len();
304
305 for (manifest_version, raw_action_list) in manifests {
306 let action_list = RegionMetaActionList::decode(&raw_action_list)?;
307 store.set_delta_file_size(manifest_version, raw_action_list.len() as u64);
309 for action in action_list.actions {
310 match action {
311 RegionMetaAction::Change(action) => {
312 manifest_builder.apply_change(manifest_version, action);
313 }
314 RegionMetaAction::PartitionExprChange(action) => {
315 manifest_builder.apply_partition_expr_change(manifest_version, action);
316 }
317 RegionMetaAction::Edit(action) => {
318 manifest_builder.apply_edit(manifest_version, action);
319 }
320 RegionMetaAction::Remove(_) => {
321 debug!(
322 "Unhandled action in {}, action: {:?}",
323 options.manifest_dir, action
324 );
325 }
326 RegionMetaAction::Truncate(action) => {
327 manifest_builder.apply_truncate(manifest_version, action);
328 }
329 }
330 }
331 }
332
333 if !manifest_builder.contains_metadata() {
335 debug!("No region manifest in {}", options.manifest_dir);
336 return Ok(None);
337 }
338
339 let manifest = manifest_builder.try_build()?;
340 debug!(
341 "Recovered region manifest from {}, manifest: {:?}",
342 options.manifest_dir, manifest
343 );
344 let version = manifest.manifest_version;
345
346 let manifest_dir = options.manifest_dir.clone();
347 let checkpointer = Checkpointer::new(
348 manifest.metadata.region_id,
349 options,
350 store.clone(),
351 last_checkpoint_version,
352 );
353 manifest_version.store(version, Ordering::Relaxed);
354 manifest
355 .removed_files
356 .update_file_removed_cnt_to_stats(stats);
357 info!(
358 "Opened region manifest {}, region_id: {}, start_version: {}, last_checkpoint_version: {}, replayed_deltas: {}, final_version: {}, cost: {:?}",
359 manifest_dir,
360 manifest.metadata.region_id,
361 replay_start_version,
362 last_checkpoint_version,
363 replayed_deltas,
364 version,
365 open_start.elapsed(),
366 );
367 Ok(Some(Self {
368 store,
369 last_version: manifest_version,
370 checkpointer,
371 manifest: Arc::new(manifest),
372 staging_manifest: None,
374 stats: stats.clone(),
375 stopped: false,
376 }))
377 }
378
379 pub async fn stop(&mut self) {
381 self.stopped = true;
382 }
383
384 pub(crate) fn is_stopped(&self) -> bool {
386 self.stopped
387 }
388
389 pub async fn install_manifest_to(
395 &mut self,
396 target_version: ManifestVersion,
397 ) -> Result<ManifestVersion> {
398 let _t = MANIFEST_OP_ELAPSED
399 .with_label_values(&["install_manifest_to"])
400 .start_timer();
401
402 let last_version = self.last_version();
403 if last_version >= target_version {
405 debug!(
406 "Target version {} is less than or equal to the current version {}, region: {}, skip install",
407 target_version, last_version, self.manifest.metadata.region_id
408 );
409 return Ok(last_version);
410 }
411
412 ensure!(
413 !self.stopped,
414 RegionStoppedSnafu {
415 region_id: self.manifest.metadata.region_id,
416 }
417 );
418
419 let region_id = self.manifest.metadata.region_id;
420 let mut manifests = self
422 .store
423 .fetch_manifests_strict_from(last_version + 1, target_version + 1, region_id)
425 .await?;
426
427 if manifests.is_empty() {
434 info!(
435 "Manifests are not strict from {}, region: {}, tries to install the last checkpoint",
436 last_version, self.manifest.metadata.region_id
437 );
438 let last_version = self.install_last_checkpoint().await?;
439 if last_version >= target_version {
441 return Ok(last_version);
442 }
443
444 manifests = self
446 .store
447 .fetch_manifests_strict_from(last_version + 1, target_version + 1, region_id)
449 .await?;
450 }
451
452 if manifests.is_empty() {
453 return NoManifestsSnafu {
454 region_id: self.manifest.metadata.region_id,
455 start_version: last_version + 1,
456 end_version: target_version + 1,
457 last_version,
458 }
459 .fail();
460 }
461
462 debug_assert_eq!(manifests.first().unwrap().0, last_version + 1);
463 let mut manifest_builder =
464 RegionManifestBuilder::with_checkpoint(Some(self.manifest.as_ref().clone()));
465
466 for (manifest_version, raw_action_list) in manifests {
467 self.store
468 .set_delta_file_size(manifest_version, raw_action_list.len() as u64);
469 let action_list = RegionMetaActionList::decode(&raw_action_list)?;
470 for action in action_list.actions {
471 match action {
472 RegionMetaAction::Change(action) => {
473 manifest_builder.apply_change(manifest_version, action);
474 }
475 RegionMetaAction::PartitionExprChange(action) => {
476 manifest_builder.apply_partition_expr_change(manifest_version, action);
477 }
478 RegionMetaAction::Edit(action) => {
479 manifest_builder.apply_edit(manifest_version, action);
480 }
481 RegionMetaAction::Remove(_) => {
482 debug!(
483 "Unhandled action for region {}, action: {:?}",
484 self.manifest.metadata.region_id, action
485 );
486 }
487 RegionMetaAction::Truncate(action) => {
488 manifest_builder.apply_truncate(manifest_version, action);
489 }
490 }
491 }
492 }
493
494 let new_manifest = manifest_builder.try_build()?;
495 ensure!(
496 new_manifest.manifest_version >= target_version,
497 InstallManifestToSnafu {
498 region_id: self.manifest.metadata.region_id,
499 target_version,
500 available_version: new_manifest.manifest_version,
501 last_version,
502 }
503 );
504
505 let version = self.last_version();
506 new_manifest
507 .removed_files
508 .update_file_removed_cnt_to_stats(&self.stats);
509 self.manifest = Arc::new(new_manifest);
510 let last_version = self.set_version(self.manifest.manifest_version);
511 info!(
512 "Install manifest changes from {} to {}, region: {}",
513 version, last_version, self.manifest.metadata.region_id
514 );
515
516 Ok(last_version)
517 }
518
519 pub(crate) async fn install_last_checkpoint(&mut self) -> Result<ManifestVersion> {
521 let last_version = self.last_version();
522 let Some((checkpoint, checkpoint_size)) = Self::last_checkpoint(&mut self.store).await?
523 else {
524 return NoCheckpointSnafu {
525 region_id: self.manifest.metadata.region_id,
526 last_version,
527 }
528 .fail();
529 };
530 self.store.reset_manifest_size();
531 self.store
532 .set_checkpoint_file_size(checkpoint.last_version, checkpoint_size);
533 let builder = RegionManifestBuilder::with_checkpoint(checkpoint.checkpoint);
534 let manifest = builder.try_build()?;
535 let last_version = self.set_version(manifest.manifest_version);
536 manifest
537 .removed_files
538 .update_file_removed_cnt_to_stats(&self.stats);
539 self.manifest = Arc::new(manifest);
540 info!(
541 "Installed region manifest from checkpoint: {}, region: {}",
542 checkpoint.last_version, self.manifest.metadata.region_id
543 );
544
545 Ok(last_version)
546 }
547
548 pub async fn update(
550 &mut self,
551 action_list: RegionMetaActionList,
552 is_staging: bool,
553 ) -> Result<ManifestVersion> {
554 let _t = MANIFEST_OP_ELAPSED
555 .with_label_values(&["update"])
556 .start_timer();
557
558 ensure!(
559 !self.stopped,
560 RegionStoppedSnafu {
561 region_id: self.manifest.metadata.region_id,
562 }
563 );
564
565 let version = self.increase_version();
566 self.store
567 .save(version, &action_list.encode()?, is_staging)
568 .await?;
569
570 let mut manifest_builder =
573 if is_staging && let Some(staging_manifest) = self.staging_manifest.as_ref() {
574 RegionManifestBuilder::with_checkpoint(Some(staging_manifest.as_ref().clone()))
575 } else {
576 RegionManifestBuilder::with_checkpoint(Some(self.manifest.as_ref().clone()))
577 };
578
579 for action in action_list.actions {
580 match action {
581 RegionMetaAction::Change(action) => {
582 manifest_builder.apply_change(version, action);
583 }
584 RegionMetaAction::PartitionExprChange(action) => {
585 manifest_builder.apply_partition_expr_change(version, action);
586 }
587 RegionMetaAction::Edit(action) => {
588 manifest_builder.apply_edit(version, action);
589 }
590 RegionMetaAction::Remove(_) => {
591 debug!(
592 "Unhandled action for region {}, action: {:?}",
593 self.manifest.metadata.region_id, action
594 );
595 }
596 RegionMetaAction::Truncate(action) => {
597 manifest_builder.apply_truncate(version, action);
598 }
599 }
600 }
601
602 if is_staging {
603 let new_manifest = manifest_builder.try_build()?;
604 self.staging_manifest = Some(Arc::new(new_manifest));
605
606 info!(
607 "Skipping checkpoint for region {} in staging mode, manifest version: {}",
608 self.manifest.metadata.region_id, self.manifest.manifest_version
609 );
610 } else {
611 let new_manifest = manifest_builder.try_build()?;
612 new_manifest
613 .removed_files
614 .update_file_removed_cnt_to_stats(&self.stats);
615 let updated_manifest = self
616 .checkpointer
617 .update_manifest_removed_files(new_manifest)?;
618 self.manifest = Arc::new(updated_manifest);
619 self.checkpointer
620 .maybe_do_checkpoint(self.manifest.as_ref());
621 }
622
623 Ok(version)
624 }
625
626 pub fn clear_deleted_files(&mut self, deleted_files: Vec<RemovedFile>) {
628 let mut manifest = (*self.manifest()).clone();
629 manifest.removed_files.clear_deleted_files(deleted_files);
630 self.set_manifest(Arc::new(manifest));
631 }
632
633 pub(crate) fn set_manifest(&mut self, manifest: Arc<RegionManifest>) {
634 self.manifest = manifest;
635 }
636
637 pub fn manifest(&self) -> Arc<RegionManifest> {
639 self.manifest.clone()
640 }
641
642 pub fn staging_manifest(&self) -> Option<Arc<RegionManifest>> {
644 self.staging_manifest.clone()
645 }
646
647 pub fn manifest_usage(&self) -> u64 {
649 self.store.total_manifest_size()
650 }
651
652 pub async fn has_update(&self) -> Result<bool> {
658 let last_version = self.last_version();
659
660 let start_after = list_start_after(self.store.manifest_dir(), last_version);
664 let streamer = self
665 .store
666 .manifest_lister(false, Some(&start_after))
667 .await?
668 .context(error::EmptyManifestDirSnafu {
669 manifest_dir: self.store.manifest_dir(),
670 })?;
671
672 let need_update = streamer
673 .try_any(|entry| async move {
674 let file_name = entry.name();
675 if is_delta_file(file_name) || is_checkpoint_file(file_name) {
676 let version = file_version(file_name);
677 if version > last_version {
678 return true;
679 }
680 }
681 false
682 })
683 .await
684 .context(error::OpenDalSnafu)?;
685
686 Ok(need_update)
687 }
688
689 fn increase_version(&mut self) -> ManifestVersion {
691 let previous = self.last_version.fetch_add(1, Ordering::Relaxed);
692 previous + 1
693 }
694
695 fn set_version(&mut self, version: ManifestVersion) -> ManifestVersion {
697 self.last_version.store(version, Ordering::Relaxed);
698 version
699 }
700
701 pub fn last_version(&self) -> ManifestVersion {
702 self.last_version.load(Ordering::Relaxed)
703 }
704
705 pub(crate) async fn last_checkpoint(
710 store: &mut ManifestObjectStore,
711 ) -> Result<Option<(RegionCheckpoint, u64)>> {
712 let last_checkpoint = store.load_last_checkpoint().await?;
713
714 if let Some((_, bytes)) = last_checkpoint {
715 let checkpoint = RegionCheckpoint::decode(&bytes)?;
716 Ok(Some((checkpoint, bytes.len() as u64)))
717 } else {
718 Ok(None)
719 }
720 }
721
722 pub fn store(&self) -> ManifestObjectStore {
723 self.store.clone()
724 }
725
726 #[cfg(test)]
727 pub(crate) fn checkpointer(&self) -> &Checkpointer {
728 &self.checkpointer
729 }
730
731 pub(crate) async fn merge_staged_actions(
734 &mut self,
735 region_state: RegionRoleState,
736 ) -> Result<Option<RegionMetaActionList>> {
737 if region_state != RegionRoleState::Leader(RegionLeaderState::Staging) {
739 return Ok(None);
740 }
741
742 let staging_manifests = self.store.fetch_staging_manifests().await?;
744
745 if staging_manifests.is_empty() {
746 info!(
747 "No staging manifests to merge for region {}",
748 self.manifest.metadata.region_id
749 );
750 return Ok(None);
751 }
752
753 info!(
754 "Merging {} staging manifests for region {}",
755 staging_manifests.len(),
756 self.manifest.metadata.region_id
757 );
758
759 let mut merged_actions = Vec::new();
761 let mut latest_version = self.last_version();
762
763 for (manifest_version, raw_action_list) in staging_manifests {
765 let action_list = RegionMetaActionList::decode(&raw_action_list)?;
766
767 for action in action_list.actions {
768 merged_actions.push(action);
769 }
770
771 latest_version = latest_version.max(manifest_version);
772 }
773
774 if merged_actions.is_empty() {
775 return Ok(None);
776 }
777
778 info!(
779 "Successfully merged {} actions from staging manifests for region {}, latest version: {}",
780 merged_actions.len(),
781 self.manifest.metadata.region_id,
782 latest_version
783 );
784
785 Ok(Some(RegionMetaActionList::new(merged_actions)))
786 }
787
788 pub(crate) fn unset_staging_manifest(&mut self) {
790 self.staging_manifest = None;
791 }
792
793 pub(crate) async fn clear_staging_manifest_and_dir(&mut self) -> Result<()> {
795 self.staging_manifest = None;
796 self.store.clear_staging_manifests().await?;
797 info!(
798 "Cleared all staging manifests for region {}",
799 self.manifest.metadata.region_id
800 );
801 Ok(())
802 }
803}
804
805#[cfg(test)]
806impl RegionManifestManager {
807 fn validate_manifest(&self, expect: &RegionMetadataRef, last_version: ManifestVersion) {
808 let manifest = self.manifest();
809 assert_eq!(manifest.metadata, *expect);
810 assert_eq!(self.manifest.manifest_version, self.last_version());
811 assert_eq!(last_version, self.last_version());
812 }
813}
814
815#[cfg(test)]
816mod test {
817 use std::time::Duration;
818
819 use api::v1::SemanticType;
820 use common_datasource::compression::CompressionType;
821 use common_test_util::temp_dir::create_temp_dir;
822 use datatypes::prelude::ConcreteDataType;
823 use datatypes::schema::ColumnSchema;
824 use store_api::metadata::{ColumnMetadata, RegionMetadataBuilder};
825
826 use super::*;
827 use crate::manifest::action::{RegionChange, RegionEdit};
828 use crate::manifest::tests::utils::basic_region_metadata;
829 use crate::test_util::TestEnv;
830
831 #[tokio::test]
832 async fn create_manifest_manager() {
833 let metadata = Arc::new(basic_region_metadata());
834 let env = TestEnv::new().await;
835 let manager = env
836 .create_manifest_manager(CompressionType::Uncompressed, 10, Some(metadata.clone()))
837 .await
838 .unwrap()
839 .unwrap();
840
841 manager.validate_manifest(&metadata, 0);
842 }
843
844 #[tokio::test]
845 async fn open_manifest_manager() {
846 let env = TestEnv::new().await;
847 assert!(
849 env.create_manifest_manager(CompressionType::Uncompressed, 10, None)
850 .await
851 .unwrap()
852 .is_none()
853 );
854
855 let metadata = Arc::new(basic_region_metadata());
857 let mut manager = env
858 .create_manifest_manager(CompressionType::Uncompressed, 10, Some(metadata.clone()))
859 .await
860 .unwrap()
861 .unwrap();
862 manager.stop().await;
864
865 let manager = env
867 .create_manifest_manager(CompressionType::Uncompressed, 10, None)
868 .await
869 .unwrap()
870 .unwrap();
871
872 manager.validate_manifest(&metadata, 0);
873 }
874
875 #[tokio::test]
876 async fn manifest_with_partition_expr_roundtrip() {
877 let env = TestEnv::new().await;
878 let expr_json =
879 r#"{"Expr":{"lhs":{"Column":"a"},"op":"GtEq","rhs":{"Value":{"UInt32":10}}}}"#;
880 let mut metadata = basic_region_metadata();
881 metadata.set_partition_expr(Some(expr_json.to_string()));
882 let metadata = Arc::new(metadata);
883 let mut manager = env
884 .create_manifest_manager(CompressionType::Uncompressed, 10, Some(metadata.clone()))
885 .await
886 .unwrap()
887 .unwrap();
888
889 let manifest = manager.manifest();
891 assert_eq!(manifest.metadata.partition_expr.as_deref(), Some(expr_json));
892
893 manager.stop().await;
894
895 let manager = env
897 .create_manifest_manager(CompressionType::Uncompressed, 10, None)
898 .await
899 .unwrap()
900 .unwrap();
901 let manifest = manager.manifest();
902 assert_eq!(manifest.metadata.partition_expr.as_deref(), Some(expr_json));
903 }
904
905 #[tokio::test]
906 async fn region_change_add_column() {
907 let metadata = Arc::new(basic_region_metadata());
908 let env = TestEnv::new().await;
909 let mut manager = env
910 .create_manifest_manager(CompressionType::Uncompressed, 10, Some(metadata.clone()))
911 .await
912 .unwrap()
913 .unwrap();
914
915 let mut new_metadata_builder = RegionMetadataBuilder::from_existing((*metadata).clone());
916 new_metadata_builder.push_column_metadata(ColumnMetadata {
917 column_schema: ColumnSchema::new("val2", ConcreteDataType::float64_datatype(), false),
918 semantic_type: SemanticType::Field,
919 column_id: 252,
920 });
921 let new_metadata = Arc::new(new_metadata_builder.build().unwrap());
922
923 let action_list =
924 RegionMetaActionList::with_action(RegionMetaAction::Change(RegionChange {
925 metadata: new_metadata.clone(),
926 sst_format: FormatType::PrimaryKey,
927 append_mode: None,
928 }));
929
930 let current_version = manager.update(action_list, false).await.unwrap();
931 assert_eq!(current_version, 1);
932 manager.validate_manifest(&new_metadata, 1);
933
934 manager.stop().await;
936 let manager = env
937 .create_manifest_manager(CompressionType::Uncompressed, 10, None)
938 .await
939 .unwrap()
940 .unwrap();
941 manager.validate_manifest(&new_metadata, 1);
942 }
943
944 async fn manifest_dir_usage(path: &str) -> u64 {
946 let mut size = 0;
947 let mut read_dir = tokio::fs::read_dir(path).await.unwrap();
948 while let Ok(dir_entry) = read_dir.next_entry().await {
949 let Some(entry) = dir_entry else {
950 break;
951 };
952 if entry.file_type().await.unwrap().is_file() {
953 let file_name = entry.file_name().into_string().unwrap();
954 if file_name.contains(".checkpoint") || file_name.contains(".json") {
955 let file_size = entry.metadata().await.unwrap().len() as usize;
956 debug!("File: {file_name:?}, size: {file_size}");
957 size += file_size;
958 }
959 }
960 }
961 size as u64
962 }
963
964 #[tokio::test]
965 async fn test_manifest_size() {
966 let metadata = Arc::new(basic_region_metadata());
967 let data_home = create_temp_dir("");
968 let data_home_path = data_home.path().to_str().unwrap().to_string();
969 let env = TestEnv::with_data_home(data_home).await;
970
971 let manifest_dir = format!("{}/manifest", data_home_path);
972
973 let mut manager = env
974 .create_manifest_manager(CompressionType::Uncompressed, 10, Some(metadata.clone()))
975 .await
976 .unwrap()
977 .unwrap();
978
979 let mut new_metadata_builder = RegionMetadataBuilder::from_existing((*metadata).clone());
980 new_metadata_builder.push_column_metadata(ColumnMetadata {
981 column_schema: ColumnSchema::new("val2", ConcreteDataType::float64_datatype(), false),
982 semantic_type: SemanticType::Field,
983 column_id: 252,
984 });
985 let new_metadata = Arc::new(new_metadata_builder.build().unwrap());
986
987 let action_list =
988 RegionMetaActionList::with_action(RegionMetaAction::Change(RegionChange {
989 metadata: new_metadata.clone(),
990 sst_format: FormatType::PrimaryKey,
991 append_mode: None,
992 }));
993
994 let current_version = manager.update(action_list, false).await.unwrap();
995 assert_eq!(current_version, 1);
996 manager.validate_manifest(&new_metadata, 1);
997
998 let manifest_size = manager.manifest_usage();
1000 assert_eq!(manifest_size, manifest_dir_usage(&manifest_dir).await);
1001
1002 for _ in 0..10 {
1004 manager
1005 .update(
1006 RegionMetaActionList::new(vec![RegionMetaAction::Edit(RegionEdit {
1007 files_to_add: vec![],
1008 files_to_remove: vec![],
1009 timestamp_ms: None,
1010 compaction_time_window: None,
1011 flushed_entry_id: None,
1012 flushed_sequence: None,
1013 committed_sequence: None,
1014 })]),
1015 false,
1016 )
1017 .await
1018 .unwrap();
1019 }
1020
1021 while manager.checkpointer.is_doing_checkpoint() {
1022 tokio::time::sleep(Duration::from_millis(10)).await;
1023 }
1024
1025 let manifest_size = manager.manifest_usage();
1027 assert_eq!(manifest_size, manifest_dir_usage(&manifest_dir).await);
1028
1029 manager.stop().await;
1032 let manager = env
1033 .create_manifest_manager(CompressionType::Uncompressed, 10, None)
1034 .await
1035 .unwrap()
1036 .unwrap();
1037 manager.validate_manifest(&new_metadata, 11);
1038
1039 let manifest_size = manager.manifest_usage();
1041 assert_eq!(manifest_size, 1397);
1042 }
1043}