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