block_test.cc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  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 <stdio.h>
  7. #include <algorithm>
  8. #include <set>
  9. #include <string>
  10. #include <unordered_set>
  11. #include <utility>
  12. #include <vector>
  13. #include "db/dbformat.h"
  14. #include "db/memtable.h"
  15. #include "db/write_batch_internal.h"
  16. #include "rocksdb/db.h"
  17. #include "rocksdb/env.h"
  18. #include "rocksdb/iterator.h"
  19. #include "rocksdb/slice_transform.h"
  20. #include "rocksdb/table.h"
  21. #include "table/block_based/block.h"
  22. #include "table/block_based/block_builder.h"
  23. #include "table/format.h"
  24. #include "test_util/testharness.h"
  25. #include "test_util/testutil.h"
  26. #include "util/random.h"
  27. namespace ROCKSDB_NAMESPACE {
  28. static std::string RandomString(Random *rnd, int len) {
  29. std::string r;
  30. test::RandomString(rnd, len, &r);
  31. return r;
  32. }
  33. std::string GenerateKey(int primary_key, int secondary_key, int padding_size,
  34. Random *rnd) {
  35. char buf[50];
  36. char *p = &buf[0];
  37. snprintf(buf, sizeof(buf), "%6d%4d", primary_key, secondary_key);
  38. std::string k(p);
  39. if (padding_size) {
  40. k += RandomString(rnd, padding_size);
  41. }
  42. return k;
  43. }
  44. // Generate random key value pairs.
  45. // The generated key will be sorted. You can tune the parameters to generated
  46. // different kinds of test key/value pairs for different scenario.
  47. void GenerateRandomKVs(std::vector<std::string> *keys,
  48. std::vector<std::string> *values, const int from,
  49. const int len, const int step = 1,
  50. const int padding_size = 0,
  51. const int keys_share_prefix = 1) {
  52. Random rnd(302);
  53. // generate different prefix
  54. for (int i = from; i < from + len; i += step) {
  55. // generating keys that shares the prefix
  56. for (int j = 0; j < keys_share_prefix; ++j) {
  57. keys->emplace_back(GenerateKey(i, j, padding_size, &rnd));
  58. // 100 bytes values
  59. values->emplace_back(RandomString(&rnd, 100));
  60. }
  61. }
  62. }
  63. class BlockTest : public testing::Test {};
  64. // block test
  65. TEST_F(BlockTest, SimpleTest) {
  66. Random rnd(301);
  67. Options options = Options();
  68. std::vector<std::string> keys;
  69. std::vector<std::string> values;
  70. BlockBuilder builder(16);
  71. int num_records = 100000;
  72. GenerateRandomKVs(&keys, &values, 0, num_records);
  73. // add a bunch of records to a block
  74. for (int i = 0; i < num_records; i++) {
  75. builder.Add(keys[i], values[i]);
  76. }
  77. // read serialized contents of the block
  78. Slice rawblock = builder.Finish();
  79. // create block reader
  80. BlockContents contents;
  81. contents.data = rawblock;
  82. Block reader(std::move(contents), kDisableGlobalSequenceNumber);
  83. // read contents of block sequentially
  84. int count = 0;
  85. InternalIterator *iter =
  86. reader.NewDataIterator(options.comparator, options.comparator);
  87. for (iter->SeekToFirst(); iter->Valid(); count++, iter->Next()) {
  88. // read kv from block
  89. Slice k = iter->key();
  90. Slice v = iter->value();
  91. // compare with lookaside array
  92. ASSERT_EQ(k.ToString().compare(keys[count]), 0);
  93. ASSERT_EQ(v.ToString().compare(values[count]), 0);
  94. }
  95. delete iter;
  96. // read block contents randomly
  97. iter = reader.NewDataIterator(options.comparator, options.comparator);
  98. for (int i = 0; i < num_records; i++) {
  99. // find a random key in the lookaside array
  100. int index = rnd.Uniform(num_records);
  101. Slice k(keys[index]);
  102. // search in block for this key
  103. iter->Seek(k);
  104. ASSERT_TRUE(iter->Valid());
  105. Slice v = iter->value();
  106. ASSERT_EQ(v.ToString().compare(values[index]), 0);
  107. }
  108. delete iter;
  109. }
  110. // return the block contents
  111. BlockContents GetBlockContents(std::unique_ptr<BlockBuilder> *builder,
  112. const std::vector<std::string> &keys,
  113. const std::vector<std::string> &values,
  114. const int /*prefix_group_size*/ = 1) {
  115. builder->reset(new BlockBuilder(1 /* restart interval */));
  116. // Add only half of the keys
  117. for (size_t i = 0; i < keys.size(); ++i) {
  118. (*builder)->Add(keys[i], values[i]);
  119. }
  120. Slice rawblock = (*builder)->Finish();
  121. BlockContents contents;
  122. contents.data = rawblock;
  123. return contents;
  124. }
  125. void CheckBlockContents(BlockContents contents, const int max_key,
  126. const std::vector<std::string> &keys,
  127. const std::vector<std::string> &values) {
  128. const size_t prefix_size = 6;
  129. // create block reader
  130. BlockContents contents_ref(contents.data);
  131. Block reader1(std::move(contents), kDisableGlobalSequenceNumber);
  132. Block reader2(std::move(contents_ref), kDisableGlobalSequenceNumber);
  133. std::unique_ptr<const SliceTransform> prefix_extractor(
  134. NewFixedPrefixTransform(prefix_size));
  135. std::unique_ptr<InternalIterator> regular_iter(
  136. reader2.NewDataIterator(BytewiseComparator(), BytewiseComparator()));
  137. // Seek existent keys
  138. for (size_t i = 0; i < keys.size(); i++) {
  139. regular_iter->Seek(keys[i]);
  140. ASSERT_OK(regular_iter->status());
  141. ASSERT_TRUE(regular_iter->Valid());
  142. Slice v = regular_iter->value();
  143. ASSERT_EQ(v.ToString().compare(values[i]), 0);
  144. }
  145. // Seek non-existent keys.
  146. // For hash index, if no key with a given prefix is not found, iterator will
  147. // simply be set as invalid; whereas the binary search based iterator will
  148. // return the one that is closest.
  149. for (int i = 1; i < max_key - 1; i += 2) {
  150. auto key = GenerateKey(i, 0, 0, nullptr);
  151. regular_iter->Seek(key);
  152. ASSERT_TRUE(regular_iter->Valid());
  153. }
  154. }
  155. // In this test case, no two key share same prefix.
  156. TEST_F(BlockTest, SimpleIndexHash) {
  157. const int kMaxKey = 100000;
  158. std::vector<std::string> keys;
  159. std::vector<std::string> values;
  160. GenerateRandomKVs(&keys, &values, 0 /* first key id */,
  161. kMaxKey /* last key id */, 2 /* step */,
  162. 8 /* padding size (8 bytes randomly generated suffix) */);
  163. std::unique_ptr<BlockBuilder> builder;
  164. auto contents = GetBlockContents(&builder, keys, values);
  165. CheckBlockContents(std::move(contents), kMaxKey, keys, values);
  166. }
  167. TEST_F(BlockTest, IndexHashWithSharedPrefix) {
  168. const int kMaxKey = 100000;
  169. // for each prefix, there will be 5 keys starts with it.
  170. const int kPrefixGroup = 5;
  171. std::vector<std::string> keys;
  172. std::vector<std::string> values;
  173. // Generate keys with same prefix.
  174. GenerateRandomKVs(&keys, &values, 0, // first key id
  175. kMaxKey, // last key id
  176. 2, // step
  177. 10, // padding size,
  178. kPrefixGroup);
  179. std::unique_ptr<BlockBuilder> builder;
  180. auto contents = GetBlockContents(&builder, keys, values, kPrefixGroup);
  181. CheckBlockContents(std::move(contents), kMaxKey, keys, values);
  182. }
  183. // A slow and accurate version of BlockReadAmpBitmap that simply store
  184. // all the marked ranges in a set.
  185. class BlockReadAmpBitmapSlowAndAccurate {
  186. public:
  187. void Mark(size_t start_offset, size_t end_offset) {
  188. assert(end_offset >= start_offset);
  189. marked_ranges_.emplace(end_offset, start_offset);
  190. }
  191. void ResetCheckSequence() { iter_valid_ = false; }
  192. // Return true if any byte in this range was Marked
  193. // This does linear search from the previous position. When calling
  194. // multiple times, `offset` needs to be incremental to get correct results.
  195. // Call ResetCheckSequence() to reset it.
  196. bool IsPinMarked(size_t offset) {
  197. if (iter_valid_) {
  198. // Has existing iterator, try linear search from
  199. // the iterator.
  200. for (int i = 0; i < 64; i++) {
  201. if (offset < iter_->second) {
  202. return false;
  203. }
  204. if (offset <= iter_->first) {
  205. return true;
  206. }
  207. iter_++;
  208. if (iter_ == marked_ranges_.end()) {
  209. iter_valid_ = false;
  210. return false;
  211. }
  212. }
  213. }
  214. // Initial call or have linear searched too many times.
  215. // Do binary search.
  216. iter_ = marked_ranges_.lower_bound(
  217. std::make_pair(offset, static_cast<size_t>(0)));
  218. if (iter_ == marked_ranges_.end()) {
  219. iter_valid_ = false;
  220. return false;
  221. }
  222. iter_valid_ = true;
  223. return offset <= iter_->first && offset >= iter_->second;
  224. }
  225. private:
  226. std::set<std::pair<size_t, size_t>> marked_ranges_;
  227. std::set<std::pair<size_t, size_t>>::iterator iter_;
  228. bool iter_valid_ = false;
  229. };
  230. TEST_F(BlockTest, BlockReadAmpBitmap) {
  231. uint32_t pin_offset = 0;
  232. SyncPoint::GetInstance()->SetCallBack(
  233. "BlockReadAmpBitmap:rnd", [&pin_offset](void *arg) {
  234. pin_offset = *(static_cast<uint32_t *>(arg));
  235. });
  236. SyncPoint::GetInstance()->EnableProcessing();
  237. std::vector<size_t> block_sizes = {
  238. 1, // 1 byte
  239. 32, // 32 bytes
  240. 61, // 61 bytes
  241. 64, // 64 bytes
  242. 512, // 0.5 KB
  243. 1024, // 1 KB
  244. 1024 * 4, // 4 KB
  245. 1024 * 10, // 10 KB
  246. 1024 * 50, // 50 KB
  247. 1024 * 1024 * 4, // 5 MB
  248. 777,
  249. 124653,
  250. };
  251. const size_t kBytesPerBit = 64;
  252. Random rnd(301);
  253. for (size_t block_size : block_sizes) {
  254. std::shared_ptr<Statistics> stats = ROCKSDB_NAMESPACE::CreateDBStatistics();
  255. BlockReadAmpBitmap read_amp_bitmap(block_size, kBytesPerBit, stats.get());
  256. BlockReadAmpBitmapSlowAndAccurate read_amp_slow_and_accurate;
  257. size_t needed_bits = (block_size / kBytesPerBit);
  258. if (block_size % kBytesPerBit != 0) {
  259. needed_bits++;
  260. }
  261. ASSERT_EQ(stats->getTickerCount(READ_AMP_TOTAL_READ_BYTES), block_size);
  262. // Generate some random entries
  263. std::vector<size_t> random_entry_offsets;
  264. for (int i = 0; i < 1000; i++) {
  265. random_entry_offsets.push_back(rnd.Next() % block_size);
  266. }
  267. std::sort(random_entry_offsets.begin(), random_entry_offsets.end());
  268. auto it =
  269. std::unique(random_entry_offsets.begin(), random_entry_offsets.end());
  270. random_entry_offsets.resize(
  271. std::distance(random_entry_offsets.begin(), it));
  272. std::vector<std::pair<size_t, size_t>> random_entries;
  273. for (size_t i = 0; i < random_entry_offsets.size(); i++) {
  274. size_t entry_start = random_entry_offsets[i];
  275. size_t entry_end;
  276. if (i + 1 < random_entry_offsets.size()) {
  277. entry_end = random_entry_offsets[i + 1] - 1;
  278. } else {
  279. entry_end = block_size - 1;
  280. }
  281. random_entries.emplace_back(entry_start, entry_end);
  282. }
  283. for (size_t i = 0; i < random_entries.size(); i++) {
  284. read_amp_slow_and_accurate.ResetCheckSequence();
  285. auto &current_entry = random_entries[rnd.Next() % random_entries.size()];
  286. read_amp_bitmap.Mark(static_cast<uint32_t>(current_entry.first),
  287. static_cast<uint32_t>(current_entry.second));
  288. read_amp_slow_and_accurate.Mark(current_entry.first,
  289. current_entry.second);
  290. size_t total_bits = 0;
  291. for (size_t bit_idx = 0; bit_idx < needed_bits; bit_idx++) {
  292. total_bits += read_amp_slow_and_accurate.IsPinMarked(
  293. bit_idx * kBytesPerBit + pin_offset);
  294. }
  295. size_t expected_estimate_useful = total_bits * kBytesPerBit;
  296. size_t got_estimate_useful =
  297. stats->getTickerCount(READ_AMP_ESTIMATE_USEFUL_BYTES);
  298. ASSERT_EQ(expected_estimate_useful, got_estimate_useful);
  299. }
  300. }
  301. SyncPoint::GetInstance()->DisableProcessing();
  302. SyncPoint::GetInstance()->ClearAllCallBacks();
  303. }
  304. TEST_F(BlockTest, BlockWithReadAmpBitmap) {
  305. Random rnd(301);
  306. Options options = Options();
  307. std::vector<std::string> keys;
  308. std::vector<std::string> values;
  309. BlockBuilder builder(16);
  310. int num_records = 10000;
  311. GenerateRandomKVs(&keys, &values, 0, num_records, 1);
  312. // add a bunch of records to a block
  313. for (int i = 0; i < num_records; i++) {
  314. builder.Add(keys[i], values[i]);
  315. }
  316. Slice rawblock = builder.Finish();
  317. const size_t kBytesPerBit = 8;
  318. // Read the block sequentially using Next()
  319. {
  320. std::shared_ptr<Statistics> stats = ROCKSDB_NAMESPACE::CreateDBStatistics();
  321. // create block reader
  322. BlockContents contents;
  323. contents.data = rawblock;
  324. Block reader(std::move(contents), kDisableGlobalSequenceNumber,
  325. kBytesPerBit, stats.get());
  326. // read contents of block sequentially
  327. size_t read_bytes = 0;
  328. DataBlockIter *iter = reader.NewDataIterator(
  329. options.comparator, options.comparator, nullptr, stats.get());
  330. for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
  331. iter->value();
  332. read_bytes += iter->TEST_CurrentEntrySize();
  333. double semi_acc_read_amp =
  334. static_cast<double>(read_bytes) / rawblock.size();
  335. double read_amp = static_cast<double>(stats->getTickerCount(
  336. READ_AMP_ESTIMATE_USEFUL_BYTES)) /
  337. stats->getTickerCount(READ_AMP_TOTAL_READ_BYTES);
  338. // Error in read amplification will be less than 1% if we are reading
  339. // sequentially
  340. double error_pct = fabs(semi_acc_read_amp - read_amp) * 100;
  341. EXPECT_LT(error_pct, 1);
  342. }
  343. delete iter;
  344. }
  345. // Read the block sequentially using Seek()
  346. {
  347. std::shared_ptr<Statistics> stats = ROCKSDB_NAMESPACE::CreateDBStatistics();
  348. // create block reader
  349. BlockContents contents;
  350. contents.data = rawblock;
  351. Block reader(std::move(contents), kDisableGlobalSequenceNumber,
  352. kBytesPerBit, stats.get());
  353. size_t read_bytes = 0;
  354. DataBlockIter *iter = reader.NewDataIterator(
  355. options.comparator, options.comparator, nullptr, stats.get());
  356. for (int i = 0; i < num_records; i++) {
  357. Slice k(keys[i]);
  358. // search in block for this key
  359. iter->Seek(k);
  360. iter->value();
  361. read_bytes += iter->TEST_CurrentEntrySize();
  362. double semi_acc_read_amp =
  363. static_cast<double>(read_bytes) / rawblock.size();
  364. double read_amp = static_cast<double>(stats->getTickerCount(
  365. READ_AMP_ESTIMATE_USEFUL_BYTES)) /
  366. stats->getTickerCount(READ_AMP_TOTAL_READ_BYTES);
  367. // Error in read amplification will be less than 1% if we are reading
  368. // sequentially
  369. double error_pct = fabs(semi_acc_read_amp - read_amp) * 100;
  370. EXPECT_LT(error_pct, 1);
  371. }
  372. delete iter;
  373. }
  374. // Read the block randomly
  375. {
  376. std::shared_ptr<Statistics> stats = ROCKSDB_NAMESPACE::CreateDBStatistics();
  377. // create block reader
  378. BlockContents contents;
  379. contents.data = rawblock;
  380. Block reader(std::move(contents), kDisableGlobalSequenceNumber,
  381. kBytesPerBit, stats.get());
  382. size_t read_bytes = 0;
  383. DataBlockIter *iter = reader.NewDataIterator(
  384. options.comparator, options.comparator, nullptr, stats.get());
  385. std::unordered_set<int> read_keys;
  386. for (int i = 0; i < num_records; i++) {
  387. int index = rnd.Uniform(num_records);
  388. Slice k(keys[index]);
  389. iter->Seek(k);
  390. iter->value();
  391. if (read_keys.find(index) == read_keys.end()) {
  392. read_keys.insert(index);
  393. read_bytes += iter->TEST_CurrentEntrySize();
  394. }
  395. double semi_acc_read_amp =
  396. static_cast<double>(read_bytes) / rawblock.size();
  397. double read_amp = static_cast<double>(stats->getTickerCount(
  398. READ_AMP_ESTIMATE_USEFUL_BYTES)) /
  399. stats->getTickerCount(READ_AMP_TOTAL_READ_BYTES);
  400. double error_pct = fabs(semi_acc_read_amp - read_amp) * 100;
  401. // Error in read amplification will be less than 2% if we are reading
  402. // randomly
  403. EXPECT_LT(error_pct, 2);
  404. }
  405. delete iter;
  406. }
  407. }
  408. TEST_F(BlockTest, ReadAmpBitmapPow2) {
  409. std::shared_ptr<Statistics> stats = ROCKSDB_NAMESPACE::CreateDBStatistics();
  410. ASSERT_EQ(BlockReadAmpBitmap(100, 1, stats.get()).GetBytesPerBit(), 1u);
  411. ASSERT_EQ(BlockReadAmpBitmap(100, 2, stats.get()).GetBytesPerBit(), 2u);
  412. ASSERT_EQ(BlockReadAmpBitmap(100, 4, stats.get()).GetBytesPerBit(), 4u);
  413. ASSERT_EQ(BlockReadAmpBitmap(100, 8, stats.get()).GetBytesPerBit(), 8u);
  414. ASSERT_EQ(BlockReadAmpBitmap(100, 16, stats.get()).GetBytesPerBit(), 16u);
  415. ASSERT_EQ(BlockReadAmpBitmap(100, 32, stats.get()).GetBytesPerBit(), 32u);
  416. ASSERT_EQ(BlockReadAmpBitmap(100, 3, stats.get()).GetBytesPerBit(), 2u);
  417. ASSERT_EQ(BlockReadAmpBitmap(100, 7, stats.get()).GetBytesPerBit(), 4u);
  418. ASSERT_EQ(BlockReadAmpBitmap(100, 11, stats.get()).GetBytesPerBit(), 8u);
  419. ASSERT_EQ(BlockReadAmpBitmap(100, 17, stats.get()).GetBytesPerBit(), 16u);
  420. ASSERT_EQ(BlockReadAmpBitmap(100, 33, stats.get()).GetBytesPerBit(), 32u);
  421. ASSERT_EQ(BlockReadAmpBitmap(100, 35, stats.get()).GetBytesPerBit(), 32u);
  422. }
  423. class IndexBlockTest
  424. : public testing::Test,
  425. public testing::WithParamInterface<std::tuple<bool, bool>> {
  426. public:
  427. IndexBlockTest() = default;
  428. bool useValueDeltaEncoding() const { return std::get<0>(GetParam()); }
  429. bool includeFirstKey() const { return std::get<1>(GetParam()); }
  430. };
  431. // Similar to GenerateRandomKVs but for index block contents.
  432. void GenerateRandomIndexEntries(std::vector<std::string> *separators,
  433. std::vector<BlockHandle> *block_handles,
  434. std::vector<std::string> *first_keys,
  435. const int len) {
  436. Random rnd(42);
  437. // For each of `len` blocks, we need to generate a first and last key.
  438. // Let's generate n*2 random keys, sort them, group into consecutive pairs.
  439. std::set<std::string> keys;
  440. while ((int)keys.size() < len * 2) {
  441. // Keys need to be at least 8 bytes long to look like internal keys.
  442. keys.insert(test::RandomKey(&rnd, 12));
  443. }
  444. uint64_t offset = 0;
  445. for (auto it = keys.begin(); it != keys.end();) {
  446. first_keys->emplace_back(*it++);
  447. separators->emplace_back(*it++);
  448. uint64_t size = rnd.Uniform(1024 * 16);
  449. BlockHandle handle(offset, size);
  450. offset += size + kBlockTrailerSize;
  451. block_handles->emplace_back(handle);
  452. }
  453. }
  454. TEST_P(IndexBlockTest, IndexValueEncodingTest) {
  455. Random rnd(301);
  456. Options options = Options();
  457. std::vector<std::string> separators;
  458. std::vector<BlockHandle> block_handles;
  459. std::vector<std::string> first_keys;
  460. const bool kUseDeltaEncoding = true;
  461. BlockBuilder builder(16, kUseDeltaEncoding, useValueDeltaEncoding());
  462. int num_records = 100;
  463. GenerateRandomIndexEntries(&separators, &block_handles, &first_keys,
  464. num_records);
  465. BlockHandle last_encoded_handle;
  466. for (int i = 0; i < num_records; i++) {
  467. IndexValue entry(block_handles[i], first_keys[i]);
  468. std::string encoded_entry;
  469. std::string delta_encoded_entry;
  470. entry.EncodeTo(&encoded_entry, includeFirstKey(), nullptr);
  471. if (useValueDeltaEncoding() && i > 0) {
  472. entry.EncodeTo(&delta_encoded_entry, includeFirstKey(),
  473. &last_encoded_handle);
  474. }
  475. last_encoded_handle = entry.handle;
  476. const Slice delta_encoded_entry_slice(delta_encoded_entry);
  477. builder.Add(separators[i], encoded_entry, &delta_encoded_entry_slice);
  478. }
  479. // read serialized contents of the block
  480. Slice rawblock = builder.Finish();
  481. // create block reader
  482. BlockContents contents;
  483. contents.data = rawblock;
  484. Block reader(std::move(contents), kDisableGlobalSequenceNumber);
  485. const bool kTotalOrderSeek = true;
  486. const bool kIncludesSeq = true;
  487. const bool kValueIsFull = !useValueDeltaEncoding();
  488. IndexBlockIter *kNullIter = nullptr;
  489. Statistics *kNullStats = nullptr;
  490. // read contents of block sequentially
  491. InternalIteratorBase<IndexValue> *iter = reader.NewIndexIterator(
  492. options.comparator, options.comparator, kNullIter, kNullStats,
  493. kTotalOrderSeek, includeFirstKey(), kIncludesSeq, kValueIsFull);
  494. iter->SeekToFirst();
  495. for (int index = 0; index < num_records; ++index) {
  496. ASSERT_TRUE(iter->Valid());
  497. Slice k = iter->key();
  498. IndexValue v = iter->value();
  499. EXPECT_EQ(separators[index], k.ToString());
  500. EXPECT_EQ(block_handles[index].offset(), v.handle.offset());
  501. EXPECT_EQ(block_handles[index].size(), v.handle.size());
  502. EXPECT_EQ(includeFirstKey() ? first_keys[index] : "",
  503. v.first_internal_key.ToString());
  504. iter->Next();
  505. }
  506. delete iter;
  507. // read block contents randomly
  508. iter = reader.NewIndexIterator(options.comparator, options.comparator,
  509. kNullIter, kNullStats, kTotalOrderSeek,
  510. includeFirstKey(), kIncludesSeq, kValueIsFull);
  511. for (int i = 0; i < num_records * 2; i++) {
  512. // find a random key in the lookaside array
  513. int index = rnd.Uniform(num_records);
  514. Slice k(separators[index]);
  515. // search in block for this key
  516. iter->Seek(k);
  517. ASSERT_TRUE(iter->Valid());
  518. IndexValue v = iter->value();
  519. EXPECT_EQ(separators[index], iter->key().ToString());
  520. EXPECT_EQ(block_handles[index].offset(), v.handle.offset());
  521. EXPECT_EQ(block_handles[index].size(), v.handle.size());
  522. EXPECT_EQ(includeFirstKey() ? first_keys[index] : "",
  523. v.first_internal_key.ToString());
  524. }
  525. delete iter;
  526. }
  527. INSTANTIATE_TEST_CASE_P(P, IndexBlockTest,
  528. ::testing::Values(std::make_tuple(false, false),
  529. std::make_tuple(false, true),
  530. std::make_tuple(true, false),
  531. std::make_tuple(true, true)));
  532. } // namespace ROCKSDB_NAMESPACE
  533. int main(int argc, char **argv) {
  534. ::testing::InitGoogleTest(&argc, argv);
  535. return RUN_ALL_TESTS();
  536. }