filename.cc raw

   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 <ctype.h>
   8  #include <stdio.h>
   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  
  20  static std::string MakeFileName(const std::string& dbname, uint64_t number,
  21                                  const char* suffix) {
  22    char buf[100];
  23    snprintf(buf, sizeof(buf), "/%06llu.%s",
  24             static_cast<unsigned long long>(number), suffix);
  25    return dbname + buf;
  26  }
  27  
  28  std::string LogFileName(const std::string& dbname, uint64_t number) {
  29    assert(number > 0);
  30    return MakeFileName(dbname, number, "log");
  31  }
  32  
  33  std::string TableFileName(const std::string& dbname, uint64_t number) {
  34    assert(number > 0);
  35    return MakeFileName(dbname, number, "ldb");
  36  }
  37  
  38  std::string SSTTableFileName(const std::string& dbname, uint64_t number) {
  39    assert(number > 0);
  40    return MakeFileName(dbname, number, "sst");
  41  }
  42  
  43  std::string DescriptorFileName(const std::string& dbname, uint64_t number) {
  44    assert(number > 0);
  45    char buf[100];
  46    snprintf(buf, sizeof(buf), "/MANIFEST-%06llu",
  47             static_cast<unsigned long long>(number));
  48    return dbname + buf;
  49  }
  50  
  51  std::string CurrentFileName(const std::string& dbname) {
  52    return dbname + "/CURRENT";
  53  }
  54  
  55  std::string LockFileName(const std::string& dbname) { return dbname + "/LOCK"; }
  56  
  57  std::string TempFileName(const std::string& dbname, uint64_t number) {
  58    assert(number > 0);
  59    return MakeFileName(dbname, number, "dbtmp");
  60  }
  61  
  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".
  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)
  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  
 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->DeleteFile(tmp);
 137    }
 138    return s;
 139  }
 140  
 141  }  // namespace leveldb
 142