db_iter.cc 35.3 KB
Newer Older
1
//  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2 3 4 5
//  This source code is licensed under the BSD-style license found in the
//  LICENSE file in the root directory of this source tree. An additional grant
//  of patent rights can be found in the PATENTS file in the same directory.
//
J
jorlow@chromium.org 已提交
6 7 8 9 10
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.

#include "db/db_iter.h"
11
#include <stdexcept>
12
#include <deque>
S
Stanislau Hlebik 已提交
13
#include <string>
S
Stanislau Hlebik 已提交
14
#include <limits>
J
jorlow@chromium.org 已提交
15 16

#include "db/dbformat.h"
17
#include "db/filename.h"
18
#include "db/merge_context.h"
19
#include "db/merge_helper.h"
20
#include "db/pinned_iterators_manager.h"
S
sdong 已提交
21
#include "port/port.h"
22 23 24
#include "rocksdb/env.h"
#include "rocksdb/iterator.h"
#include "rocksdb/merge_operator.h"
25
#include "rocksdb/options.h"
S
sdong 已提交
26
#include "table/internal_iterator.h"
27
#include "util/arena.h"
J
jorlow@chromium.org 已提交
28 29
#include "util/logging.h"
#include "util/mutexlock.h"
30
#include "util/perf_context_imp.h"
31
#include "util/string_util.h"
J
jorlow@chromium.org 已提交
32

33
namespace rocksdb {
J
jorlow@chromium.org 已提交
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54

#if 0
static void DumpInternalIter(Iterator* iter) {
  for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
    ParsedInternalKey k;
    if (!ParseInternalKey(iter->key(), &k)) {
      fprintf(stderr, "Corrupt '%s'\n", EscapeString(iter->key()).c_str());
    } else {
      fprintf(stderr, "@ '%s'\n", k.DebugString().c_str());
    }
  }
}
#endif

// Memtables and sstables that make the DB representation contain
// (userkey,seq,type) => uservalue entries.  DBIter
// combines multiple entries for the same userkey found in the DB
// representation into a single entry while accounting for sequence
// numbers, deletion markers, overwrites, etc.
class DBIter: public Iterator {
 public:
55
  // The following is grossly complicated. TODO: clean it up
J
jorlow@chromium.org 已提交
56 57 58 59 60 61 62 63 64 65
  // Which direction is the iterator currently moving?
  // (1) When moving forward, the internal iterator is positioned at
  //     the exact entry that yields this->key(), this->value()
  // (2) When moving backwards, the internal iterator is positioned
  //     just before all entries whose user key == this->key().
  enum Direction {
    kForward,
    kReverse
  };

66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
  // LocalStatistics contain Statistics counters that will be aggregated per
  // each iterator instance and then will be sent to the global statistics when
  // the iterator is destroyed.
  //
  // The purpose of this approach is to avoid perf regression happening
  // when multiple threads bump the atomic counters from a DBIter::Next().
  struct LocalStatistics {
    explicit LocalStatistics() { ResetCounters(); }

    void ResetCounters() {
      next_count_ = 0;
      next_found_count_ = 0;
      prev_count_ = 0;
      prev_found_count_ = 0;
      bytes_read_ = 0;
    }

    void BumpGlobalStatistics(Statistics* global_statistics) {
      RecordTick(global_statistics, NUMBER_DB_NEXT, next_count_);
      RecordTick(global_statistics, NUMBER_DB_NEXT_FOUND, next_found_count_);
      RecordTick(global_statistics, NUMBER_DB_PREV, prev_count_);
      RecordTick(global_statistics, NUMBER_DB_PREV_FOUND, prev_found_count_);
      RecordTick(global_statistics, ITER_BYTES_READ, bytes_read_);
      ResetCounters();
    }

    // Map to Tickers::NUMBER_DB_NEXT
    uint64_t next_count_;
    // Map to Tickers::NUMBER_DB_NEXT_FOUND
    uint64_t next_found_count_;
    // Map to Tickers::NUMBER_DB_PREV
    uint64_t prev_count_;
    // Map to Tickers::NUMBER_DB_PREV_FOUND
    uint64_t prev_found_count_;
    // Map to Tickers::ITER_BYTES_READ
    uint64_t bytes_read_;
  };

S
sdong 已提交
104 105
  DBIter(Env* env, const ImmutableCFOptions& ioptions, const Comparator* cmp,
         InternalIterator* iter, SequenceNumber s, bool arena_mode,
106
         uint64_t max_sequential_skip_in_iterations, uint64_t version_number,
107
         const Slice* iterate_upper_bound = nullptr,
108 109
         bool prefix_same_as_start = false, bool pin_data = false,
         bool total_order_seek = false)
110 111
      : arena_mode_(arena_mode),
        env_(env),
112
        logger_(ioptions.info_log),
J
jorlow@chromium.org 已提交
113
        user_comparator_(cmp),
114
        merge_operator_(ioptions.merge_operator),
J
jorlow@chromium.org 已提交
115 116
        iter_(iter),
        sequence_(s),
J
jorlow@chromium.org 已提交
117
        direction_(kForward),
118
        valid_(false),
119
        current_entry_is_merged_(false),
120
        statistics_(ioptions.statistics),
121
        version_number_(version_number),
122
        iterate_upper_bound_(iterate_upper_bound),
123
        prefix_same_as_start_(prefix_same_as_start),
124
        pin_thru_lifetime_(pin_data),
A
Andrew Kryczka 已提交
125
        total_order_seek_(total_order_seek),
A
Andrew Kryczka 已提交
126
        range_del_agg_(ioptions.internal_comparator, s) {
L
Lei Jin 已提交
127
    RecordTick(statistics_, NO_ITERATORS);
128 129
    prefix_extractor_ = ioptions.prefix_extractor;
    max_skip_ = max_sequential_skip_in_iterations;
130 131 132 133 134 135
    if (pin_thru_lifetime_) {
      pinned_iters_mgr_.StartPinning();
    }
    if (iter_) {
      iter_->SetPinnedItersMgr(&pinned_iters_mgr_);
    }
J
jorlow@chromium.org 已提交
136 137
  }
  virtual ~DBIter() {
138
    // Release pinned data if any
139 140 141
    if (pinned_iters_mgr_.PinningEnabled()) {
      pinned_iters_mgr_.ReleasePinnedData();
    }
142
    RecordTick(statistics_, NO_ITERATORS, -1);
143
    local_stats_.BumpGlobalStatistics(statistics_);
144 145 146
    if (!arena_mode_) {
      delete iter_;
    } else {
S
sdong 已提交
147
      iter_->~InternalIterator();
148 149
    }
  }
S
sdong 已提交
150
  virtual void SetIter(InternalIterator* iter) {
151 152
    assert(iter_ == nullptr);
    iter_ = iter;
153
    iter_->SetPinnedItersMgr(&pinned_iters_mgr_);
J
jorlow@chromium.org 已提交
154
  }
A
Andrew Kryczka 已提交
155 156 157 158
  virtual RangeDelAggregator* GetRangeDelAggregator() {
    return &range_del_agg_;
  }

I
Igor Sugak 已提交
159 160
  virtual bool Valid() const override { return valid_; }
  virtual Slice key() const override {
J
jorlow@chromium.org 已提交
161
    assert(valid_);
162
    return saved_key_.GetKey();
J
jorlow@chromium.org 已提交
163
  }
I
Igor Sugak 已提交
164
  virtual Slice value() const override {
J
jorlow@chromium.org 已提交
165
    assert(valid_);
166
    if (current_entry_is_merged_) {
167 168 169
      // If pinned_value_ is set then the result of merge operator is one of
      // the merge operands and we should return it.
      return pinned_value_.data() ? pinned_value_ : saved_value_;
170 171 172 173 174
    } else if (direction_ == kReverse) {
      return pinned_value_;
    } else {
      return iter_->value();
    }
J
jorlow@chromium.org 已提交
175
  }
I
Igor Sugak 已提交
176
  virtual Status status() const override {
J
jorlow@chromium.org 已提交
177 178 179 180 181 182
    if (status_.ok()) {
      return iter_->status();
    } else {
      return status_;
    }
  }
183 184 185 186 187 188

