/Users/deen/code/yugabyte-db/src/yb/tserver/encrypted_sstable-test.cc
Line | Count | Source |
1 | | // Copyright (c) Yugabyte, Inc. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
4 | | // in compliance with the License. You may obtain a copy of the License at |
5 | | // |
6 | | // http://www.apache.org/licenses/LICENSE-2.0 |
7 | | // |
8 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
9 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
10 | | // or implied. See the License for the specific language governing permissions and limitations |
11 | | // under the License. |
12 | | // |
13 | | |
14 | | #include <glog/logging.h> |
15 | | #include <gtest/gtest.h> |
16 | | |
17 | | #include "yb/gutil/stringprintf.h" |
18 | | |
19 | | #include "yb/encryption/encrypted_file.h" |
20 | | #include "yb/encryption/encryption_util.h" |
21 | | #include "yb/encryption/header_manager.h" |
22 | | #include "yb/encryption/header_manager_impl.h" |
23 | | #include "yb/encryption/universe_key_manager.h" |
24 | | |
25 | | #include "yb/rocksdb/db/dbformat.h" |
26 | | #include "yb/rocksdb/table/block_based_table_factory.h" |
27 | | #include "yb/rocksdb/table/internal_iterator.h" |
28 | | #include "yb/rocksdb/table/table_builder.h" |
29 | | #include "yb/rocksdb/util/file_reader_writer.h" |
30 | | |
31 | | #include "yb/rocksutil/rocksdb_encrypted_file_factory.h" |
32 | | |
33 | | #include "yb/tserver/universe_key_test_util.h" |
34 | | |
35 | | #include "yb/util/path_util.h" |
36 | | #include "yb/util/status.h" |
37 | | #include "yb/util/test_util.h" |
38 | | |
39 | | using namespace std::literals; |
40 | | |
41 | | using yb::tserver::GenerateTestUniverseKeyManager; |
42 | | |
43 | | DECLARE_int64(encryption_counter_min); |
44 | | DECLARE_int64(encryption_counter_max); |
45 | | DECLARE_bool(TEST_encryption_use_openssl_compatible_counter_overflow); |
46 | | |
47 | | namespace yb { |
48 | | namespace enterprise { |
49 | | |
50 | | namespace { |
51 | | |
52 | 40.4M | std::string GetKey(int i) { |
53 | 40.4M | return StringPrintf("key%09dSSSSSSSS", i); |
54 | 40.4M | } |
55 | | |
56 | 40.4M | std::string GetValue(int i) { |
57 | 40.4M | return Format("value%d", i); |
58 | 40.4M | } |
59 | | |
60 | | } // anonymous namespace |
61 | | |
62 | | class EncryptedSSTableTest : public YBTest, public testing::WithParamInterface<bool> { |
63 | | protected: |
64 | | void CounterOverflow( |
65 | | int num_keys, int64_t initial_counter); |
66 | | }; |
67 | | |
68 | | INSTANTIATE_TEST_CASE_P( |
69 | | UseOpensslCompatibleCounterOverflow, EncryptedSSTableTest, ::testing::Bool()); |
70 | | |
71 | | void EncryptedSSTableTest::CounterOverflow( |
72 | 4 | int num_keys, int64_t initial_counter) { |
73 | 4 | FLAGS_encryption_counter_min = initial_counter; |
74 | 4 | FLAGS_encryption_counter_max = initial_counter; |
75 | 4 | FLAGS_TEST_encryption_use_openssl_compatible_counter_overflow = GetParam(); |
76 | | |
77 | 4 | string test_dir; |
78 | 4 | ASSERT_OK(Env::Default()->GetTestDirectory(&test_dir)); |
79 | | |
80 | 4 | rocksdb::Options opts; |
81 | 4 | const rocksdb::ImmutableCFOptions imoptions(opts); |
82 | 4 | auto ikc = std::make_shared<rocksdb::InternalKeyComparator>(opts.comparator); |
83 | 4 | std::vector<std::unique_ptr<rocksdb::IntTblPropCollectorFactory> > |
84 | 4 | block_based_table_factories; |
85 | 4 | rocksdb::CompressionOptions compression_opts; |
86 | 4 | rocksdb::TableBuilderOptions table_builder_options( |
87 | 4 | imoptions, |
88 | 4 | ikc, |
89 | 4 | block_based_table_factories, |
90 | 4 | rocksdb::CompressionType::kSnappyCompression, |
91 | 4 | compression_opts, |
92 | 4 | /* skip_filters */ false); |
93 | | |
94 | 4 | rocksdb::TableReaderOptions table_reader_options( |
95 | 4 | imoptions, |
96 | 4 | rocksdb::EnvOptions(), |
97 | 4 | ikc, |
98 | 4 | /*skip_filters=*/ false); |
99 | | |
100 | 4 | auto universe_key_manager = GenerateTestUniverseKeyManager(); |
101 | | |
102 | 4 | auto header_manager = DefaultHeaderManager(universe_key_manager.get()); |
103 | 4 | auto env = yb::NewRocksDBEncryptedEnv(std::move(header_manager)); |
104 | | |
105 | 4 | auto file_name = JoinPathSegments(test_dir, "test-file"); |
106 | | |
107 | 4 | std::unique_ptr<rocksdb::WritableFile> base_file; |
108 | 4 | ASSERT_OK(env->NewWritableFile(file_name, &base_file, rocksdb::EnvOptions())); |
109 | 4 | rocksdb::WritableFileWriter base_writer(std::move(base_file), rocksdb::EnvOptions(), |
110 | 4 | /* suspender */ nullptr); |
111 | | |
112 | 4 | string data_file_name = file_name + ".sblock.0"; |
113 | 4 | std::unique_ptr<rocksdb::WritableFile> data_file; |
114 | 4 | ASSERT_OK(env->NewWritableFile(data_file_name, &data_file, rocksdb::EnvOptions())); |
115 | 4 | rocksdb::WritableFileWriter data_writer(std::move(data_file), rocksdb::EnvOptions(), |
116 | 4 | /* suspender */ nullptr); |
117 | | |
118 | 4 | rocksdb::BlockBasedTableFactory blk_based_tbl_factory; |
119 | 4 | auto table_builder = std::unique_ptr<rocksdb::TableBuilder>( |
120 | 4 | blk_based_tbl_factory.NewTableBuilder(table_builder_options, 0, &base_writer, &data_writer)); |
121 | | |
122 | 20.2M | for (int i = 0; i < num_keys; ++i) { |
123 | 20.2M | string key = GetKey(i); |
124 | 20.2M | table_builder->Add(key, GetValue(i)); |
125 | 20.2M | } |
126 | 4 | ASSERT_OK(table_builder->Finish()); |
127 | 4 | LOG(INFO) << "Wrote a file of total size " << table_builder->TotalFileSize() |
128 | 4 | << ", base file size: " << table_builder->BaseFileSize(); |
129 | 4 | ASSERT_OK(base_writer.Flush()); |
130 | 4 | ASSERT_OK(data_writer.Flush()); |
131 | 4 | ASSERT_OK(base_writer.Close()); |
132 | 4 | ASSERT_OK(data_writer.Close()); |
133 | | |
134 | 4 | std::unique_ptr<rocksdb::RandomAccessFile> random_access_file; |
135 | 4 | ASSERT_OK(env->NewRandomAccessFile(file_name, &random_access_file, rocksdb::EnvOptions())); |
136 | 4 | auto base_file_size = ASSERT_RESULT(random_access_file->Size()); |
137 | 4 | ASSERT_EQ(base_file_size, table_builder->BaseFileSize()); |
138 | | |
139 | 4 | std::unique_ptr<rocksdb::RandomAccessFile> random_access_data_file; |
140 | 4 | ASSERT_OK(env->NewRandomAccessFile( |
141 | 4 | data_file_name, &random_access_data_file, rocksdb::EnvOptions())); |
142 | 4 | auto data_file_reader = std::make_unique<rocksdb::RandomAccessFileReader>( |
143 | 4 | std::move(random_access_data_file), env.get()); |
144 | | |
145 | 4 | auto* eraf = down_cast<encryption::EncryptedRandomAccessFile*>(random_access_file.get()); |
146 | 4 | auto* eraf_data = down_cast<encryption::EncryptedRandomAccessFile*>(random_access_file.get()); |
147 | | |
148 | 4 | ASSERT_TRUE(eraf != nullptr); |
149 | 4 | ASSERT_TRUE(eraf_data != nullptr); |
150 | 4 | ASSERT_EQ(0, eraf->TEST_GetNumOverflowWorkarounds()); |
151 | 4 | ASSERT_EQ(0, eraf_data->TEST_GetNumOverflowWorkarounds()); |
152 | | |
153 | 4 | size_t raw_size = ASSERT_RESULT(Env::Default()->GetFileSize(file_name)); |
154 | 4 | LOG(INFO) << "Raw file size: " << raw_size; |
155 | | |
156 | 4 | auto random_access_file_reader = std::make_unique<rocksdb::RandomAccessFileReader>( |
157 | 4 | std::move(random_access_file)); |
158 | | |
159 | 4 | std::unique_ptr<rocksdb::TableReader> table_reader; |
160 | | |
161 | 4 | ASSERT_OK(blk_based_tbl_factory.NewTableReader( |
162 | 4 | table_reader_options, std::move(random_access_file_reader), |
163 | 4 | base_file_size, |
164 | 4 | &table_reader, |
165 | 4 | rocksdb::DataIndexLoadMode::PRELOAD_ON_OPEN, |
166 | 4 | rocksdb::PrefetchFilter::YES)); |
167 | | |
168 | 4 | table_reader->SetDataFileReader(std::move(data_file_reader)); |
169 | | |
170 | 4 | auto it = std::unique_ptr<rocksdb::InternalIterator>( |
171 | 4 | table_reader->NewIterator(rocksdb::ReadOptions())); |
172 | 4 | it->SeekToFirst(); |
173 | 4 | int i = 0; |
174 | 20.2M | while (it->Valid()) { |
175 | 20.2M | ASSERT_EQ(it->key(), GetKey(i)); |
176 | 20.2M | ASSERT_EQ(it->value(), GetValue(i)); |
177 | 20.2M | i++; |
178 | 20.2M | it->Next(); |
179 | 20.2M | } |
180 | 4 | ASSERT_EQ(num_keys, i); |
181 | 4 | ASSERT_GE(eraf->TEST_GetNumOverflowWorkarounds(), 0); |
182 | 4 | ASSERT_GE(eraf_data->TEST_GetNumOverflowWorkarounds(), 0); |
183 | 4 | } |
184 | | |
185 | 2 | TEST_P(EncryptedSSTableTest, CounterOverflow10MKeys) { |
186 | | // Note that only three zeros are there in the end of the initial counter below. We are trying to |
187 | | // get a counter that is 65536 bytes (4096 encryption blocks) away from overflow. |
188 | 2 | CounterOverflow(10 * 1000 * 1000, 0xfffff000); |
189 | 2 | } |
190 | | |
191 | 2 | TEST_P(EncryptedSSTableTest, CounterOverflow100000Keys) { |
192 | | // This test fails if meta block checksums are not being verified. |
193 | | // https://github.com/yugabyte/yugabyte-db/issues/3974 |
194 | 2 | CounterOverflow(100 * 1000, 0xffffff00); |
195 | 2 | } |
196 | | |
197 | | } // namespace enterprise |
198 | | } // namespace yb |