Reimplement path manipulation functionality in a more static way and extend CreateDir function to deal with dir's hierarchy

This commit is contained in:
payemo 2023-04-27 00:38:09 +03:00
parent aeebb3c17f
commit c82ca583c6
6 changed files with 108 additions and 165 deletions

View File

@ -127,14 +127,13 @@ static int TableCacheSize(const Options& sanitized_options) {
DBImpl::DBImpl(const Options& raw_options, const std::string& dbname)
: env_(raw_options.env),
dbname_(path::Normalize(dbname)),
internal_comparator_(raw_options.comparator),
internal_filter_policy_(raw_options.filter_policy),
options_(SanitizeOptions(dbname, &internal_comparator_,
options_(SanitizeOptions(dbname_, &internal_comparator_,
&internal_filter_policy_, raw_options)),
owns_info_log_(options_.info_log != raw_options.info_log),
owns_cache_(options_.block_cache != raw_options.block_cache),
dbname_(dbname),
path_(PathFactory::Create(dbname)),
table_cache_(new TableCache(dbname_, options_, TableCacheSize(options_))),
db_lock_(nullptr),
shutting_down_(false),
@ -179,9 +178,6 @@ DBImpl::~DBImpl() {
if (owns_cache_) {
delete options_.block_cache;
}
if (path_) {
delete path_;
}
}
Status DBImpl::NewDB() {
@ -301,7 +297,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(path_->ToString());
env_->CreateDir(dbname_);
assert(db_lock_ == nullptr);
Status s = env_->LockFile(LockFileName(dbname_), &db_lock_);
if (!s.ok()) {

View File

@ -160,14 +160,12 @@ class DBImpl : public DB {
// Constant after construction
Env* const env_;
const std::string dbname_;
const InternalKeyComparator internal_comparator_;
const InternalFilterPolicy internal_filter_policy_;
const Options options_; // options_.comparator == &internal_comparator_
const bool owns_info_log_;
const bool owns_cache_;
// TODO: replace with Path;
const std::string dbname_;
DbPath* const path_;
// table_cache_ provides its own synchronization
TableCache* const table_cache_;

View File

@ -8,77 +8,25 @@ namespace leveldb {
namespace path {
class DbPath {
public:
// Constants
static const char kDirectorySeparator = '\\';
static const char kAltDirecttorySeparator = '/';
static const char kVolumeSeparatorChar = ':';
const char kDirectorySeparator = '\\';
const char kAltDirecttorySeparator = '/';
const char kVolumeSeparatorChar = ':';
virtual ~DbPath() {}
bool IsAbsolute(const std::string& path);
const std::string& ToString() const { return path_; }
const char* ToCString() const { return path_.c_str(); }
bool IsRelative(const std::string& path);
const char operator[](size_t i) const { return path_[i]; }
size_t RootLength(const std::string& path);
static bool IsDirectorySeparator(const char c);
const std::string& GetRootDirectory(const std::string& path);
virtual bool IsAbsolute() const = 0;
virtual bool IsRelative() const = 0;
virtual size_t RootLength() const = 0;
std::string Normalize(const std::string& path);
inline size_t Size() const { return path_.size(); }
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());
}
bool IsDirectorySeparator(const char c);
protected:
DbPath() : path_("") {}
DbPath(const std::string& path) : path_(path) {}
static bool IsValidDriveChar(const char c);
virtual void Normalize() = 0;
bool StartsWith(const std::string& value, bool ignore_case = false) const;
std::string path_;
};
// Win path
class WindowsDbPath : public DbPath {
public:
explicit WindowsDbPath(const std::string& path) : DbPath(path) {
Normalize();
}
~WindowsDbPath() {}
bool IsAbsolute() const override;
bool IsRelative() const override;
size_t RootLength() const override;
protected:
static bool IsValidDriveChar(const char c);
void Normalize() override;
private:
const char* kExtendedPathPrefix = "\\\\?\\";
const char* kUncExtendedPathPrefix = "\\\\?\\UNC\\";
};
// Factory
class PathFactory {
public:
PathFactory() = delete;
~PathFactory() = delete;
static DbPath* Create(const std::string& path);
};
static bool StartsWith(const std::string& path, const std::string& search, bool ignore_case = false);
} // namespace path
} // namespace leveldb

View File

@ -145,8 +145,6 @@ class LEVELDB_EXPORT Env {
// Create the specified directory.
virtual Status CreateDir(const std::string& dirname) = 0;
virtual Status CreateDir(const path::DbPath& dbpath) = 0;
// Delete the specified directory.
//
// The default implementation calls DeleteDir, to support legacy Env
@ -377,9 +375,6 @@ class LEVELDB_EXPORT EnvWrapper : public Env {
Status CreateDir(const std::string& d) override {
return target_->CreateDir(d);
}
Status CreateDir(const path::DbPath& d) override {
return target_->CreateDir(d);
}
Status RemoveDir(const std::string& d) override {
return target_->RemoveDir(d);
}

View File

@ -3,59 +3,65 @@
namespace leveldb {
namespace path {
bool DbPath::IsDirectorySeparator(const char c) {
return (c == DbPath::kDirectorySeparator || c == DbPath::kAltDirecttorySeparator);
}
#ifdef LEVELDB_PLATFORM_WINDOWS
bool DbPath::StartsWith(const std::string& value, bool ignore_case) const {
if (value.size() > path_.size()) {
return false;
}
if (ignore_case) {
auto ignore_case_cmp_func = [](char a, char b) { return std::tolower(a) == std::tolower(b); };
return std::equal(value.begin(), value.end(), path_.begin(), ignore_case_cmp_func);
}
return std::equal(value.begin(), value.end(), path_.begin());
}
const char* kExtendedPathPrefix = "\\\\?\\";
const char* kUncExtendedPathPrefix = "\\\\?\\UNC\\";
// Windows
bool WindowsDbPath::IsAbsolute() const {
return path_.size() >= 3 && IsValidDriveChar(path_[0]) &&
path_[1] == DbPath::kVolumeSeparatorChar;
};
bool WindowsDbPath::IsRelative() const {
if (path_.size() < 2) {
return true;
}
if (IsDirectorySeparator(path_[0])) {
if (path_[1] != '?') {
return !IsDirectorySeparator(path_[1]);
}
return false;
}
if (path_.size() >= 3 && path_[1] == DbPath::kVolumeSeparatorChar &&
IsDirectorySeparator(path_[2])) {
return IsValidDriveChar(path_[0]);
}
return true;
};
bool WindowsDbPath::IsValidDriveChar(const char c) {
bool IsValidDriveChar(const char c) {
const char drive_char = std::toupper(c);
return drive_char >= 'A' && drive_char <= 'Z';
}
size_t WindowsDbPath::RootLength() const {
size_t path_length = path_.size();
#elif LEVELDB_PLATFORM_POSIX
#endif
bool IsDirectorySeparator(const char c) {
return (c == kDirectorySeparator || c == kAltDirecttorySeparator);
}
const std::string& GetRootDirectory(const std::string& path) {
return path.substr(0, RootLength(path));
}
bool IsAbsolute(const std::string& path) {
#ifdef LEVELDB_PLATFORM_WINDOWS
return path.size() >= 3 && IsValidDriveChar(path[0]) &&
path[1] == kVolumeSeparatorChar;
#endif
}
bool IsRelative(const std::string& path) {
if (path.size() < 2) {
return true;
}
if (IsDirectorySeparator(path[0])) {
if (path[1] != '?') {
return !IsDirectorySeparator(path[1]);
}
return false;
}
if (path.size() >= 3 && path[1] == kVolumeSeparatorChar &&
IsDirectorySeparator(path[2])) {
#ifdef LEVELDB_PLATFORM_WINDOWS
return IsValidDriveChar(path[0]);
#elif LEVELDB_PLATFORM_POSIX
#endif
}
return true;
}
size_t RootLength(const std::string& path) {
size_t path_length = path.size();
size_t root_length = 0;
size_t volume_separator_length = 2;
size_t unc_root_length = 2;
bool extended_syntax = StartsWith(kExtendedPathPrefix);
bool extended_unc_syntax = StartsWith(kUncExtendedPathPrefix);
bool extended_syntax = StartsWith(path, std::string(kExtendedPathPrefix));
bool extended_unc_syntax = StartsWith(path, std::string(kUncExtendedPathPrefix));
if (extended_syntax) {
if (extended_unc_syntax) {
@ -65,22 +71,24 @@ size_t WindowsDbPath::RootLength() const {
}
}
if ((!extended_syntax || extended_unc_syntax) && path_length != 0 && IsDirectorySeparator(path_[0])) {
if ((!extended_syntax || extended_unc_syntax) && path_length != 0 &&
IsDirectorySeparator(path[0])) {
root_length = 1;
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;
int n = 2; // maximum separators to skip
while (root_length < path_length &&
(!IsDirectorySeparator(path_[root_length]) || --n > 0)) {
(!IsDirectorySeparator(path[root_length]) || --n > 0)) {
++root_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;
if (path_length >= volume_separator_length &&
IsDirectorySeparator(path_[volume_separator_length])) {
IsDirectorySeparator(path[volume_separator_length])) {
++root_length;
}
}
@ -88,34 +96,40 @@ size_t WindowsDbPath::RootLength() const {
return root_length;
}
void WindowsDbPath::Normalize() {
auto out = path_.begin();
bool StartsWith(const std::string& path, const std::string& search,
bool ignore_case) {
if (search.size() > path.size()) {
return false;
}
if (ignore_case) {
auto ignore_case_cmp_func = [](char a, char b) {
return std::tolower(a) == std::tolower(b);
};
return std::equal(search.begin(), search.end(), path.begin(),
ignore_case_cmp_func);
}
return std::equal(search.begin(), search.end(), path.begin());
}
for (const char c : path_) {
std::string Normalize(const std::string& path) {
std::string out;
auto path_it = path.begin();
for (const char c : path) {
if (!IsDirectorySeparator(c)) {
*(out++) = c;
} else if (out == path_.begin() || !IsDirectorySeparator(*std::prev(out))) {
*(out++) = kDirectorySeparator;
out += c;
path_it++;
} else if (path_it == path.begin() ||
!IsDirectorySeparator(*std::prev(path_it))) {
out += kDirectorySeparator;
path_it++;
} else {
continue;
}
}
path_.erase(out, path_.end());
return out;
}
// Windows path
DbPath* PathFactory::Create(const std::string& path) {
#ifdef LEVELDB_PLATFORM_WINDOWS
return new WindowsDbPath(path);
#elif LEVELDB_PLATFORM_POSIX
return nullptr;
#endif
return nullptr;
}
}
}
} // namespace path
} // namespace leveldb

View File

@ -536,41 +536,33 @@ class WindowsEnv : public Env {
}
Status CreateDir(const std::string& dirname) override {
if (!::CreateDirectoryA(dirname.c_str(), nullptr)) {
return WindowsError(dirname, ::GetLastError());
}
return Status::OK();
}
size_t path_length = dirname.size();
Status CreateDir(const DbPath& dirpath) override {
size_t path_length = dirpath.Size();
if (path_length >= 2 && DbPath::IsDirectorySeparator(dirpath[path_length - 1])) {
if (path_length >= 2 && path::IsDirectorySeparator(dirname[path_length - 1])) {
--path_length;
}
if (DirectoryExists(dirpath.ToString())) {
if (DirectoryExists(dirname)) {
return Status::OK();
}
std::vector<std::string> stackDir;
bool path_exists = false;
size_t root_length = dirpath.RootLength();
size_t root_length = path::RootLength(dirname);
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);
const std::string dir = dirname.substr(0, i + 1);
if (!DirectoryExists(dir)) {
stackDir.push_back(dir);
}
else {
} else {
path_exists = true;
}
while (i > root_length && dirpath[i] != DbPath::kDirectorySeparator && dirpath[i] != DbPath::kAltDirecttorySeparator)
while (i > root_length && dirname[i] != path::kDirectorySeparator && dirname[i] != path::kAltDirecttorySeparator)
--i;
--i;
}