mirror of
https://github.com/facebook/rocksdb.git
synced 2026-07-07 22:55:23 +08:00
Compare commits
8 Commits
ajkr-patch-2
...
v3.12
| Author | SHA1 | Date | |
|---|---|---|---|
| 28d3aa3667 | |||
| 79c2075b53 | |||
| 0640c28723 | |||
| 718309432b | |||
| bc672aefb3 | |||
| b565228e1e | |||
| dc3cdfede9 | |||
| 8856b22edd |
@@ -5,6 +5,9 @@
|
||||
* Added experimental support for optimistic transactions. See include/rocksdb/utilities/optimistic_transaction.h for more info.
|
||||
* Added a new way to report QPS from db_bench (check out --report_file and --report_interval_seconds)
|
||||
* Added a cache for individual rows. See DBOptions::row_cache for more info.
|
||||
* Several new features on EventListener (see include/rocksdb/listener.h):
|
||||
- OnCompationCompleted() now returns per-compaciton job statistics, defined in include/rocksdb/compaction_job_stats.h.
|
||||
- Added OnTableFileCreated() and OnTableFileDeleted().
|
||||
|
||||
### Public API changes
|
||||
* EventListener::OnFlushCompleted() now passes FlushJobInfo instead of a list of parameters.
|
||||
|
||||
@@ -59,6 +59,7 @@ ColumnFamilyHandleImpl::~ColumnFamilyHandleImpl() {
|
||||
if (job_context.HaveSomethingToDelete()) {
|
||||
db_->PurgeObsoleteFiles(job_context);
|
||||
}
|
||||
job_context.Clean();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,11 +76,10 @@ class CompactionJobTest : public testing::Test {
|
||||
largest = internal_key;
|
||||
largest_seqno = sequence_number;
|
||||
}
|
||||
std::pair<std::string, std::string> key_value(
|
||||
{bottommost_internal_key.Encode().ToString(), value});
|
||||
contents.insert(key_value);
|
||||
contents.insert({internal_key.Encode().ToString(), value});
|
||||
if (i == 1 || k < kKeysPerFile / 2) {
|
||||
expected_results.insert(key_value);
|
||||
expected_results.insert(
|
||||
{bottommost_internal_key.Encode().ToString(), value});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +96,7 @@ class CompactionJobTest : public testing::Test {
|
||||
mutable_cf_options_, &edit, &mutex_);
|
||||
mutex_.Unlock();
|
||||
}
|
||||
versions_->SetLastSequence(sequence_number);
|
||||
versions_->SetLastSequence(sequence_number + 1);
|
||||
return expected_results;
|
||||
}
|
||||
|
||||
|
||||
+21
-19
@@ -527,6 +527,25 @@ void DBImpl::FindObsoleteFiles(JobContext* job_context, bool force,
|
||||
versions_->GetObsoleteFiles(&job_context->sst_delete_files,
|
||||
job_context->min_pending_output);
|
||||
|
||||
uint64_t min_log_number = versions_->MinLogNumber();
|
||||
if (!alive_log_files_.empty()) {
|
||||
// find newly obsoleted log files
|
||||
while (alive_log_files_.begin()->number < min_log_number) {
|
||||
auto& earliest = *alive_log_files_.begin();
|
||||
job_context->log_delete_files.push_back(earliest.number);
|
||||
total_log_size_ -= earliest.size;
|
||||
alive_log_files_.pop_front();
|
||||
// Current log should always stay alive since it can't have
|
||||
// number < MinLogNumber().
|
||||
assert(alive_log_files_.size());
|
||||
}
|
||||
}
|
||||
|
||||
// We're just cleaning up for DB::Write().
|
||||
assert(job_context->logs_to_free.empty());
|
||||
job_context->logs_to_free = logs_to_free_;
|
||||
logs_to_free_.clear();
|
||||
|
||||
// store the current filenum, lognum, etc
|
||||
job_context->manifest_file_number = versions_->manifest_file_number();
|
||||
job_context->pending_manifest_file_number =
|
||||
@@ -1309,17 +1328,6 @@ Status DBImpl::FlushMemTableToOutputFile(
|
||||
VersionStorageInfo::LevelSummaryStorage tmp;
|
||||
LogToBuffer(log_buffer, "[%s] Level summary: %s\n", cfd->GetName().c_str(),
|
||||
cfd->current()->storage_info()->LevelSummary(&tmp));
|
||||
|
||||
if (disable_delete_obsolete_files_ == 0) {
|
||||
// add to deletion state
|
||||
while (alive_log_files_.size() &&
|
||||
alive_log_files_.begin()->number < versions_->MinLogNumber()) {
|
||||
const auto& earliest = *alive_log_files_.begin();
|
||||
job_context->log_delete_files.push_back(earliest.number);
|
||||
total_log_size_ -= earliest.size;
|
||||
alive_log_files_.pop_front();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!s.ok() && !s.IsShutdownInProgress() && db_options_.paranoid_checks &&
|
||||
@@ -2145,7 +2153,9 @@ void DBImpl::RecordFlushIOStats() {
|
||||
|
||||
void DBImpl::BGWorkFlush(void* db) {
|
||||
IOSTATS_SET_THREAD_POOL_ID(Env::Priority::HIGH);
|
||||
TEST_SYNC_POINT("DBImpl::BGWorkFlush");
|
||||
reinterpret_cast<DBImpl*>(db)->BackgroundCallFlush();
|
||||
TEST_SYNC_POINT("DBImpl::BGWorkFlush:done");
|
||||
}
|
||||
|
||||
void DBImpl::BGWorkCompaction(void* db) {
|
||||
@@ -2238,10 +2248,6 @@ void DBImpl::BackgroundCallFlush() {
|
||||
|
||||
ReleaseFileNumberFromPendingOutputs(pending_outputs_inserted_elem);
|
||||
|
||||
// We're just cleaning up for DB::Write()
|
||||
job_context.logs_to_free = logs_to_free_;
|
||||
logs_to_free_.clear();
|
||||
|
||||
// If flush failed, we want to delete all temporary files that we might have
|
||||
// created. Thus, we force full scan in FindObsoleteFiles()
|
||||
FindObsoleteFiles(&job_context, !s.ok() && !s.IsShutdownInProgress());
|
||||
@@ -2308,10 +2314,6 @@ void DBImpl::BackgroundCallCompaction() {
|
||||
|
||||
ReleaseFileNumberFromPendingOutputs(pending_outputs_inserted_elem);
|
||||
|
||||
// We're just cleaning up for DB::Write()
|
||||
job_context.logs_to_free = logs_to_free_;
|
||||
logs_to_free_.clear();
|
||||
|
||||
// If compaction failed, we want to delete all temporary files that we might
|
||||
// have created (they might not be all recorded in job_context in case of a
|
||||
// failure). Thus, we force full scan in FindObsoleteFiles()
|
||||
|
||||
@@ -290,6 +290,8 @@ class DBImpl : public DB {
|
||||
|
||||
size_t TEST_LogsToFreeSize();
|
||||
|
||||
uint64_t TEST_LogfileNumber();
|
||||
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
// Returns the list of live files in 'live' and the list
|
||||
|
||||
@@ -148,5 +148,10 @@ size_t DBImpl::TEST_LogsToFreeSize() {
|
||||
return logs_to_free_.size();
|
||||
}
|
||||
|
||||
uint64_t DBImpl::TEST_LogfileNumber() {
|
||||
InstrumentedMutexLock l(&mutex_);
|
||||
return logfile_number_;
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
+2
-5
@@ -350,9 +350,6 @@ void DBIter::MergeValuesNewToOld() {
|
||||
void DBIter::Prev() {
|
||||
assert(valid_);
|
||||
if (direction_ == kForward) {
|
||||
if (!iter_->Valid()) {
|
||||
iter_->SeekToLast();
|
||||
}
|
||||
FindPrevUserKey();
|
||||
direction_ = kReverse;
|
||||
}
|
||||
@@ -556,7 +553,7 @@ void DBIter::FindNextUserKey() {
|
||||
ParsedInternalKey ikey;
|
||||
FindParseableKey(&ikey, kForward);
|
||||
while (iter_->Valid() &&
|
||||
user_comparator_->Compare(ikey.user_key, saved_key_.GetKey()) <= 0) {
|
||||
user_comparator_->Compare(ikey.user_key, saved_key_.GetKey()) != 0) {
|
||||
iter_->Next();
|
||||
FindParseableKey(&ikey, kForward);
|
||||
}
|
||||
@@ -571,7 +568,7 @@ void DBIter::FindPrevUserKey() {
|
||||
ParsedInternalKey ikey;
|
||||
FindParseableKey(&ikey, kReverse);
|
||||
while (iter_->Valid() &&
|
||||
user_comparator_->Compare(ikey.user_key, saved_key_.GetKey()) >= 0) {
|
||||
user_comparator_->Compare(ikey.user_key, saved_key_.GetKey()) == 0) {
|
||||
if (num_skipped >= max_skip_) {
|
||||
num_skipped = 0;
|
||||
IterKey last_key;
|
||||
|
||||
+6
-2
@@ -1668,7 +1668,9 @@ TEST_F(DBIteratorTest, DBIterator8) {
|
||||
ASSERT_EQ(db_iter->value().ToString(), "0");
|
||||
}
|
||||
|
||||
TEST_F(DBIteratorTest, DBIterator9) {
|
||||
// TODO(3.13): fix the issue of Seek() then Prev() which might not necessary
|
||||
// return the biggest element smaller than the seek key.
|
||||
TEST_F(DBIteratorTest, DISABLED_DBIterator9) {
|
||||
Options options;
|
||||
options.merge_operator = MergeOperators::CreateFromStringId("stringappend");
|
||||
{
|
||||
@@ -1716,7 +1718,9 @@ TEST_F(DBIteratorTest, DBIterator9) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DBIteratorTest, DBIterator10) {
|
||||
// TODO(3.13): fix the issue of Seek() then Prev() which might not necessary
|
||||
// return the biggest element smaller than the seek key.
|
||||
TEST_F(DBIteratorTest, DISABLED_DBIterator10) {
|
||||
Options options;
|
||||
|
||||
TestIterator* internal_iter = new TestIterator(BytewiseComparator());
|
||||
|
||||
+38
-3
@@ -8540,7 +8540,6 @@ TEST_F(DBTest, TransactionLogIterator) {
|
||||
} while (ChangeCompactOptions());
|
||||
}
|
||||
|
||||
#ifndef NDEBUG // sync point is not included with DNDEBUG build
|
||||
TEST_F(DBTest, TransactionLogIteratorRace) {
|
||||
static const int LOG_ITERATOR_RACE_TEST_COUNT = 2;
|
||||
static const char* sync_points[LOG_ITERATOR_RACE_TEST_COUNT][4] = {
|
||||
@@ -8595,7 +8594,6 @@ TEST_F(DBTest, TransactionLogIteratorRace) {
|
||||
} while (ChangeCompactOptions());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_F(DBTest, TransactionLogIteratorStallAtLastRecord) {
|
||||
do {
|
||||
@@ -12672,6 +12670,7 @@ TEST_F(DBTest, DontDeletePendingOutputs) {
|
||||
dbfull()->FindObsoleteFiles(&job_context, true /*force*/);
|
||||
dbfull()->TEST_UnlockMutex();
|
||||
dbfull()->PurgeObsoleteFiles(job_context);
|
||||
job_context.Clean();
|
||||
};
|
||||
|
||||
env_->table_write_callback_ = &purge_obsolete_files_function;
|
||||
@@ -14113,7 +14112,9 @@ TEST_F(DBTest, RowCache) {
|
||||
ASSERT_EQ(TestGetTickerCount(options, ROW_CACHE_MISS), 1);
|
||||
}
|
||||
|
||||
TEST_F(DBTest, PrevAfterMerge) {
|
||||
// TODO(3.13): fix the issue of Seek() + Prev() which might not necessary
|
||||
// return the biggest key which is smaller than the seek key.
|
||||
TEST_F(DBTest, DISABLED_PrevAfterMerge) {
|
||||
Options options;
|
||||
options.create_if_missing = true;
|
||||
options.merge_operator = MergeOperators::CreatePutOperator();
|
||||
@@ -14136,6 +14137,40 @@ TEST_F(DBTest, PrevAfterMerge) {
|
||||
ASSERT_EQ("1", it->key().ToString());
|
||||
}
|
||||
|
||||
TEST_F(DBTest, DeletingOldWalAfterDrop) {
|
||||
rocksdb::SyncPoint::GetInstance()->LoadDependency(
|
||||
{ { "Test:AllowFlushes", "DBImpl::BGWorkFlush" },
|
||||
{ "DBImpl::BGWorkFlush:done", "Test:WaitForFlush"} });
|
||||
rocksdb::SyncPoint::GetInstance()->ClearTrace();
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
Options options = CurrentOptions();
|
||||
options.max_total_wal_size = 8192;
|
||||
options.compression = kNoCompression;
|
||||
options.write_buffer_size = 1 << 20;
|
||||
options.level0_file_num_compaction_trigger = (1<<30);
|
||||
options.level0_slowdown_writes_trigger = (1<<30);
|
||||
options.level0_stop_writes_trigger = (1<<30);
|
||||
options.disable_auto_compactions = true;
|
||||
DestroyAndReopen(options);
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
CreateColumnFamilies({"cf1", "cf2"}, options);
|
||||
ASSERT_OK(Put(0, "key1", DummyString(8192)));
|
||||
ASSERT_OK(Put(0, "key2", DummyString(8192)));
|
||||
// the oldest wal should now be getting_flushed
|
||||
ASSERT_OK(db_->DropColumnFamily(handles_[0]));
|
||||
// all flushes should now do nothing because their CF is dropped
|
||||
TEST_SYNC_POINT("Test:AllowFlushes");
|
||||
TEST_SYNC_POINT("Test:WaitForFlush");
|
||||
uint64_t lognum1 = dbfull()->TEST_LogfileNumber();
|
||||
ASSERT_OK(Put(1, "key3", DummyString(8192)));
|
||||
ASSERT_OK(Put(1, "key4", DummyString(8192)));
|
||||
// new wal should have been created
|
||||
uint64_t lognum2 = dbfull()->TEST_LogfileNumber();
|
||||
EXPECT_GT(lognum2, lognum1);
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
@@ -169,6 +169,7 @@ void ForwardIterator::Cleanup(bool release_sv) {
|
||||
if (job_context.HaveSomethingToDelete()) {
|
||||
db_->PurgeObsoleteFiles(job_context);
|
||||
}
|
||||
job_context.Clean();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +83,10 @@ struct JobContext {
|
||||
new_superversion = create_superversion ? new SuperVersion() : nullptr;
|
||||
}
|
||||
|
||||
// For non-empty JobContext Clean() has to be called at least once before
|
||||
// before destruction (see asserts in ~JobContext()). Should be called with
|
||||
// unlocked DB mutex. Destructor doesn't call Clean() to avoid accidentally
|
||||
// doing potentially slow Clean() with locked DB mutex.
|
||||
void Clean() {
|
||||
// free pending memtables
|
||||
for (auto m : memtables_to_free) {
|
||||
@@ -109,6 +113,7 @@ struct JobContext {
|
||||
assert(memtables_to_free.size() == 0);
|
||||
assert(superversions_to_free.size() == 0);
|
||||
assert(new_superversion == nullptr);
|
||||
assert(logs_to_free.size() == 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+3
-1
@@ -612,7 +612,9 @@ class VersionSet {
|
||||
uint64_t MinLogNumber() const {
|
||||
uint64_t min_log_num = std::numeric_limits<uint64_t>::max();
|
||||
for (auto cfd : *column_family_set_) {
|
||||
if (min_log_num > cfd->GetLogNumber()) {
|
||||
// It's safe to ignore dropped column families here:
|
||||
// cfd->IsDropped() becomes true after the drop is persisted in MANIFEST.
|
||||
if (min_log_num > cfd->GetLogNumber() && !cfd->IsDropped()) {
|
||||
min_log_num = cfd->GetLogNumber();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
namespace {
|
||||
class BackupRateLimiter {
|
||||
public:
|
||||
BackupRateLimiter(Env* env, uint64_t max_bytes_per_second,
|
||||
@@ -79,7 +78,6 @@ class BackupRateLimiter {
|
||||
uint64_t bytes_since_start_;
|
||||
static const uint64_t kMicrosInSecond = 1000 * 1000LL;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
void BackupStatistics::IncrementNumberSuccessBackup() {
|
||||
number_success_backup++;
|
||||
@@ -444,26 +442,6 @@ BackupEngineImpl::BackupEngineImpl(Env* db_env,
|
||||
copy_file_buffer_size_(kDefaultCopyFileBufferSize),
|
||||
read_only_(read_only) {
|
||||
|
||||
// set up threads perform copies from files_to_copy_ in the background
|
||||
for (int t = 0; t < options_.max_background_operations; t++) {
|
||||
threads_.emplace_back([&]() {
|
||||
CopyWorkItem work_item;
|
||||
while (files_to_copy_.read(work_item)) {
|
||||
CopyResult result;
|
||||
result.status = CopyFile(work_item.src_path,
|
||||
work_item.dst_path,
|
||||
work_item.src_env,
|
||||
work_item.dst_env,
|
||||
work_item.sync,
|
||||
work_item.rate_limiter,
|
||||
&result.size,
|
||||
&result.checksum_value,
|
||||
work_item.size_limit);
|
||||
work_item.result.set_value(std::move(result));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (read_only_) {
|
||||
Log(options_.info_log, "Starting read_only backup engine");
|
||||
}
|
||||
@@ -583,6 +561,27 @@ BackupEngineImpl::BackupEngineImpl(Env* db_env,
|
||||
if (!read_only_) {
|
||||
PutLatestBackupFileContents(latest_backup_id_); // Ignore errors
|
||||
}
|
||||
|
||||
// set up threads perform copies from files_to_copy_ in the background
|
||||
for (int t = 0; t < options_.max_background_operations; t++) {
|
||||
threads_.emplace_back([&]() {
|
||||
CopyWorkItem work_item;
|
||||
while (files_to_copy_.read(work_item)) {
|
||||
CopyResult result;
|
||||
result.status = CopyFile(work_item.src_path,
|
||||
work_item.dst_path,
|
||||
work_item.src_env,
|
||||
work_item.dst_env,
|
||||
work_item.sync,
|
||||
work_item.rate_limiter,
|
||||
&result.size,
|
||||
&result.checksum_value,
|
||||
work_item.size_limit);
|
||||
work_item.result.set_value(std::move(result));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Log(options_.info_log, "Initialized BackupEngine");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user