  virtual Status GetProperty(std::string prop_name,
                             std::string* prop) override {
    if (prop == nullptr) {
      return Status::InvalidArgument("prop is nullptr");
    }
189
    if (prop_name == "rocksdb.iterator.super-version-number") {
190 191 192 193 194 195
      // First try to pass the value returned from inner iterator.
      if (!iter_->GetProperty(prop_name, prop).ok()) {
        *prop = ToString(version_number_);
      }
      return Status::OK();
    } else if (prop_name == "rocksdb.iterator.is-key-pinned") {
196
      if (valid_) {
197
        *prop = (pin_thru_lifetime_ && saved_key_.IsKeyPinned()) ? "1" : "0";
198 199 200 201 202 203
      } else {
        *prop = "Iterator is not valid.";
      }
      return Status::OK();
    }
    return Status::InvalidArgument("Undentified property.");
204
  }
J
jorlow@chromium.org 已提交
205

I
Igor Sugak 已提交
206 207 208
  virtual void Next() override;
  virtual void Prev() override;
  virtual void Seek(const Slice& target) override;
A
Aaron Gao 已提交
209
  virtual void SeekForPrev(const Slice& target) override;
I
Igor Sugak 已提交
210 211
  virtual void SeekToFirst() override;
  virtual void SeekToLast() override;
J
jorlow@chromium.org 已提交
212

J
jorlow@chromium.org 已提交
213
 private:
214
  void ReverseToForward();
215
  void ReverseToBackward();
S
Stanislau Hlebik 已提交
216 217 218 219 220 221
  void PrevInternal();
  void FindParseableKey(ParsedInternalKey* ikey, Direction direction);
  bool FindValueForCurrentKey();
  bool FindValueForCurrentKeyUsingSeek();
  void FindPrevUserKey();
  void FindNextUserKey();
222 223
  inline void FindNextUserEntry(bool skipping, bool prefix_check);
  void FindNextUserEntryInternal(bool skipping, bool prefix_check);
J
jorlow@chromium.org 已提交
224
  bool ParseKey(ParsedInternalKey* key);
225
  void MergeValuesNewToOld();
J
jorlow@chromium.org 已提交
226

227 228 229 230 231 232 233 234 235 236
  // Temporarily pin the blocks that we encounter until ReleaseTempPinnedData()
  // is called
  void TempPinData() {
    if (!pin_thru_lifetime_) {
      pinned_iters_mgr_.StartPinning();
    }
  }

  // Release blocks pinned by TempPinData()
  void ReleaseTempPinnedData() {
237 238
    if (!pin_thru_lifetime_ && pinned_iters_mgr_.PinningEnabled()) {
      pinned_iters_mgr_.ReleasePinnedData();
239 240 241
    }
  }

J
jorlow@chromium.org 已提交
242 243 244 245 246 247 248 249 250
  inline void ClearSavedValue() {
    if (saved_value_.capacity() > 1048576) {
      std::string empty;
      swap(empty, saved_value_);
    } else {
      saved_value_.clear();
    }
  }

251
  const SliceTransform* prefix_extractor_;
252
  bool arena_mode_;
J
jorlow@chromium.org 已提交
253
  Env* const env_;
I
Igor Canadi 已提交
254
  Logger* logger_;
J
jorlow@chromium.org 已提交
255
  const Comparator* const user_comparator_;
256
  const MergeOperator* const merge_operator_;
S
sdong 已提交
257
  InternalIterator* iter_;
J
jorlow@chromium.org 已提交
258
  SequenceNumber const sequence_;
J
jorlow@chromium.org 已提交
259

J
jorlow@chromium.org 已提交
260
  Status status_;
S
Stanislau Hlebik 已提交
261 262
  IterKey saved_key_;
  std::string saved_value_;
263
  Slice pinned_value_;
J
jorlow@chromium.org 已提交
264
  Direction direction_;
J
jorlow@chromium.org 已提交
265
  bool valid_;
266
  bool current_entry_is_merged_;
267
  // for prefix seek mode to support prev()
268
  Statistics* statistics_;
269
  uint64_t max_skip_;
270
  uint64_t version_number_;
271
  const Slice* iterate_upper_bound_;
272 273 274
  IterKey prefix_start_buf_;
  Slice prefix_start_key_;
  const bool prefix_same_as_start_;
275 276 277
  // Means that we will pin all data blocks we read as long the Iterator
  // is not deleted, will be true if ReadOptions::pin_data is true
  const bool pin_thru_lifetime_;
278
  const bool total_order_seek_;
279
  // List of operands for merge operator.
280
  MergeContext merge_context_;
A
Andrew Kryczka 已提交
281
  RangeDelAggregator range_del_agg_;
282
  LocalStatistics local_stats_;
283
  PinnedIteratorsManager pinned_iters_mgr_;
J
jorlow@chromium.org 已提交
284 285 286 287 288 289 290 291 292

