leveldb-ruby 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. data/README +17 -0
  2. data/ext/leveldb/extconf.rb +10 -0
  3. data/ext/leveldb/leveldb.cc +181 -0
  4. data/leveldb/Makefile +172 -0
  5. data/leveldb/db/builder.cc +90 -0
  6. data/leveldb/db/builder.h +36 -0
  7. data/leveldb/db/corruption_test.cc +354 -0
  8. data/leveldb/db/db_bench.cc +677 -0
  9. data/leveldb/db/db_impl.cc +1236 -0
  10. data/leveldb/db/db_impl.h +180 -0
  11. data/leveldb/db/db_iter.cc +298 -0
  12. data/leveldb/db/db_iter.h +26 -0
  13. data/leveldb/db/db_test.cc +1192 -0
  14. data/leveldb/db/dbformat.cc +87 -0
  15. data/leveldb/db/dbformat.h +165 -0
  16. data/leveldb/db/dbformat_test.cc +112 -0
  17. data/leveldb/db/filename.cc +135 -0
  18. data/leveldb/db/filename.h +80 -0
  19. data/leveldb/db/filename_test.cc +122 -0
  20. data/leveldb/db/log_format.h +35 -0
  21. data/leveldb/db/log_reader.cc +254 -0
  22. data/leveldb/db/log_reader.h +108 -0
  23. data/leveldb/db/log_test.cc +500 -0
  24. data/leveldb/db/log_writer.cc +103 -0
  25. data/leveldb/db/log_writer.h +48 -0
  26. data/leveldb/db/memtable.cc +108 -0
  27. data/leveldb/db/memtable.h +85 -0
  28. data/leveldb/db/repair.cc +384 -0
  29. data/leveldb/db/skiplist.h +378 -0
  30. data/leveldb/db/skiplist_test.cc +378 -0
  31. data/leveldb/db/snapshot.h +66 -0
  32. data/leveldb/db/table_cache.cc +95 -0
  33. data/leveldb/db/table_cache.h +50 -0
  34. data/leveldb/db/version_edit.cc +268 -0
  35. data/leveldb/db/version_edit.h +106 -0
  36. data/leveldb/db/version_edit_test.cc +46 -0
  37. data/leveldb/db/version_set.cc +1060 -0
  38. data/leveldb/db/version_set.h +306 -0
  39. data/leveldb/db/write_batch.cc +138 -0
  40. data/leveldb/db/write_batch_internal.h +45 -0
  41. data/leveldb/db/write_batch_test.cc +89 -0
  42. data/leveldb/include/leveldb/cache.h +99 -0
  43. data/leveldb/include/leveldb/comparator.h +63 -0
  44. data/leveldb/include/leveldb/db.h +148 -0
  45. data/leveldb/include/leveldb/env.h +302 -0
  46. data/leveldb/include/leveldb/iterator.h +100 -0
  47. data/leveldb/include/leveldb/options.h +198 -0
  48. data/leveldb/include/leveldb/slice.h +109 -0
  49. data/leveldb/include/leveldb/status.h +100 -0
  50. data/leveldb/include/leveldb/table.h +70 -0
  51. data/leveldb/include/leveldb/table_builder.h +91 -0
  52. data/leveldb/include/leveldb/write_batch.h +64 -0
  53. data/leveldb/port/port.h +23 -0
  54. data/leveldb/port/port_android.cc +64 -0
  55. data/leveldb/port/port_android.h +150 -0
  56. data/leveldb/port/port_chromium.cc +80 -0
  57. data/leveldb/port/port_chromium.h +97 -0
  58. data/leveldb/port/port_example.h +115 -0
  59. data/leveldb/port/port_osx.cc +50 -0
  60. data/leveldb/port/port_osx.h +125 -0
  61. data/leveldb/port/port_posix.cc +50 -0
  62. data/leveldb/port/port_posix.h +94 -0
  63. data/leveldb/port/sha1_portable.cc +298 -0
  64. data/leveldb/port/sha1_portable.h +25 -0
  65. data/leveldb/port/sha1_test.cc +39 -0
  66. data/leveldb/port/win/stdint.h +24 -0
  67. data/leveldb/table/block.cc +263 -0
  68. data/leveldb/table/block.h +43 -0
  69. data/leveldb/table/block_builder.cc +109 -0
  70. data/leveldb/table/block_builder.h +57 -0
  71. data/leveldb/table/format.cc +131 -0
  72. data/leveldb/table/format.h +103 -0
  73. data/leveldb/table/iterator.cc +67 -0
  74. data/leveldb/table/iterator_wrapper.h +63 -0
  75. data/leveldb/table/merger.cc +197 -0
  76. data/leveldb/table/merger.h +26 -0
  77. data/leveldb/table/table.cc +175 -0
  78. data/leveldb/table/table_builder.cc +227 -0
  79. data/leveldb/table/table_test.cc +845 -0
  80. data/leveldb/table/two_level_iterator.cc +182 -0
  81. data/leveldb/table/two_level_iterator.h +34 -0
  82. data/leveldb/util/arena.cc +68 -0
  83. data/leveldb/util/arena.h +68 -0
  84. data/leveldb/util/arena_test.cc +68 -0
  85. data/leveldb/util/cache.cc +255 -0
  86. data/leveldb/util/cache_test.cc +169 -0
  87. data/leveldb/util/coding.cc +194 -0
  88. data/leveldb/util/coding.h +104 -0
  89. data/leveldb/util/coding_test.cc +173 -0
  90. data/leveldb/util/comparator.cc +72 -0
  91. data/leveldb/util/crc32c.cc +332 -0
  92. data/leveldb/util/crc32c.h +45 -0
  93. data/leveldb/util/crc32c_test.cc +72 -0
  94. data/leveldb/util/env.cc +77 -0
  95. data/leveldb/util/env_chromium.cc +612 -0
  96. data/leveldb/util/env_posix.cc +606 -0
  97. data/leveldb/util/env_test.cc +102 -0
  98. data/leveldb/util/hash.cc +45 -0
  99. data/leveldb/util/hash.h +19 -0
  100. data/leveldb/util/histogram.cc +128 -0
  101. data/leveldb/util/histogram.h +41 -0
  102. data/leveldb/util/logging.cc +81 -0
  103. data/leveldb/util/logging.h +47 -0
  104. data/leveldb/util/mutexlock.h +39 -0
  105. data/leveldb/util/options.cc +28 -0
  106. data/leveldb/util/random.h +59 -0
  107. data/leveldb/util/status.cc +75 -0
  108. data/leveldb/util/testharness.cc +65 -0
  109. data/leveldb/util/testharness.h +129 -0
  110. data/leveldb/util/testutil.cc +51 -0
  111. data/leveldb/util/testutil.h +53 -0
  112. data/lib/leveldb.rb +36 -0
  113. metadata +183 -0
