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 namespace {
20
21 const InternalKeyComparator icmp_(BytewiseComparator());
22
23 } // namespace
24
MakeMockFile(std::initializer_list<std::pair<const std::string,std::string>> l)25 stl_wrappers::KVMap MakeMockFile(
26 std::initializer_list<std::pair<const std::string, std::string>> l) {
27 return stl_wrappers::KVMap(l, stl_wrappers::LessOfComparator(&icmp_));
28 }
29
NewIterator(const ReadOptions &,const SliceTransform *,Arena *,bool,TableReaderCaller,size_t)30 InternalIterator* MockTableReader::NewIterator(
31 const ReadOptions&, const SliceTransform* /* prefix_extractor */,
32 Arena* /*arena*/, bool /*skip_filters*/, TableReaderCaller /*caller*/,
33 size_t /*compaction_readahead_size*/) {
34 return new MockTableIterator(table_);
35 }
36
Get(const ReadOptions &,const Slice & key,GetContext * get_context,const SliceTransform *,bool)37 Status MockTableReader::Get(const ReadOptions&, const Slice& key,
38 GetContext* get_context,
39 const SliceTransform* /*prefix_extractor*/,
40 bool /*skip_filters*/) {
41 std::unique_ptr<MockTableIterator> iter(new MockTableIterator(table_));
42 for (iter->Seek(key); iter->Valid(); iter->Next()) {
43 ParsedInternalKey parsed_key;
44 if (!ParseInternalKey(iter->key(), &parsed_key)) {
45 return Status::Corruption(Slice());
46 }
47
48 bool dont_care __attribute__((__unused__));
49 if (!get_context->SaveValue(parsed_key, iter->value(), &dont_care)) {
50 break;
51 }
52 }
53 return Status::OK();
54 }
55
GetTableProperties() const56 std::shared_ptr<const TableProperties> MockTableReader::GetTableProperties()
57 const {
58 return std::shared_ptr<const TableProperties>(new TableProperties());
59 }
60
MockTableFactory()61 MockTableFactory::MockTableFactory() : next_id_(1) {}
62
NewTableReader(const TableReaderOptions &,std::unique_ptr<RandomAccessFileReader> && file,uint64_t,std::unique_ptr<TableReader> * table_reader,bool) const63 Status MockTableFactory::NewTableReader(
64 const TableReaderOptions& /*table_reader_options*/,
65 std::unique_ptr<RandomAccessFileReader>&& file, uint64_t /*file_size*/,
66 std::unique_ptr<TableReader>* table_reader,
67 bool /*prefetch_index_and_filter_in_cache*/) const {
68 uint32_t id = GetIDFromFile(file.get());
69
70 MutexLock lock_guard(&file_system_.mutex);
71
72 auto it = file_system_.files.find(id);
73 if (it == file_system_.files.end()) {
74 return Status::IOError("Mock file not found");
75 }
76
77 table_reader->reset(new MockTableReader(it->second));
78
79 return Status::OK();
80 }
81
NewTableBuilder(const TableBuilderOptions &,uint32_t,WritableFileWriter * file) const82 TableBuilder* MockTableFactory::NewTableBuilder(
83 const TableBuilderOptions& /*table_builder_options*/,
84 uint32_t /*column_family_id*/, WritableFileWriter* file) const {
85 uint32_t id = GetAndWriteNextID(file);
86
87 return new MockTableBuilder(id, &file_system_);
88 }
89
CreateMockTable(Env * env,const std::string & fname,stl_wrappers::KVMap file_contents)90 Status MockTableFactory::CreateMockTable(Env* env, const std::string& fname,
91 stl_wrappers::KVMap file_contents) {
92 std::unique_ptr<WritableFile> file;
93 auto s = env->NewWritableFile(fname, &file, EnvOptions());
94 if (!s.ok()) {
95 return s;
96 }
97
98 WritableFileWriter file_writer(NewLegacyWritableFileWrapper(std::move(file)),
99 fname, EnvOptions());
100
101 uint32_t id = GetAndWriteNextID(&file_writer);
102 file_system_.files.insert({id, std::move(file_contents)});
103 return Status::OK();
104 }
105
GetAndWriteNextID(WritableFileWriter * file) const106 uint32_t MockTableFactory::GetAndWriteNextID(WritableFileWriter* file) const {
107 uint32_t next_id = next_id_.fetch_add(1);
108 char buf[4];
109 EncodeFixed32(buf, next_id);
110 file->Append(Slice(buf, 4));
111 return next_id;
112 }
113
GetIDFromFile(RandomAccessFileReader * file) const114 uint32_t MockTableFactory::GetIDFromFile(RandomAccessFileReader* file) const {
115 char buf[4];
116 Slice result;
117 file->Read(0, 4, &result, buf, nullptr);
118 assert(result.size() == 4);
119 return DecodeFixed32(buf);
120 }
121
AssertSingleFile(const stl_wrappers::KVMap & file_contents)122 void MockTableFactory::AssertSingleFile(
123 const stl_wrappers::KVMap& file_contents) {
124 ASSERT_EQ(file_system_.files.size(), 1U);
125 ASSERT_EQ(file_contents, file_system_.files.begin()->second);
126 }
127
AssertLatestFile(const stl_wrappers::KVMap & file_contents)128 void MockTableFactory::AssertLatestFile(
129 const stl_wrappers::KVMap& file_contents) {
130 ASSERT_GE(file_system_.files.size(), 1U);
131 auto latest = file_system_.files.end();
132 --latest;
133
134 if (file_contents != latest->second) {
135 std::cout << "Wrong content! Content of latest file:" << std::endl;
136 for (const auto& kv : latest->second) {
137 ParsedInternalKey ikey;
138 std::string key, value;
139 std::tie(key, value) = kv;
140 ParseInternalKey(Slice(key), &ikey);
141 std::cout << ikey.DebugString(false) << " -> " << value << std::endl;
142 }
143 FAIL();
144 }
145 }
146
147 } // namespace mock
148 } // namespace ROCKSDB_NAMESPACE
149