Implement multiple directories creation
This commit is contained in:
parent
2df36b103d
commit
aeebb3c17f
@ -179,7 +179,7 @@ DBImpl::~DBImpl() {
|
|||||||
if (owns_cache_) {
|
if (owns_cache_) {
|
||||||
delete options_.block_cache;
|
delete options_.block_cache;
|
||||||
}
|
}
|
||||||
if (path_ != nullptr) {
|
if (path_) {
|
||||||
delete path_;
|
delete path_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -301,7 +301,7 @@ Status DBImpl::Recover(VersionEdit* edit, bool* save_manifest) {
|
|||||||
// Ignore error from CreateDir since the creation of the DB is
|
// Ignore error from CreateDir since the creation of the DB is
|
||||||
// committed only when the descriptor is created, and this directory
|
// committed only when the descriptor is created, and this directory
|
||||||
// may already exist from a previous failed creation attempt.
|
// may already exist from a previous failed creation attempt.
|
||||||
env_->CreateDir(path_->Name());
|
env_->CreateDir(path_->ToString());
|
||||||
assert(db_lock_ == nullptr);
|
assert(db_lock_ == nullptr);
|
||||||
Status s = env_->LockFile(LockFileName(dbname_), &db_lock_);
|
Status s = env_->LockFile(LockFileName(dbname_), &db_lock_);
|
||||||
if (!s.ok()) {
|
if (!s.ok()) {
|
||||||
|
@ -17,28 +17,35 @@ public:
|
|||||||
|
|
||||||
virtual ~DbPath() {}
|
virtual ~DbPath() {}
|
||||||
|
|
||||||
const std::string& Name() const { return path_; }
|
const std::string& ToString() const { return path_; }
|
||||||
const char* CName() const { return path_.c_str(); }
|
const char* ToCString() const { return path_.c_str(); }
|
||||||
|
|
||||||
|
const char operator[](size_t i) const { return path_[i]; }
|
||||||
|
|
||||||
|
static bool IsDirectorySeparator(const char c);
|
||||||
|
|
||||||
virtual bool IsAbsolute() const = 0;
|
virtual bool IsAbsolute() const = 0;
|
||||||
virtual bool IsRelative() const = 0;
|
virtual bool IsRelative() const = 0;
|
||||||
virtual size_t RootLength() = 0;
|
virtual size_t RootLength() const = 0;
|
||||||
|
|
||||||
inline size_t Size() const { return path_.size(); }
|
inline size_t Size() const { return path_.size(); }
|
||||||
inline bool IsEmpty() const { return path_.empty(); }
|
inline bool IsEmpty() const { return path_.empty(); }
|
||||||
|
inline const std::string Substring(size_t from, size_t to) const {
|
||||||
|
return path_.substr(from, to);
|
||||||
|
}
|
||||||
|
inline const std::string GetRootDirectory() const {
|
||||||
|
return path_.substr(0, RootLength());
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
DbPath() : path_("") {}
|
DbPath() : path_("") {}
|
||||||
DbPath(const std::string& path) : path_(path) {}
|
DbPath(const std::string& path) : path_(path) {}
|
||||||
|
|
||||||
std::string path_;
|
|
||||||
|
|
||||||
static bool IsDirectorySeparator(const char c);
|
|
||||||
|
|
||||||
bool StartsWith(const std::string& value, bool ignore_case = false);
|
|
||||||
|
|
||||||
virtual void Normalize() = 0;
|
virtual void Normalize() = 0;
|
||||||
|
|
||||||
|
bool StartsWith(const std::string& value, bool ignore_case = false) const;
|
||||||
|
|
||||||
|
std::string path_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Win path
|
// Win path
|
||||||
@ -51,8 +58,7 @@ public:
|
|||||||
|
|
||||||
bool IsAbsolute() const override;
|
bool IsAbsolute() const override;
|
||||||
bool IsRelative() const override;
|
bool IsRelative() const override;
|
||||||
|
size_t RootLength() const override;
|
||||||
size_t RootLength() override;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static bool IsValidDriveChar(const char c);
|
static bool IsValidDriveChar(const char c);
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "leveldb/export.h"
|
#include "leveldb/export.h"
|
||||||
#include "leveldb/status.h"
|
#include "leveldb/status.h"
|
||||||
|
#include "leveldb/db_path.h"
|
||||||
|
|
||||||
// This workaround can be removed when leveldb::Env::DeleteFile is removed.
|
// This workaround can be removed when leveldb::Env::DeleteFile is removed.
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
@ -113,6 +114,9 @@ class LEVELDB_EXPORT Env {
|
|||||||
// Returns true iff the named file exists.
|
// Returns true iff the named file exists.
|
||||||
virtual bool FileExists(const std::string& fname) = 0;
|
virtual bool FileExists(const std::string& fname) = 0;
|
||||||
|
|
||||||
|
// Returns true if the input directory path exists.
|
||||||
|
virtual bool DirectoryExists(const std::string& dirname) = 0;
|
||||||
|
|
||||||
// Store in *result the names of the children of the specified directory.
|
// Store in *result the names of the children of the specified directory.
|
||||||
// The names are relative to "dir".
|
// The names are relative to "dir".
|
||||||
// Original contents of *results are dropped.
|
// Original contents of *results are dropped.
|
||||||
@ -141,6 +145,8 @@ class LEVELDB_EXPORT Env {
|
|||||||
// Create the specified directory.
|
// Create the specified directory.
|
||||||
virtual Status CreateDir(const std::string& dirname) = 0;
|
virtual Status CreateDir(const std::string& dirname) = 0;
|
||||||
|
|
||||||
|
virtual Status CreateDir(const path::DbPath& dbpath) = 0;
|
||||||
|
|
||||||
// Delete the specified directory.
|
// Delete the specified directory.
|
||||||
//
|
//
|
||||||
// The default implementation calls DeleteDir, to support legacy Env
|
// The default implementation calls DeleteDir, to support legacy Env
|
||||||
@ -358,6 +364,9 @@ class LEVELDB_EXPORT EnvWrapper : public Env {
|
|||||||
bool FileExists(const std::string& f) override {
|
bool FileExists(const std::string& f) override {
|
||||||
return target_->FileExists(f);
|
return target_->FileExists(f);
|
||||||
}
|
}
|
||||||
|
bool DirectoryExists(const std::string& d) override {
|
||||||
|
return target_->DirectoryExists(d);
|
||||||
|
}
|
||||||
Status GetChildren(const std::string& dir,
|
Status GetChildren(const std::string& dir,
|
||||||
std::vector<std::string>* r) override {
|
std::vector<std::string>* r) override {
|
||||||
return target_->GetChildren(dir, r);
|
return target_->GetChildren(dir, r);
|
||||||
@ -368,6 +377,9 @@ class LEVELDB_EXPORT EnvWrapper : public Env {
|
|||||||
Status CreateDir(const std::string& d) override {
|
Status CreateDir(const std::string& d) override {
|
||||||
return target_->CreateDir(d);
|
return target_->CreateDir(d);
|
||||||
}
|
}
|
||||||
|
Status CreateDir(const path::DbPath& d) override {
|
||||||
|
return target_->CreateDir(d);
|
||||||
|
}
|
||||||
Status RemoveDir(const std::string& d) override {
|
Status RemoveDir(const std::string& d) override {
|
||||||
return target_->RemoveDir(d);
|
return target_->RemoveDir(d);
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ bool DbPath::IsDirectorySeparator(const char c) {
|
|||||||
return (c == DbPath::kDirectorySeparator || c == DbPath::kAltDirecttorySeparator);
|
return (c == DbPath::kDirectorySeparator || c == DbPath::kAltDirecttorySeparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DbPath::StartsWith(const std::string& value, bool ignore_case) {
|
bool DbPath::StartsWith(const std::string& value, bool ignore_case) const {
|
||||||
if (value.size() > path_.size()) {
|
if (value.size() > path_.size()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -43,30 +43,12 @@ bool WindowsDbPath::IsRelative() const {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
void WindowsDbPath::Normalize() {
|
|
||||||
auto out = path_.begin();
|
|
||||||
|
|
||||||
for (const char c : path_) {
|
|
||||||
if (!IsDirectorySeparator(c)) {
|
|
||||||
*(out++) = c;
|
|
||||||
}
|
|
||||||
else if (out == path_.begin() || !IsDirectorySeparator(*std::prev(out))) {
|
|
||||||
*(out++) = kDirectorySeparator;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
path_.erase(out, path_.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WindowsDbPath::IsValidDriveChar(const char c) {
|
bool WindowsDbPath::IsValidDriveChar(const char c) {
|
||||||
const char drive_char = std::toupper(c);
|
const char drive_char = std::toupper(c);
|
||||||
return drive_char >= 'A' && drive_char <= 'Z';
|
return drive_char >= 'A' && drive_char <= 'Z';
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t WindowsDbPath::RootLength() {
|
size_t WindowsDbPath::RootLength() const {
|
||||||
size_t path_length = path_.size();
|
size_t path_length = path_.size();
|
||||||
size_t root_length = 0;
|
size_t root_length = 0;
|
||||||
size_t volume_separator_length = 2;
|
size_t volume_separator_length = 2;
|
||||||
@ -78,8 +60,7 @@ size_t WindowsDbPath::RootLength() {
|
|||||||
if (extended_syntax) {
|
if (extended_syntax) {
|
||||||
if (extended_unc_syntax) {
|
if (extended_unc_syntax) {
|
||||||
unc_root_length = std::strlen(kUncExtendedPathPrefix);
|
unc_root_length = std::strlen(kUncExtendedPathPrefix);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
volume_separator_length += std::strlen(kExtendedPathPrefix);
|
volume_separator_length += std::strlen(kExtendedPathPrefix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -89,15 +70,17 @@ size_t WindowsDbPath::RootLength() {
|
|||||||
|
|
||||||
if (extended_unc_syntax || (path_length > 1 && IsDirectorySeparator(path_[1]))) {
|
if (extended_unc_syntax || (path_length > 1 && IsDirectorySeparator(path_[1]))) {
|
||||||
root_length = unc_root_length;
|
root_length = unc_root_length;
|
||||||
int n = 2; // maximum separators to skip
|
int n = 2; // maximum separators to skip
|
||||||
while (root_length < path_length && (!IsDirectorySeparator(path_[root_length]) || --n > 0)) {
|
while (root_length < path_length &&
|
||||||
|
(!IsDirectorySeparator(path_[root_length]) || --n > 0)) {
|
||||||
++root_length;
|
++root_length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else if (path_length >= volume_separator_length &&
|
||||||
else if (path_length >= volume_separator_length && path_[volume_separator_length - 1] == kVolumeSeparatorChar) {
|
path_[volume_separator_length - 1] == kVolumeSeparatorChar) {
|
||||||
root_length = volume_separator_length;
|
root_length = volume_separator_length;
|
||||||
if (path_length >= volume_separator_length && IsDirectorySeparator(path_[volume_separator_length])) {
|
if (path_length >= volume_separator_length &&
|
||||||
|
IsDirectorySeparator(path_[volume_separator_length])) {
|
||||||
++root_length;
|
++root_length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,6 +88,22 @@ size_t WindowsDbPath::RootLength() {
|
|||||||
return root_length;
|
return root_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WindowsDbPath::Normalize() {
|
||||||
|
auto out = path_.begin();
|
||||||
|
|
||||||
|
for (const char c : path_) {
|
||||||
|
if (!IsDirectorySeparator(c)) {
|
||||||
|
*(out++) = c;
|
||||||
|
} else if (out == path_.begin() || !IsDirectorySeparator(*std::prev(out))) {
|
||||||
|
*(out++) = kDirectorySeparator;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
path_.erase(out, path_.end());
|
||||||
|
}
|
||||||
|
|
||||||
// Windows path
|
// Windows path
|
||||||
|
|
||||||
DbPath* PathFactory::Create(const std::string& path) {
|
DbPath* PathFactory::Create(const std::string& path) {
|
||||||
|
@ -37,6 +37,8 @@ namespace leveldb {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
using namespace path;
|
||||||
|
|
||||||
constexpr const size_t kWritableFileBufferSize = 65536;
|
constexpr const size_t kWritableFileBufferSize = 65536;
|
||||||
|
|
||||||
// Up to 1000 mmaps for 64-bit binaries; none for 32-bit.
|
// Up to 1000 mmaps for 64-bit binaries; none for 32-bit.
|
||||||
@ -492,6 +494,11 @@ class WindowsEnv : public Env {
|
|||||||
return GetFileAttributesA(filename.c_str()) != INVALID_FILE_ATTRIBUTES;
|
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,
|
Status GetChildren(const std::string& directory_path,
|
||||||
std::vector<std::string>* result) override {
|
std::vector<std::string>* result) override {
|
||||||
const std::string find_pattern = directory_path + "\\*";
|
const std::string find_pattern = directory_path + "\\*";
|
||||||
@ -535,6 +542,54 @@ class WindowsEnv : public Env {
|
|||||||
return Status::OK();
|
return Status::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Status CreateDir(const DbPath& dirpath) override {
|
||||||
|
size_t path_length = dirpath.Size();
|
||||||
|
|
||||||
|
if (path_length >= 2 && DbPath::IsDirectorySeparator(dirpath[path_length - 1])) {
|
||||||
|
--path_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DirectoryExists(dirpath.ToString())) {
|
||||||
|
return Status::OK();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> stackDir;
|
||||||
|
bool path_exists = false;
|
||||||
|
size_t root_length = dirpath.RootLength();
|
||||||
|
|
||||||
|
if (path_length > root_length) { // Special case root (fullpath = X:\\)
|
||||||
|
size_t i = path_length - 1;
|
||||||
|
|
||||||
|
while (i >= root_length && !path_exists) {
|
||||||
|
const std::string dir = dirpath.Substring(0, i + 1);
|
||||||
|
|
||||||
|
if (!DirectoryExists(dir)) {
|
||||||
|
stackDir.push_back(dir);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
path_exists = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i > root_length && dirpath[i] != DbPath::kDirectorySeparator && dirpath[i] != DbPath::kAltDirecttorySeparator)
|
||||||
|
--i;
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!stackDir.empty()) {
|
||||||
|
const std::string dir = stackDir[stackDir.size() - 1];
|
||||||
|
stackDir.pop_back();
|
||||||
|
|
||||||
|
if (!DirectoryExists(dir)) {
|
||||||
|
if (!::CreateDirectoryA(dir.c_str(), nullptr)) {
|
||||||
|
return WindowsError(dir, ::GetLastError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status::OK();
|
||||||
|
}
|
||||||
|
|
||||||
Status RemoveDir(const std::string& dirname) override {
|
Status RemoveDir(const std::string& dirname) override {
|
||||||
if (!::RemoveDirectoryA(dirname.c_str())) {
|
if (!::RemoveDirectoryA(dirname.c_str())) {
|
||||||
return WindowsError(dirname, ::GetLastError());
|
return WindowsError(dirname, ::GetLastError());
|
||||||
|
Loading…
Reference in New Issue
Block a user