root/daemons/attrd/attrd_elections.c

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

DEFINITIONS

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

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

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