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