Add DBProperty to return number of snapshots and time for oldest snapshot

Summary:
Add a counter in SnapshotList to show number of snapshots. Also a unix timestamp in every snapshot.
Add two DB Properties to return number of snapshots and timestamp of the oldest one.

Test Plan: Add unit test checking

Reviewers: yhchiang, rven, igor

Reviewed By: igor

Subscribers: leveldb, dhruba, MarkCallaghan

Differential Revision: https://reviews.facebook.net/D29919
main
sdong 10 years ago
parent 6436ba6b06
commit 1f04066cab
  1. 5
      db/db_impl.cc
  2. 2
      db/db_impl.h
  3. 42
      db/db_test.cc
  4. 10
      db/internal_stats.cc
  5. 2
      db/internal_stats.h
  6. 19
      db/snapshot.h

@ -2718,10 +2718,13 @@ bool DBImpl::IsSnapshotSupported() const {
} }
const Snapshot* DBImpl::GetSnapshot() { const Snapshot* DBImpl::GetSnapshot() {
int64_t unix_time = 0;
env_->GetCurrentTime(&unix_time); // Ignore error
MutexLock l(&mutex_); MutexLock l(&mutex_);
// returns null if the underlying memtable does not support snapshot. // returns null if the underlying memtable does not support snapshot.
if (!IsSnapshotSupported()) return nullptr; if (!IsSnapshotSupported()) return nullptr;
return snapshots_.New(versions_->LastSequence()); return snapshots_.New(versions_->LastSequence(), unix_time);
} }
void DBImpl::ReleaseSnapshot(const Snapshot* s) { void DBImpl::ReleaseSnapshot(const Snapshot* s) {

@ -248,6 +248,8 @@ class DBImpl : public DB {
ColumnFamilyHandle* DefaultColumnFamily() const; ColumnFamilyHandle* DefaultColumnFamily() const;
const SnapshotList& snapshots() const { return snapshots_; }
protected: protected:
Env* const env_; Env* const env_;
const std::string dbname_; const std::string dbname_;

@ -173,7 +173,9 @@ class SpecialEnv : public EnvWrapper {
std::function<void()>* table_write_callback_; std::function<void()>* table_write_callback_;
explicit SpecialEnv(Env* base) : EnvWrapper(base), rnd_(301) { int64_t addon_time_;
explicit SpecialEnv(Env* base) : EnvWrapper(base), rnd_(301), addon_time_(0) {
delay_sstable_sync_.store(false, std::memory_order_release); delay_sstable_sync_.store(false, std::memory_order_release);
drop_writes_.store(false, std::memory_order_release); drop_writes_.store(false, std::memory_order_release);
no_space_.store(false, std::memory_order_release); no_space_.store(false, std::memory_order_release);
@ -368,6 +370,14 @@ class SpecialEnv : public EnvWrapper {
sleep_counter_.Increment(); sleep_counter_.Increment();
target()->SleepForMicroseconds(micros); target()->SleepForMicroseconds(micros);
} }
virtual Status GetCurrentTime(int64_t* unix_time) override {
Status s = target()->GetCurrentTime(unix_time);
if (s.ok()) {
*unix_time += addon_time_;
}
return s;
}
}; };
class DBTest { class DBTest {
@ -814,6 +824,19 @@ class DBTest {
return result; return result;
} }
uint64_t GetNumSnapshots() {
uint64_t int_num;
ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.num-snapshots", &int_num));
return int_num;
}
uint64_t GetTimeOldestSnapshots() {
uint64_t int_num;
ASSERT_TRUE(
dbfull()->GetIntProperty("rocksdb.oldest-snapshot-time", &int_num));
return int_num;
}
// Return a string that contains all key,value pairs in order, // Return a string that contains all key,value pairs in order,
// formatted like "(k1->v1)(k2->v2)". // formatted like "(k1->v1)(k2->v2)".
std::string Contents(int cf = 0) { std::string Contents(int cf = 0) {
@ -5429,13 +5452,25 @@ TEST(DBTest, Snapshot) {
CreateAndReopenWithCF({"pikachu"}, CurrentOptions()); CreateAndReopenWithCF({"pikachu"}, CurrentOptions());
Put(0, "foo", "0v1"); Put(0, "foo", "0v1");
Put(1, "foo", "1v1"); Put(1, "foo", "1v1");
const Snapshot* s1 = db_->GetSnapshot(); const Snapshot* s1 = db_->GetSnapshot();
ASSERT_EQ(1U, GetNumSnapshots());
uint64_t time_snap1 = GetTimeOldestSnapshots();
ASSERT_GT(time_snap1, 0U);
Put(0, "foo", "0v2"); Put(0, "foo", "0v2");
Put(1, "foo", "1v2"); Put(1, "foo", "1v2");
env_->addon_time_++;
const Snapshot* s2 = db_->GetSnapshot(); const Snapshot* s2 = db_->GetSnapshot();
ASSERT_EQ(2U, GetNumSnapshots());
ASSERT_EQ(time_snap1, GetTimeOldestSnapshots());
Put(0, "foo", "0v3"); Put(0, "foo", "0v3");
Put(1, "foo", "1v3"); Put(1, "foo", "1v3");
const Snapshot* s3 = db_->GetSnapshot(); const Snapshot* s3 = db_->GetSnapshot();
ASSERT_EQ(3U, GetNumSnapshots());
ASSERT_EQ(time_snap1, GetTimeOldestSnapshots());
Put(0, "foo", "0v4"); Put(0, "foo", "0v4");
Put(1, "foo", "1v4"); Put(1, "foo", "1v4");
@ -5449,6 +5484,8 @@ TEST(DBTest, Snapshot) {
ASSERT_EQ("1v4", Get(1, "foo")); ASSERT_EQ("1v4", Get(1, "foo"));
db_->ReleaseSnapshot(s3); db_->ReleaseSnapshot(s3);
ASSERT_EQ(2U, GetNumSnapshots());
ASSERT_EQ(time_snap1, GetTimeOldestSnapshots());
ASSERT_EQ("0v1", Get(0, "foo", s1)); ASSERT_EQ("0v1", Get(0, "foo", s1));
ASSERT_EQ("1v1", Get(1, "foo", s1)); ASSERT_EQ("1v1", Get(1, "foo", s1));
ASSERT_EQ("0v2", Get(0, "foo", s2)); ASSERT_EQ("0v2", Get(0, "foo", s2));
@ -5461,8 +5498,11 @@ TEST(DBTest, Snapshot) {
ASSERT_EQ("1v2", Get(1, "foo", s2)); ASSERT_EQ("1v2", Get(1, "foo", s2));
ASSERT_EQ("0v4", Get(0, "foo")); ASSERT_EQ("0v4", Get(0, "foo"));
ASSERT_EQ("1v4", Get(1, "foo")); ASSERT_EQ("1v4", Get(1, "foo"));
ASSERT_EQ(1U, GetNumSnapshots());
ASSERT_LT(time_snap1, GetTimeOldestSnapshots());
db_->ReleaseSnapshot(s2); db_->ReleaseSnapshot(s2);
ASSERT_EQ(0U, GetNumSnapshots());
ASSERT_EQ("0v4", Get(0, "foo")); ASSERT_EQ("0v4", Get(0, "foo"));
ASSERT_EQ("1v4", Get(1, "foo")); ASSERT_EQ("1v4", Get(1, "foo"));
} while (ChangeOptions(kSkipHashCuckoo)); } while (ChangeOptions(kSkipHashCuckoo));

@ -136,6 +136,10 @@ DBPropertyType GetPropertyType(const Slice& property, bool* is_int_property,
return kEstimatedUsageByTableReaders; return kEstimatedUsageByTableReaders;
} else if (in == "is-file-deletions-enabled") { } else if (in == "is-file-deletions-enabled") {
return kIsFileDeletionEnabled; return kIsFileDeletionEnabled;
} else if (in == "num-snapshots") {
return kNumSnapshots;
} else if (in == "oldest-snapshot-time") {
return kOldestSnapshotTime;
} }
return kUnknown; return kUnknown;
} }
@ -263,6 +267,12 @@ bool InternalStats::GetIntProperty(DBPropertyType property_type,
cfd_->imm()->current()->GetTotalNumEntries() + cfd_->imm()->current()->GetTotalNumEntries() +
vstorage->GetEstimatedActiveKeys(); vstorage->GetEstimatedActiveKeys();
return true; return true;
case kNumSnapshots:
*value = db->snapshots().count();
return true;
case kOldestSnapshotTime:
*value = static_cast<uint64_t>(db->snapshots().GetOldestSnapshotTime());
return true;
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
case kIsFileDeletionEnabled: case kIsFileDeletionEnabled:
*value = db->IsFileDeletionsEnabled(); *value = db->IsFileDeletionsEnabled();

@ -46,6 +46,8 @@ enum DBPropertyType : uint32_t {
kEstimatedUsageByTableReaders, // Estimated memory by table readers. kEstimatedUsageByTableReaders, // Estimated memory by table readers.
kIsFileDeletionEnabled, // Equals disable_delete_obsolete_files_, kIsFileDeletionEnabled, // Equals disable_delete_obsolete_files_,
// 0 means file deletions enabled // 0 means file deletions enabled
kNumSnapshots, // Number of snapshots in the system
kOldestSnapshotTime, // Unix timestamp of the first snapshot
}; };
extern DBPropertyType GetPropertyType(const Slice& property, extern DBPropertyType GetPropertyType(const Slice& property,

@ -28,6 +28,8 @@ class SnapshotImpl : public Snapshot {
SnapshotImpl* next_; SnapshotImpl* next_;
SnapshotList* list_; // just for sanity checks SnapshotList* list_; // just for sanity checks
int64_t unix_time_;
}; };
class SnapshotList { class SnapshotList {
@ -36,20 +38,23 @@ class SnapshotList {
list_.prev_ = &list_; list_.prev_ = &list_;
list_.next_ = &list_; list_.next_ = &list_;
list_.number_ = 0xFFFFFFFFL; // placeholder marker, for debugging list_.number_ = 0xFFFFFFFFL; // placeholder marker, for debugging
count_ = 0;
} }
bool empty() const { return list_.next_ == &list_; } bool empty() const { return list_.next_ == &list_; }
SnapshotImpl* oldest() const { assert(!empty()); return list_.next_; } SnapshotImpl* oldest() const { assert(!empty()); return list_.next_; }
SnapshotImpl* newest() const { assert(!empty()); return list_.prev_; } SnapshotImpl* newest() const { assert(!empty()); return list_.prev_; }
const SnapshotImpl* New(SequenceNumber seq) { const SnapshotImpl* New(SequenceNumber seq, uint64_t unix_time) {
SnapshotImpl* s = new SnapshotImpl; SnapshotImpl* s = new SnapshotImpl;
s->number_ = seq; s->number_ = seq;
s->unix_time_ = unix_time;
s->list_ = this; s->list_ = this;
s->next_ = &list_; s->next_ = &list_;
s->prev_ = list_.prev_; s->prev_ = list_.prev_;
s->prev_->next_ = s; s->prev_->next_ = s;
s->next_->prev_ = s; s->next_->prev_ = s;
count_++;
return s; return s;
} }
@ -57,6 +62,7 @@ class SnapshotList {
assert(s->list_ == this); assert(s->list_ == this);
s->prev_->next_ = s->next_; s->prev_->next_ = s->next_;
s->next_->prev_ = s->prev_; s->next_->prev_ = s->prev_;
count_--;
delete s; delete s;
} }
@ -78,9 +84,20 @@ class SnapshotList {
return newest()->number_; return newest()->number_;
} }
int64_t GetOldestSnapshotTime() const {
if (empty()) {
return 0;
} else {
return oldest()->unix_time_;
}
}
uint64_t count() const { return count_; }
private: private:
// Dummy head of doubly-linked list of snapshots // Dummy head of doubly-linked list of snapshots
SnapshotImpl list_; SnapshotImpl list_;
uint64_t count_;
}; };
} // namespace rocksdb } // namespace rocksdb

Loading…
Cancel
Save