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, "ldb");
     35 }
     36 
     37 std::string SSTTableFileName(const std::string& name, uint64_t number) {
     38   assert(number > 0);
     39   return MakeFileName(name, number, "sst");
     40 }
     41 
     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 
     50 std::string CurrentFileName(const std::string& dbname) {
     51   return dbname + "/CURRENT";
     52 }
     53 
     54 std::string LockFileName(const std::string& dbname) {
     55   return dbname + "/LOCK";
     56 }
     57 
     58 std::string TempFileName(const std::string& dbname, uint64_t number) {
     59   assert(number > 0);
     60   return MakeFileName(dbname, number, "dbtmp");
     61 }
     62 
     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".
     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)
     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 
    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