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