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