This source file includes following definitions.
- utilization_value
- compare_utilization_value
- pcmk__compare_node_capacities
- update_utilization_value
- pcmk__consume_node_capacity
- pcmk__release_node_capacity
- check_capacity
- have_enough_capacity
- sum_resource_utilization
- pcmk__ban_insufficient_capacity
- new_load_stopped_op
- pcmk__create_utilization_constraints
- pcmk__show_node_capacities
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 #include "libpacemaker_private.h"
15
16
17
18
19
20
21
22
23
24
25
26
27
28 static int
29 utilization_value(const char *s)
30 {
31 int value = 0;
32
33 if ((s != NULL) && (pcmk__scan_min_int(s, &value, INT_MIN) == EINVAL)) {
34 pe_warn("Using 0 for utilization instead of invalid value '%s'", value);
35 value = 0;
36 }
37 return value;
38 }
39
40
41
42
43
44
45 struct compare_data {
46 const pe_node_t *node1;
47 const pe_node_t *node2;
48 bool node2_only;
49 int result;
50 };
51
52
53
54
55
56
57
58
59
60
61
62
63
64 static void
65 compare_utilization_value(gpointer key, gpointer value, gpointer user_data)
66 {
67 int node1_capacity = 0;
68 int node2_capacity = 0;
69 struct compare_data *data = user_data;
70 const char *node2_value = NULL;
71
72 if (data->node2_only) {
73 if (g_hash_table_lookup(data->node1->details->utilization, key)) {
74 return;
75 }
76 } else {
77 node1_capacity = utilization_value((const char *) value);
78 }
79
80 node2_value = g_hash_table_lookup(data->node2->details->utilization, key);
81 node2_capacity = utilization_value(node2_value);
82
83 if (node1_capacity > node2_capacity) {
84 data->result--;
85 } else if (node1_capacity < node2_capacity) {
86 data->result++;
87 }
88 }
89
90
91
92
93
94
95
96
97
98
99
100
101 int
102 pcmk__compare_node_capacities(const pe_node_t *node1, const pe_node_t *node2)
103 {
104 struct compare_data data = {
105 .node1 = node1,
106 .node2 = node2,
107 .node2_only = false,
108 .result = 0,
109 };
110
111
112 g_hash_table_foreach(node1->details->utilization, compare_utilization_value,
113 &data);
114
115
116 data.node2_only = true;
117 g_hash_table_foreach(node2->details->utilization, compare_utilization_value,
118 &data);
119
120 return data.result;
121 }
122
123
124
125
126
127
128 struct calculate_data {
129 GHashTable *current_utilization;
130 bool plus;
131 };
132
133
134
135
136
137
138
139
140
141 static void
142 update_utilization_value(gpointer key, gpointer value, gpointer user_data)
143 {
144 int result = 0;
145 const char *current = NULL;
146 struct calculate_data *data = user_data;
147
148 current = g_hash_table_lookup(data->current_utilization, key);
149 if (data->plus) {
150 result = utilization_value(current) + utilization_value(value);
151 } else if (current) {
152 result = utilization_value(current) - utilization_value(value);
153 }
154 g_hash_table_replace(data->current_utilization,
155 strdup(key), pcmk__itoa(result));
156 }
157
158
159
160
161
162
163
164
165 void
166 pcmk__consume_node_capacity(GHashTable *current_utilization, pe_resource_t *rsc)
167 {
168 struct calculate_data data = {
169 .current_utilization = current_utilization,
170 .plus = false,
171 };
172
173 g_hash_table_foreach(rsc->utilization, update_utilization_value, &data);
174 }
175
176
177
178
179
180
181
182
183 void
184 pcmk__release_node_capacity(GHashTable *current_utilization, pe_resource_t *rsc)
185 {
186 struct calculate_data data = {
187 .current_utilization = current_utilization,
188 .plus = true,
189 };
190
191 g_hash_table_foreach(rsc->utilization, update_utilization_value, &data);
192 }
193
194
195
196
197
198
199 struct capacity_data {
200 pe_node_t *node;
201 const char *rsc_id;
202 bool is_enough;
203 };
204
205
206
207
208
209
210
211
212
213 static void
214 check_capacity(gpointer key, gpointer value, gpointer user_data)
215 {
216 int required = 0;
217 int remaining = 0;
218 const char *node_value_s = NULL;
219 struct capacity_data *data = user_data;
220
221 node_value_s = g_hash_table_lookup(data->node->details->utilization, key);
222
223 required = utilization_value(value);
224 remaining = utilization_value(node_value_s);
225
226 if (required > remaining) {
227 crm_debug("Remaining capacity for %s on %s (%d) is insufficient "
228 "for resource %s usage (%d)",
229 (const char *) key, data->node->details->uname, remaining,
230 data->rsc_id, required);
231 data->is_enough = false;
232 }
233 }
234
235
236
237
238
239
240
241
242
243
244
245 static bool
246 have_enough_capacity(pe_node_t *node, const char *rsc_id,
247 GHashTable *utilization)
248 {
249 struct capacity_data data = {
250 .node = node,
251 .rsc_id = rsc_id,
252 .is_enough = true,
253 };
254
255 g_hash_table_foreach(utilization, check_capacity, &data);
256 return data.is_enough;
257 }
258
259
260
261
262
263
264
265
266
267
268
269
270 static GHashTable *
271 sum_resource_utilization(pe_resource_t *orig_rsc, GList *rscs)
272 {
273 GHashTable *utilization = pcmk__strkey_table(free, free);
274
275 for (GList *iter = rscs; iter != NULL; iter = iter->next) {
276 pe_resource_t *rsc = (pe_resource_t *) iter->data;
277
278 rsc->cmds->add_utilization(rsc, orig_rsc, rscs, utilization);
279 }
280 return utilization;
281 }
282
283
284
285
286
287
288
289
290
291 void
292 pcmk__ban_insufficient_capacity(pe_resource_t *rsc, pe_node_t **prefer,
293 pe_working_set_t *data_set)
294 {
295 bool any_capable = false;
296 char *rscs_id = NULL;
297 pe_node_t *node = NULL;
298 pe_node_t *most_capable_node = NULL;
299 GList *colocated_rscs = NULL;
300 GHashTable *unallocated_utilization = NULL;
301 GHashTableIter iter;
302
303 CRM_CHECK((rsc != NULL) && (prefer != NULL) && (data_set != NULL), return);
304
305
306 if (pcmk__str_eq(data_set->placement_strategy, "default",
307 pcmk__str_casei)) {
308 return;
309 }
310
311
312 colocated_rscs = rsc->cmds->colocated_resources(rsc, NULL, NULL);
313 if (colocated_rscs == NULL) {
314 return;
315 }
316
317 rscs_id = crm_strdup_printf("%s and its colocated resources", rsc->id);
318
319
320 if (g_list_find(colocated_rscs, rsc) == NULL) {
321 colocated_rscs = g_list_append(colocated_rscs, rsc);
322 }
323
324
325 unallocated_utilization = sum_resource_utilization(rsc, colocated_rscs);
326
327
328 g_hash_table_iter_init(&iter, rsc->allowed_nodes);
329 while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
330 if (!pcmk__node_available(node) || (node->weight < 0)) {
331 continue;
332 }
333
334 if (have_enough_capacity(node, rscs_id, unallocated_utilization)) {
335 any_capable = true;
336 }
337
338
339 if ((most_capable_node == NULL)
340 || (pcmk__compare_node_capacities(node, most_capable_node) < 0)) {
341 most_capable_node = node;
342 }
343 }
344
345 if (any_capable) {
346
347 g_hash_table_iter_init(&iter, rsc->allowed_nodes);
348 while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
349 if ((node->weight >= 0) && pcmk__node_available(node)
350 && !have_enough_capacity(node, rscs_id,
351 unallocated_utilization)) {
352 pe_rsc_debug(rsc, "%s does not have enough capacity for %s",
353 node->details->uname, rscs_id);
354 resource_location(rsc, node, -INFINITY, "__limit_utilization__",
355 data_set);
356 }
357 }
358
359 } else {
360
361 if (*prefer == NULL) {
362 *prefer = most_capable_node;
363 }
364 g_hash_table_iter_init(&iter, rsc->allowed_nodes);
365 while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
366 if ((node->weight >= 0) && pcmk__node_available(node)
367 && !have_enough_capacity(node, rsc->id, rsc->utilization)) {
368 pe_rsc_debug(rsc, "%s does not have enough capacity for %s",
369 node->details->uname, rsc->id);
370 resource_location(rsc, node, -INFINITY, "__limit_utilization__",
371 data_set);
372 }
373 }
374 }
375
376 g_hash_table_destroy(unallocated_utilization);
377 g_list_free(colocated_rscs);
378 free(rscs_id);
379
380 pe__show_node_weights(true, rsc, "Post-utilization",
381 rsc->allowed_nodes, data_set);
382 }
383
384
385
386
387
388
389
390
391
392
393 static pe_action_t *
394 new_load_stopped_op(const pe_node_t *node, pe_working_set_t *data_set)
395 {
396 char *load_stopped_task = crm_strdup_printf(LOAD_STOPPED "_%s",
397 node->details->uname);
398 pe_action_t *load_stopped = get_pseudo_op(load_stopped_task, data_set);
399
400 if (load_stopped->node == NULL) {
401 load_stopped->node = pe__copy_node(node);
402 pe__clear_action_flags(load_stopped, pe_action_optional);
403 }
404 free(load_stopped_task);
405 return load_stopped;
406 }
407
408
409
410
411
412
413
414
415 void
416 pcmk__create_utilization_constraints(pe_resource_t *rsc, GList *allowed_nodes)
417 {
418 GList *iter = NULL;
419 pe_node_t *node = NULL;
420 pe_action_t *load_stopped = NULL;
421
422 pe_rsc_trace(rsc, "Creating utilization constraints for %s - strategy: %s",
423 rsc->id, rsc->cluster->placement_strategy);
424
425
426 for (iter = rsc->running_on; iter != NULL; iter = iter->next) {
427 node = (pe_node_t *) iter->data;
428 load_stopped = new_load_stopped_op(node, rsc->cluster);
429 pcmk__new_ordering(rsc, stop_key(rsc), NULL, NULL, NULL, load_stopped,
430 pe_order_load, rsc->cluster);
431 }
432
433
434 for (GList *iter = allowed_nodes; iter; iter = iter->next) {
435 node = (pe_node_t *) iter->data;
436 load_stopped = new_load_stopped_op(node, rsc->cluster);
437 pcmk__new_ordering(NULL, NULL, load_stopped, rsc, start_key(rsc), NULL,
438 pe_order_load, rsc->cluster);
439 pcmk__new_ordering(NULL, NULL, load_stopped,
440 rsc, pcmk__op_key(rsc->id, RSC_MIGRATE, 0), NULL,
441 pe_order_load, rsc->cluster);
442 }
443 }
444
445
446
447
448
449
450
451
452 void
453 pcmk__show_node_capacities(const char *desc, pe_working_set_t *data_set)
454 {
455 if (!pcmk_is_set(data_set->flags, pe_flag_show_utilization)) {
456 return;
457 }
458 for (GList *iter = data_set->nodes; iter != NULL; iter = iter->next) {
459 pe_node_t *node = (pe_node_t *) iter->data;
460 pcmk__output_t *out = data_set->priv;
461
462 out->message(out, "node-capacity", node, desc);
463 }
464 }