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).
6 #include "trace_replay/io_tracer.h"
8 #include "rocksdb/env.h"
9 #include "rocksdb/status.h"
10 #include "test_util/testharness.h"
11 #include "test_util/testutil.h"
13 namespace ROCKSDB_NAMESPACE
{
16 const std::string kDummyFile
= "/dummy/file";
20 class IOTracerTest
: public testing::Test
{
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";
29 ~IOTracerTest() override
{
30 EXPECT_OK(env_
->DeleteFile(trace_file_path_
));
31 EXPECT_OK(env_
->DeleteDir(test_path_
));
34 std::string
GetFileOperation(uint64_t id
) {
51 void WriteIOOp(IOTraceWriter
* writer
, uint64_t nrecords
) {
53 for (uint64_t i
= 0; i
< nrecords
; i
++) {
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
);
60 record
.offset
= i
+ 20;
61 ASSERT_OK(writer
->WriteIOOp(record
));
65 void VerifyIOOp(IOTraceReader
* reader
, uint32_t nrecords
) {
67 for (uint32_t i
= 0; i
< nrecords
; i
++) {
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);
78 EnvOptions env_options_
;
79 std::string trace_file_path_
;
80 std::string test_path_
;
83 TEST_F(IOTracerTest
, AtomicWrite
) {
84 std::string file_name
= kDummyFile
+ std::to_string(0);
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_
,
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_
));
98 // Verify trace file contains one record.
99 std::unique_ptr
<TraceReader
> trace_reader
;
100 ASSERT_OK(NewFileTraceReader(env_
, env_options_
, trace_file_path_
,
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
));
117 TEST_F(IOTracerTest
, AtomicWriteBeforeStartTrace
) {
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_
,
125 // The record should not be written to the trace_file since StartIOTrace is
127 ASSERT_OK(writer
.WriteIOOp(record
));
128 ASSERT_OK(env_
->FileExists(trace_file_path_
));
131 // Verify trace file contains nothing.
132 std::unique_ptr
<TraceReader
> trace_reader
;
133 ASSERT_OK(NewFileTraceReader(env_
, env_options_
, trace_file_path_
,
135 IOTraceReader
reader(std::move(trace_reader
));
136 IOTraceHeader header
;
137 ASSERT_NOK(reader
.ReadHeader(&header
));
141 TEST_F(IOTracerTest
, AtomicNoWriteAfterEndTrace
) {
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_
,
151 ASSERT_OK(writer
.StartIOTrace(env_
, trace_opt
, std::move(trace_writer
)));
152 ASSERT_OK(writer
.WriteIOOp(record
));
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_
));
160 // Verify trace file contains one record.
161 std::unique_ptr
<TraceReader
> trace_reader
;
162 ASSERT_OK(NewFileTraceReader(env_
, env_options_
, trace_file_path_
,
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
));
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);
176 ASSERT_NOK(reader
.ReadIOOp(&access_record
));
180 TEST_F(IOTracerTest
, AtomicMultipleWrites
) {
182 TraceOptions trace_opt
;
183 std::unique_ptr
<TraceWriter
> trace_writer
;
184 ASSERT_OK(NewFileTraceWriter(env_
, env_options_
, trace_file_path_
,
186 IOTraceWriter
writer(env_
, trace_opt
, std::move(trace_writer
));
187 ASSERT_OK(writer
.WriteHeader());
189 WriteIOOp(&writer
, 10);
190 ASSERT_OK(env_
->FileExists(trace_file_path_
));
194 // Verify trace file is generated correctly.
195 std::unique_ptr
<TraceReader
> trace_reader
;
196 ASSERT_OK(NewFileTraceReader(env_
, env_options_
, trace_file_path_
,
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
));
204 VerifyIOOp(&reader
, 10);
205 // Read one more and record and it should report error.
206 IOTraceRecord record
;
207 ASSERT_NOK(reader
.ReadIOOp(&record
));
210 } // namespace ROCKSDB_NAMESPACE
212 int main(int argc
, char** argv
) {
213 ::testing::InitGoogleTest(&argc
, argv
);
214 return RUN_ALL_TESTS();