]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/trace_replay/io_tracer_test.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / rocksdb / trace_replay / io_tracer_test.cc
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 #include "trace_replay/io_tracer.h"
7
8 #include "rocksdb/env.h"
9 #include "rocksdb/status.h"
10 #include "test_util/testharness.h"
11 #include "test_util/testutil.h"
12
13 namespace ROCKSDB_NAMESPACE {
14
15 namespace {
16 const std::string kDummyFile = "/dummy/file";
17
18 } // namespace
19
20 class IOTracerTest : public testing::Test {
21 public:
22 IOTracerTest() {
23 test_path_ = test::PerThreadDBPath("io_tracer_test");
24 env_ = ROCKSDB_NAMESPACE::Env::Default();
25 EXPECT_OK(env_->CreateDir(test_path_));
26 trace_file_path_ = test_path_ + "/io_trace";
27 }
28
29 ~IOTracerTest() override {
30 EXPECT_OK(env_->DeleteFile(trace_file_path_));
31 EXPECT_OK(env_->DeleteDir(test_path_));
32 }
33
34 std::string GetFileOperation(uint64_t id) {
35 id = id % 4;
36 switch (id) {
37 case 0:
38 return "CreateDir";
39 case 1:
40 return "GetChildren";
41 case 2:
42 return "FileSize";
43 case 3:
44 return "DeleteDir";
45 default:
46 assert(false);
47 }
48 return "";
49 }
50
51 void WriteIOOp(IOTraceWriter* writer, uint64_t nrecords) {
52 assert(writer);
53 for (uint64_t i = 0; i < nrecords; i++) {
54 IOTraceRecord record;
55 record.trace_type = TraceType::kIOLenAndOffset;
56 record.file_operation = GetFileOperation(i);
57 record.io_status = IOStatus::OK().ToString();
58 record.file_name = kDummyFile + std::to_string(i);
59 record.len = i;
60 record.offset = i + 20;
61 ASSERT_OK(writer->WriteIOOp(record));
62 }
63 }
64
65 void VerifyIOOp(IOTraceReader* reader, uint32_t nrecords) {
66 assert(reader);
67 for (uint32_t i = 0; i < nrecords; i++) {
68 IOTraceRecord record;
69 ASSERT_OK(reader->ReadIOOp(&record));
70 ASSERT_EQ(record.file_operation, GetFileOperation(i));
71 ASSERT_EQ(record.io_status, IOStatus::OK().ToString());
72 ASSERT_EQ(record.len, i);
73 ASSERT_EQ(record.offset, i + 20);
74 }
75 }
76
77 Env* env_;
78 EnvOptions env_options_;
79 std::string trace_file_path_;
80 std::string test_path_;
81 };
82
83 TEST_F(IOTracerTest, AtomicWrite) {
84 std::string file_name = kDummyFile + std::to_string(0);
85 {
86 IOTraceRecord record(0, TraceType::kIOFileName, GetFileOperation(0), 0,
87 IOStatus::OK().ToString(), file_name);
88 TraceOptions trace_opt;
89 std::unique_ptr<TraceWriter> trace_writer;
90 ASSERT_OK(NewFileTraceWriter(env_, env_options_, trace_file_path_,
91 &trace_writer));
92 IOTracer writer;
93 ASSERT_OK(writer.StartIOTrace(env_, trace_opt, std::move(trace_writer)));
94 ASSERT_OK(writer.WriteIOOp(record));
95 ASSERT_OK(env_->FileExists(trace_file_path_));
96 }
97 {
98 // Verify trace file contains one record.
99 std::unique_ptr<TraceReader> trace_reader;
100 ASSERT_OK(NewFileTraceReader(env_, env_options_, trace_file_path_,
101 &trace_reader));
102 IOTraceReader reader(std::move(trace_reader));
103 IOTraceHeader header;
104 ASSERT_OK(reader.ReadHeader(&header));
105 ASSERT_EQ(kMajorVersion, static_cast<int>(header.rocksdb_major_version));
106 ASSERT_EQ(kMinorVersion, static_cast<int>(header.rocksdb_minor_version));
107 // Read record and verify data.
108 IOTraceRecord access_record;
109 ASSERT_OK(reader.ReadIOOp(&access_record));
110 ASSERT_EQ(access_record.file_operation, GetFileOperation(0));
111 ASSERT_EQ(access_record.io_status, IOStatus::OK().ToString());
112 ASSERT_EQ(access_record.file_name, file_name);
113 ASSERT_NOK(reader.ReadIOOp(&access_record));
114 }
115 }
116
117 TEST_F(IOTracerTest, AtomicWriteBeforeStartTrace) {
118 {
119 IOTraceRecord record(0, TraceType::kIOGeneral, GetFileOperation(0), 0,
120 IOStatus::OK().ToString());
121 std::unique_ptr<TraceWriter> trace_writer;
122 ASSERT_OK(NewFileTraceWriter(env_, env_options_, trace_file_path_,
123 &trace_writer));
124 IOTracer writer;
125 // The record should not be written to the trace_file since StartIOTrace is
126 // not called.
127 ASSERT_OK(writer.WriteIOOp(record));
128 ASSERT_OK(env_->FileExists(trace_file_path_));
129 }
130 {
131 // Verify trace file contains nothing.
132 std::unique_ptr<TraceReader> trace_reader;
133 ASSERT_OK(NewFileTraceReader(env_, env_options_, trace_file_path_,
134 &trace_reader));
135 IOTraceReader reader(std::move(trace_reader));
136 IOTraceHeader header;
137 ASSERT_NOK(reader.ReadHeader(&header));
138 }
139 }
140
141 TEST_F(IOTracerTest, AtomicNoWriteAfterEndTrace) {
142 {
143 IOTraceRecord record(0, TraceType::kIOFileNameAndFileSize,
144 GetFileOperation(2), 0 /*latency*/,
145 IOStatus::OK().ToString(), "", 10 /*file_size*/);
146 TraceOptions trace_opt;
147 std::unique_ptr<TraceWriter> trace_writer;
148 ASSERT_OK(NewFileTraceWriter(env_, env_options_, trace_file_path_,
149 &trace_writer));
150 IOTracer writer;
151 ASSERT_OK(writer.StartIOTrace(env_, trace_opt, std::move(trace_writer)));
152 ASSERT_OK(writer.WriteIOOp(record));
153 writer.EndIOTrace();
154 // Write the record again. This time the record should not be written since
155 // EndIOTrace is called.
156 ASSERT_OK(writer.WriteIOOp(record));
157 ASSERT_OK(env_->FileExists(trace_file_path_));
158 }
159 {
160 // Verify trace file contains one record.
161 std::unique_ptr<TraceReader> trace_reader;
162 ASSERT_OK(NewFileTraceReader(env_, env_options_, trace_file_path_,
163 &trace_reader));
164 IOTraceReader reader(std::move(trace_reader));
165 IOTraceHeader header;
166 ASSERT_OK(reader.ReadHeader(&header));
167 ASSERT_EQ(kMajorVersion, static_cast<int>(header.rocksdb_major_version));
168 ASSERT_EQ(kMinorVersion, static_cast<int>(header.rocksdb_minor_version));
169
170 IOTraceRecord access_record;
171 ASSERT_OK(reader.ReadIOOp(&access_record));
172 ASSERT_EQ(access_record.file_operation, GetFileOperation(2));
173 ASSERT_EQ(access_record.io_status, IOStatus::OK().ToString());
174 ASSERT_EQ(access_record.file_size, 10);
175 // No more record.
176 ASSERT_NOK(reader.ReadIOOp(&access_record));
177 }
178 }
179
180 TEST_F(IOTracerTest, AtomicMultipleWrites) {
181 {
182 TraceOptions trace_opt;
183 std::unique_ptr<TraceWriter> trace_writer;
184 ASSERT_OK(NewFileTraceWriter(env_, env_options_, trace_file_path_,
185 &trace_writer));
186 IOTraceWriter writer(env_, trace_opt, std::move(trace_writer));
187 ASSERT_OK(writer.WriteHeader());
188 // Write 10 records
189 WriteIOOp(&writer, 10);
190 ASSERT_OK(env_->FileExists(trace_file_path_));
191 }
192
193 {
194 // Verify trace file is generated correctly.
195 std::unique_ptr<TraceReader> trace_reader;
196 ASSERT_OK(NewFileTraceReader(env_, env_options_, trace_file_path_,
197 &trace_reader));
198 IOTraceReader reader(std::move(trace_reader));
199 IOTraceHeader header;
200 ASSERT_OK(reader.ReadHeader(&header));
201 ASSERT_EQ(kMajorVersion, static_cast<int>(header.rocksdb_major_version));
202 ASSERT_EQ(kMinorVersion, static_cast<int>(header.rocksdb_minor_version));
203 // Read 10 records.
204 VerifyIOOp(&reader, 10);
205 // Read one more and record and it should report error.
206 IOTraceRecord record;
207 ASSERT_NOK(reader.ReadIOOp(&record));
208 }
209 }
210 } // namespace ROCKSDB_NAMESPACE
211
212 int main(int argc, char** argv) {
213 ::testing::InitGoogleTest(&argc, argv);
214 return RUN_ALL_TESTS();
215 }