1
0
mirror of https://github.com/google/leveldb.git synced 2025-04-25 14:00:27 +08:00
This commit is contained in:
payemo 2025-02-06 19:42:12 +08:00 committed by GitHub
commit 45662f3b9b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 233 additions and 5 deletions

View File

@ -37,6 +37,8 @@
namespace leveldb {
using namespace path;
const int kNumNonTableCacheFiles = 10;
// Information kept for every waiting writer
@ -125,13 +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),
table_cache_(new TableCache(dbname_, options_, TableCacheSize(options_))),
db_lock_(nullptr),
shutting_down_(false),

View File

@ -17,9 +17,12 @@
#include "leveldb/env.h"
#include "port/port.h"
#include "port/thread_annotations.h"
#include "leveldb/db_path.h"
namespace leveldb {
using namespace path;
class MemTable;
class TableCache;
class Version;
@ -157,12 +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_;
const std::string dbname_;
// table_cache_ provides its own synchronization
TableCache* const table_cache_;

34
include/leveldb/db_path.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef STORAGE_LEVELDB_INCLUDE_DB_PATH_H_
#define STORAGE_LEVELDB_INCLUDE_DB_PATH_H_
#include <cstdint>
#include <string>
namespace leveldb {
namespace path {
const char kDirectorySeparator = '\\';
const char kAltDirecttorySeparator = '/';
const char kVolumeSeparatorChar = ':';
bool IsAbsolute(const std::string& path);
bool IsRelative(const std::string& path);
size_t RootLength(const std::string& path);
const std::string& GetRootDirectory(const std::string& path);
std::string Normalize(const std::string& path);
bool IsDirectorySeparator(const char c);
static bool IsValidDriveChar(const char c);
static bool StartsWith(const std::string& path, const std::string& search, bool ignore_case = false);
} // namespace path
} // namespace leveldb
#endif // STORAGE_LEVELDB_INCLUDE_DB_PATH_H_

View File

@ -20,6 +20,7 @@
#include "leveldb/export.h"
#include "leveldb/status.h"
#include "leveldb/db_path.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 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.
// The names are relative to "dir".
// Original contents of *results are dropped.
@ -358,6 +362,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);

135
util/db_path.cc Normal file
View File

@ -0,0 +1,135 @@
#include "leveldb/db_path.h"
namespace leveldb {
namespace path {
#ifdef LEVELDB_PLATFORM_WINDOWS
const char* kExtendedPathPrefix = "\\\\?\\";
const char* kUncExtendedPathPrefix = "\\\\?\\UNC\\";
bool IsValidDriveChar(const char c) {
const char drive_char = std::toupper(c);
return drive_char >= 'A' && drive_char <= 'Z';
}
#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(path, std::string(kExtendedPathPrefix));
bool extended_unc_syntax = StartsWith(path, std::string(kUncExtendedPathPrefix));
if (extended_syntax) {
if (extended_unc_syntax) {
unc_root_length = std::strlen(kUncExtendedPathPrefix);
} else {
volume_separator_length += std::strlen(kExtendedPathPrefix);
}
}
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]))) {
root_length = unc_root_length;
int n = 2; // maximum separators to skip
while (root_length < path_length &&
(!IsDirectorySeparator(path[root_length]) || --n > 0)) {
++root_length;
}
}
} else if (path_length >= volume_separator_length &&
path[volume_separator_length - 1] == kVolumeSeparatorChar) {
root_length = volume_separator_length;
if (path_length >= volume_separator_length &&
IsDirectorySeparator(path[volume_separator_length])) {
++root_length;
}
}
return root_length;
}
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());
}
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;
path_it++;
} else if (path_it == path.begin() ||
!IsDirectorySeparator(*std::prev(path_it))) {
out += kDirectorySeparator;
path_it++;
} else {
continue;
}
}
return out;
}
} // namespace path
} // namespace leveldb

View File

@ -37,6 +37,8 @@ namespace leveldb {
namespace {
using namespace path;
constexpr const size_t kWritableFileBufferSize = 65536;
// 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;
}
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 + "\\*";
@ -529,9 +536,49 @@ class WindowsEnv : public Env {
}
Status CreateDir(const std::string& dirname) override {
if (!::CreateDirectoryA(dirname.c_str(), nullptr)) {
return WindowsError(dirname, ::GetLastError());
size_t path_length = dirname.size();
if (path_length >= 2 && path::IsDirectorySeparator(dirname[path_length - 1])) {
--path_length;
}
if (DirectoryExists(dirname)) {
return Status::OK();
}
std::vector<std::string> stackDir;
bool path_exists = false;
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 = dirname.substr(0, i + 1);
if (!DirectoryExists(dir)) {
stackDir.push_back(dir);
} else {
path_exists = true;
}
while (i > root_length && dirname[i] != path::kDirectorySeparator && dirname[i] != path::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();
}