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