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
15namespace rocksdb {
16
17Cleanable::Cleanable() {
18 cleanup_.function = nullptr;
19 cleanup_.next = nullptr;
20}
21
22Cleanable::~Cleanable() { DoCleanup(); }
23
24Cleanable::Cleanable(Cleanable&& other) {
25 *this = std::move(other);
26}
27
28Cleanable& 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.
53void 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
70void 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
83void 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
98Status 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
109namespace {
110class 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
134class 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
159Iterator* NewEmptyIterator() {
160 return new EmptyIterator(Status::OK());
161}
162
163Iterator* NewErrorIterator(const Status& status) {
164 return new EmptyIterator(status);
165}
166
167InternalIterator* NewEmptyInternalIterator() {
168 return new EmptyInternalIterator(Status::OK());
169}
170
171InternalIterator* 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
180InternalIterator* NewErrorInternalIterator(const Status& status) {
181 return new EmptyInternalIterator(status);
182}
183
184InternalIterator* 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