1 /* copyright (C) 2013-2020 Codership Oy <info@codership.com>
2 *
3 * $Id$
4 */
5
6 #undef NDEBUG
7
8 #include "test_key.hpp"
9 #include "../src/key_set.hpp"
10
11 #include "gu_logger.hpp"
12 #include "gu_hexdump.hpp"
13
14 #include <check.h>
15
16 using namespace galera;
17
18 class TestBaseName : public gu::Allocator::BaseName
19 {
20 std::string str_;
21
22 public:
23
TestBaseName(const char * name)24 TestBaseName(const char* name) : str_(name) {}
print(std::ostream & os) const25 void print(std::ostream& os) const { os << str_; }
26 };
27
version_to_hash_size(KeySet::Version const ver)28 static size_t version_to_hash_size (KeySet::Version const ver)
29 {
30 switch (ver)
31 {
32 case KeySet::FLAT16: ck_abort_msg("FLAT16 is not supported by test");
33 case KeySet::FLAT16A: return 16;
34 case KeySet::FLAT8: ck_abort_msg( "FLAT8 is not supported by test");
35 case KeySet::FLAT8A: return 8;
36 default: ck_abort_msg("Unsupported KeySet verison: %d", ver);
37 }
38
39 abort();
40 }
41
test_ver(gu::RecordSet::Version const rsv,int ws_ver)42 static void test_ver(gu::RecordSet::Version const rsv, int ws_ver)
43 {
44 int const alignment
45 (rsv >= gu::RecordSet::VER2 ? gu::RecordSet::VER2_ALIGNMENT : 1);
46 KeySet::Version const tk_ver(KeySet::FLAT16A);
47 size_t const base_size(version_to_hash_size(tk_ver));
48
49 union { gu::byte_t buf[1024]; gu_word_t align; } reserved;
50 assert((uintptr_t(reserved.buf) % GU_WORD_BYTES) == 0);
51 TestBaseName const str("key_set_test");
52 KeySetOut kso (reserved.buf, sizeof(reserved.buf), str, tk_ver, rsv, ws_ver);
53
54 ck_assert(kso.count() == 0);
55 size_t total_size(kso.size());
56 log_info << "Start size: " << total_size;
57
58 TestKey tk0(tk_ver, WSREP_KEY_SHARED, false, "a0");
59 kso.append(tk0());
60 ck_assert(kso.count() == 1);
61
62 total_size += base_size + 2 + 1*4;
63 total_size = GU_ALIGN(total_size, alignment);
64 ck_assert_msg(total_size == kso.size(), "Size: %zu, expected: %zu",
65 kso.size(), total_size);
66
67 kso.append(tk0());
68 ck_assert(kso.count() == 1);
69
70 ck_assert_msg(total_size == kso.size(), "Size: %zu, expected: %zu",
71 kso.size(), total_size);
72
73 TestKey tk1(tk_ver, WSREP_KEY_SHARED, true, "a0", "a1", "a2");
74 mark_point();
75 kso.append(tk1());
76 ck_assert_msg(kso.count() == 3, "key count: expected 3, got %d",
77 kso.count());
78
79 total_size += base_size + 2 + 2*4;
80 total_size = GU_ALIGN(total_size, alignment);
81 total_size += base_size + 2 + 3*4;
82 total_size = GU_ALIGN(total_size, alignment);
83 ck_assert_msg(total_size == kso.size(), "Size: %zu, expected: %zu",
84 kso.size(), total_size);
85
86 TestKey tk2(tk_ver, WSREP_KEY_EXCLUSIVE, false, "a0", "a1", "b2");
87 kso.append(tk2());
88 ck_assert_msg(kso.count() == 4, "key count: expected 4, got %d",
89 kso.count());
90
91 total_size += base_size + 2 + 3*4;
92 total_size = GU_ALIGN(total_size, alignment);
93 ck_assert_msg(total_size == kso.size(), "Size: %zu, expected: %zu",
94 kso.size(), total_size);
95
96 /* this should update a sronger version of "a2" */
97 TestKey tk2_(tk_ver, WSREP_KEY_SEMI, false, "a0", "a1", "a2");
98 kso.append(tk2_());
99 ck_assert_msg(kso.count() == 5, "key count: expected 5, got %d",
100 kso.count());
101
102 total_size += base_size + 2 + 3*4;
103 total_size = GU_ALIGN(total_size, alignment);
104 ck_assert_msg(total_size == kso.size(), "Size: %zu, expected: %zu",
105 kso.size(), total_size);
106
107 /* it is a duplicate, but it should add an exclusive verision of the key */
108 TestKey tk3(tk_ver, WSREP_KEY_EXCLUSIVE, true, "a0", "a1");
109 log_info << "######## Appending exclusive duplicate tk3: begin";
110 kso.append(tk3());
111 log_info << "######## Appending exclusive duplicate tk3: end";
112 ck_assert_msg(kso.count() == 6, "key count: expected 6, got %d",
113 kso.count());
114
115 total_size += base_size + 2 + 2*4;
116 total_size = GU_ALIGN(total_size, alignment);
117 ck_assert_msg(total_size == kso.size(), "Size: %zu, expected: %zu",
118 kso.size(), total_size);
119
120 /* tk3 should make it impossible to add anything past a0:a1 */
121 TestKey tk4(tk_ver, WSREP_KEY_EXCLUSIVE, false, "a0", "a1", "c2");
122 log_info << "######## Appending exclusive duplicate tk4: begin";
123 kso.append(tk4());
124 log_info << "######## Appending exclusive duplicate tk4: end";
125 ck_assert_msg(kso.count() == 6, "key count: expected 6, got %d",
126 kso.count());
127
128 ck_assert_msg(total_size == kso.size(), "Size: %zu, expected: %zu",
129 kso.size(), total_size);
130
131 /* adding shared key should have no effect */
132 TestKey tk5(tk_ver, WSREP_KEY_SHARED, true, "a0", "a1");
133 kso.append(tk5());
134 ck_assert_msg(kso.count() == 6, "key count: expected 6, got %d",
135 kso.count());
136
137 ck_assert_msg(total_size == kso.size(), "Size: %zu, expected: %zu",
138 kso.size(), total_size);
139
140 /* adding semi key should have no effect */
141 TestKey tk5_(tk_ver, WSREP_KEY_SHARED, true, "a0", "a1");
142 kso.append(tk5_());
143 ck_assert_msg(kso.count() == 6, "key count: expected 6, got %d",
144 kso.count());
145
146 ck_assert_msg(total_size == kso.size(), "Size: %zu, expected: %zu",
147 kso.size(), total_size);
148
149 /* tk5 should not make any changes */
150 TestKey tk6(tk_ver, WSREP_KEY_EXCLUSIVE, false, "a0", "a1", "c2");
151 kso.append(tk6());
152 ck_assert_msg(kso.count() == 6, "key count: expected 6, got %d",
153 kso.count());
154
155 ck_assert_msg(total_size == kso.size(), "Size: %zu, expected: %zu",
156 kso.size(), total_size);
157
158 /* a0:b1:... should still be possible, should add 2 keys: b1 and c2 */
159 TestKey tk7(tk_ver, WSREP_KEY_SEMI, true, "a0", "b1", "c2");
160 kso.append(tk7());
161 ck_assert_msg(kso.count() == 8, "key count: expected 8, got %d",
162 kso.count());
163
164 total_size += base_size + 2 + 2*4;
165 total_size = GU_ALIGN(total_size, alignment);
166 total_size += base_size + 2 + 3*4;
167 total_size = GU_ALIGN(total_size, alignment);
168 ck_assert_msg(total_size == kso.size(), "Size: %zu, expected: %zu",
169 kso.size(), total_size);
170
171 /* make sure a0:b1:b2 is possible despite we have a0:a1:b2 already
172 * (should be no collision on b2) */
173 TestKey tk8(tk_ver, WSREP_KEY_SEMI, false, "a0", "b1", "b2");
174 kso.append(tk8());
175 ck_assert_msg(kso.count() == 9, "key count: expected 9, got %d",
176 kso.count());
177
178 total_size += base_size + 2 + 3*4;
179 total_size = GU_ALIGN(total_size, alignment);
180 ck_assert_msg(total_size == kso.size(), "Size: %zu, expected: %zu",
181 kso.size(), total_size);
182
183 int expected_count(kso.count());
184 TestKey tk8_(tk_ver, WSREP_KEY_EXCLUSIVE, false, "a0", "b1", "b2");
185 kso.append(tk8_());
186 if (3 == ws_ver)
187 {
188 /* version 3 does not distinguish SEMI and EXCLUSIVE,
189 the key should be ignored */
190 }
191 else if (4 == ws_ver)
192 {
193 /* in verson 4 EXCLUSIVE is a stronger key than SEMI - should be added
194 to the set */
195
196 expected_count++;
197 total_size += base_size + 2 + 3*4;
198 total_size = GU_ALIGN(total_size, alignment);
199 }
200 else abort();
201
202 ck_assert_msg(kso.count() == expected_count,"key count: expected %d, got %d",
203 expected_count, kso.count());
204 ck_assert_msg(total_size == kso.size(), "Size: %zu, expected: %zu",
205 kso.size(), total_size);
206
207 log_info << "size before huge key: " << total_size;
208
209 char huge_key[2048];
210 memset (huge_key, 'x', sizeof(huge_key));
211 huge_key[ sizeof(huge_key) - 1 ] = 0;
212 TestKey tk9(tk_ver, WSREP_KEY_EXCLUSIVE, false, huge_key, huge_key,huge_key);
213 kso.append(tk9());
214 expected_count += 3;
215 ck_assert_msg(kso.count() == expected_count, "key count: expected %d, got %d",
216 expected_count, kso.count());
217
218 total_size += base_size + 2 + 1*256;
219 total_size = GU_ALIGN(total_size, alignment);
220 total_size += base_size + 2 + 2*256;
221 total_size = GU_ALIGN(total_size, alignment);
222 total_size += base_size + 2 + 3*256;
223 total_size = GU_ALIGN(total_size, alignment);
224 ck_assert_msg(total_size == kso.size(), "Size: %zu, expected: %zu",
225 kso.size(), total_size);
226
227 log_info << "End size: " << kso.size();
228
229 KeySetOut::GatherVector out;
230 out->reserve(kso.page_count());
231 size_t const out_size(kso.gather(out));
232
233 log_info << "Gather size: " << out_size << ", buf count: " << out->size();
234 ck_assert_msg(0 == out_size % alignment, "out size not aligned by %zd",
235 out_size % alignment);
236
237 std::vector<gu::byte_t> in;
238 in.reserve(out_size);
239 for (size_t i(0); i < out->size(); ++i)
240 {
241 const gu::byte_t* ptr(reinterpret_cast<const gu::byte_t*>(out[i].ptr));
242 in.insert (in.end(), ptr, ptr + out[i].size);
243 }
244
245 ck_assert(in.size() == out_size);
246
247 KeySetIn ksi (kso.version(), in.data(), in.size());
248
249 ck_assert_msg(ksi.count() == kso.count(),
250 "Received keys: %d, expected: %d", ksi.count(), kso.count());
251 ck_assert_msg(ksi.size() == kso.size(),
252 "Received size: %zu, expected: %zu", ksi.size(), kso.size());
253
254 try
255 {
256 ksi.checksum();
257 }
258 catch (std::exception& e)
259 {
260 ck_abort_msg("%s", e.what());
261 }
262
263 int shared(0); // to stiffle clang complaints about unused variables
264
265 int const P_SHARED(KeySet::KeyPart::prefix(WSREP_KEY_SHARED, ws_ver));
266
267 for (int i(0); i < ksi.count(); ++i)
268 {
269 KeySet::KeyPart kp(ksi.next());
270 shared += (kp.prefix() == P_SHARED);
271 }
272
273 KeySetIn ksi_empty;
274
275 ck_assert_msg(ksi_empty.count() == 0,
276 "Received keys: %d, expected: %d", ksi_empty.count(), 0);
277 ck_assert_msg(ksi_empty.size() == 0,
278 "Received size: %zu, expected: %d", ksi_empty.size(), 0);
279
280 ksi_empty.init (kso.version(), in.data(), in.size());
281
282 ck_assert_msg(ksi_empty.count() == kso.count(),
283 "Received keys: %d, expected: %d",
284 ksi_empty.count(),kso.count());
285 ck_assert_msg(ksi_empty.size() == kso.size(),
286 "Received size: %zu, expected: %zu",
287 ksi_empty.size(), kso.size());
288
289 try
290 {
291 ksi_empty.checksum();
292 }
293 catch (std::exception& e)
294 {
295 ck_abort_msg("%s", e.what());
296 }
297
298 for (int i(0); i < ksi_empty.count(); ++i)
299 {
300 KeySet::KeyPart kp(ksi_empty.next());
301 shared += (kp.prefix() == P_SHARED);
302 }
303
304 ksi_empty.rewind();
305
306 for (int i(0); i < ksi_empty.count(); ++i)
307 {
308 KeySet::KeyPart kp(ksi_empty.next());
309 shared += (kp.prefix() == P_SHARED);
310 }
311
312 ck_assert(0 != shared);
313 }
314
315 #ifndef GALERA_ONLY_ALIGNED
START_TEST(ver1_3)316 START_TEST (ver1_3)
317 {
318 test_ver(gu::RecordSet::VER1, 3);
319 }
320 END_TEST
321 #endif /* GALERA_ONLY_ALIGNED */
322
START_TEST(ver2_3)323 START_TEST (ver2_3)
324 {
325 test_ver(gu::RecordSet::VER2, 3);
326 }
327 END_TEST
328
START_TEST(ver2_4)329 START_TEST (ver2_4)
330 {
331 test_ver(gu::RecordSet::VER2, 4);
332 }
333 END_TEST
334
key_set_suite()335 Suite* key_set_suite ()
336 {
337 TCase* t = tcase_create ("KeySet");
338 #ifndef GALERA_ONLY_ALIGNED
339 tcase_add_test (t, ver1_3);
340 #endif
341 tcase_add_test (t, ver2_3);
342 tcase_add_test (t, ver2_4);
343 tcase_set_timeout(t, 60);
344
345 Suite* s = suite_create ("KeySet");
346 suite_add_tcase (s, t);
347
348 return s;
349 }
350