  // No copying allowed
  DBIter(const DBIter&);
  void operator=(const DBIter&);
};

inline bool DBIter::ParseKey(ParsedInternalKey* ikey) {
  if (!ParseInternalKey(iter_->key(), ikey)) {
    status_ = Status::Corruption("corrupted internal key in DBIter");
293 294
    Log(InfoLogLevel::ERROR_LEVEL,
        logger_, "corrupted internal key in DBIter: %s",
295
        iter_->key().ToString(true).c_str());
J
jorlow@chromium.org 已提交
296 297 298 299 300 301
    return false;
  } else {
    return true;
  }
}

J
jorlow@chromium.org 已提交
302 303 304
void DBIter::Next() {
  assert(valid_);

305 306
  // Release temporarily pinned blocks from last operation
  ReleaseTempPinnedData();
S
Stanislau Hlebik 已提交
307
  if (direction_ == kReverse) {
308
    ReverseToForward();
309 310 311 312 313 314 315
  } else if (iter_->Valid() && !current_entry_is_merged_) {
    // If the current value is not a merge, the iter position is the
    // current key, which is already returned. We can safely issue a
    // Next() without checking the current key.
    // If the current key is a merge, very likely iter already points
    // to the next internal position.
    iter_->Next();
316
    PERF_COUNTER_ADD(internal_key_skipped_count, 1);
J
jorlow@chromium.org 已提交
317
  }
J
jorlow@chromium.org 已提交
318

319 320 321
  if (statistics_ != nullptr) {
    local_stats_.next_count_++;
  }
322 323
  // Now we point to the next internal position, for both of merge and
  // not merge cases.
324 325 326 327
  if (!iter_->Valid()) {
    valid_ = false;
    return;
  }
328
  FindNextUserEntry(true /* skipping the current user key */, prefix_same_as_start_);
329 330 331 332
  if (statistics_ != nullptr && valid_) {
    local_stats_.next_found_count_++;
    local_stats_.bytes_read_ += (key().size() + value().size());
  }
J
jorlow@chromium.org 已提交
333 334
}

335 336 337 338 339 340 341 342
// PRE: saved_key_ has the current user key if skipping
// POST: saved_key_ should have the next user key if valid_,
//       if the current entry is a result of merge
//           current_entry_is_merged_ => true
//           saved_value_             => the merged value
//
// NOTE: In between, saved_key_ can point to a user key that has
//       a delete marker
343 344 345 346 347 348
//
// The prefix_check parameter controls whether we check the iterated
// keys against the prefix of the seeked key. Set to false when
// performing a seek without a key (e.g. SeekToFirst). Set to
// prefix_same_as_start_ for other iterations.
inline void DBIter::FindNextUserEntry(bool skipping, bool prefix_check) {
349
  PERF_TIMER_GUARD(find_next_user_entry_time);
350
  FindNextUserEntryInternal(skipping, prefix_check);
351 352 353
}

// Actual implementation of DBIter::FindNextUserEntry()
354
void DBIter::FindNextUserEntryInternal(bool skipping, bool prefix_check) {
J
jorlow@chromium.org 已提交
355 356 357
  // Loop until we hit an acceptable entry to yield
  assert(iter_->Valid());
  assert(direction_ == kForward);
358
  current_entry_is_merged_ = false;
359
  uint64_t num_skipped = 0;
J
jorlow@chromium.org 已提交
360
  do {
J
jorlow@chromium.org 已提交
361
    ParsedInternalKey ikey;
362 363 364

    if (ParseKey(&ikey)) {
      if (iterate_upper_bound_ != nullptr &&
365
          user_comparator_->Compare(ikey.user_key, *iterate_upper_bound_) >= 0) {
366 367 368
        break;
      }

369 370 371 372 373
      if (prefix_extractor_ && prefix_check &&
          prefix_extractor_->Transform(ikey.user_key).compare(prefix_start_key_) != 0) {
        break;
      }

374 375 376 377 378 379 380 381
      if (ikey.sequence <= sequence_) {
        if (skipping &&
           user_comparator_->Compare(ikey.user_key, saved_key_.GetKey()) <= 0) {
          num_skipped++;  // skip this entry
          PERF_COUNTER_ADD(internal_key_skipped_count, 1);
        } else {
          switch (ikey.type) {
            case kTypeDeletion:
A
Andres Noetzli 已提交
382
            case kTypeSingleDeletion:
383 384
              // Arrange to skip all upcoming entries for this key since
              // they are hidden by this deletion.
385 386 387
              saved_key_.SetKey(
                  ikey.user_key,
                  !iter_->IsKeyPinned() || !pin_thru_lifetime_ /* copy */);
388 389 390 391 392
              skipping = true;
              num_skipped = 0;
              PERF_COUNTER_ADD(internal_delete_skipped_count, 1);
              break;
            case kTypeValue:
393 394 395
              saved_key_.SetKey(
                  ikey.user_key,
                  !iter_->IsKeyPinned() || !pin_thru_lifetime_ /* copy */);
A
Andrew Kryczka 已提交
396 397 398 399 400 401 402 403 404 405 406
              if (range_del_agg_.ShouldDelete(ikey)) {
                // Arrange to skip all upcoming entries for this key since
                // they are hidden by this deletion.
                skipping = true;
                num_skipped = 0;
                PERF_COUNTER_ADD(internal_delete_skipped_count, 1);
              } else {
                valid_ = true;
                return;
              }
              break;
407
            case kTypeMerge:
408 409 410
              saved_key_.SetKey(
                  ikey.user_key,
                  !iter_->IsKeyPinned() || !pin_thru_lifetime_ /* copy */);
A
Andrew Kryczka 已提交
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
              if (range_del_agg_.ShouldDelete(ikey)) {
                // Arrange to skip all upcoming entries for this key since
                // they are hidden by this deletion.
                skipping = true;
                num_skipped = 0;
                PERF_COUNTER_ADD(internal_delete_skipped_count, 1);
              } else {
                // By now, we are sure the current ikey is going to yield a
                // value
                current_entry_is_merged_ = true;
                valid_ = true;
                MergeValuesNewToOld();  // Go to a different state machine
                return;
              }
              break;
426 427 428 429
            default:
              assert(false);
              break;
          }
430
        }
J
jorlow@chromium.org 已提交
431
      }
J
jorlow@chromium.org 已提交
432
    }
433 434
    // If we have sequentially iterated via numerous keys and still not
    // found the next user-key, then it is better to seek so that we can
C
clark.kang 已提交
435
    // avoid too many key comparisons. We seek to the last occurrence of
436 437
    // our current key by looking for sequence number 0 and type deletion
    // (the smallest type).
438 439 440
    if (skipping && num_skipped > max_skip_) {
      num_skipped = 0;
      std::string last_key;
441
      AppendInternalKey(&last_key, ParsedInternalKey(saved_key_.GetKey(), 0,
442
                                                     kTypeDeletion));
443 444 445 446 447
      iter_->Seek(last_key);
      RecordTick(statistics_, NUMBER_OF_RESEEKS_IN_ITERATION);
    } else {
      iter_->Next();
    }
J
jorlow@chromium.org 已提交
448 449
  } while (iter_->Valid());
  valid_ = false;
J
jorlow@chromium.org 已提交
450 451
}

