root/daemons/attrd/attrd_elections.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. attrd_election_init
  2. attrd_election_fini
  3. attrd_start_election_if_needed
  4. attrd_election_won
  5. attrd_handle_election_op
  6. attrd_check_for_new_writer
  7. attrd_declare_winner
  8. attrd_remove_voter
  9. attrd_xml_add_writer

   1 /*
   2  * Copyright 2013-2019 Andrew Beekhof <andrew@beekhof.net>
   3  *
   4  * This source code is licensed under the GNU General Public License version 2
   5  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   6  */
   7 
   8 #include <crm_internal.h>
   9 #include <crm/msg_xml.h>
  10 #include <crm/cluster.h>
  11 #include <crm/cluster/election.h>
  12 
  13 #include "pacemaker-attrd.h"
  14 
  15 static char *peer_writer = NULL;
  16 static election_t *writer = NULL;
  17 
  18 void
  19 attrd_election_init()
     /* [previous][next][first][last][top][bottom][index][help] */
  20 {
  21     writer = election_init(T_ATTRD, attrd_cluster->uname, 120000,
  22                            attrd_election_cb);
  23 }
  24 
  25 void
  26 attrd_election_fini()
     /* [previous][next][first][last][top][bottom][index][help] */
  27 {
  28     election_fini(writer);
  29 }
  30 
  31 void
  32 attrd_start_election_if_needed()
     /* [previous][next][first][last][top][bottom][index][help] */
  33 {
  34     if ((peer_writer == NULL)
  35         && (election_state(writer) != election_in_progress)
  36         && !attrd_shutting_down()) {
  37 
  38         crm_info("Starting an election to determine the writer");
  39         election_vote(writer);
  40     }
  41 }
  42 
  43 bool
  44 attrd_election_won()
     /* [previous][next][first][last][top][bottom][index][help] */
  45 {
  46     return (election_state(writer) == election_won);
  47 }
  48 
  49 void
  50 attrd_handle_election_op(const crm_node_t *peer, xmlNode *xml)
     /* [previous][next][first][last][top][bottom][index][help] */
  51 {
  52     enum election_result rc = 0;
  53     enum election_result previous = election_state(writer);
  54 
  55     crm_xml_add(xml, F_CRM_HOST_FROM, peer->uname);
  56 
  57     // Don't become writer if we're shutting down
  58     rc = election_count_vote(writer, xml, !attrd_shutting_down());
  59 
  60     switch(rc) {
  61         case election_start:
  62             crm_debug("Unsetting writer (was %s) and starting new election",
  63                       peer_writer? peer_writer : "unset");
  64             free(peer_writer);
  65             peer_writer = NULL;
  66             election_vote(writer);
  67             break;
  68 
  69         case election_lost:
  70             /* The election API should really distinguish between "we just lost
  71              * to this peer" and "we already lost previously, and we are
  72              * discarding this vote for some reason", but it doesn't.
  73              *
  74              * In the first case, we want to tentatively set the peer writer to
  75              * this peer, even though another peer may eventually win (which we
  76              * will learn via attrd_check_for_new_writer()), so
  77              * attrd_start_election_if_needed() doesn't start a new election.
  78              *
  79              * Approximate a test for that case as best as possible.
  80              */
  81             if ((peer_writer == NULL) || (previous != election_lost)) {
  82                 free(peer_writer);
  83                 peer_writer = strdup(peer->uname);
  84                 crm_debug("Election lost, presuming %s is writer for now",
  85                           peer_writer);
  86             }
  87             break;
  88 
  89         case election_in_progress:
  90             election_check(writer);
  91             break;
  92 
  93         default:
  94             crm_info("Ignoring election op from %s due to error", peer->uname);
  95             break;
  96     }
  97 }
  98 
  99 bool
 100 attrd_check_for_new_writer(const crm_node_t *peer, const xmlNode *xml)
     /* [previous][next][first][last][top][bottom][index][help] */
 101 {
 102     int peer_state = 0;
 103 
 104     crm_element_value_int(xml, PCMK__XA_ATTR_WRITER, &peer_state);
 105     if (peer_state == election_won) {
 106         if ((election_state(writer) == election_won)
 107            && !pcmk__str_eq(peer->uname, attrd_cluster->uname, pcmk__str_casei)) {
 108             crm_notice("Detected another attribute writer (%s), starting new election",
 109                        peer->uname);
 110             election_vote(writer);
 111 
 112         } else if (!pcmk__str_eq(peer->uname, peer_writer, pcmk__str_casei)) {
 113             crm_notice("Recorded new attribute writer: %s (was %s)",
 114                        peer->uname, (peer_writer? peer_writer : "unset"));
 115             free(peer_writer);
 116             peer_writer = strdup(peer->uname);
 117         }
 118     }
 119     return (peer_state == election_won);
 120 }
 121 
 122 void
 123 attrd_declare_winner()
     /* [previous][next][first][last][top][bottom][index][help] */
 124 {
 125     crm_notice("Recorded local node as attribute writer (was %s)",
 126                (peer_writer? peer_writer : "unset"));
 127     free(peer_writer);
 128     peer_writer = strdup(attrd_cluster->uname);
 129 }
 130 
 131 void
 132 attrd_remove_voter(const crm_node_t *peer)
     /* [previous][next][first][last][top][bottom][index][help] */
 133 {
 134     election_remove(writer, peer->uname);
 135     if (peer_writer && pcmk__str_eq(peer->uname, peer_writer, pcmk__str_casei)) {
 136         free(peer_writer);
 137         peer_writer = NULL;
 138         crm_notice("Lost attribute writer %s", peer->uname);
 139 
 140         /* Clear any election dampening in effect. Otherwise, if the lost writer
 141          * had just won, the election could fizzle out with no new writer.
 142          */
 143         election_clear_dampening(writer);
 144 
 145         /* If the writer received attribute updates during its shutdown, it will
 146          * not have written them to the CIB. Ensure we get a new writer so they
 147          * are written out. This means that every node that sees the writer
 148          * leave will start a new election, but that's better than losing
 149          * attributes.
 150          */
 151         attrd_start_election_if_needed();
 152     }
 153 }
 154 
 155 void
 156 attrd_xml_add_writer(xmlNode *xml)
     /* [previous][next][first][last][top][bottom][index][help] */
 157 {
 158     crm_xml_add_int(xml, PCMK__XA_ATTR_WRITER, election_state(writer));
 159 }

/* [previous][next][first][last][top][bottom][index][help] */