1use object_store::util;
16use snafu::OptionExt as _;
17use store_api::metric_engine_consts::{DATA_REGION_SUBDIR, METADATA_REGION_SUBDIR};
18use store_api::path_utils::region_name;
19use store_api::region_request::PathType;
20use store_api::storage::{FileId, RegionId};
21
22use crate::error::UnexpectedSnafu;
23use crate::sst::file::RegionFileId;
24
25pub fn region_dir_from_table_dir(
27 table_dir: &str,
28 region_id: RegionId,
29 path_type: PathType,
30) -> String {
31 let region_name = region_name(region_id.table_id(), region_id.region_sequence());
32 let base_region_dir = util::join_dir(table_dir, ®ion_name);
33
34 match path_type {
35 PathType::Bare => base_region_dir,
36 PathType::Data => util::join_dir(&base_region_dir, DATA_REGION_SUBDIR),
37 PathType::Metadata => util::join_dir(&base_region_dir, METADATA_REGION_SUBDIR),
38 }
39}
40
41pub fn sst_file_path(table_dir: &str, region_file_id: RegionFileId, path_type: PathType) -> String {
42 let region_dir = region_dir_from_table_dir(table_dir, region_file_id.region_id(), path_type);
43 util::join_path(
44 ®ion_dir,
45 &format!("{}.parquet", region_file_id.file_id()),
46 )
47}
48
49pub fn index_file_path(
50 table_dir: &str,
51 region_file_id: RegionFileId,
52 path_type: PathType,
53) -> String {
54 let region_dir = region_dir_from_table_dir(table_dir, region_file_id.region_id(), path_type);
55 let index_dir = util::join_dir(®ion_dir, "index");
56 util::join_path(&index_dir, &format!("{}.puffin", region_file_id.file_id()))
57}
58
59pub fn parse_file_id_from_path(filepath: &str) -> crate::error::Result<FileId> {
61 let filename = filepath.rsplit('/').next().context(UnexpectedSnafu {
62 reason: format!("invalid file path: {}", filepath),
63 })?;
64 let parts: Vec<&str> = filename.split('.').collect();
65 if parts.len() != 2 {
66 return UnexpectedSnafu {
67 reason: format!("invalid file name: {}", filename),
68 }
69 .fail();
70 }
71 if parts[1] != "parquet" && parts[1] != "puffin" {
72 return UnexpectedSnafu {
73 reason: format!("invalid file extension: {}", parts[1]),
74 }
75 .fail();
76 }
77 let file_id = parts[0];
78 FileId::parse_str(file_id).map_err(|e| {
79 UnexpectedSnafu {
80 reason: format!("invalid file id: {}, err: {}", file_id, e),
81 }
82 .build()
83 })
84}
85
86#[cfg(test)]
87mod tests {
88 use store_api::storage::{FileId, RegionId};
89
90 use super::*;
91
92 #[test]
93 fn test_sst_file_path() {
94 let file_id = FileId::random();
95 let region_file_id = RegionFileId::new(RegionId::new(1, 2), file_id);
96 assert_eq!(
97 sst_file_path("table_dir", region_file_id, PathType::Bare),
98 format!("table_dir/1_0000000002/{}.parquet", file_id)
99 );
100 assert_eq!(
101 sst_file_path("table_dir", region_file_id, PathType::Data),
102 format!("table_dir/1_0000000002/data/{}.parquet", file_id)
103 );
104 assert_eq!(
105 sst_file_path("table_dir", region_file_id, PathType::Metadata),
106 format!("table_dir/1_0000000002/metadata/{}.parquet", file_id)
107 );
108 }
109
110 #[test]
111 fn test_index_file_path() {
112 let file_id = FileId::random();
113 let region_file_id = RegionFileId::new(RegionId::new(1, 2), file_id);
114 assert_eq!(
115 index_file_path("table_dir", region_file_id, PathType::Bare),
116 format!("table_dir/1_0000000002/index/{}.puffin", file_id)
117 );
118 assert_eq!(
119 index_file_path("table_dir", region_file_id, PathType::Data),
120 format!("table_dir/1_0000000002/data/index/{}.puffin", file_id)
121 );
122 assert_eq!(
123 index_file_path("table_dir", region_file_id, PathType::Metadata),
124 format!("table_dir/1_0000000002/metadata/index/{}.puffin", file_id)
125 );
126 }
127}