16 namespace fs = std::filesystem;
18 static constexpr auto snapshot_file_prefix =
"snapshot";
19 static constexpr auto snapshot_idx_delimiter =
"_";
20 static constexpr auto snapshot_committed_suffix =
".committed";
21 static constexpr auto snapshot_ignored_file_suffix =
"ignored";
23 static bool is_snapshot_file(
const std::string& file_name)
25 return file_name.starts_with(snapshot_file_prefix);
28 static bool is_snapshot_file_committed(
const std::string& file_name)
30 return file_name.ends_with(snapshot_committed_suffix);
33 static bool is_snapshot_file_ignored(
const std::string& file_name)
35 return file_name.ends_with(snapshot_ignored_file_suffix);
38 static void ignore_snapshot_file(
39 const fs::path& dir,
const std::string& file_name)
41 if (is_snapshot_file_ignored(file_name))
46 auto ignored_file_name =
47 fmt::format(
"{}.{}", file_name, snapshot_ignored_file_suffix);
50 "Ignoring snapshot file - rename({} to {})",
53 files::rename(dir / file_name, dir / ignored_file_name);
57 static size_t read_idx(
const std::string& str)
60 const auto* end_ptr = str.data() + str.size();
62 auto res = std::from_chars(str.data(), end_ptr, idx);
63 if (res.ec != std::errc())
65 throw std::logic_error(
66 fmt::format(
"Could not read idx from string \"{}\": {}", str, res.ec));
69 if (res.ptr != end_ptr)
71 throw std::logic_error(fmt::format(
72 R
"(Trailing characters in "{}" cannot be converted to idx: "{}")",
74 std::string(res.ptr, end_ptr)));
79 static std::optional<size_t> get_evidence_commit_idx_from_file_name(
80 const std::string& file_name)
86 auto pos = file_name.find(snapshot_committed_suffix);
87 if (pos == std::string::npos)
89 throw std::logic_error(
90 fmt::format(
"Snapshot file \"{}\" is not committed", file_name));
93 pos = file_name.find(snapshot_idx_delimiter, pos);
94 if (pos == std::string::npos)
100 return read_idx(file_name.substr(pos + 1));
103 static size_t get_snapshot_idx_from_file_name(
const std::string& file_name)
105 if (!is_snapshot_file(file_name))
107 throw std::logic_error(
108 fmt::format(
"File \"{}\" is not a valid snapshot file", file_name));
111 auto idx_pos = file_name.find_first_of(snapshot_idx_delimiter);
112 if (idx_pos == std::string::npos)
114 throw std::logic_error(fmt::format(
115 "Snapshot file name {} does not contain snapshot seqno", file_name));
118 auto evidence_idx_pos =
119 file_name.find_first_of(snapshot_idx_delimiter, idx_pos + 1);
120 if (evidence_idx_pos == std::string::npos)
122 throw std::logic_error(fmt::format(
123 "Snapshot file \"{}\" does not contain evidence index", file_name));
127 file_name.substr(idx_pos + 1, evidence_idx_pos - idx_pos - 1));
130 static size_t get_snapshot_evidence_idx_from_file_name(
131 const std::string& file_name)
133 if (!is_snapshot_file(file_name))
135 throw std::logic_error(
136 fmt::format(
"File \"{}\" is not a valid snapshot file", file_name));
139 auto idx_pos = file_name.find_first_of(snapshot_idx_delimiter);
140 if (idx_pos == std::string::npos)
142 throw std::logic_error(
143 fmt::format(
"Snapshot file \"{}\" does not contain index", file_name));
146 auto evidence_idx_pos =
147 file_name.find_first_of(snapshot_idx_delimiter, idx_pos + 1);
148 if (evidence_idx_pos == std::string::npos)
150 throw std::logic_error(fmt::format(
151 "Snapshot file \"{}\" does not contain evidence index", file_name));
155 size_t end_str = std::string::npos;
156 auto commit_suffix_pos =
157 file_name.find_first_of(snapshot_committed_suffix, evidence_idx_pos + 1);
158 if (commit_suffix_pos != std::string::npos)
160 end_str = commit_suffix_pos - evidence_idx_pos - 1;
163 return read_idx(file_name.substr(evidence_idx_pos + 1, end_str));
166 inline std::vector<std::pair<size_t, fs::path>>
168 const std::vector<fs::path>& directories,
169 std::optional<size_t> minimum_idx = std::nullopt)
171 std::vector<std::pair<size_t, fs::path>> committed_snapshots_with_idx;
173 for (
const auto& dir : directories)
175 for (
const auto& f : fs::directory_iterator(dir))
177 auto file_name = f.path().filename();
178 if (!is_snapshot_file(file_name))
184 if (!is_snapshot_file_committed(file_name))
186 LOG_DEBUG_FMT(
"Ignoring non-committed snapshot file {}", file_name);
190 if (fs::exists(f.path()) && fs::is_empty(f.path()))
192 LOG_INFO_FMT(
"Ignoring empty snapshot file {}", file_name);
196 const auto idx = get_snapshot_idx_from_file_name(file_name.string());
197 if (minimum_idx.has_value() && idx < minimum_idx.value())
200 "Ignoring snapshot file {} below minimum idx {}",
202 minimum_idx.value());
207 committed_snapshots_with_idx.emplace_back(idx, f.path());
213 committed_snapshots_with_idx.begin(),
214 committed_snapshots_with_idx.end(),
216 const std::pair<size_t, fs::path>& lhs,
217 const std::pair<size_t, fs::path>& rhs) {
218 return lhs.first > rhs.first;
221 return committed_snapshots_with_idx;
225 const std::vector<fs::path>& directories,
226 std::optional<size_t> minimum_idx = std::nullopt)
235 return paths.front().second;
239 const fs::path& directory, std::optional<size_t> minimum_idx = std::nullopt)
241 std::vector<fs::path> directories{directory};
243 directories, minimum_idx);
#define LOG_INFO_FMT
Definition internal_logger.h:15
#define LOG_DEBUG_FMT
Definition internal_logger.h:14
std::vector< std::pair< size_t, fs::path > > find_committed_snapshots_in_directories(const std::vector< fs::path > &directories, std::optional< size_t > minimum_idx=std::nullopt)
Definition filenames.h:167
std::optional< fs::path > find_latest_committed_snapshot_in_directory(const fs::path &directory, std::optional< size_t > minimum_idx=std::nullopt)
Definition filenames.h:238
std::optional< fs::path > find_latest_committed_snapshot_in_directories(const std::vector< fs::path > &directories, std::optional< size_t > minimum_idx=std::nullopt)
Definition filenames.h:224
Definition time_bound_logger.h:14