]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/table/mock_table.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / rocksdb / table / mock_table.cc
1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under both the GPLv2 (found in the
3 // COPYING file in the root directory) and Apache 2.0 License
4 // (found in the LICENSE.Apache file in the root directory).
5
6 #include "table/mock_table.h"
7
8 #include "db/dbformat.h"
9 #include "env/composite_env_wrapper.h"
10 #include "file/random_access_file_reader.h"
11 #include "port/port.h"
12 #include "rocksdb/table_properties.h"
13 #include "table/get_context.h"
14 #include "util/coding.h"
15
16 namespace ROCKSDB_NAMESPACE {
17 namespace mock {
18
19 KVVector MakeMockFile(std::initializer_list<KVPair> l) { return KVVector(l); }
20
21 void SortKVVector(KVVector* kv_vector, const Comparator* ucmp) {
22 InternalKeyComparator icmp(ucmp);
23 std::sort(kv_vector->begin(), kv_vector->end(),
24 [icmp](KVPair a, KVPair b) -> bool {
25 return icmp.Compare(a.first, b.first) < 0;
26 });
27 }
28
29 class MockTableReader : public TableReader {
30 public:
31 explicit MockTableReader(const KVVector& table) : table_(table) {}
32
33 InternalIterator* NewIterator(const ReadOptions&,
34 const SliceTransform* prefix_extractor,
35 Arena* arena, bool skip_filters,
36 TableReaderCaller caller,
37 size_t compaction_readahead_size = 0,
38 bool allow_unprepared_value = false) override;
39
40 Status Get(const ReadOptions& readOptions, const Slice& key,
41 GetContext* get_context, const SliceTransform* prefix_extractor,
42 bool skip_filters = false) override;
43
44 uint64_t ApproximateOffsetOf(const Slice& /*key*/,
45 TableReaderCaller /*caller*/) override {
46 return 0;
47 }
48
49 uint64_t ApproximateSize(const Slice& /*start*/, const Slice& /*end*/,
50 TableReaderCaller /*caller*/) override {
51 return 0;
52 }
53
54 size_t ApproximateMemoryUsage() const override { return 0; }
55
56 void SetupForCompaction() override {}
57
58 std::shared_ptr<const TableProperties> GetTableProperties() const override;
59
60 ~MockTableReader() {}
61
62 private:
63 const KVVector& table_;
64 };
65
66 class MockTableIterator : public InternalIterator {
67 public:
68 explicit MockTableIterator(const KVVector& table) : table_(table) {
69 itr_ = table_.end();
70 }
71
72 bool Valid() const override { return itr_ != table_.end(); }
73
74 void SeekToFirst() override { itr_ = table_.begin(); }
75
76 void SeekToLast() override {
77 itr_ = table_.end();
78 --itr_;
79 }
80
81 void Seek(const Slice& target) override {
82 KVPair target_pair(target.ToString(), "");
83 InternalKeyComparator icmp(BytewiseComparator());
84 itr_ = std::lower_bound(table_.begin(), table_.end(), target_pair,
85 [icmp](KVPair a, KVPair b) -> bool {
86 return icmp.Compare(a.first, b.first) < 0;
87 });
88 }
89
90 void SeekForPrev(const Slice& target) override {
91 KVPair target_pair(target.ToString(), "");
92 InternalKeyComparator icmp(BytewiseComparator());
93 itr_ = std::upper_bound(table_.begin(), table_.end(), target_pair,
94 [icmp](KVPair a, KVPair b) -> bool {
95 return icmp.Compare(a.first, b.first) < 0;
96 });
97 Prev();
98 }
99
100 void Next() override { ++itr_; }
101
102 void Prev() override {
103 if (itr_ == table_.begin()) {
104 itr_ = table_.end();
105 } else {
106 --itr_;
107 }
108 }
109
110 Slice key() const override { return Slice(itr_->first); }
111
112 Slice value() const override { return Slice(itr_->second); }
113
114 Status status() const override { return Status::OK(); }
115
116 private:
117 const KVVector& table_;
118 KVVector::const_iterator itr_;
119 };
120
121 class MockTableBuilder : public TableBuilder {
122 public:
123 MockTableBuilder(uint32_t id, MockTableFileSystem* file_system,
124 MockTableFactory::MockCorruptionMode corrupt_mode =
125 MockTableFactory::kCorruptNone)
126 : id_(id), file_system_(file_system), corrupt_mode_(corrupt_mode) {
127 table_ = MakeMockFile({});
128 }
129
130 // REQUIRES: Either Finish() or Abandon() has been called.
131 ~MockTableBuilder() {}
132
133 // Add key,value to the table being constructed.
134 // REQUIRES: key is after any previously added key according to comparator.
135 // REQUIRES: Finish(), Abandon() have not been called
136 void Add(const Slice& key, const Slice& value) override {
137 if (corrupt_mode_ == MockTableFactory::kCorruptValue) {
138 // Corrupt the value
139 table_.push_back({key.ToString(), value.ToString() + " "});
140 corrupt_mode_ = MockTableFactory::kCorruptNone;
141 } else if (corrupt_mode_ == MockTableFactory::kCorruptKey) {
142 table_.push_back({key.ToString() + " ", value.ToString()});
143 corrupt_mode_ = MockTableFactory::kCorruptNone;
144 } else if (corrupt_mode_ == MockTableFactory::kCorruptReorderKey) {
145 if (prev_key_.empty()) {
146 prev_key_ = key.ToString();
147 prev_value_ = value.ToString();
148 } else {
149 table_.push_back({key.ToString(), value.ToString()});
150 table_.push_back({prev_key_, prev_value_});
151 corrupt_mode_ = MockTableFactory::kCorruptNone;
152 }
153 } else {
154 table_.push_back({key.ToString(), value.ToString()});
155 }
156 }
157
158 // Return non-ok iff some error has been detected.
159 Status status() const override { return Status::OK(); }
160
161 // Return non-ok iff some error happens during IO.
162 IOStatus io_status() const override { return IOStatus::OK(); }
163
164 Status Finish() override {
165 MutexLock lock_guard(&file_system_->mutex);
166 file_system_->files.insert({id_, table_});
167 return Status::OK();
168 }
169
170 void Abandon() override {}
171
172 uint64_t NumEntries() const override { return table_.size(); }
173
174 uint64_t FileSize() const override { return table_.size(); }
175
176 TableProperties GetTableProperties() const override {
177 return TableProperties();
178 }
179
180 // Get file checksum
181 std::string GetFileChecksum() const override { return kUnknownFileChecksum; }
182 // Get file checksum function name
183 const char* GetFileChecksumFuncName() const override {
184 return kUnknownFileChecksumFuncName;
185 }
186
187 private:
188 uint32_t id_;
189 std::string prev_key_;
190 std::string prev_value_;
191 MockTableFileSystem* file_system_;
192 int corrupt_mode_;
193 KVVector table_;
194 };
195
196 InternalIterator* MockTableReader::NewIterator(
197 const ReadOptions&, const SliceTransform* /* prefix_extractor */,
198 Arena* /*arena*/, bool /*skip_filters*/, TableReaderCaller /*caller*/,
199 size_t /*compaction_readahead_size*/, bool /* allow_unprepared_value */) {
200 return new MockTableIterator(table_);
201 }
202
203 Status MockTableReader::Get(const ReadOptions&, const Slice& key,
204 GetContext* get_context,
205 const SliceTransform* /*prefix_extractor*/,
206 bool /*skip_filters*/) {
207 std::unique_ptr<MockTableIterator> iter(new MockTableIterator(table_));
208 for (iter->Seek(key); iter->Valid(); iter->Next()) {
209 ParsedInternalKey parsed_key;
210 Status pik_status =
211 ParseInternalKey(iter->key(), &parsed_key, true /* log_err_key */);
212 if (!pik_status.ok()) {
213 return pik_status;
214 }
215
216 bool dont_care __attribute__((__unused__));
217 if (!get_context->SaveValue(parsed_key, iter->value(), &dont_care)) {
218 break;
219 }
220 }
221 return Status::OK();
222 }
223
224 std::shared_ptr<const TableProperties> MockTableReader::GetTableProperties()
225 const {
226 return std::shared_ptr<const TableProperties>(new TableProperties());
227 }
228
229 MockTableFactory::MockTableFactory()
230 : next_id_(1), corrupt_mode_(MockTableFactory::kCorruptNone) {}
231
232 Status MockTableFactory::NewTableReader(
233 const ReadOptions& /*ro*/,
234 const TableReaderOptions& /*table_reader_options*/,
235 std::unique_ptr<RandomAccessFileReader>&& file, uint64_t /*file_size*/,
236 std::unique_ptr<TableReader>* table_reader,
237 bool /*prefetch_index_and_filter_in_cache*/) const {
238 uint32_t id = GetIDFromFile(file.get());
239
240 MutexLock lock_guard(&file_system_.mutex);
241
242 auto it = file_system_.files.find(id);
243 if (it == file_system_.files.end()) {
244 return Status::IOError("Mock file not found");
245 }
246
247 table_reader->reset(new MockTableReader(it->second));
248
249 return Status::OK();
250 }
251
252 TableBuilder* MockTableFactory::NewTableBuilder(
253 const TableBuilderOptions& /*table_builder_options*/,
254 uint32_t /*column_family_id*/, WritableFileWriter* file) const {
255 uint32_t id = GetAndWriteNextID(file);
256
257 return new MockTableBuilder(id, &file_system_, corrupt_mode_);
258 }
259
260 Status MockTableFactory::CreateMockTable(Env* env, const std::string& fname,
261 KVVector file_contents) {
262 std::unique_ptr<WritableFile> file;
263 auto s = env->NewWritableFile(fname, &file, EnvOptions());
264 if (!s.ok()) {
265 return s;
266 }
267
268 WritableFileWriter file_writer(NewLegacyWritableFileWrapper(std::move(file)),
269 fname, EnvOptions());
270
271 uint32_t id = GetAndWriteNextID(&file_writer);
272 file_system_.files.insert({id, std::move(file_contents)});
273 return Status::OK();
274 }
275
276 uint32_t MockTableFactory::GetAndWriteNextID(WritableFileWriter* file) const {
277 uint32_t next_id = next_id_.fetch_add(1);
278 char buf[4];
279 EncodeFixed32(buf, next_id);
280 file->Append(Slice(buf, 4));
281 return next_id;
282 }
283
284 uint32_t MockTableFactory::GetIDFromFile(RandomAccessFileReader* file) const {
285 char buf[4];
286 Slice result;
287 file->Read(IOOptions(), 0, 4, &result, buf, nullptr);
288 assert(result.size() == 4);
289 return DecodeFixed32(buf);
290 }
291
292 void MockTableFactory::AssertSingleFile(const KVVector& file_contents) {
293 ASSERT_EQ(file_system_.files.size(), 1U);
294 ASSERT_EQ(file_contents, file_system_.files.begin()->second);
295 }
296
297 void MockTableFactory::AssertLatestFile(const KVVector& file_contents) {
298 ASSERT_GE(file_system_.files.size(), 1U);
299 auto latest = file_system_.files.end();
300 --latest;
301
302 if (file_contents != latest->second) {
303 std::cout << "Wrong content! Content of latest file:" << std::endl;
304 for (const auto& kv : latest->second) {
305 ParsedInternalKey ikey;
306 std::string key, value;
307 std::tie(key, value) = kv;
308 ASSERT_OK(ParseInternalKey(Slice(key), &ikey, true /* log_err_key */));
309 std::cout << ikey.DebugString(true, false) << " -> " << value
310 << std::endl;
311 }
312 FAIL();
313 }
314 }
315
316 } // namespace mock
317 } // namespace ROCKSDB_NAMESPACE