]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
11fdf7f2 TL |
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). | |
7c673cae FG |
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 | ||
11fdf7f2 TL |
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 | ||
7c673cae FG |
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; } | |
11fdf7f2 TL |
114 | virtual void Seek(const Slice& /*target*/) override {} |
115 | virtual void SeekForPrev(const Slice& /*target*/) override {} | |
7c673cae FG |
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 | ||
11fdf7f2 TL |
134 | template <class TValue = Slice> |
135 | class EmptyInternalIterator : public InternalIteratorBase<TValue> { | |
7c673cae FG |
136 | public: |
137 | explicit EmptyInternalIterator(const Status& s) : status_(s) {} | |
138 | virtual bool Valid() const override { return false; } | |
11fdf7f2 TL |
139 | virtual void Seek(const Slice& /*target*/) override {} |
140 | virtual void SeekForPrev(const Slice& /*target*/) override {} | |
7c673cae FG |
141 | virtual void SeekToFirst() override {} |
142 | virtual void SeekToLast() override {} | |
143 | virtual void Next() override { assert(false); } | |
144 | virtual void Prev() override { assert(false); } | |
145 | Slice key() const override { | |
146 | assert(false); | |
147 | return Slice(); | |
148 | } | |
11fdf7f2 | 149 | TValue value() const override { |
7c673cae | 150 | assert(false); |
11fdf7f2 | 151 | return TValue(); |
7c673cae FG |
152 | } |
153 | virtual Status status() const override { return status_; } | |
154 | ||
155 | private: | |
156 | Status status_; | |
157 | }; | |
158 | } // namespace | |
159 | ||
160 | Iterator* NewEmptyIterator() { | |
161 | return new EmptyIterator(Status::OK()); | |
162 | } | |
163 | ||
164 | Iterator* NewErrorIterator(const Status& status) { | |
165 | return new EmptyIterator(status); | |
166 | } | |
167 | ||
11fdf7f2 TL |
168 | template <class TValue> |
169 | InternalIteratorBase<TValue>* NewErrorInternalIterator(const Status& status) { | |
170 | return new EmptyInternalIterator<TValue>(status); | |
7c673cae | 171 | } |
11fdf7f2 TL |
172 | template InternalIteratorBase<BlockHandle>* NewErrorInternalIterator( |
173 | const Status& status); | |
174 | template InternalIteratorBase<Slice>* NewErrorInternalIterator( | |
175 | const Status& status); | |
176 | ||
177 | template <class TValue> | |
178 | InternalIteratorBase<TValue>* NewErrorInternalIterator(const Status& status, | |
179 | Arena* arena) { | |
7c673cae | 180 | if (arena == nullptr) { |
11fdf7f2 | 181 | return NewErrorInternalIterator<TValue>(status); |
7c673cae FG |
182 | } else { |
183 | auto mem = arena->AllocateAligned(sizeof(EmptyIterator)); | |
11fdf7f2 | 184 | return new (mem) EmptyInternalIterator<TValue>(status); |
7c673cae FG |
185 | } |
186 | } | |
11fdf7f2 TL |
187 | template InternalIteratorBase<BlockHandle>* NewErrorInternalIterator( |
188 | const Status& status, Arena* arena); | |
189 | template InternalIteratorBase<Slice>* NewErrorInternalIterator( | |
190 | const Status& status, Arena* arena); | |
191 | ||
192 | template <class TValue> | |
193 | InternalIteratorBase<TValue>* NewEmptyInternalIterator() { | |
194 | return new EmptyInternalIterator<TValue>(Status::OK()); | |
7c673cae | 195 | } |
11fdf7f2 TL |
196 | template InternalIteratorBase<BlockHandle>* NewEmptyInternalIterator(); |
197 | template InternalIteratorBase<Slice>* NewEmptyInternalIterator(); | |
7c673cae | 198 | |
11fdf7f2 TL |
199 | template <class TValue> |
200 | InternalIteratorBase<TValue>* NewEmptyInternalIterator(Arena* arena) { | |
7c673cae | 201 | if (arena == nullptr) { |
11fdf7f2 | 202 | return NewEmptyInternalIterator<TValue>(); |
7c673cae FG |
203 | } else { |
204 | auto mem = arena->AllocateAligned(sizeof(EmptyIterator)); | |
11fdf7f2 | 205 | return new (mem) EmptyInternalIterator<TValue>(Status::OK()); |
7c673cae FG |
206 | } |
207 | } | |
11fdf7f2 TL |
208 | template InternalIteratorBase<BlockHandle>* NewEmptyInternalIterator( |
209 | Arena* arena); | |
210 | template InternalIteratorBase<Slice>* NewEmptyInternalIterator(Arena* arena); | |
7c673cae FG |
211 | |
212 | } // namespace rocksdb |