This source file includes following definitions.
- next_key
- free_waitlist_node
- sync_point_str
- attrd_add_client_to_waitlist
- attrd_free_waitlist
- attrd_remove_client_from_waitlist
- attrd_ack_waitlist_clients
- attrd_cluster_sync_point_update
- attrd_request_sync_point
- attrd_request_has_sync_point
- free_action
- confirmation_timeout_cb
- attrd_do_not_expect_from_peer
- attrd_do_not_wait_for_client
- attrd_expect_confirmations
- attrd_free_confirmations
- attrd_handle_confirmation
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <crm/msg_xml.h>
13 #include <crm/common/attrd_internal.h>
14
15 #include "pacemaker-attrd.h"
16
17
18
19
20
21
22
23
24 static GHashTable *waitlist = NULL;
25 static int waitlist_client = 0;
26
27 struct waitlist_node {
28
29 enum attrd_sync_point sync_point;
30
31
32 char *client_id;
33 uint32_t ipc_id;
34 uint32_t flags;
35 };
36
37
38
39
40
41
42
43
44
45
46
47 static GHashTable *expected_confirmations = NULL;
48
49
50
51
52
53 struct confirmation_action {
54
55
56
57
58
59
60
61
62 GList *respondents;
63
64
65
66
67
68 mainloop_timer_t *timer;
69
70
71
72
73 attrd_confirmation_action_fn fn;
74
75
76
77
78 char *client_id;
79 uint32_t ipc_id;
80 uint32_t flags;
81
82
83
84
85 void *xml;
86 };
87
88 static void
89 next_key(void)
90 {
91 do {
92 waitlist_client++;
93 if (waitlist_client < 0) {
94 waitlist_client = 1;
95 }
96 } while (g_hash_table_contains(waitlist, GINT_TO_POINTER(waitlist_client)));
97 }
98
99 static void
100 free_waitlist_node(gpointer data)
101 {
102 struct waitlist_node *wl = (struct waitlist_node *) data;
103
104 free(wl->client_id);
105 free(wl);
106 }
107
108 static const char *
109 sync_point_str(enum attrd_sync_point sync_point)
110 {
111 if (sync_point == attrd_sync_point_local) {
112 return PCMK__VALUE_LOCAL;
113 } else if (sync_point == attrd_sync_point_cluster) {
114 return PCMK__VALUE_CLUSTER;
115 } else {
116 return "unknown";
117 }
118 }
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134 void
135 attrd_add_client_to_waitlist(pcmk__request_t *request)
136 {
137 const char *sync_point = attrd_request_sync_point(request->xml);
138 struct waitlist_node *wl = NULL;
139
140 if (sync_point == NULL) {
141 return;
142 }
143
144 if (waitlist == NULL) {
145 waitlist = pcmk__intkey_table(free_waitlist_node);
146 }
147
148 wl = calloc(sizeof(struct waitlist_node), 1);
149
150 CRM_ASSERT(wl != NULL);
151
152 wl->client_id = strdup(request->ipc_client->id);
153
154 CRM_ASSERT(wl->client_id);
155
156 if (pcmk__str_eq(sync_point, PCMK__VALUE_LOCAL, pcmk__str_none)) {
157 wl->sync_point = attrd_sync_point_local;
158 } else if (pcmk__str_eq(sync_point, PCMK__VALUE_CLUSTER, pcmk__str_none)) {
159 wl->sync_point = attrd_sync_point_cluster;
160 } else {
161 free_waitlist_node(wl);
162 return;
163 }
164
165 wl->ipc_id = request->ipc_id;
166 wl->flags = request->flags;
167
168 next_key();
169 pcmk__intkey_table_insert(waitlist, waitlist_client, wl);
170
171 crm_trace("Added client %s to waitlist for %s sync point",
172 wl->client_id, sync_point_str(wl->sync_point));
173 crm_trace("%d clients now on waitlist", g_hash_table_size(waitlist));
174
175
176
177
178 crm_xml_add_int(request->xml, XML_LRM_ATTR_CALLID, waitlist_client);
179 }
180
181
182
183
184
185
186 void
187 attrd_free_waitlist(void)
188 {
189 if (waitlist == NULL) {
190 return;
191 }
192
193 g_hash_table_destroy(waitlist);
194 waitlist = NULL;
195 }
196
197
198
199
200
201
202
203
204 void
205 attrd_remove_client_from_waitlist(pcmk__client_t *client)
206 {
207 GHashTableIter iter;
208 gpointer value;
209
210 if (waitlist == NULL) {
211 return;
212 }
213
214 g_hash_table_iter_init(&iter, waitlist);
215
216 while (g_hash_table_iter_next(&iter, NULL, &value)) {
217 struct waitlist_node *wl = (struct waitlist_node *) value;
218
219 if (pcmk__str_eq(wl->client_id, client->id, pcmk__str_none)) {
220 g_hash_table_iter_remove(&iter);
221 crm_trace("%d clients now on waitlist", g_hash_table_size(waitlist));
222 }
223 }
224 }
225
226
227
228
229
230
231
232
233
234
235
236
237
238 void
239 attrd_ack_waitlist_clients(enum attrd_sync_point sync_point, const xmlNode *xml)
240 {
241 int callid;
242 gpointer value;
243
244 if (waitlist == NULL) {
245 return;
246 }
247
248 if (crm_element_value_int(xml, XML_LRM_ATTR_CALLID, &callid) == -1) {
249 crm_warn("Could not get callid from request XML");
250 return;
251 }
252
253 value = pcmk__intkey_table_lookup(waitlist, callid);
254 if (value != NULL) {
255 struct waitlist_node *wl = (struct waitlist_node *) value;
256 pcmk__client_t *client = NULL;
257
258 if (wl->sync_point != sync_point) {
259 return;
260 }
261
262 crm_notice("Alerting client %s for reached %s sync point",
263 wl->client_id, sync_point_str(wl->sync_point));
264
265 client = pcmk__find_client_by_id(wl->client_id);
266 if (client == NULL) {
267 return;
268 }
269
270 attrd_send_ack(client, wl->ipc_id, wl->flags | crm_ipc_client_response);
271
272
273 pcmk__intkey_table_remove(waitlist, callid);
274
275 crm_trace("%d clients now on waitlist", g_hash_table_size(waitlist));
276 }
277 }
278
279
280
281
282
283
284
285
286
287
288 int
289 attrd_cluster_sync_point_update(xmlNode *xml)
290 {
291 crm_trace("Hit cluster sync point for attribute update");
292 attrd_ack_waitlist_clients(attrd_sync_point_cluster, xml);
293 return pcmk_rc_ok;
294 }
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313 const char *
314 attrd_request_sync_point(xmlNode *xml)
315 {
316 CRM_CHECK(xml != NULL, return NULL);
317
318 if (xml->children != NULL) {
319 xmlNode *child = pcmk__xe_match(xml, XML_ATTR_OP, PCMK__XA_ATTR_SYNC_POINT, NULL);
320
321 if (child) {
322 return crm_element_value(child, PCMK__XA_ATTR_SYNC_POINT);
323 } else {
324 return NULL;
325 }
326
327 } else {
328 return crm_element_value(xml, PCMK__XA_ATTR_SYNC_POINT);
329 }
330 }
331
332
333
334
335
336
337
338
339
340 bool
341 attrd_request_has_sync_point(xmlNode *xml)
342 {
343 return attrd_request_sync_point(xml) != NULL;
344 }
345
346 static void
347 free_action(gpointer data)
348 {
349 struct confirmation_action *action = (struct confirmation_action *) data;
350 g_list_free_full(action->respondents, free);
351 mainloop_timer_del(action->timer);
352 free_xml(action->xml);
353 free(action->client_id);
354 free(action);
355 }
356
357
358
359
360
361
362 static gboolean
363 confirmation_timeout_cb(gpointer data)
364 {
365 struct confirmation_action *action = (struct confirmation_action *) data;
366
367 GHashTableIter iter;
368 gpointer value;
369
370 if (expected_confirmations == NULL) {
371 return G_SOURCE_REMOVE;
372 }
373
374 g_hash_table_iter_init(&iter, expected_confirmations);
375
376 while (g_hash_table_iter_next(&iter, NULL, &value)) {
377 if (value == action) {
378 pcmk__client_t *client = pcmk__find_client_by_id(action->client_id);
379 if (client == NULL) {
380 return G_SOURCE_REMOVE;
381 }
382
383 crm_trace("Timed out waiting for confirmations for client %s", client->id);
384 pcmk__ipc_send_ack(client, action->ipc_id, action->flags | crm_ipc_client_response,
385 "ack", ATTRD_PROTOCOL_VERSION, CRM_EX_TIMEOUT);
386
387 g_hash_table_iter_remove(&iter);
388 crm_trace("%d requests now in expected confirmations table", g_hash_table_size(expected_confirmations));
389 break;
390 }
391 }
392
393 return G_SOURCE_REMOVE;
394 }
395
396
397
398
399
400
401
402
403
404 void
405 attrd_do_not_expect_from_peer(const char *host)
406 {
407 GList *keys = NULL;
408
409 if (expected_confirmations == NULL) {
410 return;
411 }
412
413 keys = g_hash_table_get_keys(expected_confirmations);
414
415 crm_trace("Removing peer %s from expected confirmations", host);
416
417 for (GList *node = keys; node != NULL; node = node->next) {
418 int callid = *(int *) node->data;
419 attrd_handle_confirmation(callid, host);
420 }
421
422 g_list_free(keys);
423 }
424
425
426
427
428
429
430
431
432
433
434 void
435 attrd_do_not_wait_for_client(pcmk__client_t *client)
436 {
437 GHashTableIter iter;
438 gpointer value;
439
440 if (expected_confirmations == NULL) {
441 return;
442 }
443
444 g_hash_table_iter_init(&iter, expected_confirmations);
445
446 while (g_hash_table_iter_next(&iter, NULL, &value)) {
447 struct confirmation_action *action = (struct confirmation_action *) value;
448
449 if (pcmk__str_eq(action->client_id, client->id, pcmk__str_none)) {
450 crm_trace("Removing client %s from expected confirmations", client->id);
451 g_hash_table_iter_remove(&iter);
452 crm_trace("%d requests now in expected confirmations table", g_hash_table_size(expected_confirmations));
453 break;
454 }
455 }
456 }
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476 void
477 attrd_expect_confirmations(pcmk__request_t *request, attrd_confirmation_action_fn fn)
478 {
479 struct confirmation_action *action = NULL;
480 GHashTableIter iter;
481 gpointer host, ver;
482 GList *respondents = NULL;
483 int callid;
484
485 if (expected_confirmations == NULL) {
486 expected_confirmations = pcmk__intkey_table((GDestroyNotify) free_action);
487 }
488
489 if (crm_element_value_int(request->xml, XML_LRM_ATTR_CALLID, &callid) == -1) {
490 crm_err("Could not get callid from xml");
491 return;
492 }
493
494 if (pcmk__intkey_table_lookup(expected_confirmations, callid)) {
495 crm_err("Already waiting on confirmations for call id %d", callid);
496 return;
497 }
498
499 g_hash_table_iter_init(&iter, peer_protocol_vers);
500 while (g_hash_table_iter_next(&iter, &host, &ver)) {
501 if (ATTRD_SUPPORTS_CONFIRMATION(GPOINTER_TO_INT(ver))) {
502 char *s = strdup((char *) host);
503
504 CRM_ASSERT(s != NULL);
505 respondents = g_list_prepend(respondents, s);
506 }
507 }
508
509 action = calloc(1, sizeof(struct confirmation_action));
510 CRM_ASSERT(action != NULL);
511
512 action->respondents = respondents;
513 action->fn = fn;
514 action->xml = copy_xml(request->xml);
515
516 action->client_id = strdup(request->ipc_client->id);
517 CRM_ASSERT(action->client_id != NULL);
518
519 action->ipc_id = request->ipc_id;
520 action->flags = request->flags;
521
522 action->timer = mainloop_timer_add(NULL, 15000, FALSE, confirmation_timeout_cb, action);
523 mainloop_timer_start(action->timer);
524
525 pcmk__intkey_table_insert(expected_confirmations, callid, action);
526 crm_trace("Callid %d now waiting on %d confirmations", callid, g_list_length(respondents));
527 crm_trace("%d requests now in expected confirmations table", g_hash_table_size(expected_confirmations));
528 }
529
530 void
531 attrd_free_confirmations(void)
532 {
533 if (expected_confirmations != NULL) {
534 g_hash_table_destroy(expected_confirmations);
535 expected_confirmations = NULL;
536 }
537 }
538
539
540
541
542
543
544
545
546
547
548
549
550 void
551 attrd_handle_confirmation(int callid, const char *host)
552 {
553 struct confirmation_action *action = NULL;
554 GList *node = NULL;
555
556 if (expected_confirmations == NULL) {
557 return;
558 }
559
560 action = pcmk__intkey_table_lookup(expected_confirmations, callid);
561 if (action == NULL) {
562 return;
563 }
564
565 node = g_list_find_custom(action->respondents, host, (GCompareFunc) strcasecmp);
566
567 if (node == NULL) {
568 return;
569 }
570
571 action->respondents = g_list_remove(action->respondents, node->data);
572 crm_trace("Callid %d now waiting on %d confirmations", callid, g_list_length(action->respondents));
573
574 if (action->respondents == NULL) {
575 action->fn(action->xml);
576 pcmk__intkey_table_remove(expected_confirmations, callid);
577 crm_trace("%d requests now in expected confirmations table", g_hash_table_size(expected_confirmations));
578 }
579 }