13 #include <sys/resource.h>    22 #define STORM_INTERVAL   2          35     time_t last_election_loss; 
    49 election_timer_cb(gpointer user_data)
    53     crm_info(
"%s timed out, declaring local node as winner", e->name);
    92     static guint count = 0;
    98         crm_perror(LOG_CRIT, 
"Cannot create election");
   102     e->uname = strdup(
uname);
   103     if (e->uname == NULL) {
   104         crm_perror(LOG_CRIT, 
"Cannot create election");
   113                                     election_timer_cb, e);
   130     if ((e != NULL) && (
uname != NULL) && (e->voted != NULL)) {
   131         crm_trace(
"Discarding %s (no-)vote from lost peer %s", e->name, 
uname);
   132         g_hash_table_remove(e->voted, 
uname);
   145         crm_trace(
"Resetting election %s", e->name);
   148             crm_trace(
"Destroying voted cache with %d members", g_hash_table_size(e->voted));
   149             g_hash_table_destroy(e->voted);
   209         crm_err(
"No election defined");
   214 get_uptime(
struct timeval *output)
   216     static time_t expires = 0;
   217     static struct rusage info;
   219     time_t tm_now = time(NULL);
   221     if (expires < tm_now) {
   224         info.ru_utime.tv_sec = 0;
   225         info.ru_utime.tv_usec = 0;
   226         rc = getrusage(RUSAGE_SELF, &info);
   232             crm_perror(LOG_ERR, 
"Could not calculate the current uptime");
   237         crm_debug(
"Current CPU usage is: %lds, %ldus", (
long)info.ru_utime.tv_sec,
   238                   (
long)info.ru_utime.tv_usec);
   242     output->tv_sec = info.ru_utime.tv_sec;
   243     output->tv_usec = info.ru_utime.tv_usec;
   249 compare_age(
struct timeval your_age)
   251     struct timeval our_age;
   253     get_uptime(&our_age); 
   255     if (our_age.tv_sec > your_age.tv_sec) {
   256         crm_debug(
"Win: %ld vs %ld (seconds)", (
long)our_age.tv_sec, (
long)your_age.tv_sec);
   258     } 
else if (our_age.tv_sec < your_age.tv_sec) {
   259         crm_debug(
"Lose: %ld vs %ld (seconds)", (
long)our_age.tv_sec, (
long)your_age.tv_sec);
   261     } 
else if (our_age.tv_usec > your_age.tv_usec) {
   262         crm_debug(
"Win: %ld.%06ld vs %ld.%06ld (usec)",
   263                   (
long)our_age.tv_sec, (
long)our_age.tv_usec, (
long)your_age.tv_sec, (
long)your_age.tv_usec);
   265     } 
else if (our_age.tv_usec < your_age.tv_usec) {
   266         crm_debug(
"Lose: %ld.%06ld vs %ld.%06ld (usec)",
   267                   (
long)our_age.tv_sec, (
long)our_age.tv_usec, (
long)your_age.tv_sec, (
long)your_age.tv_usec);
   292     xmlNode *vote = NULL;
   296         crm_trace(
"Election vote requested, but no election available");
   303         crm_trace(
"Cannot vote in %s yet: local node not connected to cluster",
   324     crm_debug(
"Started %s round %d", e->name, e->count);
   325     election_timeout_start(e);
   351         crm_trace(
"Election check requested, but no election available");
   354     if (e->voted == NULL) {
   355         crm_trace(
"%s check requested, but no votes received yet", e->name);
   359     voted_size = g_hash_table_size(e->voted);
   366     if (voted_size >= num_members) {
   369         if (voted_size > num_members) {
   370             GHashTableIter gIter;
   374             crm_warn(
"Received too many votes in %s", e->name);
   376             while (g_hash_table_iter_next(&gIter, NULL, (gpointer *) & node)) {
   378                     crm_warn(
"* expected vote: %s", node->uname);
   382             g_hash_table_iter_init(&gIter, e->voted);
   383             while (g_hash_table_iter_next(&gIter, (gpointer *) & key, NULL)) {
   389         crm_info(
"%s won by local node", e->name);
   390         election_complete(e);
   394         crm_debug(
"%s still waiting on %d of %d votes",
   395                   e->name, num_members - voted_size, num_members);
   401 #define LOSS_DAMPEN 2              407     const char *election_owner;
   424 parse_election_message(
const election_t *e, 
const xmlNode *message,
   427     CRM_CHECK(message && vote, 
return FALSE);
   429     vote->election_id = -1;
   430     vote->age.tv_sec = -1;
   431     vote->age.tv_usec = -1;
   440     if ((vote->op == NULL) || (vote->from == NULL) || (vote->version == NULL)
   441         || (vote->election_owner == NULL) || (vote->election_id < 0)) {
   443         crm_warn(
"Invalid %s message from %s in %s ",
   444                  (vote->op? vote->op : 
"election"),
   445                  (vote->from? vote->from : 
"unspecified node"),
   446                  (e? e->name : 
"election"));
   458         if ((vote->age.tv_sec < 0) || (vote->age.tv_usec < 0)) {
   459             crm_warn(
"Cannot count %s %s from %s because it is missing uptime",
   460                      (e? e->name : 
"election"), vote->op, vote->from);
   465         crm_info(
"Cannot process %s message from %s because %s is not a known election op",
   466                  (e? e->name : 
"election"), vote->from, vote->op);
   473         crm_info(
"Cannot count %s from %s because no election available",
   474                  vote->op, vote->from);
   482         crm_info(
"Cannot count %s %s from %s because no peer information available",
   483                  e->name, vote->op, vote->from);
   492     CRM_ASSERT(e && vote && vote->from && vote->op);
   494     if (e->voted == NULL) {
   501 send_no_vote(
crm_node_t *peer, 
struct vote *vote)
   533     int log_level = LOG_INFO;
   534     gboolean done = FALSE;
   535     gboolean we_lose = FALSE;
   536     const char *reason = 
"unknown";
   537     bool we_are_owner = FALSE;
   538     crm_node_t *our_node = NULL, *your_node = NULL;
   539     time_t tm_now = time(NULL);
   543     if (parse_election_message(e, message, &vote) == FALSE) {
   551     we_are_owner = (our_node != NULL)
   552                    && pcmk__str_eq(our_node->
uuid, vote.election_owner,
   556         reason = 
"Not eligible";
   560         reason = 
"We are not part of the cluster";
   564     } 
else if (we_are_owner && (vote.election_id != e->count)) {
   566         reason = 
"Superseded";
   571         reason = 
"Peer is not part of our cluster";
   572         log_level = LOG_WARNING;
   581             crm_warn(
"Cannot count %s round %d %s from %s because we are not election owner (%s)",
   582                      e->name, vote.election_id, vote.op, vote.from,
   583                      vote.election_owner);
   588             crm_debug(
"Not counting %s round %d %s from %s because no election in progress",
   589                       e->name, vote.election_id, vote.op, vote.from);
   592         record_vote(e, &vote);
   598         int age_result = compare_age(vote.age);
   601         if (version_result < 0) {
   605         } 
else if (version_result > 0) {
   608         } 
else if (age_result < 0) {
   612         } 
else if (age_result > 0) {
   615         } 
else if (strcasecmp(e->uname, vote.from) > 0) {
   616             reason = 
"Host name";
   620             reason = 
"Host name";
   624     if (e->expires < tm_now) {
   625         e->election_wins = 0;
   628     } 
else if (done == FALSE && we_lose == FALSE) {
   635         if (e->election_wins > (peers * peers)) {
   636             crm_warn(
"%s election storm detected: %d wins in %d seconds",
   638             e->election_wins = 0;
   640             if (e->wrote_blackbox == FALSE) {
   652                 e->wrote_blackbox = TRUE;
   659                    "Processed %s round %d %s (current round %d) from %s (%s)",
   660                    e->name, vote.election_id, vote.op, e->count, vote.from,
   664     } 
else if (we_lose == FALSE) {
   678         if ((e->last_election_loss == 0)
   679             || ((tm_now - e->last_election_loss) > (time_t) 
LOSS_DAMPEN)) {
   681             do_crm_log(log_level, 
"%s round %d (owner node ID %s) pass: %s from %s (%s)",
   682                        e->name, vote.election_id, vote.election_owner, vote.op,
   685             e->last_election_loss = 0;
   692             char *loss_time = ctime(&e->last_election_loss);
   699             crm_info(
"Ignoring %s round %d (owner node ID %s) pass vs %s because we lost less than %ds ago at %s",
   700                      e->name, vote.election_id, vote.election_owner, vote.from,
   705     e->last_election_loss = tm_now;
   707     do_crm_log(log_level, 
"%s round %d (owner node ID %s) lost: %s from %s (%s)",
   708                e->name, vote.election_id, vote.election_owner, vote.op,
   712     send_no_vote(your_node, &vote);
   725     e->last_election_loss = 0;
 
#define CRM_CHECK(expr, failure_action)
 
crm_node_t * pcmk__get_node(unsigned int id, const char *uname, const char *uuid, uint32_t flags)
 
void mainloop_timer_start(mainloop_timer_t *t)
 
guint mainloop_timer_set_period(mainloop_timer_t *t, guint period_ms)
 
#define PCMK__XA_ELECTION_AGE_NANO_SEC
 
void mainloop_timer_del(mainloop_timer_t *t)
 
Search for cluster nodes from membership cache. 
 
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value. 
 
struct mainloop_timer_s mainloop_timer_t
 
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value. 
 
struct election_s election_t
 
void election_timeout_stop(election_t *e)
Stop an election's timer, if running. 
 
bool pcmk__cluster_send_message(const crm_node_t *node, enum crm_ais_msg_types service, const xmlNode *data)
 
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute. 
 
void mainloop_timer_stop(mainloop_timer_t *t)
 
Wrappers for and extensions to glib mainloop. 
 
void election_clear_dampening(election_t *e)
Reset any election dampening currently in effect. 
 
#define PCMK__XA_CRM_TASK
 
unsigned int pcmk__cluster_num_active_nodes(void)
 
#define crm_warn(fmt, args...)
 
#define crm_debug(fmt, args...)
 
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute. 
 
int crm_element_value_timeval(const xmlNode *data, const char *name_sec, const char *name_usec, struct timeval *dest)
Retrieve the value of XML second/microsecond attributes as time. 
 
void election_vote(election_t *e)
Start a new election by offering local node's candidacy. 
 
#define crm_trace(fmt, args...)
 
#define do_crm_log(level, fmt, args...)
Log a message. 
 
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
 
enum election_result election_state(const election_t *e)
Get current state of an election. 
 
#define PCMK__XA_ELECTION_OWNER
 
Wrappers for and extensions to libxml2. 
 
enum election_result election_count_vote(election_t *e, const xmlNode *message, bool can_win)
Process an election message (vote or no-vote) from a peer. 
 
#define PCMK__XA_ELECTION_AGE_SEC
 
void free_xml(xmlNode *child)
 
#define PCMK__XA_ELECTION_ID
 
void election_timeout_set_period(election_t *e, guint period)
Change an election's timeout (restarting timer if running) 
 
election_t * election_init(const char *name, const char *uname, guint period_ms, GSourceFunc cb)
Create a new election object. 
 
void crm_write_blackbox(int nsig, const struct qb_log_callsite *callsite)
 
void election_fini(election_t *e)
Free an election object. 
 
const char * crm_xml_add_timeval(xmlNode *xml, const char *name_sec, const char *name_usec, const struct timeval *value)
Create XML attributes for seconds and microseconds. 
 
Functions for conducting elections. 
 
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
 
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr. 
 
void election_reset(election_t *e)
Stop election timer and disregard all votes. 
 
#define crm_err(fmt, args...)
 
int compare_version(const char *version1, const char *version2)
 
mainloop_timer_t * mainloop_timer_add(const char *name, guint period_ms, bool repeat, GSourceFunc cb, void *userdata)
 
bool pcmk__cluster_is_node_active(const crm_node_t *node)
 
bool election_check(election_t *e)
Check whether local node has won an election. 
 
#define create_request(task, xml_data, host_to, sys_to, sys_from, uuid_from)
 
GHashTable * crm_peer_cache
 
#define crm_info(fmt, args...)
 
void pcmk__insert_dup(GHashTable *table, const char *name, const char *value)
 
void election_remove(election_t *e, const char *uname)
Disregard any previous vote by specified peer.