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