1 /* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 #include <stdlib.h>
24 #include <assert.h>
25
26 #include "x_platform.h"
27
28 #include "xcom_common.h"
29 #include "xcom_vp.h"
30 #include "node_list.h"
31 #include "simset.h"
32 #include "task.h"
33 #include "server_struct.h"
34 #include "xcom_detector.h"
35 #include "site_struct.h"
36 #include "xcom_base.h"
37 #include "bitset.h"
38 #include "xcom_memory.h"
39 #include "synode_no.h"
40 #include "node_no.h"
41 #include "task_debug.h"
42 #include "xcom_transport.h"
43 #include "site_def.h"
44 #include "node_set.h"
45
46 typedef site_def *site_def_ptr;
47
48 struct site_def_ptr_array {
49 u_int count;
50 u_int site_def_ptr_array_len;
51 site_def_ptr *site_def_ptr_array_val;
52 };
53 typedef struct site_def_ptr_array site_def_ptr_array;
54
55 init_xdr_array(site_def_ptr)
56 free_xdr_array(site_def_ptr)
57 set_xdr_array(site_def_ptr)
58
59 /* FIFO of site definitions */
60 static site_def_ptr_array site_defs;
61 static site_def *incoming = 0;
62 static inline node_no _get_maxnodes(site_def const *site);
63
64 /* purecov: begin deadcode */
65 /* Save incoming site def, but do not make it available yet */
begin_site_def(site_def * s)66 site_def *begin_site_def(site_def *s)
67 {
68 assert(!incoming);
69 incoming = s;
70 assert(s->global_node_set.node_set_len == _get_maxnodes(s));
71 return incoming;
72 }
73
74
75 /* Push saved site def, making it active from synode start */
end_site_def(synode_no start)76 site_def *end_site_def(synode_no start)
77 {
78 assert(incoming);
79 incoming->start = start;
80 return push_site_def(incoming);
81 }
82 /* purecov: end */
83
84 /* Rteurn pointer to array of site defs */
get_all_site_defs(site_def *** s,uint32_t * n)85 void get_all_site_defs(site_def ***s, uint32_t *n)
86 {
87 *s = site_defs.site_def_ptr_array_val;
88 *n = site_defs.site_def_ptr_array_len;
89 }
90
91
92 /* Module initialization */
init_site_vars()93 void init_site_vars()
94 {
95 init_site_def_ptr_array(&site_defs);
96 site_defs.count = 0;
97 incoming = 0;
98 }
99
100
101 /* Recursively free a complete site_def. Only free the site_def, not
102 the servers that it points to, since servers are shared by multiple
103 site_defs, and will eventually be deallocated by garbage_collect_servers
104 */
free_site_def(site_def * s)105 void free_site_def(site_def *s)
106 {
107 if (s) {
108 invalidate_detector_sites(s);
109 xdr_free((xdrproc_t) xdr_node_list, (char *)(&s->nodes));
110 free_node_set(&s->global_node_set);
111 free_node_set(&s->local_node_set);
112 free(s);
113 }
114 }
115
116
117 /* Free all resources in this module */
free_site_defs()118 void free_site_defs()
119 {
120 u_int i;
121 for(i = 0; i < site_defs.count; i++) {
122 free_site_def(site_defs.site_def_ptr_array_val[i]);
123 }
124 free_site_def_ptr_array(&site_defs);
125 site_defs.count = 0;
126 free_site_def(incoming);
127 }
128
129
130 /* Add a new site definition to the list */
push_site_def(site_def * s)131 site_def *push_site_def(site_def *s)
132 {
133 uint32_t i;
134 set_site_def_ptr(&site_defs, 0, site_defs.count);
135 DBGOUT(FN;
136 NDBG(site_defs.count,u);
137 PTREXP(s);
138 if (s) {
139 SYCEXP(s->start);
140 SYCEXP(s->boot_key);
141 }
142 );
143 for (i = site_defs.count; i > 0; i--) {
144 DBGOUT(NDBG(i-1,d);
145 PTREXP(site_defs.site_def_ptr_array_val[i-1]);
146 if (site_defs.site_def_ptr_array_val[i-1]) {
147 SYCEXP(site_defs.site_def_ptr_array_val[i-1]->start);
148 SYCEXP(site_defs.site_def_ptr_array_val[i-1]->boot_key);
149 }
150 );
151 site_defs.site_def_ptr_array_val[i] = site_defs.site_def_ptr_array_val[i-1];
152 }
153 set_site_def_ptr(&site_defs, s, 0);
154 if(s){
155 s->x_proto = set_latest_common_proto(common_xcom_version(s));
156 G_DEBUG("latest common protocol is now %d",s->x_proto);
157 }
158 site_defs.count++;
159 assert(!s || (s->global_node_set.node_set_len == _get_maxnodes(s)));
160 return s;
161 }
162
163 /* Return first site def */
_get_site_def()164 static inline site_def const *_get_site_def()
165 {
166 assert(site_defs.count == 0 || !site_defs.site_def_ptr_array_val[0] || site_defs.site_def_ptr_array_val[0]->global_node_set.node_set_len ==
167 _get_maxnodes(site_defs.site_def_ptr_array_val[0]));
168 if (site_defs.count > 0)
169 return site_defs.site_def_ptr_array_val[0];
170 else
171 return 0;
172 }
173
174
175 /* Return first site def */
get_site_def_rw()176 site_def *get_site_def_rw()
177 {
178 if (site_defs.count > 0)
179 return site_defs.site_def_ptr_array_val[0];
180 else
181 return 0;
182 }
183
184 /* purecov: begin deadcode */
185 /* Return previous site def */
_get_prev_site_def()186 static inline site_def const *_get_prev_site_def()
187 {
188 assert(site_defs.count == 0 || !site_defs.site_def_ptr_array_val[1] || site_defs.site_def_ptr_array_val[1]->global_node_set.node_set_len ==
189 _get_maxnodes(site_defs.site_def_ptr_array_val[1]));
190 if (site_defs.count > 0)
191 return site_defs.site_def_ptr_array_val[1];
192 else
193 return 0;
194 }
195 /* purecov: end */
196
197
198
199 /* Return first site def */
get_site_def()200 site_def const *get_site_def()
201 {
202 return _get_site_def();
203 }
204
205 /* purecov: begin deadcode */
206 /* Return previous site def */
get_prev_site_def()207 site_def const *get_prev_site_def()
208 {
209 return _get_prev_site_def();
210 }
211 /* purecov: end */
212
match_def(site_def const * site,synode_no synode)213 static inline int match_def(site_def const *site, synode_no synode)
214 {
215 return site && (synode.group_id == 0 || synode.group_id == site->start.group_id)
216 && !synode_lt(synode, site->start);
217 }
218
219 /* Return first site def which has start less than or equal to synode */
find_site_def(synode_no synode)220 site_def const *find_site_def(synode_no synode)
221 {
222 site_def const * retval = 0;
223 u_int i;
224
225 for(i = 0; i < site_defs.count; i++)
226 if (match_def(site_defs.site_def_ptr_array_val[i], synode)){
227 retval = site_defs.site_def_ptr_array_val[i];
228 break;
229 }
230 assert(!retval || retval->global_node_set.node_set_len == _get_maxnodes(retval));
231 return retval;
232 }
233
234 /* As find_site_def, but return pointer to non-const object */
find_site_def_rw(synode_no synode)235 site_def *find_site_def_rw(synode_no synode)
236 {
237 site_def * retval = 0;
238 u_int i;
239
240 for(i = 0; i < site_defs.count; i++)
241 if (match_def(site_defs.site_def_ptr_array_val[i], synode)){
242 retval = site_defs.site_def_ptr_array_val[i];
243 break;
244 }
245 assert(!retval || retval->global_node_set.node_set_len == _get_maxnodes(retval));
246 return retval;
247 }
248
249
garbage_collect_site_defs(synode_no x)250 void garbage_collect_site_defs(synode_no x)
251 {
252 u_int i;
253 u_int s_max = site_defs.count;
254
255 DBGOUT(FN;
256 NDBG(site_defs.count, u);
257 SYCEXP(x);
258 );
259 for (i = 3; i < s_max; i++) {
260 if (match_def(site_defs.site_def_ptr_array_val[i], x)) {
261 break;
262 }
263 }
264 i++;
265 for (; i < s_max; i++) {
266 site_def * site = site_defs.site_def_ptr_array_val[i];
267 DBGOUT(NDBG(i, d);
268 PTREXP(site_defs.site_def_ptr_array_val[i]); );
269 if (site) {
270 DBGOUT(SYCEXP(site->start);
271 SYCEXP(site->boot_key); );
272 free_site_def(site);
273 site_defs.site_def_ptr_array_val[i] = 0;
274 }
275 site_defs.count--;
276 }
277 }
278
279 /* purecov: begin deadcode */
dbg_site_def(site_def const * site)280 char *dbg_site_def(site_def const *site)
281 {
282 assert(site->global_node_set.node_set_len == _get_maxnodes(site));
283 return dbg_list(&site->nodes);
284 }
285 /* purecov: end */
286
287 /* Create a new empty site_def */
new_site_def()288 site_def *new_site_def()
289 {
290 site_def * retval = (site_def * ) calloc(1, sizeof(site_def));
291 retval->nodeno = VOID_NODE_NO;
292 return retval;
293 }
294
295
296 /* {{{ Clone a site definition */
297
clone_site_def(site_def const * site)298 site_def *clone_site_def(site_def const *site)
299 {
300 site_def * retval = new_site_def();
301 assert(site->global_node_set.node_set_len == _get_maxnodes(site));
302 *retval = *site;
303 init_node_list(site->nodes.node_list_len, site->nodes.node_list_val, &retval->nodes);
304 retval->global_node_set = clone_node_set(site->global_node_set);
305 retval->local_node_set = clone_node_set(site->local_node_set);
306 assert(retval->global_node_set.node_set_len == _get_maxnodes(retval));
307 DBGOUT(FN; PTREXP(site); PTREXP(retval));
308 return retval;
309 }
310
311
312 /* }}} */
313
314 /* {{{ Initialize a site definition from array of string pointers */
315
init_site_def(u_int n,node_address * names,site_def * site)316 void init_site_def(u_int n, node_address *names, site_def *site)
317 {
318 site->start = null_synode;
319 site->boot_key = null_synode;
320 site->nodeno = VOID_NODE_NO;
321 init_detector(site->detected);
322 init_node_list(n, names, &site->nodes);
323 site->global_node_count = 0;
324 alloc_node_set(&site->global_node_set, NSERVERS);
325 site->global_node_set.node_set_len = site->nodes.node_list_len;
326 set_node_set(&site->global_node_set); /* Assume everyone is there */
327 assert(site->global_node_set.node_set_len == _get_maxnodes(site));
328 alloc_node_set(&site->local_node_set, NSERVERS);
329 site->local_node_set.node_set_len = site->nodes.node_list_len;
330 set_node_set(&site->local_node_set); /* Assume everyone is there */
331 assert(site->local_node_set.node_set_len == _get_maxnodes(site));
332 site->detector_updated = 0;
333 site->x_proto = my_xcom_version;
334 }
335
336
337 /* }}} */
338
339
340 /* Add nodes to site definition, avoid duplicates */
add_site_def(u_int n,node_address * names,site_def * site)341 void add_site_def(u_int n, node_address *names, site_def *site)
342 {
343 if (n > 0) {
344 add_node_list(n, names, &site->nodes);
345 }
346 realloc_node_set(&site->global_node_set, _get_maxnodes(site));
347 realloc_node_set(&site->local_node_set, _get_maxnodes(site));
348 }
349
350 /* Remove nodes from site definition, ignore missing nodes */
remove_site_def(u_int n,node_address * names,site_def * site)351 void remove_site_def(u_int n, node_address *names, site_def *site)
352 {
353 if (n > 0) {
354 remove_node_list(n, names, &site->nodes);
355 }
356 init_detector(site->detected); /* Zero all unused timestamps */
357 realloc_node_set(&site->global_node_set, _get_maxnodes(site));
358 realloc_node_set(&site->local_node_set, _get_maxnodes(site));
359 }
360
361 /* purecov: begin deadcode */
362 /* Return boot_key of first site def */
get_boot_key()363 synode_no get_boot_key()
364 {
365 assert(!_get_site_def() || _get_site_def()->global_node_set.node_set_len == _get_maxnodes(_get_site_def()));
366 if (get_site_def()) {
367 return get_site_def()->boot_key;
368 } else {
369 return null_synode;
370 }
371 }
372
373
374 /* Set boot_key of first site def */
set_boot_key(synode_no const x)375 void set_boot_key(synode_no const x)
376 {
377 assert(_get_site_def());
378 assert(_get_site_def()->global_node_set.node_set_len == _get_maxnodes(_get_site_def()));
379 if (site_defs.site_def_ptr_array_val[0]) {
380 site_defs.site_def_ptr_array_val[0]->boot_key = x;
381 }
382 }
383 /* purecov: end */
384
385 /* Return group id of site */
get_group_id(site_def const * site)386 uint32_t get_group_id(site_def const *site)
387 {
388 if (site) {
389 uint32_t group_id = site->start.group_id;
390 assert(site->global_node_set.node_set_len == _get_maxnodes(site));
391 MAY_DBG(FN; NDBG(group_id, lx); );
392 return group_id;
393 } else {
394 return null_id;
395 }
396 }
397
398
399 #if 0
400 void set_group_id(site_def *site, uint32_t id)
401 {
402 MAY_DBG(FN; STRLIT("changing group id from ");
403 NDBG(get_group_id(site), lx);
404 STRLIT("to ");
405 NDBG(id, lu);
406 );
407 site->group_id = id;
408 }
409
410
411 #endif
412
_get_maxnodes(site_def const * site)413 static inline node_no _get_maxnodes(site_def const *site)
414 {
415 if (site) {
416 return site->nodes.node_list_len;
417 } else
418 return 0;
419 }
420
421
422 /* Return maxnodes of site */
get_maxnodes(site_def const * site)423 node_no get_maxnodes(site_def const *site)
424 {
425 return _get_maxnodes(site);
426 }
427
428 /* purecov: begin deadcode */
get_prev_maxnodes()429 node_no get_prev_maxnodes()
430 {
431 return _get_maxnodes(_get_prev_site_def());
432 }
433 /* purecov: end */
434
435 /* Return nodeno of site */
_get_nodeno(site_def const * site)436 static inline node_no _get_nodeno(site_def const *site)
437 {
438 if (site) {
439 assert(site->global_node_set.node_set_len == _get_maxnodes(site));
440 return site->nodeno;
441 } else
442 return VOID_NODE_NO;
443 }
444
445 /* purecov: begin deadcode */
446 /* Return nodeno of site */
get_nodeno(site_def const * site)447 node_no get_nodeno(site_def const *site)
448 {
449 return _get_nodeno(site);
450 }
451 /* purecov: end */
452
get_prev_nodeno()453 node_no get_prev_nodeno()
454 {
455 return _get_nodeno(_get_prev_site_def());
456 }
457
458
import_config(gcs_snapshot * gcs_snap)459 void import_config(gcs_snapshot *gcs_snap)
460 {
461 int i;
462 DBGOUT(FN; SYCEXP(gcs_snap->log_start));
463 for (i = (int)gcs_snap->cfg.configs_len-1; i >= 0; i--) {
464 config_ptr cp = gcs_snap->cfg.configs_val[i];
465 if (cp) {
466 site_def * site = new_site_def();
467 DBGOUT(FN; SYCEXP(cp->start); SYCEXP(cp->boot_key));
468 init_site_def(cp->nodes.node_list_len,
469 cp->nodes.node_list_val, site);
470 site->start = cp->start;
471 site->boot_key = cp->boot_key;
472 site_install_action(site, app_type);
473 }
474 }
475 }
476
477 extern synode_no executed_msg;
478
export_config()479 gcs_snapshot *export_config()
480 {
481 u_int i;
482 gcs_snapshot *gcs_snap = calloc(1, sizeof(gcs_snapshot));
483 gcs_snap->cfg.configs_val = calloc(site_defs.count, sizeof(config_ptr));
484 gcs_snap->cfg.configs_len = site_defs.count;
485
486 for (i = 0; i < site_defs.count; i++) {
487 site_def *site = site_defs.site_def_ptr_array_val[i];
488 if(site) {
489 config_ptr cp = calloc(1, sizeof(config));
490 init_node_list(site->nodes.node_list_len,
491 site->nodes.node_list_val, &cp->nodes);
492 cp->start = site->start;
493 cp->boot_key = site->boot_key;
494 DBGOUT(FN; SYCEXP(cp->start); SYCEXP(cp->boot_key));
495 gcs_snap->cfg.configs_val[i] = cp;
496 }
497 }
498 gcs_snap->log_start = get_delivered_msg();
499 return gcs_snap;
500 }
501
502
503 /* Return the global minimum delivered message number, based on incoming gossip */
get_min_delivered_msg(site_def const * s)504 synode_no get_min_delivered_msg(site_def const *s)
505 {
506 u_int i;
507 synode_no retval = null_synode;
508 int init = 1;
509
510 for (i = 0; i < s->nodes.node_list_len; i++) {
511 if (s->servers[i]->detected + DETECTOR_LIVE_TIMEOUT > task_now()) {
512 if (init) {
513 init = 0;
514 retval = s->delivered_msg[i];
515 } else {
516 if (synode_lt(s->delivered_msg[i], retval)) {
517 retval = s->delivered_msg[i];
518 }
519 }
520 }
521 }
522 DBGOUT(FN; SYCEXP(retval));
523 return retval;
524 }
525
526
527 /* Track the minimum delivered message numbers based on incoming messages */
update_delivered(site_def * s,node_no node,synode_no msgno)528 void update_delivered(site_def *s, node_no node, synode_no msgno)
529 {
530 if(node < s->nodes.node_list_len){
531 s->delivered_msg[node] = msgno;
532 DBGOUT(FN; SYCEXP(s->delivered_msg[node]); NDBG(node,u));
533 }
534 }
535