filename.cc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  1. // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
  2. // This source code is licensed under both the GPLv2 (found in the
  3. // COPYING file in the root directory) and Apache 2.0 License
  4. // (found in the LICENSE.Apache file in the root directory).
  5. //
  6. // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
  7. // Use of this source code is governed by a BSD-style license that can be
  8. // found in the LICENSE file. See the AUTHORS file for names of contributors.
  9. #include "file/filename.h"
  10. #include <cctype>
  11. #include <cinttypes>
  12. #include <cstdio>
  13. #include <vector>
  14. #include "file/file_util.h"
  15. #include "file/writable_file_writer.h"
  16. #include "rocksdb/env.h"
  17. #include "rocksdb/file_system.h"
  18. #include "test_util/sync_point.h"
  19. #include "util/stop_watch.h"
  20. #include "util/string_util.h"
  21. namespace ROCKSDB_NAMESPACE {
  22. const std::string kCurrentFileName = "CURRENT";
  23. const std::string kOptionsFileNamePrefix = "OPTIONS-";
  24. const std::string kCompactionProgressFileNamePrefix = "COMPACTION_PROGRESS-";
  25. const std::string kTempFileNameSuffix = "dbtmp";
  26. static const std::string kRocksDbTFileExt = "sst";
  27. static const std::string kLevelDbTFileExt = "ldb";
  28. static const std::string kRocksDBBlobFileExt = "blob";
  29. static const std::string kArchivalDirName = "archive";
  30. // Given a path, flatten the path name by replacing all chars not in
  31. // {[0-9,a-z,A-Z,-,_,.]} with _. And append '_LOG\0' at the end.
  32. // Return the number of chars stored in dest not including the trailing '\0'.
  33. static size_t GetInfoLogPrefix(const std::string& path, char* dest, int len) {
  34. const char suffix[] = "_LOG";
  35. size_t write_idx = 0;
  36. size_t i = 0;
  37. size_t src_len = path.size();
  38. while (i < src_len && write_idx < len - sizeof(suffix)) {
  39. if ((path[i] >= 'a' && path[i] <= 'z') ||
  40. (path[i] >= '0' && path[i] <= '9') ||
  41. (path[i] >= 'A' && path[i] <= 'Z') || path[i] == '-' ||
  42. path[i] == '.' || path[i] == '_') {
  43. dest[write_idx++] = path[i];
  44. } else {
  45. if (i > 0) {
  46. dest[write_idx++] = '_';
  47. }
  48. }
  49. i++;
  50. }
  51. assert(sizeof(suffix) <= len - write_idx);
  52. // "\0" is automatically added by snprintf
  53. snprintf(dest + write_idx, len - write_idx, suffix);
  54. write_idx += sizeof(suffix) - 1;
  55. return write_idx;
  56. }
  57. static std::string MakeFileName(uint64_t number, const char* suffix) {
  58. char buf[100];
  59. snprintf(buf, sizeof(buf), "%06llu.%s",
  60. static_cast<unsigned long long>(number), suffix);
  61. return buf;
  62. }
  63. static std::string MakeFileName(const std::string& name, uint64_t number,
  64. const char* suffix) {
  65. return name + "/" + MakeFileName(number, suffix);
  66. }
  67. std::string LogFileName(const std::string& name, uint64_t number) {
  68. assert(number > 0);
  69. return MakeFileName(name, number, "log");
  70. }
  71. std::string LogFileName(uint64_t number) {
  72. assert(number > 0);
  73. return MakeFileName(number, "log");
  74. }
  75. std::string BlobFileName(uint64_t number) {
  76. assert(number > 0);
  77. return MakeFileName(number, kRocksDBBlobFileExt.c_str());
  78. }
  79. std::string BlobFileName(const std::string& blobdirname, uint64_t number) {
  80. assert(number > 0);
  81. return MakeFileName(blobdirname, number, kRocksDBBlobFileExt.c_str());
  82. }
  83. std::string BlobFileName(const std::string& dbname, const std::string& blob_dir,
  84. uint64_t number) {
  85. assert(number > 0);
  86. return MakeFileName(dbname + "/" + blob_dir, number,
  87. kRocksDBBlobFileExt.c_str());
  88. }
  89. std::string ArchivalDirectory(const std::string& dir) {
  90. return dir + "/" + kArchivalDirName;
  91. }
  92. std::string ArchivedLogFileName(const std::string& name, uint64_t number) {
  93. assert(number > 0);
  94. return MakeFileName(name + "/" + kArchivalDirName, number, "log");
  95. }
  96. std::string MakeTableFileName(const std::string& path, uint64_t number) {
  97. return MakeFileName(path, number, kRocksDbTFileExt.c_str());
  98. }
  99. std::string MakeTableFileName(uint64_t number) {
  100. return MakeFileName(number, kRocksDbTFileExt.c_str());
  101. }
  102. std::string Rocks2LevelTableFileName(const std::string& fullname) {
  103. assert(fullname.size() > kRocksDbTFileExt.size() + 1);
  104. if (fullname.size() <= kRocksDbTFileExt.size() + 1) {
  105. return "";
  106. }
  107. return fullname.substr(0, fullname.size() - kRocksDbTFileExt.size()) +
  108. kLevelDbTFileExt;
  109. }
  110. uint64_t TableFileNameToNumber(const std::string& name) {
  111. uint64_t number = 0;
  112. uint64_t base = 1;
  113. int pos = static_cast<int>(name.find_last_of('.'));
  114. while (--pos >= 0 && name[pos] >= '0' && name[pos] <= '9') {
  115. number += (name[pos] - '0') * base;
  116. base *= 10;
  117. }
  118. return number;
  119. }
  120. std::string TableFileName(const std::vector<DbPath>& db_paths, uint64_t number,
  121. uint32_t path_id) {
  122. assert(number > 0);
  123. std::string path;
  124. if (path_id >= db_paths.size()) {
  125. path = db_paths.back().path;
  126. } else {
  127. path = db_paths[path_id].path;
  128. }
  129. return MakeTableFileName(path, number);
  130. }
  131. void FormatFileNumber(uint64_t number, uint32_t path_id, char* out_buf,
  132. size_t out_buf_size) {
  133. if (path_id == 0) {
  134. snprintf(out_buf, out_buf_size, "%" PRIu64, number);
  135. } else {
  136. snprintf(out_buf, out_buf_size,
  137. "%" PRIu64
  138. "(path "
  139. "%" PRIu32 ")",
  140. number, path_id);
  141. }
  142. }
  143. std::string DescriptorFileName(uint64_t number) {
  144. assert(number > 0);
  145. char buf[100];
  146. snprintf(buf, sizeof(buf), "MANIFEST-%06llu",
  147. static_cast<unsigned long long>(number));
  148. return buf;
  149. }
  150. std::string DescriptorFileName(const std::string& dbname, uint64_t number) {
  151. return dbname + "/" + DescriptorFileName(number);
  152. }
  153. std::string CurrentFileName(const std::string& dbname) {
  154. return dbname + "/" + kCurrentFileName;
  155. }
  156. std::string LockFileName(const std::string& dbname) { return dbname + "/LOCK"; }
  157. std::string TempFileName(const std::string& dbname, uint64_t number) {
  158. return MakeFileName(dbname, number, kTempFileNameSuffix.c_str());
  159. }
  160. InfoLogPrefix::InfoLogPrefix(bool has_log_dir,
  161. const std::string& db_absolute_path) {
  162. if (!has_log_dir) {
  163. const char kInfoLogPrefix[] = "LOG";
  164. // "\0" is automatically added to the end
  165. snprintf(buf, sizeof(buf), kInfoLogPrefix);
  166. prefix = Slice(buf, sizeof(kInfoLogPrefix) - 1);
  167. } else {
  168. size_t len =
  169. GetInfoLogPrefix(NormalizePath(db_absolute_path), buf, sizeof(buf));
  170. prefix = Slice(buf, len);
  171. }
  172. }
  173. std::string InfoLogFileName(const std::string& dbname,
  174. const std::string& db_path,
  175. const std::string& log_dir) {
  176. if (log_dir.empty()) {
  177. return dbname + "/LOG";
  178. }
  179. InfoLogPrefix info_log_prefix(true, db_path);
  180. return log_dir + "/" + info_log_prefix.buf;
  181. }
  182. // Return the name of the old info log file for "dbname".
  183. std::string OldInfoLogFileName(const std::string& dbname, uint64_t ts,
  184. const std::string& db_path,
  185. const std::string& log_dir) {
  186. char buf[50];
  187. snprintf(buf, sizeof(buf), "%llu", static_cast<unsigned long long>(ts));
  188. if (log_dir.empty()) {
  189. return dbname + "/LOG.old." + buf;
  190. }
  191. InfoLogPrefix info_log_prefix(true, db_path);
  192. return log_dir + "/" + info_log_prefix.buf + ".old." + buf;
  193. }
  194. std::string OptionsFileName(uint64_t file_num) {
  195. char buffer[256];
  196. snprintf(buffer, sizeof(buffer), "%s%06" PRIu64,
  197. kOptionsFileNamePrefix.c_str(), file_num);
  198. return buffer;
  199. }
  200. std::string OptionsFileName(const std::string& dbname, uint64_t file_num) {
  201. return dbname + "/" + OptionsFileName(file_num);
  202. }
  203. std::string TempOptionsFileName(const std::string& dbname, uint64_t file_num) {
  204. char buffer[256];
  205. snprintf(buffer, sizeof(buffer), "%s%06" PRIu64 ".%s",
  206. kOptionsFileNamePrefix.c_str(), file_num,
  207. kTempFileNameSuffix.c_str());
  208. return dbname + "/" + buffer;
  209. }
  210. std::string CompactionProgressFileName(const std::string& dbname,
  211. uint64_t timestamp) {
  212. char buffer[256];
  213. snprintf(buffer, sizeof(buffer), "%s%llu",
  214. kCompactionProgressFileNamePrefix.c_str(),
  215. static_cast<unsigned long long>(timestamp));
  216. return dbname + "/" + buffer;
  217. }
  218. std::string TempCompactionProgressFileName(const std::string& dbname,
  219. uint64_t timestamp) {
  220. char buffer[256];
  221. snprintf(buffer, sizeof(buffer), "%s%llu.%s",
  222. kCompactionProgressFileNamePrefix.c_str(),
  223. static_cast<unsigned long long>(timestamp),
  224. kTempFileNameSuffix.c_str());
  225. return dbname + "/" + buffer;
  226. }
  227. std::string MetaDatabaseName(const std::string& dbname, uint64_t number) {
  228. char buf[100];
  229. snprintf(buf, sizeof(buf), "/METADB-%llu",
  230. static_cast<unsigned long long>(number));
  231. return dbname + buf;
  232. }
  233. std::string IdentityFileName(const std::string& dbname) {
  234. return dbname + "/IDENTITY";
  235. }
  236. // Owned filenames have the form:
  237. // dbname/IDENTITY
  238. // dbname/CURRENT
  239. // dbname/LOCK
  240. // dbname/<info_log_name_prefix>
  241. // dbname/<info_log_name_prefix>.old.[0-9]+
  242. // dbname/MANIFEST-[0-9]+
  243. // dbname/[0-9]+.(log|sst|blob)
  244. // dbname/METADB-[0-9]+
  245. // dbname/OPTIONS-[0-9]+
  246. // dbname/OPTIONS-[0-9]+.dbtmp
  247. // dbname/COMPACTION_PROGRESS-[timestamp]
  248. // dbname/COMPACTION_PROGRESS-[timestamp].dbtmp
  249. // Disregards / at the beginning
  250. bool ParseFileName(const std::string& fname, uint64_t* number, FileType* type,
  251. WalFileType* log_type) {
  252. return ParseFileName(fname, number, "", type, log_type);
  253. }
  254. bool ParseFileName(const std::string& fname, uint64_t* number,
  255. const Slice& info_log_name_prefix, FileType* type,
  256. WalFileType* log_type) {
  257. Slice rest(fname);
  258. if (fname.length() > 1 && fname[0] == '/') {
  259. rest.remove_prefix(1);
  260. }
  261. if (rest == "IDENTITY") {
  262. *number = 0;
  263. *type = kIdentityFile;
  264. } else if (rest == "CURRENT") {
  265. *number = 0;
  266. *type = kCurrentFile;
  267. } else if (rest == "LOCK") {
  268. *number = 0;
  269. *type = kDBLockFile;
  270. } else if (info_log_name_prefix.size() > 0 &&
  271. rest.starts_with(info_log_name_prefix)) {
  272. rest.remove_prefix(info_log_name_prefix.size());
  273. if (rest == "" || rest == ".old") {
  274. *number = 0;
  275. *type = kInfoLogFile;
  276. } else if (rest.starts_with(".old.")) {
  277. uint64_t ts_suffix;
  278. // sizeof also counts the trailing '\0'.
  279. rest.remove_prefix(sizeof(".old.") - 1);
  280. if (!ConsumeDecimalNumber(&rest, &ts_suffix)) {
  281. return false;
  282. }
  283. *number = ts_suffix;
  284. *type = kInfoLogFile;
  285. }
  286. } else if (rest.starts_with("MANIFEST-")) {
  287. rest.remove_prefix(strlen("MANIFEST-"));
  288. uint64_t num;
  289. if (!ConsumeDecimalNumber(&rest, &num)) {
  290. return false;
  291. }
  292. if (!rest.empty()) {
  293. return false;
  294. }
  295. *type = kDescriptorFile;
  296. *number = num;
  297. } else if (rest.starts_with("METADB-")) {
  298. rest.remove_prefix(strlen("METADB-"));
  299. uint64_t num;
  300. if (!ConsumeDecimalNumber(&rest, &num)) {
  301. return false;
  302. }
  303. if (!rest.empty()) {
  304. return false;
  305. }
  306. *type = kMetaDatabase;
  307. *number = num;
  308. } else if (rest.starts_with(kOptionsFileNamePrefix)) {
  309. uint64_t ts_suffix;
  310. bool is_temp_file = false;
  311. rest.remove_prefix(kOptionsFileNamePrefix.size());
  312. const std::string kTempFileNameSuffixWithDot =
  313. std::string(".") + kTempFileNameSuffix;
  314. if (rest.ends_with(kTempFileNameSuffixWithDot)) {
  315. rest.remove_suffix(kTempFileNameSuffixWithDot.size());
  316. is_temp_file = true;
  317. }
  318. if (!ConsumeDecimalNumber(&rest, &ts_suffix)) {
  319. return false;
  320. }
  321. *number = ts_suffix;
  322. *type = is_temp_file ? kTempFile : kOptionsFile;
  323. } else if (rest.starts_with(kCompactionProgressFileNamePrefix)) {
  324. uint64_t timestamp;
  325. bool is_temp_file = false;
  326. rest.remove_prefix(kCompactionProgressFileNamePrefix.size());
  327. const std::string kTempFileNameSuffixWithDot =
  328. std::string(".") + kTempFileNameSuffix;
  329. if (rest.ends_with(kTempFileNameSuffixWithDot)) {
  330. rest.remove_suffix(kTempFileNameSuffixWithDot.size());
  331. is_temp_file = true;
  332. }
  333. if (!ConsumeDecimalNumber(&rest, &timestamp)) {
  334. return false;
  335. }
  336. if (!rest.empty()) {
  337. return false;
  338. }
  339. *number = timestamp;
  340. *type = is_temp_file ? kTempFile : kCompactionProgressFile;
  341. } else {
  342. // Avoid strtoull() to keep filename format independent of the
  343. // current locale
  344. bool archive_dir_found = false;
  345. if (rest.starts_with(kArchivalDirName)) {
  346. if (rest.size() <= kArchivalDirName.size()) {
  347. return false;
  348. }
  349. rest.remove_prefix(kArchivalDirName.size() +
  350. 1); // Add 1 to remove / also
  351. if (log_type) {
  352. *log_type = kArchivedLogFile;
  353. }
  354. archive_dir_found = true;
  355. }
  356. uint64_t num;
  357. if (!ConsumeDecimalNumber(&rest, &num)) {
  358. return false;
  359. }
  360. if (rest.size() <= 1 || rest[0] != '.') {
  361. return false;
  362. }
  363. rest.remove_prefix(1);
  364. Slice suffix = rest;
  365. if (suffix == Slice("log")) {
  366. *type = kWalFile;
  367. if (log_type && !archive_dir_found) {
  368. *log_type = kAliveLogFile;
  369. }
  370. } else if (archive_dir_found) {
  371. return false; // Archive dir can contain only log files
  372. } else if (suffix == Slice(kRocksDbTFileExt) ||
  373. suffix == Slice(kLevelDbTFileExt)) {
  374. *type = kTableFile;
  375. } else if (suffix == Slice(kRocksDBBlobFileExt)) {
  376. *type = kBlobFile;
  377. } else if (suffix == Slice(kTempFileNameSuffix)) {
  378. *type = kTempFile;
  379. } else {
  380. return false;
  381. }
  382. *number = num;
  383. }
  384. return true;
  385. }
  386. IOStatus SetCurrentFile(const WriteOptions& write_options, FileSystem* fs,
  387. const std::string& dbname, uint64_t descriptor_number,
  388. Temperature temp,
  389. FSDirectory* dir_contains_current_file) {
  390. // Remove leading "dbname/" and add newline to manifest file name
  391. std::string manifest = DescriptorFileName(dbname, descriptor_number);
  392. Slice contents = manifest;
  393. assert(contents.starts_with(dbname + "/"));
  394. contents.remove_prefix(dbname.size() + 1);
  395. std::string tmp = TempFileName(dbname, descriptor_number);
  396. IOOptions opts;
  397. IOStatus s = PrepareIOFromWriteOptions(write_options, opts);
  398. FileOptions file_opts;
  399. file_opts.temperature = temp;
  400. if (s.ok()) {
  401. s = WriteStringToFile(fs, contents.ToString() + "\n", tmp, true, opts,
  402. file_opts);
  403. }
  404. TEST_SYNC_POINT_CALLBACK("SetCurrentFile:BeforeRename", &s);
  405. if (s.ok()) {
  406. TEST_KILL_RANDOM_WITH_WEIGHT("SetCurrentFile:0", REDUCE_ODDS2);
  407. s = fs->RenameFile(tmp, CurrentFileName(dbname), opts, nullptr);
  408. TEST_KILL_RANDOM_WITH_WEIGHT("SetCurrentFile:1", REDUCE_ODDS2);
  409. TEST_SYNC_POINT_CALLBACK("SetCurrentFile:AfterRename", &s);
  410. }
  411. if (s.ok()) {
  412. if (dir_contains_current_file != nullptr) {
  413. s = dir_contains_current_file->FsyncWithDirOptions(
  414. opts, nullptr, DirFsyncOptions(CurrentFileName(dbname)));
  415. }
  416. } else {
  417. fs->DeleteFile(tmp, opts, nullptr)
  418. .PermitUncheckedError(); // NOTE: PermitUncheckedError is acceptable
  419. // here as we are already handling an error
  420. // case, and this is just a best-attempt
  421. // effort at some cleanup
  422. }
  423. return s;
  424. }
  425. Status SetIdentityFile(const WriteOptions& write_options, Env* env,
  426. const std::string& dbname, Temperature temp,
  427. const std::string& db_id) {
  428. std::string id;
  429. if (db_id.empty()) {
  430. id = env->GenerateUniqueId();
  431. } else {
  432. id = db_id;
  433. }
  434. assert(!id.empty());
  435. // Reserve the filename dbname/000000.dbtmp for the temporary identity file
  436. std::string tmp = TempFileName(dbname, 0);
  437. std::string identify_file_name = IdentityFileName(dbname);
  438. Status s;
  439. IOOptions opts;
  440. s = PrepareIOFromWriteOptions(write_options, opts);
  441. FileOptions file_opts;
  442. file_opts.temperature = temp;
  443. if (s.ok()) {
  444. s = WriteStringToFile(env->GetFileSystem().get(), id, tmp,
  445. /*should_sync=*/true, opts, file_opts);
  446. }
  447. if (s.ok()) {
  448. s = env->RenameFile(tmp, identify_file_name);
  449. }
  450. std::unique_ptr<FSDirectory> dir_obj;
  451. if (s.ok()) {
  452. s = env->GetFileSystem()->NewDirectory(dbname, opts, &dir_obj, nullptr);
  453. }
  454. if (s.ok()) {
  455. s = dir_obj->FsyncWithDirOptions(opts, nullptr,
  456. DirFsyncOptions(identify_file_name));
  457. }
  458. // The default Close() could return "NotSupported" and we bypass it
  459. // if it is not impelmented. Detailed explanations can be found in
  460. // db/db_impl/db_impl.h
  461. if (s.ok()) {
  462. Status temp_s = dir_obj->Close(opts, nullptr);
  463. if (!temp_s.ok()) {
  464. if (temp_s.IsNotSupported()) {
  465. temp_s.PermitUncheckedError();
  466. } else {
  467. s = temp_s;
  468. }
  469. }
  470. }
  471. if (!s.ok()) {
  472. env->DeleteFile(tmp).PermitUncheckedError();
  473. }
  474. return s;
  475. }
  476. IOStatus SyncManifest(const ImmutableDBOptions* db_options,
  477. const WriteOptions& write_options,
  478. WritableFileWriter* file) {
  479. TEST_KILL_RANDOM_WITH_WEIGHT("SyncManifest:0", REDUCE_ODDS2);
  480. StopWatch sw(db_options->clock, db_options->stats, MANIFEST_FILE_SYNC_MICROS);
  481. IOOptions io_options;
  482. IOStatus s = PrepareIOFromWriteOptions(write_options, io_options);
  483. if (!s.ok()) {
  484. return s;
  485. }
  486. return file->Sync(io_options, db_options->use_fsync);
  487. }
  488. Status GetInfoLogFiles(const std::shared_ptr<FileSystem>& fs,
  489. const std::string& db_log_dir, const std::string& dbname,
  490. std::string* parent_dir,
  491. std::vector<std::string>* info_log_list) {
  492. assert(parent_dir != nullptr);
  493. assert(info_log_list != nullptr);
  494. uint64_t number = 0;
  495. FileType type = kWalFile;
  496. if (!db_log_dir.empty()) {
  497. *parent_dir = db_log_dir;
  498. } else {
  499. *parent_dir = dbname;
  500. }
  501. InfoLogPrefix info_log_prefix(!db_log_dir.empty(), dbname);
  502. std::vector<std::string> file_names;
  503. Status s = fs->GetChildren(*parent_dir, IOOptions(), &file_names, nullptr);
  504. if (!s.ok()) {
  505. return s;
  506. }
  507. for (auto& f : file_names) {
  508. if (ParseFileName(f, &number, info_log_prefix.prefix, &type) &&
  509. (type == kInfoLogFile)) {
  510. info_log_list->push_back(f);
  511. }
  512. }
  513. return Status::OK();
  514. }
  515. std::string NormalizePath(const std::string& path) {
  516. std::string dst;
  517. if (path.length() > 2 && path[0] == kFilePathSeparator &&
  518. path[1] == kFilePathSeparator) { // Handle UNC names
  519. dst.append(2, kFilePathSeparator);
  520. }
  521. for (auto c : path) {
  522. if (!dst.empty() && (c == kFilePathSeparator || c == '/') &&
  523. (dst.back() == kFilePathSeparator || dst.back() == '/')) {
  524. continue;
  525. }
  526. dst.push_back(c);
  527. }
  528. return dst;
  529. }
  530. } // namespace ROCKSDB_NAMESPACE