leveldb 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +95 -0
- data/ext/Rakefile +11 -0
- data/ext/leveldb/LICENSE +27 -0
- data/ext/leveldb/Makefile +206 -0
- data/ext/leveldb/build_config.mk +13 -0
- data/ext/leveldb/db/builder.cc +88 -0
- data/ext/leveldb/db/builder.h +34 -0
- data/ext/leveldb/db/c.cc +595 -0
- data/ext/leveldb/db/c_test.c +390 -0
- data/ext/leveldb/db/corruption_test.cc +359 -0
- data/ext/leveldb/db/db_bench.cc +979 -0
- data/ext/leveldb/db/db_impl.cc +1485 -0
- data/ext/leveldb/db/db_impl.h +203 -0
- data/ext/leveldb/db/db_iter.cc +299 -0
- data/ext/leveldb/db/db_iter.h +26 -0
- data/ext/leveldb/db/db_test.cc +2092 -0
- data/ext/leveldb/db/dbformat.cc +140 -0
- data/ext/leveldb/db/dbformat.h +227 -0
- data/ext/leveldb/db/dbformat_test.cc +112 -0
- data/ext/leveldb/db/filename.cc +139 -0
- data/ext/leveldb/db/filename.h +80 -0
- data/ext/leveldb/db/filename_test.cc +122 -0
- data/ext/leveldb/db/leveldb_main.cc +238 -0
- data/ext/leveldb/db/log_format.h +35 -0
- data/ext/leveldb/db/log_reader.cc +259 -0
- data/ext/leveldb/db/log_reader.h +108 -0
- data/ext/leveldb/db/log_test.cc +500 -0
- data/ext/leveldb/db/log_writer.cc +103 -0
- data/ext/leveldb/db/log_writer.h +48 -0
- data/ext/leveldb/db/memtable.cc +145 -0
- data/ext/leveldb/db/memtable.h +91 -0
- data/ext/leveldb/db/repair.cc +389 -0
- data/ext/leveldb/db/skiplist.h +379 -0
- data/ext/leveldb/db/skiplist_test.cc +378 -0
- data/ext/leveldb/db/snapshot.h +66 -0
- data/ext/leveldb/db/table_cache.cc +121 -0
- data/ext/leveldb/db/table_cache.h +61 -0
- data/ext/leveldb/db/version_edit.cc +266 -0
- data/ext/leveldb/db/version_edit.h +107 -0
- data/ext/leveldb/db/version_edit_test.cc +46 -0
- data/ext/leveldb/db/version_set.cc +1443 -0
- data/ext/leveldb/db/version_set.h +383 -0
- data/ext/leveldb/db/version_set_test.cc +179 -0
- data/ext/leveldb/db/write_batch.cc +147 -0
- data/ext/leveldb/db/write_batch_internal.h +49 -0
- data/ext/leveldb/db/write_batch_test.cc +120 -0
- data/ext/leveldb/doc/bench/db_bench_sqlite3.cc +718 -0
- data/ext/leveldb/doc/bench/db_bench_tree_db.cc +528 -0
- data/ext/leveldb/helpers/memenv/memenv.cc +384 -0
- data/ext/leveldb/helpers/memenv/memenv.h +20 -0
- data/ext/leveldb/helpers/memenv/memenv_test.cc +232 -0
- data/ext/leveldb/include/leveldb/c.h +291 -0
- data/ext/leveldb/include/leveldb/cache.h +99 -0
- data/ext/leveldb/include/leveldb/comparator.h +63 -0
- data/ext/leveldb/include/leveldb/db.h +161 -0
- data/ext/leveldb/include/leveldb/env.h +333 -0
- data/ext/leveldb/include/leveldb/filter_policy.h +70 -0
- data/ext/leveldb/include/leveldb/iterator.h +100 -0
- data/ext/leveldb/include/leveldb/options.h +195 -0
- data/ext/leveldb/include/leveldb/slice.h +109 -0
- data/ext/leveldb/include/leveldb/status.h +106 -0
- data/ext/leveldb/include/leveldb/table.h +85 -0
- data/ext/leveldb/include/leveldb/table_builder.h +92 -0
- data/ext/leveldb/include/leveldb/write_batch.h +64 -0
- data/ext/leveldb/issues/issue178_test.cc +92 -0
- data/ext/leveldb/port/atomic_pointer.h +224 -0
- data/ext/leveldb/port/port.h +19 -0
- data/ext/leveldb/port/port_example.h +135 -0
- data/ext/leveldb/port/port_posix.cc +54 -0
- data/ext/leveldb/port/port_posix.h +157 -0
- data/ext/leveldb/port/thread_annotations.h +59 -0
- data/ext/leveldb/port/win/stdint.h +24 -0
- data/ext/leveldb/table/block.cc +268 -0
- data/ext/leveldb/table/block.h +44 -0
- data/ext/leveldb/table/block_builder.cc +109 -0
- data/ext/leveldb/table/block_builder.h +57 -0
- data/ext/leveldb/table/filter_block.cc +111 -0
- data/ext/leveldb/table/filter_block.h +68 -0
- data/ext/leveldb/table/filter_block_test.cc +128 -0
- data/ext/leveldb/table/format.cc +145 -0
- data/ext/leveldb/table/format.h +108 -0
- data/ext/leveldb/table/iterator.cc +67 -0
- data/ext/leveldb/table/iterator_wrapper.h +63 -0
- data/ext/leveldb/table/merger.cc +197 -0
- data/ext/leveldb/table/merger.h +26 -0
- data/ext/leveldb/table/table.cc +275 -0
- data/ext/leveldb/table/table_builder.cc +270 -0
- data/ext/leveldb/table/table_test.cc +868 -0
- data/ext/leveldb/table/two_level_iterator.cc +182 -0
- data/ext/leveldb/table/two_level_iterator.h +34 -0
- data/ext/leveldb/util/arena.cc +68 -0
- data/ext/leveldb/util/arena.h +68 -0
- data/ext/leveldb/util/arena_test.cc +68 -0
- data/ext/leveldb/util/bloom.cc +95 -0
- data/ext/leveldb/util/bloom_test.cc +160 -0
- data/ext/leveldb/util/cache.cc +325 -0
- data/ext/leveldb/util/cache_test.cc +186 -0
- data/ext/leveldb/util/coding.cc +194 -0
- data/ext/leveldb/util/coding.h +104 -0
- data/ext/leveldb/util/coding_test.cc +196 -0
- data/ext/leveldb/util/comparator.cc +81 -0
- data/ext/leveldb/util/crc32c.cc +332 -0
- data/ext/leveldb/util/crc32c.h +45 -0
- data/ext/leveldb/util/crc32c_test.cc +72 -0
- data/ext/leveldb/util/env.cc +96 -0
- data/ext/leveldb/util/env_posix.cc +698 -0
- data/ext/leveldb/util/env_test.cc +104 -0
- data/ext/leveldb/util/filter_policy.cc +11 -0
- data/ext/leveldb/util/hash.cc +52 -0
- data/ext/leveldb/util/hash.h +19 -0
- data/ext/leveldb/util/histogram.cc +139 -0
- data/ext/leveldb/util/histogram.h +42 -0
- data/ext/leveldb/util/logging.cc +81 -0
- data/ext/leveldb/util/logging.h +47 -0
- data/ext/leveldb/util/mutexlock.h +41 -0
- data/ext/leveldb/util/options.cc +29 -0
- data/ext/leveldb/util/posix_logger.h +98 -0
- data/ext/leveldb/util/random.h +59 -0
- data/ext/leveldb/util/status.cc +75 -0
- data/ext/leveldb/util/testharness.cc +77 -0
- data/ext/leveldb/util/testharness.h +138 -0
- data/ext/leveldb/util/testutil.cc +51 -0
- data/ext/leveldb/util/testutil.h +53 -0
- data/lib/leveldb/version.rb +3 -0
- data/lib/leveldb.rb +1006 -0
- metadata +228 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
|
3
|
+
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
|
4
|
+
|
|
5
|
+
#include "table/merger.h"
|
|
6
|
+
|
|
7
|
+
#include "leveldb/comparator.h"
|
|
8
|
+
#include "leveldb/iterator.h"
|
|
9
|
+
#include "table/iterator_wrapper.h"
|
|
10
|
+
|
|
11
|
+
namespace leveldb {
|
|
12
|
+
|
|
13
|
+
namespace {
|
|
14
|
+
class MergingIterator : public Iterator {
|
|
15
|
+
public:
|
|
16
|
+
MergingIterator(const Comparator* comparator, Iterator** children, int n)
|
|
17
|
+
: comparator_(comparator),
|
|
18
|
+
children_(new IteratorWrapper[n]),
|
|
19
|
+
n_(n),
|
|
20
|
+
current_(NULL),
|
|
21
|
+
direction_(kForward) {
|
|
22
|
+
for (int i = 0; i < n; i++) {
|
|
23
|
+
children_[i].Set(children[i]);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
virtual ~MergingIterator() {
|
|
28
|
+
delete[] children_;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
virtual bool Valid() const {
|
|
32
|
+
return (current_ != NULL);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
virtual void SeekToFirst() {
|
|
36
|
+
for (int i = 0; i < n_; i++) {
|
|
37
|
+
children_[i].SeekToFirst();
|
|
38
|
+
}
|
|
39
|
+
FindSmallest();
|
|
40
|
+
direction_ = kForward;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
virtual void SeekToLast() {
|
|
44
|
+
for (int i = 0; i < n_; i++) {
|
|
45
|
+
children_[i].SeekToLast();
|
|
46
|
+
}
|
|
47
|
+
FindLargest();
|
|
48
|
+
direction_ = kReverse;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
virtual void Seek(const Slice& target) {
|
|
52
|
+
for (int i = 0; i < n_; i++) {
|
|
53
|
+
children_[i].Seek(target);
|
|
54
|
+
}
|
|
55
|
+
FindSmallest();
|
|
56
|
+
direction_ = kForward;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
virtual void Next() {
|
|
60
|
+
assert(Valid());
|
|
61
|
+
|
|
62
|
+
// Ensure that all children are positioned after key().
|
|
63
|
+
// If we are moving in the forward direction, it is already
|
|
64
|
+
// true for all of the non-current_ children since current_ is
|
|
65
|
+
// the smallest child and key() == current_->key(). Otherwise,
|
|
66
|
+
// we explicitly position the non-current_ children.
|
|
67
|
+
if (direction_ != kForward) {
|
|
68
|
+
for (int i = 0; i < n_; i++) {
|
|
69
|
+
IteratorWrapper* child = &children_[i];
|
|
70
|
+
if (child != current_) {
|
|
71
|
+
child->Seek(key());
|
|
72
|
+
if (child->Valid() &&
|
|
73
|
+
comparator_->Compare(key(), child->key()) == 0) {
|
|
74
|
+
child->Next();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
direction_ = kForward;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
current_->Next();
|
|
82
|
+
FindSmallest();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
virtual void Prev() {
|
|
86
|
+
assert(Valid());
|
|
87
|
+
|
|
88
|
+
// Ensure that all children are positioned before key().
|
|
89
|
+
// If we are moving in the reverse direction, it is already
|
|
90
|
+
// true for all of the non-current_ children since current_ is
|
|
91
|
+
// the largest child and key() == current_->key(). Otherwise,
|
|
92
|
+
// we explicitly position the non-current_ children.
|
|
93
|
+
if (direction_ != kReverse) {
|
|
94
|
+
for (int i = 0; i < n_; i++) {
|
|
95
|
+
IteratorWrapper* child = &children_[i];
|
|
96
|
+
if (child != current_) {
|
|
97
|
+
child->Seek(key());
|
|
98
|
+
if (child->Valid()) {
|
|
99
|
+
// Child is at first entry >= key(). Step back one to be < key()
|
|
100
|
+
child->Prev();
|
|
101
|
+
} else {
|
|
102
|
+
// Child has no entries >= key(). Position at last entry.
|
|
103
|
+
child->SeekToLast();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
direction_ = kReverse;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
current_->Prev();
|
|
111
|
+
FindLargest();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
virtual Slice key() const {
|
|
115
|
+
assert(Valid());
|
|
116
|
+
return current_->key();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
virtual Slice value() const {
|
|
120
|
+
assert(Valid());
|
|
121
|
+
return current_->value();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
virtual Status status() const {
|
|
125
|
+
Status status;
|
|
126
|
+
for (int i = 0; i < n_; i++) {
|
|
127
|
+
status = children_[i].status();
|
|
128
|
+
if (!status.ok()) {
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return status;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private:
|
|
136
|
+
void FindSmallest();
|
|
137
|
+
void FindLargest();
|
|
138
|
+
|
|
139
|
+
// We might want to use a heap in case there are lots of children.
|
|
140
|
+
// For now we use a simple array since we expect a very small number
|
|
141
|
+
// of children in leveldb.
|
|
142
|
+
const Comparator* comparator_;
|
|
143
|
+
IteratorWrapper* children_;
|
|
144
|
+
int n_;
|
|
145
|
+
IteratorWrapper* current_;
|
|
146
|
+
|
|
147
|
+
// Which direction is the iterator moving?
|
|
148
|
+
enum Direction {
|
|
149
|
+
kForward,
|
|
150
|
+
kReverse
|
|
151
|
+
};
|
|
152
|
+
Direction direction_;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
void MergingIterator::FindSmallest() {
|
|
156
|
+
IteratorWrapper* smallest = NULL;
|
|
157
|
+
for (int i = 0; i < n_; i++) {
|
|
158
|
+
IteratorWrapper* child = &children_[i];
|
|
159
|
+
if (child->Valid()) {
|
|
160
|
+
if (smallest == NULL) {
|
|
161
|
+
smallest = child;
|
|
162
|
+
} else if (comparator_->Compare(child->key(), smallest->key()) < 0) {
|
|
163
|
+
smallest = child;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
current_ = smallest;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
void MergingIterator::FindLargest() {
|
|
171
|
+
IteratorWrapper* largest = NULL;
|
|
172
|
+
for (int i = n_-1; i >= 0; i--) {
|
|
173
|
+
IteratorWrapper* child = &children_[i];
|
|
174
|
+
if (child->Valid()) {
|
|
175
|
+
if (largest == NULL) {
|
|
176
|
+
largest = child;
|
|
177
|
+
} else if (comparator_->Compare(child->key(), largest->key()) > 0) {
|
|
178
|
+
largest = child;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
current_ = largest;
|
|
183
|
+
}
|
|
184
|
+
} // namespace
|
|
185
|
+
|
|
186
|
+
Iterator* NewMergingIterator(const Comparator* cmp, Iterator** list, int n) {
|
|
187
|
+
assert(n >= 0);
|
|
188
|
+
if (n == 0) {
|
|
189
|
+
return NewEmptyIterator();
|
|
190
|
+
} else if (n == 1) {
|
|
191
|
+
return list[0];
|
|
192
|
+
} else {
|
|
193
|
+
return new MergingIterator(cmp, list, n);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
} // namespace leveldb
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
|
3
|
+
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
|
4
|
+
|
|
5
|
+
#ifndef STORAGE_LEVELDB_TABLE_MERGER_H_
|
|
6
|
+
#define STORAGE_LEVELDB_TABLE_MERGER_H_
|
|
7
|
+
|
|
8
|
+
namespace leveldb {
|
|
9
|
+
|
|
10
|
+
class Comparator;
|
|
11
|
+
class Iterator;
|
|
12
|
+
|
|
13
|
+
// Return an iterator that provided the union of the data in
|
|
14
|
+
// children[0,n-1]. Takes ownership of the child iterators and
|
|
15
|
+
// will delete them when the result iterator is deleted.
|
|
16
|
+
//
|
|
17
|
+
// The result does no duplicate suppression. I.e., if a particular
|
|
18
|
+
// key is present in K child iterators, it will be yielded K times.
|
|
19
|
+
//
|
|
20
|
+
// REQUIRES: n >= 0
|
|
21
|
+
extern Iterator* NewMergingIterator(
|
|
22
|
+
const Comparator* comparator, Iterator** children, int n);
|
|
23
|
+
|
|
24
|
+
} // namespace leveldb
|
|
25
|
+
|
|
26
|
+
#endif // STORAGE_LEVELDB_TABLE_MERGER_H_
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
|
3
|
+
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
|
4
|
+
|
|
5
|
+
#include "leveldb/table.h"
|
|
6
|
+
|
|
7
|
+
#include "leveldb/cache.h"
|
|
8
|
+
#include "leveldb/comparator.h"
|
|
9
|
+
#include "leveldb/env.h"
|
|
10
|
+
#include "leveldb/filter_policy.h"
|
|
11
|
+
#include "leveldb/options.h"
|
|
12
|
+
#include "table/block.h"
|
|
13
|
+
#include "table/filter_block.h"
|
|
14
|
+
#include "table/format.h"
|
|
15
|
+
#include "table/two_level_iterator.h"
|
|
16
|
+
#include "util/coding.h"
|
|
17
|
+
|
|
18
|
+
namespace leveldb {
|
|
19
|
+
|
|
20
|
+
struct Table::Rep {
|
|
21
|
+
~Rep() {
|
|
22
|
+
delete filter;
|
|
23
|
+
delete [] filter_data;
|
|
24
|
+
delete index_block;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Options options;
|
|
28
|
+
Status status;
|
|
29
|
+
RandomAccessFile* file;
|
|
30
|
+
uint64_t cache_id;
|
|
31
|
+
FilterBlockReader* filter;
|
|
32
|
+
const char* filter_data;
|
|
33
|
+
|
|
34
|
+
BlockHandle metaindex_handle; // Handle to metaindex_block: saved from footer
|
|
35
|
+
Block* index_block;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
Status Table::Open(const Options& options,
|
|
39
|
+
RandomAccessFile* file,
|
|
40
|
+
uint64_t size,
|
|
41
|
+
Table** table) {
|
|
42
|
+
*table = NULL;
|
|
43
|
+
if (size < Footer::kEncodedLength) {
|
|
44
|
+
return Status::InvalidArgument("file is too short to be an sstable");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
char footer_space[Footer::kEncodedLength];
|
|
48
|
+
Slice footer_input;
|
|
49
|
+
Status s = file->Read(size - Footer::kEncodedLength, Footer::kEncodedLength,
|
|
50
|
+
&footer_input, footer_space);
|
|
51
|
+
if (!s.ok()) return s;
|
|
52
|
+
|
|
53
|
+
Footer footer;
|
|
54
|
+
s = footer.DecodeFrom(&footer_input);
|
|
55
|
+
if (!s.ok()) return s;
|
|
56
|
+
|
|
57
|
+
// Read the index block
|
|
58
|
+
BlockContents contents;
|
|
59
|
+
Block* index_block = NULL;
|
|
60
|
+
if (s.ok()) {
|
|
61
|
+
s = ReadBlock(file, ReadOptions(), footer.index_handle(), &contents);
|
|
62
|
+
if (s.ok()) {
|
|
63
|
+
index_block = new Block(contents);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (s.ok()) {
|
|
68
|
+
// We've successfully read the footer and the index block: we're
|
|
69
|
+
// ready to serve requests.
|
|
70
|
+
Rep* rep = new Table::Rep;
|
|
71
|
+
rep->options = options;
|
|
72
|
+
rep->file = file;
|
|
73
|
+
rep->metaindex_handle = footer.metaindex_handle();
|
|
74
|
+
rep->index_block = index_block;
|
|
75
|
+
rep->cache_id = (options.block_cache ? options.block_cache->NewId() : 0);
|
|
76
|
+
rep->filter_data = NULL;
|
|
77
|
+
rep->filter = NULL;
|
|
78
|
+
*table = new Table(rep);
|
|
79
|
+
(*table)->ReadMeta(footer);
|
|
80
|
+
} else {
|
|
81
|
+
if (index_block) delete index_block;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return s;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
void Table::ReadMeta(const Footer& footer) {
|
|
88
|
+
if (rep_->options.filter_policy == NULL) {
|
|
89
|
+
return; // Do not need any metadata
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// TODO(sanjay): Skip this if footer.metaindex_handle() size indicates
|
|
93
|
+
// it is an empty block.
|
|
94
|
+
ReadOptions opt;
|
|
95
|
+
BlockContents contents;
|
|
96
|
+
if (!ReadBlock(rep_->file, opt, footer.metaindex_handle(), &contents).ok()) {
|
|
97
|
+
// Do not propagate errors since meta info is not needed for operation
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
Block* meta = new Block(contents);
|
|
101
|
+
|
|
102
|
+
Iterator* iter = meta->NewIterator(BytewiseComparator());
|
|
103
|
+
std::string key = "filter.";
|
|
104
|
+
key.append(rep_->options.filter_policy->Name());
|
|
105
|
+
iter->Seek(key);
|
|
106
|
+
if (iter->Valid() && iter->key() == Slice(key)) {
|
|
107
|
+
ReadFilter(iter->value());
|
|
108
|
+
}
|
|
109
|
+
delete iter;
|
|
110
|
+
delete meta;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
void Table::ReadFilter(const Slice& filter_handle_value) {
|
|
114
|
+
Slice v = filter_handle_value;
|
|
115
|
+
BlockHandle filter_handle;
|
|
116
|
+
if (!filter_handle.DecodeFrom(&v).ok()) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// We might want to unify with ReadBlock() if we start
|
|
121
|
+
// requiring checksum verification in Table::Open.
|
|
122
|
+
ReadOptions opt;
|
|
123
|
+
BlockContents block;
|
|
124
|
+
if (!ReadBlock(rep_->file, opt, filter_handle, &block).ok()) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (block.heap_allocated) {
|
|
128
|
+
rep_->filter_data = block.data.data(); // Will need to delete later
|
|
129
|
+
}
|
|
130
|
+
rep_->filter = new FilterBlockReader(rep_->options.filter_policy, block.data);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
Table::~Table() {
|
|
134
|
+
delete rep_;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
static void DeleteBlock(void* arg, void* ignored) {
|
|
138
|
+
delete reinterpret_cast<Block*>(arg);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
static void DeleteCachedBlock(const Slice& key, void* value) {
|
|
142
|
+
Block* block = reinterpret_cast<Block*>(value);
|
|
143
|
+
delete block;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
static void ReleaseBlock(void* arg, void* h) {
|
|
147
|
+
Cache* cache = reinterpret_cast<Cache*>(arg);
|
|
148
|
+
Cache::Handle* handle = reinterpret_cast<Cache::Handle*>(h);
|
|
149
|
+
cache->Release(handle);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Convert an index iterator value (i.e., an encoded BlockHandle)
|
|
153
|
+
// into an iterator over the contents of the corresponding block.
|
|
154
|
+
Iterator* Table::BlockReader(void* arg,
|
|
155
|
+
const ReadOptions& options,
|
|
156
|
+
const Slice& index_value) {
|
|
157
|
+
Table* table = reinterpret_cast<Table*>(arg);
|
|
158
|
+
Cache* block_cache = table->rep_->options.block_cache;
|
|
159
|
+
Block* block = NULL;
|
|
160
|
+
Cache::Handle* cache_handle = NULL;
|
|
161
|
+
|
|
162
|
+
BlockHandle handle;
|
|
163
|
+
Slice input = index_value;
|
|
164
|
+
Status s = handle.DecodeFrom(&input);
|
|
165
|
+
// We intentionally allow extra stuff in index_value so that we
|
|
166
|
+
// can add more features in the future.
|
|
167
|
+
|
|
168
|
+
if (s.ok()) {
|
|
169
|
+
BlockContents contents;
|
|
170
|
+
if (block_cache != NULL) {
|
|
171
|
+
char cache_key_buffer[16];
|
|
172
|
+
EncodeFixed64(cache_key_buffer, table->rep_->cache_id);
|
|
173
|
+
EncodeFixed64(cache_key_buffer+8, handle.offset());
|
|
174
|
+
Slice key(cache_key_buffer, sizeof(cache_key_buffer));
|
|
175
|
+
cache_handle = block_cache->Lookup(key);
|
|
176
|
+
if (cache_handle != NULL) {
|
|
177
|
+
block = reinterpret_cast<Block*>(block_cache->Value(cache_handle));
|
|
178
|
+
} else {
|
|
179
|
+
s = ReadBlock(table->rep_->file, options, handle, &contents);
|
|
180
|
+
if (s.ok()) {
|
|
181
|
+
block = new Block(contents);
|
|
182
|
+
if (contents.cachable && options.fill_cache) {
|
|
183
|
+
cache_handle = block_cache->Insert(
|
|
184
|
+
key, block, block->size(), &DeleteCachedBlock);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
} else {
|
|
189
|
+
s = ReadBlock(table->rep_->file, options, handle, &contents);
|
|
190
|
+
if (s.ok()) {
|
|
191
|
+
block = new Block(contents);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
Iterator* iter;
|
|
197
|
+
if (block != NULL) {
|
|
198
|
+
iter = block->NewIterator(table->rep_->options.comparator);
|
|
199
|
+
if (cache_handle == NULL) {
|
|
200
|
+
iter->RegisterCleanup(&DeleteBlock, block, NULL);
|
|
201
|
+
} else {
|
|
202
|
+
iter->RegisterCleanup(&ReleaseBlock, block_cache, cache_handle);
|
|
203
|
+
}
|
|
204
|
+
} else {
|
|
205
|
+
iter = NewErrorIterator(s);
|
|
206
|
+
}
|
|
207
|
+
return iter;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
Iterator* Table::NewIterator(const ReadOptions& options) const {
|
|
211
|
+
return NewTwoLevelIterator(
|
|
212
|
+
rep_->index_block->NewIterator(rep_->options.comparator),
|
|
213
|
+
&Table::BlockReader, const_cast<Table*>(this), options);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
Status Table::InternalGet(const ReadOptions& options, const Slice& k,
|
|
217
|
+
void* arg,
|
|
218
|
+
void (*saver)(void*, const Slice&, const Slice&)) {
|
|
219
|
+
Status s;
|
|
220
|
+
Iterator* iiter = rep_->index_block->NewIterator(rep_->options.comparator);
|
|
221
|
+
iiter->Seek(k);
|
|
222
|
+
if (iiter->Valid()) {
|
|
223
|
+
Slice handle_value = iiter->value();
|
|
224
|
+
FilterBlockReader* filter = rep_->filter;
|
|
225
|
+
BlockHandle handle;
|
|
226
|
+
if (filter != NULL &&
|
|
227
|
+
handle.DecodeFrom(&handle_value).ok() &&
|
|
228
|
+
!filter->KeyMayMatch(handle.offset(), k)) {
|
|
229
|
+
// Not found
|
|
230
|
+
} else {
|
|
231
|
+
Iterator* block_iter = BlockReader(this, options, iiter->value());
|
|
232
|
+
block_iter->Seek(k);
|
|
233
|
+
if (block_iter->Valid()) {
|
|
234
|
+
(*saver)(arg, block_iter->key(), block_iter->value());
|
|
235
|
+
}
|
|
236
|
+
s = block_iter->status();
|
|
237
|
+
delete block_iter;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (s.ok()) {
|
|
241
|
+
s = iiter->status();
|
|
242
|
+
}
|
|
243
|
+
delete iiter;
|
|
244
|
+
return s;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
uint64_t Table::ApproximateOffsetOf(const Slice& key) const {
|
|
249
|
+
Iterator* index_iter =
|
|
250
|
+
rep_->index_block->NewIterator(rep_->options.comparator);
|
|
251
|
+
index_iter->Seek(key);
|
|
252
|
+
uint64_t result;
|
|
253
|
+
if (index_iter->Valid()) {
|
|
254
|
+
BlockHandle handle;
|
|
255
|
+
Slice input = index_iter->value();
|
|
256
|
+
Status s = handle.DecodeFrom(&input);
|
|
257
|
+
if (s.ok()) {
|
|
258
|
+
result = handle.offset();
|
|
259
|
+
} else {
|
|
260
|
+
// Strange: we can't decode the block handle in the index block.
|
|
261
|
+
// We'll just return the offset of the metaindex block, which is
|
|
262
|
+
// close to the whole file size for this case.
|
|
263
|
+
result = rep_->metaindex_handle.offset();
|
|
264
|
+
}
|
|
265
|
+
} else {
|
|
266
|
+
// key is past the last key in the file. Approximate the offset
|
|
267
|
+
// by returning the offset of the metaindex block (which is
|
|
268
|
+
// right near the end of the file).
|
|
269
|
+
result = rep_->metaindex_handle.offset();
|
|
270
|
+
}
|
|
271
|
+
delete index_iter;
|
|
272
|
+
return result;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
} // namespace leveldb
|