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

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