leveldb-ruby 0.14 → 0.15
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.
- data/LICENSE +24 -0
- data/README +60 -16
- data/ext/leveldb/extconf.rb +1 -1
- data/ext/leveldb/leveldb.cc +187 -18
- data/leveldb/Makefile +82 -96
- data/leveldb/build_detect_platform +137 -51
- data/leveldb/db/c.cc +110 -0
- data/leveldb/db/db_bench.cc +105 -4
- data/leveldb/db/db_impl.cc +135 -45
- data/leveldb/db/db_impl.h +12 -10
- data/leveldb/db/db_test.cc +666 -431
- data/leveldb/db/dbformat.cc +20 -0
- data/leveldb/db/dbformat.h +12 -0
- data/leveldb/db/repair.cc +3 -1
- data/leveldb/db/skiplist.h +2 -1
- data/leveldb/db/table_cache.cc +42 -16
- data/leveldb/db/table_cache.h +11 -0
- data/leveldb/db/version_set.cc +46 -41
- data/leveldb/db/version_set.h +9 -0
- data/leveldb/db/write_batch.cc +13 -4
- data/leveldb/db/write_batch_internal.h +2 -0
- data/leveldb/db/write_batch_test.cc +31 -0
- data/leveldb/include/leveldb/c.h +29 -0
- data/leveldb/include/leveldb/db.h +2 -1
- data/leveldb/include/leveldb/filter_policy.h +70 -0
- data/leveldb/include/leveldb/options.h +8 -0
- data/leveldb/include/leveldb/status.h +6 -0
- data/leveldb/include/leveldb/table.h +15 -0
- data/leveldb/include/leveldb/table_builder.h +1 -0
- data/leveldb/port/atomic_pointer.h +13 -5
- data/leveldb/port/port.h +0 -2
- data/leveldb/port/port_example.h +10 -0
- data/leveldb/port/port_posix.cc +4 -0
- data/leveldb/port/port_posix.h +24 -9
- data/leveldb/table/block.cc +8 -4
- data/leveldb/table/block.h +3 -2
- data/leveldb/table/filter_block.cc +111 -0
- data/leveldb/table/filter_block.h +68 -0
- data/leveldb/table/filter_block_test.cc +128 -0
- data/leveldb/table/format.cc +17 -7
- data/leveldb/table/format.h +9 -4
- data/leveldb/table/table.cc +107 -6
- data/leveldb/table/table_builder.cc +49 -6
- data/leveldb/table/table_test.cc +8 -24
- data/leveldb/util/bloom.cc +95 -0
- data/leveldb/util/bloom_test.cc +159 -0
- data/leveldb/util/coding_test.cc +23 -0
- data/leveldb/util/comparator.cc +8 -3
- data/leveldb/util/env_posix.cc +46 -4
- data/leveldb/util/filter_policy.cc +11 -0
- data/leveldb/util/options.cc +2 -1
- data/lib/leveldb.rb +31 -5
- metadata +227 -109
- data/leveldb/port/port_android.cc +0 -64
- data/leveldb/port/port_android.h +0 -156
@@ -0,0 +1,70 @@
|
|
1
|
+
// Copyright (c) 2012 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
|
+
// A database can be configured with a custom FilterPolicy object.
|
6
|
+
// This object is responsible for creating a small filter from a set
|
7
|
+
// of keys. These filters are stored in leveldb and are consulted
|
8
|
+
// automatically by leveldb to decide whether or not to read some
|
9
|
+
// information from disk. In many cases, a filter can cut down the
|
10
|
+
// number of disk seeks form a handful to a single disk seek per
|
11
|
+
// DB::Get() call.
|
12
|
+
//
|
13
|
+
// Most people will want to use the builtin bloom filter support (see
|
14
|
+
// NewBloomFilterPolicy() below).
|
15
|
+
|
16
|
+
#ifndef STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_
|
17
|
+
#define STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_
|
18
|
+
|
19
|
+
#include <string>
|
20
|
+
|
21
|
+
namespace leveldb {
|
22
|
+
|
23
|
+
class Slice;
|
24
|
+
|
25
|
+
class FilterPolicy {
|
26
|
+
public:
|
27
|
+
virtual ~FilterPolicy();
|
28
|
+
|
29
|
+
// Return the name of this policy. Note that if the filter encoding
|
30
|
+
// changes in an incompatible way, the name returned by this method
|
31
|
+
// must be changed. Otherwise, old incompatible filters may be
|
32
|
+
// passed to methods of this type.
|
33
|
+
virtual const char* Name() const = 0;
|
34
|
+
|
35
|
+
// keys[0,n-1] contains a list of keys (potentially with duplicates)
|
36
|
+
// that are ordered according to the user supplied comparator.
|
37
|
+
// Append a filter that summarizes keys[0,n-1] to *dst.
|
38
|
+
//
|
39
|
+
// Warning: do not change the initial contents of *dst. Instead,
|
40
|
+
// append the newly constructed filter to *dst.
|
41
|
+
virtual void CreateFilter(const Slice* keys, int n, std::string* dst)
|
42
|
+
const = 0;
|
43
|
+
|
44
|
+
// "filter" contains the data appended by a preceding call to
|
45
|
+
// CreateFilter() on this class. This method must return true if
|
46
|
+
// the key was in the list of keys passed to CreateFilter().
|
47
|
+
// This method may return true or false if the key was not on the
|
48
|
+
// list, but it should aim to return false with a high probability.
|
49
|
+
virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const = 0;
|
50
|
+
};
|
51
|
+
|
52
|
+
// Return a new filter policy that uses a bloom filter with approximately
|
53
|
+
// the specified number of bits per key. A good value for bits_per_key
|
54
|
+
// is 10, which yields a filter with ~ 1% false positive rate.
|
55
|
+
//
|
56
|
+
// Callers must delete the result after any database that is using the
|
57
|
+
// result has been closed.
|
58
|
+
//
|
59
|
+
// Note: if you are using a custom comparator that ignores some parts
|
60
|
+
// of the keys being compared, you must not use NewBloomFilterPolicy()
|
61
|
+
// and must provide your own FilterPolicy that also ignores the
|
62
|
+
// corresponding parts of the keys. For example, if the comparator
|
63
|
+
// ignores trailing spaces, it would be incorrect to use a
|
64
|
+
// FilterPolicy (like NewBloomFilterPolicy) that does not ignore
|
65
|
+
// trailing spaces in keys.
|
66
|
+
extern const FilterPolicy* NewBloomFilterPolicy(int bits_per_key);
|
67
|
+
|
68
|
+
}
|
69
|
+
|
70
|
+
#endif // STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_
|
@@ -12,6 +12,7 @@ namespace leveldb {
|
|
12
12
|
class Cache;
|
13
13
|
class Comparator;
|
14
14
|
class Env;
|
15
|
+
class FilterPolicy;
|
15
16
|
class Logger;
|
16
17
|
class Snapshot;
|
17
18
|
|
@@ -127,6 +128,13 @@ struct Options {
|
|
127
128
|
// efficiently detect that and will switch to uncompressed mode.
|
128
129
|
CompressionType compression;
|
129
130
|
|
131
|
+
// If non-NULL, use the specified filter policy to reduce disk reads.
|
132
|
+
// Many applications will benefit from passing the result of
|
133
|
+
// NewBloomFilterPolicy() here.
|
134
|
+
//
|
135
|
+
// Default: NULL
|
136
|
+
const FilterPolicy* filter_policy;
|
137
|
+
|
130
138
|
// Create an Options object with default values for all fields.
|
131
139
|
Options();
|
132
140
|
};
|
@@ -54,6 +54,12 @@ class Status {
|
|
54
54
|
// Returns true iff the status indicates a NotFound error.
|
55
55
|
bool IsNotFound() const { return code() == kNotFound; }
|
56
56
|
|
57
|
+
// Returns true iff the status indicates a Corruption error.
|
58
|
+
bool IsCorruption() const { return code() == kCorruption; }
|
59
|
+
|
60
|
+
// Returns true iff the status indicates an IOError.
|
61
|
+
bool IsIOError() const { return code() == kIOError; }
|
62
|
+
|
57
63
|
// Return a string representation of this status suitable for printing.
|
58
64
|
// Returns the string "OK" for success.
|
59
65
|
std::string ToString() const;
|
@@ -12,9 +12,11 @@ namespace leveldb {
|
|
12
12
|
|
13
13
|
class Block;
|
14
14
|
class BlockHandle;
|
15
|
+
class Footer;
|
15
16
|
struct Options;
|
16
17
|
class RandomAccessFile;
|
17
18
|
struct ReadOptions;
|
19
|
+
class TableCache;
|
18
20
|
|
19
21
|
// A Table is a sorted map from strings to strings. Tables are
|
20
22
|
// immutable and persistent. A Table may be safely accessed from
|
@@ -60,6 +62,19 @@ class Table {
|
|
60
62
|
explicit Table(Rep* rep) { rep_ = rep; }
|
61
63
|
static Iterator* BlockReader(void*, const ReadOptions&, const Slice&);
|
62
64
|
|
65
|
+
// Calls (*handle_result)(arg, ...) with the entry found after a call
|
66
|
+
// to Seek(key). May not make such a call if filter policy says
|
67
|
+
// that key is not present.
|
68
|
+
friend class TableCache;
|
69
|
+
Status InternalGet(
|
70
|
+
const ReadOptions&, const Slice& key,
|
71
|
+
void* arg,
|
72
|
+
void (*handle_result)(void* arg, const Slice& k, const Slice& v));
|
73
|
+
|
74
|
+
|
75
|
+
void ReadMeta(const Footer& footer);
|
76
|
+
void ReadFilter(const Slice& filter_handle_value);
|
77
|
+
|
63
78
|
// No copying allowed
|
64
79
|
Table(const Table&);
|
65
80
|
void operator=(const Table&);
|
@@ -73,13 +73,21 @@ inline void MemoryBarrier() {
|
|
73
73
|
}
|
74
74
|
#define LEVELDB_HAVE_MEMORY_BARRIER
|
75
75
|
|
76
|
-
// ARM
|
77
|
-
#elif defined(ARCH_CPU_ARM_FAMILY)
|
76
|
+
// ARM Linux
|
77
|
+
#elif defined(ARCH_CPU_ARM_FAMILY) && defined(__linux__)
|
78
78
|
typedef void (*LinuxKernelMemoryBarrierFunc)(void);
|
79
|
-
|
80
|
-
|
79
|
+
// The Linux ARM kernel provides a highly optimized device-specific memory
|
80
|
+
// barrier function at a fixed memory address that is mapped in every
|
81
|
+
// user-level process.
|
82
|
+
//
|
83
|
+
// This beats using CPU-specific instructions which are, on single-core
|
84
|
+
// devices, un-necessary and very costly (e.g. ARMv7-A "dmb" takes more
|
85
|
+
// than 180ns on a Cortex-A8 like the one on a Nexus One). Benchmarking
|
86
|
+
// shows that the extra function call cost is completely negligible on
|
87
|
+
// multi-core devices.
|
88
|
+
//
|
81
89
|
inline void MemoryBarrier() {
|
82
|
-
|
90
|
+
(*(LinuxKernelMemoryBarrierFunc)0xffff0fa0)();
|
83
91
|
}
|
84
92
|
#define LEVELDB_HAVE_MEMORY_BARRIER
|
85
93
|
|
data/leveldb/port/port.h
CHANGED
data/leveldb/port/port_example.h
CHANGED
@@ -60,6 +60,16 @@ class CondVar {
|
|
60
60
|
void SignallAll();
|
61
61
|
};
|
62
62
|
|
63
|
+
// Thread-safe initialization.
|
64
|
+
// Used as follows:
|
65
|
+
// static port::OnceType init_control = LEVELDB_ONCE_INIT;
|
66
|
+
// static void Initializer() { ... do something ...; }
|
67
|
+
// ...
|
68
|
+
// port::InitOnce(&init_control, &Initializer);
|
69
|
+
typedef intptr_t OnceType;
|
70
|
+
#define LEVELDB_ONCE_INIT 0
|
71
|
+
extern void InitOnce(port::OnceType*, void (*initializer)());
|
72
|
+
|
63
73
|
// A type that holds a pointer that can be read or written atomically
|
64
74
|
// (i.e., without word-tearing.)
|
65
75
|
class AtomicPointer {
|
data/leveldb/port/port_posix.cc
CHANGED
@@ -46,5 +46,9 @@ void CondVar::SignalAll() {
|
|
46
46
|
PthreadCall("broadcast", pthread_cond_broadcast(&cv_));
|
47
47
|
}
|
48
48
|
|
49
|
+
void InitOnce(OnceType* once, void (*initializer)()) {
|
50
|
+
PthreadCall("once", pthread_once(once, initializer));
|
51
|
+
}
|
52
|
+
|
49
53
|
} // namespace port
|
50
54
|
} // namespace leveldb
|
data/leveldb/port/port_posix.h
CHANGED
@@ -7,17 +7,22 @@
|
|
7
7
|
#ifndef STORAGE_LEVELDB_PORT_PORT_POSIX_H_
|
8
8
|
#define STORAGE_LEVELDB_PORT_PORT_POSIX_H_
|
9
9
|
|
10
|
+
#undef PLATFORM_IS_LITTLE_ENDIAN
|
10
11
|
#if defined(OS_MACOSX)
|
11
12
|
#include <machine/endian.h>
|
13
|
+
#if defined(__DARWIN_LITTLE_ENDIAN) && defined(__DARWIN_BYTE_ORDER)
|
14
|
+
#define PLATFORM_IS_LITTLE_ENDIAN \
|
15
|
+
(__DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN)
|
16
|
+
#endif
|
12
17
|
#elif defined(OS_SOLARIS)
|
13
18
|
#include <sys/isa_defs.h>
|
14
19
|
#ifdef _LITTLE_ENDIAN
|
15
|
-
#define
|
20
|
+
#define PLATFORM_IS_LITTLE_ENDIAN true
|
16
21
|
#else
|
17
|
-
#define
|
22
|
+
#define PLATFORM_IS_LITTLE_ENDIAN false
|
18
23
|
#endif
|
19
24
|
#elif defined(OS_FREEBSD) || defined(OS_OPENBSD) || defined(OS_NETBSD) ||\
|
20
|
-
defined(OS_DRAGONFLYBSD)
|
25
|
+
defined(OS_DRAGONFLYBSD) || defined(OS_ANDROID)
|
21
26
|
#include <sys/types.h>
|
22
27
|
#include <sys/endian.h>
|
23
28
|
#else
|
@@ -31,14 +36,13 @@
|
|
31
36
|
#include <string>
|
32
37
|
#include "port/atomic_pointer.h"
|
33
38
|
|
34
|
-
#
|
35
|
-
#define
|
36
|
-
#else
|
37
|
-
#define IS_LITTLE_ENDIAN (__BYTE_ORDER == __LITTLE_ENDIAN)
|
39
|
+
#ifndef PLATFORM_IS_LITTLE_ENDIAN
|
40
|
+
#define PLATFORM_IS_LITTLE_ENDIAN (__BYTE_ORDER == __LITTLE_ENDIAN)
|
38
41
|
#endif
|
39
42
|
|
40
43
|
#if defined(OS_MACOSX) || defined(OS_SOLARIS) || defined(OS_FREEBSD) ||\
|
41
|
-
defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD)
|
44
|
+
defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD) ||\
|
45
|
+
defined(OS_ANDROID)
|
42
46
|
// Use fread/fwrite/fflush on platforms without _unlocked variants
|
43
47
|
#define fread_unlocked fread
|
44
48
|
#define fwrite_unlocked fwrite
|
@@ -51,10 +55,17 @@
|
|
51
55
|
#define fdatasync fsync
|
52
56
|
#endif
|
53
57
|
|
58
|
+
#if defined(OS_ANDROID) && __ANDROID_API__ < 9
|
59
|
+
// fdatasync() was only introduced in API level 9 on Android. Use fsync()
|
60
|
+
// when targetting older platforms.
|
61
|
+
#define fdatasync fsync
|
62
|
+
#endif
|
63
|
+
|
54
64
|
namespace leveldb {
|
55
65
|
namespace port {
|
56
66
|
|
57
|
-
static const bool kLittleEndian =
|
67
|
+
static const bool kLittleEndian = PLATFORM_IS_LITTLE_ENDIAN;
|
68
|
+
#undef PLATFORM_IS_LITTLE_ENDIAN
|
58
69
|
|
59
70
|
class CondVar;
|
60
71
|
|
@@ -88,6 +99,10 @@ class CondVar {
|
|
88
99
|
Mutex* mu_;
|
89
100
|
};
|
90
101
|
|
102
|
+
typedef pthread_once_t OnceType;
|
103
|
+
#define LEVELDB_ONCE_INIT PTHREAD_ONCE_INIT
|
104
|
+
extern void InitOnce(OnceType* once, void (*initializer)());
|
105
|
+
|
91
106
|
inline bool Snappy_Compress(const char* input, size_t length,
|
92
107
|
::std::string* output) {
|
93
108
|
#ifdef SNAPPY
|
data/leveldb/table/block.cc
CHANGED
@@ -9,6 +9,7 @@
|
|
9
9
|
#include <vector>
|
10
10
|
#include <algorithm>
|
11
11
|
#include "leveldb/comparator.h"
|
12
|
+
#include "table/format.h"
|
12
13
|
#include "util/coding.h"
|
13
14
|
#include "util/logging.h"
|
14
15
|
|
@@ -19,9 +20,10 @@ inline uint32_t Block::NumRestarts() const {
|
|
19
20
|
return DecodeFixed32(data_ + size_ - sizeof(uint32_t));
|
20
21
|
}
|
21
22
|
|
22
|
-
Block::Block(const
|
23
|
-
: data_(data),
|
24
|
-
size_(size)
|
23
|
+
Block::Block(const BlockContents& contents)
|
24
|
+
: data_(contents.data.data()),
|
25
|
+
size_(contents.data.size()),
|
26
|
+
owned_(contents.heap_allocated) {
|
25
27
|
if (size_ < sizeof(uint32_t)) {
|
26
28
|
size_ = 0; // Error marker
|
27
29
|
} else {
|
@@ -35,7 +37,9 @@ Block::Block(const char* data, size_t size)
|
|
35
37
|
}
|
36
38
|
|
37
39
|
Block::~Block() {
|
38
|
-
|
40
|
+
if (owned_) {
|
41
|
+
delete[] data_;
|
42
|
+
}
|
39
43
|
}
|
40
44
|
|
41
45
|
// Helper routine: decode the next block entry starting at "p",
|
data/leveldb/table/block.h
CHANGED
@@ -11,13 +11,13 @@
|
|
11
11
|
|
12
12
|
namespace leveldb {
|
13
13
|
|
14
|
+
struct BlockContents;
|
14
15
|
class Comparator;
|
15
16
|
|
16
17
|
class Block {
|
17
18
|
public:
|
18
19
|
// Initialize the block with the specified contents.
|
19
|
-
|
20
|
-
Block(const char* data, size_t size);
|
20
|
+
explicit Block(const BlockContents& contents);
|
21
21
|
|
22
22
|
~Block();
|
23
23
|
|
@@ -30,6 +30,7 @@ class Block {
|
|
30
30
|
const char* data_;
|
31
31
|
size_t size_;
|
32
32
|
uint32_t restart_offset_; // Offset in data_ of restart array
|
33
|
+
bool owned_; // Block owns data_[]
|
33
34
|
|
34
35
|
// No copying allowed
|
35
36
|
Block(const Block&);
|
@@ -0,0 +1,111 @@
|
|
1
|
+
// Copyright (c) 2012 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/filter_block.h"
|
6
|
+
|
7
|
+
#include "leveldb/filter_policy.h"
|
8
|
+
#include "util/coding.h"
|
9
|
+
|
10
|
+
namespace leveldb {
|
11
|
+
|
12
|
+
// See doc/table_format.txt for an explanation of the filter block format.
|
13
|
+
|
14
|
+
// Generate new filter every 2KB of data
|
15
|
+
static const size_t kFilterBaseLg = 11;
|
16
|
+
static const size_t kFilterBase = 1 << kFilterBaseLg;
|
17
|
+
|
18
|
+
FilterBlockBuilder::FilterBlockBuilder(const FilterPolicy* policy)
|
19
|
+
: policy_(policy) {
|
20
|
+
}
|
21
|
+
|
22
|
+
void FilterBlockBuilder::StartBlock(uint64_t block_offset) {
|
23
|
+
uint64_t filter_index = (block_offset / kFilterBase);
|
24
|
+
assert(filter_index >= filter_offsets_.size());
|
25
|
+
while (filter_index > filter_offsets_.size()) {
|
26
|
+
GenerateFilter();
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
void FilterBlockBuilder::AddKey(const Slice& key) {
|
31
|
+
Slice k = key;
|
32
|
+
start_.push_back(keys_.size());
|
33
|
+
keys_.append(k.data(), k.size());
|
34
|
+
}
|
35
|
+
|
36
|
+
Slice FilterBlockBuilder::Finish() {
|
37
|
+
if (!start_.empty()) {
|
38
|
+
GenerateFilter();
|
39
|
+
}
|
40
|
+
|
41
|
+
// Append array of per-filter offsets
|
42
|
+
const uint32_t array_offset = result_.size();
|
43
|
+
for (size_t i = 0; i < filter_offsets_.size(); i++) {
|
44
|
+
PutFixed32(&result_, filter_offsets_[i]);
|
45
|
+
}
|
46
|
+
|
47
|
+
PutFixed32(&result_, array_offset);
|
48
|
+
result_.push_back(kFilterBaseLg); // Save encoding parameter in result
|
49
|
+
return Slice(result_);
|
50
|
+
}
|
51
|
+
|
52
|
+
void FilterBlockBuilder::GenerateFilter() {
|
53
|
+
const size_t num_keys = start_.size();
|
54
|
+
if (num_keys == 0) {
|
55
|
+
// Fast path if there are no keys for this filter
|
56
|
+
filter_offsets_.push_back(result_.size());
|
57
|
+
return;
|
58
|
+
}
|
59
|
+
|
60
|
+
// Make list of keys from flattened key structure
|
61
|
+
start_.push_back(keys_.size()); // Simplify length computation
|
62
|
+
tmp_keys_.resize(num_keys);
|
63
|
+
for (size_t i = 0; i < num_keys; i++) {
|
64
|
+
const char* base = keys_.data() + start_[i];
|
65
|
+
size_t length = start_[i+1] - start_[i];
|
66
|
+
tmp_keys_[i] = Slice(base, length);
|
67
|
+
}
|
68
|
+
|
69
|
+
// Generate filter for current set of keys and append to result_.
|
70
|
+
filter_offsets_.push_back(result_.size());
|
71
|
+
policy_->CreateFilter(&tmp_keys_[0], num_keys, &result_);
|
72
|
+
|
73
|
+
tmp_keys_.clear();
|
74
|
+
keys_.clear();
|
75
|
+
start_.clear();
|
76
|
+
}
|
77
|
+
|
78
|
+
FilterBlockReader::FilterBlockReader(const FilterPolicy* policy,
|
79
|
+
const Slice& contents)
|
80
|
+
: policy_(policy),
|
81
|
+
data_(NULL),
|
82
|
+
offset_(NULL),
|
83
|
+
num_(0),
|
84
|
+
base_lg_(0) {
|
85
|
+
size_t n = contents.size();
|
86
|
+
if (n < 5) return; // 1 byte for base_lg_ and 4 for start of offset array
|
87
|
+
base_lg_ = contents[n-1];
|
88
|
+
uint32_t last_word = DecodeFixed32(contents.data() + n - 5);
|
89
|
+
if (last_word > n - 5) return;
|
90
|
+
data_ = contents.data();
|
91
|
+
offset_ = data_ + last_word;
|
92
|
+
num_ = (n - 5 - last_word) / 4;
|
93
|
+
}
|
94
|
+
|
95
|
+
bool FilterBlockReader::KeyMayMatch(uint64_t block_offset, const Slice& key) {
|
96
|
+
uint64_t index = block_offset >> base_lg_;
|
97
|
+
if (index < num_) {
|
98
|
+
uint32_t start = DecodeFixed32(offset_ + index*4);
|
99
|
+
uint32_t limit = DecodeFixed32(offset_ + index*4 + 4);
|
100
|
+
if (start <= limit && limit <= (offset_ - data_)) {
|
101
|
+
Slice filter = Slice(data_ + start, limit - start);
|
102
|
+
return policy_->KeyMayMatch(key, filter);
|
103
|
+
} else if (start == limit) {
|
104
|
+
// Empty filters do not match any keys
|
105
|
+
return false;
|
106
|
+
}
|
107
|
+
}
|
108
|
+
return true; // Errors are treated as potential matches
|
109
|
+
}
|
110
|
+
|
111
|
+
}
|