452 453 454 455 456 457 458
// Merge values of the same user key starting from the current iter_ position
// Scan from the newer entries to older entries.
// PRE: iter_->key() points to the first merge type entry
//      saved_key_ stores the user key
// POST: saved_value_ has the merged value for the user key
//       iter_ points to the next entry (or invalid)
void DBIter::MergeValuesNewToOld() {
459
  if (!merge_operator_) {
460 461
    Log(InfoLogLevel::ERROR_LEVEL,
        logger_, "Options::merge_operator is null.");
462
    status_ = Status::InvalidArgument("merge_operator_ must be set.");
463 464
    valid_ = false;
    return;
D
Deon Nicholas 已提交
465
  }
466

467 468
  // Temporarily pin the blocks that hold merge operands
  TempPinData();
469
  merge_context_.Clear();
470
  // Start the merge process by pushing the first operand
471 472
  merge_context_.PushOperand(iter_->value(),
                             iter_->IsValuePinned() /* operand_pinned */);
473 474 475 476 477 478 479 480

  ParsedInternalKey ikey;
  for (iter_->Next(); iter_->Valid(); iter_->Next()) {
    if (!ParseKey(&ikey)) {
      // skip corrupted key
      continue;
    }

481
    if (!user_comparator_->Equal(ikey.user_key, saved_key_.GetKey())) {
482 483
      // hit the next user key, stop right here
      break;
A
Andrew Kryczka 已提交
484 485
    } else if (kTypeDeletion == ikey.type || kTypeSingleDeletion == ikey.type ||
               range_del_agg_.ShouldDelete(ikey)) {
486 487 488 489
      // hit a delete with the same user key, stop right here
      // iter_ is positioned after delete
      iter_->Next();
      break;
A
Andres Noetzli 已提交
490
    } else if (kTypeValue == ikey.type) {
491 492 493
      // hit a put, merge the put value with operands and store the
      // final result in saved_value_. We are done!
      // ignore corruption if there is any.
I
Igor Canadi 已提交
494
      const Slice val = iter_->value();
495 496
      MergeHelper::TimedFullMerge(merge_operator_, ikey.user_key, &val,
                                  merge_context_.GetOperands(), &saved_value_,
497
                                  logger_, statistics_, env_, &pinned_value_);
498 499 500
      // iter_ is positioned after put
      iter_->Next();
      return;
A
Andres Noetzli 已提交
501
    } else if (kTypeMerge == ikey.type) {
502 503
      // hit a merge, add the value as an operand and run associative merge.
      // when complete, add result to operands and continue.
504 505
      merge_context_.PushOperand(iter_->value(),
                                 iter_->IsValuePinned() /* operand_pinned */);
A
Andres Noetzli 已提交
506 507
    } else {
      assert(false);
508 509 510
    }
  }

511 512 513 514 515 516
  // we either exhausted all internal keys under this user key, or hit
  // a deletion marker.
  // feed null as the existing value to the merge operator, such that
  // client can differentiate this scenario and do things accordingly.
  MergeHelper::TimedFullMerge(merge_operator_, saved_key_.GetKey(), nullptr,
                              merge_context_.GetOperands(), &saved_value_,
517
                              logger_, statistics_, env_, &pinned_value_);
518 519
}

J
jorlow@chromium.org 已提交
520 521
void DBIter::Prev() {
  assert(valid_);
522
  ReleaseTempPinnedData();
S
Stanislau Hlebik 已提交
523
  if (direction_ == kForward) {
524
    ReverseToBackward();
S
Stanislau Hlebik 已提交
525 526
  }
  PrevInternal();
M
Manuel Ung 已提交
527
  if (statistics_ != nullptr) {
528
    local_stats_.prev_count_++;
M
Manuel Ung 已提交
529
    if (valid_) {
530 531
      local_stats_.prev_found_count_++;
      local_stats_.bytes_read_ += (key().size() + value().size());
M
Manuel Ung 已提交
532 533
    }
  }
S
Stanislau Hlebik 已提交
534
}
J
jorlow@chromium.org 已提交
535

536 537 538 539 540
void DBIter::ReverseToForward() {
  if (prefix_extractor_ != nullptr && !total_order_seek_) {
    IterKey last_key;
    last_key.SetInternalKey(ParsedInternalKey(
        saved_key_.GetKey(), kMaxSequenceNumber, kValueTypeForSeek));
A
Aaron Gao 已提交
541
    iter_->Seek(last_key.GetKey());
542 543 544 545 546 547 548 549
  }
  FindNextUserKey();
  direction_ = kForward;
  if (!iter_->Valid()) {
    iter_->SeekToFirst();
  }
}

550
void DBIter::ReverseToBackward() {
551 552 553 554
  if (prefix_extractor_ != nullptr && !total_order_seek_) {
    IterKey last_key;
    last_key.SetInternalKey(
        ParsedInternalKey(saved_key_.GetKey(), 0, kValueTypeForSeekForPrev));
A
Aaron Gao 已提交
555
    iter_->SeekForPrev(last_key.GetKey());
556
  }
557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582
  if (current_entry_is_merged_) {
    // Not placed in the same key. Need to call Prev() until finding the
    // previous key.
    if (!iter_->Valid()) {
      iter_->SeekToLast();
    }
    ParsedInternalKey ikey;
    FindParseableKey(&ikey, kReverse);
    while (iter_->Valid() &&
           user_comparator_->Compare(ikey.user_key, saved_key_.GetKey()) > 0) {
      iter_->Prev();
      FindParseableKey(&ikey, kReverse);
    }
  }
#ifndef NDEBUG
  if (iter_->Valid()) {
    ParsedInternalKey ikey;
    assert(ParseKey(&ikey));
    assert(user_comparator_->Compare(ikey.user_key, saved_key_.GetKey()) <= 0);
  }
#endif

  FindPrevUserKey();
  direction_ = kReverse;
}

