1 // Copyright (C) 2007-2020 Codership Oy <info@codership.com>
2 
3 // $Id$
4 
5 #define GCS_STATE_MSG_ACCESS
6 #include "../gcs_state_msg.hpp"
7 
8 #include "gcs_state_msg_test.hpp" // must be included last
9 #include "gu_inttypes.hpp"
10 
11 static int const QUORUM_VERSION = 6;
12 
START_TEST(gcs_state_msg_test_basic)13 START_TEST (gcs_state_msg_test_basic)
14 {
15     ssize_t send_len, ret;
16     gu_uuid_t    state_uuid;
17     gu_uuid_t    group_uuid;
18     gu_uuid_t    prim_uuid;
19     gcs_state_msg_t* send_state;
20     gcs_state_msg_t* recv_state;
21 
22     gu_uuid_generate (&state_uuid, NULL, 0);
23     gu_uuid_generate (&group_uuid, NULL, 0);
24     gu_uuid_generate (&prim_uuid,  NULL, 0);
25 
26     gcs_seqno_t const prim_seqno(457);
27     gcs_seqno_t const received(3456);
28     gcs_seqno_t const cached(2345);
29     gcs_seqno_t const last_applied(3450);
30     gcs_seqno_t const vote_seqno(3449);
31     int64_t     const vote_res(0x1244567879012345ULL);
32     int         const vote_policy(0);
33     int         const prim_joined(5);
34     gcs_node_state_t const prim_state(GCS_NODE_STATE_JOINED);
35     gcs_node_state_t const current_state(GCS_NODE_STATE_NON_PRIM);
36     const char* const name("MyName");
37     const char* const inc_addr("192.168.0.1:2345");
38     int         const gcs_proto_ver(2);
39     int         const repl_proto_ver(1);
40     int         const appl_proto_ver(2);
41     int         const prim_gcs_ver(0);
42     int         const prim_repl_ver(1);
43     int         const prim_appl_ver(1);
44     int         const desync_count(0);
45     int         const flags(GCS_STATE_FREP);
46 
47     send_state = gcs_state_msg_create (&state_uuid,
48                                        &group_uuid,
49                                        &prim_uuid,
50                                        prim_seqno,
51                                        received,      // last received seqno
52                                        cached,        // last cached seqno
53                                        last_applied,  // last applied
54                                        vote_seqno,    // last vote seqno
55                                        vote_res,      // last vote result
56                                        vote_policy,   // voting protocol
57                                        prim_joined,   // prim_joined
58                                        prim_state,    // prim_state
59                                        current_state,  // current_state
60                                        name,           // name
61                                        inc_addr,       // inc_addr
62                                        gcs_proto_ver,  // gcs_proto_ver
63                                        repl_proto_ver, // repl_proto_ver
64                                        appl_proto_ver, // appl_proto_ver
65                                        prim_gcs_ver,   // prim_gcs_ver
66                                        prim_repl_ver,  // prim_repl_ver
67                                        prim_appl_ver,  // prim_appl_ver
68                                        desync_count,   // desync_count
69                                        flags           // flags
70         );
71 
72     ck_assert(NULL != send_state);
73 
74     ck_assert(send_state->flags          == flags);
75     ck_assert(send_state->gcs_proto_ver  == gcs_proto_ver);
76     ck_assert(send_state->repl_proto_ver == repl_proto_ver);
77     ck_assert(send_state->appl_proto_ver == appl_proto_ver);
78     ck_assert_msg(send_state->received   == received,
79                   "Last received seqno: sent %" PRId64 ", recv %" PRId64,
80                   send_state->received, received);
81     ck_assert_msg(send_state->cached     == cached,
82                   "Last cached seqno: sent %" PRId64 ", recv %" PRId64,
83                   send_state->cached, cached);
84     ck_assert(send_state->prim_seqno    == prim_seqno);
85     ck_assert(send_state->current_state == current_state);
86     ck_assert(send_state->prim_state    == prim_state);
87     ck_assert(send_state->prim_joined   == prim_joined);
88     ck_assert(!gu_uuid_compare (&send_state->state_uuid, &state_uuid));
89     ck_assert(!gu_uuid_compare (&send_state->group_uuid, &group_uuid));
90     ck_assert(!gu_uuid_compare (&send_state->prim_uuid,  &prim_uuid));
91     ck_assert(!strcmp(send_state->name,     name));
92     ck_assert(!strcmp(send_state->inc_addr, inc_addr));
93 
94     {
95         size_t str_len = 1024;
96         char   send_str[str_len];
97         ck_assert(gcs_state_msg_snprintf(send_str, str_len, send_state) > 0);
98     }
99 
100     //v1-2
101     ck_assert(send_state->appl_proto_ver == appl_proto_ver);
102     //v3
103     ck_assert(send_state->cached         == cached);
104     //v4
105     ck_assert(send_state->desync_count   == desync_count);
106     //v5
107     ck_assert(send_state->last_applied   == last_applied);
108     ck_assert(send_state->vote_seqno     == vote_seqno);
109     ck_assert(send_state->vote_res       == vote_res);
110     ck_assert(send_state->vote_policy    == vote_policy);
111 
112     send_len = gcs_state_msg_len (send_state);
113     ck_assert_msg(send_len >= 0, "gcs_state_msg_len() returned %zd (%s)",
114                   send_len, strerror (-send_len));
115     {
116         uint8_t send_buf[send_len];
117 
118         ret = gcs_state_msg_write (send_buf, send_state);
119         ck_assert_msg(ret == send_len, "Return value does not match send_len: "
120                       "expected %zd, got %zd", send_len, ret);
121 
122         recv_state = gcs_state_msg_read (send_buf, send_len);
123         ck_assert(NULL != recv_state);
124     }
125 
126     ck_assert(send_state->flags          == recv_state->flags);
127     ck_assert(send_state->gcs_proto_ver  == recv_state->gcs_proto_ver);
128     ck_assert(send_state->repl_proto_ver == recv_state->repl_proto_ver);
129     ck_assert_msg(recv_state->repl_proto_ver == 1, "repl_proto_ver: %d",
130                   recv_state->repl_proto_ver);
131     ck_assert(send_state->appl_proto_ver == recv_state->appl_proto_ver);
132     ck_assert_msg(recv_state->appl_proto_ver == 2, "appl_proto_ver: %d",
133                   recv_state->appl_proto_ver);
134     ck_assert(send_state->prim_gcs_ver  == recv_state->prim_gcs_ver);
135     ck_assert_msg(recv_state->prim_gcs_ver  == 0, "prim_gcs_ver: %d",
136                   recv_state->prim_appl_ver);
137     ck_assert(send_state->prim_repl_ver == recv_state->prim_repl_ver);
138     ck_assert_msg(recv_state->prim_repl_ver == 1, "prim_repl_ver: %d",
139                   recv_state->prim_appl_ver);
140     ck_assert(send_state->prim_appl_ver == recv_state->prim_appl_ver);
141     ck_assert_msg(recv_state->prim_appl_ver == 1, "prim_appl_ver: %d",
142                   recv_state->prim_appl_ver);
143     ck_assert_msg(send_state->received       == recv_state->received,
144                   "Last received seqno: sent %" PRId64 " , recv %" PRId64,
145                   send_state->received, recv_state->received);
146     ck_assert_msg(send_state->cached         == recv_state->cached,
147                   "Last cached seqno: sent %" PRId64 ", recv %" PRId64,
148                   send_state->cached, recv_state->cached);
149     ck_assert(send_state->prim_seqno    == recv_state->prim_seqno);
150     ck_assert(send_state->current_state == recv_state->current_state);
151     ck_assert(send_state->prim_state    == recv_state->prim_state);
152     ck_assert(send_state->prim_joined   == recv_state->prim_joined);
153     ck_assert(!gu_uuid_compare(&recv_state->state_uuid, &state_uuid));
154     ck_assert(!gu_uuid_compare(&recv_state->group_uuid, &group_uuid));
155     ck_assert(!gu_uuid_compare(&recv_state->prim_uuid,  &prim_uuid));
156     ck_assert(!strcmp(send_state->name,     recv_state->name));
157     ck_assert(!strcmp(send_state->inc_addr, recv_state->inc_addr));
158 
159     {
160         size_t str_len = 1024;
161         char   str[str_len];
162 
163         ck_assert(gcs_state_msg_snprintf(str, str_len, send_state) > 0);
164         ck_assert(gcs_state_msg_snprintf(str, str_len, recv_state) > 0);
165     }
166 
167     //v1-2
168     ck_assert(send_state->appl_proto_ver == recv_state->appl_proto_ver);
169     //v3
170     ck_assert(send_state->cached         == recv_state->cached);
171     //v4
172     ck_assert(send_state->desync_count   == recv_state->desync_count);
173     //v5
174     ck_assert(send_state->last_applied   == recv_state->last_applied);
175     ck_assert(send_state->vote_seqno     == recv_state->vote_seqno);
176     ck_assert(send_state->vote_res       == recv_state->vote_res);
177     ck_assert(send_state->vote_policy    == recv_state->vote_policy);
178 
179     gcs_state_msg_destroy (send_state);
180     gcs_state_msg_destroy (recv_state);
181 }
182 END_TEST
183 
START_TEST(gcs_state_msg_test_quorum_inherit)184 START_TEST (gcs_state_msg_test_quorum_inherit)
185 {
186     gcs_state_msg_t* st[3] = { NULL, };
187 
188     gu_uuid_t state_uuid;
189     gu_uuid_t group1_uuid, group2_uuid;
190     gu_uuid_t prim1_uuid, prim2_uuid;
191 
192     gu_uuid_generate (&state_uuid,  NULL, 0);
193     gu_uuid_generate (&group1_uuid, NULL, 0);
194     gu_uuid_generate (&group2_uuid, NULL, 0);
195     gu_uuid_generate (&prim1_uuid,  NULL, 0);
196     gu_uuid_generate (&prim2_uuid,  NULL, 0);
197 
198     gcs_seqno_t prim1_seqno = 123;
199     gcs_seqno_t prim2_seqno = 834;
200 
201     gcs_seqno_t act1_seqno = 345;
202     gcs_seqno_t act2_seqno = 239472508908LL;
203 
204     gcs_state_quorum_t quorum;
205 
206     mark_point();
207 
208     /* First just nodes from different groups and configurations, none JOINED */
209     st[0] = gcs_state_msg_create (&state_uuid, &group2_uuid, &prim2_uuid,
210                                   prim2_seqno - 1, act2_seqno - 1, act2_seqno -1,
211                                   act2_seqno - 1, GCS_SEQNO_ILL, 0,
212                                   GCS_VOTE_ZERO_WINS, 5,
213                                   GCS_NODE_STATE_PRIM, GCS_NODE_STATE_PRIM,
214                                   "node0", "",
215                                   0, 1, 1, 0, 0, 0,
216                                   0, 0);
217     ck_assert(NULL != st[0]);
218 
219     st[1] = gcs_state_msg_create (&state_uuid, &group1_uuid, &prim1_uuid,
220                                   prim1_seqno, act1_seqno, act1_seqno - 1,
221                                   act1_seqno - 1, GCS_SEQNO_ILL, 0,
222                                   GCS_VOTE_ZERO_WINS, 3,
223                                   GCS_NODE_STATE_PRIM, GCS_NODE_STATE_PRIM,
224                                   "node1", "",
225                                   0, 1, 0, 0, 0, 0,
226                                   0, 0);
227     ck_assert(NULL != st[1]);
228 
229     st[2] = gcs_state_msg_create (&state_uuid, &group2_uuid, &prim2_uuid,
230                                   prim2_seqno, act2_seqno, act2_seqno - 2,
231                                   act2_seqno - 1, GCS_SEQNO_ILL, 0,
232                                   GCS_VOTE_ZERO_WINS, 5,
233                                   GCS_NODE_STATE_PRIM, GCS_NODE_STATE_PRIM,
234                                   "node2", "",
235                                   0, 1, 1, 0, 0, 0,
236                                   0, 1);
237     ck_assert(NULL != st[2]);
238 
239     gu_info ("                  Inherited 1");
240     int ret = gcs_state_msg_get_quorum ((const gcs_state_msg_t**)st,
241                                         sizeof(st)/sizeof(gcs_state_msg_t*),
242                                         &quorum);
243     ck_assert(0 == ret);
244     ck_assert(QUORUM_VERSION == quorum.version);
245     ck_assert(false == quorum.primary);
246     ck_assert(0 == gu_uuid_compare(&quorum.group_uuid, &GU_UUID_NIL));
247     ck_assert(GCS_SEQNO_ILL == quorum.act_id);
248     ck_assert(GCS_SEQNO_ILL == quorum.conf_id);
249     ck_assert(-1 == quorum.gcs_proto_ver);
250     ck_assert(-1 == quorum.repl_proto_ver);
251     ck_assert(-1 == quorum.appl_proto_ver);
252 
253     /* now make node1 inherit PC */
254     gcs_state_msg_destroy (st[1]);
255     st[1] = gcs_state_msg_create (&state_uuid, &group1_uuid, &prim1_uuid,
256                                   prim1_seqno, act1_seqno, act1_seqno - 3,
257                                   act1_seqno - 2, GCS_SEQNO_ILL, 0,
258                                   GCS_VOTE_ZERO_WINS, 3,
259                                   GCS_NODE_STATE_JOINED, GCS_NODE_STATE_DONOR,
260                                   "node1", "",
261                                   0, 1, 0, 0, 0, 0,
262                                   0, 0);
263     ck_assert(NULL != st[1]);
264 
265     gu_info ("                  Inherited 2");
266     ret = gcs_state_msg_get_quorum ((const gcs_state_msg_t**)st,
267                                     sizeof(st)/sizeof(gcs_state_msg_t*),
268                                     &quorum);
269     ck_assert(0 == ret);
270     ck_assert(QUORUM_VERSION == quorum.version);
271     ck_assert(true == quorum.primary);
272     ck_assert(0 == gu_uuid_compare(&quorum.group_uuid, &group1_uuid));
273     ck_assert(act1_seqno  == quorum.act_id);
274     ck_assert(prim1_seqno == quorum.conf_id);
275     ck_assert(0 == quorum.gcs_proto_ver);
276     ck_assert(1 == quorum.repl_proto_ver);
277     ck_assert(0 == quorum.appl_proto_ver);
278 
279     /* now make node0 inherit PC (should yield conflicting uuids) */
280     gcs_state_msg_destroy (st[0]);
281     st[0] = gcs_state_msg_create (&state_uuid, &group2_uuid, &prim2_uuid,
282                                   prim2_seqno - 1, act2_seqno - 1, -1,
283                                   act2_seqno - 1, GCS_SEQNO_ILL, 0,
284                                   GCS_VOTE_ZERO_WINS, 5,
285                                   GCS_NODE_STATE_SYNCED, GCS_NODE_STATE_SYNCED,
286                                   "node0", "",
287                                   0, 1, 1, 0, 0, 0,
288                                   0, 0);
289     ck_assert(NULL != st[0]);
290 
291     gu_info ("                  Inherited 3");
292     ret = gcs_state_msg_get_quorum ((const gcs_state_msg_t**)st,
293                                     sizeof(st)/sizeof(gcs_state_msg_t*),
294                                     &quorum);
295     ck_assert(0 == ret);
296     ck_assert(QUORUM_VERSION == quorum.version);
297     ck_assert(false == quorum.primary);
298     ck_assert(0 == gu_uuid_compare(&quorum.group_uuid, &GU_UUID_NIL));
299     ck_assert(GCS_SEQNO_ILL == quorum.act_id);
300     ck_assert(GCS_SEQNO_ILL == quorum.conf_id);
301     ck_assert(-1 == quorum.gcs_proto_ver);
302     ck_assert(-1 == quorum.repl_proto_ver);
303     ck_assert(-1 == quorum.appl_proto_ver);
304 
305     /* now make node1 non-joined again: group2 should win */
306     gcs_state_msg_destroy (st[1]);
307     st[1] = gcs_state_msg_create (&state_uuid, &group1_uuid, &prim1_uuid,
308                                   prim1_seqno, act1_seqno, act1_seqno -3,
309                                   act1_seqno - 1, GCS_SEQNO_ILL, 0,
310                                   GCS_VOTE_ZERO_WINS, 3,
311                                   GCS_NODE_STATE_JOINED, GCS_NODE_STATE_PRIM,
312                                   "node1", "",
313                                   0, 1, 0, 0, 0, 0,
314                                   0, 0);
315     ck_assert(NULL != st[1]);
316 
317     gu_info ("                  Inherited 4");
318     ret = gcs_state_msg_get_quorum ((const gcs_state_msg_t**)st,
319                                     sizeof(st)/sizeof(gcs_state_msg_t*),
320                                     &quorum);
321     ck_assert(0 == ret);
322     ck_assert(QUORUM_VERSION == quorum.version);
323     ck_assert(true == quorum.primary);
324     ck_assert(0 == gu_uuid_compare(&quorum.group_uuid, &group2_uuid));
325     ck_assert(act2_seqno - 1 == quorum.act_id);
326     ck_assert(prim2_seqno - 1 == quorum.conf_id);
327     ck_assert(0 == quorum.gcs_proto_ver);
328     ck_assert(1 == quorum.repl_proto_ver);
329     ck_assert(0 == quorum.appl_proto_ver);
330 
331     /* now make node2 joined: it should become a representative */
332     gcs_state_msg_destroy (st[2]);
333     st[2] = gcs_state_msg_create (&state_uuid, &group2_uuid, &prim2_uuid,
334                                   prim2_seqno, act2_seqno, act2_seqno - 2,
335                                   act2_seqno - 1, GCS_SEQNO_ILL, 0,
336                                   GCS_VOTE_ZERO_WINS, 5,
337                                   GCS_NODE_STATE_SYNCED, GCS_NODE_STATE_SYNCED,
338                                   "node2", "",
339                                   0, 1, 1, 0, 1, 0,
340                                   0, 0);
341     ck_assert(NULL != st[2]);
342 
343     gu_info ("                  Inherited 5");
344     ret = gcs_state_msg_get_quorum ((const gcs_state_msg_t**)st,
345                                     sizeof(st)/sizeof(gcs_state_msg_t*),
346                                     &quorum);
347     ck_assert(0 == ret);
348     ck_assert(QUORUM_VERSION == quorum.version);
349     ck_assert(true == quorum.primary);
350     ck_assert(0 == gu_uuid_compare(&quorum.group_uuid, &group2_uuid));
351     ck_assert(act2_seqno == quorum.act_id);
352     ck_assert(prim2_seqno == quorum.conf_id);
353     ck_assert(0 == quorum.gcs_proto_ver);
354     ck_assert(1 == quorum.repl_proto_ver);
355     ck_assert(0 == quorum.appl_proto_ver);
356 
357     gcs_state_msg_destroy (st[0]);
358     gcs_state_msg_destroy (st[1]);
359     gcs_state_msg_destroy (st[2]);
360 }
361 END_TEST
362 
START_TEST(gcs_state_msg_test_quorum_remerge)363 START_TEST (gcs_state_msg_test_quorum_remerge)
364 {
365     gcs_state_msg_t* st[3] = { NULL, };
366 
367     gu_uuid_t state_uuid;
368     gu_uuid_t group1_uuid, group2_uuid;
369     gu_uuid_t prim0_uuid, prim1_uuid, prim2_uuid;
370 
371     gu_uuid_generate (&state_uuid,  NULL, 0);
372     gu_uuid_generate (&group1_uuid, NULL, 0);
373     gu_uuid_generate (&group2_uuid, NULL, 0);
374     gu_uuid_generate (&prim0_uuid,  NULL, 0);
375     gu_uuid_generate (&prim1_uuid,  NULL, 0);
376     gu_uuid_generate (&prim2_uuid,  NULL, 0);
377 
378     gcs_seqno_t prim1_seqno = 123;
379     gcs_seqno_t prim2_seqno = 834;
380 
381     gcs_seqno_t act1_seqno = 345;
382     gcs_seqno_t act2_seqno = 239472508908LL;
383 
384     gcs_state_quorum_t quorum;
385 
386     mark_point();
387 
388     /* First just nodes from different groups and configurations, none JOINED */
389     st[0] = gcs_state_msg_create (&state_uuid, &group2_uuid, &prim0_uuid,
390                                   prim2_seqno - 1, act2_seqno - 1,act2_seqno -2,
391                                   act2_seqno - 1, GCS_SEQNO_ILL, 0,
392                                   GCS_VOTE_ZERO_WINS, 5,
393                                   GCS_NODE_STATE_JOINER,GCS_NODE_STATE_NON_PRIM,
394                                   "node0", "",
395                                   0, 1, 1, 0, 0, 0,
396                                   0, 0);
397     ck_assert(NULL != st[0]);
398 
399     st[1] = gcs_state_msg_create (&state_uuid, &group1_uuid, &prim1_uuid,
400                                   prim1_seqno, act1_seqno, act1_seqno - 3,
401                                   act1_seqno - 2, GCS_SEQNO_ILL, 0,
402                                   GCS_VOTE_ZERO_WINS, 3,
403                                   GCS_NODE_STATE_JOINER,GCS_NODE_STATE_NON_PRIM,
404                                   "node1", "",
405                                   0, 1, 0, 0, 0, 0,
406                                   0, 0);
407     ck_assert(NULL != st[1]);
408 
409     st[2] = gcs_state_msg_create (&state_uuid, &group2_uuid, &prim2_uuid,
410                                   prim2_seqno, act2_seqno, -1,
411                                   act2_seqno - 1, GCS_SEQNO_ILL, 0,
412                                   GCS_VOTE_ZERO_WINS, 5,
413                                   GCS_NODE_STATE_JOINER,GCS_NODE_STATE_NON_PRIM,
414                                   "node2", "",
415                                   0, 1, 1, 0, 0, 0,
416                                   0, 1);
417     ck_assert(NULL != st[2]);
418 
419     gu_info ("                  Remerged 1");
420     int ret = gcs_state_msg_get_quorum ((const gcs_state_msg_t**)st,
421                                         sizeof(st)/sizeof(gcs_state_msg_t*),
422                                         &quorum);
423     ck_assert(0 == ret);
424     ck_assert(QUORUM_VERSION == quorum.version);
425     ck_assert(false == quorum.primary);
426     ck_assert(0 == gu_uuid_compare(&quorum.group_uuid, &GU_UUID_NIL));
427     ck_assert(GCS_SEQNO_ILL == quorum.act_id);
428     ck_assert(GCS_SEQNO_ILL == quorum.conf_id);
429     ck_assert(-1 == quorum.gcs_proto_ver);
430     ck_assert(-1 == quorum.repl_proto_ver);
431     ck_assert(-1 == quorum.appl_proto_ver);
432 
433     /* Now make node0 to be joined at least once */
434     gcs_state_msg_destroy (st[0]);
435     st[0] = gcs_state_msg_create (&state_uuid, &group2_uuid, &prim0_uuid,
436                                   prim2_seqno - 1, act2_seqno - 1, -1,
437                                   act2_seqno - 1, GCS_SEQNO_ILL, 0,
438                                   GCS_VOTE_ZERO_WINS, 5,
439                                   GCS_NODE_STATE_DONOR, GCS_NODE_STATE_NON_PRIM,
440                                   "node0", "",
441                                   0, 1, 1, 0, 0, 0,
442                                   3, 0);
443     ck_assert(NULL != st[0]);
444     ck_assert(3 == gcs_state_msg_get_desync_count(st[0]));
445 
446     gu_info ("                  Remerged 2");
447     ret = gcs_state_msg_get_quorum ((const gcs_state_msg_t**)st,
448                                     sizeof(st)/sizeof(gcs_state_msg_t*),
449                                     &quorum);
450     ck_assert(0 == ret);
451     ck_assert(QUORUM_VERSION == quorum.version);
452     ck_assert(true == quorum.primary);
453     ck_assert(0 == gu_uuid_compare(&quorum.group_uuid, &group2_uuid));
454     ck_assert(act2_seqno - 1 == quorum.act_id);
455     ck_assert(prim2_seqno - 1 == quorum.conf_id);
456     ck_assert(0 == quorum.gcs_proto_ver);
457     ck_assert(1 == quorum.repl_proto_ver);
458     ck_assert(0 == quorum.appl_proto_ver);
459 
460     /* Now make node2 to be joined too */
461     gcs_state_msg_destroy (st[2]);
462     st[2] = gcs_state_msg_create (&state_uuid, &group2_uuid, &prim2_uuid,
463                                   prim2_seqno, act2_seqno, act2_seqno - 3,
464                                   act2_seqno - 1, GCS_SEQNO_ILL, 0,
465                                   GCS_VOTE_ZERO_WINS, 5,
466                                   GCS_NODE_STATE_JOINED,GCS_NODE_STATE_NON_PRIM,
467                                   "node2", "",
468                                   0, 1, 1, 0, 0, 0,
469                                   0, 1);
470     ck_assert(NULL != st[2]);
471 
472     gu_info ("                  Remerged 3");
473     ret = gcs_state_msg_get_quorum ((const gcs_state_msg_t**)st,
474                                     sizeof(st)/sizeof(gcs_state_msg_t*),
475                                     &quorum);
476     ck_assert(0 == ret);
477     ck_assert(QUORUM_VERSION == quorum.version);
478     ck_assert(true == quorum.primary);
479     ck_assert(0 == gu_uuid_compare(&quorum.group_uuid, &group2_uuid));
480     ck_assert(act2_seqno == quorum.act_id);
481     ck_assert(prim2_seqno == quorum.conf_id);
482     ck_assert(0 == quorum.gcs_proto_ver);
483     ck_assert(1 == quorum.repl_proto_ver);
484     ck_assert(0 == quorum.appl_proto_ver);
485 
486     /* now make node1 joined too: conflict */
487     gcs_state_msg_destroy (st[1]);
488     st[1] = gcs_state_msg_create (&state_uuid, &group1_uuid, &prim1_uuid,
489                                   prim1_seqno, act1_seqno, act1_seqno,
490                                   act1_seqno - 1, GCS_SEQNO_ILL, 0,
491                                   GCS_VOTE_ZERO_WINS, 3,
492                                   GCS_NODE_STATE_SYNCED,GCS_NODE_STATE_NON_PRIM,
493                                   "node1", "",
494                                   0, 1, 0, 0, 0, 0,
495                                   0, 0);
496     ck_assert(NULL != st[1]);
497 
498     gu_info ("                  Remerged 4");
499     ret = gcs_state_msg_get_quorum ((const gcs_state_msg_t**)st,
500                                     sizeof(st)/sizeof(gcs_state_msg_t*),
501                                     &quorum);
502     ck_assert(0 == ret);
503     ck_assert(QUORUM_VERSION == quorum.version);
504     ck_assert(false == quorum.primary);
505     ck_assert(0 == gu_uuid_compare(&quorum.group_uuid, &GU_UUID_NIL));
506     ck_assert(GCS_SEQNO_ILL == quorum.act_id);
507     ck_assert(GCS_SEQNO_ILL == quorum.conf_id);
508     ck_assert(-1 == quorum.gcs_proto_ver);
509     ck_assert(-1 == quorum.repl_proto_ver);
510     ck_assert(-1 == quorum.appl_proto_ver);
511 
512     /* now make node1 current joiner: should be ignored */
513     gcs_state_msg_destroy (st[1]);
514     st[1] = gcs_state_msg_create (&state_uuid, &group1_uuid, &prim1_uuid,
515                                   prim1_seqno, act1_seqno, act1_seqno - 2,
516                                   act1_seqno - 1, GCS_SEQNO_ILL, 0,
517                                   GCS_VOTE_ZERO_WINS, 3,
518                                   GCS_NODE_STATE_SYNCED, GCS_NODE_STATE_JOINER,
519                                   "node1", "",
520                                   0, 1, 0, 0, 0, 0,
521                                   0, 0);
522     ck_assert(NULL != st[1]);
523 
524     gu_info ("                  Remerged 5");
525     ret = gcs_state_msg_get_quorum ((const gcs_state_msg_t**)st,
526                                     sizeof(st)/sizeof(gcs_state_msg_t*),
527                                     &quorum);
528     ck_assert(0 == ret);
529     ck_assert(QUORUM_VERSION == quorum.version);
530     ck_assert(true == quorum.primary);
531     ck_assert(0 == gu_uuid_compare(&quorum.group_uuid, &group2_uuid));
532     ck_assert(act2_seqno == quorum.act_id);
533     ck_assert(prim2_seqno == quorum.conf_id);
534     ck_assert(0 == quorum.gcs_proto_ver);
535     ck_assert(1 == quorum.repl_proto_ver);
536     ck_assert(0 == quorum.appl_proto_ver);
537 
538     gcs_state_msg_destroy (st[0]);
539     gcs_state_msg_destroy (st[1]);
540     gcs_state_msg_destroy (st[2]);
541 }
542 END_TEST
543 
gcs_state_msg_test_gh24(int const gcs_proto_ver)544 void gcs_state_msg_test_gh24(int const gcs_proto_ver)
545 {
546     gcs_state_msg_t* st[7] = { NULL, };
547     gu_uuid_t state_uuid, group_uuid;
548     gu_uuid_generate(&state_uuid, NULL, 0);
549     gu_uuid_generate(&group_uuid, NULL, 0);
550     gu_uuid_t prim_uuid1, prim_uuid2;
551     gu_uuid_generate(&prim_uuid1, NULL, 0);
552     gu_uuid_generate(&prim_uuid2, NULL, 0);
553 
554     gcs_seqno_t const prim_seqno1 = 37;
555     int const prim_joined1 = 3;
556     uint8_t const vp1(0);
557     gcs_seqno_t const prim_seqno2 = 35;
558     int const prim_joined2 = 6;
559     uint8_t const vp2(2);
560     gcs_seqno_t const received = prim_seqno2;
561     gcs_seqno_t const cached = 0;
562 
563     gcs_state_quorum_t quorum;
564     // first three are 35.
565     st[0] = gcs_state_msg_create(&state_uuid, &group_uuid, &prim_uuid2,
566                                  prim_seqno2, received, cached,
567                                  received - 7, GCS_SEQNO_ILL, 0, vp2,
568                                  prim_joined2,
569                                  GCS_NODE_STATE_SYNCED,
570                                  GCS_NODE_STATE_NON_PRIM,
571                                  "home0", "",
572                                  gcs_proto_ver, 4, 2, 0, 0, 0,
573                                  0, 2);
574     ck_assert(st[0] != 0);
575     ck_assert(gcs_state_msg_vote_policy(st[0]) == vp2);
576     st[1] = gcs_state_msg_create(&state_uuid, &group_uuid, &prim_uuid2,
577                                  prim_seqno2, received, cached,
578                                  received - 11, GCS_SEQNO_ILL, 0, vp2,
579                                  prim_joined2,
580                                  GCS_NODE_STATE_SYNCED,
581                                  GCS_NODE_STATE_NON_PRIM,
582                                  "home1", "",
583                                  gcs_proto_ver, 4, 2, 0, 0, 0,
584                                  0, 2);
585     ck_assert(st[1] != 0);
586     st[2] = gcs_state_msg_create(&state_uuid, &group_uuid, &prim_uuid2,
587                                  prim_seqno2, received, cached,
588                                  received - 5, GCS_SEQNO_ILL, 0, vp2,
589                                  prim_joined2,
590                                  GCS_NODE_STATE_SYNCED,
591                                  GCS_NODE_STATE_NON_PRIM,
592                                  "home2", "",
593                                  gcs_proto_ver, 4, 2, 0, 0, 0,
594                                  0, 2);
595     ck_assert(st[2] != 0);
596 
597     // last four are 37.
598     st[3] = gcs_state_msg_create(&state_uuid, &group_uuid, &prim_uuid1,
599                                  prim_seqno1, received, cached,
600                                  received - 8, GCS_SEQNO_ILL, 0, vp1,
601                                  prim_joined1,
602                                  GCS_NODE_STATE_SYNCED,
603                                  GCS_NODE_STATE_NON_PRIM,
604                                  "home3", "",
605                                  gcs_proto_ver, 4, 2, 0, 0, 0,
606                                  0, 3);
607     ck_assert(st[3] != 0);
608     ck_assert(gcs_state_msg_vote_policy(st[3]) == vp1);
609     st[4] = gcs_state_msg_create(&state_uuid, &group_uuid, &prim_uuid1,
610                                  prim_seqno1, received, cached,
611                                  received - 3, GCS_SEQNO_ILL, 0, vp1,
612                                  prim_joined1,
613                                  GCS_NODE_STATE_SYNCED,
614                                  GCS_NODE_STATE_NON_PRIM,
615                                  "home4", "",
616                                  gcs_proto_ver, 4, 2, 0, 0, 0,
617                                  0, 2);
618     ck_assert(st[4] != 0);
619     st[5] = gcs_state_msg_create(&state_uuid, &group_uuid, &prim_uuid1,
620                                  prim_seqno1, received, cached,
621                                  received - 10, GCS_SEQNO_ILL, 0, vp1,
622                                  prim_joined1,
623                                  GCS_NODE_STATE_SYNCED,
624                                  GCS_NODE_STATE_NON_PRIM,
625                                  "home5", "",
626                                  gcs_proto_ver, 4, 2, 0, 0, 0,
627                                  0, 2);
628     ck_assert(st[5] != 0);
629     st[6] = gcs_state_msg_create(&state_uuid, &group_uuid, &prim_uuid1,
630                                  prim_seqno1, received, cached,
631                                  received - 13, GCS_SEQNO_ILL, 0, vp1,
632                                  prim_joined1,
633                                  GCS_NODE_STATE_PRIM,
634                                  GCS_NODE_STATE_NON_PRIM,
635                                  "home6", "",
636                                  gcs_proto_ver, 4, 2, 0, 0, 0,
637                                  0, 2);
638     ck_assert(st[6] != 0);
639     int ret = gcs_state_msg_get_quorum((const gcs_state_msg_t**)st, 7,
640                                        &quorum);
641     ck_assert(ret == 0);
642     ck_assert(quorum.primary == true);
643     ck_assert(quorum.conf_id == prim_seqno1);
644     switch (gcs_proto_ver)
645     {
646     case 0:
647         ck_assert_msg(quorum.vote_policy == GCS_VOTE_ZERO_WINS,
648                       "found policy %d, expected %d", quorum.vote_policy,
649                       GCS_VOTE_ZERO_WINS);
650         break;
651     case 1:
652         ck_assert_msg(quorum.vote_policy == vp1,
653                       "found policy %d, expected %d", quorum.vote_policy, vp1);
654         break;
655     default:
656         ck_abort_msg("unsupported GCS protocol: %d", gcs_proto_ver);
657     }
658 
659     for(int i=0;i<7;i++) gcs_state_msg_destroy(st[i]);
660 }
661 
START_TEST(gcs_state_msg_test_gh24_0)662 START_TEST(gcs_state_msg_test_gh24_0) // also tests vote policy switch
663 {
664     gcs_state_msg_test_gh24(0);
665 }
666 END_TEST
667 
START_TEST(gcs_state_msg_test_gh24_1)668 START_TEST(gcs_state_msg_test_gh24_1) // also tests vote policy switch
669 {
670     gcs_state_msg_test_gh24(1);
671 }
672 END_TEST
673 
674 /* This test is to test that protocol downgrade is disabled with state
675  * excahnge >= v6 */
676 static void
gcs_state_msg_test_v6_upgrade(int const from_ver)677 gcs_state_msg_test_v6_upgrade(int const from_ver)
678 {
679     gcs_state_msg_t* st[3] = { NULL, };
680 
681     gu_uuid_t state_uuid;
682     gu_uuid_t group_uuid;
683     gu_uuid_t prim_uuid;
684 
685     gu_uuid_generate (&state_uuid,  NULL, 0);
686     gu_uuid_generate (&group_uuid, NULL, 0);
687     gu_uuid_generate (&prim_uuid,  NULL, 0);
688 
689     gcs_seqno_t prim_seqno = 123;
690     gcs_seqno_t act_seqno  = 345;
691 
692     gcs_state_quorum_t quorum;
693 
694     mark_point();
695 
696     /* Start with "heterogeneous" PC, where node2 is a v4 node */
697     st[0] = gcs_state_msg_create (&state_uuid, &group_uuid, &prim_uuid,
698                                   prim_seqno - 1, act_seqno - 1, act_seqno - 1,
699                                   0, 0, 0, 0,
700                                   3,
701                                   GCS_NODE_STATE_PRIM, GCS_NODE_STATE_PRIM,
702                                   "node0", "",
703                                   4, 4, 4, 0, 0, 0,
704                                   0, 0);
705     ck_assert(NULL != st[0]);
706 
707     st[1] = gcs_state_msg_create (&state_uuid, &group_uuid, &prim_uuid,
708                                   prim_seqno, act_seqno, act_seqno - 3,
709                                   0, 0, 0, 0,
710                                   3,
711                                   GCS_NODE_STATE_JOINED, GCS_NODE_STATE_JOINED,
712                                   "node1", "",
713                                   3, 3, 3, 0, 0, 0,
714                                   0, 0);
715     ck_assert(NULL != st[1]);
716 
717     st[2] = gcs_state_msg_create (&state_uuid, &group_uuid, &prim_uuid,
718                                   prim_seqno, act_seqno, act_seqno - 3,
719                                   0, 0, 0, 0,
720                                   3,
721                                   GCS_NODE_STATE_JOINED, GCS_NODE_STATE_JOINED,
722                                   "node2", "",
723                                   0, 1, 1, 0, 0, 0,
724                                   0, 0);
725     ck_assert(NULL != st[2]);
726     st[2]->version = from_ver;
727 
728     gu_info ("                  proto_ver I");
729     int
730     ret = gcs_state_msg_get_quorum ((const gcs_state_msg_t**)st,
731                                     sizeof(st)/sizeof(gcs_state_msg_t*),
732                                     &quorum);
733     ck_assert(0 == ret);
734     ck_assert(from_ver == quorum.version);
735     ck_assert(true == quorum.primary);
736     ck_assert(0 == gu_uuid_compare(&quorum.group_uuid, &group_uuid));
737     ck_assert(act_seqno  == quorum.act_id);
738     ck_assert(prim_seqno == quorum.conf_id);
739     ck_assert(0 == quorum.gcs_proto_ver);
740     ck_assert(1 == quorum.repl_proto_ver);
741     ck_assert(1 == quorum.appl_proto_ver);
742     ck_assert(GCS_VOTE_ZERO_WINS == quorum.vote_policy);
743 
744 #define UPDATE_STATE_MSG(x)                       \
745     st[x]->prim_seqno = prim_seqno;               \
746     st[x]->received   = act_seqno;                \
747     st[x]->prim_gcs_ver  = quorum.gcs_proto_ver;  \
748     st[x]->prim_repl_ver = quorum.repl_proto_ver; \
749     st[x]->prim_appl_ver = quorum.appl_proto_ver;
750 
751     /* disconnect node2: protocol versions should go up (also bump seqnos) */
752     prim_seqno++;
753     act_seqno++;
754     UPDATE_STATE_MSG(0);
755     UPDATE_STATE_MSG(1);
756     gu_info ("                  proto_ver II");
757     ret = gcs_state_msg_get_quorum ((const gcs_state_msg_t**)st,
758                                     2,
759                                     &quorum);
760     ck_assert(0 == ret);
761     ck_assert(QUORUM_VERSION == quorum.version);
762     ck_assert(true == quorum.primary);
763     ck_assert(0 == gu_uuid_compare(&quorum.group_uuid, &group_uuid));
764     ck_assert(act_seqno  == quorum.act_id);
765     ck_assert(prim_seqno == quorum.conf_id);
766     ck_assert(3 == quorum.gcs_proto_ver);
767     ck_assert(3 == quorum.repl_proto_ver);
768     ck_assert(3 == quorum.appl_proto_ver);
769     ck_assert(0 == quorum.vote_policy);
770 
771     /* reconnect node2: protocol versions should go down for backward
772      * compatibility */
773     prim_seqno++;
774     act_seqno++;
775     UPDATE_STATE_MSG(0);
776     UPDATE_STATE_MSG(1);
777     gu_info ("                  proto_ver III");
778     ret = gcs_state_msg_get_quorum ((const gcs_state_msg_t**)st,
779                                     3,
780                                     &quorum);
781     ck_assert(0 == ret);
782     ck_assert(from_ver == quorum.version);
783     ck_assert(true == quorum.primary);
784     ck_assert(0 == gu_uuid_compare(&quorum.group_uuid, &group_uuid));
785     ck_assert(act_seqno  == quorum.act_id);
786     ck_assert(prim_seqno == quorum.conf_id);
787     ck_assert(0 == quorum.gcs_proto_ver);
788     ck_assert(1 == quorum.repl_proto_ver);
789     ck_assert(1 == quorum.appl_proto_ver);
790     ck_assert(GCS_VOTE_ZERO_WINS == quorum.vote_policy);
791 
792 
793     /* disconnect node2 */
794     prim_seqno++;
795     act_seqno++;
796     UPDATE_STATE_MSG(0);
797     UPDATE_STATE_MSG(1);
798     gu_info ("                  proto_ver IV");
799     ret = gcs_state_msg_get_quorum ((const gcs_state_msg_t**)st,
800                                     2,
801                                     &quorum);
802     ck_assert(0 == ret);
803     ck_assert(QUORUM_VERSION == quorum.version);
804     ck_assert(true == quorum.primary);
805     ck_assert(0 == gu_uuid_compare(&quorum.group_uuid, &group_uuid));
806     ck_assert(act_seqno  == quorum.act_id);
807     ck_assert(prim_seqno == quorum.conf_id);
808     ck_assert(3 == quorum.gcs_proto_ver);
809     ck_assert(3 == quorum.repl_proto_ver);
810     ck_assert(3 == quorum.appl_proto_ver);
811     ck_assert(0 == quorum.vote_policy);
812 
813     /* upgrade node2 */
814     st[2]->version = QUORUM_VERSION;
815     st[2]->gcs_proto_ver  = 2;
816     st[2]->repl_proto_ver = 2;
817     st[2]->appl_proto_ver = 2;
818 
819     /* reconnect node2: this time protocol versions should stay */
820     prim_seqno++;
821     act_seqno++;
822     UPDATE_STATE_MSG(0);
823     UPDATE_STATE_MSG(1);
824     gu_info ("                  proto_ver V");
825     ret = gcs_state_msg_get_quorum ((const gcs_state_msg_t**)st,
826                                     3,
827                                     &quorum);
828     ck_assert(0 == ret);
829     ck_assert(QUORUM_VERSION == quorum.version);
830     ck_assert(true == quorum.primary);
831     ck_assert(0 == gu_uuid_compare(&quorum.group_uuid, &group_uuid));
832     ck_assert(act_seqno  == quorum.act_id);
833     ck_assert(prim_seqno == quorum.conf_id);
834     ck_assert(3 == quorum.gcs_proto_ver);
835     ck_assert(3 == quorum.repl_proto_ver);
836     ck_assert(3 == quorum.appl_proto_ver);
837     ck_assert(0 == quorum.vote_policy);
838 
839     gcs_state_msg_destroy (st[0]);
840     gcs_state_msg_destroy (st[1]);
841     gcs_state_msg_destroy (st[2]);
842 #undef UPDATE_STATE_MSG
843 }
844 
START_TEST(gcs_state_msg_test_v4v6_upgrade)845 START_TEST (gcs_state_msg_test_v4v6_upgrade)
846 {
847     gcs_state_msg_test_v6_upgrade(4);
848 }
849 END_TEST
850 
START_TEST(gcs_state_msg_test_v5v6_upgrade)851 START_TEST (gcs_state_msg_test_v5v6_upgrade)
852 {
853     gcs_state_msg_test_v6_upgrade(5);
854 }
855 END_TEST
856 
gcs_state_msg_suite(void)857 Suite *gcs_state_msg_suite(void)
858 {
859   Suite *s  = suite_create("GCS state message");
860   TCase *tc_basic   = tcase_create("gcs_state_msg_basic");
861   TCase *tc_inherit = tcase_create("gcs_state_msg_inherit");
862   TCase *tc_remerge = tcase_create("gcs_state_msg_remerge");
863   TCase *tc_proto_ver = tcase_create("gcs_state_msg_proto_ver");
864 
865   suite_add_tcase (s, tc_basic);
866   tcase_add_test  (tc_basic, gcs_state_msg_test_basic);
867 
868   suite_add_tcase (s, tc_inherit);
869   tcase_add_test  (tc_inherit, gcs_state_msg_test_quorum_inherit);
870 
871   suite_add_tcase (s, tc_remerge);
872   tcase_add_test  (tc_remerge, gcs_state_msg_test_quorum_remerge);
873   tcase_add_test  (tc_remerge, gcs_state_msg_test_gh24_0);
874   tcase_add_test  (tc_remerge, gcs_state_msg_test_gh24_1);
875 
876   suite_add_tcase (s, tc_proto_ver);
877   tcase_add_test  (tc_proto_ver, gcs_state_msg_test_v4v6_upgrade);
878   tcase_add_test  (tc_proto_ver, gcs_state_msg_test_v5v6_upgrade);
879 
880   return s;
881 }
882