]>
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" | |
f67539c2 | 11 | #include "memory/arena.h" |
7c673cae FG |
12 | #include "table/internal_iterator.h" |
13 | #include "table/iterator_wrapper.h" | |
7c673cae | 14 | |
f67539c2 | 15 | namespace ROCKSDB_NAMESPACE { |
7c673cae FG |
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 | } | |
494da23a | 106 | return Status::InvalidArgument("Unidentified property."); |
7c673cae FG |
107 | } |
108 | ||
109 | namespace { | |
110 | class EmptyIterator : public Iterator { | |
111 | public: | |
112 | explicit EmptyIterator(const Status& s) : status_(s) { } | |
494da23a TL |
113 | bool Valid() const override { return false; } |
114 | void Seek(const Slice& /*target*/) override {} | |
115 | void SeekForPrev(const Slice& /*target*/) override {} | |
116 | void SeekToFirst() override {} | |
117 | void SeekToLast() override {} | |
118 | void Next() override { assert(false); } | |
119 | void Prev() override { assert(false); } | |
7c673cae FG |
120 | Slice key() const override { |
121 | assert(false); | |
122 | return Slice(); | |
123 | } | |
124 | Slice value() const override { | |
125 | assert(false); | |
126 | return Slice(); | |
127 | } | |
494da23a | 128 | Status status() const override { return status_; } |
7c673cae FG |
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) {} | |
494da23a TL |
138 | bool Valid() const override { return false; } |
139 | void Seek(const Slice& /*target*/) override {} | |
140 | void SeekForPrev(const Slice& /*target*/) override {} | |
141 | void SeekToFirst() override {} | |
142 | void SeekToLast() override {} | |
143 | void Next() override { assert(false); } | |
144 | void Prev() override { assert(false); } | |
7c673cae FG |
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 | 152 | } |
494da23a | 153 | Status status() const override { return status_; } |
7c673cae FG |
154 | |
155 | private: | |
156 | Status status_; | |
157 | }; | |
158 | } // namespace | |
159 | ||
494da23a | 160 | Iterator* NewEmptyIterator() { return new EmptyIterator(Status::OK()); } |
7c673cae FG |
161 | |
162 | Iterator* NewErrorIterator(const Status& status) { | |
163 | return new EmptyIterator(status); | |
164 | } | |
165 | ||
11fdf7f2 TL |
166 | template <class TValue> |
167 | InternalIteratorBase<TValue>* NewErrorInternalIterator(const Status& status) { | |
168 | return new EmptyInternalIterator<TValue>(status); | |
7c673cae | 169 | } |
f67539c2 | 170 | template InternalIteratorBase<IndexValue>* NewErrorInternalIterator( |
11fdf7f2 TL |
171 | const Status& status); |
172 | template InternalIteratorBase<Slice>* NewErrorInternalIterator( | |
173 | const Status& status); | |
174 | ||
175 | template <class TValue> | |
176 | InternalIteratorBase<TValue>* NewErrorInternalIterator(const Status& status, | |
177 | Arena* arena) { | |
7c673cae | 178 | if (arena == nullptr) { |
11fdf7f2 | 179 | return NewErrorInternalIterator<TValue>(status); |
7c673cae | 180 | } else { |
494da23a | 181 | auto mem = arena->AllocateAligned(sizeof(EmptyInternalIterator<TValue>)); |
11fdf7f2 | 182 | return new (mem) EmptyInternalIterator<TValue>(status); |
7c673cae FG |
183 | } |
184 | } | |
f67539c2 | 185 | template InternalIteratorBase<IndexValue>* NewErrorInternalIterator( |
11fdf7f2 TL |
186 | const Status& status, Arena* arena); |
187 | template InternalIteratorBase<Slice>* NewErrorInternalIterator( | |
188 | const Status& status, Arena* arena); | |
189 | ||
190 | template <class TValue> | |
191 | InternalIteratorBase<TValue>* NewEmptyInternalIterator() { | |
192 | return new EmptyInternalIterator<TValue>(Status::OK()); | |
7c673cae | 193 | } |
f67539c2 | 194 | template InternalIteratorBase<IndexValue>* NewEmptyInternalIterator(); |
11fdf7f2 | 195 | template InternalIteratorBase<Slice>* NewEmptyInternalIterator(); |
7c673cae | 196 | |
11fdf7f2 TL |
197 | template <class TValue> |
198 | InternalIteratorBase<TValue>* NewEmptyInternalIterator(Arena* arena) { | |
7c673cae | 199 | if (arena == nullptr) { |
11fdf7f2 | 200 | return NewEmptyInternalIterator<TValue>(); |
7c673cae | 201 | } else { |
494da23a | 202 | auto mem = arena->AllocateAligned(sizeof(EmptyInternalIterator<TValue>)); |
11fdf7f2 | 203 | return new (mem) EmptyInternalIterator<TValue>(Status::OK()); |
7c673cae FG |
204 | } |
205 | } | |
f67539c2 | 206 | template InternalIteratorBase<IndexValue>* NewEmptyInternalIterator( |
11fdf7f2 TL |
207 | Arena* arena); |
208 | template InternalIteratorBase<Slice>* NewEmptyInternalIterator(Arena* arena); | |
7c673cae | 209 | |
f67539c2 | 210 | } // namespace ROCKSDB_NAMESPACE |