S
Stanislau Hlebik 已提交
583 584 585 586
void DBIter::PrevInternal() {
  if (!iter_->Valid()) {
    valid_ = false;
    return;
587 588
  }

S
Stanislau Hlebik 已提交
589 590 591
  ParsedInternalKey ikey;

  while (iter_->Valid()) {
592
    saved_key_.SetKey(ExtractUserKey(iter_->key()),
593
                      !iter_->IsKeyPinned() || !pin_thru_lifetime_ /* copy */);
S
Stanislau Hlebik 已提交
594 595
    if (FindValueForCurrentKey()) {
      valid_ = true;
J
jorlow@chromium.org 已提交
596 597 598
      if (!iter_->Valid()) {
        return;
      }
S
Stanislau Hlebik 已提交
599
      FindParseableKey(&ikey, kReverse);
600
      if (user_comparator_->Equal(ikey.user_key, saved_key_.GetKey())) {
S
Stanislau Hlebik 已提交
601
        FindPrevUserKey();
J
jorlow@chromium.org 已提交
602
      }
A
Aaron Gao 已提交
603 604 605
      if (valid_ && prefix_extractor_ && prefix_same_as_start_ &&
          prefix_extractor_->Transform(saved_key_.GetKey())
                  .compare(prefix_start_key_) != 0) {
606
        valid_ = false;
A
Aaron Gao 已提交
607
      }
S
Stanislau Hlebik 已提交
608
      return;
J
jorlow@chromium.org 已提交
609
    }
S
Stanislau Hlebik 已提交
610 611 612 613
    if (!iter_->Valid()) {
      break;
    }
    FindParseableKey(&ikey, kReverse);
614
    if (user_comparator_->Equal(ikey.user_key, saved_key_.GetKey())) {
S
Stanislau Hlebik 已提交
615 616 617 618
      FindPrevUserKey();
    }
  }
  // We haven't found any key - iterator is not valid
A
Aaron Gao 已提交
619
  // Or the prefix is different than start prefix
620
  assert(!iter_->Valid());
S
Stanislau Hlebik 已提交
621
  valid_ = false;
J
jorlow@chromium.org 已提交
622 623
}

S
Stanislau Hlebik 已提交
624
// This function checks, if the entry with biggest sequence_number <= sequence_
A
Andres Noetzli 已提交
625 626
// is non kTypeDeletion or kTypeSingleDeletion. If it's not, we save value in
// saved_value_
S
Stanislau Hlebik 已提交
627 628
bool DBIter::FindValueForCurrentKey() {
  assert(iter_->Valid());
629
  merge_context_.Clear();
630
  current_entry_is_merged_ = false;
A
Andres Noetzli 已提交
631 632
  // last entry before merge (could be kTypeDeletion, kTypeSingleDeletion or
  // kTypeValue)
S
Stanislau Hlebik 已提交
633 634
  ValueType last_not_merge_type = kTypeDeletion;
  ValueType last_key_entry_type = kTypeDeletion;
J
jorlow@chromium.org 已提交
635

S
Stanislau Hlebik 已提交
636 637 638
  ParsedInternalKey ikey;
  FindParseableKey(&ikey, kReverse);

639 640 641
  // Temporarily pin blocks that hold (merge operands / the value)
  ReleaseTempPinnedData();
  TempPinData();
S
Stanislau Hlebik 已提交
642 643
  size_t num_skipped = 0;
  while (iter_->Valid() && ikey.sequence <= sequence_ &&
644
         user_comparator_->Equal(ikey.user_key, saved_key_.GetKey())) {
S
Stanislau Hlebik 已提交
645 646 647 648 649 650 651 652
    // We iterate too much: let's use Seek() to avoid too much key comparisons
    if (num_skipped >= max_skip_) {
      return FindValueForCurrentKeyUsingSeek();
    }

    last_key_entry_type = ikey.type;
    switch (last_key_entry_type) {
      case kTypeValue:
A
Andrew Kryczka 已提交
653 654 655 656 657 658 659
        if (range_del_agg_.ShouldDelete(ikey)) {
          last_key_entry_type = kTypeRangeDeletion;
          PERF_COUNTER_ADD(internal_delete_skipped_count, 1);
        } else {
          assert(iter_->IsValuePinned());
          pinned_value_ = iter_->value();
        }
660
        merge_context_.Clear();
A
Andrew Kryczka 已提交
661
        last_not_merge_type = last_key_entry_type;
S
Stanislau Hlebik 已提交
662 663
        break;
      case kTypeDeletion:
A
Andres Noetzli 已提交
664
      case kTypeSingleDeletion:
665
        merge_context_.Clear();
A
Andres Noetzli 已提交
666
        last_not_merge_type = last_key_entry_type;
667
        PERF_COUNTER_ADD(internal_delete_skipped_count, 1);
S
Stanislau Hlebik 已提交
668 669
        break;
      case kTypeMerge:
A
Andrew Kryczka 已提交
670 671 672 673 674 675 676 677 678 679
        if (range_del_agg_.ShouldDelete(ikey)) {
          merge_context_.Clear();
          last_key_entry_type = kTypeRangeDeletion;
          last_not_merge_type = last_key_entry_type;
          PERF_COUNTER_ADD(internal_delete_skipped_count, 1);
        } else {
          assert(merge_operator_ != nullptr);
          merge_context_.PushOperandBack(
              iter_->value(), iter_->IsValuePinned() /* operand_pinned */);
        }
S
Stanislau Hlebik 已提交
680 681 682 683 684
        break;
      default:
        assert(false);
    }

685
    PERF_COUNTER_ADD(internal_key_skipped_count, 1);
686
    assert(user_comparator_->Equal(ikey.user_key, saved_key_.GetKey()));
S
Stanislau Hlebik 已提交
687 688 689 690 691 692 693
    iter_->Prev();
    ++num_skipped;
    FindParseableKey(&ikey, kReverse);
  }

  switch (last_key_entry_type) {
    case kTypeDeletion:
A
Andres Noetzli 已提交
694
    case kTypeSingleDeletion:
A
Andrew Kryczka 已提交
695
    case kTypeRangeDeletion:
S
Stanislau Hlebik 已提交
696 697 698
      valid_ = false;
      return false;
    case kTypeMerge:
699
      current_entry_is_merged_ = true;
A
Aaron Gao 已提交
700
      if (last_not_merge_type == kTypeDeletion ||
A
Andrew Kryczka 已提交
701 702
          last_not_merge_type == kTypeSingleDeletion ||
          last_not_merge_type == kTypeRangeDeletion) {
703 704
        MergeHelper::TimedFullMerge(merge_operator_, saved_key_.GetKey(),
                                    nullptr, merge_context_.GetOperands(),
705 706
                                    &saved_value_, logger_, statistics_, env_,
                                    &pinned_value_);
707
      } else {
S
Stanislau Hlebik 已提交
708
        assert(last_not_merge_type == kTypeValue);
709 710 711
        MergeHelper::TimedFullMerge(merge_operator_, saved_key_.GetKey(),
                                    &pinned_value_,
                                    merge_context_.GetOperands(), &saved_value_,
712
                                    logger_, statistics_, env_, &pinned_value_);
713
      }
S
Stanislau Hlebik 已提交
714 715 716 717 718 719 720
      break;
    case kTypeValue:
      // do nothing - we've already has value in saved_value_
      break;
    default:
      assert(false);
      break;
J
jorlow@chromium.org 已提交
721
  }
S
Stanislau Hlebik 已提交
722 723 724
  valid_ = true;
  return true;
}
J
jorlow@chromium.org 已提交
725

