This source file includes following definitions.
- do_compare_capacity1
- do_compare_capacity2
- compare_capacity
- do_calculate_utilization
- calculate_utilization
- check_capacity
- have_enough_capacity
- native_add_unallocated_utilization
- add_unallocated_utilization
- sum_unallocated_utilization
- find_colocated_rscs
- process_utilization
- group_find_colocated_rscs
- group_add_unallocated_utilization
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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)
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)
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
79
80
81 int
82 compare_capacity(const node_t * node1, const node_t * node2)
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)
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
120
121
122 void
123 calculate_utilization(GHashTable * current_utilization,
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)
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)
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)
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,
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
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
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)
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)
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
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
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
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
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
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)
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
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)
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,
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