1179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
2179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org// Use of this source code is governed by a BSD-style license that can be
3179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org// found in the LICENSE file. See the AUTHORS file for names of contributors.
4179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
5179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "table/two_level_iterator.h"
6179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
7fbd97aa4c5325eace57d24b89845b9581bac9324jorlow@chromium.org#include "leveldb/table.h"
8179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "table/block.h"
9179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "table/format.h"
10179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "table/iterator_wrapper.h"
11179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
12179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgnamespace leveldb {
13179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
14179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgnamespace {
15179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
16179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgtypedef Iterator* (*BlockFunction)(void*, const ReadOptions&, const Slice&);
17179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
18179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgclass TwoLevelIterator: public Iterator {
19179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org public:
20179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  TwoLevelIterator(
21179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    Iterator* index_iter,
22179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    BlockFunction block_function,
23179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    void* arg,
24179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    const ReadOptions& options);
25179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
26179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual ~TwoLevelIterator();
27179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
28179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual void Seek(const Slice& target);
29179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual void SeekToFirst();
30179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual void SeekToLast();
31179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual void Next();
32179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual void Prev();
33179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
34179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual bool Valid() const {
35179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    return data_iter_.Valid();
36179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
37179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual Slice key() const {
38179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    assert(Valid());
39179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    return data_iter_.key();
40179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
41179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual Slice value() const {
42179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    assert(Valid());
43179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    return data_iter_.value();
44179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
45179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  virtual Status status() const {
46179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    // It'd be nice if status() returned a const Status& instead of a Status
47179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    if (!index_iter_.status().ok()) {
48179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      return index_iter_.status();
49179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    } else if (data_iter_.iter() != NULL && !data_iter_.status().ok()) {
50179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      return data_iter_.status();
51179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    } else {
52179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      return status_;
53179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
54179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
55179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
56179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org private:
57179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  void SaveError(const Status& s) {
58179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    if (status_.ok() && !s.ok()) status_ = s;
59179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
60179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  void SkipEmptyDataBlocksForward();
61179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  void SkipEmptyDataBlocksBackward();
62179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  void SetDataIterator(Iterator* data_iter);
63179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  void InitDataBlock();
64179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
65179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  BlockFunction block_function_;
66179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  void* arg_;
67179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  const ReadOptions options_;
68179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  Status status_;
69179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  IteratorWrapper index_iter_;
70179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  IteratorWrapper data_iter_; // May be NULL
71179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  // If data_iter_ is non-NULL, then "data_block_handle_" holds the
72179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  // "index_value" passed to block_function_ to create the data_iter_.
73179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  std::string data_block_handle_;
74179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org};
75179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
76179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgTwoLevelIterator::TwoLevelIterator(
77179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    Iterator* index_iter,
78179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    BlockFunction block_function,
79179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    void* arg,
80179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    const ReadOptions& options)
81179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    : block_function_(block_function),
82179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      arg_(arg),
83179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      options_(options),
84179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      index_iter_(index_iter),
85179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      data_iter_(NULL) {
86179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
87179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
88179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgTwoLevelIterator::~TwoLevelIterator() {
89179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
90179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
91179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgvoid TwoLevelIterator::Seek(const Slice& target) {
92179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  index_iter_.Seek(target);
93179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  InitDataBlock();
94179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  if (data_iter_.iter() != NULL) data_iter_.Seek(target);
95179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  SkipEmptyDataBlocksForward();
96179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
97179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
98179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgvoid TwoLevelIterator::SeekToFirst() {
99179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  index_iter_.SeekToFirst();
100179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  InitDataBlock();
101179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  if (data_iter_.iter() != NULL) data_iter_.SeekToFirst();
102179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  SkipEmptyDataBlocksForward();
103179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
104179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
105179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgvoid TwoLevelIterator::SeekToLast() {
106179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  index_iter_.SeekToLast();
107179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  InitDataBlock();
108179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  if (data_iter_.iter() != NULL) data_iter_.SeekToLast();
109179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  SkipEmptyDataBlocksBackward();
110179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
111179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
112179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgvoid TwoLevelIterator::Next() {
113179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  assert(Valid());
114179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  data_iter_.Next();
115179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  SkipEmptyDataBlocksForward();
116179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
117179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
118179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgvoid TwoLevelIterator::Prev() {
119179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  assert(Valid());
120179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  data_iter_.Prev();
121179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  SkipEmptyDataBlocksBackward();
122179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
123179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
124179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
125179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgvoid TwoLevelIterator::SkipEmptyDataBlocksForward() {
126179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  while (data_iter_.iter() == NULL || !data_iter_.Valid()) {
127179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    // Move to next block
128179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    if (!index_iter_.Valid()) {
129179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      SetDataIterator(NULL);
130179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      return;
131179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
132179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    index_iter_.Next();
133179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    InitDataBlock();
134179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    if (data_iter_.iter() != NULL) data_iter_.SeekToFirst();
135179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
136179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
137179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
138179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgvoid TwoLevelIterator::SkipEmptyDataBlocksBackward() {
139179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  while (data_iter_.iter() == NULL || !data_iter_.Valid()) {
140179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    // Move to next block
141179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    if (!index_iter_.Valid()) {
142179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      SetDataIterator(NULL);
143179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      return;
144179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
145179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    index_iter_.Prev();
146179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    InitDataBlock();
147179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    if (data_iter_.iter() != NULL) data_iter_.SeekToLast();
148179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
149179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
150179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
151179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgvoid TwoLevelIterator::SetDataIterator(Iterator* data_iter) {
152179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  if (data_iter_.iter() != NULL) SaveError(data_iter_.status());
153179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  data_iter_.Set(data_iter);
154179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
155179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
156179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgvoid TwoLevelIterator::InitDataBlock() {
157179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  if (!index_iter_.Valid()) {
158179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    SetDataIterator(NULL);
159179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  } else {
160179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    Slice handle = index_iter_.value();
161179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    if (data_iter_.iter() != NULL && handle.compare(data_block_handle_) == 0) {
162179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      // data_iter_ is already constructed with this iterator, so
163179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      // no need to change anything
164179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    } else {
165179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      Iterator* iter = (*block_function_)(arg_, options_, handle);
166179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      data_block_handle_.assign(handle.data(), handle.size());
167179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org      SetDataIterator(iter);
168179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    }
169179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  }
170179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
171179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
17245b9940be332834440bd5299419f396e38085ebehans@chromium.org}  // namespace
173179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
174179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgIterator* NewTwoLevelIterator(
175179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    Iterator* index_iter,
176179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    BlockFunction block_function,
177179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    void* arg,
178179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org    const ReadOptions& options) {
179179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org  return new TwoLevelIterator(index_iter, block_function, arg, options);
180179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org}
181179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org
18245b9940be332834440bd5299419f396e38085ebehans@chromium.org}  // namespace leveldb
183