S
Stanislau Hlebik 已提交
726 727 728
// This function is used in FindValueForCurrentKey.
// We use Seek() function instead of Prev() to find necessary value
bool DBIter::FindValueForCurrentKeyUsingSeek() {
729 730 731
  // FindValueForCurrentKey will enable pinning before calling
  // FindValueForCurrentKeyUsingSeek()
  assert(pinned_iters_mgr_.PinningEnabled());
S
Stanislau Hlebik 已提交
732 733 734 735 736 737 738 739 740 741
  std::string last_key;
  AppendInternalKey(&last_key, ParsedInternalKey(saved_key_.GetKey(), sequence_,
                                                 kValueTypeForSeek));
  iter_->Seek(last_key);
  RecordTick(statistics_, NUMBER_OF_RESEEKS_IN_ITERATION);

  // assume there is at least one parseable key for this user key
  ParsedInternalKey ikey;
  FindParseableKey(&ikey, kForward);

A
Andrew Kryczka 已提交
742 743
  if (ikey.type == kTypeDeletion || ikey.type == kTypeSingleDeletion ||
      range_del_agg_.ShouldDelete(ikey)) {
J
jorlow@chromium.org 已提交
744
    valid_ = false;
S
Stanislau Hlebik 已提交
745 746
    return false;
  }
A
Andrew Kryczka 已提交
747 748 749 750 751 752
  if (ikey.type == kTypeValue) {
    assert(iter_->IsValuePinned());
    pinned_value_ = iter_->value();
    valid_ = true;
    return true;
  }
S
Stanislau Hlebik 已提交
753 754 755

  // kTypeMerge. We need to collect all kTypeMerge values and save them
  // in operands
756
  current_entry_is_merged_ = true;
757
  merge_context_.Clear();
S
Stanislau Hlebik 已提交
758
  while (iter_->Valid() &&
759
         user_comparator_->Equal(ikey.user_key, saved_key_.GetKey()) &&
A
Andrew Kryczka 已提交
760
         ikey.type == kTypeMerge && !range_del_agg_.ShouldDelete(ikey)) {
761 762
    merge_context_.PushOperand(iter_->value(),
                               iter_->IsValuePinned() /* operand_pinned */);
S
Stanislau Hlebik 已提交
763 764 765 766 767
    iter_->Next();
    FindParseableKey(&ikey, kForward);
  }

  if (!iter_->Valid() ||
768
      !user_comparator_->Equal(ikey.user_key, saved_key_.GetKey()) ||
A
Andrew Kryczka 已提交
769 770
      ikey.type == kTypeDeletion || ikey.type == kTypeSingleDeletion ||
      range_del_agg_.ShouldDelete(ikey)) {
771 772
    MergeHelper::TimedFullMerge(merge_operator_, saved_key_.GetKey(), nullptr,
                                merge_context_.GetOperands(), &saved_value_,
773
                                logger_, statistics_, env_, &pinned_value_);
S
Stanislau Hlebik 已提交
774 775
    // Make iter_ valid and point to saved_key_
    if (!iter_->Valid() ||
776
        !user_comparator_->Equal(ikey.user_key, saved_key_.GetKey())) {
S
Stanislau Hlebik 已提交
777 778 779
      iter_->Seek(last_key);
      RecordTick(statistics_, NUMBER_OF_RESEEKS_IN_ITERATION);
    }
J
jorlow@chromium.org 已提交
780
    valid_ = true;
S
Stanislau Hlebik 已提交
781 782 783
    return true;
  }

I
Igor Canadi 已提交
784
  const Slice& val = iter_->value();
785 786
  MergeHelper::TimedFullMerge(merge_operator_, saved_key_.GetKey(), &val,
                              merge_context_.GetOperands(), &saved_value_,
787
                              logger_, statistics_, env_, &pinned_value_);
S
Stanislau Hlebik 已提交
788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
  valid_ = true;
  return true;
}

// Used in Next to change directions
// Go to next user key
// Don't use Seek(),
// because next user key will be very close
void DBIter::FindNextUserKey() {
  if (!iter_->Valid()) {
    return;
  }
  ParsedInternalKey ikey;
  FindParseableKey(&ikey, kForward);
  while (iter_->Valid() &&
803
         !user_comparator_->Equal(ikey.user_key, saved_key_.GetKey())) {
S
Stanislau Hlebik 已提交
804 805 806 807 808 809 810 811 812 813 814 815 816
    iter_->Next();
    FindParseableKey(&ikey, kForward);
  }
}

