1 //  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2 //  This source code is licensed under both the GPLv2 (found in the
3 //  COPYING file in the root directory) and Apache 2.0 License
4 //  (found in the LICENSE.Apache file in the root directory).
5 //
6 // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
7 // Use of this source code is governed by a BSD-style license that can be
8 // found in the LICENSE file. See the AUTHORS file for names of contributors.
9 
10 #include "db/arena_wrapped_db_iter.h"
11 #include "memory/arena.h"
12 #include "rocksdb/env.h"
13 #include "rocksdb/iterator.h"
14 #include "rocksdb/options.h"
15 #include "table/internal_iterator.h"
16 #include "table/iterator_wrapper.h"
17 #include "util/user_comparator_wrapper.h"
18 
19 namespace ROCKSDB_NAMESPACE {
20 
GetProperty(std::string prop_name,std::string * prop)21 Status ArenaWrappedDBIter::GetProperty(std::string prop_name,
22                                        std::string* prop) {
23   if (prop_name == "rocksdb.iterator.super-version-number") {
24     // First try to pass the value returned from inner iterator.
25     if (!db_iter_->GetProperty(prop_name, prop).ok()) {
26       *prop = ToString(sv_number_);
27     }
28     return Status::OK();
29   }
30   return db_iter_->GetProperty(prop_name, prop);
31 }
32 
Init(Env * env,const ReadOptions & read_options,const ImmutableCFOptions & cf_options,const MutableCFOptions & mutable_cf_options,const SequenceNumber & sequence,uint64_t max_sequential_skip_in_iteration,uint64_t version_number,ReadCallback * read_callback,DBImpl * db_impl,ColumnFamilyData * cfd,bool allow_blob,bool allow_refresh)33 void ArenaWrappedDBIter::Init(Env* env, const ReadOptions& read_options,
34                               const ImmutableCFOptions& cf_options,
35                               const MutableCFOptions& mutable_cf_options,
36                               const SequenceNumber& sequence,
37                               uint64_t max_sequential_skip_in_iteration,
38                               uint64_t version_number,
39                               ReadCallback* read_callback, DBImpl* db_impl,
40                               ColumnFamilyData* cfd, bool allow_blob,
41                               bool allow_refresh) {
42   auto mem = arena_.AllocateAligned(sizeof(DBIter));
43   db_iter_ = new (mem) DBIter(env, read_options, cf_options, mutable_cf_options,
44                               cf_options.user_comparator, nullptr, sequence,
45                               true, max_sequential_skip_in_iteration,
46                               read_callback, db_impl, cfd, allow_blob);
47   sv_number_ = version_number;
48   allow_refresh_ = allow_refresh;
49 }
50 
Refresh()51 Status ArenaWrappedDBIter::Refresh() {
52   if (cfd_ == nullptr || db_impl_ == nullptr || !allow_refresh_) {
53     return Status::NotSupported("Creating renew iterator is not allowed.");
54   }
55   assert(db_iter_ != nullptr);
56   // TODO(yiwu): For last_seq_same_as_publish_seq_==false, this is not the
57   // correct behavior. Will be corrected automatically when we take a snapshot
58   // here for the case of WritePreparedTxnDB.
59   SequenceNumber latest_seq = db_impl_->GetLatestSequenceNumber();
60   uint64_t cur_sv_number = cfd_->GetSuperVersionNumber();
61   if (sv_number_ != cur_sv_number) {
62     Env* env = db_iter_->env();
63     db_iter_->~DBIter();
64     arena_.~Arena();
65     new (&arena_) Arena();
66 
67     SuperVersion* sv = cfd_->GetReferencedSuperVersion(db_impl_);
68     if (read_callback_) {
69       read_callback_->Refresh(latest_seq);
70     }
71     Init(env, read_options_, *(cfd_->ioptions()), sv->mutable_cf_options,
72          latest_seq, sv->mutable_cf_options.max_sequential_skip_in_iterations,
73          cur_sv_number, read_callback_, db_impl_, cfd_, allow_blob_,
74          allow_refresh_);
75 
76     InternalIterator* internal_iter = db_impl_->NewInternalIterator(
77         read_options_, cfd_, sv, &arena_, db_iter_->GetRangeDelAggregator(),
78         latest_seq);
79     SetIterUnderDBIter(internal_iter);
80   } else {
81     db_iter_->set_sequence(latest_seq);
82     db_iter_->set_valid(false);
83   }
84   return Status::OK();
85 }
86 
NewArenaWrappedDbIterator(Env * env,const ReadOptions & read_options,const ImmutableCFOptions & cf_options,const MutableCFOptions & mutable_cf_options,const SequenceNumber & sequence,uint64_t max_sequential_skip_in_iterations,uint64_t version_number,ReadCallback * read_callback,DBImpl * db_impl,ColumnFamilyData * cfd,bool allow_blob,bool allow_refresh)87 ArenaWrappedDBIter* NewArenaWrappedDbIterator(
88     Env* env, const ReadOptions& read_options,
89     const ImmutableCFOptions& cf_options,
90     const MutableCFOptions& mutable_cf_options, const SequenceNumber& sequence,
91     uint64_t max_sequential_skip_in_iterations, uint64_t version_number,
92     ReadCallback* read_callback, DBImpl* db_impl, ColumnFamilyData* cfd,
93     bool allow_blob, bool allow_refresh) {
94   ArenaWrappedDBIter* iter = new ArenaWrappedDBIter();
95   iter->Init(env, read_options, cf_options, mutable_cf_options, sequence,
96              max_sequential_skip_in_iterations, version_number, read_callback,
97              db_impl, cfd, allow_blob, allow_refresh);
98   if (db_impl != nullptr && cfd != nullptr && allow_refresh) {
99     iter->StoreRefreshInfo(read_options, db_impl, cfd, read_callback,
100                            allow_blob);
101   }
102 
103   return iter;
104 }
105 
106 }  // namespace ROCKSDB_NAMESPACE
107