| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
- // This source code is licensed under both the GPLv2 (found in the
- // COPYING file in the root directory) and Apache 2.0 License
- // (found in the LICENSE.Apache file in the root directory).
- //
- // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file. See the AUTHORS file for names of contributors.
- #pragma once
- #include <vector>
- #include "rocksdb/db.h"
- namespace ROCKSDB_NAMESPACE {
- class SnapshotList;
- // Snapshots are kept in a doubly-linked list in the DB.
- // Each SnapshotImpl corresponds to a particular sequence number.
- class SnapshotImpl : public Snapshot {
- public:
- SequenceNumber number_; // const after creation
- // It indicates the smallest uncommitted data at the time the snapshot was
- // taken. This is currently used by WritePrepared transactions to limit the
- // scope of queries to IsInSnpashot.
- SequenceNumber min_uncommitted_ = kMinUnCommittedSeq;
- virtual SequenceNumber GetSequenceNumber() const override { return number_; }
- private:
- friend class SnapshotList;
- // SnapshotImpl is kept in a doubly-linked circular list
- SnapshotImpl* prev_;
- SnapshotImpl* next_;
- SnapshotList* list_; // just for sanity checks
- int64_t unix_time_;
- // Will this snapshot be used by a Transaction to do write-conflict checking?
- bool is_write_conflict_boundary_;
- };
- class SnapshotList {
- public:
- SnapshotList() {
- list_.prev_ = &list_;
- list_.next_ = &list_;
- list_.number_ = 0xFFFFFFFFL; // placeholder marker, for debugging
- // Set all the variables to make UBSAN happy.
- list_.list_ = nullptr;
- list_.unix_time_ = 0;
- list_.is_write_conflict_boundary_ = false;
- count_ = 0;
- }
- // No copy-construct.
- SnapshotList(const SnapshotList&) = delete;
- bool empty() const { return list_.next_ == &list_; }
- SnapshotImpl* oldest() const { assert(!empty()); return list_.next_; }
- SnapshotImpl* newest() const { assert(!empty()); return list_.prev_; }
- SnapshotImpl* New(SnapshotImpl* s, SequenceNumber seq, uint64_t unix_time,
- bool is_write_conflict_boundary) {
- s->number_ = seq;
- s->unix_time_ = unix_time;
- s->is_write_conflict_boundary_ = is_write_conflict_boundary;
- s->list_ = this;
- s->next_ = &list_;
- s->prev_ = list_.prev_;
- s->prev_->next_ = s;
- s->next_->prev_ = s;
- count_++;
- return s;
- }
- // Do not responsible to free the object.
- void Delete(const SnapshotImpl* s) {
- assert(s->list_ == this);
- s->prev_->next_ = s->next_;
- s->next_->prev_ = s->prev_;
- count_--;
- }
- // retrieve all snapshot numbers up until max_seq. They are sorted in
- // ascending order (with no duplicates).
- std::vector<SequenceNumber> GetAll(
- SequenceNumber* oldest_write_conflict_snapshot = nullptr,
- const SequenceNumber& max_seq = kMaxSequenceNumber) const {
- std::vector<SequenceNumber> ret;
- GetAll(&ret, oldest_write_conflict_snapshot, max_seq);
- return ret;
- }
- void GetAll(std::vector<SequenceNumber>* snap_vector,
- SequenceNumber* oldest_write_conflict_snapshot = nullptr,
- const SequenceNumber& max_seq = kMaxSequenceNumber) const {
- std::vector<SequenceNumber>& ret = *snap_vector;
- // So far we have no use case that would pass a non-empty vector
- assert(ret.size() == 0);
- if (oldest_write_conflict_snapshot != nullptr) {
- *oldest_write_conflict_snapshot = kMaxSequenceNumber;
- }
- if (empty()) {
- return;
- }
- const SnapshotImpl* s = &list_;
- while (s->next_ != &list_) {
- if (s->next_->number_ > max_seq) {
- break;
- }
- // Avoid duplicates
- if (ret.empty() || ret.back() != s->next_->number_) {
- ret.push_back(s->next_->number_);
- }
- if (oldest_write_conflict_snapshot != nullptr &&
- *oldest_write_conflict_snapshot == kMaxSequenceNumber &&
- s->next_->is_write_conflict_boundary_) {
- // If this is the first write-conflict boundary snapshot in the list,
- // it is the oldest
- *oldest_write_conflict_snapshot = s->next_->number_;
- }
- s = s->next_;
- }
- return;
- }
- // get the sequence number of the most recent snapshot
- SequenceNumber GetNewest() {
- if (empty()) {
- return 0;
- }
- return newest()->number_;
- }
- int64_t GetOldestSnapshotTime() const {
- if (empty()) {
- return 0;
- } else {
- return oldest()->unix_time_;
- }
- }
- int64_t GetOldestSnapshotSequence() const {
- if (empty()) {
- return 0;
- } else {
- return oldest()->GetSequenceNumber();
- }
- }
- uint64_t count() const { return count_; }
- private:
- // Dummy head of doubly-linked list of snapshots
- SnapshotImpl list_;
- uint64_t count_;
- };
- } // namespace ROCKSDB_NAMESPACE
|