// Go to previous user_key
void DBIter::FindPrevUserKey() {
  if (!iter_->Valid()) {
    return;
  }
  size_t num_skipped = 0;
  ParsedInternalKey ikey;
  FindParseableKey(&ikey, kReverse);
817 818 819 820 821 822 823 824 825 826 827 828 829 830 831
  int cmp;
  while (iter_->Valid() && ((cmp = user_comparator_->Compare(
                                 ikey.user_key, saved_key_.GetKey())) == 0 ||
                            (cmp > 0 && ikey.sequence > sequence_))) {
    if (cmp == 0) {
      if (num_skipped >= max_skip_) {
        num_skipped = 0;
        IterKey last_key;
        last_key.SetInternalKey(ParsedInternalKey(
            saved_key_.GetKey(), kMaxSequenceNumber, kValueTypeForSeek));
        iter_->Seek(last_key.GetKey());
        RecordTick(statistics_, NUMBER_OF_RESEEKS_IN_ITERATION);
      } else {
        ++num_skipped;
      }
S
Stanislau Hlebik 已提交
832 833 834 835 836 837 838 839 840 841 842 843 844 845
    }
    iter_->Prev();
    FindParseableKey(&ikey, kReverse);
  }
}

// Skip all unparseable keys
void DBIter::FindParseableKey(ParsedInternalKey* ikey, Direction direction) {
  while (iter_->Valid() && !ParseKey(ikey)) {
    if (direction == kReverse) {
      iter_->Prev();
    } else {
      iter_->Next();
    }
J
jorlow@chromium.org 已提交
846 847
  }
}
J
jorlow@chromium.org 已提交
848

J
jorlow@chromium.org 已提交
849
void DBIter::Seek(const Slice& target) {
L
Lei Jin 已提交
850
  StopWatch sw(env_, statistics_, DB_SEEK);
851
  ReleaseTempPinnedData();
852 853 854
  saved_key_.Clear();
  // now savved_key is used to store internal key.
  saved_key_.SetInternalKey(target, sequence_);
855 856 857 858 859

  {
    PERF_TIMER_GUARD(seek_internal_seek_time);
    iter_->Seek(saved_key_.GetKey());
  }
M
Manuel Ung 已提交
860
  RecordTick(statistics_, NUMBER_DB_SEEK);
J
jorlow@chromium.org 已提交
861
  if (iter_->Valid()) {
862 863 864
    if (prefix_extractor_ && prefix_same_as_start_) {
      prefix_start_key_ = prefix_extractor_->Transform(target);
    }
865 866
    direction_ = kForward;
    ClearSavedValue();
867 868 869 870
    FindNextUserEntry(false /* not skipping */, prefix_same_as_start_);
    if (!valid_) {
      prefix_start_key_.clear();
    }
M
Manuel Ung 已提交
871 872 873 874 875 876
    if (statistics_ != nullptr) {
      if (valid_) {
        RecordTick(statistics_, NUMBER_DB_SEEK_FOUND);
        RecordTick(statistics_, ITER_BYTES_READ, key().size() + value().size());
      }
    }
J
jorlow@chromium.org 已提交
877 878 879
  } else {
    valid_ = false;
  }
880

881
  if (valid_ && prefix_extractor_ && prefix_same_as_start_) {
882 883
    prefix_start_buf_.SetKey(prefix_start_key_);
    prefix_start_key_ = prefix_start_buf_.GetKey();
884
  }
J
jorlow@chromium.org 已提交
885
}
J
jorlow@chromium.org 已提交
886

A
Aaron Gao 已提交
887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925
void DBIter::SeekForPrev(const Slice& target) {
  StopWatch sw(env_, statistics_, DB_SEEK);
  ReleaseTempPinnedData();
  saved_key_.Clear();
  // now saved_key is used to store internal key.
  saved_key_.SetInternalKey(target, 0 /* sequence_number */,
                            kValueTypeForSeekForPrev);

  {
    PERF_TIMER_GUARD(seek_internal_seek_time);
    iter_->SeekForPrev(saved_key_.GetKey());
  }

  RecordTick(statistics_, NUMBER_DB_SEEK);
  if (iter_->Valid()) {
    if (prefix_extractor_ && prefix_same_as_start_) {
      prefix_start_key_ = prefix_extractor_->Transform(target);
    }
    direction_ = kReverse;
    ClearSavedValue();
    PrevInternal();
    if (!valid_) {
      prefix_start_key_.clear();
    }
    if (statistics_ != nullptr) {
      if (valid_) {
        RecordTick(statistics_, NUMBER_DB_SEEK_FOUND);
        RecordTick(statistics_, ITER_BYTES_READ, key().size() + value().size());
      }
    }
  } else {
    valid_ = false;
  }
  if (valid_ && prefix_extractor_ && prefix_same_as_start_) {
    prefix_start_buf_.SetKey(prefix_start_key_);
    prefix_start_key_ = prefix_start_buf_.GetKey();
  }
}

J
jorlow@chromium.org 已提交
926
void DBIter::SeekToFirst() {
S
Stanislau Hlebik 已提交
927
  // Don't use iter_::Seek() if we set a prefix extractor
928
  // because prefix seek will be used.
929
  if (prefix_extractor_ != nullptr) {
S
Stanislau Hlebik 已提交
930 931
    max_skip_ = std::numeric_limits<uint64_t>::max();
  }
J
jorlow@chromium.org 已提交
932
  direction_ = kForward;
933
  ReleaseTempPinnedData();
J
jorlow@chromium.org 已提交
934
  ClearSavedValue();
935 936 937 938 939 940

  {
    PERF_TIMER_GUARD(seek_internal_seek_time);
    iter_->SeekToFirst();
  }

M
Manuel Ung 已提交
941
  RecordTick(statistics_, NUMBER_DB_SEEK);
J
jorlow@chromium.org 已提交
942
  if (iter_->Valid()) {
943
    FindNextUserEntry(false /* not skipping */, false /* no prefix check */);
M
Manuel Ung 已提交
944 945 946 947 948 949
    if (statistics_ != nullptr) {
      if (valid_) {
        RecordTick(statistics_, NUMBER_DB_SEEK_FOUND);
        RecordTick(statistics_, ITER_BYTES_READ, key().size() + value().size());
      }
    }
J
jorlow@chromium.org 已提交
950 951
  } else {
    valid_ = false;
J
jorlow@chromium.org 已提交
952
  }
953
  if (valid_ && prefix_extractor_ && prefix_same_as_start_) {
954 955
    prefix_start_buf_.SetKey(prefix_extractor_->Transform(saved_key_.GetKey()));
    prefix_start_key_ = prefix_start_buf_.GetKey();
956
  }
J
jorlow@chromium.org 已提交
957 958
}

