提供基本的ttl测试用例
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

834 lines
24 KiB

  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. #include "leveldb/table.h"
  5. #include <map>
  6. #include <string>
  7. #include "gtest/gtest.h"
  8. #include "db/dbformat.h"
  9. #include "db/memtable.h"
  10. #include "db/write_batch_internal.h"
  11. #include "leveldb/db.h"
  12. #include "leveldb/env.h"
  13. #include "leveldb/iterator.h"
  14. #include "leveldb/table_builder.h"
  15. #include "table/block.h"
  16. #include "table/block_builder.h"
  17. #include "table/format.h"
  18. #include "util/random.h"
  19. #include "util/testutil.h"
  20. namespace leveldb {
  21. // Return reverse of "key".
  22. // Used to test non-lexicographic comparators.
  23. static std::string Reverse(const Slice& key) {
  24. std::string str(key.ToString());
  25. std::string rev("");
  26. for (std::string::reverse_iterator rit = str.rbegin(); rit != str.rend();
  27. ++rit) {
  28. rev.push_back(*rit);
  29. }
  30. return rev;
  31. }
  32. namespace {
  33. class ReverseKeyComparator : public Comparator {
  34. public:
  35. const char* Name() const override {
  36. return "leveldb.ReverseBytewiseComparator";
  37. }
  38. int Compare(const Slice& a, const Slice& b) const override {
  39. return BytewiseComparator()->Compare(Reverse(a), Reverse(b));
  40. }
  41. void FindShortestSeparator(std::string* start,
  42. const Slice& limit) const override {
  43. std::string s = Reverse(*start);
  44. std::string l = Reverse(limit);
  45. BytewiseComparator()->FindShortestSeparator(&s, l);
  46. *start = Reverse(s);
  47. }
  48. void FindShortSuccessor(std::string* key) const override {
  49. std::string s = Reverse(*key);
  50. BytewiseComparator()->FindShortSuccessor(&s);
  51. *key = Reverse(s);
  52. }
  53. };
  54. } // namespace
  55. static ReverseKeyComparator reverse_key_comparator;
  56. static void Increment(const Comparator* cmp, std::string* key) {
  57. if (cmp == BytewiseComparator()) {
  58. key->push_back('\0');
  59. } else {
  60. assert(cmp == &reverse_key_comparator);
  61. std::string rev = Reverse(*key);
  62. rev.push_back('\0');
  63. *key = Reverse(rev);
  64. }
  65. }
  66. // An STL comparator that uses a Comparator
  67. namespace {
  68. struct STLLessThan {
  69. const Comparator* cmp;
  70. STLLessThan() : cmp(BytewiseComparator()) {}
  71. STLLessThan(const Comparator* c) : cmp(c) {}
  72. bool operator()(const std::string& a, const std::string& b) const {
  73. return cmp->Compare(Slice(a), Slice(b)) < 0;
  74. }
  75. };
  76. } // namespace
  77. class StringSink : public WritableFile {
  78. public:
  79. ~StringSink() override = default;
  80. const std::string& contents() const { return contents_; }
  81. Status Close() override { return Status::OK(); }
  82. Status Flush() override { return Status::OK(); }
  83. Status Sync() override { return Status::OK(); }
  84. Status Append(const Slice& data) override {
  85. contents_.append(data.data(), data.size());
  86. return Status::OK();
  87. }
  88. private:
  89. std::string contents_;
  90. };
  91. class StringSource : public RandomAccessFile {
  92. public:
  93. StringSource(const Slice& contents)
  94. : contents_(contents.data(), contents.size()) {}
  95. ~StringSource() override = default;
  96. uint64_t Size() const { return contents_.size(); }
  97. Status Read(uint64_t offset, size_t n, Slice* result,
  98. char* scratch) const override {
  99. if (offset >= contents_.size()) {
  100. return Status::InvalidArgument("invalid Read offset");
  101. }
  102. if (offset + n > contents_.size()) {
  103. n = contents_.size() - offset;
  104. }
  105. std::memcpy(scratch, &contents_[offset], n);
  106. *result = Slice(scratch, n);
  107. return Status::OK();
  108. }
  109. private:
  110. std::string contents_;
  111. };
  112. typedef std::map<std::string, std::string, STLLessThan> KVMap;
  113. // Helper class for tests to unify the interface between
  114. // BlockBuilder/TableBuilder and Block/Table.
  115. class Constructor {
  116. public:
  117. explicit Constructor(const Comparator* cmp) : data_(STLLessThan(cmp)) {}
  118. virtual ~Constructor() = default;
  119. void Add(const std::string& key, const Slice& value) {
  120. data_[key] = value.ToString();
  121. }
  122. // Finish constructing the data structure with all the keys that have
  123. // been added so far. Returns the keys in sorted order in "*keys"
  124. // and stores the key/value pairs in "*kvmap"
  125. void Finish(const Options& options, std::vector<std::string>* keys,
  126. KVMap* kvmap) {
  127. *kvmap = data_;
  128. keys->clear();
  129. for (const auto& kvp : data_) {
  130. keys->push_back(kvp.first);
  131. }
  132. data_.clear();
  133. Status s = FinishImpl(options, *kvmap);
  134. ASSERT_TRUE(s.ok()) << s.ToString();
  135. }
  136. // Construct the data structure from the data in "data"
  137. virtual Status FinishImpl(const Options& options, const KVMap& data) = 0;
  138. virtual Iterator* NewIterator() const = 0;
  139. const KVMap& data() const { return data_; }
  140. virtual DB* db() const { return nullptr; } // Overridden in DBConstructor
  141. private:
  142. KVMap data_;
  143. };
  144. class BlockConstructor : public Constructor {
  145. public:
  146. explicit BlockConstructor(const Comparator* cmp)
  147. : Constructor(cmp), comparator_(cmp), block_(nullptr) {}
  148. ~BlockConstructor() override { delete block_; }
  149. Status FinishImpl(const Options& options, const KVMap& data) override {
  150. delete block_;
  151. block_ = nullptr;
  152. BlockBuilder builder(&options);
  153. for (const auto& kvp : data) {
  154. builder.Add(kvp.first, kvp.second);
  155. }
  156. // Open the block
  157. data_ = builder.Finish().ToString();
  158. BlockContents contents;
  159. contents.data = data_;
  160. contents.cachable = false;
  161. contents.heap_allocated = false;
  162. block_ = new Block(contents);
  163. return Status::OK();
  164. }
  165. Iterator* NewIterator() const override {
  166. return block_->NewIterator(comparator_);
  167. }
  168. private:
  169. const Comparator* const comparator_;
  170. std::string data_;
  171. Block* block_;
  172. BlockConstructor();
  173. };
  174. class TableConstructor : public Constructor {
  175. public:
  176. TableConstructor(const Comparator* cmp)
  177. : Constructor(cmp), source_(nullptr), table_(nullptr) {}
  178. ~TableConstructor() override { Reset(); }
  179. Status FinishImpl(const Options& options, const KVMap& data) override {
  180. Reset();
  181. StringSink sink;
  182. TableBuilder builder(options, &sink);
  183. for (const auto& kvp : data) {
  184. builder.Add(kvp.first, kvp.second);
  185. EXPECT_LEVELDB_OK(builder.status());
  186. }
  187. Status s = builder.Finish();
  188. EXPECT_LEVELDB_OK(s);
  189. EXPECT_EQ(sink.contents().size(), builder.FileSize());
  190. // Open the table
  191. source_ = new StringSource(sink.contents());
  192. Options table_options;
  193. table_options.comparator = options.comparator;
  194. return Table::Open(table_options, source_, sink.contents().size(), &table_);
  195. }
  196. Iterator* NewIterator() const override {
  197. return table_->NewIterator(ReadOptions());
  198. }
  199. uint64_t ApproximateOffsetOf(const Slice& key) const {
  200. return table_->ApproximateOffsetOf(key);
  201. }
  202. private:
  203. void Reset() {
  204. delete table_;
  205. delete source_;
  206. table_ = nullptr;
  207. source_ = nullptr;
  208. }
  209. StringSource* source_;
  210. Table* table_;
  211. TableConstructor();
  212. };
  213. // A helper class that converts internal format keys into user keys
  214. class KeyConvertingIterator : public Iterator {
  215. public:
  216. explicit KeyConvertingIterator(Iterator* iter) : iter_(iter) {}
  217. KeyConvertingIterator(const KeyConvertingIterator&) = delete;
  218. KeyConvertingIterator& operator=(const KeyConvertingIterator&) = delete;
  219. ~KeyConvertingIterator() override { delete iter_; }
  220. bool Valid() const override { return iter_->Valid(); }
  221. void Seek(const Slice& target) override {
  222. ParsedInternalKey ikey(target, kMaxSequenceNumber, kTypeValue);
  223. std::string encoded;
  224. AppendInternalKey(&encoded, ikey);
  225. iter_->Seek(encoded);
  226. }
  227. void SeekToFirst() override { iter_->SeekToFirst(); }
  228. void SeekToLast() override { iter_->SeekToLast(); }
  229. void Next() override { iter_->Next(); }
  230. void Prev() override { iter_->Prev(); }
  231. Slice key() const override {
  232. assert(Valid());
  233. ParsedInternalKey key;
  234. if (!ParseInternalKey(iter_->key(), &key)) {
  235. status_ = Status::Corruption("malformed internal key");
  236. return Slice("corrupted key");
  237. }
  238. return key.user_key;
  239. }
  240. Slice value() const override { return iter_->value(); }
  241. Status status() const override {
  242. return status_.ok() ? iter_->status() : status_;
  243. }
  244. private:
  245. mutable Status status_;
  246. Iterator* iter_;
  247. };
  248. class MemTableConstructor : public Constructor {
  249. public:
  250. explicit MemTableConstructor(const Comparator* cmp)
  251. : Constructor(cmp), internal_comparator_(cmp) {
  252. memtable_ = new MemTable(internal_comparator_);
  253. memtable_->Ref();
  254. }
  255. ~MemTableConstructor() override { memtable_->Unref(); }
  256. Status FinishImpl(const Options& options, const KVMap& data) override {
  257. memtable_->Unref();
  258. memtable_ = new MemTable(internal_comparator_);
  259. memtable_->Ref();
  260. int seq = 1;
  261. for (const auto& kvp : data) {
  262. memtable_->Add(seq, kTypeValue, kvp.first, kvp.second);
  263. seq++;
  264. }
  265. return Status::OK();
  266. }
  267. Iterator* NewIterator() const override {
  268. return new KeyConvertingIterator(memtable_->NewIterator());
  269. }
  270. private:
  271. const InternalKeyComparator internal_comparator_;
  272. MemTable* memtable_;
  273. };
  274. class DBConstructor : public Constructor {
  275. public:
  276. explicit DBConstructor(const Comparator* cmp)
  277. : Constructor(cmp), comparator_(cmp) {
  278. db_ = nullptr;
  279. NewDB();
  280. }
  281. ~DBConstructor() override { delete db_; }
  282. Status FinishImpl(const Options& options, const KVMap& data) override {
  283. delete db_;
  284. db_ = nullptr;
  285. NewDB();
  286. for (const auto& kvp : data) {
  287. WriteBatch batch;
  288. batch.Put(kvp.first, kvp.second);
  289. EXPECT_TRUE(db_->Write(WriteOptions(), &batch).ok());
  290. }
  291. return Status::OK();
  292. }
  293. Iterator* NewIterator() const override {
  294. return db_->NewIterator(ReadOptions());
  295. }
  296. DB* db() const override { return db_; }
  297. private:
  298. void NewDB() {
  299. std::string name = testing::TempDir() + "table_testdb";
  300. Options options;
  301. options.comparator = comparator_;
  302. Status status = DestroyDB(name, options);
  303. ASSERT_TRUE(status.ok()) << status.ToString();
  304. options.create_if_missing = true;
  305. options.error_if_exists = true;
  306. options.write_buffer_size = 10000; // Something small to force merging
  307. status = DB::Open(options, name, &db_);
  308. ASSERT_TRUE(status.ok()) << status.ToString();
  309. }
  310. const Comparator* const comparator_;
  311. DB* db_;
  312. };
  313. enum TestType { TABLE_TEST, BLOCK_TEST, MEMTABLE_TEST, DB_TEST };
  314. struct TestArgs {
  315. TestType type;
  316. bool reverse_compare;
  317. int restart_interval;
  318. };
  319. static const TestArgs kTestArgList[] = {
  320. {TABLE_TEST, false, 16},
  321. {TABLE_TEST, false, 1},
  322. {TABLE_TEST, false, 1024},
  323. {TABLE_TEST, true, 16},
  324. {TABLE_TEST, true, 1},
  325. {TABLE_TEST, true, 1024},
  326. {BLOCK_TEST, false, 16},
  327. {BLOCK_TEST, false, 1},
  328. {BLOCK_TEST, false, 1024},
  329. {BLOCK_TEST, true, 16},
  330. {BLOCK_TEST, true, 1},
  331. {BLOCK_TEST, true, 1024},
  332. // Restart interval does not matter for memtables
  333. {MEMTABLE_TEST, false, 16},
  334. {MEMTABLE_TEST, true, 16},
  335. // Do not bother with restart interval variations for DB
  336. {DB_TEST, false, 16},
  337. {DB_TEST, true, 16},
  338. };
  339. static const int kNumTestArgs = sizeof(kTestArgList) / sizeof(kTestArgList[0]);
  340. class Harness : public testing::Test {
  341. public:
  342. Harness() : constructor_(nullptr) {}
  343. void Init(const TestArgs& args) {
  344. delete constructor_;
  345. constructor_ = nullptr;
  346. options_ = Options();
  347. options_.block_restart_interval = args.restart_interval;
  348. // Use shorter block size for tests to exercise block boundary
  349. // conditions more.
  350. options_.block_size = 256;
  351. if (args.reverse_compare) {
  352. options_.comparator = &reverse_key_comparator;
  353. }
  354. switch (args.type) {
  355. case TABLE_TEST:
  356. constructor_ = new TableConstructor(options_.comparator);
  357. break;
  358. case BLOCK_TEST:
  359. constructor_ = new BlockConstructor(options_.comparator);
  360. break;
  361. case MEMTABLE_TEST:
  362. constructor_ = new MemTableConstructor(options_.comparator);
  363. break;
  364. case DB_TEST:
  365. constructor_ = new DBConstructor(options_.comparator);
  366. break;
  367. }
  368. }
  369. ~Harness() { delete constructor_; }
  370. void Add(const std::string& key, const std::string& value) {
  371. constructor_->Add(key, value);
  372. }
  373. void Test(Random* rnd) {
  374. std::vector<std::string> keys;
  375. KVMap data;
  376. constructor_->Finish(options_, &keys, &data);
  377. TestForwardScan(keys, data);
  378. TestBackwardScan(keys, data);
  379. TestRandomAccess(rnd, keys, data);
  380. }
  381. void TestForwardScan(const std::vector<std::string>& keys,
  382. const KVMap& data) {
  383. Iterator* iter = constructor_->NewIterator();
  384. ASSERT_TRUE(!iter->Valid());
  385. iter->SeekToFirst();
  386. for (KVMap::const_iterator model_iter = data.begin();
  387. model_iter != data.end(); ++model_iter) {
  388. ASSERT_EQ(ToString(data, model_iter), ToString(iter));
  389. iter->Next();
  390. }
  391. ASSERT_TRUE(!iter->Valid());
  392. delete iter;
  393. }
  394. void TestBackwardScan(const std::vector<std::string>& keys,
  395. const KVMap& data) {
  396. Iterator* iter = constructor_->NewIterator();
  397. ASSERT_TRUE(!iter->Valid());
  398. iter->SeekToLast();
  399. for (KVMap::const_reverse_iterator model_iter = data.rbegin();
  400. model_iter != data.rend(); ++model_iter) {
  401. ASSERT_EQ(ToString(data, model_iter), ToString(iter));
  402. iter->Prev();
  403. }
  404. ASSERT_TRUE(!iter->Valid());
  405. delete iter;
  406. }
  407. void TestRandomAccess(Random* rnd, const std::vector<std::string>& keys,
  408. const KVMap& data) {
  409. static const bool kVerbose = false;
  410. Iterator* iter = constructor_->NewIterator();
  411. ASSERT_TRUE(!iter->Valid());
  412. KVMap::const_iterator model_iter = data.begin();
  413. if (kVerbose) std::fprintf(stderr, "---\n");
  414. for (int i = 0; i < 200; i++) {
  415. const int toss = rnd->Uniform(5);
  416. switch (toss) {
  417. case 0: {
  418. if (iter->Valid()) {
  419. if (kVerbose) std::fprintf(stderr, "Next\n");
  420. iter->Next();
  421. ++model_iter;
  422. ASSERT_EQ(ToString(data, model_iter), ToString(iter));
  423. }
  424. break;
  425. }
  426. case 1: {
  427. if (kVerbose) std::fprintf(stderr, "SeekToFirst\n");
  428. iter->SeekToFirst();
  429. model_iter = data.begin();
  430. ASSERT_EQ(ToString(data, model_iter), ToString(iter));
  431. break;
  432. }
  433. case 2: {
  434. std::string key = PickRandomKey(rnd, keys);
  435. model_iter = data.lower_bound(key);
  436. if (kVerbose)
  437. std::fprintf(stderr, "Seek '%s'\n", EscapeString(key).c_str());
  438. iter->Seek(Slice(key));
  439. ASSERT_EQ(ToString(data, model_iter), ToString(iter));
  440. break;
  441. }
  442. case 3: {
  443. if (iter->Valid()) {
  444. if (kVerbose) std::fprintf(stderr, "Prev\n");
  445. iter->Prev();
  446. if (model_iter == data.begin()) {
  447. model_iter = data.end(); // Wrap around to invalid value
  448. } else {
  449. --model_iter;
  450. }
  451. ASSERT_EQ(ToString(data, model_iter), ToString(iter));
  452. }
  453. break;
  454. }
  455. case 4: {
  456. if (kVerbose) std::fprintf(stderr, "SeekToLast\n");
  457. iter->SeekToLast();
  458. if (keys.empty()) {
  459. model_iter = data.end();
  460. } else {
  461. std::string last = data.rbegin()->first;
  462. model_iter = data.lower_bound(last);
  463. }
  464. ASSERT_EQ(ToString(data, model_iter), ToString(iter));
  465. break;
  466. }
  467. }
  468. }
  469. delete iter;
  470. }
  471. std::string ToString(const KVMap& data, const KVMap::const_iterator& it) {
  472. if (it == data.end()) {
  473. return "END";
  474. } else {
  475. return "'" + it->first + "->" + it->second + "'";
  476. }
  477. }
  478. std::string ToString(const KVMap& data,
  479. const KVMap::const_reverse_iterator& it) {
  480. if (it == data.rend()) {
  481. return "END";
  482. } else {
  483. return "'" + it->first + "->" + it->second + "'";
  484. }
  485. }
  486. std::string ToString(const Iterator* it) {
  487. if (!it->Valid()) {
  488. return "END";
  489. } else {
  490. return "'" + it->key().ToString() + "->" + it->value().ToString() + "'";
  491. }
  492. }
  493. std::string PickRandomKey(Random* rnd, const std::vector<std::string>& keys) {
  494. if (keys.empty()) {
  495. return "foo";
  496. } else {
  497. const int index = rnd->Uniform(keys.size());
  498. std::string result = keys[index];
  499. switch (rnd->Uniform(3)) {
  500. case 0:
  501. // Return an existing key
  502. break;
  503. case 1: {
  504. // Attempt to return something smaller than an existing key
  505. if (!result.empty() && result[result.size() - 1] > '\0') {
  506. result[result.size() - 1]--;
  507. }
  508. break;
  509. }
  510. case 2: {
  511. // Return something larger than an existing key
  512. Increment(options_.comparator, &result);
  513. break;
  514. }
  515. }
  516. return result;
  517. }
  518. }
  519. // Returns nullptr if not running against a DB
  520. DB* db() const { return constructor_->db(); }
  521. private:
  522. Options options_;
  523. Constructor* constructor_;
  524. };
  525. // Test empty table/block.
  526. TEST_F(Harness, Empty) {
  527. for (int i = 0; i < kNumTestArgs; i++) {
  528. Init(kTestArgList[i]);
  529. Random rnd(test::RandomSeed() + 1);
  530. Test(&rnd);
  531. }
  532. }
  533. // Special test for a block with no restart entries. The C++ leveldb
  534. // code never generates such blocks, but the Java version of leveldb
  535. // seems to.
  536. TEST_F(Harness, ZeroRestartPointsInBlock) {
  537. char data[sizeof(uint32_t)];
  538. memset(data, 0, sizeof(data));
  539. BlockContents contents;
  540. contents.data = Slice(data, sizeof(data));
  541. contents.cachable = false;
  542. contents.heap_allocated = false;
  543. Block block(contents);
  544. Iterator* iter = block.NewIterator(BytewiseComparator());
  545. iter->SeekToFirst();
  546. ASSERT_TRUE(!iter->Valid());
  547. iter->SeekToLast();
  548. ASSERT_TRUE(!iter->Valid());
  549. iter->Seek("foo");
  550. ASSERT_TRUE(!iter->Valid());
  551. delete iter;
  552. }
  553. // Test the empty key
  554. TEST_F(Harness, SimpleEmptyKey) {
  555. for (int i = 0; i < kNumTestArgs; i++) {
  556. Init(kTestArgList[i]);
  557. Random rnd(test::RandomSeed() + 1);
  558. Add("", "v");
  559. Test(&rnd);
  560. }
  561. }
  562. TEST_F(Harness, SimpleSingle) {
  563. for (int i = 0; i < kNumTestArgs; i++) {
  564. Init(kTestArgList[i]);
  565. Random rnd(test::RandomSeed() + 2);
  566. Add("abc", "v");
  567. Test(&rnd);
  568. }
  569. }
  570. TEST_F(Harness, SimpleMulti) {
  571. for (int i = 0; i < kNumTestArgs; i++) {
  572. Init(kTestArgList[i]);
  573. Random rnd(test::RandomSeed() + 3);
  574. Add("abc", "v");
  575. Add("abcd", "v");
  576. Add("ac", "v2");
  577. Test(&rnd);
  578. }
  579. }
  580. TEST_F(Harness, SimpleSpecialKey) {
  581. for (int i = 0; i < kNumTestArgs; i++) {
  582. Init(kTestArgList[i]);
  583. Random rnd(test::RandomSeed() + 4);
  584. Add("\xff\xff", "v3");
  585. Test(&rnd);
  586. }
  587. }
  588. TEST_F(Harness, Randomized) {
  589. for (int i = 0; i < kNumTestArgs; i++) {
  590. Init(kTestArgList[i]);
  591. Random rnd(test::RandomSeed() + 5);
  592. for (int num_entries = 0; num_entries < 2000;
  593. num_entries += (num_entries < 50 ? 1 : 200)) {
  594. if ((num_entries % 10) == 0) {
  595. std::fprintf(stderr, "case %d of %d: num_entries = %d\n", (i + 1),
  596. int(kNumTestArgs), num_entries);
  597. }
  598. for (int e = 0; e < num_entries; e++) {
  599. std::string v;
  600. Add(test::RandomKey(&rnd, rnd.Skewed(4)),
  601. test::RandomString(&rnd, rnd.Skewed(5), &v).ToString());
  602. }
  603. Test(&rnd);
  604. }
  605. }
  606. }
  607. TEST_F(Harness, RandomizedLongDB) {
  608. Random rnd(test::RandomSeed());
  609. TestArgs args = {DB_TEST, false, 16};
  610. Init(args);
  611. int num_entries = 100000;
  612. for (int e = 0; e < num_entries; e++) {
  613. std::string v;
  614. Add(test::RandomKey(&rnd, rnd.Skewed(4)),
  615. test::RandomString(&rnd, rnd.Skewed(5), &v).ToString());
  616. }
  617. Test(&rnd);
  618. // We must have created enough data to force merging
  619. int files = 0;
  620. for (int level = 0; level < config::kNumLevels; level++) {
  621. std::string value;
  622. char name[100];
  623. std::snprintf(name, sizeof(name), "leveldb.num-files-at-level%d", level);
  624. ASSERT_TRUE(db()->GetProperty(name, &value));
  625. files += atoi(value.c_str());
  626. }
  627. ASSERT_GT(files, 0);
  628. }
  629. TEST(MemTableTest, Simple) {
  630. InternalKeyComparator cmp(BytewiseComparator());
  631. MemTable* memtable = new MemTable(cmp);
  632. memtable->Ref();
  633. WriteBatch batch;
  634. WriteBatchInternal::SetSequence(&batch, 100);
  635. batch.Put(std::string("k1"), std::string("v1"));
  636. batch.Put(std::string("k2"), std::string("v2"));
  637. batch.Put(std::string("k3"), std::string("v3"));
  638. batch.Put(std::string("largekey"), std::string("vlarge"));
  639. ASSERT_TRUE(WriteBatchInternal::InsertInto(&batch, memtable).ok());
  640. Iterator* iter = memtable->NewIterator();
  641. iter->SeekToFirst();
  642. while (iter->Valid()) {
  643. std::fprintf(stderr, "key: '%s' -> '%s'\n", iter->key().ToString().c_str(),
  644. iter->value().ToString().c_str());
  645. iter->Next();
  646. }
  647. delete iter;
  648. memtable->Unref();
  649. }
  650. static bool Between(uint64_t val, uint64_t low, uint64_t high) {
  651. bool result = (val >= low) && (val <= high);
  652. if (!result) {
  653. std::fprintf(stderr, "Value %llu is not in range [%llu, %llu]\n",
  654. (unsigned long long)(val), (unsigned long long)(low),
  655. (unsigned long long)(high));
  656. }
  657. return result;
  658. }
  659. TEST(TableTest, ApproximateOffsetOfPlain) {
  660. TableConstructor c(BytewiseComparator());
  661. c.Add("k01", "hello");
  662. c.Add("k02", "hello2");
  663. c.Add("k03", std::string(10000, 'x'));
  664. c.Add("k04", std::string(200000, 'x'));
  665. c.Add("k05", std::string(300000, 'x'));
  666. c.Add("k06", "hello3");
  667. c.Add("k07", std::string(100000, 'x'));
  668. std::vector<std::string> keys;
  669. KVMap kvmap;
  670. Options options;
  671. options.block_size = 1024;
  672. options.compression = kNoCompression;
  673. c.Finish(options, &keys, &kvmap);
  674. ASSERT_TRUE(Between(c.ApproximateOffsetOf("abc"), 0, 0));
  675. ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01"), 0, 0));
  676. ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01a"), 0, 0));
  677. ASSERT_TRUE(Between(c.ApproximateOffsetOf("k02"), 0, 0));
  678. ASSERT_TRUE(Between(c.ApproximateOffsetOf("k03"), 0, 0));
  679. ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04"), 10000, 11000));
  680. ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04a"), 210000, 211000));
  681. ASSERT_TRUE(Between(c.ApproximateOffsetOf("k05"), 210000, 211000));
  682. ASSERT_TRUE(Between(c.ApproximateOffsetOf("k06"), 510000, 511000));
  683. ASSERT_TRUE(Between(c.ApproximateOffsetOf("k07"), 510000, 511000));
  684. ASSERT_TRUE(Between(c.ApproximateOffsetOf("xyz"), 610000, 612000));
  685. }
  686. static bool SnappyCompressionSupported() {
  687. std::string out;
  688. Slice in = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
  689. return port::Snappy_Compress(in.data(), in.size(), &out);
  690. }
  691. TEST(TableTest, ApproximateOffsetOfCompressed) {
  692. if (!SnappyCompressionSupported()) {
  693. std::fprintf(stderr, "skipping compression tests\n");
  694. return;
  695. }
  696. Random rnd(301);
  697. TableConstructor c(BytewiseComparator());
  698. std::string tmp;
  699. c.Add("k01", "hello");
  700. c.Add("k02", test::CompressibleString(&rnd, 0.25, 10000, &tmp));
  701. c.Add("k03", "hello3");
  702. c.Add("k04", test::CompressibleString(&rnd, 0.25, 10000, &tmp));
  703. std::vector<std::string> keys;
  704. KVMap kvmap;
  705. Options options;
  706. options.block_size = 1024;
  707. options.compression = kSnappyCompression;
  708. c.Finish(options, &keys, &kvmap);
  709. // Expected upper and lower bounds of space used by compressible strings.
  710. static const int kSlop = 1000; // Compressor effectiveness varies.
  711. const int expected = 2500; // 10000 * compression ratio (0.25)
  712. const int min_z = expected - kSlop;
  713. const int max_z = expected + kSlop;
  714. ASSERT_TRUE(Between(c.ApproximateOffsetOf("abc"), 0, kSlop));
  715. ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01"), 0, kSlop));
  716. ASSERT_TRUE(Between(c.ApproximateOffsetOf("k02"), 0, kSlop));
  717. // Have now emitted a large compressible string, so adjust expected offset.
  718. ASSERT_TRUE(Between(c.ApproximateOffsetOf("k03"), min_z, max_z));
  719. ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04"), min_z, max_z));
  720. // Have now emitted two large compressible strings, so adjust expected offset.
  721. ASSERT_TRUE(Between(c.ApproximateOffsetOf("xyz"), 2 * min_z, 2 * max_z));
  722. }
  723. } // namespace leveldb
  724. int main(int argc, char** argv) {
  725. testing::InitGoogleTest(&argc, argv);
  726. return RUN_ALL_TESTS();
  727. }