Return the anti-affinity score, which is a measure of the amount of * violations of anti-affinity in the current cluster layout, that is, how * badly the masters and slaves are distributed in the different IP * addresses so that slaves of the same master are not in the master * host and are also in different hosts. * * The score is calculated as follows: * * SAME_AS_MASTER = 10000 * each s
| 2998 | * so that the optimizer can try changing the configuration of the |
| 2999 | * slaves violating the anti-affinity goals. */ |
| 3000 | static int clusterManagerGetAntiAffinityScore(clusterManagerNodeArray *ipnodes, |
| 3001 | int ip_count, clusterManagerNode ***offending, int *offending_len) |
| 3002 | { |
| 3003 | int score = 0, i, j; |
| 3004 | int node_len = cluster_manager.nodes->len; |
| 3005 | clusterManagerNode **offending_p = NULL; |
| 3006 | if (offending != NULL) { |
| 3007 | *offending = zcalloc(node_len * sizeof(clusterManagerNode*)); |
| 3008 | offending_p = *offending; |
| 3009 | } |
| 3010 | /* For each set of nodes in the same host, split by |
| 3011 | * related nodes (masters and slaves which are involved in |
| 3012 | * replication of each other) */ |
| 3013 | for (i = 0; i < ip_count; i++) { |
| 3014 | clusterManagerNodeArray *node_array = &(ipnodes[i]); |
| 3015 | dict *related = dictCreate(&clusterManagerDictType, NULL); |
| 3016 | char *ip = NULL; |
| 3017 | for (j = 0; j < node_array->len; j++) { |
| 3018 | clusterManagerNode *node = node_array->nodes[j]; |
| 3019 | if (node == NULL) continue; |
| 3020 | if (!ip) ip = node->ip; |
| 3021 | sds types; |
| 3022 | /* We always use the Master ID as key. */ |
| 3023 | sds key = (!node->replicate ? node->name : node->replicate); |
| 3024 | assert(key != NULL); |
| 3025 | dictEntry *entry = dictFind(related, key); |
| 3026 | if (entry) types = sdsdup((sds) dictGetVal(entry)); |
| 3027 | else types = sdsempty(); |
| 3028 | /* Master type 'm' is always set as the first character of the |
| 3029 | * types string. */ |
| 3030 | if (node->replicate) types = sdscat(types, "s"); |
| 3031 | else { |
| 3032 | sds s = sdscatsds(sdsnew("m"), types); |
| 3033 | sdsfree(types); |
| 3034 | types = s; |
| 3035 | } |
| 3036 | dictReplace(related, key, types); |
| 3037 | } |
| 3038 | /* Now it's trivial to check, for each related group having the |
| 3039 | * same host, what is their local score. */ |
| 3040 | dictIterator *iter = dictGetIterator(related); |
| 3041 | dictEntry *entry; |
| 3042 | while ((entry = dictNext(iter)) != NULL) { |
| 3043 | sds types = (sds) dictGetVal(entry); |
| 3044 | sds name = (sds) dictGetKey(entry); |
| 3045 | int typeslen = sdslen(types); |
| 3046 | if (typeslen < 2) continue; |
| 3047 | if (types[0] == 'm') score += (10000 * (typeslen - 1)); |
| 3048 | else score += (1 * typeslen); |
| 3049 | if (offending == NULL) continue; |
| 3050 | /* Populate the list of offending nodes. */ |
| 3051 | listIter li; |
| 3052 | listNode *ln; |
| 3053 | listRewind(cluster_manager.nodes, &li); |
| 3054 | while ((ln = listNext(&li)) != NULL) { |
| 3055 | clusterManagerNode *n = ln->value; |
| 3056 | if (n->replicate == NULL) continue; |
| 3057 | if (!strcmp(n->replicate, name) && !strcmp(n->ip, ip)) { |
no test coverage detected