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 "rocksdb/iterator.h"
11 #include "memory/arena.h"
12 #include "table/internal_iterator.h"
13 #include "table/iterator_wrapper.h"
14 
15 namespace ROCKSDB_NAMESPACE {
16 
Cleanable()17 Cleanable::Cleanable() {
18   cleanup_.function = nullptr;
19   cleanup_.next = nullptr;
20 }
21 
~Cleanable()22 Cleanable::~Cleanable() { DoCleanup(); }
23 
Cleanable(Cleanable && other)24 Cleanable::Cleanable(Cleanable&& other) {
25   *this = std::move(other);
26 }
27 
operator =(Cleanable && other)28 Cleanable& Cleanable::operator=(Cleanable&& other) {
29   if (this != &other) {
30     cleanup_ = other.cleanup_;
31     other.cleanup_.function = nullptr;
32     other.cleanup_.next = nullptr;
33   }
34   return *this;
35 }
36 
37 // If the entire linked list was on heap we could have simply add attach one
38 // link list to another. However the head is an embeded object to avoid the cost
39 // of creating objects for most of the use cases when the Cleanable has only one
40 // Cleanup to do. We could put evernything on heap if benchmarks show no
41 // negative impact on performance.
42 // Also we need to iterate on the linked list since there is no pointer to the
43 // tail. We can add the tail pointer but maintainin it might negatively impact
44 // the perforamnce for the common case of one cleanup where tail pointer is not
45 // needed. Again benchmarks could clarify that.
46 // Even without a tail pointer we could iterate on the list, find the tail, and
47 // have only that node updated without the need to insert the Cleanups one by
48 // one. This however would be redundant when the source Cleanable has one or a
49 // few Cleanups which is the case most of the time.
50 // TODO(myabandeh): if the list is too long we should maintain a tail pointer
51 // and have the entire list (minus the head that has to be inserted separately)
52 // merged with the target linked list at once.
DelegateCleanupsTo(Cleanable * other)53 void Cleanable::DelegateCleanupsTo(Cleanable* other) {
54   assert(other != nullptr);
55   if (cleanup_.function == nullptr) {
56     return;
57   }
58   Cleanup* c = &cleanup_;
59   other->RegisterCleanup(c->function, c->arg1, c->arg2);
60   c = c->next;
61   while (c != nullptr) {
62     Cleanup* next = c->next;
63     other->RegisterCleanup(c);
64     c = next;
65   }
66   cleanup_.function = nullptr;
67   cleanup_.next = nullptr;
68 }
69 
RegisterCleanup(Cleanable::Cleanup * c)70 void Cleanable::RegisterCleanup(Cleanable::Cleanup* c) {
71   assert(c != nullptr);
72   if (cleanup_.function == nullptr) {
73     cleanup_.function = c->function;
74     cleanup_.arg1 = c->arg1;
75     cleanup_.arg2 = c->arg2;
76     delete c;
77   } else {
78     c->next = cleanup_.next;
79     cleanup_.next = c;
80   }
81 }
82 
RegisterCleanup(CleanupFunction func,void * arg1,void * arg2)83 void Cleanable::RegisterCleanup(CleanupFunction func, void* arg1, void* arg2) {
84   assert(func != nullptr);
85   Cleanup* c;
86   if (cleanup_.function == nullptr) {
87     c = &cleanup_;
88   } else {
89     c = new Cleanup;
90     c->next = cleanup_.next;
91     cleanup_.next = c;
92   }
93   c->function = func;
94   c->arg1 = arg1;
95   c->arg2 = arg2;
96 }
97 
GetProperty(std::string prop_name,std::string * prop)98 Status Iterator::GetProperty(std::string prop_name, std::string* prop) {
99   if (prop == nullptr) {
100     return Status::InvalidArgument("prop is nullptr");
101   }
102   if (prop_name == "rocksdb.iterator.is-key-pinned") {
103     *prop = "0";
104     return Status::OK();
105   }
106   return Status::InvalidArgument("Unidentified property.");
107 }
108 
109 namespace {
110 class EmptyIterator : public Iterator {
111  public:
EmptyIterator(const Status & s)112   explicit EmptyIterator(const Status& s) : status_(s) { }
Valid() const113   bool Valid() const override { return false; }
Seek(const Slice &)114   void Seek(const Slice& /*target*/) override {}
SeekForPrev(const Slice &)115   void SeekForPrev(const Slice& /*target*/) override {}
SeekToFirst()116   void SeekToFirst() override {}
SeekToLast()117   void SeekToLast() override {}
Next()118   void Next() override { assert(false); }
Prev()119   void Prev() override { assert(false); }
key() const120   Slice key() const override {
121     assert(false);
122     return Slice();
123   }
value() const124   Slice value() const override {
125     assert(false);
126     return Slice();
127   }
status() const128   Status status() const override { return status_; }
129 
130  private:
131   Status status_;
132 };
133 
134 template <class TValue = Slice>
135 class EmptyInternalIterator : public InternalIteratorBase<TValue> {
136  public:
EmptyInternalIterator(const Status & s)137   explicit EmptyInternalIterator(const Status& s) : status_(s) {}
Valid() const138   bool Valid() const override { return false; }
Seek(const Slice &)139   void Seek(const Slice& /*target*/) override {}
SeekForPrev(const Slice &)140   void SeekForPrev(const Slice& /*target*/) override {}
SeekToFirst()141   void SeekToFirst() override {}
SeekToLast()142   void SeekToLast() override {}
Next()143   void Next() override { assert(false); }
Prev()144   void Prev() override { assert(false); }
key() const145   Slice key() const override {
146     assert(false);
147     return Slice();
148   }
value() const149   TValue value() const override {
150     assert(false);
151     return TValue();
152   }
status() const153   Status status() const override { return status_; }
154 
155  private:
156   Status status_;
157 };
158 }  // namespace
159 
NewEmptyIterator()160 Iterator* NewEmptyIterator() { return new EmptyIterator(Status::OK()); }
161 
NewErrorIterator(const Status & status)162 Iterator* NewErrorIterator(const Status& status) {
163   return new EmptyIterator(status);
164 }
165 
166 template <class TValue>
NewErrorInternalIterator(const Status & status)167 InternalIteratorBase<TValue>* NewErrorInternalIterator(const Status& status) {
168   return new EmptyInternalIterator<TValue>(status);
169 }
170 template InternalIteratorBase<IndexValue>* NewErrorInternalIterator(
171     const Status& status);
172 template InternalIteratorBase<Slice>* NewErrorInternalIterator(
173     const Status& status);
174 
175 template <class TValue>
NewErrorInternalIterator(const Status & status,Arena * arena)176 InternalIteratorBase<TValue>* NewErrorInternalIterator(const Status& status,
177                                                        Arena* arena) {
178   if (arena == nullptr) {
179     return NewErrorInternalIterator<TValue>(status);
180   } else {
181     auto mem = arena->AllocateAligned(sizeof(EmptyInternalIterator<TValue>));
182     return new (mem) EmptyInternalIterator<TValue>(status);
183   }
184 }
185 template InternalIteratorBase<IndexValue>* NewErrorInternalIterator(
186     const Status& status, Arena* arena);
187 template InternalIteratorBase<Slice>* NewErrorInternalIterator(
188     const Status& status, Arena* arena);
189 
190 template <class TValue>
NewEmptyInternalIterator()191 InternalIteratorBase<TValue>* NewEmptyInternalIterator() {
192   return new EmptyInternalIterator<TValue>(Status::OK());
193 }
194 template InternalIteratorBase<IndexValue>* NewEmptyInternalIterator();
195 template InternalIteratorBase<Slice>* NewEmptyInternalIterator();
196 
197 template <class TValue>
NewEmptyInternalIterator(Arena * arena)198 InternalIteratorBase<TValue>* NewEmptyInternalIterator(Arena* arena) {
199   if (arena == nullptr) {
200     return NewEmptyInternalIterator<TValue>();
201   } else {
202     auto mem = arena->AllocateAligned(sizeof(EmptyInternalIterator<TValue>));
203     return new (mem) EmptyInternalIterator<TValue>(Status::OK());
204   }
205 }
206 template InternalIteratorBase<IndexValue>* NewEmptyInternalIterator(
207     Arena* arena);
208 template InternalIteratorBase<Slice>* NewEmptyInternalIterator(Arena* arena);
209 
210 }  // namespace ROCKSDB_NAMESPACE
211