DB::Close() to fail when there are unreleased snapshots (#5272)
Summary: Sometimes, users might make mistake of not releasing snapshots before closing the DB. This is undocumented use of RocksDB and the behavior is unknown. We return DB::Close() to provide a way to check it for the users. Aborted() will be returned to users when they call DB::Close(). Pull Request resolved: https://github.com/facebook/rocksdb/pull/5272 Differential Revision: D15159713 Pulled By: siying fbshipit-source-id: 39369def612398d9f239d83d396b5a28e5af65cd
This commit is contained in:
parent
521d234bda
commit
4e0f2aadb0
@ -1,5 +1,7 @@
|
||||
# Rocksdb Change Log
|
||||
## Unreleased
|
||||
### Public API Change
|
||||
* Now DB::Close() will return Aborted() error when there is unreleased snapshot. Users can retry after all snapshots are released.
|
||||
|
||||
## 6.2.0 (4/30/2019)
|
||||
### New Features
|
||||
|
@ -582,6 +582,12 @@ Status DBImpl::CloseHelper() {
|
||||
ret = s;
|
||||
}
|
||||
}
|
||||
if (ret.IsAborted()) {
|
||||
// Reserve IsAborted() error for those where users didn't release
|
||||
// certain resource and they can release them and come back and
|
||||
// retry. In this case, we wrap this exception to something else.
|
||||
return Status::Incomplete(ret.ToString());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -3036,6 +3042,14 @@ DB::~DB() {}
|
||||
|
||||
Status DBImpl::Close() {
|
||||
if (!closed_) {
|
||||
{
|
||||
InstrumentedMutexLock l(&mutex_);
|
||||
// If there is unreleased snapshot, fail the close call
|
||||
if (!snapshots_.empty()) {
|
||||
return Status::Aborted("Cannot close DB with unreleased snapshot.");
|
||||
}
|
||||
}
|
||||
|
||||
closed_ = true;
|
||||
return CloseImpl();
|
||||
}
|
||||
|
@ -3738,6 +3738,21 @@ TEST_F(DBTest2, OldStatsInterface) {
|
||||
ASSERT_GT(dos->num_rt, 0);
|
||||
ASSERT_GT(dos->num_mt, 0);
|
||||
}
|
||||
|
||||
TEST_F(DBTest2, CloseWithUnreleasedSnapshot) {
|
||||
const Snapshot* ss = db_->GetSnapshot();
|
||||
|
||||
for (auto h : handles_) {
|
||||
db_->DestroyColumnFamilyHandle(h);
|
||||
}
|
||||
handles_.clear();
|
||||
|
||||
ASSERT_NOK(db_->Close());
|
||||
db_->ReleaseSnapshot(ss);
|
||||
ASSERT_OK(db_->Close());
|
||||
delete db_;
|
||||
db_ = nullptr;
|
||||
}
|
||||
} // namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
@ -232,9 +232,13 @@ class DB {
|
||||
// status in case there are any errors. This will not fsync the WAL files.
|
||||
// If syncing is required, the caller must first call SyncWAL(), or Write()
|
||||
// using an empty write batch with WriteOptions.sync=true.
|
||||
// Regardless of the return status, the DB must be freed. If the return
|
||||
// status is NotSupported(), then the DB implementation does cleanup in the
|
||||
// destructor
|
||||
// Regardless of the return status, the DB must be freed.
|
||||
// If the return status is Aborted(), closing fails because there is
|
||||
// unreleased snapshot in the system. In this case, users can release
|
||||
// the unreleased snapshots and try again and expect it to succeed. For
|
||||
// other status, recalling Close() will be no-op.
|
||||
// If the return status is NotSupported(), then the DB implementation does
|
||||
// cleanup in the destructor
|
||||
virtual Status Close() { return Status::NotSupported(); }
|
||||
|
||||
// ListColumnFamilies will open the DB specified by argument name
|
||||
|
Loading…
x
Reference in New Issue
Block a user