mirror of
https://github.com/google/leveldb.git
synced 2025-04-25 14:00:27 +08:00
Implement iterative directories creation
This commit is contained in:
parent
77d66aaf3e
commit
d5d450d29b
@ -295,7 +295,7 @@ Status DBImpl::Recover(VersionEdit* edit, bool* save_manifest) {
|
||||
// Ignore error from CreateDir since the creation of the DB is
|
||||
// committed only when the descriptor is created, and this directory
|
||||
// may already exist from a previous failed creation attempt.
|
||||
env_->CreateDir(dbname_);
|
||||
env_->CreateDirIteratively(dbname_);
|
||||
assert(db_lock_ == nullptr);
|
||||
Status s = env_->LockFile(LockFileName(dbname_), &db_lock_);
|
||||
if (!s.ok()) {
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include "leveldb/export.h"
|
||||
#include "leveldb/status.h"
|
||||
#include "util/dir_helper.h"
|
||||
|
||||
// This workaround can be removed when leveldb::Env::DeleteFile is removed.
|
||||
#if defined(_WIN32)
|
||||
@ -113,6 +114,9 @@ class LEVELDB_EXPORT Env {
|
||||
// Returns true iff the named file exists.
|
||||
virtual bool FileExists(const std::string& fname) = 0;
|
||||
|
||||
// Returns true if specified director path exists.
|
||||
virtual bool DirectoryExists(const std::string& dir_path) = 0;
|
||||
|
||||
// Store in *result the names of the children of the specified directory.
|
||||
// The names are relative to "dir".
|
||||
// Original contents of *results are dropped.
|
||||
@ -216,6 +220,9 @@ class LEVELDB_EXPORT Env {
|
||||
|
||||
// Sleep/delay the thread for the prescribed number of micro-seconds.
|
||||
virtual void SleepForMicroseconds(int micros) = 0;
|
||||
|
||||
// Create folder with specified subfolders recursively
|
||||
virtual Status CreateDirIteratively(const std::string& path) = 0;
|
||||
};
|
||||
|
||||
// A file abstraction for reading sequentially through a file
|
||||
@ -358,6 +365,9 @@ class LEVELDB_EXPORT EnvWrapper : public Env {
|
||||
bool FileExists(const std::string& f) override {
|
||||
return target_->FileExists(f);
|
||||
}
|
||||
bool DirectoryExists(const std::string& d) override {
|
||||
return target_->DirectoryExists(d);
|
||||
}
|
||||
Status GetChildren(const std::string& dir,
|
||||
std::vector<std::string>* r) override {
|
||||
return target_->GetChildren(dir, r);
|
||||
@ -368,6 +378,9 @@ class LEVELDB_EXPORT EnvWrapper : public Env {
|
||||
Status CreateDir(const std::string& d) override {
|
||||
return target_->CreateDir(d);
|
||||
}
|
||||
Status CreateDirIteratively(const std::string& d) override {
|
||||
return target_->CreateDirIteratively(d);
|
||||
}
|
||||
Status RemoveDir(const std::string& d) override {
|
||||
return target_->RemoveDir(d);
|
||||
}
|
||||
|
41
util/dir_helper.h
Normal file
41
util/dir_helper.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef STORAGE_LEVELDB_UTIL_DIR_HELPER_H_
|
||||
#define STORAGE_LEVELDB_UTIL_DIR_HELPER_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
inline bool IsAbsolute(const std::string& dirpath) {
|
||||
return (
|
||||
dirpath.size() >= 3 &&
|
||||
(std::toupper(dirpath[0]) >= 'A' && std::toupper(dirpath[0]) <= 'Z') &&
|
||||
dirpath[1] == ':');
|
||||
}
|
||||
|
||||
inline bool IsDirectorySeparator(const char c) {
|
||||
return (c == '/' || c == '\\');
|
||||
}
|
||||
|
||||
inline std::string GetNormalizedDirectoryPath(const std::string& dirpath) {
|
||||
std::string path = dirpath;
|
||||
size_t remove_pos = 0;
|
||||
|
||||
if (!IsAbsolute(path)) {
|
||||
remove_pos = path.find_first_not_of(".\\/");
|
||||
if (remove_pos != std::string::npos) {
|
||||
path.erase(0, remove_pos);
|
||||
}
|
||||
}
|
||||
if (IsDirectorySeparator(path[path.size() - 1])) {
|
||||
remove_pos = path.find_last_not_of(".\\/");
|
||||
if (remove_pos != std::string::npos) {
|
||||
path.erase(remove_pos + 1);
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
#endif
|
@ -23,6 +23,7 @@
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stack>
|
||||
|
||||
#include "leveldb/env.h"
|
||||
#include "leveldb/slice.h"
|
||||
@ -492,6 +493,11 @@ class WindowsEnv : public Env {
|
||||
return GetFileAttributesA(filename.c_str()) != INVALID_FILE_ATTRIBUTES;
|
||||
}
|
||||
|
||||
bool DirectoryExists(const std::string& dir_path) override {
|
||||
DWORD attrs = GetFileAttributesA(dir_path.c_str());
|
||||
return attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY);
|
||||
}
|
||||
|
||||
Status GetChildren(const std::string& directory_path,
|
||||
std::vector<std::string>* result) override {
|
||||
const std::string find_pattern = directory_path + "\\*";
|
||||
@ -535,6 +541,43 @@ class WindowsEnv : public Env {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status CreateDirIteratively(const std::string& path) override {
|
||||
if (DirectoryExists(path)) {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
std::string& dirpath = GetNormalizedDirectoryPath(path);
|
||||
|
||||
std::stack<std::string> dirs;
|
||||
bool dir_exists = false;
|
||||
int root_length = IsAbsolute(dirpath) ? 2 : 0;
|
||||
int path_length = dirpath.size() - 1;
|
||||
|
||||
while (path_length >= root_length && !dir_exists) {
|
||||
std::string dir = dirpath.substr(0, path_length + 1);
|
||||
|
||||
if (!DirectoryExists(dir)) {
|
||||
dirs.push(std::move(dir));
|
||||
} else {
|
||||
dir_exists = true;
|
||||
}
|
||||
|
||||
while (path_length > root_length && !IsDirectorySeparator(dirpath[path_length])) {
|
||||
--path_length;
|
||||
}
|
||||
--path_length;
|
||||
}
|
||||
while (!dirs.empty()) {
|
||||
const std::string dir_to_create = dirs.top();
|
||||
dirs.pop();
|
||||
|
||||
if (!::CreateDirectoryA(dir_to_create.c_str(), nullptr)) {
|
||||
return WindowsError(dir_to_create, ::GetLastError());
|
||||
}
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status RemoveDir(const std::string& dirname) override {
|
||||
if (!::RemoveDirectoryA(dirname.c_str())) {
|
||||
return WindowsError(dirname, ::GetLastError());
|
||||
|
Loading…
Reference in New Issue
Block a user