io_tracer_parser_test.cc 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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. #ifndef GFLAGS
  7. #include <cstdio>
  8. int main() {
  9. fprintf(stderr, "Please install gflags to run io_tracer_parser_test\n");
  10. return 0;
  11. }
  12. #else
  13. #include <string>
  14. #include <vector>
  15. #include "rocksdb/db.h"
  16. #include "rocksdb/env.h"
  17. #include "rocksdb/status.h"
  18. #include "rocksdb/trace_reader_writer.h"
  19. #include "test_util/testharness.h"
  20. #include "test_util/testutil.h"
  21. #include "tools/io_tracer_parser_tool.h"
  22. namespace ROCKSDB_NAMESPACE {
  23. namespace {
  24. const int kMaxArgCount = 100;
  25. const size_t kArgBufferSize = 100000;
  26. } // namespace
  27. class IOTracerParserTest : public testing::Test {
  28. public:
  29. IOTracerParserTest() {
  30. test_path_ = test::PerThreadDBPath("io_tracer_parser_test");
  31. env_ = ROCKSDB_NAMESPACE::Env::Default();
  32. EXPECT_OK(env_->CreateDirIfMissing(test_path_));
  33. trace_file_path_ = test_path_ + "/io_trace_file";
  34. dbname_ = test_path_ + "/db";
  35. Options options;
  36. options.create_if_missing = true;
  37. EXPECT_OK(DB::Open(options, dbname_, &db_));
  38. }
  39. ~IOTracerParserTest() {
  40. if (env_->FileExists(trace_file_path_).ok()) {
  41. EXPECT_OK(env_->DeleteFile(trace_file_path_));
  42. }
  43. if (db_ != nullptr) {
  44. Options options;
  45. options.env = env_;
  46. delete db_;
  47. db_ = nullptr;
  48. EXPECT_OK(DestroyDB(dbname_, options));
  49. }
  50. EXPECT_OK(env_->DeleteDir(test_path_));
  51. }
  52. void GenerateIOTrace() {
  53. WriteOptions write_opt;
  54. TraceOptions trace_opt;
  55. std::unique_ptr<TraceWriter> trace_writer;
  56. ASSERT_OK(NewFileTraceWriter(env_, env_options_, trace_file_path_,
  57. &trace_writer));
  58. ASSERT_OK(db_->StartIOTrace(trace_opt, std::move(trace_writer)));
  59. for (int i = 0; i < 10; i++) {
  60. ASSERT_OK(db_->Put(write_opt, "key_" + std::to_string(i),
  61. "value_" + std::to_string(i)));
  62. ASSERT_OK(db_->Flush(FlushOptions()));
  63. }
  64. ASSERT_OK(db_->EndIOTrace());
  65. ASSERT_OK(env_->FileExists(trace_file_path_));
  66. }
  67. void RunIOTracerParserTool() {
  68. std::vector<std::string> params = {"./io_tracer_parser",
  69. "-io_trace_file=" + trace_file_path_};
  70. char arg_buffer[kArgBufferSize];
  71. char* argv[kMaxArgCount];
  72. int argc = 0;
  73. int cursor = 0;
  74. for (const auto& arg : params) {
  75. ASSERT_LE(cursor + arg.size() + 1, kArgBufferSize);
  76. ASSERT_LE(argc + 1, kMaxArgCount);
  77. snprintf(arg_buffer + cursor, arg.size() + 1, "%s", arg.c_str());
  78. argv[argc++] = arg_buffer + cursor;
  79. cursor += static_cast<int>(arg.size()) + 1;
  80. }
  81. ASSERT_EQ(0, ROCKSDB_NAMESPACE::io_tracer_parser(argc, argv));
  82. }
  83. DB* db_;
  84. Env* env_;
  85. EnvOptions env_options_;
  86. std::string trace_file_path_;
  87. std::string output_file_;
  88. std::string test_path_;
  89. std::string dbname_;
  90. };
  91. TEST_F(IOTracerParserTest, InvalidArguments) {
  92. {
  93. std::vector<std::string> params = {"./io_tracer_parser"};
  94. char arg_buffer[kArgBufferSize];
  95. char* argv[kMaxArgCount];
  96. int argc = 0;
  97. int cursor = 0;
  98. for (const auto& arg : params) {
  99. ASSERT_LE(cursor + arg.size() + 1, kArgBufferSize);
  100. ASSERT_LE(argc + 1, kMaxArgCount);
  101. snprintf(arg_buffer + cursor, arg.size() + 1, "%s", arg.c_str());
  102. argv[argc++] = arg_buffer + cursor;
  103. cursor += static_cast<int>(arg.size()) + 1;
  104. }
  105. ASSERT_EQ(1, ROCKSDB_NAMESPACE::io_tracer_parser(argc, argv));
  106. }
  107. }
  108. TEST_F(IOTracerParserTest, DumpAndParseIOTraceRecords) {
  109. GenerateIOTrace();
  110. RunIOTracerParserTool();
  111. }
  112. TEST_F(IOTracerParserTest, NoRecordingAfterEndIOTrace) {
  113. uint64_t file_size = 0;
  114. // Generate IO trace records and parse them.
  115. {
  116. GenerateIOTrace();
  117. RunIOTracerParserTool();
  118. ASSERT_OK(env_->GetFileSize(trace_file_path_, &file_size));
  119. }
  120. // Once DB::EndIOTrace is invoked in GenerateIOTrace(), no new records should
  121. // be appended.
  122. {
  123. WriteOptions write_opt;
  124. for (int i = 10; i < 20; i++) {
  125. ASSERT_OK(db_->Put(write_opt, "key_" + std::to_string(i),
  126. "value_" + std::to_string(i)));
  127. ASSERT_OK(db_->Flush(FlushOptions()));
  128. }
  129. }
  130. uint64_t new_file_size = 0;
  131. ASSERT_OK(env_->GetFileSize(trace_file_path_, &new_file_size));
  132. ASSERT_EQ(file_size, new_file_size);
  133. }
  134. TEST_F(IOTracerParserTest, NoRecordingBeforeStartIOTrace) {
  135. {
  136. WriteOptions write_opt;
  137. for (int i = 10; i < 20; i++) {
  138. ASSERT_OK(db_->Put(write_opt, "key_" + std::to_string(i),
  139. "value_" + std::to_string(i)));
  140. ASSERT_OK(db_->Flush(FlushOptions()));
  141. }
  142. // IO trace file doesn't exist
  143. ASSERT_NOK(env_->FileExists(trace_file_path_));
  144. }
  145. // Generate IO trace records and parse them.
  146. {
  147. GenerateIOTrace();
  148. RunIOTracerParserTool();
  149. }
  150. }
  151. } // namespace ROCKSDB_NAMESPACE
  152. int main(int argc, char** argv) {
  153. ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
  154. ::testing::InitGoogleTest(&argc, argv);
  155. return RUN_ALL_TESTS();
  156. }
  157. #endif // GFLAGS