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 "table/internal_iterator.h" |
12 | #include "table/iterator_wrapper.h" |
13 | #include "util/arena.h" |
14 | |
15 | namespace rocksdb { |
16 | |
17 | Cleanable::Cleanable() { |
18 | cleanup_.function = nullptr; |
19 | cleanup_.next = nullptr; |
20 | } |
21 | |
22 | Cleanable::~Cleanable() { DoCleanup(); } |
23 | |
24 | Cleanable::Cleanable(Cleanable&& other) { |
25 | *this = std::move(other); |
26 | } |
27 | |
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. |
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 | |
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 | |
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 | |
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("Undentified property." ); |
107 | } |
108 | |
109 | namespace { |
110 | class EmptyIterator : public Iterator { |
111 | public: |
112 | explicit EmptyIterator(const Status& s) : status_(s) { } |
113 | virtual bool Valid() const override { return false; } |
114 | virtual void Seek(const Slice& target) override {} |
115 | virtual void SeekForPrev(const Slice& target) override {} |
116 | virtual void SeekToFirst() override {} |
117 | virtual void SeekToLast() override {} |
118 | virtual void Next() override { assert(false); } |
119 | virtual void Prev() override { assert(false); } |
120 | Slice key() const override { |
121 | assert(false); |
122 | return Slice(); |
123 | } |
124 | Slice value() const override { |
125 | assert(false); |
126 | return Slice(); |
127 | } |
128 | virtual Status status() const override { return status_; } |
129 | |
130 | private: |
131 | Status status_; |
132 | }; |
133 | |
134 | class EmptyInternalIterator : public InternalIterator { |
135 | public: |
136 | explicit EmptyInternalIterator(const Status& s) : status_(s) {} |
137 | virtual bool Valid() const override { return false; } |
138 | virtual void Seek(const Slice& target) override {} |
139 | virtual void SeekForPrev(const Slice& target) override {} |
140 | virtual void SeekToFirst() override {} |
141 | virtual void SeekToLast() override {} |
142 | virtual void Next() override { assert(false); } |
143 | virtual void Prev() override { assert(false); } |
144 | Slice key() const override { |
145 | assert(false); |
146 | return Slice(); |
147 | } |
148 | Slice value() const override { |
149 | assert(false); |
150 | return Slice(); |
151 | } |
152 | virtual Status status() const override { return status_; } |
153 | |
154 | private: |
155 | Status status_; |
156 | }; |
157 | } // namespace |
158 | |
159 | Iterator* NewEmptyIterator() { |
160 | return new EmptyIterator(Status::OK()); |
161 | } |
162 | |
163 | Iterator* NewErrorIterator(const Status& status) { |
164 | return new EmptyIterator(status); |
165 | } |
166 | |
167 | InternalIterator* NewEmptyInternalIterator() { |
168 | return new EmptyInternalIterator(Status::OK()); |
169 | } |
170 | |
171 | InternalIterator* NewEmptyInternalIterator(Arena* arena) { |
172 | if (arena == nullptr) { |
173 | return NewEmptyInternalIterator(); |
174 | } else { |
175 | auto mem = arena->AllocateAligned(sizeof(EmptyIterator)); |
176 | return new (mem) EmptyInternalIterator(Status::OK()); |
177 | } |
178 | } |
179 | |
180 | InternalIterator* NewErrorInternalIterator(const Status& status) { |
181 | return new EmptyInternalIterator(status); |
182 | } |
183 | |
184 | InternalIterator* NewErrorInternalIterator(const Status& status, Arena* arena) { |
185 | if (arena == nullptr) { |
186 | return NewErrorInternalIterator(status); |
187 | } else { |
188 | auto mem = arena->AllocateAligned(sizeof(EmptyIterator)); |
189 | return new (mem) EmptyInternalIterator(status); |
190 | } |
191 | } |
192 | |
193 | } // namespace rocksdb |
194 | |