filiptepper-leveldb-ruby 0.14
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +24 -0
- data/README +72 -0
- data/ext/leveldb/extconf.rb +14 -0
- data/ext/leveldb/leveldb.cc +530 -0
- data/ext/leveldb/platform.rb +83 -0
- data/leveldb/Makefile +191 -0
- data/leveldb/build_detect_platform +160 -0
- data/leveldb/db/builder.cc +88 -0
- data/leveldb/db/builder.h +34 -0
- data/leveldb/db/c.cc +581 -0
- data/leveldb/db/corruption_test.cc +359 -0
- data/leveldb/db/db_bench.cc +970 -0
- data/leveldb/db/db_impl.cc +1448 -0
- data/leveldb/db/db_impl.h +194 -0
- data/leveldb/db/db_iter.cc +299 -0
- data/leveldb/db/db_iter.h +26 -0
- data/leveldb/db/db_test.cc +1901 -0
- data/leveldb/db/dbformat.cc +140 -0
- data/leveldb/db/dbformat.h +227 -0
- data/leveldb/db/dbformat_test.cc +112 -0
- data/leveldb/db/filename.cc +139 -0
- data/leveldb/db/filename.h +80 -0
- data/leveldb/db/filename_test.cc +122 -0
- data/leveldb/db/log_format.h +35 -0
- data/leveldb/db/log_reader.cc +259 -0
- data/leveldb/db/log_reader.h +108 -0
- data/leveldb/db/log_test.cc +500 -0
- data/leveldb/db/log_writer.cc +103 -0
- data/leveldb/db/log_writer.h +48 -0
- data/leveldb/db/memtable.cc +145 -0
- data/leveldb/db/memtable.h +91 -0
- data/leveldb/db/repair.cc +389 -0
- data/leveldb/db/skiplist.h +379 -0
- data/leveldb/db/skiplist_test.cc +378 -0
- data/leveldb/db/snapshot.h +66 -0
- data/leveldb/db/table_cache.cc +121 -0
- data/leveldb/db/table_cache.h +61 -0
- data/leveldb/db/version_edit.cc +266 -0
- data/leveldb/db/version_edit.h +107 -0
- data/leveldb/db/version_edit_test.cc +46 -0
- data/leveldb/db/version_set.cc +1402 -0
- data/leveldb/db/version_set.h +370 -0
- data/leveldb/db/version_set_test.cc +179 -0
- data/leveldb/db/write_batch.cc +147 -0
- data/leveldb/db/write_batch_internal.h +49 -0
- data/leveldb/db/write_batch_test.cc +120 -0
- data/leveldb/helpers/memenv/memenv.cc +374 -0
- data/leveldb/helpers/memenv/memenv.h +20 -0
- data/leveldb/helpers/memenv/memenv_test.cc +232 -0
- data/leveldb/include/leveldb/c.h +275 -0
- data/leveldb/include/leveldb/cache.h +99 -0
- data/leveldb/include/leveldb/comparator.h +63 -0
- data/leveldb/include/leveldb/db.h +161 -0
- data/leveldb/include/leveldb/env.h +323 -0
- data/leveldb/include/leveldb/filter_policy.h +70 -0
- data/leveldb/include/leveldb/iterator.h +100 -0
- data/leveldb/include/leveldb/options.h +195 -0
- data/leveldb/include/leveldb/slice.h +109 -0
- data/leveldb/include/leveldb/status.h +106 -0
- data/leveldb/include/leveldb/table.h +85 -0
- data/leveldb/include/leveldb/table_builder.h +92 -0
- data/leveldb/include/leveldb/write_batch.h +64 -0
- data/leveldb/port/atomic_pointer.h +144 -0
- data/leveldb/port/port.h +21 -0
- data/leveldb/port/port_android.cc +64 -0
- data/leveldb/port/port_android.h +159 -0
- data/leveldb/port/port_example.h +125 -0
- data/leveldb/port/port_posix.cc +50 -0
- data/leveldb/port/port_posix.h +129 -0
- data/leveldb/port/win/stdint.h +24 -0
- data/leveldb/table/block.cc +267 -0
- data/leveldb/table/block.h +44 -0
- data/leveldb/table/block_builder.cc +109 -0
- data/leveldb/table/block_builder.h +57 -0
- 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 +145 -0
- data/leveldb/table/format.h +108 -0
- data/leveldb/table/iterator.cc +67 -0
- data/leveldb/table/iterator_wrapper.h +63 -0
- data/leveldb/table/merger.cc +197 -0
- data/leveldb/table/merger.h +26 -0
- data/leveldb/table/table.cc +276 -0
- data/leveldb/table/table_builder.cc +270 -0
- data/leveldb/table/table_test.cc +838 -0
- data/leveldb/table/two_level_iterator.cc +182 -0
- data/leveldb/table/two_level_iterator.h +34 -0
- data/leveldb/util/arena.cc +68 -0
- data/leveldb/util/arena.h +68 -0
- data/leveldb/util/arena_test.cc +68 -0
- data/leveldb/util/bloom.cc +95 -0
- data/leveldb/util/bloom_test.cc +159 -0
- data/leveldb/util/cache.cc +328 -0
- data/leveldb/util/cache_test.cc +186 -0
- data/leveldb/util/coding.cc +194 -0
- data/leveldb/util/coding.h +104 -0
- data/leveldb/util/coding_test.cc +173 -0
- data/leveldb/util/comparator.cc +76 -0
- data/leveldb/util/crc32c.cc +332 -0
- data/leveldb/util/crc32c.h +45 -0
- data/leveldb/util/crc32c_test.cc +72 -0
- data/leveldb/util/env.cc +96 -0
- data/leveldb/util/env_posix.cc +609 -0
- data/leveldb/util/env_test.cc +104 -0
- data/leveldb/util/filter_policy.cc +11 -0
- data/leveldb/util/hash.cc +45 -0
- data/leveldb/util/hash.h +19 -0
- data/leveldb/util/histogram.cc +139 -0
- data/leveldb/util/histogram.h +42 -0
- data/leveldb/util/logging.cc +81 -0
- data/leveldb/util/logging.h +47 -0
- data/leveldb/util/mutexlock.h +39 -0
- data/leveldb/util/options.cc +29 -0
- data/leveldb/util/posix_logger.h +98 -0
- data/leveldb/util/random.h +59 -0
- data/leveldb/util/status.cc +75 -0
- data/leveldb/util/testharness.cc +77 -0
- data/leveldb/util/testharness.h +138 -0
- data/leveldb/util/testutil.cc +51 -0
- data/leveldb/util/testutil.h +53 -0
- data/lib/leveldb.rb +76 -0
- metadata +175 -0
@@ -0,0 +1,140 @@
|
|
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 <stdio.h>
|
6
|
+
#include "db/dbformat.h"
|
7
|
+
#include "port/port.h"
|
8
|
+
#include "util/coding.h"
|
9
|
+
|
10
|
+
namespace leveldb {
|
11
|
+
|
12
|
+
static uint64_t PackSequenceAndType(uint64_t seq, ValueType t) {
|
13
|
+
assert(seq <= kMaxSequenceNumber);
|
14
|
+
assert(t <= kValueTypeForSeek);
|
15
|
+
return (seq << 8) | t;
|
16
|
+
}
|
17
|
+
|
18
|
+
void AppendInternalKey(std::string* result, const ParsedInternalKey& key) {
|
19
|
+
result->append(key.user_key.data(), key.user_key.size());
|
20
|
+
PutFixed64(result, PackSequenceAndType(key.sequence, key.type));
|
21
|
+
}
|
22
|
+
|
23
|
+
std::string ParsedInternalKey::DebugString() const {
|
24
|
+
char buf[50];
|
25
|
+
snprintf(buf, sizeof(buf), "' @ %llu : %d",
|
26
|
+
(unsigned long long) sequence,
|
27
|
+
int(type));
|
28
|
+
std::string result = "'";
|
29
|
+
result += user_key.ToString();
|
30
|
+
result += buf;
|
31
|
+
return result;
|
32
|
+
}
|
33
|
+
|
34
|
+
std::string InternalKey::DebugString() const {
|
35
|
+
std::string result;
|
36
|
+
ParsedInternalKey parsed;
|
37
|
+
if (ParseInternalKey(rep_, &parsed)) {
|
38
|
+
result = parsed.DebugString();
|
39
|
+
} else {
|
40
|
+
result = "(bad)";
|
41
|
+
result.append(EscapeString(rep_));
|
42
|
+
}
|
43
|
+
return result;
|
44
|
+
}
|
45
|
+
|
46
|
+
const char* InternalKeyComparator::Name() const {
|
47
|
+
return "leveldb.InternalKeyComparator";
|
48
|
+
}
|
49
|
+
|
50
|
+
int InternalKeyComparator::Compare(const Slice& akey, const Slice& bkey) const {
|
51
|
+
// Order by:
|
52
|
+
// increasing user key (according to user-supplied comparator)
|
53
|
+
// decreasing sequence number
|
54
|
+
// decreasing type (though sequence# should be enough to disambiguate)
|
55
|
+
int r = user_comparator_->Compare(ExtractUserKey(akey), ExtractUserKey(bkey));
|
56
|
+
if (r == 0) {
|
57
|
+
const uint64_t anum = DecodeFixed64(akey.data() + akey.size() - 8);
|
58
|
+
const uint64_t bnum = DecodeFixed64(bkey.data() + bkey.size() - 8);
|
59
|
+
if (anum > bnum) {
|
60
|
+
r = -1;
|
61
|
+
} else if (anum < bnum) {
|
62
|
+
r = +1;
|
63
|
+
}
|
64
|
+
}
|
65
|
+
return r;
|
66
|
+
}
|
67
|
+
|
68
|
+
void InternalKeyComparator::FindShortestSeparator(
|
69
|
+
std::string* start,
|
70
|
+
const Slice& limit) const {
|
71
|
+
// Attempt to shorten the user portion of the key
|
72
|
+
Slice user_start = ExtractUserKey(*start);
|
73
|
+
Slice user_limit = ExtractUserKey(limit);
|
74
|
+
std::string tmp(user_start.data(), user_start.size());
|
75
|
+
user_comparator_->FindShortestSeparator(&tmp, user_limit);
|
76
|
+
if (tmp.size() < user_start.size() &&
|
77
|
+
user_comparator_->Compare(user_start, tmp) < 0) {
|
78
|
+
// User key has become shorter physically, but larger logically.
|
79
|
+
// Tack on the earliest possible number to the shortened user key.
|
80
|
+
PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber,kValueTypeForSeek));
|
81
|
+
assert(this->Compare(*start, tmp) < 0);
|
82
|
+
assert(this->Compare(tmp, limit) < 0);
|
83
|
+
start->swap(tmp);
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
void InternalKeyComparator::FindShortSuccessor(std::string* key) const {
|
88
|
+
Slice user_key = ExtractUserKey(*key);
|
89
|
+
std::string tmp(user_key.data(), user_key.size());
|
90
|
+
user_comparator_->FindShortSuccessor(&tmp);
|
91
|
+
if (tmp.size() < user_key.size() &&
|
92
|
+
user_comparator_->Compare(user_key, tmp) < 0) {
|
93
|
+
// User key has become shorter physically, but larger logically.
|
94
|
+
// Tack on the earliest possible number to the shortened user key.
|
95
|
+
PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber,kValueTypeForSeek));
|
96
|
+
assert(this->Compare(*key, tmp) < 0);
|
97
|
+
key->swap(tmp);
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|
101
|
+
const char* InternalFilterPolicy::Name() const {
|
102
|
+
return user_policy_->Name();
|
103
|
+
}
|
104
|
+
|
105
|
+
void InternalFilterPolicy::CreateFilter(const Slice* keys, int n,
|
106
|
+
std::string* dst) const {
|
107
|
+
// We rely on the fact that the code in table.cc does not mind us
|
108
|
+
// adjusting keys[].
|
109
|
+
Slice* mkey = const_cast<Slice*>(keys);
|
110
|
+
for (int i = 0; i < n; i++) {
|
111
|
+
mkey[i] = ExtractUserKey(keys[i]);
|
112
|
+
// TODO(sanjay): Suppress dups?
|
113
|
+
}
|
114
|
+
user_policy_->CreateFilter(keys, n, dst);
|
115
|
+
}
|
116
|
+
|
117
|
+
bool InternalFilterPolicy::KeyMayMatch(const Slice& key, const Slice& f) const {
|
118
|
+
return user_policy_->KeyMayMatch(ExtractUserKey(key), f);
|
119
|
+
}
|
120
|
+
|
121
|
+
LookupKey::LookupKey(const Slice& user_key, SequenceNumber s) {
|
122
|
+
size_t usize = user_key.size();
|
123
|
+
size_t needed = usize + 13; // A conservative estimate
|
124
|
+
char* dst;
|
125
|
+
if (needed <= sizeof(space_)) {
|
126
|
+
dst = space_;
|
127
|
+
} else {
|
128
|
+
dst = new char[needed];
|
129
|
+
}
|
130
|
+
start_ = dst;
|
131
|
+
dst = EncodeVarint32(dst, usize + 8);
|
132
|
+
kstart_ = dst;
|
133
|
+
memcpy(dst, user_key.data(), usize);
|
134
|
+
dst += usize;
|
135
|
+
EncodeFixed64(dst, PackSequenceAndType(s, kValueTypeForSeek));
|
136
|
+
dst += 8;
|
137
|
+
end_ = dst;
|
138
|
+
}
|
139
|
+
|
140
|
+
} // namespace leveldb
|
@@ -0,0 +1,227 @@
|
|
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_DB_FORMAT_H_
|
6
|
+
#define STORAGE_LEVELDB_DB_FORMAT_H_
|
7
|
+
|
8
|
+
#include <stdio.h>
|
9
|
+
#include "leveldb/comparator.h"
|
10
|
+
#include "leveldb/db.h"
|
11
|
+
#include "leveldb/filter_policy.h"
|
12
|
+
#include "leveldb/slice.h"
|
13
|
+
#include "leveldb/table_builder.h"
|
14
|
+
#include "util/coding.h"
|
15
|
+
#include "util/logging.h"
|
16
|
+
|
17
|
+
namespace leveldb {
|
18
|
+
|
19
|
+
// Grouping of constants. We may want to make some of these
|
20
|
+
// parameters set via options.
|
21
|
+
namespace config {
|
22
|
+
static const int kNumLevels = 7;
|
23
|
+
|
24
|
+
// Level-0 compaction is started when we hit this many files.
|
25
|
+
static const int kL0_CompactionTrigger = 4;
|
26
|
+
|
27
|
+
// Soft limit on number of level-0 files. We slow down writes at this point.
|
28
|
+
static const int kL0_SlowdownWritesTrigger = 8;
|
29
|
+
|
30
|
+
// Maximum number of level-0 files. We stop writes at this point.
|
31
|
+
static const int kL0_StopWritesTrigger = 12;
|
32
|
+
|
33
|
+
// Maximum level to which a new compacted memtable is pushed if it
|
34
|
+
// does not create overlap. We try to push to level 2 to avoid the
|
35
|
+
// relatively expensive level 0=>1 compactions and to avoid some
|
36
|
+
// expensive manifest file operations. We do not push all the way to
|
37
|
+
// the largest level since that can generate a lot of wasted disk
|
38
|
+
// space if the same key space is being repeatedly overwritten.
|
39
|
+
static const int kMaxMemCompactLevel = 2;
|
40
|
+
|
41
|
+
} // namespace config
|
42
|
+
|
43
|
+
class InternalKey;
|
44
|
+
|
45
|
+
// Value types encoded as the last component of internal keys.
|
46
|
+
// DO NOT CHANGE THESE ENUM VALUES: they are embedded in the on-disk
|
47
|
+
// data structures.
|
48
|
+
enum ValueType {
|
49
|
+
kTypeDeletion = 0x0,
|
50
|
+
kTypeValue = 0x1
|
51
|
+
};
|
52
|
+
// kValueTypeForSeek defines the ValueType that should be passed when
|
53
|
+
// constructing a ParsedInternalKey object for seeking to a particular
|
54
|
+
// sequence number (since we sort sequence numbers in decreasing order
|
55
|
+
// and the value type is embedded as the low 8 bits in the sequence
|
56
|
+
// number in internal keys, we need to use the highest-numbered
|
57
|
+
// ValueType, not the lowest).
|
58
|
+
static const ValueType kValueTypeForSeek = kTypeValue;
|
59
|
+
|
60
|
+
typedef uint64_t SequenceNumber;
|
61
|
+
|
62
|
+
// We leave eight bits empty at the bottom so a type and sequence#
|
63
|
+
// can be packed together into 64-bits.
|
64
|
+
static const SequenceNumber kMaxSequenceNumber =
|
65
|
+
((0x1ull << 56) - 1);
|
66
|
+
|
67
|
+
struct ParsedInternalKey {
|
68
|
+
Slice user_key;
|
69
|
+
SequenceNumber sequence;
|
70
|
+
ValueType type;
|
71
|
+
|
72
|
+
ParsedInternalKey() { } // Intentionally left uninitialized (for speed)
|
73
|
+
ParsedInternalKey(const Slice& u, const SequenceNumber& seq, ValueType t)
|
74
|
+
: user_key(u), sequence(seq), type(t) { }
|
75
|
+
std::string DebugString() const;
|
76
|
+
};
|
77
|
+
|
78
|
+
// Return the length of the encoding of "key".
|
79
|
+
inline size_t InternalKeyEncodingLength(const ParsedInternalKey& key) {
|
80
|
+
return key.user_key.size() + 8;
|
81
|
+
}
|
82
|
+
|
83
|
+
// Append the serialization of "key" to *result.
|
84
|
+
extern void AppendInternalKey(std::string* result,
|
85
|
+
const ParsedInternalKey& key);
|
86
|
+
|
87
|
+
// Attempt to parse an internal key from "internal_key". On success,
|
88
|
+
// stores the parsed data in "*result", and returns true.
|
89
|
+
//
|
90
|
+
// On error, returns false, leaves "*result" in an undefined state.
|
91
|
+
extern bool ParseInternalKey(const Slice& internal_key,
|
92
|
+
ParsedInternalKey* result);
|
93
|
+
|
94
|
+
// Returns the user key portion of an internal key.
|
95
|
+
inline Slice ExtractUserKey(const Slice& internal_key) {
|
96
|
+
assert(internal_key.size() >= 8);
|
97
|
+
return Slice(internal_key.data(), internal_key.size() - 8);
|
98
|
+
}
|
99
|
+
|
100
|
+
inline ValueType ExtractValueType(const Slice& internal_key) {
|
101
|
+
assert(internal_key.size() >= 8);
|
102
|
+
const size_t n = internal_key.size();
|
103
|
+
uint64_t num = DecodeFixed64(internal_key.data() + n - 8);
|
104
|
+
unsigned char c = num & 0xff;
|
105
|
+
return static_cast<ValueType>(c);
|
106
|
+
}
|
107
|
+
|
108
|
+
// A comparator for internal keys that uses a specified comparator for
|
109
|
+
// the user key portion and breaks ties by decreasing sequence number.
|
110
|
+
class InternalKeyComparator : public Comparator {
|
111
|
+
private:
|
112
|
+
const Comparator* user_comparator_;
|
113
|
+
public:
|
114
|
+
explicit InternalKeyComparator(const Comparator* c) : user_comparator_(c) { }
|
115
|
+
virtual const char* Name() const;
|
116
|
+
virtual int Compare(const Slice& a, const Slice& b) const;
|
117
|
+
virtual void FindShortestSeparator(
|
118
|
+
std::string* start,
|
119
|
+
const Slice& limit) const;
|
120
|
+
virtual void FindShortSuccessor(std::string* key) const;
|
121
|
+
|
122
|
+
const Comparator* user_comparator() const { return user_comparator_; }
|
123
|
+
|
124
|
+
int Compare(const InternalKey& a, const InternalKey& b) const;
|
125
|
+
};
|
126
|
+
|
127
|
+
// Filter policy wrapper that converts from internal keys to user keys
|
128
|
+
class InternalFilterPolicy : public FilterPolicy {
|
129
|
+
private:
|
130
|
+
const FilterPolicy* const user_policy_;
|
131
|
+
public:
|
132
|
+
explicit InternalFilterPolicy(const FilterPolicy* p) : user_policy_(p) { }
|
133
|
+
virtual const char* Name() const;
|
134
|
+
virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const;
|
135
|
+
virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const;
|
136
|
+
};
|
137
|
+
|
138
|
+
// Modules in this directory should keep internal keys wrapped inside
|
139
|
+
// the following class instead of plain strings so that we do not
|
140
|
+
// incorrectly use string comparisons instead of an InternalKeyComparator.
|
141
|
+
class InternalKey {
|
142
|
+
private:
|
143
|
+
std::string rep_;
|
144
|
+
public:
|
145
|
+
InternalKey() { } // Leave rep_ as empty to indicate it is invalid
|
146
|
+
InternalKey(const Slice& user_key, SequenceNumber s, ValueType t) {
|
147
|
+
AppendInternalKey(&rep_, ParsedInternalKey(user_key, s, t));
|
148
|
+
}
|
149
|
+
|
150
|
+
void DecodeFrom(const Slice& s) { rep_.assign(s.data(), s.size()); }
|
151
|
+
Slice Encode() const {
|
152
|
+
assert(!rep_.empty());
|
153
|
+
return rep_;
|
154
|
+
}
|
155
|
+
|
156
|
+
Slice user_key() const { return ExtractUserKey(rep_); }
|
157
|
+
|
158
|
+
void SetFrom(const ParsedInternalKey& p) {
|
159
|
+
rep_.clear();
|
160
|
+
AppendInternalKey(&rep_, p);
|
161
|
+
}
|
162
|
+
|
163
|
+
void Clear() { rep_.clear(); }
|
164
|
+
|
165
|
+
std::string DebugString() const;
|
166
|
+
};
|
167
|
+
|
168
|
+
inline int InternalKeyComparator::Compare(
|
169
|
+
const InternalKey& a, const InternalKey& b) const {
|
170
|
+
return Compare(a.Encode(), b.Encode());
|
171
|
+
}
|
172
|
+
|
173
|
+
inline bool ParseInternalKey(const Slice& internal_key,
|
174
|
+
ParsedInternalKey* result) {
|
175
|
+
const size_t n = internal_key.size();
|
176
|
+
if (n < 8) return false;
|
177
|
+
uint64_t num = DecodeFixed64(internal_key.data() + n - 8);
|
178
|
+
unsigned char c = num & 0xff;
|
179
|
+
result->sequence = num >> 8;
|
180
|
+
result->type = static_cast<ValueType>(c);
|
181
|
+
result->user_key = Slice(internal_key.data(), n - 8);
|
182
|
+
return (c <= static_cast<unsigned char>(kTypeValue));
|
183
|
+
}
|
184
|
+
|
185
|
+
// A helper class useful for DBImpl::Get()
|
186
|
+
class LookupKey {
|
187
|
+
public:
|
188
|
+
// Initialize *this for looking up user_key at a snapshot with
|
189
|
+
// the specified sequence number.
|
190
|
+
LookupKey(const Slice& user_key, SequenceNumber sequence);
|
191
|
+
|
192
|
+
~LookupKey();
|
193
|
+
|
194
|
+
// Return a key suitable for lookup in a MemTable.
|
195
|
+
Slice memtable_key() const { return Slice(start_, end_ - start_); }
|
196
|
+
|
197
|
+
// Return an internal key (suitable for passing to an internal iterator)
|
198
|
+
Slice internal_key() const { return Slice(kstart_, end_ - kstart_); }
|
199
|
+
|
200
|
+
// Return the user key
|
201
|
+
Slice user_key() const { return Slice(kstart_, end_ - kstart_ - 8); }
|
202
|
+
|
203
|
+
private:
|
204
|
+
// We construct a char array of the form:
|
205
|
+
// klength varint32 <-- start_
|
206
|
+
// userkey char[klength] <-- kstart_
|
207
|
+
// tag uint64
|
208
|
+
// <-- end_
|
209
|
+
// The array is a suitable MemTable key.
|
210
|
+
// The suffix starting with "userkey" can be used as an InternalKey.
|
211
|
+
const char* start_;
|
212
|
+
const char* kstart_;
|
213
|
+
const char* end_;
|
214
|
+
char space_[200]; // Avoid allocation for short keys
|
215
|
+
|
216
|
+
// No copying allowed
|
217
|
+
LookupKey(const LookupKey&);
|
218
|
+
void operator=(const LookupKey&);
|
219
|
+
};
|
220
|
+
|
221
|
+
inline LookupKey::~LookupKey() {
|
222
|
+
if (start_ != space_) delete[] start_;
|
223
|
+
}
|
224
|
+
|
225
|
+
} // namespace leveldb
|
226
|
+
|
227
|
+
#endif // STORAGE_LEVELDB_DB_FORMAT_H_
|
@@ -0,0 +1,112 @@
|
|
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 "db/dbformat.h"
|
6
|
+
#include "util/logging.h"
|
7
|
+
#include "util/testharness.h"
|
8
|
+
|
9
|
+
namespace leveldb {
|
10
|
+
|
11
|
+
static std::string IKey(const std::string& user_key,
|
12
|
+
uint64_t seq,
|
13
|
+
ValueType vt) {
|
14
|
+
std::string encoded;
|
15
|
+
AppendInternalKey(&encoded, ParsedInternalKey(user_key, seq, vt));
|
16
|
+
return encoded;
|
17
|
+
}
|
18
|
+
|
19
|
+
static std::string Shorten(const std::string& s, const std::string& l) {
|
20
|
+
std::string result = s;
|
21
|
+
InternalKeyComparator(BytewiseComparator()).FindShortestSeparator(&result, l);
|
22
|
+
return result;
|
23
|
+
}
|
24
|
+
|
25
|
+
static std::string ShortSuccessor(const std::string& s) {
|
26
|
+
std::string result = s;
|
27
|
+
InternalKeyComparator(BytewiseComparator()).FindShortSuccessor(&result);
|
28
|
+
return result;
|
29
|
+
}
|
30
|
+
|
31
|
+
static void TestKey(const std::string& key,
|
32
|
+
uint64_t seq,
|
33
|
+
ValueType vt) {
|
34
|
+
std::string encoded = IKey(key, seq, vt);
|
35
|
+
|
36
|
+
Slice in(encoded);
|
37
|
+
ParsedInternalKey decoded("", 0, kTypeValue);
|
38
|
+
|
39
|
+
ASSERT_TRUE(ParseInternalKey(in, &decoded));
|
40
|
+
ASSERT_EQ(key, decoded.user_key.ToString());
|
41
|
+
ASSERT_EQ(seq, decoded.sequence);
|
42
|
+
ASSERT_EQ(vt, decoded.type);
|
43
|
+
|
44
|
+
ASSERT_TRUE(!ParseInternalKey(Slice("bar"), &decoded));
|
45
|
+
}
|
46
|
+
|
47
|
+
class FormatTest { };
|
48
|
+
|
49
|
+
TEST(FormatTest, InternalKey_EncodeDecode) {
|
50
|
+
const char* keys[] = { "", "k", "hello", "longggggggggggggggggggggg" };
|
51
|
+
const uint64_t seq[] = {
|
52
|
+
1, 2, 3,
|
53
|
+
(1ull << 8) - 1, 1ull << 8, (1ull << 8) + 1,
|
54
|
+
(1ull << 16) - 1, 1ull << 16, (1ull << 16) + 1,
|
55
|
+
(1ull << 32) - 1, 1ull << 32, (1ull << 32) + 1
|
56
|
+
};
|
57
|
+
for (int k = 0; k < sizeof(keys) / sizeof(keys[0]); k++) {
|
58
|
+
for (int s = 0; s < sizeof(seq) / sizeof(seq[0]); s++) {
|
59
|
+
TestKey(keys[k], seq[s], kTypeValue);
|
60
|
+
TestKey("hello", 1, kTypeDeletion);
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
TEST(FormatTest, InternalKeyShortSeparator) {
|
66
|
+
// When user keys are same
|
67
|
+
ASSERT_EQ(IKey("foo", 100, kTypeValue),
|
68
|
+
Shorten(IKey("foo", 100, kTypeValue),
|
69
|
+
IKey("foo", 99, kTypeValue)));
|
70
|
+
ASSERT_EQ(IKey("foo", 100, kTypeValue),
|
71
|
+
Shorten(IKey("foo", 100, kTypeValue),
|
72
|
+
IKey("foo", 101, kTypeValue)));
|
73
|
+
ASSERT_EQ(IKey("foo", 100, kTypeValue),
|
74
|
+
Shorten(IKey("foo", 100, kTypeValue),
|
75
|
+
IKey("foo", 100, kTypeValue)));
|
76
|
+
ASSERT_EQ(IKey("foo", 100, kTypeValue),
|
77
|
+
Shorten(IKey("foo", 100, kTypeValue),
|
78
|
+
IKey("foo", 100, kTypeDeletion)));
|
79
|
+
|
80
|
+
// When user keys are misordered
|
81
|
+
ASSERT_EQ(IKey("foo", 100, kTypeValue),
|
82
|
+
Shorten(IKey("foo", 100, kTypeValue),
|
83
|
+
IKey("bar", 99, kTypeValue)));
|
84
|
+
|
85
|
+
// When user keys are different, but correctly ordered
|
86
|
+
ASSERT_EQ(IKey("g", kMaxSequenceNumber, kValueTypeForSeek),
|
87
|
+
Shorten(IKey("foo", 100, kTypeValue),
|
88
|
+
IKey("hello", 200, kTypeValue)));
|
89
|
+
|
90
|
+
// When start user key is prefix of limit user key
|
91
|
+
ASSERT_EQ(IKey("foo", 100, kTypeValue),
|
92
|
+
Shorten(IKey("foo", 100, kTypeValue),
|
93
|
+
IKey("foobar", 200, kTypeValue)));
|
94
|
+
|
95
|
+
// When limit user key is prefix of start user key
|
96
|
+
ASSERT_EQ(IKey("foobar", 100, kTypeValue),
|
97
|
+
Shorten(IKey("foobar", 100, kTypeValue),
|
98
|
+
IKey("foo", 200, kTypeValue)));
|
99
|
+
}
|
100
|
+
|
101
|
+
TEST(FormatTest, InternalKeyShortestSuccessor) {
|
102
|
+
ASSERT_EQ(IKey("g", kMaxSequenceNumber, kValueTypeForSeek),
|
103
|
+
ShortSuccessor(IKey("foo", 100, kTypeValue)));
|
104
|
+
ASSERT_EQ(IKey("\xff\xff", 100, kTypeValue),
|
105
|
+
ShortSuccessor(IKey("\xff\xff", 100, kTypeValue)));
|
106
|
+
}
|
107
|
+
|
108
|
+
} // namespace leveldb
|
109
|
+
|
110
|
+
int main(int argc, char** argv) {
|
111
|
+
return leveldb::test::RunAllTests();
|
112
|
+
}
|