]> git.proxmox.com Git - ceph.git/blame - ceph/src/rocksdb/db/blob/db_blob_basic_test.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / rocksdb / db / blob / db_blob_basic_test.cc
CommitLineData
20effc67
TL
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 "db/blob/blob_index.h"
7#include "db/db_test_util.h"
8#include "port/stack_trace.h"
9#include "test_util/sync_point.h"
10#include "utilities/fault_injection_env.h"
11
12namespace ROCKSDB_NAMESPACE {
13
14class DBBlobBasicTest : public DBTestBase {
15 protected:
16 DBBlobBasicTest()
17 : DBTestBase("/db_blob_basic_test", /* env_do_fsync */ false) {}
18};
19
20TEST_F(DBBlobBasicTest, GetBlob) {
21 Options options = GetDefaultOptions();
22 options.enable_blob_files = true;
23 options.min_blob_size = 0;
24
25 Reopen(options);
26
27 constexpr char key[] = "key";
28 constexpr char blob_value[] = "blob_value";
29
30 ASSERT_OK(Put(key, blob_value));
31
32 ASSERT_OK(Flush());
33
34 ASSERT_EQ(Get(key), blob_value);
35
36 // Try again with no I/O allowed. The table and the necessary blocks should
37 // already be in their respective caches; however, the blob itself can only be
38 // read from the blob file, so the read should return Incomplete.
39 ReadOptions read_options;
40 read_options.read_tier = kBlockCacheTier;
41
42 PinnableSlice result;
43 ASSERT_TRUE(db_->Get(read_options, db_->DefaultColumnFamily(), key, &result)
44 .IsIncomplete());
45}
46
47TEST_F(DBBlobBasicTest, GetBlob_CorruptIndex) {
48 Options options = GetDefaultOptions();
49 options.enable_blob_files = true;
50 options.min_blob_size = 0;
51
52 Reopen(options);
53
54 constexpr char key[] = "key";
55
56 // Fake a corrupt blob index.
57 const std::string blob_index("foobar");
58
59 WriteBatch batch;
60 ASSERT_OK(WriteBatchInternal::PutBlobIndex(&batch, 0, key, blob_index));
61 ASSERT_OK(db_->Write(WriteOptions(), &batch));
62
63 ASSERT_OK(Flush());
64
65 PinnableSlice result;
66 ASSERT_TRUE(db_->Get(ReadOptions(), db_->DefaultColumnFamily(), key, &result)
67 .IsCorruption());
68}
69
70TEST_F(DBBlobBasicTest, GetBlob_InlinedTTLIndex) {
71 constexpr uint64_t min_blob_size = 10;
72
73 Options options = GetDefaultOptions();
74 options.enable_blob_files = true;
75 options.min_blob_size = min_blob_size;
76
77 Reopen(options);
78
79 constexpr char key[] = "key";
80 constexpr char blob[] = "short";
81 static_assert(sizeof(short) - 1 < min_blob_size,
82 "Blob too long to be inlined");
83
84 // Fake an inlined TTL blob index.
85 std::string blob_index;
86
87 constexpr uint64_t expiration = 1234567890;
88
89 BlobIndex::EncodeInlinedTTL(&blob_index, expiration, blob);
90
91 WriteBatch batch;
92 ASSERT_OK(WriteBatchInternal::PutBlobIndex(&batch, 0, key, blob_index));
93 ASSERT_OK(db_->Write(WriteOptions(), &batch));
94
95 ASSERT_OK(Flush());
96
97 PinnableSlice result;
98 ASSERT_TRUE(db_->Get(ReadOptions(), db_->DefaultColumnFamily(), key, &result)
99 .IsCorruption());
100}
101
102TEST_F(DBBlobBasicTest, GetBlob_IndexWithInvalidFileNumber) {
103 Options options = GetDefaultOptions();
104 options.enable_blob_files = true;
105 options.min_blob_size = 0;
106
107 Reopen(options);
108
109 constexpr char key[] = "key";
110
111 // Fake a blob index referencing a non-existent blob file.
112 std::string blob_index;
113
114 constexpr uint64_t blob_file_number = 1000;
115 constexpr uint64_t offset = 1234;
116 constexpr uint64_t size = 5678;
117
118 BlobIndex::EncodeBlob(&blob_index, blob_file_number, offset, size,
119 kNoCompression);
120
121 WriteBatch batch;
122 ASSERT_OK(WriteBatchInternal::PutBlobIndex(&batch, 0, key, blob_index));
123 ASSERT_OK(db_->Write(WriteOptions(), &batch));
124
125 ASSERT_OK(Flush());
126
127 PinnableSlice result;
128 ASSERT_TRUE(db_->Get(ReadOptions(), db_->DefaultColumnFamily(), key, &result)
129 .IsCorruption());
130}
131
132class DBBlobBasicIOErrorTest : public DBBlobBasicTest,
133 public testing::WithParamInterface<std::string> {
134 protected:
135 DBBlobBasicIOErrorTest() : sync_point_(GetParam()) {
136 fault_injection_env_.reset(new FaultInjectionTestEnv(env_));
137 }
138 ~DBBlobBasicIOErrorTest() { Close(); }
139
140 std::unique_ptr<FaultInjectionTestEnv> fault_injection_env_;
141 std::string sync_point_;
142};
143
144INSTANTIATE_TEST_CASE_P(DBBlobBasicTest, DBBlobBasicIOErrorTest,
145 ::testing::ValuesIn(std::vector<std::string>{
146 "BlobFileReader::OpenFile:NewRandomAccessFile",
147 "BlobFileReader::GetBlob:ReadFromFile"}));
148
149TEST_P(DBBlobBasicIOErrorTest, GetBlob_IOError) {
150 Options options;
151 options.env = fault_injection_env_.get();
152 options.enable_blob_files = true;
153 options.min_blob_size = 0;
154
155 Reopen(options);
156
157 constexpr char key[] = "key";
158 constexpr char blob_value[] = "blob_value";
159
160 ASSERT_OK(Put(key, blob_value));
161
162 ASSERT_OK(Flush());
163
164 SyncPoint::GetInstance()->SetCallBack(sync_point_, [this](void* /* arg */) {
165 fault_injection_env_->SetFilesystemActive(false,
166 Status::IOError(sync_point_));
167 });
168 SyncPoint::GetInstance()->EnableProcessing();
169
170 PinnableSlice result;
171 ASSERT_TRUE(db_->Get(ReadOptions(), db_->DefaultColumnFamily(), key, &result)
172 .IsIOError());
173
174 SyncPoint::GetInstance()->DisableProcessing();
175 SyncPoint::GetInstance()->ClearAllCallBacks();
176}
177
178} // namespace ROCKSDB_NAMESPACE
179
180int main(int argc, char** argv) {
181 ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
182 ::testing::InitGoogleTest(&argc, argv);
183 return RUN_ALL_TESTS();
184}