leveldb::DestroyDB will now delete empty directories.
Env's that filtered out dot files ("." and "..") would return an empty vector of children causing DestroyDB to do nothing. This fixes https://github.com/google/leveldb/issues/215 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=172501335
This commit is contained in:
parent
23162ca1c6
commit
0509414f85
@ -1537,15 +1537,15 @@ Snapshot::~Snapshot() {
|
|||||||
Status DestroyDB(const std::string& dbname, const Options& options) {
|
Status DestroyDB(const std::string& dbname, const Options& options) {
|
||||||
Env* env = options.env;
|
Env* env = options.env;
|
||||||
std::vector<std::string> filenames;
|
std::vector<std::string> filenames;
|
||||||
// Ignore error in case directory does not exist
|
Status result = env->GetChildren(dbname, &filenames);
|
||||||
env->GetChildren(dbname, &filenames);
|
if (!result.ok()) {
|
||||||
if (filenames.empty()) {
|
// Ignore error in case directory does not exist
|
||||||
return Status::OK();
|
return Status::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
FileLock* lock;
|
FileLock* lock;
|
||||||
const std::string lockname = LockFileName(dbname);
|
const std::string lockname = LockFileName(dbname);
|
||||||
Status result = env->LockFile(lockname, &lock);
|
result = env->LockFile(lockname, &lock);
|
||||||
if (result.ok()) {
|
if (result.ok()) {
|
||||||
uint64_t number;
|
uint64_t number;
|
||||||
FileType type;
|
FileType type;
|
||||||
|
@ -61,6 +61,36 @@ void DelayMilliseconds(int millis) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test Env to override default Env behavior for testing.
|
||||||
|
class TestEnv : public EnvWrapper {
|
||||||
|
public:
|
||||||
|
explicit TestEnv(Env* base) : EnvWrapper(base), ignore_dot_files_(false) {}
|
||||||
|
|
||||||
|
void SetIgnoreDotFiles(bool ignored) { ignore_dot_files_ = ignored; }
|
||||||
|
|
||||||
|
Status GetChildren(const std::string& dir,
|
||||||
|
std::vector<std::string>* result) override {
|
||||||
|
Status s = target()->GetChildren(dir, result);
|
||||||
|
if (!s.ok() || !ignore_dot_files_) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string>::iterator it = result->begin();
|
||||||
|
while (it != result->end()) {
|
||||||
|
if ((*it == ".") || (*it == "..")) {
|
||||||
|
it = result->erase(it);
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool ignore_dot_files_;
|
||||||
|
};
|
||||||
|
|
||||||
// Special Env used to delay background operations
|
// Special Env used to delay background operations
|
||||||
class SpecialEnv : public EnvWrapper {
|
class SpecialEnv : public EnvWrapper {
|
||||||
public:
|
public:
|
||||||
@ -1561,6 +1591,58 @@ TEST(DBTest, DBOpen_Options) {
|
|||||||
db = NULL;
|
db = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(DBTest, DestroyEmptyDir) {
|
||||||
|
std::string dbname = test::TmpDir() + "/db_empty_dir";
|
||||||
|
TestEnv env(Env::Default());
|
||||||
|
env.DeleteDir(dbname);
|
||||||
|
ASSERT_TRUE(!env.FileExists(dbname));
|
||||||
|
|
||||||
|
Options opts;
|
||||||
|
opts.env = &env;
|
||||||
|
|
||||||
|
ASSERT_OK(env.CreateDir(dbname));
|
||||||
|
ASSERT_TRUE(env.FileExists(dbname));
|
||||||
|
std::vector<std::string> children;
|
||||||
|
ASSERT_OK(env.GetChildren(dbname, &children));
|
||||||
|
// The POSIX env does not filter out '.' and '..' special files.
|
||||||
|
ASSERT_EQ(2, children.size());
|
||||||
|
ASSERT_OK(DestroyDB(dbname, opts));
|
||||||
|
ASSERT_TRUE(!env.FileExists(dbname));
|
||||||
|
|
||||||
|
// Should also be destroyed if Env is filtering out dot files.
|
||||||
|
env.SetIgnoreDotFiles(true);
|
||||||
|
ASSERT_OK(env.CreateDir(dbname));
|
||||||
|
ASSERT_TRUE(env.FileExists(dbname));
|
||||||
|
ASSERT_OK(env.GetChildren(dbname, &children));
|
||||||
|
ASSERT_EQ(0, children.size());
|
||||||
|
ASSERT_OK(DestroyDB(dbname, opts));
|
||||||
|
ASSERT_TRUE(!env.FileExists(dbname));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DBTest, DestroyOpenDB) {
|
||||||
|
std::string dbname = test::TmpDir() + "/open_db_dir";
|
||||||
|
env_->DeleteDir(dbname);
|
||||||
|
ASSERT_TRUE(!env_->FileExists(dbname));
|
||||||
|
|
||||||
|
Options opts;
|
||||||
|
opts.create_if_missing = true;
|
||||||
|
DB* db = NULL;
|
||||||
|
ASSERT_OK(DB::Open(opts, dbname, &db));
|
||||||
|
ASSERT_TRUE(db != NULL);
|
||||||
|
|
||||||
|
// Must fail to destroy an open db.
|
||||||
|
ASSERT_TRUE(env_->FileExists(dbname));
|
||||||
|
ASSERT_TRUE(!DestroyDB(dbname, Options()).ok());
|
||||||
|
ASSERT_TRUE(env_->FileExists(dbname));
|
||||||
|
|
||||||
|
delete db;
|
||||||
|
db = NULL;
|
||||||
|
|
||||||
|
// Should succeed destroying a closed db.
|
||||||
|
ASSERT_OK(DestroyDB(dbname, Options()));
|
||||||
|
ASSERT_TRUE(!env_->FileExists(dbname));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(DBTest, Locking) {
|
TEST(DBTest, Locking) {
|
||||||
DB* db2 = NULL;
|
DB* db2 = NULL;
|
||||||
Status s = DB::Open(CurrentOptions(), dbname_, &db2);
|
Status s = DB::Open(CurrentOptions(), dbname_, &db2);
|
||||||
|
@ -151,6 +151,9 @@ class LEVELDB_EXPORT DB {
|
|||||||
|
|
||||||
// Destroy the contents of the specified database.
|
// Destroy the contents of the specified database.
|
||||||
// Be very careful using this method.
|
// Be very careful using this method.
|
||||||
|
//
|
||||||
|
// Note: For backwards compatibility, if DestroyDB is unable to list the
|
||||||
|
// database files, Status::OK() will still be returned masking this failure.
|
||||||
LEVELDB_EXPORT Status DestroyDB(const std::string& name,
|
LEVELDB_EXPORT Status DestroyDB(const std::string& name,
|
||||||
const Options& options);
|
const Options& options);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user