root/pengine/utilization.c

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

DEFINITIONS

This source file includes following definitions.
  1. do_compare_capacity1
  2. do_compare_capacity2
  3. compare_capacity
  4. do_calculate_utilization
  5. calculate_utilization
  6. check_capacity
  7. have_enough_capacity
  8. native_add_unallocated_utilization
  9. add_unallocated_utilization
  10. sum_unallocated_utilization
  11. find_colocated_rscs
  12. process_utilization
  13. group_find_colocated_rscs
  14. group_add_unallocated_utilization

   1 /*
   2  * Copyright (C) 2014 Gao,Yan <ygao@suse.com>
   3  *
   4  * This program is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2 of the License, or (at your option) any later version.
   8  *
   9  * This software is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12  * General Public License for more details.
  13  *
  14  * You should have received a copy of the GNU General Public
  15  * License along with this library; if not, write to the Free Software
  16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  17  */
  18 
  19 #include <crm_internal.h>
  20 #include <crm/msg_xml.h>
  21 #include <allocate.h>
  22 #include <utils.h>
  23 
  24 static GListPtr find_colocated_rscs(GListPtr colocated_rscs, resource_t * rsc,
  25                                     resource_t * orig_rsc);
  26 
  27 static GListPtr group_find_colocated_rscs(GListPtr colocated_rscs, resource_t * rsc,
  28                                           resource_t * orig_rsc);
  29 
  30 static void group_add_unallocated_utilization(GHashTable * all_utilization, resource_t * rsc,
  31                                               GListPtr all_rscs);
  32 
  33 struct compare_data {
  34     const node_t *node1;
  35     const node_t *node2;
  36     int result;
  37 };
  38 
  39 static void
  40 do_compare_capacity1(gpointer key, gpointer value, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
  41 {
  42     int node1_capacity = 0;
  43     int node2_capacity = 0;
  44     struct compare_data *data = user_data;
  45 
  46     node1_capacity = crm_parse_int(value, "0");
  47     node2_capacity =
  48         crm_parse_int(g_hash_table_lookup(data->node2->details->utilization, key), "0");
  49 
  50     if (node1_capacity > node2_capacity) {
  51         data->result--;
  52     } else if (node1_capacity < node2_capacity) {
  53         data->result++;
  54     }
  55 }
  56 
  57 static void
  58 do_compare_capacity2(gpointer key, gpointer value, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
  59 {
  60     int node1_capacity = 0;
  61     int node2_capacity = 0;
  62     struct compare_data *data = user_data;
  63 
  64     if (g_hash_table_lookup_extended(data->node1->details->utilization, key, NULL, NULL)) {
  65         return;
  66     }
  67 
  68     node1_capacity = 0;
  69     node2_capacity = crm_parse_int(value, "0");
  70 
  71     if (node1_capacity > node2_capacity) {
  72         data->result--;
  73     } else if (node1_capacity < node2_capacity) {
  74         data->result++;
  75     }
  76 }
  77 
  78 /* rc < 0 if 'node1' has more capacity remaining
  79  * rc > 0 if 'node1' has less capacity remaining
  80  */
  81 int
  82 compare_capacity(const node_t * node1, const node_t * node2)
     /* [previous][next][first][last][top][bottom][index][help] */
  83 {
  84     struct compare_data data;
  85 
  86     data.node1 = node1;
  87     data.node2 = node2;
  88     data.result = 0;
  89 
  90     g_hash_table_foreach(node1->details->utilization, do_compare_capacity1, &data);
  91     g_hash_table_foreach(node2->details->utilization, do_compare_capacity2, &data);
  92 
  93     return data.result;
  94 }
  95 
  96 struct calculate_data {
  97     GHashTable *current_utilization;
  98     gboolean plus;
  99 };
 100 
 101 static void
 102 do_calculate_utilization(gpointer key, gpointer value, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 103 {
 104     const char *current = NULL;
 105     char *result = NULL;
 106     struct calculate_data *data = user_data;
 107 
 108     current = g_hash_table_lookup(data->current_utilization, key);
 109     if (data->plus) {
 110         result = crm_itoa(crm_parse_int(current, "0") + crm_parse_int(value, "0"));
 111         g_hash_table_replace(data->current_utilization, strdup(key), result);
 112 
 113     } else if (current) {
 114         result = crm_itoa(crm_parse_int(current, "0") - crm_parse_int(value, "0"));
 115         g_hash_table_replace(data->current_utilization, strdup(key), result);
 116     }
 117 }
 118 
 119 /* Specify 'plus' to FALSE when allocating
 120  * Otherwise to TRUE when deallocating
 121  */
 122 void
 123 calculate_utilization(GHashTable * current_utilization,
     /* [previous][next][first][last][top][bottom][index][help] */
 124                       GHashTable * utilization, gboolean plus)
 125 {
 126     struct calculate_data data;
 127 
 128     data.current_utilization = current_utilization;
 129     data.plus = plus;
 130 
 131     g_hash_table_foreach(utilization, do_calculate_utilization, &data);
 132 }
 133 
 134 
 135 struct capacity_data {
 136     node_t *node;
 137     const char *rsc_id;
 138     gboolean is_enough;
 139 };
 140 
 141 static void
 142 check_capacity(gpointer key, gpointer value, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 143 {
 144     int required = 0;
 145     int remaining = 0;
 146     struct capacity_data *data = user_data;
 147 
 148     required = crm_parse_int(value, "0");
 149     remaining = crm_parse_int(g_hash_table_lookup(data->node->details->utilization, key), "0");
 150 
 151     if (required > remaining) {
 152         CRM_ASSERT(data->rsc_id);
 153         CRM_ASSERT(data->node);
 154 
 155         crm_debug("Node %s does not have enough %s for %s: required=%d remaining=%d",
 156                   data->node->details->uname, (char *)key, data->rsc_id, required, remaining);
 157         data->is_enough = FALSE;
 158     }
 159 }
 160 
 161 static gboolean
 162 have_enough_capacity(node_t * node, const char * rsc_id, GHashTable * utilization)
     /* [previous][next][first][last][top][bottom][index][help] */
 163 {
 164     struct capacity_data data;
 165 
 166     data.node = node;
 167     data.rsc_id = rsc_id;
 168     data.is_enough = TRUE;
 169 
 170     g_hash_table_foreach(utilization, check_capacity, &data);
 171 
 172     return data.is_enough;
 173 }
 174 
 175 
 176 static void
 177 native_add_unallocated_utilization(GHashTable * all_utilization, resource_t * rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 178 {
 179     if(is_set(rsc->flags, pe_rsc_provisional) == FALSE) {
 180         return;
 181     }
 182 
 183     calculate_utilization(all_utilization, rsc->utilization, TRUE);
 184 }
 185 
 186 static void
 187 add_unallocated_utilization(GHashTable * all_utilization, resource_t * rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
 188                     GListPtr all_rscs, resource_t * orig_rsc)
 189 {
 190     if(is_set(rsc->flags, pe_rsc_provisional) == FALSE) {
 191         return;
 192     }
 193 
 194     if (rsc->variant == pe_native) {
 195         pe_rsc_trace(orig_rsc, "%s: Adding %s as colocated utilization",
 196                      orig_rsc->id, rsc->id);
 197         native_add_unallocated_utilization(all_utilization, rsc);
 198 
 199     } else if (rsc->variant == pe_group) {
 200         pe_rsc_trace(orig_rsc, "%s: Adding %s as colocated utilization",
 201                      orig_rsc->id, rsc->id);
 202         group_add_unallocated_utilization(all_utilization, rsc, all_rscs);
 203 
 204     } else if (pe_rsc_is_clone(rsc)) {
 205         GListPtr gIter1 = NULL;
 206         gboolean existing = FALSE;
 207 
 208         /* Check if there's any child already existing in the list */
 209         gIter1 = rsc->children;
 210         for (; gIter1 != NULL; gIter1 = gIter1->next) {
 211             resource_t *child = (resource_t *) gIter1->data;
 212             GListPtr gIter2 = NULL;
 213 
 214             if (g_list_find(all_rscs, child)) {
 215                 existing = TRUE;
 216 
 217             } else {
 218                 /* Check if there's any child of another cloned group already existing in the list */
 219                 gIter2 = child->children;
 220                 for (; gIter2 != NULL; gIter2 = gIter2->next) {
 221                     resource_t *grandchild = (resource_t *) gIter2->data;
 222 
 223                     if (g_list_find(all_rscs, grandchild)) {
 224                         pe_rsc_trace(orig_rsc, "%s: Adding %s as colocated utilization",
 225                                      orig_rsc->id, child->id);
 226                         add_unallocated_utilization(all_utilization, child, all_rscs, orig_rsc);
 227                         existing = TRUE;
 228                         break;
 229                     }
 230                 }
 231             }
 232         }
 233 
 234         if (existing == FALSE) {
 235             resource_t *first_child = (resource_t *) rsc->children->data;
 236 
 237             pe_rsc_trace(orig_rsc, "%s: Adding %s as colocated utilization",
 238                          orig_rsc->id, ID(first_child->xml));
 239             add_unallocated_utilization(all_utilization, first_child, all_rscs, orig_rsc);
 240         }
 241     }
 242 }
 243 
 244 static GHashTable *
 245 sum_unallocated_utilization(resource_t * rsc, GListPtr colocated_rscs)
     /* [previous][next][first][last][top][bottom][index][help] */
 246 {
 247     GListPtr gIter = NULL;
 248     GListPtr all_rscs = NULL;
 249     GHashTable *all_utilization = crm_str_table_new();
 250 
 251     all_rscs = g_list_copy(colocated_rscs);
 252     if (g_list_find(all_rscs, rsc) == FALSE) {
 253         all_rscs = g_list_append(all_rscs, rsc);
 254     }
 255 
 256     for (gIter = all_rscs; gIter != NULL; gIter = gIter->next) {
 257         resource_t *listed_rsc = (resource_t *) gIter->data;
 258 
 259         if(is_set(listed_rsc->flags, pe_rsc_provisional) == FALSE) {
 260             continue;
 261         }
 262 
 263         pe_rsc_trace(rsc, "%s: Processing unallocated colocated %s", rsc->id, listed_rsc->id);
 264         add_unallocated_utilization(all_utilization, listed_rsc, all_rscs, rsc);
 265     }
 266 
 267     g_list_free(all_rscs);
 268 
 269     return all_utilization;
 270 }
 271 
 272 static GListPtr
 273 find_colocated_rscs(GListPtr colocated_rscs, resource_t * rsc, resource_t * orig_rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 274 {
 275     GListPtr gIter = NULL;
 276 
 277     if (rsc == NULL) {
 278         return colocated_rscs;
 279 
 280     } else if (g_list_find(colocated_rscs, rsc)) {
 281         return colocated_rscs;
 282     }
 283 
 284     crm_trace("%s: %s is supposed to be colocated with %s", orig_rsc->id, rsc->id, orig_rsc->id);
 285     colocated_rscs = g_list_append(colocated_rscs, rsc);
 286 
 287     for (gIter = rsc->rsc_cons; gIter != NULL; gIter = gIter->next) {
 288         rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
 289         resource_t *rsc_rh = constraint->rsc_rh;
 290 
 291         /* Break colocation loop */
 292         if (rsc_rh == orig_rsc) {
 293             continue;
 294         }
 295 
 296         if (constraint->score == INFINITY
 297             && filter_colocation_constraint(rsc, rsc_rh, constraint, TRUE) == influence_rsc_location) {
 298 
 299             if (rsc_rh->variant == pe_group) {
 300                 /* Need to use group_variant_data */
 301                 colocated_rscs = group_find_colocated_rscs(colocated_rscs, rsc_rh, orig_rsc);
 302 
 303             } else {
 304                 colocated_rscs = find_colocated_rscs(colocated_rscs, rsc_rh, orig_rsc);
 305             }
 306         }
 307     }
 308 
 309     for (gIter = rsc->rsc_cons_lhs; gIter != NULL; gIter = gIter->next) {
 310         rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
 311         resource_t *rsc_lh = constraint->rsc_lh;
 312 
 313         /* Break colocation loop */
 314         if (rsc_lh == orig_rsc) {
 315             continue;
 316         }
 317 
 318         if (pe_rsc_is_clone(rsc_lh) == FALSE && pe_rsc_is_clone(rsc)) {
 319             /* We do not know if rsc_lh will be colocated with orig_rsc in this case */
 320             continue;
 321         }
 322 
 323         if (constraint->score == INFINITY
 324             && filter_colocation_constraint(rsc_lh, rsc, constraint, TRUE) == influence_rsc_location) {
 325 
 326             if (rsc_lh->variant == pe_group) {
 327                 /* Need to use group_variant_data */
 328                 colocated_rscs = group_find_colocated_rscs(colocated_rscs, rsc_lh, orig_rsc);
 329 
 330             } else {
 331                 colocated_rscs = find_colocated_rscs(colocated_rscs, rsc_lh, orig_rsc);
 332             }
 333         }
 334     }
 335 
 336     return colocated_rscs;
 337 }
 338 
 339 void
 340 process_utilization(resource_t * rsc, node_t ** prefer, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 341 {
 342     int alloc_details = scores_log_level + 1;
 343 
 344     if (safe_str_neq(data_set->placement_strategy, "default")) {
 345         GHashTableIter iter;
 346         GListPtr colocated_rscs = NULL;
 347         gboolean any_capable = FALSE;
 348         node_t *node = NULL;
 349 
 350         colocated_rscs = find_colocated_rscs(colocated_rscs, rsc, rsc);
 351         if (colocated_rscs) {
 352             GHashTable *unallocated_utilization = NULL;
 353             char *rscs_id = crm_concat(rsc->id, "and its colocated resources", ' ');
 354             node_t *most_capable_node = NULL;
 355 
 356             unallocated_utilization = sum_unallocated_utilization(rsc, colocated_rscs);
 357 
 358             g_hash_table_iter_init(&iter, rsc->allowed_nodes);
 359             while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
 360                 if (can_run_resources(node) == FALSE || node->weight < 0) {
 361                     continue;
 362                 }
 363 
 364                 if (have_enough_capacity(node, rscs_id, unallocated_utilization)) {
 365                     any_capable = TRUE;
 366                 }
 367 
 368                 if (most_capable_node == NULL ||
 369                     compare_capacity(node, most_capable_node) < 0) {
 370                     /* < 0 means 'node' is more capable */
 371                     most_capable_node = node;
 372                 }
 373             }
 374 
 375             if (any_capable) {
 376                 g_hash_table_iter_init(&iter, rsc->allowed_nodes);
 377                 while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
 378                     if (can_run_resources(node) == FALSE || node->weight < 0) {
 379                         continue;
 380                     }
 381 
 382                     if (have_enough_capacity(node, rscs_id, unallocated_utilization) == FALSE) {
 383                         pe_rsc_debug(rsc,
 384                                      "Resource %s and its colocated resources"
 385                                      " cannot be allocated to node %s: not enough capacity",
 386                                      rsc->id, node->details->uname);
 387                         resource_location(rsc, node, -INFINITY, "__limit_utilization__", data_set);
 388                     }
 389                 }
 390 
 391             } else if (*prefer == NULL) {
 392                 *prefer = most_capable_node;
 393             }
 394 
 395             if (unallocated_utilization) {
 396                 g_hash_table_destroy(unallocated_utilization);
 397             }
 398 
 399             g_list_free(colocated_rscs);
 400             free(rscs_id);
 401         }
 402 
 403         if (any_capable == FALSE) {
 404             g_hash_table_iter_init(&iter, rsc->allowed_nodes);
 405             while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
 406                 if (can_run_resources(node) == FALSE || node->weight < 0) {
 407                     continue;
 408                 }
 409 
 410                 if (have_enough_capacity(node, rsc->id, rsc->utilization) == FALSE) {
 411                     pe_rsc_debug(rsc,
 412                                  "Resource %s cannot be allocated to node %s:"
 413                                  " not enough capacity",
 414                                  rsc->id, node->details->uname);
 415                     resource_location(rsc, node, -INFINITY, "__limit_utilization__", data_set);
 416                 }
 417             }
 418         }
 419         dump_node_scores(alloc_details, rsc, "Post-utilization", rsc->allowed_nodes);
 420     }
 421 }
 422 
 423 #define VARIANT_GROUP 1
 424 #include <lib/pengine/variant.h>
 425 
 426 GListPtr
 427 group_find_colocated_rscs(GListPtr colocated_rscs, resource_t * rsc, resource_t * orig_rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 428 {
 429     group_variant_data_t *group_data = NULL;
 430 
 431     get_group_variant_data(group_data, rsc);
 432     if (group_data->colocated || pe_rsc_is_clone(rsc->parent)) {
 433         GListPtr gIter = rsc->children;
 434 
 435         for (; gIter != NULL; gIter = gIter->next) {
 436             resource_t *child_rsc = (resource_t *) gIter->data;
 437 
 438             colocated_rscs = find_colocated_rscs(colocated_rscs, child_rsc, orig_rsc);
 439         }
 440 
 441     } else {
 442         if (group_data->first_child) {
 443             colocated_rscs = find_colocated_rscs(colocated_rscs, group_data->first_child, orig_rsc);
 444         }
 445     }
 446 
 447     colocated_rscs = find_colocated_rscs(colocated_rscs, rsc, orig_rsc);
 448 
 449     return colocated_rscs;
 450 }
 451 
 452 static void
 453 group_add_unallocated_utilization(GHashTable * all_utilization, resource_t * rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
 454                                   GListPtr all_rscs)
 455 {
 456     group_variant_data_t *group_data = NULL;
 457 
 458     get_group_variant_data(group_data, rsc);
 459     if (group_data->colocated || pe_rsc_is_clone(rsc->parent)) {
 460         GListPtr gIter = rsc->children;
 461 
 462         for (; gIter != NULL; gIter = gIter->next) {
 463             resource_t *child_rsc = (resource_t *) gIter->data;
 464 
 465             if (is_set(child_rsc->flags, pe_rsc_provisional) &&
 466                 g_list_find(all_rscs, child_rsc) == FALSE) {
 467                 native_add_unallocated_utilization(all_utilization, child_rsc);
 468             }
 469         }
 470 
 471     } else {
 472         if (group_data->first_child &&
 473             is_set(group_data->first_child->flags, pe_rsc_provisional) &&
 474             g_list_find(all_rscs, group_data->first_child) == FALSE) {
 475             native_add_unallocated_utilization(all_utilization, group_data->first_child);
 476         }
 477     }
 478 }
 479 
 480 

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