J
jorlow@chromium.org 已提交
959
void DBIter::SeekToLast() {
S
Stanislau Hlebik 已提交
960
  // Don't use iter_::Seek() if we set a prefix extractor
961
  // because prefix seek will be used.
962
  if (prefix_extractor_ != nullptr) {
S
Stanislau Hlebik 已提交
963 964
    max_skip_ = std::numeric_limits<uint64_t>::max();
  }
J
jorlow@chromium.org 已提交
965
  direction_ = kReverse;
966
  ReleaseTempPinnedData();
J
jorlow@chromium.org 已提交
967
  ClearSavedValue();
968 969 970 971 972

  {
    PERF_TIMER_GUARD(seek_internal_seek_time);
    iter_->SeekToLast();
  }
973 974 975 976
  // When the iterate_upper_bound is set to a value,
  // it will seek to the last key before the
  // ReadOptions.iterate_upper_bound
  if (iter_->Valid() && iterate_upper_bound_ != nullptr) {
977 978 979 980 981
    SeekForPrev(*iterate_upper_bound_);
    if (!Valid()) {
      return;
    } else if (user_comparator_->Equal(*iterate_upper_bound_, key())) {
      Prev();
982
    }
983 984
  } else {
    PrevInternal();
985
  }
M
Manuel Ung 已提交
986 987 988 989 990 991 992
  if (statistics_ != nullptr) {
    RecordTick(statistics_, NUMBER_DB_SEEK);
    if (valid_) {
      RecordTick(statistics_, NUMBER_DB_SEEK_FOUND);
      RecordTick(statistics_, ITER_BYTES_READ, key().size() + value().size());
    }
  }
993
  if (valid_ && prefix_extractor_ && prefix_same_as_start_) {
994 995
    prefix_start_buf_.SetKey(prefix_extractor_->Transform(saved_key_.GetKey()));
    prefix_start_key_ = prefix_start_buf_.GetKey();
996
  }
J
jorlow@chromium.org 已提交
997 998
}

999 1000 1001 1002 1003 1004 1005 1006 1007 1008
Iterator* NewDBIterator(
    Env* env, const ImmutableCFOptions& ioptions,
    const Comparator* user_key_comparator, InternalIterator* internal_iter,
    const SequenceNumber& sequence, uint64_t max_sequential_skip_in_iterations,
    uint64_t version_number, const Slice* iterate_upper_bound,
    bool prefix_same_as_start, bool pin_data, bool total_order_seek) {
  DBIter* db_iter = new DBIter(
      env, ioptions, user_key_comparator, internal_iter, sequence, false,
      max_sequential_skip_in_iterations, version_number, iterate_upper_bound,
      prefix_same_as_start, pin_data, total_order_seek);
1009
  return db_iter;
1010 1011
}

I
Igor Canadi 已提交
1012
ArenaWrappedDBIter::~ArenaWrappedDBIter() { db_iter_->~DBIter(); }
1013 1014 1015

void ArenaWrappedDBIter::SetDBIter(DBIter* iter) { db_iter_ = iter; }

A
Andrew Kryczka 已提交
1016 1017 1018 1019
RangeDelAggregator* ArenaWrappedDBIter::GetRangeDelAggregator() {
  return db_iter_->GetRangeDelAggregator();
}

S
sdong 已提交
1020
void ArenaWrappedDBIter::SetIterUnderDBIter(InternalIterator* iter) {
1021 1022 1023 1024 1025 1026 1027 1028 1029
  static_cast<DBIter*>(db_iter_)->SetIter(iter);
}

inline bool ArenaWrappedDBIter::Valid() const { return db_iter_->Valid(); }
inline void ArenaWrappedDBIter::SeekToFirst() { db_iter_->SeekToFirst(); }
inline void ArenaWrappedDBIter::SeekToLast() { db_iter_->SeekToLast(); }
inline void ArenaWrappedDBIter::Seek(const Slice& target) {
  db_iter_->Seek(target);
}
A
Aaron Gao 已提交
1030 1031 1032
inline void ArenaWrappedDBIter::SeekForPrev(const Slice& target) {
  db_iter_->SeekForPrev(target);
}
1033 1034 1035 1036 1037
inline void ArenaWrappedDBIter::Next() { db_iter_->Next(); }
inline void ArenaWrappedDBIter::Prev() { db_iter_->Prev(); }
inline Slice ArenaWrappedDBIter::key() const { return db_iter_->key(); }
inline Slice ArenaWrappedDBIter::value() const { return db_iter_->value(); }
inline Status ArenaWrappedDBIter::status() const { return db_iter_->status(); }
1038 1039 1040 1041
inline Status ArenaWrappedDBIter::GetProperty(std::string prop_name,
                                              std::string* prop) {
  return db_iter_->GetProperty(prop_name, prop);
}
1042 1043 1044 1045
void ArenaWrappedDBIter::RegisterCleanup(CleanupFunction function, void* arg1,
                                         void* arg2) {
  db_iter_->RegisterCleanup(function, arg1, arg2);
}
J
jorlow@chromium.org 已提交
1046

1047
ArenaWrappedDBIter* NewArenaWrappedDbIterator(
1048
    Env* env, const ImmutableCFOptions& ioptions,
1049
    const Comparator* user_key_comparator, const SequenceNumber& sequence,
1050
    uint64_t max_sequential_skip_in_iterations, uint64_t version_number,
1051 1052
    const Slice* iterate_upper_bound, bool prefix_same_as_start, bool pin_data,
    bool total_order_seek) {
1053 1054 1055
  ArenaWrappedDBIter* iter = new ArenaWrappedDBIter();
  Arena* arena = iter->GetArena();
  auto mem = arena->AllocateAligned(sizeof(DBIter));
1056 1057 1058 1059
  DBIter* db_iter = new (mem) DBIter(
      env, ioptions, user_key_comparator, nullptr, sequence, true,
      max_sequential_skip_in_iterations, version_number, iterate_upper_bound,
      prefix_same_as_start, pin_data, total_order_seek);
1060

1061
  iter->SetDBIter(db_iter);
1062

1063
  return iter;
J
jorlow@chromium.org 已提交
1064 1065
}

1066
}  // namespace rocksdb