Home | History | Annotate | Download | only in db
      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