mirror of
https://github.com/google/leveldb.git
synced 2025-04-01 12:30:12 +08:00
Clean up SnapshotImpl.
* Omit SnapshotImpl::list_ when assert() isn't on * Make SnapshotImpl::number_ const and set it in the constructor * Make SnapshotImpl::number_ private and access it via a getter * Rename SnapshotImpl::number_ to SnapshotImpl::sequence_number_ * Rename SnapshotList::list_ to SnapshotList::head_ * Wrap casting from Snapshot* to SnapshotImpl* in ToSnapshotImpl() ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=194852828
This commit is contained in:
parent
e7840de9f3
commit
1868398150
@ -906,7 +906,7 @@ Status DBImpl::DoCompactionWork(CompactionState* compact) {
|
|||||||
if (snapshots_.empty()) {
|
if (snapshots_.empty()) {
|
||||||
compact->smallest_snapshot = versions_->LastSequence();
|
compact->smallest_snapshot = versions_->LastSequence();
|
||||||
} else {
|
} else {
|
||||||
compact->smallest_snapshot = snapshots_.oldest()->number_;
|
compact->smallest_snapshot = snapshots_.oldest()->sequence_number();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release mutex while we're actually doing the compaction work
|
// Release mutex while we're actually doing the compaction work
|
||||||
@ -1121,7 +1121,8 @@ Status DBImpl::Get(const ReadOptions& options,
|
|||||||
MutexLock l(&mutex_);
|
MutexLock l(&mutex_);
|
||||||
SequenceNumber snapshot;
|
SequenceNumber snapshot;
|
||||||
if (options.snapshot != nullptr) {
|
if (options.snapshot != nullptr) {
|
||||||
snapshot = reinterpret_cast<const SnapshotImpl*>(options.snapshot)->number_;
|
snapshot =
|
||||||
|
static_cast<const SnapshotImpl*>(options.snapshot)->sequence_number();
|
||||||
} else {
|
} else {
|
||||||
snapshot = versions_->LastSequence();
|
snapshot = versions_->LastSequence();
|
||||||
}
|
}
|
||||||
@ -1168,7 +1169,7 @@ Iterator* DBImpl::NewIterator(const ReadOptions& options) {
|
|||||||
return NewDBIterator(
|
return NewDBIterator(
|
||||||
this, user_comparator(), iter,
|
this, user_comparator(), iter,
|
||||||
(options.snapshot != nullptr
|
(options.snapshot != nullptr
|
||||||
? reinterpret_cast<const SnapshotImpl*>(options.snapshot)->number_
|
? static_cast<const SnapshotImpl*>(options.snapshot)->sequence_number()
|
||||||
: latest_snapshot),
|
: latest_snapshot),
|
||||||
seed);
|
seed);
|
||||||
}
|
}
|
||||||
@ -1185,9 +1186,9 @@ const Snapshot* DBImpl::GetSnapshot() {
|
|||||||
return snapshots_.New(versions_->LastSequence());
|
return snapshots_.New(versions_->LastSequence());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DBImpl::ReleaseSnapshot(const Snapshot* s) {
|
void DBImpl::ReleaseSnapshot(const Snapshot* snapshot) {
|
||||||
MutexLock l(&mutex_);
|
MutexLock l(&mutex_);
|
||||||
snapshots_.Delete(reinterpret_cast<const SnapshotImpl*>(s));
|
snapshots_.Delete(static_cast<const SnapshotImpl*>(snapshot));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convenience methods
|
// Convenience methods
|
||||||
|
@ -631,6 +631,55 @@ TEST(DBTest, GetSnapshot) {
|
|||||||
} while (ChangeOptions());
|
} while (ChangeOptions());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(DBTest, GetIdenticalSnapshots) {
|
||||||
|
do {
|
||||||
|
// Try with both a short key and a long key
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
std::string key = (i == 0) ? std::string("foo") : std::string(200, 'x');
|
||||||
|
ASSERT_OK(Put(key, "v1"));
|
||||||
|
const Snapshot* s1 = db_->GetSnapshot();
|
||||||
|
const Snapshot* s2 = db_->GetSnapshot();
|
||||||
|
const Snapshot* s3 = db_->GetSnapshot();
|
||||||
|
ASSERT_OK(Put(key, "v2"));
|
||||||
|
ASSERT_EQ("v2", Get(key));
|
||||||
|
ASSERT_EQ("v1", Get(key, s1));
|
||||||
|
ASSERT_EQ("v1", Get(key, s2));
|
||||||
|
ASSERT_EQ("v1", Get(key, s3));
|
||||||
|
db_->ReleaseSnapshot(s1);
|
||||||
|
dbfull()->TEST_CompactMemTable();
|
||||||
|
ASSERT_EQ("v2", Get(key));
|
||||||
|
ASSERT_EQ("v1", Get(key, s2));
|
||||||
|
db_->ReleaseSnapshot(s2);
|
||||||
|
ASSERT_EQ("v1", Get(key, s3));
|
||||||
|
db_->ReleaseSnapshot(s3);
|
||||||
|
}
|
||||||
|
} while (ChangeOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DBTest, IterateOverEmptySnapshot) {
|
||||||
|
do {
|
||||||
|
const Snapshot* snapshot = db_->GetSnapshot();
|
||||||
|
ReadOptions read_options;
|
||||||
|
read_options.snapshot = snapshot;
|
||||||
|
ASSERT_OK(Put("foo", "v1"));
|
||||||
|
ASSERT_OK(Put("foo", "v2"));
|
||||||
|
|
||||||
|
Iterator* iterator1 = db_->NewIterator(read_options);
|
||||||
|
iterator1->SeekToFirst();
|
||||||
|
ASSERT_TRUE(!iterator1->Valid());
|
||||||
|
delete iterator1;
|
||||||
|
|
||||||
|
dbfull()->TEST_CompactMemTable();
|
||||||
|
|
||||||
|
Iterator* iterator2 = db_->NewIterator(read_options);
|
||||||
|
iterator2->SeekToFirst();
|
||||||
|
ASSERT_TRUE(!iterator2->Valid());
|
||||||
|
delete iterator2;
|
||||||
|
|
||||||
|
db_->ReleaseSnapshot(snapshot);
|
||||||
|
} while (ChangeOptions());
|
||||||
|
}
|
||||||
|
|
||||||
TEST(DBTest, GetLevel0Ordering) {
|
TEST(DBTest, GetLevel0Ordering) {
|
||||||
do {
|
do {
|
||||||
// Check that we process level-0 files in correct order. The code
|
// Check that we process level-0 files in correct order. The code
|
||||||
|
@ -16,50 +16,72 @@ class SnapshotList;
|
|||||||
// Each SnapshotImpl corresponds to a particular sequence number.
|
// Each SnapshotImpl corresponds to a particular sequence number.
|
||||||
class SnapshotImpl : public Snapshot {
|
class SnapshotImpl : public Snapshot {
|
||||||
public:
|
public:
|
||||||
SequenceNumber number_; // const after creation
|
SnapshotImpl(SequenceNumber sequence_number)
|
||||||
|
: sequence_number_(sequence_number) {}
|
||||||
|
|
||||||
|
SequenceNumber sequence_number() const { return sequence_number_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class SnapshotList;
|
friend class SnapshotList;
|
||||||
|
|
||||||
// SnapshotImpl is kept in a doubly-linked circular list
|
// SnapshotImpl is kept in a doubly-linked circular list. The SnapshotList
|
||||||
|
// implementation operates on the next/previous fields direcly.
|
||||||
SnapshotImpl* prev_;
|
SnapshotImpl* prev_;
|
||||||
SnapshotImpl* next_;
|
SnapshotImpl* next_;
|
||||||
|
|
||||||
SnapshotList* list_; // just for sanity checks
|
const SequenceNumber sequence_number_;
|
||||||
|
|
||||||
|
#if !defined(NDEBUG)
|
||||||
|
SnapshotList* list_ = nullptr;
|
||||||
|
#endif // !defined(NDEBUG)
|
||||||
};
|
};
|
||||||
|
|
||||||
class SnapshotList {
|
class SnapshotList {
|
||||||
public:
|
public:
|
||||||
SnapshotList() {
|
SnapshotList() : head_(0) {
|
||||||
list_.prev_ = &list_;
|
head_.prev_ = &head_;
|
||||||
list_.next_ = &list_;
|
head_.next_ = &head_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty() const { return list_.next_ == &list_; }
|
bool empty() const { return head_.next_ == &head_; }
|
||||||
SnapshotImpl* oldest() const { assert(!empty()); return list_.next_; }
|
SnapshotImpl* oldest() const { assert(!empty()); return head_.next_; }
|
||||||
SnapshotImpl* newest() const { assert(!empty()); return list_.prev_; }
|
SnapshotImpl* newest() const { assert(!empty()); return head_.prev_; }
|
||||||
|
|
||||||
const SnapshotImpl* New(SequenceNumber seq) {
|
// Creates a SnapshotImpl and appends it to the end of the list.
|
||||||
SnapshotImpl* s = new SnapshotImpl;
|
SnapshotImpl* New(SequenceNumber sequence_number) {
|
||||||
s->number_ = seq;
|
assert(empty() || newest()->sequence_number_ <= sequence_number);
|
||||||
s->list_ = this;
|
|
||||||
s->next_ = &list_;
|
SnapshotImpl* snapshot = new SnapshotImpl(sequence_number);
|
||||||
s->prev_ = list_.prev_;
|
|
||||||
s->prev_->next_ = s;
|
#if !defined(NDEBUG)
|
||||||
s->next_->prev_ = s;
|
snapshot->list_ = this;
|
||||||
return s;
|
#endif // !defined(NDEBUG)
|
||||||
|
snapshot->next_ = &head_;
|
||||||
|
snapshot->prev_ = head_.prev_;
|
||||||
|
snapshot->prev_->next_ = snapshot;
|
||||||
|
snapshot->next_->prev_ = snapshot;
|
||||||
|
return snapshot;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Delete(const SnapshotImpl* s) {
|
// Removes a SnapshotImpl from this list.
|
||||||
assert(s->list_ == this);
|
//
|
||||||
s->prev_->next_ = s->next_;
|
// The snapshot must have been created by calling New() on this list.
|
||||||
s->next_->prev_ = s->prev_;
|
//
|
||||||
delete s;
|
// The snapshot pointer should not be const, because its memory is
|
||||||
|
// deallocated. However, that would force us to change DB::ReleaseSnapshot(),
|
||||||
|
// which is in the API, and currently takes a const Snapshot.
|
||||||
|
void Delete(const SnapshotImpl* snapshot) {
|
||||||
|
#if !defined(NDEBUG)
|
||||||
|
assert(snapshot->list_ == this);
|
||||||
|
#endif // !defined(NDEBUG)
|
||||||
|
snapshot->prev_->next_ = snapshot->next_;
|
||||||
|
snapshot->next_->prev_ = snapshot->prev_;
|
||||||
|
delete snapshot;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Dummy head of doubly-linked list of snapshots
|
// Dummy head of doubly-linked list of snapshots
|
||||||
SnapshotImpl list_;
|
SnapshotImpl head_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace leveldb
|
} // namespace leveldb
|
||||||
|
Loading…
Reference in New Issue
Block a user