/Users/deen/code/yugabyte-db/src/yb/rocksdb/db/db_block_cache_test.cc
Line | Count | Source |
1 | | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
2 | | // This source code is licensed under the BSD-style license found in the |
3 | | // LICENSE file in the root directory of this source tree. An additional grant |
4 | | // of patent rights can be found in the PATENTS file in the same directory. |
5 | | // |
6 | | // The following only applies to changes made to this file as part of YugaByte development. |
7 | | // |
8 | | // Portions Copyright (c) YugaByte, Inc. |
9 | | // |
10 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
11 | | // in compliance with the License. You may obtain a copy of the License at |
12 | | // |
13 | | // http://www.apache.org/licenses/LICENSE-2.0 |
14 | | // |
15 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
16 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
17 | | // or implied. See the License for the specific language governing permissions and limitations |
18 | | // under the License. |
19 | | // |
20 | | // Copyright (c) 2011 The LevelDB Authors. All rights reserved. |
21 | | // Use of this source code is governed by a BSD-style license that can be |
22 | | // found in the LICENSE file. See the AUTHORS file for names of contributors. |
23 | | #include "yb/rocksdb/db/db_test_util.h" |
24 | | #include "yb/rocksdb/port/stack_trace.h" |
25 | | |
26 | | DECLARE_double(cache_single_touch_ratio); |
27 | | DECLARE_bool(cache_overflow_single_touch); |
28 | | |
29 | | namespace rocksdb { |
30 | | |
31 | | class DBBlockCacheTest : public DBTestBase { |
32 | | private: |
33 | | size_t miss_count_ = 0; |
34 | | size_t hit_count_ = 0; |
35 | | size_t insert_count_ = 0; |
36 | | size_t failure_count_ = 0; |
37 | | size_t compressed_miss_count_ = 0; |
38 | | size_t compressed_hit_count_ = 0; |
39 | | size_t compressed_insert_count_ = 0; |
40 | | size_t compressed_failure_count_ = 0; |
41 | | |
42 | | public: |
43 | | const size_t kNumBlocks = 10; |
44 | | const size_t kValueSize = 100; |
45 | | |
46 | 2 | DBBlockCacheTest() : DBTestBase("/db_block_cache_test") {} |
47 | | |
48 | 2 | BlockBasedTableOptions GetTableOptions() { |
49 | 2 | BlockBasedTableOptions table_options; |
50 | | // Set a small enough block size so that each key-value get its own block. |
51 | 2 | table_options.block_size = 1; |
52 | 2 | return table_options; |
53 | 2 | } |
54 | | |
55 | 2 | Options GetOptions(const BlockBasedTableOptions& table_options) { |
56 | 2 | Options options = CurrentOptions(); |
57 | 2 | options.create_if_missing = true; |
58 | | // options.compression = kNoCompression; |
59 | 2 | options.statistics = rocksdb::CreateDBStatisticsForTests(); |
60 | 2 | options.table_factory.reset(new BlockBasedTableFactory(table_options)); |
61 | 2 | return options; |
62 | 2 | } |
63 | | |
64 | 2 | void InitTable(const Options& options) { |
65 | 2 | std::string value(kValueSize, 'a'); |
66 | 22 | for (size_t i = 0; i < kNumBlocks; i++) { |
67 | 20 | ASSERT_OK(Put(ToString(i), value.c_str())); |
68 | 20 | } |
69 | 2 | } |
70 | | |
71 | 2 | void RecordCacheCounters(const Options& options) { |
72 | 2 | miss_count_ = TestGetTickerCount(options, BLOCK_CACHE_MISS); |
73 | 2 | hit_count_ = TestGetTickerCount(options, BLOCK_CACHE_HIT); |
74 | 2 | insert_count_ = TestGetTickerCount(options, BLOCK_CACHE_ADD); |
75 | 2 | failure_count_ = TestGetTickerCount(options, BLOCK_CACHE_ADD_FAILURES); |
76 | 2 | compressed_miss_count_ = |
77 | 2 | TestGetTickerCount(options, BLOCK_CACHE_COMPRESSED_MISS); |
78 | 2 | compressed_hit_count_ = |
79 | 2 | TestGetTickerCount(options, BLOCK_CACHE_COMPRESSED_HIT); |
80 | 2 | compressed_insert_count_ = |
81 | 2 | TestGetTickerCount(options, BLOCK_CACHE_COMPRESSED_ADD); |
82 | 2 | compressed_failure_count_ = |
83 | 2 | TestGetTickerCount(options, BLOCK_CACHE_COMPRESSED_ADD_FAILURES); |
84 | 2 | } |
85 | | |
86 | | void CheckCacheCounters(const Options& options, size_t expected_misses, |
87 | | size_t expected_hits, size_t expected_inserts, |
88 | 36 | size_t expected_failures) { |
89 | 36 | size_t new_miss_count = TestGetTickerCount(options, BLOCK_CACHE_MISS); |
90 | 36 | size_t new_hit_count = TestGetTickerCount(options, BLOCK_CACHE_HIT); |
91 | 36 | size_t new_st_hit_count = TestGetTickerCount(options, BLOCK_CACHE_SINGLE_TOUCH_HIT); |
92 | 36 | size_t new_mt_hit_count = TestGetTickerCount(options, BLOCK_CACHE_MULTI_TOUCH_HIT); |
93 | 36 | size_t new_insert_count = TestGetTickerCount(options, BLOCK_CACHE_ADD); |
94 | 36 | size_t new_st_insert_count = TestGetTickerCount(options, BLOCK_CACHE_SINGLE_TOUCH_ADD); |
95 | 36 | size_t new_mt_insert_count = TestGetTickerCount(options, BLOCK_CACHE_MULTI_TOUCH_ADD); |
96 | 36 | size_t new_failure_count = |
97 | 36 | TestGetTickerCount(options, BLOCK_CACHE_ADD_FAILURES); |
98 | 36 | ASSERT_EQ(miss_count_ + expected_misses, new_miss_count); |
99 | 36 | ASSERT_EQ(hit_count_ + expected_hits, new_hit_count); |
100 | 36 | ASSERT_EQ(new_st_hit_count + new_mt_hit_count, new_hit_count); |
101 | 36 | ASSERT_EQ(insert_count_ + expected_inserts, new_insert_count); |
102 | 36 | ASSERT_EQ(new_st_insert_count + new_mt_insert_count, new_insert_count); |
103 | 36 | ASSERT_EQ(failure_count_ + expected_failures, new_failure_count); |
104 | 36 | miss_count_ = new_miss_count; |
105 | 36 | hit_count_ = new_hit_count; |
106 | 36 | insert_count_ = new_insert_count; |
107 | 36 | failure_count_ = new_failure_count; |
108 | 36 | } |
109 | | |
110 | | void CheckCompressedCacheCounters(const Options& options, |
111 | | size_t expected_misses, |
112 | | size_t expected_hits, |
113 | | size_t expected_inserts, |
114 | 9 | size_t expected_failures) { |
115 | 9 | size_t new_miss_count = |
116 | 9 | TestGetTickerCount(options, BLOCK_CACHE_COMPRESSED_MISS); |
117 | 9 | size_t new_hit_count = |
118 | 9 | TestGetTickerCount(options, BLOCK_CACHE_COMPRESSED_HIT); |
119 | 9 | size_t new_insert_count = |
120 | 9 | TestGetTickerCount(options, BLOCK_CACHE_COMPRESSED_ADD); |
121 | 9 | size_t new_failure_count = |
122 | 9 | TestGetTickerCount(options, BLOCK_CACHE_COMPRESSED_ADD_FAILURES); |
123 | 9 | ASSERT_EQ(compressed_miss_count_ + expected_misses, new_miss_count); |
124 | 9 | ASSERT_EQ(compressed_hit_count_ + expected_hits, new_hit_count); |
125 | 9 | ASSERT_EQ(compressed_insert_count_ + expected_inserts, new_insert_count); |
126 | 9 | ASSERT_EQ(compressed_failure_count_ + expected_failures, new_failure_count); |
127 | 9 | compressed_miss_count_ = new_miss_count; |
128 | 9 | compressed_hit_count_ = new_hit_count; |
129 | 9 | compressed_insert_count_ = new_insert_count; |
130 | 9 | compressed_failure_count_ = new_failure_count; |
131 | 9 | } |
132 | | }; |
133 | | |
134 | 1 | TEST_F(DBBlockCacheTest, TestWithoutCompressedBlockCache) { |
135 | 1 | ReadOptions read_options; |
136 | 1 | auto table_options = GetTableOptions(); |
137 | 1 | auto options = GetOptions(table_options); |
138 | 1 | InitTable(options); |
139 | | |
140 | 1 | FLAGS_cache_overflow_single_touch = false; |
141 | 1 | std::shared_ptr<Cache> cache = NewLRUCache(0, 0, false); |
142 | 1 | table_options.block_cache = cache; |
143 | 1 | options.table_factory.reset(new BlockBasedTableFactory(table_options)); |
144 | 1 | Reopen(options); |
145 | 1 | RecordCacheCounters(options); |
146 | | |
147 | 1 | std::vector<std::unique_ptr<Iterator>> iterators(kNumBlocks - 1); |
148 | 1 | Iterator* iter = nullptr; |
149 | | |
150 | | // Load blocks into cache. |
151 | 10 | for (size_t i = 0; i < kNumBlocks - 1; i++) { |
152 | 9 | iter = db_->NewIterator(read_options); |
153 | 9 | iter->Seek(ToString(i)); |
154 | 9 | ASSERT_OK(iter->status()); |
155 | 9 | CheckCacheCounters(options, 1, 0, 1, 0); |
156 | 9 | iterators[i].reset(iter); |
157 | 9 | } |
158 | 1 | size_t usage = cache->GetUsage(); |
159 | 1 | ASSERT_LT(0, usage); |
160 | | // Updating multi-touch capacity exactly equal to the usage to induce failures. |
161 | 1 | cache->SetCapacity(usage / FLAGS_cache_single_touch_ratio); |
162 | 1 | ASSERT_EQ(usage, cache->GetPinnedUsage()); |
163 | | |
164 | | // Release iterators and access cache again. |
165 | 10 | for (size_t i = 0; i < kNumBlocks - 1; i++) { |
166 | 9 | iterators[i].reset(); |
167 | 9 | CheckCacheCounters(options, 0, 0, 0, 0); |
168 | 9 | } |
169 | 1 | ASSERT_EQ(0, cache->GetPinnedUsage()); |
170 | 10 | for (size_t i = 0; i < kNumBlocks - 1; i++) { |
171 | 9 | iter = db_->NewIterator(read_options); |
172 | 9 | iter->Seek(ToString(i)); |
173 | 9 | ASSERT_OK(iter->status()); |
174 | 9 | CheckCacheCounters(options, 0, 1, 0, 0); |
175 | 9 | iterators[i].reset(iter); |
176 | 9 | } |
177 | 1 | FLAGS_cache_overflow_single_touch = true; |
178 | 1 | } |
179 | | |
180 | | #ifdef SNAPPY |
181 | 1 | TEST_F(DBBlockCacheTest, TestWithCompressedBlockCache) { |
182 | 1 | ReadOptions read_options; |
183 | 1 | auto table_options = GetTableOptions(); |
184 | 1 | auto options = GetOptions(table_options); |
185 | 1 | options.compression = CompressionType::kSnappyCompression; |
186 | 1 | InitTable(options); |
187 | | |
188 | 1 | FLAGS_cache_overflow_single_touch = false; |
189 | 1 | std::shared_ptr<Cache> cache = NewLRUCache(0, 0, false); |
190 | 1 | std::shared_ptr<Cache> compressed_cache = NewLRUCache(0, 0, false); |
191 | 1 | table_options.block_cache = cache; |
192 | 1 | table_options.block_cache_compressed = compressed_cache; |
193 | 1 | options.table_factory.reset(new BlockBasedTableFactory(table_options)); |
194 | 1 | Reopen(options); |
195 | 1 | RecordCacheCounters(options); |
196 | | |
197 | 1 | std::vector<std::unique_ptr<Iterator>> iterators(kNumBlocks - 1); |
198 | 1 | Iterator* iter = nullptr; |
199 | | |
200 | | // Load blocks into cache. |
201 | 10 | for (size_t i = 0; i < kNumBlocks - 1; i++) { |
202 | 9 | iter = db_->NewIterator(read_options); |
203 | 9 | iter->Seek(ToString(i)); |
204 | 9 | ASSERT_OK(iter->status()); |
205 | 9 | CheckCacheCounters(options, 1, 0, 1, 0); |
206 | 9 | CheckCompressedCacheCounters(options, 1, 0, 1, 0); |
207 | 9 | iterators[i].reset(iter); |
208 | 9 | } |
209 | 1 | size_t usage = cache->GetUsage(); |
210 | 1 | ASSERT_LT(0, usage); |
211 | 1 | ASSERT_EQ(usage, cache->GetPinnedUsage()); |
212 | 1 | size_t compressed_usage = compressed_cache->GetUsage(); |
213 | 1 | ASSERT_LT(0, compressed_usage); |
214 | | // Compressed block cache cannot be pinned. |
215 | 1 | ASSERT_EQ(0, compressed_cache->GetPinnedUsage()); |
216 | 1 | FLAGS_cache_overflow_single_touch = true; |
217 | 1 | } |
218 | | #endif |
219 | | |
220 | | } // namespace rocksdb |
221 | | |
222 | 13.2k | int main(int argc, char** argv) { |
223 | 13.2k | rocksdb::port::InstallStackTraceHandler(); |
224 | 13.2k | ::testing::InitGoogleTest(&argc, argv); |
225 | 13.2k | return RUN_ALL_TESTS(); |
226 | 13.2k | } |