Skip to content

Commit

Permalink
leveldb::DestroyDB will now delete empty directories.
Browse files Browse the repository at this point in the history
Env's that filtered out dot files ("." and "..") would return an
empty vector of children causing DestroyDB to do nothing. This fixes
#215

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=172501335
  • Loading branch information
cmumford authored and pwnall committed Nov 3, 2017
1 parent 23162ca commit 0509414
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 4 deletions.
8 changes: 4 additions & 4 deletions db/db_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1537,15 +1537,15 @@ Snapshot::~Snapshot() {
Status DestroyDB(const std::string& dbname, const Options& options) {
Env* env = options.env;
std::vector<std::string> filenames;
// Ignore error in case directory does not exist
env->GetChildren(dbname, &filenames);
if (filenames.empty()) {
Status result = env->GetChildren(dbname, &filenames);
if (!result.ok()) {
// Ignore error in case directory does not exist
return Status::OK();
}

FileLock* lock;
const std::string lockname = LockFileName(dbname);
Status result = env->LockFile(lockname, &lock);
result = env->LockFile(lockname, &lock);
if (result.ok()) {
uint64_t number;
FileType type;
Expand Down
82 changes: 82 additions & 0 deletions db/db_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
class SpecialEnv : public EnvWrapper {
public:
Expand Down Expand Up @@ -1561,6 +1591,58 @@ TEST(DBTest, DBOpen_Options) {
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) {
DB* db2 = NULL;
Status s = DB::Open(CurrentOptions(), dbname_, &db2);
Expand Down
3 changes: 3 additions & 0 deletions include/leveldb/db.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ class LEVELDB_EXPORT DB {

// Destroy the contents of the specified database.
// 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,
const Options& options);

Expand Down

0 comments on commit 0509414

Please sign in to comment.