/* search the node lists list for a node to takeover this ip. pick the node that currently are serving the least number of ips so that the ips get spread out evenly. */ int find_takeover_node(struct ipalloc_state *ipalloc_state, struct public_ip_list *ip) { int pnn, min=0, num; int i, numnodes; numnodes = ipalloc_state->num; pnn = -1; for (i=0; i<numnodes; i++) { /* verify that this node can serve this ip */ if (!can_node_takeover_ip(ipalloc_state, i, ip)) { /* no it couldnt so skip to the next node */ continue; } num = node_ip_coverage(i, ipalloc_state->all_ips); /* was this the first node we checked ? */ if (pnn == -1) { pnn = i; min = num; } else { if (num < min) { pnn = i; min = num; } } } if (pnn == -1) { DEBUG(DEBUG_WARNING,(__location__ " Could not find node to take over public address '%s'\n", ctdb_sock_addr_to_string(ipalloc_state, &ip->addr))); return -1; } ip->pnn = pnn; return 0; }
/* LCP2 algorithm for rebalancing the cluster. Given a candidate node * to move IPs from, determines the best IP/destination node * combination to move from the source node. */ static bool lcp2_failback_candidate(struct ipalloc_state *ipalloc_state, int srcnode, uint32_t *lcp2_imbalances, bool *rebalance_candidates) { int dstnode, mindstnode, numnodes; uint32_t srcimbl, srcdsum, dstimbl, dstdsum; uint32_t minsrcimbl, mindstimbl; struct public_ip_list *minip; struct public_ip_list *t; /* Find an IP and destination node that best reduces imbalance. */ srcimbl = 0; minip = NULL; minsrcimbl = 0; mindstnode = -1; mindstimbl = 0; numnodes = ipalloc_state->num; DEBUG(DEBUG_DEBUG,(" ----------------------------------------\n")); DEBUG(DEBUG_DEBUG,(" CONSIDERING MOVES FROM %d [%d]\n", srcnode, lcp2_imbalances[srcnode])); for (t = ipalloc_state->all_ips; t != NULL; t = t->next) { /* Only consider addresses on srcnode. */ if (t->pnn != srcnode) { continue; } /* What is this IP address costing the source node? */ srcdsum = ip_distance_2_sum(&(t->addr), ipalloc_state->all_ips, srcnode); srcimbl = lcp2_imbalances[srcnode] - srcdsum; /* Consider this IP address would cost each potential * destination node. Destination nodes are limited to * those that are newly healthy, since we don't want * to do gratuitous failover of IPs just to make minor * balance improvements. */ for (dstnode = 0; dstnode < numnodes; dstnode++) { if (!rebalance_candidates[dstnode]) { continue; } /* only check nodes that can actually takeover this ip */ if (!can_node_takeover_ip(ipalloc_state, dstnode, t)) { /* no it couldnt so skip to the next node */ continue; } dstdsum = ip_distance_2_sum(&(t->addr), ipalloc_state->all_ips, dstnode); dstimbl = lcp2_imbalances[dstnode] + dstdsum; DEBUG(DEBUG_DEBUG,(" %d [%d] -> %s -> %d [+%d]\n", srcnode, -srcdsum, ctdb_sock_addr_to_string( ipalloc_state, &(t->addr)), dstnode, dstdsum)); if ((dstimbl < lcp2_imbalances[srcnode]) && (dstdsum < srcdsum) && \ ((mindstnode == -1) || \ ((srcimbl + dstimbl) < (minsrcimbl + mindstimbl)))) { minip = t; minsrcimbl = srcimbl; mindstnode = dstnode; mindstimbl = dstimbl; } } } DEBUG(DEBUG_DEBUG,(" ----------------------------------------\n")); if (mindstnode != -1) { /* We found a move that makes things better... */ DEBUG(DEBUG_INFO, ("%d [%d] -> %s -> %d [+%d]\n", srcnode, minsrcimbl - lcp2_imbalances[srcnode], ctdb_sock_addr_to_string(ipalloc_state, &(minip->addr)), mindstnode, mindstimbl - lcp2_imbalances[mindstnode])); lcp2_imbalances[srcnode] = minsrcimbl; lcp2_imbalances[mindstnode] = mindstimbl; minip->pnn = mindstnode; return true; } return false; }
/* Allocate any unassigned addresses using the LCP2 algorithm to find * the IP/node combination that will cost the least. */ static void lcp2_allocate_unassigned(struct ipalloc_state *ipalloc_state, uint32_t *lcp2_imbalances) { struct public_ip_list *t; int dstnode, numnodes; int minnode; uint32_t mindsum, dstdsum, dstimbl; uint32_t minimbl = 0; struct public_ip_list *minip; bool should_loop = true; bool have_unassigned = true; numnodes = ipalloc_state->num; while (have_unassigned && should_loop) { should_loop = false; DEBUG(DEBUG_DEBUG,(" ----------------------------------------\n")); DEBUG(DEBUG_DEBUG,(" CONSIDERING MOVES (UNASSIGNED)\n")); minnode = -1; mindsum = 0; minip = NULL; /* loop over each unassigned ip. */ for (t = ipalloc_state->all_ips; t != NULL ; t = t->next) { if (t->pnn != -1) { continue; } for (dstnode = 0; dstnode < numnodes; dstnode++) { /* only check nodes that can actually takeover this ip */ if (!can_node_takeover_ip(ipalloc_state, dstnode, t)) { /* no it couldnt so skip to the next node */ continue; } dstdsum = ip_distance_2_sum(&(t->addr), ipalloc_state->all_ips, dstnode); dstimbl = lcp2_imbalances[dstnode] + dstdsum; DEBUG(DEBUG_DEBUG, (" %s -> %d [+%d]\n", ctdb_sock_addr_to_string(ipalloc_state, &(t->addr)), dstnode, dstimbl - lcp2_imbalances[dstnode])); if ((minnode == -1) || (dstdsum < mindsum)) { minnode = dstnode; minimbl = dstimbl; mindsum = dstdsum; minip = t; should_loop = true; } } } DEBUG(DEBUG_DEBUG,(" ----------------------------------------\n")); /* If we found one then assign it to the given node. */ if (minnode != -1) { minip->pnn = minnode; lcp2_imbalances[minnode] = minimbl; DEBUG(DEBUG_INFO,(" %s -> %d [+%d]\n", ctdb_sock_addr_to_string( ipalloc_state, &(minip->addr)), minnode, mindsum)); } /* There might be a better way but at least this is clear. */ have_unassigned = false; for (t = ipalloc_state->all_ips; t != NULL; t = t->next) { if (t->pnn == -1) { have_unassigned = true; } } } /* We know if we have an unassigned addresses so we might as * well optimise. */ if (have_unassigned) { for (t = ipalloc_state->all_ips; t != NULL; t = t->next) { if (t->pnn == -1) { DEBUG(DEBUG_WARNING, ("Failed to find node to cover ip %s\n", ctdb_sock_addr_to_string(ipalloc_state, &t->addr))); } } } }