• 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 <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 
MakeFileName(const std::string & name,uint64_t number,const char * suffix)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 
LogFileName(const std::string & name,uint64_t number)27 std::string LogFileName(const std::string& name, uint64_t number) {
28   assert(number > 0);
29   return MakeFileName(name, number, "log");
30 }
31 
TableFileName(const std::string & name,uint64_t number)32 std::string TableFileName(const std::string& name, uint64_t number) {
33   assert(number > 0);
34   return MakeFileName(name, number, "ldb");
35 }
36 
SSTTableFileName(const std::string & name,uint64_t number)37 std::string SSTTableFileName(const std::string& name, uint64_t number) {
38   assert(number > 0);
39   return MakeFileName(name, number, "sst");
40 }
41 
DescriptorFileName(const std::string & dbname,uint64_t number)42 std::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 
CurrentFileName(const std::string & dbname)50 std::string CurrentFileName(const std::string& dbname) {
51   return dbname + "/CURRENT";
52 }
53 
LockFileName(const std::string & dbname)54 std::string LockFileName(const std::string& dbname) {
55   return dbname + "/LOCK";
56 }
57 
TempFileName(const std::string & dbname,uint64_t number)58 std::string TempFileName(const std::string& dbname, uint64_t number) {
59   assert(number > 0);
60   return MakeFileName(dbname, number, "dbtmp");
61 }
62 
InfoLogFileName(const std::string & dbname)63 std::string InfoLogFileName(const std::string& dbname) {
64   return dbname + "/LOG";
65 }
66 
67 // Return the name of the old info log file for "dbname".
OldInfoLogFileName(const std::string & dbname)68 std::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)
ParseFileName(const std::string & fname,uint64_t * number,FileType * type)80 bool 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 
SetCurrentFile(Env * env,const std::string & dbname,uint64_t descriptor_number)126 Status 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