github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/sstable/testdata/make-table.cc (about) 1 // Copyright 2011 The LevelDB-Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // This program adds N lines from infile to a leveldb table at outfile. 6 // The h.txt infile was generated via: 7 // cat hamlet-act-1.txt | tr '[:upper:]' '[:lower:]' | grep -o -E '\w+' | sort | uniq -c > infile 8 // 9 // To build and run: 10 // g++ make-table.cc -lleveldb && ./a.out 11 12 #include <fstream> 13 #include <iostream> 14 #include <string> 15 16 #include "rocksdb/env.h" 17 #include "rocksdb/filter_policy.h" 18 #include "rocksdb/slice_transform.h" 19 #include "rocksdb/sst_file_writer.h" 20 #include "rocksdb/table.h" 21 22 const char* infile = "h.txt"; 23 24 // A dummy prefix extractor that cuts off the last two bytes for keys of 25 // length three or over. This is not a valid prefix extractor and barely 26 // enough to do a little bit of unit testing. 27 // 28 // TODO(tbg): write some test infra using CockroachDB MVCC data. 29 class PrefixExtractor : public rocksdb::SliceTransform { 30 public: 31 PrefixExtractor() {} 32 33 virtual const char* Name() const { return "leveldb.BytewiseComparator"; } 34 35 virtual rocksdb::Slice Transform(const rocksdb::Slice& src) const { 36 auto sl = rocksdb::Slice(src.data(), src.size()); 37 return sl; 38 } 39 40 virtual bool InDomain(const rocksdb::Slice& src) const { return true; } 41 }; 42 43 class KeyCountPropertyCollector : public rocksdb::TablePropertiesCollector { 44 public: 45 KeyCountPropertyCollector() 46 : count_(0) { 47 } 48 49 rocksdb::Status AddUserKey(const rocksdb::Slice&, const rocksdb::Slice&, 50 rocksdb::EntryType type, rocksdb::SequenceNumber, 51 uint64_t) override { 52 count_++; 53 return rocksdb::Status::OK(); 54 } 55 56 rocksdb::Status Finish(rocksdb::UserCollectedProperties* properties) override { 57 char buf[16]; 58 sprintf(buf, "%d", count_); 59 *properties = rocksdb::UserCollectedProperties{ 60 {"test.key-count", buf}, 61 }; 62 return rocksdb::Status::OK(); 63 } 64 65 const char* Name() const override { return "KeyCountPropertyCollector"; } 66 67 rocksdb::UserCollectedProperties GetReadableProperties() const override { 68 return rocksdb::UserCollectedProperties{}; 69 } 70 71 private: 72 int count_; 73 }; 74 75 class KeyCountPropertyCollectorFactory : public rocksdb::TablePropertiesCollectorFactory { 76 virtual rocksdb::TablePropertiesCollector* CreateTablePropertiesCollector( 77 rocksdb::TablePropertiesCollectorFactory::Context context) override { 78 return new KeyCountPropertyCollector(); 79 } 80 const char* Name() const override { return "KeyCountPropertyCollector"; } 81 }; 82 83 int write() { 84 for (int i = 0; i < 10; ++i) { 85 rocksdb::Options options; 86 rocksdb::BlockBasedTableOptions table_options; 87 const char* outfile; 88 89 table_options.block_size = 2048; 90 table_options.index_shortening = rocksdb::BlockBasedTableOptions::IndexShorteningMode::kShortenSeparatorsAndSuccessor; 91 92 switch (i) { 93 case 0: 94 outfile = "h.ldb"; 95 table_options.format_version = 0; 96 table_options.whole_key_filtering = false; 97 break; 98 99 case 1: 100 outfile = "h.sst"; 101 options.table_properties_collector_factories.emplace_back( 102 new KeyCountPropertyCollectorFactory); 103 table_options.whole_key_filtering = false; 104 break; 105 106 case 2: 107 outfile = "h.no-compression.sst"; 108 options.table_properties_collector_factories.emplace_back( 109 new KeyCountPropertyCollectorFactory); 110 options.compression = rocksdb::kNoCompression; 111 table_options.whole_key_filtering = false; 112 break; 113 114 case 3: 115 outfile = "h.block-bloom.no-compression.sst"; 116 options.compression = rocksdb::kNoCompression; 117 table_options.filter_policy.reset(rocksdb::NewBloomFilterPolicy(10, true)); 118 table_options.whole_key_filtering = true; 119 break; 120 121 case 4: 122 outfile = "h.table-bloom.no-compression.sst"; 123 options.compression = rocksdb::kNoCompression; 124 table_options.filter_policy.reset(rocksdb::NewBloomFilterPolicy(10, false)); 125 table_options.whole_key_filtering = true; 126 break; 127 128 case 5: 129 // TODO(peter): unused at this time 130 // 131 // outfile = "h.block-bloom.no-compression.prefix_extractor.sst"; 132 // options.compression = rocksdb::kNoCompression; 133 // options.prefix_extractor.reset(new PrefixExtractor); 134 // table_options.filter_policy.reset(rocksdb::NewBloomFilterPolicy(10, true)); 135 // table_options.whole_key_filtering = true; 136 // break; 137 continue; 138 139 case 6: 140 // TODO(peter): unused at this time 141 // 142 // outfile = "h.table-bloom.no-compression.prefix_extractor.sst"; 143 // options.compression = rocksdb::kNoCompression; 144 // options.prefix_extractor.reset(new PrefixExtractor); 145 // table_options.filter_policy.reset(rocksdb::NewBloomFilterPolicy(10, false)); 146 // table_options.whole_key_filtering = true; 147 // break; 148 continue; 149 150 case 7: 151 // TODO(peter): unused at this time 152 // 153 // outfile = "h.block-bloom.no-compression.prefix_extractor.no_whole_key_filter.sst"; 154 // options.compression = rocksdb::kNoCompression; 155 // options.prefix_extractor.reset(new PrefixExtractor); 156 // table_options.filter_policy.reset(rocksdb::NewBloomFilterPolicy(10, true)); 157 // table_options.whole_key_filtering = false; 158 // break; 159 continue; 160 161 case 8: 162 outfile = "h.table-bloom.no-compression.prefix_extractor.no_whole_key_filter.sst"; 163 options.compression = rocksdb::kNoCompression; 164 options.prefix_extractor.reset(new PrefixExtractor); 165 table_options.filter_policy.reset(rocksdb::NewBloomFilterPolicy(10, false)); 166 table_options.whole_key_filtering = false; 167 break; 168 169 case 9: 170 outfile = "h.no-compression.two_level_index.sst"; 171 options.table_properties_collector_factories.emplace_back( 172 new KeyCountPropertyCollectorFactory); 173 options.compression = rocksdb::kNoCompression; 174 table_options.index_type = rocksdb::BlockBasedTableOptions::IndexType::kTwoLevelIndexSearch; 175 // Use small metadata_block_size to stress two_level_index. 176 table_options.metadata_block_size = 128; 177 table_options.whole_key_filtering = false; 178 break; 179 180 default: 181 continue; 182 } 183 184 options.table_factory.reset(rocksdb::NewBlockBasedTableFactory(table_options)); 185 186 std::unique_ptr<rocksdb::SstFileWriter> tb(new rocksdb::SstFileWriter({}, options)); 187 rocksdb::Status status = tb->Open(outfile); 188 if (!status.ok()) { 189 std::cerr << "SstFileWriter::Open: " << status.ToString() << std::endl; 190 return 1; 191 } 192 193 int rangeDelLength = 0; 194 int rangeDelCounter = 0; 195 std::ifstream in(infile); 196 std::string s; 197 std::string rangeDelStart; 198 for (int i = 0; getline(in, s); i++) { 199 std::string key(s, 8); 200 std::string val(s, 0, 7); 201 val = val.substr(1 + val.rfind(' ')); 202 tb->Put(key.c_str(), val.c_str()); 203 // Add range deletions of increasing length. 204 if (i % 100 == 0) { 205 rangeDelStart = key; 206 rangeDelCounter = 0; 207 rangeDelLength++; 208 } 209 rangeDelCounter++; 210 211 if (rangeDelCounter == rangeDelLength) { 212 tb->DeleteRange(rangeDelStart, key.c_str()); 213 } 214 } 215 216 rocksdb::ExternalSstFileInfo info; 217 status = tb->Finish(&info); 218 if (!status.ok()) { 219 std::cerr << "TableBuilder::Finish: " << status.ToString() << std::endl; 220 return 1; 221 } 222 223 std::cout << outfile << ": wrote " << info.num_entries << " entries, " << info.file_size << "b" << std::endl; 224 } 225 return 0; 226 } 227 228 int main(int argc, char** argv) { 229 return write(); 230 }