/Users/deen/code/yugabyte-db/src/yb/rocksdb/db/filename.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
2 | | // This source code is licensed under the BSD-style license found in the |
3 | | // LICENSE file in the root directory of this source tree. An additional grant |
4 | | // of patent rights can be found in the PATENTS file in the same directory. |
5 | | // |
6 | | // The following only applies to changes made to this file as part of YugaByte development. |
7 | | // |
8 | | // Portions Copyright (c) YugaByte, Inc. |
9 | | // |
10 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
11 | | // in compliance with the License. You may obtain a copy of the License at |
12 | | // |
13 | | // http://www.apache.org/licenses/LICENSE-2.0 |
14 | | // |
15 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
16 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
17 | | // or implied. See the License for the specific language governing permissions and limitations |
18 | | // under the License. |
19 | | // |
20 | | // Copyright (c) 2011 The LevelDB Authors. All rights reserved. |
21 | | // Use of this source code is governed by a BSD-style license that can be |
22 | | // found in the LICENSE file. See the AUTHORS file for names of contributors. |
23 | | #ifndef __STDC_FORMAT_MACROS |
24 | | #define __STDC_FORMAT_MACROS |
25 | | #endif |
26 | | |
27 | | #include "yb/rocksdb/db/filename.h" |
28 | | #include <inttypes.h> |
29 | | |
30 | | #include <stdio.h> |
31 | | #include <vector> |
32 | | #include "yb/rocksdb/env.h" |
33 | | #include "yb/rocksdb/util/file_reader_writer.h" |
34 | | #include "yb/rocksdb/util/logging.h" |
35 | | #include "yb/rocksdb/util/sync_point.h" |
36 | | |
37 | | namespace rocksdb { |
38 | | |
39 | | static const char kRocksDbTFileExt[] = "sst"; |
40 | | static const char kLevelDbTFileExt[] = "ldb"; |
41 | | static const char kRocksDbTSBlockExtSuffix[] = "sblock"; |
42 | | static const char kRocksDbTSBlockFileExt[] = "sst.sblock.0"; |
43 | | |
44 | | // Given a path, flatten the path name by replacing all chars not in |
45 | | // {[0-9,a-z,A-Z,-,_,.]} with _. And append '_LOG\0' at the end. |
46 | | // Return the number of chars stored in dest not including the trailing '\0'. |
47 | 1.82k | static size_t GetInfoLogPrefix(const std::string& path, char* dest, int len) { |
48 | 1.82k | const char suffix[] = "_LOG"; |
49 | | |
50 | 1.82k | size_t write_idx = 0; |
51 | 1.82k | size_t i = 0; |
52 | 1.82k | size_t src_len = path.size(); |
53 | | |
54 | 94.8k | while (i < src_len && write_idx < len - sizeof(suffix)) { |
55 | 93.0k | if ((path[i] >= 'a' && path[i] <= 'z') || |
56 | 53.9k | (path[i] >= '0' && path[i] <= '9') || |
57 | 18.2k | (path[i] >= 'A' && path[i] <= 'Z') || |
58 | 18.2k | path[i] == '-' || |
59 | 18.2k | path[i] == '.' || |
60 | 87.5k | path[i] == '_') { |
61 | 87.5k | dest[write_idx++] = path[i]; |
62 | 5.45k | } else { |
63 | 5.45k | if (i > 0) { |
64 | 3.62k | dest[write_idx++] = '_'; |
65 | 3.62k | } |
66 | 5.45k | } |
67 | 93.0k | i++; |
68 | 93.0k | } |
69 | 1.82k | assert(sizeof(suffix) <= len - write_idx); |
70 | | // "\0" is automatically added by snprintf |
71 | 1.82k | snprintf(dest + write_idx, len - write_idx, suffix); |
72 | 1.82k | write_idx += sizeof(suffix) - 1; |
73 | 1.82k | return write_idx; |
74 | 1.82k | } |
75 | | |
76 | | static std::string MakeFileName(const std::string& name, uint64_t number, |
77 | 1.81M | const char* suffix) { |
78 | 1.81M | char buf[100]; |
79 | 1.81M | snprintf(buf, sizeof(buf), "/%06" PRIu64 ".%s", number, suffix); |
80 | 1.81M | return name + buf; |
81 | 1.81M | } |
82 | | |
83 | 396k | std::string LogFileName(const std::string& name, uint64_t number) { |
84 | 396k | assert(number > 0); |
85 | 396k | return MakeFileName(name, number, "log"); |
86 | 396k | } |
87 | | |
88 | 348k | std::string ArchivalDirectory(const std::string& dir) { |
89 | 348k | return dir + "/" + ARCHIVAL_DIR; |
90 | 348k | } |
91 | 650 | std::string ArchivedLogFileName(const std::string& name, uint64_t number) { |
92 | 650 | assert(number > 0); |
93 | 650 | return MakeFileName(name + "/" + ARCHIVAL_DIR, number, "log"); |
94 | 650 | } |
95 | | |
96 | 490k | std::string MakeTableFileName(const std::string& path, uint64_t number) { |
97 | 490k | return MakeFileName(path, number, kRocksDbTFileExt); |
98 | 490k | } |
99 | | |
100 | 12 | std::string Rocks2LevelTableFileName(const std::string& fullname) { |
101 | 12 | assert(fullname.size() > sizeof(kRocksDbTFileExt)); |
102 | 12 | if (fullname.size() <= sizeof(kRocksDbTFileExt)) { |
103 | 0 | return ""; |
104 | 0 | } |
105 | 12 | return fullname.substr(0, fullname.size() - sizeof(kRocksDbTFileExt) + 1) + |
106 | 12 | kLevelDbTFileExt; |
107 | 12 | } |
108 | | |
109 | 358 | uint64_t TableFileNameToNumber(const std::string& name) { |
110 | 358 | uint64_t number = 0; |
111 | 358 | uint64_t base = 1; |
112 | 358 | int pos = static_cast<int>(name.find_last_of('.')); |
113 | 2.50k | while (--pos >= 0 && name[pos] >= '0' && name[pos] <= '9') { |
114 | 2.14k | number += (name[pos] - '0') * base; |
115 | 2.14k | base *= 10; |
116 | 2.14k | } |
117 | 358 | return number; |
118 | 358 | } |
119 | | |
120 | | std::string TableFileName(const std::vector<DbPath>& db_paths, uint64_t number, |
121 | 285k | uint32_t path_id) { |
122 | 285k | assert(number > 0); |
123 | 285k | std::string path; |
124 | 285k | if (path_id >= db_paths.size()) { |
125 | 0 | path = db_paths.back().path; |
126 | 285k | } else { |
127 | 285k | path = db_paths[path_id].path; |
128 | 285k | } |
129 | 285k | return MakeTableFileName(path, number); |
130 | 285k | } |
131 | | |
132 | 214k | extern std::string TableBaseToDataFileName(const std::string& base_fname) { |
133 | 214k | return base_fname + "." + kRocksDbTSBlockExtSuffix + ".0"; |
134 | 214k | } |
135 | | |
136 | | void FormatFileNumber(uint64_t number, uint32_t path_id, char* out_buf, |
137 | 0 | size_t out_buf_size) { |
138 | 0 | if (path_id == 0) { |
139 | 0 | snprintf(out_buf, out_buf_size, "%" PRIu64, number); |
140 | 0 | } else { |
141 | 0 | snprintf(out_buf, out_buf_size, "%" PRIu64 |
142 | 0 | "(path " |
143 | 0 | "%" PRIu32 ")", |
144 | 0 | number, path_id); |
145 | 0 | } |
146 | 0 | } |
147 | | |
148 | 1.43M | std::string DescriptorFileName(const std::string& dbname, uint64_t number) { |
149 | 1.43M | assert(number > 0); |
150 | 1.43M | char buf[100]; |
151 | 1.43M | snprintf(buf, sizeof(buf), "/MANIFEST-%06" PRIu64, number); |
152 | 1.43M | return dbname + buf; |
153 | 1.43M | } |
154 | | |
155 | 1.27M | std::string CurrentFileName(const std::string& dbname) { |
156 | 1.27M | return dbname + "/CURRENT"; |
157 | 1.27M | } |
158 | | |
159 | 687k | std::string LockFileName(const std::string& dbname) { |
160 | 687k | return dbname + "/LOCK"; |
161 | 687k | } |
162 | | |
163 | 923k | std::string TempFileName(const std::string& dbname, uint64_t number) { |
164 | 923k | return MakeFileName(dbname, number, kTempFileNameSuffix); |
165 | 923k | } |
166 | | |
167 | | InfoLogPrefix::InfoLogPrefix(bool has_log_dir, |
168 | 2.07M | const std::string& db_absolute_path) { |
169 | 2.07M | if (!has_log_dir) { |
170 | 2.07M | const char kInfoLogPrefix[] = "LOG"; |
171 | | // "\0" is automatically added to the end |
172 | 2.07M | snprintf(buf, sizeof(buf), kInfoLogPrefix); |
173 | 2.07M | prefix = Slice(buf, sizeof(kInfoLogPrefix) - 1); |
174 | 2.52k | } else { |
175 | 2.52k | size_t len = GetInfoLogPrefix(db_absolute_path, buf, sizeof(buf)); |
176 | 2.52k | prefix = Slice(buf, len); |
177 | 2.52k | } |
178 | 2.07M | } |
179 | | |
180 | | std::string InfoLogFileName(const std::string& dbname, |
181 | 21.0k | const std::string& db_path, const std::string& log_dir) { |
182 | 21.0k | if (log_dir.empty()) { |
183 | 20.7k | return dbname + "/LOG"; |
184 | 20.7k | } |
185 | | |
186 | 268 | InfoLogPrefix info_log_prefix(true, db_path); |
187 | 268 | return log_dir + "/" + info_log_prefix.buf; |
188 | 268 | } |
189 | | |
190 | | // Return the name of the old info log file for "dbname". |
191 | | std::string OldInfoLogFileName(const std::string& dbname, uint64_t ts, |
192 | 13.0k | const std::string& db_path, const std::string& log_dir) { |
193 | 13.0k | char buf[50]; |
194 | 13.0k | snprintf(buf, sizeof(buf), "%" PRIu64, ts); |
195 | | |
196 | 13.0k | if (log_dir.empty()) { |
197 | 12.7k | return dbname + "/LOG.old." + buf; |
198 | 12.7k | } |
199 | | |
200 | 229 | InfoLogPrefix info_log_prefix(true, db_path); |
201 | 229 | return log_dir + "/" + info_log_prefix.buf + ".old." + buf; |
202 | 229 | } |
203 | | |
204 | 999k | std::string OptionsFileName(const std::string& dbname, uint64_t file_num) { |
205 | 999k | char buffer[256]; |
206 | 999k | snprintf(buffer, sizeof(buffer), "%s%06" PRIu64, |
207 | 999k | kOptionsFileNamePrefix, file_num); |
208 | 999k | return dbname + "/" + buffer; |
209 | 999k | } |
210 | | |
211 | 999k | std::string TempOptionsFileName(const std::string& dbname, uint64_t file_num) { |
212 | 999k | char buffer[256]; |
213 | 999k | snprintf(buffer, sizeof(buffer), "%s%06" PRIu64 ".%s", |
214 | 999k | kOptionsFileNamePrefix, file_num, |
215 | 999k | kTempFileNameSuffix); |
216 | 999k | return dbname + "/" + buffer; |
217 | 999k | } |
218 | | |
219 | 3 | std::string MetaDatabaseName(const std::string& dbname, uint64_t number) { |
220 | 3 | char buf[100]; |
221 | 3 | snprintf(buf, sizeof(buf), "/METADB-%" PRIu64, number); |
222 | 3 | return dbname + buf; |
223 | 3 | } |
224 | | |
225 | 676k | std::string IdentityFileName(const std::string& dbname) { |
226 | 676k | return dbname + "/IDENTITY"; |
227 | 676k | } |
228 | | |
229 | | // Owned filenames have the form: |
230 | | // dbname/IDENTITY |
231 | | // dbname/CURRENT |
232 | | // dbname/LOCK |
233 | | // dbname/<info_log_name_prefix> |
234 | | // dbname/<info_log_name_prefix>.old.[0-9]+ |
235 | | // dbname/MANIFEST-[0-9]+ |
236 | | // dbname/[0-9]+.(log|sst) |
237 | | // dbname/METADB-[0-9]+ |
238 | | // dbname/OPTIONS-[0-9]+ |
239 | | // dbname/OPTIONS-[0-9]+.dbtmp |
240 | | // Disregards / at the beginning |
241 | | bool ParseFileName(const std::string& fname, |
242 | | uint64_t* number, |
243 | | FileType* type, |
244 | 12.3M | WalFileType* log_type) { |
245 | 12.3M | return ParseFileName(fname, number, "", type, log_type); |
246 | 12.3M | } |
247 | | |
248 | | bool ParseFileName(const std::string& fname, uint64_t* number, |
249 | | const Slice& info_log_name_prefix, FileType* type, |
250 | 26.4M | WalFileType* log_type) { |
251 | 26.4M | Slice rest(fname); |
252 | 26.4M | if (fname.length() > 1 && fname[0] == '/') { |
253 | 5.00M | rest.remove_prefix(1); |
254 | 5.00M | } |
255 | 26.4M | if (rest == "IDENTITY") { |
256 | 3.02M | *number = 0; |
257 | 3.02M | *type = kIdentityFile; |
258 | 23.4M | } else if (rest == "CURRENT") { |
259 | 3.03M | *number = 0; |
260 | 3.03M | *type = kCurrentFile; |
261 | 20.3M | } else if (rest == "LOCK") { |
262 | 3.02M | *number = 0; |
263 | 3.02M | *type = kDBLockFile; |
264 | 17.3M | } else if (info_log_name_prefix.size() > 0 && |
265 | 9.01M | rest.starts_with(info_log_name_prefix)) { |
266 | 794k | rest.remove_prefix(info_log_name_prefix.size()); |
267 | 794k | if (rest == "" || rest == ".old") { |
268 | 95.4k | *number = 0; |
269 | 95.4k | *type = kInfoLogFile; |
270 | 698k | } else if (rest.starts_with(".old.")) { |
271 | 698k | uint64_t ts_suffix; |
272 | | // sizeof also counts the trailing '\0'. |
273 | 698k | rest.remove_prefix(sizeof(".old.") - 1); |
274 | 698k | if (!ConsumeDecimalNumber(&rest, &ts_suffix)) { |
275 | 0 | return false; |
276 | 0 | } |
277 | 698k | *number = ts_suffix; |
278 | 698k | *type = kInfoLogFile; |
279 | 698k | } |
280 | 16.5M | } else if (rest.starts_with("MANIFEST-")) { |
281 | 4.11M | rest.remove_prefix(strlen("MANIFEST-")); |
282 | 4.11M | uint64_t num; |
283 | 4.11M | if (!ConsumeDecimalNumber(&rest, &num)) { |
284 | 1 | return false; |
285 | 1 | } |
286 | 4.11M | if (!rest.empty()) { |
287 | 1 | return false; |
288 | 1 | } |
289 | 4.11M | *type = kDescriptorFile; |
290 | 4.11M | *number = num; |
291 | 12.4M | } else if (rest.starts_with("METADB-")) { |
292 | 11 | rest.remove_prefix(strlen("METADB-")); |
293 | 11 | uint64_t num; |
294 | 11 | if (!ConsumeDecimalNumber(&rest, &num)) { |
295 | 1 | return false; |
296 | 1 | } |
297 | 10 | if (!rest.empty()) { |
298 | 1 | return false; |
299 | 1 | } |
300 | 9 | *type = kMetaDatabase; |
301 | 9 | *number = num; |
302 | 12.4M | } else if (rest.starts_with(kOptionsFileNamePrefix)) { |
303 | 3.99M | uint64_t ts_suffix; |
304 | 3.99M | bool is_temp_file = false; |
305 | 3.99M | rest.remove_prefix(sizeof(kOptionsFileNamePrefix) - 1); |
306 | 3.99M | const std::string kTempFileNameSuffixWithDot = |
307 | 3.99M | std::string(".") + kTempFileNameSuffix; |
308 | 3.99M | if (rest.ends_with(kTempFileNameSuffixWithDot)) { |
309 | 169 | rest.remove_suffix(kTempFileNameSuffixWithDot.size()); |
310 | 169 | is_temp_file = true; |
311 | 169 | } |
312 | 3.99M | if (!ConsumeDecimalNumber(&rest, &ts_suffix)) { |
313 | 0 | return false; |
314 | 0 | } |
315 | 3.99M | *number = ts_suffix; |
316 | 3.99M | *type = is_temp_file ? kTempFile : kOptionsFile; |
317 | 8.44M | } else { |
318 | | // Avoid strtoull() to keep filename format independent of the |
319 | | // current locale |
320 | 8.44M | bool archive_dir_found = false; |
321 | 8.44M | if (rest.starts_with(ARCHIVAL_DIR)) { |
322 | 554 | if (rest.size() < sizeof(ARCHIVAL_DIR)) { |
323 | 553 | return false; |
324 | 553 | } |
325 | 1 | rest.remove_prefix(sizeof(ARCHIVAL_DIR)); // Don't subtract 1 to remove / also |
326 | 1 | if (log_type) { |
327 | 1 | *log_type = kArchivedLogFile; |
328 | 1 | } |
329 | 1 | archive_dir_found = true; |
330 | 1 | } |
331 | 8.44M | uint64_t num; |
332 | 8.44M | if (!ConsumeDecimalNumber(&rest, &num)) { |
333 | 5.12M | return false; |
334 | 5.12M | } |
335 | 3.33M | if (rest.size() <= 1 || rest[0] != '.') { |
336 | 2 | return false; |
337 | 2 | } |
338 | 3.32M | rest.remove_prefix(1); |
339 | | |
340 | 3.32M | Slice suffix = rest; |
341 | 3.32M | if (suffix == Slice("log")) { |
342 | 2.75M | *type = kLogFile; |
343 | 2.75M | if (log_type && !archive_dir_found) { |
344 | 1 | *log_type = kAliveLogFile; |
345 | 1 | } |
346 | 562k | } else if (archive_dir_found) { |
347 | 0 | return false; // Archive dir can contain only log files |
348 | 562k | } else if (suffix == Slice(kRocksDbTFileExt) || |
349 | 322k | suffix == Slice(kLevelDbTFileExt)) { |
350 | 322k | *type = kTableFile; |
351 | 255k | } else if (suffix == Slice(kRocksDbTSBlockFileExt)) { |
352 | 255k | *type = kTableSBlockFile; |
353 | 18.4E | } else if (suffix == Slice(kTempFileNameSuffix)) { |
354 | 19 | *type = kTempFile; |
355 | 18.4E | } else { |
356 | 18.4E | return false; |
357 | 18.4E | } |
358 | 3.33M | *number = num; |
359 | 3.33M | } |
360 | 21.3M | return true; |
361 | 26.4M | } |
362 | | |
363 | | Status SetCurrentFile(Env* env, const std::string& dbname, |
364 | | uint64_t descriptor_number, |
365 | | Directory* directory_to_fsync, |
366 | 588k | bool disable_data_sync) { |
367 | | // Remove leading "dbname/" and add newline to manifest file name |
368 | 588k | std::string manifest = DescriptorFileName(dbname, descriptor_number); |
369 | 588k | Slice contents = manifest; |
370 | 588k | assert(contents.starts_with(dbname + "/")); |
371 | 588k | contents.remove_prefix(dbname.size() + 1); |
372 | 588k | std::string tmp = TempFileName(dbname, descriptor_number); |
373 | 588k | Status s = WriteStringToFile(env, contents.ToString() + "\n", tmp, !disable_data_sync); |
374 | 588k | if (s.ok()) { |
375 | 588k | TEST_KILL_RANDOM("SetCurrentFile:0", rocksdb_kill_odds * REDUCE_ODDS2); |
376 | 588k | s = env->RenameFile(tmp, CurrentFileName(dbname)); |
377 | 588k | TEST_KILL_RANDOM("SetCurrentFile:1", rocksdb_kill_odds * REDUCE_ODDS2); |
378 | 588k | } |
379 | 588k | if (s.ok()) { |
380 | 588k | if (directory_to_fsync != nullptr && !disable_data_sync) { |
381 | 9.14k | RETURN_NOT_OK(directory_to_fsync->Fsync()); |
382 | 9.14k | } |
383 | 18.4E | } else { |
384 | 18.4E | env->CleanupFile(tmp); |
385 | 18.4E | } |
386 | 588k | return s; |
387 | 588k | } |
388 | | |
389 | 335k | Status SetIdentityFile(Env* env, const std::string& dbname) { |
390 | 335k | std::string id = env->GenerateUniqueId(); |
391 | 335k | assert(!id.empty()); |
392 | | // Reserve the filename dbname/000000.dbtmp for the temporary identity file |
393 | 335k | std::string tmp = TempFileName(dbname, 0); |
394 | 335k | Status s = WriteStringToFile(env, id, tmp, true); |
395 | 335k | if (s.ok()) { |
396 | 334k | s = env->RenameFile(tmp, IdentityFileName(dbname)); |
397 | 334k | } |
398 | 335k | if (!s.ok()) { |
399 | 0 | env->CleanupFile(tmp); |
400 | 0 | } |
401 | 335k | return s; |
402 | 335k | } |
403 | | |
404 | | Status SyncManifest(Env* env, const DBOptions* db_options, |
405 | 642k | WritableFileWriter* file) { |
406 | 642k | TEST_KILL_RANDOM("SyncManifest:0", rocksdb_kill_odds * REDUCE_ODDS2); |
407 | 642k | if (db_options->disableDataSync) { |
408 | 575k | return Status::OK(); |
409 | 67.4k | } else { |
410 | 67.4k | return file->Sync(db_options->use_fsync); |
411 | 67.4k | } |
412 | 642k | } |
413 | | |
414 | | } // namespace rocksdb |