@@ -0,0 +1,39 @@
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 "port/port.h"
6
+ #include "util/testharness.h"
7
+
8
+ namespace leveldb {
9
+ namespace port {
10
+
11
+ class SHA1 { };
12
+
13
+ static std::string TestSHA1(const char* data, size_t len) {
14
+ char hash_val[20];
15
+ SHA1_Hash(data, len, hash_val);
16
+ char buf[41];
17
+ for (int i = 0; i < 20; i++) {
18
+ snprintf(buf + i * 2, 41 - i * 2,
19
+ "%02x",
20
+ static_cast<unsigned int>(static_cast<unsigned char>(
21
+ hash_val[i])));
22
+ }
23
+ return std::string(buf, 40);
24
+ }
25
+
26
+ TEST(SHA1, Simple) {
27
+ ASSERT_EQ("da39a3ee5e6b4b0d3255bfef95601890afd80709", TestSHA1("", 0));
28
+ ASSERT_EQ("aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d", TestSHA1("hello", 5));
29
+ std::string x(10000, 'x');
30
+ ASSERT_EQ("f8c5cde791c5056cf515881e701c8a9ecb439a75",
31
+ TestSHA1(x.data(), x.size()));
32
+ }
33
+
34
+ }
35
+ }
36
+
37
+ int main(int argc, char** argv) {
38
+ return leveldb::test::RunAllTests();
39
+ }
@@ -0,0 +1,24 @@
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
+ // MSVC didn't ship with this file until the 2010 version.
6
+
7
+ #ifndef STORAGE_LEVELDB_PORT_WIN_STDINT_H_
8
+ #define STORAGE_LEVELDB_PORT_WIN_STDINT_H_
9
+
10
+ #if !defined(_MSC_VER)
11
+ #error This file should only be included when compiling with MSVC.
12
+ #endif
13
+
14
+ // Define C99 equivalent types.
15
+ typedef signed char int8_t;
16
+ typedef signed short int16_t;
17
+ typedef signed int int32_t;
18
+ typedef signed long long int64_t;
19
+ typedef unsigned char uint8_t;
20
+ typedef unsigned short uint16_t;
21
+ typedef unsigned int uint32_t;
22
+ typedef unsigned long long uint64_t;
23
+
24
+ #endif // STORAGE_LEVELDB_PORT_WIN_STDINT_H_
@@ -0,0 +1,263 @@
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
+ // Decodes the blocks generated by block_builder.cc.
6
+
7
+ #include "table/block.h"
8
+
9
+ #include <vector>
10
+ #include <algorithm>
11
+ #include "leveldb/comparator.h"
12
+ #include "util/coding.h"
13
+ #include "util/logging.h"
14
+
15
+ namespace leveldb {
16
+
17
+ inline uint32_t Block::NumRestarts() const {
18
+ assert(size_ >= 2*sizeof(uint32_t));
19
+ return DecodeFixed32(data_ + size_ - sizeof(uint32_t));
20
+ }
21
+
22
+ Block::Block(const char* data, size_t size)
23
+ : data_(data),
24
+ size_(size) {
25
+ if (size_ < sizeof(uint32_t)) {
26
+ size_ = 0; // Error marker
27
+ } else {
28
+ restart_offset_ = size_ - (1 + NumRestarts()) * sizeof(uint32_t);
29
+ if (restart_offset_ > size_ - sizeof(uint32_t)) {
30
+ // The size is too small for NumRestarts() and therefore
31
+ // restart_offset_ wrapped around.
32
+ size_ = 0;
33
+ }
34
+ }
35
+ }
36
+
37
+ Block::~Block() {
38
+ delete[] data_;
39
+ }
40
+
41
+ // Helper routine: decode the next block entry starting at "p",
42
+ // storing the number of shared key bytes, non_shared key bytes,
43
+ // and the length of the value in "*shared", "*non_shared", and
44
+ // "*value_length", respectively. Will not derefence past "limit".
45
+ //
46
+ // If any errors are detected, returns NULL. Otherwise, returns a
47
+ // pointer to the key delta (just past the three decoded values).
48
+ static inline const char* DecodeEntry(const char* p, const char* limit,
49
+ uint32_t* shared,
50
+ uint32_t* non_shared,
51
+ uint32_t* value_length) {
52
+ if (limit - p < 3) return NULL;
53
+ *shared = reinterpret_cast<const unsigned char*>(p)[0];
54
+ *non_shared = reinterpret_cast<const unsigned char*>(p)[1];
55
+ *value_length = reinterpret_cast<const unsigned char*>(p)[2];
56
+ if ((*shared | *non_shared | *value_length) < 128) {
57
+ // Fast path: all three values are encoded in one byte each
58
+ p += 3;
59
+ } else {
60
+ if ((p = GetVarint32Ptr(p, limit, shared)) == NULL) return NULL;
61
+ if ((p = GetVarint32Ptr(p, limit, non_shared)) == NULL) return NULL;
62
+ if ((p = GetVarint32Ptr(p, limit, value_length)) == NULL) return NULL;
63
+ }
64
+
65
+ if (static_cast<uint32_t>(limit - p) < (*non_shared + *value_length)) {
66
+ return NULL;
67
+ }
68
+ return p;
69
+ }
70
+
71
+ class Block::Iter : public Iterator {
72
+ private:
73
+ const Comparator* const comparator_;
74
+ const char* const data_; // underlying block contents
75
+ uint32_t const restarts_; // Offset of restart array (list of fixed32)
76
+ uint32_t const num_restarts_; // Number of uint32_t entries in restart array
77
+
78
+ // current_ is offset in data_ of current entry. >= restarts_ if !Valid
79
+ uint32_t current_;
80
+ uint32_t restart_index_; // Index of restart block in which current_ falls
81
+ std::string key_;
82
+ Slice value_;
83
+ Status status_;
84
+
85
+ inline int Compare(const Slice& a, const Slice& b) const {
86
+ return comparator_->Compare(a, b);
87
+ }
88
+
89
+ // Return the offset in data_ just past the end of the current entry.
90
+ inline uint32_t NextEntryOffset() const {
91
+ return (value_.data() + value_.size()) - data_;
92
+ }
93
+
94
+ uint32_t GetRestartPoint(uint32_t index) {
95
+ assert(index < num_restarts_);
96
+ return DecodeFixed32(data_ + restarts_ + index * sizeof(uint32_t));
97
+ }
98
+
99
+ void SeekToRestartPoint(uint32_t index) {
100
+ key_.clear();
101
+ restart_index_ = index;
102
+ // current_ will be fixed by ParseNextKey();
103
+
104
+ // ParseNextKey() starts at the end of value_, so set value_ accordingly
105
+ uint32_t offset = GetRestartPoint(index);
106
+ value_ = Slice(data_ + offset, 0);
107
+ }
108
+
109
+ public:
110
+ Iter(const Comparator* comparator,
111
+ const char* data,
112
+ uint32_t restarts,
113
+ uint32_t num_restarts)
114
+ : comparator_(comparator),
115
+ data_(data),
116
+ restarts_(restarts),
117
+ num_restarts_(num_restarts),
118
+ current_(restarts_),
119
+ restart_index_(num_restarts_) {
120
+ assert(num_restarts_ > 0);
121
+ }
122
+
123
+ virtual bool Valid() const { return current_ < restarts_; }
124
+ virtual Status status() const { return status_; }
125
+ virtual Slice key() const {
126
+ assert(Valid());
127
+ return key_;
128
+ }
129
+ virtual Slice value() const {
130
+ assert(Valid());
131
+ return value_;
132
+ }
133
+
134
+ virtual void Next() {
135
+ assert(Valid());
136
+ ParseNextKey();
137
+ }
138
+
139
+ virtual void Prev() {
140
+ assert(Valid());
141
+
142
+ // Scan backwards to a restart point before current_
143
+ const uint32_t original = current_;
144
+ while (GetRestartPoint(restart_index_) >= original) {
145
+ if (restart_index_ == 0) {
146
+ // No more entries
147
+ current_ = restarts_;
148
+ restart_index_ = num_restarts_;
149
+ return;
150
+ }
151
+ restart_index_--;
152
+ }
153
+
154
+ SeekToRestartPoint(restart_index_);
155
+ do {
156
+ // Loop until end of current entry hits the start of original entry
157
+ } while (ParseNextKey() && NextEntryOffset() < original);
158
+ }
159
+
160
+ virtual void Seek(const Slice& target) {
161
+ // Binary search in restart array to find the first restart point
162
+ // with a key >= target
163
+ uint32_t left = 0;
164
+ uint32_t right = num_restarts_ - 1;
165
+ while (left < right) {
166
+ uint32_t mid = (left + right + 1) / 2;
167
+ uint32_t region_offset = GetRestartPoint(mid);
168
+ uint32_t shared, non_shared, value_length;
169
+ const char* key_ptr = DecodeEntry(data_ + region_offset,
170
+ data_ + restarts_,
171
+ &shared, &non_shared, &value_length);
172
+ if (key_ptr == NULL || (shared != 0)) {
173
+ CorruptionError();
174
+ return;
175
+ }
176
+ Slice mid_key(key_ptr, non_shared);
177
+ if (Compare(mid_key, target) < 0) {
178
+ // Key at "mid" is smaller than "target". Therefore all
179
+ // blocks before "mid" are uninteresting.
180
+ left = mid;
181
+ } else {
182
+ // Key at "mid" is >= "target". Therefore all blocks at or
183
+ // after "mid" are uninteresting.
184
+ right = mid - 1;
185
+ }
186
+ }
187
+
188
+ // Linear search (within restart block) for first key >= target
189
+ SeekToRestartPoint(left);
190
+ while (true) {
191
+ if (!ParseNextKey()) {
192
+ return;
193
+ }
194
+ if (Compare(key_, target) >= 0) {
195
+ return;
196
+ }
197
+ }
198
+ }
199
+
200
+ virtual void SeekToFirst() {
201
+ SeekToRestartPoint(0);
202
+ ParseNextKey();
203
+ }
204
+
205
+ virtual void SeekToLast() {
206
+ SeekToRestartPoint(num_restarts_ - 1);
207
+ while (ParseNextKey() && NextEntryOffset() < restarts_) {
208
+ // Keep skipping
209
+ }
210
+ }
211
+
212
+ private:
213
+ void CorruptionError() {
214
+ current_ = restarts_;
215
+ restart_index_ = num_restarts_;
216
+ status_ = Status::Corruption("bad entry in block");
217
+ key_.clear();
218
+ value_.clear();
219
+ }
220
+
221
+ bool ParseNextKey() {
222
+ current_ = NextEntryOffset();
223
+ const char* p = data_ + current_;
224
+ const char* limit = data_ + restarts_; // Restarts come right after data
225
+ if (p >= limit) {
226
+ // No more entries to return. Mark as invalid.
227
+ current_ = restarts_;
228
+ restart_index_ = num_restarts_;
229
+ return false;
230
+ }
231
+
232
+ // Decode next entry
233
+ uint32_t shared, non_shared, value_length;
234
+ p = DecodeEntry(p, limit, &shared, &non_shared, &value_length);
235
+ if (p == NULL || key_.size() < shared) {
236
+ CorruptionError();
237
+ return false;
238
+ } else {
239
+ key_.resize(shared);
240
+ key_.append(p, non_shared);
241
+ value_ = Slice(p + non_shared, value_length);
242
+ while (restart_index_ + 1 < num_restarts_ &&
243
+ GetRestartPoint(restart_index_ + 1) < current_) {
244
+ ++restart_index_;
245
+ }
246
+ return true;
247
+ }
248
+ }
249
+ };
250
+
251
+ Iterator* Block::NewIterator(const Comparator* cmp) {
252
+ if (size_ < 2*sizeof(uint32_t)) {
253
+ return NewErrorIterator(Status::Corruption("bad block contents"));
254
+ }
255
+ const uint32_t num_restarts = NumRestarts();
256
+ if (num_restarts == 0) {
257
+ return NewEmptyIterator();
258
+ } else {
259
+ return new Iter(cmp, data_, restart_offset_, num_restarts);
260
+ }
261
+ }
262
+
263
+ }
@@ -0,0 +1,43 @@
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_BLOCK_H_
6
+ #define STORAGE_LEVELDB_TABLE_BLOCK_H_
7
+
8
+ #include <stddef.h>
9
+ #include <stdint.h>
10
+ #include "leveldb/iterator.h"
11
+
12
+ namespace leveldb {
13
+
14
+ class Comparator;
15
+
16
+ class Block {
17
+ public:
18
+ // Initialize the block with the specified contents.
19
+ // Takes ownership of data[] and will delete[] it when done.
20
+ Block(const char* data, size_t size);
21
+
22
+ ~Block();
23
+
24
+ size_t size() const { return size_; }
25
+ Iterator* NewIterator(const Comparator* comparator);
26
+
27
+ private:
28
+ uint32_t NumRestarts() const;
29
+
30
+ const char* data_;
31
+ size_t size_;
32
+ uint32_t restart_offset_; // Offset in data_ of restart array
33
+
34
+ // No copying allowed
35
+ Block(const Block&);
36
+ void operator=(const Block&);
37
+
38
+ class Iter;
39
+ };
40
+
41
+ }
42
+
43
+ #endif // STORAGE_LEVELDB_TABLE_BLOCK_H_
@@ -0,0 +1,109 @@
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
+ // BlockBuilder generates blocks where keys are prefix-compressed:
6
+ //
7
+ // When we store a key, we drop the prefix shared with the previous
8
+ // string. This helps reduce the space requirement significantly.
9
+ // Furthermore, once every K keys, we do not apply the prefix
10
+ // compression and store the entire key. We call this a "restart
11
+ // point". The tail end of the block stores the offsets of all of the
12
+ // restart points, and can be used to do a binary search when looking
13
+ // for a particular key. Values are stored as-is (without compression)
14
+ // immediately following the corresponding key.
15
+ //
16
+ // An entry for a particular key-value pair has the form:
17
+ // shared_bytes: varint32
18
+ // unshared_bytes: varint32
19
+ // value_length: varint32
20
+ // key_delta: char[unshared_bytes]
21
+ // value: char[value_length]
22
+ // shared_bytes == 0 for restart points.
23
+ //
24
+ // The trailer of the block has the form:
25
+ // restarts: uint32[num_restarts]
26
+ // num_restarts: uint32
27
+ // restarts[i] contains the offset within the block of the ith restart point.
28
+
29
+ #include "table/block_builder.h"
30
+
31
+ #include <algorithm>
32
+ #include <assert.h>
33
+ #include "leveldb/comparator.h"
34
+ #include "leveldb/table_builder.h"
35
+ #include "util/coding.h"
36
+
37
+ namespace leveldb {
38
+
39
+ BlockBuilder::BlockBuilder(const Options* options)
40
+ : options_(options),
41
+ restarts_(),
42
+ counter_(0),
43
+ finished_(false) {
44
+ assert(options->block_restart_interval >= 1);
45
+ restarts_.push_back(0); // First restart point is at offset 0
46
+ }
47
+
48
+ void BlockBuilder::Reset() {
49
+ buffer_.clear();
50
+ restarts_.clear();
51
+ restarts_.push_back(0); // First restart point is at offset 0
52
+ counter_ = 0;
53
+ finished_ = false;
54
+ last_key_.clear();
55
+ }
56
+
57
+ size_t BlockBuilder::CurrentSizeEstimate() const {
58
+ return (buffer_.size() + // Raw data buffer
59
+ restarts_.size() * sizeof(uint32_t) + // Restart array
60
+ sizeof(uint32_t)); // Restart array length
61
+ }
62
+
63
+ Slice BlockBuilder::Finish() {
64
+ // Append restart array
65
+ for (size_t i = 0; i < restarts_.size(); i++) {
66
+ PutFixed32(&buffer_, restarts_[i]);
67
+ }
68
+ PutFixed32(&buffer_, restarts_.size());
69
+ finished_ = true;
70
+ return Slice(buffer_);
71
+ }
72
+
73
+ void BlockBuilder::Add(const Slice& key, const Slice& value) {
74
+ Slice last_key_piece(last_key_);
75
+ assert(!finished_);
76
+ assert(counter_ <= options_->block_restart_interval);
77
+ assert(buffer_.empty() // No values yet?
78
+ || options_->comparator->Compare(key, last_key_piece) > 0);
79
+ size_t shared = 0;
80
+ if (counter_ < options_->block_restart_interval) {
81
+ // See how much sharing to do with previous string
82
+ const size_t min_length = std::min(last_key_piece.size(), key.size());
83
+ while ((shared < min_length) && (last_key_piece[shared] == key[shared])) {
84
+ shared++;
85
+ }
86
+ } else {
87
+ // Restart compression
88
+ restarts_.push_back(buffer_.size());
89
+ counter_ = 0;
90
+ }
91
+ const size_t non_shared = key.size() - shared;
92
+
93
+ // Add "<shared><non_shared><value_size>" to buffer_
94
+ PutVarint32(&buffer_, shared);
95
+ PutVarint32(&buffer_, non_shared);
96
+ PutVarint32(&buffer_, value.size());
97
+
98
+ // Add string delta to buffer_ followed by value
99
+ buffer_.append(key.data() + shared, non_shared);
100
+ buffer_.append(value.data(), value.size());
101
+
102
+ // Update state
103
+ last_key_.resize(shared);
104
+ last_key_.append(key.data() + shared, non_shared);
105
+ assert(Slice(last_key_) == key);
106
+ counter_++;
107
+ }
108
+
109
+ }