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
12namespace leveldb {
13
14// A utility routine: write "data" to the named file and Sync() it.
15extern Status WriteStringToFileSync(Env* env, const Slice& data,
16                                    const std::string& fname);
17
18static 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
27std::string LogFileName(const std::string& name, uint64_t number) {
28  assert(number > 0);
29  return MakeFileName(name, number, "log");
30}
31
32std::string TableFileName(const std::string& name, uint64_t number) {
33  assert(number > 0);
34  return MakeFileName(name, number, "ldb");
35}
36
37std::string SSTTableFileName(const std::string& name, uint64_t number) {
38  assert(number > 0);
39  return MakeFileName(name, number, "sst");
40}
41
42std::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
50std::string CurrentFileName(const std::string& dbname) {
51  return dbname + "/CURRENT";
52}
53
54std::string LockFileName(const std::string& dbname) {
55  return dbname + "/LOCK";
56}
57
58std::string TempFileName(const std::string& dbname, uint64_t number) {
59  assert(number > 0);
60  return MakeFileName(dbname, number, "dbtmp");
61}
62
63std::string InfoLogFileName(const std::string& dbname) {
64  return dbname + "/LOG";
65}
66
67// Return the name of the old info log file for "dbname".
68std::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)
80bool 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
126Status 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