Remove the force mode for EnableFileDeletions API (#12337)

Summary:
There is no strong reason for user to need this mode while on the other hand, its behavior is destructive.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/12337

Reviewed By: hx235

Differential Revision: D53630393

Pulled By: jowlyzhang

fbshipit-source-id: ce94b537258102cd98f89aa4090025663664dd78
This commit is contained in:
Yu Zhang 2024-02-13 18:36:25 -08:00 committed by Facebook GitHub Bot
parent 8c7c0a38f1
commit 4bea83aa44
27 changed files with 79 additions and 105 deletions

View File

@ -1874,9 +1874,8 @@ void rocksdb_disable_file_deletions(rocksdb_t* db, char** errptr) {
SaveError(errptr, db->rep->DisableFileDeletions()); SaveError(errptr, db->rep->DisableFileDeletions());
} }
void rocksdb_enable_file_deletions(rocksdb_t* db, unsigned char force, void rocksdb_enable_file_deletions(rocksdb_t* db, char** errptr) {
char** errptr) { SaveError(errptr, db->rep->EnableFileDeletions());
SaveError(errptr, db->rep->EnableFileDeletions(force));
} }
void rocksdb_destroy_db(const rocksdb_options_t* options, const char* name, void rocksdb_destroy_db(const rocksdb_options_t* options, const char* name,

View File

@ -121,7 +121,7 @@ Status DBImpl::GetSortedWalFiles(VectorLogPtr& files) {
// DisableFileDeletions / EnableFileDeletions not supported in read-only DB // DisableFileDeletions / EnableFileDeletions not supported in read-only DB
if (deletions_disabled.ok()) { if (deletions_disabled.ok()) {
Status s2 = EnableFileDeletions(/*force=*/false); Status s2 = EnableFileDeletions();
assert(s2.ok()); assert(s2.ok());
s2.PermitUncheckedError(); s2.PermitUncheckedError();
} else { } else {

View File

@ -90,7 +90,7 @@ class CompactedDBImpl : public DBImpl {
Status DisableFileDeletions() override { Status DisableFileDeletions() override {
return Status::NotSupported("Not supported in compacted db mode."); return Status::NotSupported("Not supported in compacted db mode.");
} }
Status EnableFileDeletions(bool /*force*/) override { Status EnableFileDeletions() override {
return Status::NotSupported("Not supported in compacted db mode."); return Status::NotSupported("Not supported in compacted db mode.");
} }
Status GetLiveFiles(std::vector<std::string>& ret, Status GetLiveFiles(std::vector<std::string>& ret,

View File

@ -498,7 +498,7 @@ class DBImpl : public DB {
Status DisableFileDeletions() override; Status DisableFileDeletions() override;
Status EnableFileDeletions(bool force) override; Status EnableFileDeletions() override;
virtual bool IsFileDeletionsEnabled() const; virtual bool IsFileDeletionsEnabled() const;

View File

@ -67,17 +67,14 @@ Status DBImpl::DisableFileDeletionsWithLock() {
return Status::OK(); return Status::OK();
} }
Status DBImpl::EnableFileDeletions(bool force) { Status DBImpl::EnableFileDeletions() {
// Job id == 0 means that this is not our background process, but rather // Job id == 0 means that this is not our background process, but rather
// user thread // user thread
JobContext job_context(0); JobContext job_context(0);
int saved_counter; // initialize on all paths int saved_counter; // initialize on all paths
{ {
InstrumentedMutexLock l(&mutex_); InstrumentedMutexLock l(&mutex_);
if (force) { if (disable_delete_obsolete_files_ > 0) {
// if force, we need to enable file deletions right away
disable_delete_obsolete_files_ = 0;
} else if (disable_delete_obsolete_files_ > 0) {
--disable_delete_obsolete_files_; --disable_delete_obsolete_files_;
} }
saved_counter = disable_delete_obsolete_files_; saved_counter = disable_delete_obsolete_files_;

View File

@ -101,7 +101,7 @@ class DBImplReadOnly : public DBImpl {
return Status::NotSupported("Not supported operation in read only mode."); return Status::NotSupported("Not supported operation in read only mode.");
} }
Status EnableFileDeletions(bool /*force*/) override { Status EnableFileDeletions() override {
return Status::NotSupported("Not supported operation in read only mode."); return Status::NotSupported("Not supported operation in read only mode.");
} }
Status GetLiveFiles(std::vector<std::string>& ret, Status GetLiveFiles(std::vector<std::string>& ret,

View File

@ -189,7 +189,7 @@ class DBImplSecondary : public DBImpl {
return Status::NotSupported("Not supported operation in secondary mode."); return Status::NotSupported("Not supported operation in secondary mode.");
} }
Status EnableFileDeletions(bool /*force*/) override { Status EnableFileDeletions() override {
return Status::NotSupported("Not supported operation in secondary mode."); return Status::NotSupported("Not supported operation in secondary mode.");
} }

View File

@ -236,7 +236,7 @@ TEST_F(DBTestXactLogIterator, TransactionLogIteratorCorruptedLog) {
ASSERT_OK(test::TruncateFile(env_, logfile_path, ASSERT_OK(test::TruncateFile(env_, logfile_path,
wal_files.front()->SizeFileBytes() / 2)); wal_files.front()->SizeFileBytes() / 2));
ASSERT_OK(db_->EnableFileDeletions(/*force=*/false)); ASSERT_OK(db_->EnableFileDeletions());
// Insert a new entry to a new log file // Insert a new entry to a new log file
ASSERT_OK(Put("key1025", DummyString(10))); ASSERT_OK(Put("key1025", DummyString(10)));

View File

@ -106,12 +106,18 @@ TEST_F(DBPropertiesTest, Empty) {
dbfull()->GetProperty("rocksdb.is-file-deletions-enabled", &num)); dbfull()->GetProperty("rocksdb.is-file-deletions-enabled", &num));
ASSERT_EQ("0", num); ASSERT_EQ("0", num);
ASSERT_OK(db_->EnableFileDeletions(/*force=*/false)); ASSERT_OK(db_->EnableFileDeletions());
ASSERT_TRUE( ASSERT_TRUE(
dbfull()->GetProperty("rocksdb.is-file-deletions-enabled", &num)); dbfull()->GetProperty("rocksdb.is-file-deletions-enabled", &num));
ASSERT_EQ("0", num); ASSERT_EQ("0", num);
ASSERT_OK(db_->EnableFileDeletions(/*force=*/true)); ASSERT_OK(db_->EnableFileDeletions());
ASSERT_TRUE(
dbfull()->GetProperty("rocksdb.is-file-deletions-enabled", &num));
ASSERT_EQ("0", num);
// File deletion enabled after `EnableFileDeletions` called as many times
// as `DisableFileDeletions`.
ASSERT_OK(db_->EnableFileDeletions());
ASSERT_TRUE( ASSERT_TRUE(
dbfull()->GetProperty("rocksdb.is-file-deletions-enabled", &num)); dbfull()->GetProperty("rocksdb.is-file-deletions-enabled", &num));
ASSERT_EQ("1", num); ASSERT_EQ("1", num);
@ -1743,7 +1749,7 @@ TEST_F(DBPropertiesTest, SstFilesSize) {
ASSERT_EQ(obsolete_sst_size, sst_size); ASSERT_EQ(obsolete_sst_size, sst_size);
// Let the obsolete files be deleted. // Let the obsolete files be deleted.
ASSERT_OK(db_->EnableFileDeletions(/*force=*/false)); ASSERT_OK(db_->EnableFileDeletions());
ASSERT_TRUE(db_->GetIntProperty(DB::Properties::kObsoleteSstFilesSize, ASSERT_TRUE(db_->GetIntProperty(DB::Properties::kObsoleteSstFilesSize,
&obsolete_sst_size)); &obsolete_sst_size));
ASSERT_EQ(obsolete_sst_size, 0); ASSERT_EQ(obsolete_sst_size, 0);

View File

@ -2517,7 +2517,7 @@ TEST_F(DBTest, SnapshotFiles) {
} }
// release file snapshot // release file snapshot
ASSERT_OK(dbfull()->EnableFileDeletions(/*force*/ false)); ASSERT_OK(dbfull()->EnableFileDeletions());
// overwrite one key, this key should not appear in the snapshot // overwrite one key, this key should not appear in the snapshot
std::vector<std::string> extras; std::vector<std::string> extras;
for (unsigned int i = 0; i < 1; i++) { for (unsigned int i = 0; i < 1; i++) {
@ -3354,7 +3354,7 @@ class ModelDB : public DB {
Status DisableFileDeletions() override { return Status::OK(); } Status DisableFileDeletions() override { return Status::OK(); }
Status EnableFileDeletions(bool /*force*/) override { return Status::OK(); } Status EnableFileDeletions() override { return Status::OK(); }
Status GetLiveFiles(std::vector<std::string>&, uint64_t* /*size*/, Status GetLiveFiles(std::vector<std::string>&, uint64_t* /*size*/,
bool /*flush_memtable*/ = true) override { bool /*flush_memtable*/ = true) override {

View File

@ -4161,7 +4161,7 @@ TEST_F(DBTest2, LiveFilesOmitObsoleteFiles) {
ASSERT_OK(env_->FileExists(LogFileName(dbname_, log_file->LogNumber()))); ASSERT_OK(env_->FileExists(LogFileName(dbname_, log_file->LogNumber())));
} }
ASSERT_OK(db_->EnableFileDeletions(/*force=*/false)); ASSERT_OK(db_->EnableFileDeletions());
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing(); ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
} }

View File

@ -1195,7 +1195,7 @@ TEST_F(DBWALTest, DISABLED_FullPurgePreservesLogPendingReuse) {
ROCKSDB_NAMESPACE::port::Thread thread([&]() { ROCKSDB_NAMESPACE::port::Thread thread([&]() {
TEST_SYNC_POINT( TEST_SYNC_POINT(
"DBWALTest::FullPurgePreservesLogPendingReuse:PreFullPurge"); "DBWALTest::FullPurgePreservesLogPendingReuse:PreFullPurge");
ASSERT_OK(db_->EnableFileDeletions(/*force=*/true)); ASSERT_OK(db_->EnableFileDeletions());
TEST_SYNC_POINT( TEST_SYNC_POINT(
"DBWALTest::FullPurgePreservesLogPendingReuse:PostFullPurge"); "DBWALTest::FullPurgePreservesLogPendingReuse:PostFullPurge");
}); });

View File

@ -163,7 +163,7 @@ TEST_F(ObsoleteFilesTest, DeleteObsoleteOptionsFile) {
{{"paranoid_file_checks", "true"}})); {{"paranoid_file_checks", "true"}}));
} }
} }
ASSERT_OK(dbfull()->EnableFileDeletions(/*force=*/false)); ASSERT_OK(dbfull()->EnableFileDeletions());
Close(); Close();

View File

@ -691,8 +691,8 @@ extern ROCKSDB_LIBRARY_API void rocksdb_flush_wal(rocksdb_t* db,
extern ROCKSDB_LIBRARY_API void rocksdb_disable_file_deletions(rocksdb_t* db, extern ROCKSDB_LIBRARY_API void rocksdb_disable_file_deletions(rocksdb_t* db,
char** errptr); char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_enable_file_deletions( extern ROCKSDB_LIBRARY_API void rocksdb_enable_file_deletions(rocksdb_t* db,
rocksdb_t* db, unsigned char force, char** errptr); char** errptr);
/* Management operations */ /* Management operations */

View File

@ -1669,17 +1669,10 @@ class DB {
// critical for operations like making a backup. So the counter implementation // critical for operations like making a backup. So the counter implementation
// makes the file deletion disabled as long as there is one caller requesting // makes the file deletion disabled as long as there is one caller requesting
// so, and only when every caller agrees to re-enable file deletion, it will // so, and only when every caller agrees to re-enable file deletion, it will
// be enabled. So be careful when calling this function with force = true as // be enabled. Two threads can call this method concurrently without
// explained below.
// If force == true, the call to EnableFileDeletions() will guarantee that
// file deletions are enabled after the call, even if DisableFileDeletions()
// was called multiple times before.
// If force == false, EnableFileDeletions will only enable file deletion
// after it's been called at least as many times as DisableFileDeletions(),
// enabling the two methods to be called by two threads concurrently without
// synchronization -- i.e., file deletions will be enabled only after both // synchronization -- i.e., file deletions will be enabled only after both
// threads call EnableFileDeletions() // threads call EnableFileDeletions()
virtual Status EnableFileDeletions(bool force) = 0; virtual Status EnableFileDeletions() = 0;
// Retrieves the creation time of the oldest file in the DB. // Retrieves the creation time of the oldest file in the DB.
// This API only works if max_open_files = -1, if it is not then // This API only works if max_open_files = -1, if it is not then

View File

@ -400,9 +400,7 @@ class StackableDB : public DB {
Status DisableFileDeletions() override { return db_->DisableFileDeletions(); } Status DisableFileDeletions() override { return db_->DisableFileDeletions(); }
Status EnableFileDeletions(bool force) override { Status EnableFileDeletions() override { return db_->EnableFileDeletions(); }
return db_->EnableFileDeletions(force);
}
void GetLiveFilesMetaData(std::vector<LiveFileMetaData>* metadata) override { void GetLiveFilesMetaData(std::vector<LiveFileMetaData>* metadata) override {
db_->GetLiveFilesMetaData(metadata); db_->GetLiveFilesMetaData(metadata);

View File

@ -3550,10 +3550,9 @@ void Java_org_rocksdb_RocksDB_disableFileDeletions(JNIEnv* env, jclass,
* Signature: (JZ)V * Signature: (JZ)V
*/ */
void Java_org_rocksdb_RocksDB_enableFileDeletions(JNIEnv* env, jclass, void Java_org_rocksdb_RocksDB_enableFileDeletions(JNIEnv* env, jclass,
jlong jdb_handle, jlong jdb_handle) {
jboolean jforce) {
auto* db = reinterpret_cast<ROCKSDB_NAMESPACE::DB*>(jdb_handle); auto* db = reinterpret_cast<ROCKSDB_NAMESPACE::DB*>(jdb_handle);
ROCKSDB_NAMESPACE::Status s = db->EnableFileDeletions(jforce); ROCKSDB_NAMESPACE::Status s = db->EnableFileDeletions();
if (!s.ok()) { if (!s.ok()) {
ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s); ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
} }

View File

@ -4284,28 +4284,18 @@ public class RocksDB extends RocksObject {
} }
/** /**
* <p>Enable deleting obsolete files. * <p>EnableFileDeletions will only enable file deletion after
* If force == true, the call to EnableFileDeletions() * it's been called at least as many times as DisableFileDeletions(),
* will guarantee that file deletions are enabled after * enabling the two methods to be called by two threads concurrently
* the call, even if DisableFileDeletions() was called * without synchronization
* multiple times before.</p>
*
* <p>If force == false, EnableFileDeletions will only
* enable file deletion after it's been called at least
* as many times as DisableFileDeletions(), enabling
* the two methods to be called by two threads
* concurrently without synchronization
* -- i.e., file deletions will be enabled only after both * -- i.e., file deletions will be enabled only after both
* threads call EnableFileDeletions()</p> * threads call EnableFileDeletions()</p>
* *
* @param force boolean value described above.
*
* @throws RocksDBException thrown if operation was not performed * @throws RocksDBException thrown if operation was not performed
* successfully. * successfully.
*/ */
public void enableFileDeletions(final boolean force) public void enableFileDeletions() throws RocksDBException {
throws RocksDBException { enableFileDeletions(nativeHandle_);
enableFileDeletions(nativeHandle_, force);
} }
public static class LiveFiles { public static class LiveFiles {
@ -5041,8 +5031,7 @@ public class RocksDB extends RocksObject {
private static native void syncWal(final long handle) throws RocksDBException; private static native void syncWal(final long handle) throws RocksDBException;
private static native long getLatestSequenceNumber(final long handle); private static native long getLatestSequenceNumber(final long handle);
private static native void disableFileDeletions(long handle) throws RocksDBException; private static native void disableFileDeletions(long handle) throws RocksDBException;
private static native void enableFileDeletions(long handle, boolean force) private static native void enableFileDeletions(long handle) throws RocksDBException;
throws RocksDBException;
private static native String[] getLiveFiles(final long handle, final boolean flushMemtable) private static native String[] getLiveFiles(final long handle, final boolean flushMemtable)
throws RocksDBException; throws RocksDBException;
private static native LogFile[] getSortedWalFiles(final long handle) throws RocksDBException; private static native LogFile[] getSortedWalFiles(final long handle) throws RocksDBException;

View File

@ -1244,9 +1244,7 @@ public class RocksDBTest {
dbFolder.getRoot().getAbsolutePath()) dbFolder.getRoot().getAbsolutePath())
) { ) {
db.disableFileDeletions(); db.disableFileDeletions();
db.enableFileDeletions(false); db.enableFileDeletions();
db.disableFileDeletions();
db.enableFileDeletions(true);
} }
} }

View File

@ -271,7 +271,7 @@ class FileChecksumTestHelper {
break; break;
} }
} }
EXPECT_OK(db_->EnableFileDeletions(/*force=*/false)); EXPECT_OK(db_->EnableFileDeletions());
return cs; return cs;
} }
}; };

View File

@ -0,0 +1 @@
Remove the force mode for `EnableFileDeletions` API because it is unsafe with no known legitimate use.

View File

@ -1583,7 +1583,7 @@ IOStatus BackupEngineImpl::CreateNewBackupWithMetadata(
// we copied all the files, enable file deletions // we copied all the files, enable file deletions
if (disabled.ok()) { // If we successfully disabled file deletions if (disabled.ok()) { // If we successfully disabled file deletions
db->EnableFileDeletions(/*force=*/false).PermitUncheckedError(); db->EnableFileDeletions().PermitUncheckedError();
} }
auto backup_time = backup_env_->NowMicros() - start_backup; auto backup_time = backup_env_->NowMicros() - start_backup;

View File

@ -86,7 +86,7 @@ class DummyDB : public StackableDB {
DBOptions GetDBOptions() const override { return DBOptions(options_); } DBOptions GetDBOptions() const override { return DBOptions(options_); }
Status EnableFileDeletions(bool /*force*/) override { Status EnableFileDeletions() override {
EXPECT_TRUE(!deletions_enabled_); EXPECT_TRUE(!deletions_enabled_);
deletions_enabled_ = true; deletions_enabled_ = true;
return Status::OK(); return Status::OK();

View File

@ -156,7 +156,7 @@ class BlobDBImpl : public BlobDB {
Status DisableFileDeletions() override; Status DisableFileDeletions() override;
Status EnableFileDeletions(bool force) override; Status EnableFileDeletions() override;
Status GetLiveFiles(std::vector<std::string>&, uint64_t* manifest_file_size, Status GetLiveFiles(std::vector<std::string>&, uint64_t* manifest_file_size,
bool flush_memtable = true) override; bool flush_memtable = true) override;

View File

@ -35,9 +35,9 @@ Status BlobDBImpl::DisableFileDeletions() {
return Status::OK(); return Status::OK();
} }
Status BlobDBImpl::EnableFileDeletions(bool force) { Status BlobDBImpl::EnableFileDeletions() {
// Enable base DB file deletions. // Enable base DB file deletions.
Status s = db_impl_->EnableFileDeletions(force); Status s = db_impl_->EnableFileDeletions();
if (!s.ok()) { if (!s.ok()) {
return s; return s;
} }
@ -45,9 +45,7 @@ Status BlobDBImpl::EnableFileDeletions(bool force) {
int count = 0; int count = 0;
{ {
MutexLock l(&delete_file_mutex_); MutexLock l(&delete_file_mutex_);
if (force) { if (disable_file_deletions_ > 0) {
disable_file_deletions_ = 0;
} else if (disable_file_deletions_ > 0) {
count = --disable_file_deletions_; count = --disable_file_deletions_;
} }
assert(count >= 0); assert(count >= 0);

View File

@ -2009,7 +2009,6 @@ TEST_F(BlobDBTest, DisableFileDeletions) {
bdb_options.disable_background_tasks = true; bdb_options.disable_background_tasks = true;
Open(bdb_options); Open(bdb_options);
std::map<std::string, std::string> data; std::map<std::string, std::string> data;
for (bool force : {true, false}) {
ASSERT_OK(Put("foo", "v", &data)); ASSERT_OK(Put("foo", "v", &data));
auto blob_files = blob_db_impl()->TEST_GetBlobFiles(); auto blob_files = blob_db_impl()->TEST_GetBlobFiles();
ASSERT_EQ(1, blob_files.size()); ASSERT_EQ(1, blob_files.size());
@ -2026,23 +2025,20 @@ TEST_F(BlobDBTest, DisableFileDeletions) {
ASSERT_EQ(1, blob_db_impl()->TEST_GetBlobFiles().size()); ASSERT_EQ(1, blob_db_impl()->TEST_GetBlobFiles().size());
ASSERT_EQ(1, blob_db_impl()->TEST_GetObsoleteFiles().size()); ASSERT_EQ(1, blob_db_impl()->TEST_GetObsoleteFiles().size());
VerifyDB(data); VerifyDB(data);
// Enable file deletions once. If force=true, file deletion is enabled. // Enable file deletions once. File deletion will later get enabled when
// Otherwise it needs to enable it for a second time. // `EnableFileDeletions` called for a second time.
ASSERT_OK(blob_db_->EnableFileDeletions(force)); ASSERT_OK(blob_db_->EnableFileDeletions());
blob_db_impl()->TEST_DeleteObsoleteFiles(); blob_db_impl()->TEST_DeleteObsoleteFiles();
if (!force) {
ASSERT_EQ(1, blob_db_impl()->TEST_GetBlobFiles().size()); ASSERT_EQ(1, blob_db_impl()->TEST_GetBlobFiles().size());
ASSERT_EQ(1, blob_db_impl()->TEST_GetObsoleteFiles().size()); ASSERT_EQ(1, blob_db_impl()->TEST_GetObsoleteFiles().size());
VerifyDB(data); VerifyDB(data);
// Call EnableFileDeletions a second time. // Call EnableFileDeletions a second time.
ASSERT_OK(blob_db_->EnableFileDeletions(/*force=*/false)); ASSERT_OK(blob_db_->EnableFileDeletions());
blob_db_impl()->TEST_DeleteObsoleteFiles(); blob_db_impl()->TEST_DeleteObsoleteFiles();
} // File should be deleted by now.
// Regardless of value of `force`, file should be deleted by now.
ASSERT_EQ(0, blob_db_impl()->TEST_GetBlobFiles().size()); ASSERT_EQ(0, blob_db_impl()->TEST_GetBlobFiles().size());
ASSERT_EQ(0, blob_db_impl()->TEST_GetObsoleteFiles().size()); ASSERT_EQ(0, blob_db_impl()->TEST_GetObsoleteFiles().size());
VerifyDB({}); VerifyDB({});
}
} }
TEST_F(BlobDBTest, MaintainBlobFileToSstMapping) { TEST_F(BlobDBTest, MaintainBlobFileToSstMapping) {

View File

@ -148,7 +148,7 @@ Status CheckpointImpl::CreateCheckpoint(const std::string& checkpoint_dir,
// we copied all the files, enable file deletions // we copied all the files, enable file deletions
if (disabled_file_deletions) { if (disabled_file_deletions) {
Status ss = db_->EnableFileDeletions(/*force=*/false); Status ss = db_->EnableFileDeletions();
assert(ss.ok()); assert(ss.ok());
ss.PermitUncheckedError(); ss.PermitUncheckedError();
} }
@ -337,7 +337,7 @@ Status CheckpointImpl::ExportColumnFamily(
nullptr, Temperature::kUnknown); nullptr, Temperature::kUnknown);
} /*copy_file_cb*/); } /*copy_file_cb*/);
const auto enable_status = db_->EnableFileDeletions(/*force=*/false); const auto enable_status = db_->EnableFileDeletions();
if (s.ok()) { if (s.ok()) {
s = enable_status; s = enable_status;
} }