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/common/xml.h>
  13 #include <crm/common/attrs_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 PCMK_VALUE_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 = pcmk__assert_alloc(1, sizeof(struct waitlist_node));
 149 
 150     if (pcmk__str_eq(sync_point, PCMK__VALUE_LOCAL, pcmk__str_none)) {
 151         wl->sync_point = attrd_sync_point_local;
 152     } else if (pcmk__str_eq(sync_point, PCMK__VALUE_CLUSTER, pcmk__str_none)) {
 153         wl->sync_point = attrd_sync_point_cluster;
 154     } else {
 155         free_waitlist_node(wl);
 156         return;
 157     }
 158 
 159     wl->client_id = pcmk__str_copy(request->ipc_client->id);
 160     wl->ipc_id = request->ipc_id;
 161     wl->flags = request->flags;
 162 
 163     next_key();
 164     pcmk__intkey_table_insert(waitlist, waitlist_client, wl);
 165 
 166     crm_trace("Added client %s to waitlist for %s sync point",
 167               wl->client_id, sync_point_str(wl->sync_point));
 168     crm_trace("%d clients now on waitlist", g_hash_table_size(waitlist));
 169 
 170     
 171 
 172 
 173     crm_xml_add_int(request->xml, PCMK__XA_CALL_ID, waitlist_client);
 174 }
 175 
 176 
 177 
 178 
 179 
 180 
 181 void
 182 attrd_free_waitlist(void)
     
 183 {
 184     if (waitlist == NULL) {
 185         return;
 186     }
 187 
 188     g_hash_table_destroy(waitlist);
 189     waitlist = NULL;
 190 }
 191 
 192 
 193 
 194 
 195 
 196 
 197 
 198 
 199 void
 200 attrd_remove_client_from_waitlist(pcmk__client_t *client)
     
 201 {
 202     GHashTableIter iter;
 203     gpointer value;
 204 
 205     if (waitlist == NULL) {
 206         return;
 207     }
 208 
 209     g_hash_table_iter_init(&iter, waitlist);
 210 
 211     while (g_hash_table_iter_next(&iter, NULL, &value)) {
 212         struct waitlist_node *wl = (struct waitlist_node *) value;
 213 
 214         if (pcmk__str_eq(wl->client_id, client->id, pcmk__str_none)) {
 215             g_hash_table_iter_remove(&iter);
 216             crm_trace("%d clients now on waitlist", g_hash_table_size(waitlist));
 217         }
 218     }
 219 }
 220 
 221 
 222 
 223 
 224 
 225 
 226 
 227 
 228 
 229 
 230 
 231 
 232 
 233 void
 234 attrd_ack_waitlist_clients(enum attrd_sync_point sync_point, const xmlNode *xml)
     
 235 {
 236     int callid;
 237     gpointer value;
 238 
 239     if (waitlist == NULL) {
 240         return;
 241     }
 242 
 243     if (crm_element_value_int(xml, PCMK__XA_CALL_ID, &callid) == -1) {
 244         crm_warn("Could not get callid from request XML");
 245         return;
 246     }
 247 
 248     value = pcmk__intkey_table_lookup(waitlist, callid);
 249     if (value != NULL) {
 250         struct waitlist_node *wl = (struct waitlist_node *) value;
 251         pcmk__client_t *client = NULL;
 252 
 253         if (wl->sync_point != sync_point) {
 254             return;
 255         }
 256 
 257         crm_notice("Alerting client %s for reached %s sync point",
 258                    wl->client_id, sync_point_str(wl->sync_point));
 259 
 260         client = pcmk__find_client_by_id(wl->client_id);
 261         if (client == NULL) {
 262             return;
 263         }
 264 
 265         attrd_send_ack(client, wl->ipc_id, wl->flags | crm_ipc_client_response);
 266 
 267         
 268         pcmk__intkey_table_remove(waitlist, callid);
 269 
 270         crm_trace("%d clients now on waitlist", g_hash_table_size(waitlist));
 271     }
 272 }
 273 
 274 
 275 
 276 
 277 
 278 
 279 
 280 
 281 
 282 
 283 int
 284 attrd_cluster_sync_point_update(xmlNode *xml)
     
 285 {
 286     crm_trace("Hit cluster sync point for attribute update");
 287     attrd_ack_waitlist_clients(attrd_sync_point_cluster, xml);
 288     return pcmk_rc_ok;
 289 }
 290 
 291 
 292 
 293 
 294 
 295 
 296 
 297 
 298 
 299 
 300 
 301 
 302 
 303 
 304 
 305 
 306 
 307 
 308 const char *
 309 attrd_request_sync_point(xmlNode *xml)
     
 310 {
 311     CRM_CHECK(xml != NULL, return NULL);
 312 
 313     if (xml->children != NULL) {
 314         xmlNode *child = pcmk__xe_first_child(xml, PCMK_XE_OP,
 315                                               PCMK__XA_ATTR_SYNC_POINT, NULL);
 316 
 317         if (child) {
 318             return crm_element_value(child, PCMK__XA_ATTR_SYNC_POINT);
 319         } else {
 320             return NULL;
 321         }
 322 
 323     } else {
 324         return crm_element_value(xml, PCMK__XA_ATTR_SYNC_POINT);
 325     }
 326 }
 327 
 328 
 329 
 330 
 331 
 332 
 333 
 334 
 335 
 336 bool
 337 attrd_request_has_sync_point(xmlNode *xml)
     
 338 {
 339     return attrd_request_sync_point(xml) != NULL;
 340 }
 341 
 342 static void
 343 free_action(gpointer data)
     
 344 {
 345     struct confirmation_action *action = (struct confirmation_action *) data;
 346     g_list_free_full(action->respondents, free);
 347     mainloop_timer_del(action->timer);
 348     free_xml(action->xml);
 349     free(action->client_id);
 350     free(action);
 351 }
 352 
 353 
 354 
 355 
 356 
 357 
 358 static gboolean
 359 confirmation_timeout_cb(gpointer data)
     
 360 {
 361     struct confirmation_action *action = (struct confirmation_action *) data;
 362 
 363     GHashTableIter iter;
 364     gpointer value;
 365 
 366     if (expected_confirmations == NULL) {
 367         return G_SOURCE_REMOVE;
 368     }
 369 
 370     g_hash_table_iter_init(&iter, expected_confirmations);
 371 
 372     while (g_hash_table_iter_next(&iter, NULL, &value)) {
 373         if (value == action) {
 374             pcmk__client_t *client = pcmk__find_client_by_id(action->client_id);
 375             if (client == NULL) {
 376                 return G_SOURCE_REMOVE;
 377             }
 378 
 379             crm_trace("Timed out waiting for confirmations for client %s", client->id);
 380             pcmk__ipc_send_ack(client, action->ipc_id,
 381                                action->flags|crm_ipc_client_response,
 382                                PCMK__XE_ACK, ATTRD_PROTOCOL_VERSION,
 383                                CRM_EX_TIMEOUT);
 384 
 385             g_hash_table_iter_remove(&iter);
 386             crm_trace("%d requests now in expected confirmations table", g_hash_table_size(expected_confirmations));
 387             break;
 388         }
 389     }
 390 
 391     return G_SOURCE_REMOVE;
 392 }
 393 
 394 
 395 
 396 
 397 
 398 
 399 
 400 
 401 
 402 void
 403 attrd_do_not_expect_from_peer(const char *host)
     
 404 {
 405     GList *keys = NULL;
 406 
 407     if (expected_confirmations == NULL) {
 408         return;
 409     }
 410 
 411     keys = g_hash_table_get_keys(expected_confirmations);
 412 
 413     crm_trace("Removing peer %s from expected confirmations", host);
 414 
 415     for (GList *node = keys; node != NULL; node = node->next) {
 416         int callid = *(int *) node->data;
 417         attrd_handle_confirmation(callid, host);
 418     }
 419 
 420     g_list_free(keys);
 421 }
 422 
 423 
 424 
 425 
 426 
 427 
 428 
 429 
 430 
 431 
 432 void
 433 attrd_do_not_wait_for_client(pcmk__client_t *client)
     
 434 {
 435     GHashTableIter iter;
 436     gpointer value;
 437 
 438     if (expected_confirmations == NULL) {
 439         return;
 440     }
 441 
 442     g_hash_table_iter_init(&iter, expected_confirmations);
 443 
 444     while (g_hash_table_iter_next(&iter, NULL, &value)) {
 445         struct confirmation_action *action = (struct confirmation_action *) value;
 446 
 447         if (pcmk__str_eq(action->client_id, client->id, pcmk__str_none)) {
 448             crm_trace("Removing client %s from expected confirmations", client->id);
 449             g_hash_table_iter_remove(&iter);
 450             crm_trace("%d requests now in expected confirmations table", g_hash_table_size(expected_confirmations));
 451             break;
 452         }
 453     }
 454 }
 455 
 456 
 457 
 458 
 459 
 460 
 461 
 462 
 463 
 464 
 465 
 466 
 467 
 468 
 469 
 470 
 471 
 472 
 473 
 474 void
 475 attrd_expect_confirmations(pcmk__request_t *request, attrd_confirmation_action_fn fn)
     
 476 {
 477     struct confirmation_action *action = NULL;
 478     GHashTableIter iter;
 479     gpointer host, ver;
 480     GList *respondents = NULL;
 481     int callid;
 482 
 483     if (expected_confirmations == NULL) {
 484         expected_confirmations = pcmk__intkey_table((GDestroyNotify) free_action);
 485     }
 486 
 487     if (crm_element_value_int(request->xml, PCMK__XA_CALL_ID, &callid) == -1) {
 488         crm_err("Could not get callid from xml");
 489         return;
 490     }
 491 
 492     if (pcmk__intkey_table_lookup(expected_confirmations, callid)) {
 493         crm_err("Already waiting on confirmations for call id %d", callid);
 494         return;
 495     }
 496 
 497     g_hash_table_iter_init(&iter, peer_protocol_vers);
 498     while (g_hash_table_iter_next(&iter, &host, &ver)) {
 499         if (ATTRD_SUPPORTS_CONFIRMATION(GPOINTER_TO_INT(ver))) {
 500             respondents = g_list_prepend(respondents,
 501                                          pcmk__str_copy((char *) host));
 502         }
 503     }
 504 
 505     action = pcmk__assert_alloc(1, sizeof(struct confirmation_action));
 506 
 507     action->respondents = respondents;
 508     action->fn = fn;
 509     action->xml = pcmk__xml_copy(NULL, request->xml);
 510     action->client_id = pcmk__str_copy(request->ipc_client->id);
 511     action->ipc_id = request->ipc_id;
 512     action->flags = request->flags;
 513 
 514     action->timer = mainloop_timer_add(NULL, 15000, FALSE, confirmation_timeout_cb, action);
 515     mainloop_timer_start(action->timer);
 516 
 517     pcmk__intkey_table_insert(expected_confirmations, callid, action);
 518     crm_trace("Callid %d now waiting on %d confirmations", callid, g_list_length(respondents));
 519     crm_trace("%d requests now in expected confirmations table", g_hash_table_size(expected_confirmations));
 520 }
 521 
 522 void
 523 attrd_free_confirmations(void)
     
 524 {
 525     if (expected_confirmations != NULL) {
 526         g_hash_table_destroy(expected_confirmations);
 527         expected_confirmations = NULL;
 528     }
 529 }
 530 
 531 
 532 
 533 
 534 
 535 
 536 
 537 
 538 
 539 
 540 
 541 
 542 void
 543 attrd_handle_confirmation(int callid, const char *host)
     
 544 {
 545     struct confirmation_action *action = NULL;
 546     GList *node = NULL;
 547 
 548     if (expected_confirmations == NULL) {
 549         return;
 550     }
 551 
 552     action = pcmk__intkey_table_lookup(expected_confirmations, callid);
 553     if (action == NULL) {
 554         return;
 555     }
 556 
 557     node = g_list_find_custom(action->respondents, host, (GCompareFunc) strcasecmp);
 558 
 559     if (node == NULL) {
 560         return;
 561     }
 562 
 563     action->respondents = g_list_remove(action->respondents, node->data);
 564     crm_trace("Callid %d now waiting on %d confirmations", callid, g_list_length(action->respondents));
 565 
 566     if (action->respondents == NULL) {
 567         action->fn(action->xml);
 568         pcmk__intkey_table_remove(expected_confirmations, callid);
 569         crm_trace("%d requests now in expected confirmations table", g_hash_table_size(expected_confirmations));
 570     }
 571 }