iterator.cc 6.7 KB

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