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