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