1 // Copyright (c) 2011 The LevelDB Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. See the AUTHORS file for names of contributors. 4 5 #include <ctype.h> 6 #include <stdio.h> 7 #include "db/filename.h" 8 #include "db/dbformat.h" 9 #include "leveldb/env.h" 10 #include "util/logging.h" 11 12 namespace leveldb { 13 14 // A utility routine: write "data" to the named file and Sync() it. 15 extern Status WriteStringToFileSync(Env* env, const Slice& data, 16 const std::string& fname); 17 18 static std::string MakeFileName(const std::string& name, uint64_t number, 19 const char* suffix) { 20 char buf[100]; 21 snprintf(buf, sizeof(buf), "/%06llu.%s", 22 static_cast<unsigned long long>(number), 23 suffix); 24 return name + buf; 25 } 26 27 std::string LogFileName(const std::string& name, uint64_t number) { 28 assert(number > 0); 29 return MakeFileName(name, number, "log"); 30 } 31 32 std::string TableFileName(const std::string& name, uint64_t number) { 33 assert(number > 0); 34 return MakeFileName(name, number, "sst"); 35 } 36 37 std::string DescriptorFileName(const std::string& dbname, uint64_t number) { 38 assert(number > 0); 39 char buf[100]; 40 snprintf(buf, sizeof(buf), "/MANIFEST-%06llu", 41 static_cast<unsigned long long>(number)); 42 return dbname + buf; 43 } 44 45 std::string CurrentFileName(const std::string& dbname) { 46 return dbname + "/CURRENT"; 47 } 48 49 std::string LockFileName(const std::string& dbname) { 50 return dbname + "/LOCK"; 51 } 52 53 std::string TempFileName(const std::string& dbname, uint64_t number) { 54 assert(number > 0); 55 return MakeFileName(dbname, number, "dbtmp"); 56 } 57 58 std::string InfoLogFileName(const std::string& dbname) { 59 return dbname + "/LOG"; 60 } 61 62 // Return the name of the old info log file for "dbname". 63 std::string OldInfoLogFileName(const std::string& dbname) { 64 return dbname + "/LOG.old"; 65 } 66 67 68 // Owned filenames have the form: 69 // dbname/CURRENT 70 // dbname/LOCK 71 // dbname/LOG 72 // dbname/LOG.old 73 // dbname/MANIFEST-[0-9]+ 74 // dbname/[0-9]+.(log|sst) 75 bool ParseFileName(const std::string& fname, 76 uint64_t* number, 77 FileType* type) { 78 Slice rest(fname); 79 if (rest == "CURRENT") { 80 *number = 0; 81 *type = kCurrentFile; 82 } else if (rest == "LOCK") { 83 *number = 0; 84 *type = kDBLockFile; 85 } else if (rest == "LOG" || rest == "LOG.old") { 86 *number = 0; 87 *type = kInfoLogFile; 88 } else if (rest.starts_with("MANIFEST-")) { 89 rest.remove_prefix(strlen("MANIFEST-")); 90 uint64_t num; 91 if (!ConsumeDecimalNumber(&rest, &num)) { 92 return false; 93 } 94 if (!rest.empty()) { 95 return false; 96 } 97 *type = kDescriptorFile; 98 *number = num; 99 } else { 100 // Avoid strtoull() to keep filename format independent of the 101 // current locale 102 uint64_t num; 103 if (!ConsumeDecimalNumber(&rest, &num)) { 104 return false; 105 } 106 Slice suffix = rest; 107 if (suffix == Slice(".log")) { 108 *type = kLogFile; 109 } else if (suffix == Slice(".sst")) { 110 *type = kTableFile; 111 } else if (suffix == Slice(".dbtmp")) { 112 *type = kTempFile; 113 } else { 114 return false; 115 } 116 *number = num; 117 } 118 return true; 119 } 120 121 Status SetCurrentFile(Env* env, const std::string& dbname, 122 uint64_t descriptor_number) { 123 // Remove leading "dbname/" and add newline to manifest file name 124 std::string manifest = DescriptorFileName(dbname, descriptor_number); 125 Slice contents = manifest; 126 assert(contents.starts_with(dbname + "/")); 127 contents.remove_prefix(dbname.size() + 1); 128 std::string tmp = TempFileName(dbname, descriptor_number); 129 Status s = WriteStringToFileSync(env, contents.ToString() + "\n", tmp); 130 if (s.ok()) { 131 s = env->RenameFile(tmp, CurrentFileName(dbname)); 132 } 133 if (!s.ok()) { 134 env->DeleteFile(tmp); 135 } 136 return s; 137 } 138 139 } // namespace leveldb 140