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