diff --git a/core/legion.c b/core/legion.c index f7afedb6..c1d35526 100644 --- a/core/legion.c +++ b/core/legion.c @@ -203,9 +203,9 @@ static void legions_check_nodes() { struct uwsgi_legion_node *uwsgi_legion_get_lord(struct uwsgi_legion *); -static void legions_report_quorum(struct uwsgi_legion *ul, uint64_t best_valor, char *best_uuid) { +static void legions_report_quorum(struct uwsgi_legion *ul, uint64_t best_valor, char *best_uuid, int votes) { struct uwsgi_legion_node *nodes = ul->nodes_head; - uwsgi_log("\n[uwsgi-legion] --- WE HAVE QUORUM FOR LEGION %s !!! (valor: %llu uuid: %.*s checksum: %llu) ---\n", ul->legion, best_valor, 36, best_uuid, ul->checksum); + uwsgi_log("\n[uwsgi-legion] --- WE HAVE QUORUM FOR LEGION %s !!! (valor: %llu uuid: %.*s checksum: %llu votes: %d) ---\n", ul->legion, best_valor, 36, best_uuid, ul->checksum, votes); while (nodes) { uwsgi_log("[uwsgi-legion-node] node: %.*s valor: %llu uuid: %.*s last_seen: %d vote_valor: %llu vote_uuid: %.*s\n", nodes->name_len, nodes->name, nodes->valor, 36, nodes->uuid, nodes->last_seen, nodes->lord_valor, 36, nodes->lord_uuid); nodes = nodes->next; @@ -258,34 +258,29 @@ static void legions_check_nodes_step2() { // ... ok let's see if all of the nodes agree on the lord // ... but first check if i am not alone... - int have_quorum = 0; - if (!ul->nodes_head) { - have_quorum = 1; - } - else { - struct uwsgi_legion_node *nodes = ul->nodes_head; - while (nodes) { - if (nodes->checksum != ul->checksum) { - have_quorum = 0; - break; - } - if (nodes->lord_valor != best_valor) { - have_quorum = 0; - break; - } - if (memcmp(nodes->lord_uuid, best_uuid, 36)) { - have_quorum = 0; - break; - } - have_quorum++; - nodes = nodes->next; + int votes = 1; + struct uwsgi_legion_node *nodes = ul->nodes_head; + while (nodes) { + if (nodes->checksum != ul->checksum) { + votes = 0; + break; } + if (nodes->lord_valor != best_valor) { + votes = 0; + break; + } + if (memcmp(nodes->lord_uuid, best_uuid, 36)) { + votes = 0; + break; + } + votes++; + nodes = nodes->next; } - if (have_quorum) { + if (votes >= ul->quorum) { if (i_am_the_best) { if (!ul->i_am_the_lord) { - legions_report_quorum(ul, best_valor, best_uuid); + legions_report_quorum(ul, best_valor, best_uuid, votes); uwsgi_log("[uwsgi-legion] i am now the Lord of the Legion %s\n", ul->legion); // triggering lord hooks struct uwsgi_string_list *usl = ul->lord_hooks; @@ -301,7 +296,7 @@ static void legions_check_nodes_step2() { } else { if (ul->i_am_the_lord) { - legions_report_quorum(ul, best_valor, best_uuid); + legions_report_quorum(ul, best_valor, best_uuid, votes); uwsgi_log("[uwsgi-legion] a new Lord (valor: %llu uuid: %.*s) raised for Legion %s...\n", ul->lord_valor, 36, ul->lord_uuid, ul->legion); // no more lord, trigger unlord hooks struct uwsgi_string_list *usl = ul->unlord_hooks; @@ -370,6 +365,7 @@ static void *legion_loop(void *foobar) { if (!uwsgi.legion_tolerance) uwsgi.legion_tolerance = 15; + int first_round = 1; for (;;) { int timeout = uwsgi.legion_freq; time_t now = uwsgi_now(); @@ -489,35 +485,12 @@ static void *legion_loop(void *foobar) { } + // skip the first round if i no packet is received + if (first_round) { + first_round = 0; + continue; + } legions_check_nodes_step2(); - -/* - if (ul->lord > 0) { - if (legion_msg.valor > ul->valor) { - uwsgi_log("[uwsgi-legion] a new Lord (name: %.*s pid: %d) raised for Legion %s...\n", legion_msg.name_len, legion_msg.name, (int) legion_msg.pid, ul->legion); - // no more lord, trigger unlord hooks - struct uwsgi_string_list *usl = ul->unlord_hooks; - while(usl) { - int ret = uwsgi_legion_action_call("unlord", ul, usl); - if (ret) { - uwsgi_log("[uwsgi-legion] ERROR, unlord hook returned: %d\n", ret); - } - usl = usl->next; - } - ul->last_seen_lord = uwsgi_now(); - ul->lord = 0; - continue; - } - } - - if (legion_msg.valor > ul->valor) { - // a lord - ul->last_seen_lord = uwsgi_now(); - } - else if (legion_msg.valor == ul->valor) { - uwsgi_log("[uwsgi-legion] a node with the same valor announced itself !!!\n"); - } -*/ } return NULL; @@ -697,6 +670,27 @@ void uwsgi_opt_legion_node(char *opt, char *value, void *foobar) { usl->custom_ptr = sin; } +void uwsgi_opt_legion_quorum(char *opt, char *value, void *foobar) { + + char *legion = uwsgi_str(value); + + char *space = strchr(legion, ' '); + if (!space) { + uwsgi_log("invalid legion-quorum syntax, must be \n"); + exit(1); + } + *space = 0; + + struct uwsgi_legion *ul = uwsgi_legion_get_by_name(legion); + if (!ul) { + uwsgi_log("unknown legion: %s\n", legion); + exit(1); + } + + ul->quorum = atoi(space+1); +} + + void uwsgi_opt_legion_hook(char *opt, char *value, void *foobar) { char *legion = uwsgi_str(value); diff --git a/core/uwsgi.c b/core/uwsgi.c index 9b71528f..b75fcd23 100644 --- a/core/uwsgi.c +++ b/core/uwsgi.c @@ -340,6 +340,7 @@ static struct uwsgi_option uwsgi_base_options[] = { {"legion-unlord", required_argument, 0, "action to call on Lord dismiss", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER}, {"legion-setup", required_argument, 0, "action to call on legion setup", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER}, {"legion-death", required_argument, 0, "action to call on legion death (shutdown of the instance)", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER}, + {"legion-quorum", required_argument, 0, "set the quorum of a legion", uwsgi_opt_legion_quorum, NULL, UWSGI_OPT_MASTER}, {"subscriptions-sign-check", required_argument, 0, "set digest algorithm and certificate directory for secured subscription system", uwsgi_opt_scd, NULL, UWSGI_OPT_MASTER}, {"subscriptions-sign-check-tolerance", required_argument, 0, "set the maximum tolerance (in seconds) of clock skew for secured subscription system", uwsgi_opt_set_int, &uwsgi.subscriptions_sign_check_tolerance, UWSGI_OPT_MASTER}, #endif diff --git a/uwsgi.h b/uwsgi.h index 7aac0af3..3ebdb84e 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -541,7 +541,10 @@ struct uwsgi_legion { char uuid[37]; int socket; + int quorum; + uint64_t checksum; + char lord_uuid[36]; uint64_t lord_valor; @@ -3606,6 +3609,7 @@ char *uwsgi_strip(char *); #ifdef UWSGI_SSL void uwsgi_opt_legion(char *, char *, void *); void uwsgi_opt_legion_node(char *, char *, void *); +void uwsgi_opt_legion_quorum(char *, char *, void *); void uwsgi_opt_legion_hook(char *, char *, void *); void uwsgi_legion_add(struct uwsgi_legion *); char *uwsgi_ssl_rand(size_t);