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 // Copyright (c) 2012 The LevelDB Authors. All rights reserved.
7 // Use of this source code is governed by a BSD-style license that can be
8 // found in the LICENSE file. See the AUTHORS file for names of contributors.
9
10 #ifndef ROCKSDB_LITE
11 #ifndef GFLAGS
12 #include <cstdio>
main()13 int main() {
14 fprintf(stderr, "Please install gflags to run trace_analyzer test\n");
15 return 1;
16 }
17 #else
18
19 #include <chrono>
20 #include <cstdio>
21 #include <cstdlib>
22 #include <sstream>
23 #include <thread>
24
25 #include "db/db_test_util.h"
26 #include "file/line_file_reader.h"
27 #include "rocksdb/db.h"
28 #include "rocksdb/env.h"
29 #include "rocksdb/status.h"
30 #include "rocksdb/trace_reader_writer.h"
31 #include "test_util/testharness.h"
32 #include "test_util/testutil.h"
33 #include "tools/trace_analyzer_tool.h"
34 #include "trace_replay/trace_replay.h"
35
36 namespace ROCKSDB_NAMESPACE {
37
38 namespace {
39 static const int kMaxArgCount = 100;
40 static const size_t kArgBufferSize = 100000;
41 } // namespace
42
43 // The helper functions for the test
44 class TraceAnalyzerTest : public testing::Test {
45 public:
TraceAnalyzerTest()46 TraceAnalyzerTest() : rnd_(0xFB) {
47 // test_path_ = test::TmpDir() + "trace_analyzer_test";
48 test_path_ = test::PerThreadDBPath("trace_analyzer_test");
49 env_ = ROCKSDB_NAMESPACE::Env::Default();
50 env_->CreateDir(test_path_).PermitUncheckedError();
51 dbname_ = test_path_ + "/db";
52 }
53
~TraceAnalyzerTest()54 ~TraceAnalyzerTest() override {}
55
GenerateTrace(std::string trace_path)56 void GenerateTrace(std::string trace_path) {
57 Options options;
58 options.create_if_missing = true;
59 options.merge_operator = MergeOperators::CreatePutOperator();
60 Slice upper_bound("a");
61 Slice lower_bound("abce");
62 ReadOptions ro;
63 ro.iterate_upper_bound = &upper_bound;
64 ro.iterate_lower_bound = &lower_bound;
65 WriteOptions wo;
66 TraceOptions trace_opt;
67 DB* db_ = nullptr;
68 std::string value;
69 std::unique_ptr<TraceWriter> trace_writer;
70 Iterator* single_iter = nullptr;
71
72 ASSERT_OK(
73 NewFileTraceWriter(env_, env_options_, trace_path, &trace_writer));
74 ASSERT_OK(DB::Open(options, dbname_, &db_));
75 ASSERT_OK(db_->StartTrace(trace_opt, std::move(trace_writer)));
76
77 WriteBatch batch;
78 ASSERT_OK(batch.Put("a", "aaaaaaaaa"));
79 ASSERT_OK(batch.Merge("b", "aaaaaaaaaaaaaaaaaaaa"));
80 ASSERT_OK(batch.Delete("c"));
81 ASSERT_OK(batch.SingleDelete("d"));
82 ASSERT_OK(batch.DeleteRange("e", "f"));
83 ASSERT_OK(db_->Write(wo, &batch));
84
85 ASSERT_OK(db_->Get(ro, "a", &value));
86 single_iter = db_->NewIterator(ro);
87 single_iter->Seek("a");
88 ASSERT_OK(single_iter->status());
89 single_iter->SeekForPrev("b");
90 ASSERT_OK(single_iter->status());
91 delete single_iter;
92 std::this_thread::sleep_for (std::chrono::seconds(1));
93
94 db_->Get(ro, "g", &value).PermitUncheckedError();
95
96 ASSERT_OK(db_->EndTrace());
97
98 ASSERT_OK(env_->FileExists(trace_path));
99
100 std::unique_ptr<WritableFile> whole_f;
101 std::string whole_path = test_path_ + "/0.txt";
102 ASSERT_OK(env_->NewWritableFile(whole_path, &whole_f, env_options_));
103 std::string whole_str = "0x61\n0x62\n0x63\n0x64\n0x65\n0x66\n";
104 ASSERT_OK(whole_f->Append(whole_str));
105 delete db_;
106 ASSERT_OK(DestroyDB(dbname_, options));
107 }
108
RunTraceAnalyzer(const std::vector<std::string> & args)109 void RunTraceAnalyzer(const std::vector<std::string>& args) {
110 char arg_buffer[kArgBufferSize];
111 char* argv[kMaxArgCount];
112 int argc = 0;
113 int cursor = 0;
114
115 for (const auto& arg : args) {
116 ASSERT_LE(cursor + arg.size() + 1, kArgBufferSize);
117 ASSERT_LE(argc + 1, kMaxArgCount);
118 snprintf(arg_buffer + cursor, arg.size() + 1, "%s", arg.c_str());
119
120 argv[argc++] = arg_buffer + cursor;
121 cursor += static_cast<int>(arg.size()) + 1;
122 }
123
124 ASSERT_EQ(0, ROCKSDB_NAMESPACE::trace_analyzer_tool(argc, argv));
125 }
126
CheckFileContent(const std::vector<std::string> & cnt,std::string file_path,bool full_content)127 void CheckFileContent(const std::vector<std::string>& cnt,
128 std::string file_path, bool full_content) {
129 const auto& fs = env_->GetFileSystem();
130 FileOptions fopts(env_options_);
131
132 ASSERT_OK(fs->FileExists(file_path, fopts.io_options, nullptr));
133 std::unique_ptr<FSSequentialFile> file;
134 ASSERT_OK(fs->NewSequentialFile(file_path, fopts, &file, nullptr));
135
136 LineFileReader lf_reader(std::move(file), file_path,
137 4096 /* filereadahead_size */);
138
139 std::vector<std::string> result;
140 std::string line;
141 while (lf_reader.ReadLine(&line)) {
142 result.push_back(line);
143 }
144
145 ASSERT_OK(lf_reader.GetStatus());
146
147 ASSERT_EQ(cnt.size(), result.size());
148 for (int i = 0; i < static_cast<int>(result.size()); i++) {
149 if (full_content) {
150 ASSERT_EQ(result[i], cnt[i]);
151 } else {
152 ASSERT_EQ(result[i][0], cnt[i][0]);
153 }
154 }
155
156 return;
157 }
158
AnalyzeTrace(std::vector<std::string> & paras_diff,std::string output_path,std::string trace_path)159 void AnalyzeTrace(std::vector<std::string>& paras_diff,
160 std::string output_path, std::string trace_path) {
161 std::vector<std::string> paras = {"./trace_analyzer",
162 "-convert_to_human_readable_trace",
163 "-output_key_stats",
164 "-output_access_count_stats",
165 "-output_prefix=test",
166 "-output_prefix_cut=1",
167 "-output_time_series",
168 "-output_value_distribution",
169 "-output_qps_stats",
170 "-no_key",
171 "-no_print"};
172 for (auto& para : paras_diff) {
173 paras.push_back(para);
174 }
175 Status s = env_->FileExists(trace_path);
176 if (!s.ok()) {
177 GenerateTrace(trace_path);
178 }
179 ASSERT_OK(env_->CreateDir(output_path));
180 RunTraceAnalyzer(paras);
181 }
182
183 ROCKSDB_NAMESPACE::Env* env_;
184 EnvOptions env_options_;
185 std::string test_path_;
186 std::string dbname_;
187 Random rnd_;
188 };
189
TEST_F(TraceAnalyzerTest,Get)190 TEST_F(TraceAnalyzerTest, Get) {
191 std::string trace_path = test_path_ + "/trace";
192 std::string output_path = test_path_ + "/get";
193 std::string file_path;
194 std::vector<std::string> paras = {
195 "-analyze_get=true", "-analyze_put=false",
196 "-analyze_delete=false", "-analyze_single_delete=false",
197 "-analyze_range_delete=false", "-analyze_iterator=false"};
198 paras.push_back("-output_dir=" + output_path);
199 paras.push_back("-trace_path=" + trace_path);
200 paras.push_back("-key_space_dir=" + test_path_);
201 AnalyzeTrace(paras, output_path, trace_path);
202
203 // check the key_stats file
204 std::vector<std::string> k_stats = {"0 10 0 1 1.000000", "0 10 1 1 1.000000"};
205 file_path = output_path + "/test-get-0-accessed_key_stats.txt";
206 CheckFileContent(k_stats, file_path, true);
207
208 // Check the access count distribution
209 std::vector<std::string> k_dist = {"access_count: 1 num: 2"};
210 file_path = output_path + "/test-get-0-accessed_key_count_distribution.txt";
211 CheckFileContent(k_dist, file_path, true);
212
213 // Check the trace sequence
214 std::vector<std::string> k_sequence = {"1", "5", "2", "3", "4",
215 "0", "6", "7", "0"};
216 file_path = output_path + "/test-human_readable_trace.txt";
217 CheckFileContent(k_sequence, file_path, false);
218
219 // Check the prefix
220 std::vector<std::string> k_prefix = {"0 0 0 0.000000 0.000000 0x30",
221 "1 1 1 1.000000 1.000000 0x61"};
222 file_path = output_path + "/test-get-0-accessed_key_prefix_cut.txt";
223 CheckFileContent(k_prefix, file_path, true);
224
225 // Check the time series
226 std::vector<std::string> k_series = {"0 1533000630 0", "0 1533000630 1"};
227 file_path = output_path + "/test-get-0-time_series.txt";
228 CheckFileContent(k_series, file_path, false);
229
230 // Check the accessed key in whole key space
231 std::vector<std::string> k_whole_access = {"0 1"};
232 file_path = output_path + "/test-get-0-whole_key_stats.txt";
233 CheckFileContent(k_whole_access, file_path, true);
234
235 // Check the whole key prefix cut
236 std::vector<std::string> k_whole_prefix = {"0 0x61", "1 0x62", "2 0x63",
237 "3 0x64", "4 0x65", "5 0x66"};
238 file_path = output_path + "/test-get-0-whole_key_prefix_cut.txt";
239 CheckFileContent(k_whole_prefix, file_path, true);
240
241 // Check the overall qps
242 std::vector<std::string> all_qps = {"1 0 0 0 0 0 0 0 1"};
243 file_path = output_path + "/test-qps_stats.txt";
244 CheckFileContent(all_qps, file_path, true);
245
246 // Check the qps of get
247 std::vector<std::string> get_qps = {"1"};
248 file_path = output_path + "/test-get-0-qps_stats.txt";
249 CheckFileContent(get_qps, file_path, true);
250
251 // Check the top k qps prefix cut
252 std::vector<std::string> top_qps = {"At time: 0 with QPS: 1",
253 "The prefix: 0x61 Access count: 1"};
254 file_path = output_path + "/test-get-0-accessed_top_k_qps_prefix_cut.txt";
255 CheckFileContent(top_qps, file_path, true);
256 }
257
258 // Test analyzing of Put
TEST_F(TraceAnalyzerTest,Put)259 TEST_F(TraceAnalyzerTest, Put) {
260 std::string trace_path = test_path_ + "/trace";
261 std::string output_path = test_path_ + "/put";
262 std::string file_path;
263 std::vector<std::string> paras = {
264 "-analyze_get=false", "-analyze_put=true",
265 "-analyze_delete=false", "-analyze_single_delete=false",
266 "-analyze_range_delete=false", "-analyze_iterator=false"};
267 paras.push_back("-output_dir=" + output_path);
268 paras.push_back("-trace_path=" + trace_path);
269 paras.push_back("-key_space_dir=" + test_path_);
270 AnalyzeTrace(paras, output_path, trace_path);
271
272 // check the key_stats file
273 std::vector<std::string> k_stats = {"0 9 0 1 1.000000"};
274 file_path = output_path + "/test-put-0-accessed_key_stats.txt";
275 CheckFileContent(k_stats, file_path, true);
276
277 // Check the access count distribution
278 std::vector<std::string> k_dist = {"access_count: 1 num: 1"};
279 file_path = output_path + "/test-put-0-accessed_key_count_distribution.txt";
280 CheckFileContent(k_dist, file_path, true);
281
282 // Check the trace sequence
283 std::vector<std::string> k_sequence = {"1", "5", "2", "3", "4",
284 "0", "6", "7", "0"};
285 file_path = output_path + "/test-human_readable_trace.txt";
286 CheckFileContent(k_sequence, file_path, false);
287
288 // Check the prefix
289 std::vector<std::string> k_prefix = {"0 0 0 0.000000 0.000000 0x30"};
290 file_path = output_path + "/test-put-0-accessed_key_prefix_cut.txt";
291 CheckFileContent(k_prefix, file_path, true);
292
293 // Check the time series
294 std::vector<std::string> k_series = {"1 1533056278 0"};
295 file_path = output_path + "/test-put-0-time_series.txt";
296 CheckFileContent(k_series, file_path, false);
297
298 // Check the accessed key in whole key space
299 std::vector<std::string> k_whole_access = {"0 1"};
300 file_path = output_path + "/test-put-0-whole_key_stats.txt";
301 CheckFileContent(k_whole_access, file_path, true);
302
303 // Check the whole key prefix cut
304 std::vector<std::string> k_whole_prefix = {"0 0x61", "1 0x62", "2 0x63",
305 "3 0x64", "4 0x65", "5 0x66"};
306 file_path = output_path + "/test-put-0-whole_key_prefix_cut.txt";
307 CheckFileContent(k_whole_prefix, file_path, true);
308
309 // Check the overall qps
310 std::vector<std::string> all_qps = {"0 1 0 0 0 0 0 0 1"};
311 file_path = output_path + "/test-qps_stats.txt";
312 CheckFileContent(all_qps, file_path, true);
313
314 // Check the qps of Put
315 std::vector<std::string> get_qps = {"1"};
316 file_path = output_path + "/test-put-0-qps_stats.txt";
317 CheckFileContent(get_qps, file_path, true);
318
319 // Check the top k qps prefix cut
320 std::vector<std::string> top_qps = {"At time: 0 with QPS: 1",
321 "The prefix: 0x61 Access count: 1"};
322 file_path = output_path + "/test-put-0-accessed_top_k_qps_prefix_cut.txt";
323 CheckFileContent(top_qps, file_path, true);
324
325 // Check the value size distribution
326 std::vector<std::string> value_dist = {
327 "Number_of_value_size_between 0 and 16 is: 1"};
328 file_path = output_path + "/test-put-0-accessed_value_size_distribution.txt";
329 CheckFileContent(value_dist, file_path, true);
330 }
331
332 // Test analyzing of delete
TEST_F(TraceAnalyzerTest,Delete)333 TEST_F(TraceAnalyzerTest, Delete) {
334 std::string trace_path = test_path_ + "/trace";
335 std::string output_path = test_path_ + "/delete";
336 std::string file_path;
337 std::vector<std::string> paras = {
338 "-analyze_get=false", "-analyze_put=false",
339 "-analyze_delete=true", "-analyze_single_delete=false",
340 "-analyze_range_delete=false", "-analyze_iterator=false"};
341 paras.push_back("-output_dir=" + output_path);
342 paras.push_back("-trace_path=" + trace_path);
343 paras.push_back("-key_space_dir=" + test_path_);
344 AnalyzeTrace(paras, output_path, trace_path);
345
346 // check the key_stats file
347 std::vector<std::string> k_stats = {"0 0 0 1 1.000000"};
348 file_path = output_path + "/test-delete-0-accessed_key_stats.txt";
349 CheckFileContent(k_stats, file_path, true);
350
351 // Check the access count distribution
352 std::vector<std::string> k_dist = {"access_count: 1 num: 1"};
353 file_path =
354 output_path + "/test-delete-0-accessed_key_count_distribution.txt";
355 CheckFileContent(k_dist, file_path, true);
356
357 // Check the trace sequence
358 std::vector<std::string> k_sequence = {"1", "5", "2", "3", "4",
359 "0", "6", "7", "0"};
360 file_path = output_path + "/test-human_readable_trace.txt";
361 CheckFileContent(k_sequence, file_path, false);
362
363 // Check the prefix
364 std::vector<std::string> k_prefix = {"0 0 0 0.000000 0.000000 0x30"};
365 file_path = output_path + "/test-delete-0-accessed_key_prefix_cut.txt";
366 CheckFileContent(k_prefix, file_path, true);
367
368 // Check the time series
369 std::vector<std::string> k_series = {"2 1533000630 0"};
370 file_path = output_path + "/test-delete-0-time_series.txt";
371 CheckFileContent(k_series, file_path, false);
372
373 // Check the accessed key in whole key space
374 std::vector<std::string> k_whole_access = {"2 1"};
375 file_path = output_path + "/test-delete-0-whole_key_stats.txt";
376 CheckFileContent(k_whole_access, file_path, true);
377
378 // Check the whole key prefix cut
379 std::vector<std::string> k_whole_prefix = {"0 0x61", "1 0x62", "2 0x63",
380 "3 0x64", "4 0x65", "5 0x66"};
381 file_path = output_path + "/test-delete-0-whole_key_prefix_cut.txt";
382 CheckFileContent(k_whole_prefix, file_path, true);
383
384 // Check the overall qps
385 std::vector<std::string> all_qps = {"0 0 1 0 0 0 0 0 1"};
386 file_path = output_path + "/test-qps_stats.txt";
387 CheckFileContent(all_qps, file_path, true);
388
389 // Check the qps of Delete
390 std::vector<std::string> get_qps = {"1"};
391 file_path = output_path + "/test-delete-0-qps_stats.txt";
392 CheckFileContent(get_qps, file_path, true);
393
394 // Check the top k qps prefix cut
395 std::vector<std::string> top_qps = {"At time: 0 with QPS: 1",
396 "The prefix: 0x63 Access count: 1"};
397 file_path = output_path + "/test-delete-0-accessed_top_k_qps_prefix_cut.txt";
398 CheckFileContent(top_qps, file_path, true);
399 }
400
401 // Test analyzing of Merge
TEST_F(TraceAnalyzerTest,Merge)402 TEST_F(TraceAnalyzerTest, Merge) {
403 std::string trace_path = test_path_ + "/trace";
404 std::string output_path = test_path_ + "/merge";
405 std::string file_path;
406 std::vector<std::string> paras = {
407 "-analyze_get=false", "-analyze_put=false",
408 "-analyze_delete=false", "-analyze_merge=true",
409 "-analyze_single_delete=false", "-analyze_range_delete=false",
410 "-analyze_iterator=false"};
411 paras.push_back("-output_dir=" + output_path);
412 paras.push_back("-trace_path=" + trace_path);
413 paras.push_back("-key_space_dir=" + test_path_);
414 AnalyzeTrace(paras, output_path, trace_path);
415
416 // check the key_stats file
417 std::vector<std::string> k_stats = {"0 20 0 1 1.000000"};
418 file_path = output_path + "/test-merge-0-accessed_key_stats.txt";
419 CheckFileContent(k_stats, file_path, true);
420
421 // Check the access count distribution
422 std::vector<std::string> k_dist = {"access_count: 1 num: 1"};
423 file_path = output_path + "/test-merge-0-accessed_key_count_distribution.txt";
424 CheckFileContent(k_dist, file_path, true);
425
426 // Check the trace sequence
427 std::vector<std::string> k_sequence = {"1", "5", "2", "3", "4",
428 "0", "6", "7", "0"};
429 file_path = output_path + "/test-human_readable_trace.txt";
430 CheckFileContent(k_sequence, file_path, false);
431
432 // Check the prefix
433 std::vector<std::string> k_prefix = {"0 0 0 0.000000 0.000000 0x30"};
434 file_path = output_path + "/test-merge-0-accessed_key_prefix_cut.txt";
435 CheckFileContent(k_prefix, file_path, true);
436
437 // Check the time series
438 std::vector<std::string> k_series = {"5 1533000630 0"};
439 file_path = output_path + "/test-merge-0-time_series.txt";
440 CheckFileContent(k_series, file_path, false);
441
442 // Check the accessed key in whole key space
443 std::vector<std::string> k_whole_access = {"1 1"};
444 file_path = output_path + "/test-merge-0-whole_key_stats.txt";
445 CheckFileContent(k_whole_access, file_path, true);
446
447 // Check the whole key prefix cut
448 std::vector<std::string> k_whole_prefix = {"0 0x61", "1 0x62", "2 0x63",
449 "3 0x64", "4 0x65", "5 0x66"};
450 file_path = output_path + "/test-merge-0-whole_key_prefix_cut.txt";
451 CheckFileContent(k_whole_prefix, file_path, true);
452
453 // Check the overall qps
454 std::vector<std::string> all_qps = {"0 0 0 0 0 1 0 0 1"};
455 file_path = output_path + "/test-qps_stats.txt";
456 CheckFileContent(all_qps, file_path, true);
457
458 // Check the qps of Merge
459 std::vector<std::string> get_qps = {"1"};
460 file_path = output_path + "/test-merge-0-qps_stats.txt";
461 CheckFileContent(get_qps, file_path, true);
462
463 // Check the top k qps prefix cut
464 std::vector<std::string> top_qps = {"At time: 0 with QPS: 1",
465 "The prefix: 0x62 Access count: 1"};
466 file_path = output_path + "/test-merge-0-accessed_top_k_qps_prefix_cut.txt";
467 CheckFileContent(top_qps, file_path, true);
468
469 // Check the value size distribution
470 std::vector<std::string> value_dist = {
471 "Number_of_value_size_between 0 and 24 is: 1"};
472 file_path =
473 output_path + "/test-merge-0-accessed_value_size_distribution.txt";
474 CheckFileContent(value_dist, file_path, true);
475 }
476
477 // Test analyzing of SingleDelete
TEST_F(TraceAnalyzerTest,SingleDelete)478 TEST_F(TraceAnalyzerTest, SingleDelete) {
479 std::string trace_path = test_path_ + "/trace";
480 std::string output_path = test_path_ + "/single_delete";
481 std::string file_path;
482 std::vector<std::string> paras = {
483 "-analyze_get=false", "-analyze_put=false",
484 "-analyze_delete=false", "-analyze_merge=false",
485 "-analyze_single_delete=true", "-analyze_range_delete=false",
486 "-analyze_iterator=false"};
487 paras.push_back("-output_dir=" + output_path);
488 paras.push_back("-trace_path=" + trace_path);
489 paras.push_back("-key_space_dir=" + test_path_);
490 AnalyzeTrace(paras, output_path, trace_path);
491
492 // check the key_stats file
493 std::vector<std::string> k_stats = {"0 0 0 1 1.000000"};
494 file_path = output_path + "/test-single_delete-0-accessed_key_stats.txt";
495 CheckFileContent(k_stats, file_path, true);
496
497 // Check the access count distribution
498 std::vector<std::string> k_dist = {"access_count: 1 num: 1"};
499 file_path =
500 output_path + "/test-single_delete-0-accessed_key_count_distribution.txt";
501 CheckFileContent(k_dist, file_path, true);
502
503 // Check the trace sequence
504 std::vector<std::string> k_sequence = {"1", "5", "2", "3", "4",
505 "0", "6", "7", "0"};
506 file_path = output_path + "/test-human_readable_trace.txt";
507 CheckFileContent(k_sequence, file_path, false);
508
509 // Check the prefix
510 std::vector<std::string> k_prefix = {"0 0 0 0.000000 0.000000 0x30"};
511 file_path = output_path + "/test-single_delete-0-accessed_key_prefix_cut.txt";
512 CheckFileContent(k_prefix, file_path, true);
513
514 // Check the time series
515 std::vector<std::string> k_series = {"3 1533000630 0"};
516 file_path = output_path + "/test-single_delete-0-time_series.txt";
517 CheckFileContent(k_series, file_path, false);
518
519 // Check the accessed key in whole key space
520 std::vector<std::string> k_whole_access = {"3 1"};
521 file_path = output_path + "/test-single_delete-0-whole_key_stats.txt";
522 CheckFileContent(k_whole_access, file_path, true);
523
524 // Check the whole key prefix cut
525 std::vector<std::string> k_whole_prefix = {"0 0x61", "1 0x62", "2 0x63",
526 "3 0x64", "4 0x65", "5 0x66"};
527 file_path = output_path + "/test-single_delete-0-whole_key_prefix_cut.txt";
528 CheckFileContent(k_whole_prefix, file_path, true);
529
530 // Check the overall qps
531 std::vector<std::string> all_qps = {"0 0 0 1 0 0 0 0 1"};
532 file_path = output_path + "/test-qps_stats.txt";
533 CheckFileContent(all_qps, file_path, true);
534
535 // Check the qps of SingleDelete
536 std::vector<std::string> get_qps = {"1"};
537 file_path = output_path + "/test-single_delete-0-qps_stats.txt";
538 CheckFileContent(get_qps, file_path, true);
539
540 // Check the top k qps prefix cut
541 std::vector<std::string> top_qps = {"At time: 0 with QPS: 1",
542 "The prefix: 0x64 Access count: 1"};
543 file_path =
544 output_path + "/test-single_delete-0-accessed_top_k_qps_prefix_cut.txt";
545 CheckFileContent(top_qps, file_path, true);
546 }
547
548 // Test analyzing of delete
TEST_F(TraceAnalyzerTest,DeleteRange)549 TEST_F(TraceAnalyzerTest, DeleteRange) {
550 std::string trace_path = test_path_ + "/trace";
551 std::string output_path = test_path_ + "/range_delete";
552 std::string file_path;
553 std::vector<std::string> paras = {
554 "-analyze_get=false", "-analyze_put=false",
555 "-analyze_delete=false", "-analyze_merge=false",
556 "-analyze_single_delete=false", "-analyze_range_delete=true",
557 "-analyze_iterator=false"};
558 paras.push_back("-output_dir=" + output_path);
559 paras.push_back("-trace_path=" + trace_path);
560 paras.push_back("-key_space_dir=" + test_path_);
561 AnalyzeTrace(paras, output_path, trace_path);
562
563 // check the key_stats file
564 std::vector<std::string> k_stats = {"0 0 0 1 1.000000", "0 0 1 1 1.000000"};
565 file_path = output_path + "/test-range_delete-0-accessed_key_stats.txt";
566 CheckFileContent(k_stats, file_path, true);
567
568 // Check the access count distribution
569 std::vector<std::string> k_dist = {"access_count: 1 num: 2"};
570 file_path =
571 output_path + "/test-range_delete-0-accessed_key_count_distribution.txt";
572 CheckFileContent(k_dist, file_path, true);
573
574 // Check the trace sequence
575 std::vector<std::string> k_sequence = {"1", "5", "2", "3", "4",
576 "0", "6", "7", "0"};
577 file_path = output_path + "/test-human_readable_trace.txt";
578 CheckFileContent(k_sequence, file_path, false);
579
580 // Check the prefix
581 std::vector<std::string> k_prefix = {"0 0 0 0.000000 0.000000 0x30",
582 "1 1 1 1.000000 1.000000 0x65"};
583 file_path = output_path + "/test-range_delete-0-accessed_key_prefix_cut.txt";
584 CheckFileContent(k_prefix, file_path, true);
585
586 // Check the time series
587 std::vector<std::string> k_series = {"4 1533000630 0", "4 1533060100 1"};
588 file_path = output_path + "/test-range_delete-0-time_series.txt";
589 CheckFileContent(k_series, file_path, false);
590
591 // Check the accessed key in whole key space
592 std::vector<std::string> k_whole_access = {"4 1", "5 1"};
593 file_path = output_path + "/test-range_delete-0-whole_key_stats.txt";
594 CheckFileContent(k_whole_access, file_path, true);
595
596 // Check the whole key prefix cut
597 std::vector<std::string> k_whole_prefix = {"0 0x61", "1 0x62", "2 0x63",
598 "3 0x64", "4 0x65", "5 0x66"};
599 file_path = output_path + "/test-range_delete-0-whole_key_prefix_cut.txt";
600 CheckFileContent(k_whole_prefix, file_path, true);
601
602 // Check the overall qps
603 std::vector<std::string> all_qps = {"0 0 0 0 2 0 0 0 2"};
604 file_path = output_path + "/test-qps_stats.txt";
605 CheckFileContent(all_qps, file_path, true);
606
607 // Check the qps of DeleteRange
608 std::vector<std::string> get_qps = {"2"};
609 file_path = output_path + "/test-range_delete-0-qps_stats.txt";
610 CheckFileContent(get_qps, file_path, true);
611
612 // Check the top k qps prefix cut
613 std::vector<std::string> top_qps = {"At time: 0 with QPS: 2",
614 "The prefix: 0x65 Access count: 1",
615 "The prefix: 0x66 Access count: 1"};
616 file_path =
617 output_path + "/test-range_delete-0-accessed_top_k_qps_prefix_cut.txt";
618 CheckFileContent(top_qps, file_path, true);
619 }
620
621 // Test analyzing of Iterator
TEST_F(TraceAnalyzerTest,Iterator)622 TEST_F(TraceAnalyzerTest, Iterator) {
623 std::string trace_path = test_path_ + "/trace";
624 std::string output_path = test_path_ + "/iterator";
625 std::string file_path;
626 std::vector<std::string> paras = {
627 "-analyze_get=false", "-analyze_put=false",
628 "-analyze_delete=false", "-analyze_merge=false",
629 "-analyze_single_delete=false", "-analyze_range_delete=false",
630 "-analyze_iterator=true"};
631 paras.push_back("-output_dir=" + output_path);
632 paras.push_back("-trace_path=" + trace_path);
633 paras.push_back("-key_space_dir=" + test_path_);
634 AnalyzeTrace(paras, output_path, trace_path);
635
636 // Check the output of Seek
637 // check the key_stats file
638 std::vector<std::string> k_stats = {"0 0 0 1 1.000000"};
639 file_path = output_path + "/test-iterator_Seek-0-accessed_key_stats.txt";
640 CheckFileContent(k_stats, file_path, true);
641
642 // Check the access count distribution
643 std::vector<std::string> k_dist = {"access_count: 1 num: 1"};
644 file_path =
645 output_path + "/test-iterator_Seek-0-accessed_key_count_distribution.txt";
646 CheckFileContent(k_dist, file_path, true);
647
648 // Check the trace sequence
649 std::vector<std::string> k_sequence = {"1", "5", "2", "3", "4",
650 "0", "6", "7", "0"};
651 file_path = output_path + "/test-human_readable_trace.txt";
652 CheckFileContent(k_sequence, file_path, false);
653
654 // Check the prefix
655 std::vector<std::string> k_prefix = {"0 0 0 0.000000 0.000000 0x30"};
656 file_path = output_path + "/test-iterator_Seek-0-accessed_key_prefix_cut.txt";
657 CheckFileContent(k_prefix, file_path, true);
658
659 // Check the time series
660 std::vector<std::string> k_series = {"6 1 0"};
661 file_path = output_path + "/test-iterator_Seek-0-time_series.txt";
662 CheckFileContent(k_series, file_path, false);
663
664 // Check the accessed key in whole key space
665 std::vector<std::string> k_whole_access = {"0 1"};
666 file_path = output_path + "/test-iterator_Seek-0-whole_key_stats.txt";
667 CheckFileContent(k_whole_access, file_path, true);
668
669 // Check the whole key prefix cut
670 std::vector<std::string> k_whole_prefix = {"0 0x61", "1 0x62", "2 0x63",
671 "3 0x64", "4 0x65", "5 0x66"};
672 file_path = output_path + "/test-iterator_Seek-0-whole_key_prefix_cut.txt";
673 CheckFileContent(k_whole_prefix, file_path, true);
674
675 // Check the overall qps
676 std::vector<std::string> all_qps = {"0 0 0 0 0 0 1 1 2"};
677 file_path = output_path + "/test-qps_stats.txt";
678 CheckFileContent(all_qps, file_path, true);
679
680 // Check the qps of Iterator_Seek
681 std::vector<std::string> get_qps = {"1"};
682 file_path = output_path + "/test-iterator_Seek-0-qps_stats.txt";
683 CheckFileContent(get_qps, file_path, true);
684
685 // Check the top k qps prefix cut
686 std::vector<std::string> top_qps = {"At time: 0 with QPS: 1",
687 "The prefix: 0x61 Access count: 1"};
688 file_path =
689 output_path + "/test-iterator_Seek-0-accessed_top_k_qps_prefix_cut.txt";
690 CheckFileContent(top_qps, file_path, true);
691
692 // Check the output of SeekForPrev
693 // check the key_stats file
694 k_stats = {"0 0 0 1 1.000000"};
695 file_path =
696 output_path + "/test-iterator_SeekForPrev-0-accessed_key_stats.txt";
697 CheckFileContent(k_stats, file_path, true);
698
699 // Check the access count distribution
700 k_dist = {"access_count: 1 num: 1"};
701 file_path =
702 output_path +
703 "/test-iterator_SeekForPrev-0-accessed_key_count_distribution.txt";
704 CheckFileContent(k_dist, file_path, true);
705
706 // Check the prefix
707 k_prefix = {"0 0 0 0.000000 0.000000 0x30"};
708 file_path =
709 output_path + "/test-iterator_SeekForPrev-0-accessed_key_prefix_cut.txt";
710 CheckFileContent(k_prefix, file_path, true);
711
712 // Check the time series
713 k_series = {"7 0 0"};
714 file_path = output_path + "/test-iterator_SeekForPrev-0-time_series.txt";
715 CheckFileContent(k_series, file_path, false);
716
717 // Check the accessed key in whole key space
718 k_whole_access = {"1 1"};
719 file_path = output_path + "/test-iterator_SeekForPrev-0-whole_key_stats.txt";
720 CheckFileContent(k_whole_access, file_path, true);
721
722 // Check the whole key prefix cut
723 k_whole_prefix = {"0 0x61", "1 0x62", "2 0x63", "3 0x64", "4 0x65", "5 0x66"};
724 file_path =
725 output_path + "/test-iterator_SeekForPrev-0-whole_key_prefix_cut.txt";
726 CheckFileContent(k_whole_prefix, file_path, true);
727
728 // Check the qps of Iterator_SeekForPrev
729 get_qps = {"1"};
730 file_path = output_path + "/test-iterator_SeekForPrev-0-qps_stats.txt";
731 CheckFileContent(get_qps, file_path, true);
732
733 // Check the top k qps prefix cut
734 top_qps = {"At time: 0 with QPS: 1", "The prefix: 0x62 Access count: 1"};
735 file_path = output_path +
736 "/test-iterator_SeekForPrev-0-accessed_top_k_qps_prefix_cut.txt";
737 CheckFileContent(top_qps, file_path, true);
738 }
739
740 } // namespace ROCKSDB_NAMESPACE
741
main(int argc,char ** argv)742 int main(int argc, char** argv) {
743 ::testing::InitGoogleTest(&argc, argv);
744 return RUN_ALL_TESTS();
745 }
746 #endif // GFLAG
747 #else
748 #include <stdio.h>
749
main(int,char **)750 int main(int /*argc*/, char** /*argv*/) {
751 fprintf(stderr, "Trace_analyzer test is not supported in ROCKSDB_LITE\n");
752 return 0;
753 }
754
755 #endif // !ROCKSDB_LITE return RUN_ALL_TESTS();
756