pacemaker 3.0.1-16e74fc4da
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
pcmk_sched_nodes.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2024 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU General Public License version 2
7 * or later (GPLv2+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11#include <crm/common/xml.h>
13#include <pacemaker-internal.h>
14#include <pacemaker.h>
16
29bool
30pcmk__node_available(const pcmk_node_t *node, bool consider_score,
31 bool consider_guest)
32{
33 if ((node == NULL) || (node->details == NULL) || !node->details->online
34 || node->details->shutdown || node->details->unclean
36 || node->details->maintenance) {
37 return false;
38 }
39
40 if (consider_score && (node->assign->score < 0)) {
41 return false;
42 }
43
44 // @TODO Go through all callers to see which should set consider_guest
45 if (consider_guest && pcmk__is_guest_or_bundle_node(node)) {
46 pcmk_resource_t *guest = node->priv->remote->priv->launcher;
47
48 if (guest->priv->fns->location(guest, NULL,
49 pcmk__rsc_node_assigned) == NULL) {
50 return false;
51 }
52 }
53
54 return true;
55}
56
66GHashTable *
67pcmk__copy_node_table(GHashTable *nodes)
68{
69 GHashTable *new_table = NULL;
70 GHashTableIter iter;
71 pcmk_node_t *node = NULL;
72
73 if (nodes == NULL) {
74 return NULL;
75 }
77 g_hash_table_iter_init(&iter, nodes);
78 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
79 pcmk_node_t *new_node = pe__copy_node(node);
80
81 g_hash_table_insert(new_table, (gpointer) new_node->priv->id,
82 new_node);
83 }
84 return new_table;
85}
86
95static void
96destroy_node_tables(gpointer data)
97{
98 g_hash_table_destroy((GHashTable *) data);
99}
100
116void
117pcmk__copy_node_tables(const pcmk_resource_t *rsc, GHashTable **copy)
118{
119 pcmk__assert((rsc != NULL) && (copy != NULL));
120
121 if (*copy == NULL) {
122 *copy = pcmk__strkey_table(NULL, destroy_node_tables);
123 }
124
125 g_hash_table_insert(*copy, rsc->id,
127
128 for (const GList *iter = rsc->priv->children;
129 iter != NULL; iter = iter->next) {
130
131 pcmk__copy_node_tables((const pcmk_resource_t *) iter->data, copy);
132 }
133}
134
149void
151{
152 pcmk__assert((rsc != NULL) && (backup != NULL));
153
154 g_hash_table_destroy(rsc->priv->allowed_nodes);
155
156 // Copy to avoid danger with multiple restores
157 rsc->priv->allowed_nodes =
158 pcmk__copy_node_table(g_hash_table_lookup(backup, rsc->id));
159
160 for (GList *iter = rsc->priv->children;
161 iter != NULL; iter = iter->next) {
162
163 pcmk__restore_node_tables((pcmk_resource_t *) iter->data, backup);
164 }
165}
166
176GList *
177pcmk__copy_node_list(const GList *list, bool reset)
178{
179 GList *result = NULL;
180
181 for (const GList *iter = list; iter != NULL; iter = iter->next) {
182 pcmk_node_t *new_node = NULL;
183 pcmk_node_t *this_node = iter->data;
184
185 new_node = pe__copy_node(this_node);
186 if (reset) {
187 new_node->assign->score = 0;
188 }
189 result = g_list_prepend(result, new_node);
190 }
191 return result;
192}
193
208static gint
209compare_nodes(gconstpointer a, gconstpointer b, gpointer data)
210{
211 const pcmk_node_t *node1 = (const pcmk_node_t *) a;
212 const pcmk_node_t *node2 = (const pcmk_node_t *) b;
213 const pcmk_node_t *preferred = (const pcmk_node_t *) data;
214
215 int node1_score = -PCMK_SCORE_INFINITY;
216 int node2_score = -PCMK_SCORE_INFINITY;
217
218 int result = 0;
219
220 if (a == NULL) {
221 return 1;
222 }
223 if (b == NULL) {
224 return -1;
225 }
226
227 // Compare node scores
228
229 if (pcmk__node_available(node1, false, false)) {
230 node1_score = node1->assign->score;
231 }
232 if (pcmk__node_available(node2, false, false)) {
233 node2_score = node2->assign->score;
234 }
235
236 if (node1_score > node2_score) {
237 crm_trace("%s before %s (score %d > %d)",
238 pcmk__node_name(node1), pcmk__node_name(node2),
239 node1_score, node2_score);
240 return -1;
241 }
242
243 if (node1_score < node2_score) {
244 crm_trace("%s after %s (score %d < %d)",
245 pcmk__node_name(node1), pcmk__node_name(node2),
246 node1_score, node2_score);
247 return 1;
248 }
249
250 // If appropriate, compare node utilization
251
252 if (pcmk__str_eq(node1->priv->scheduler->priv->placement_strategy,
254 goto equal;
255 }
256
257 if (pcmk__str_eq(node1->priv->scheduler->priv->placement_strategy,
259
261 if (result < 0) {
262 crm_trace("%s before %s (greater capacity by %d attributes)",
263 pcmk__node_name(node1), pcmk__node_name(node2),
264 result * -1);
265 return -1;
266 } else if (result > 0) {
267 crm_trace("%s after %s (lower capacity by %d attributes)",
268 pcmk__node_name(node1), pcmk__node_name(node2), result);
269 return 1;
270 }
271 }
272
273 // Compare number of resources already assigned to node
274
276 crm_trace("%s before %s (%d resources < %d)",
277 pcmk__node_name(node1), pcmk__node_name(node2),
279 return -1;
280
281 } else if (node1->priv->num_resources > node2->priv->num_resources) {
282 crm_trace("%s after %s (%d resources > %d)",
283 pcmk__node_name(node1), pcmk__node_name(node2),
285 return 1;
286 }
287
288 // Check whether one node is already running desired resource
289
290 if (preferred != NULL) {
291 if (pcmk__same_node(preferred, node1)) {
292 crm_trace("%s before %s (preferred node)",
293 pcmk__node_name(node1), pcmk__node_name(node2));
294 return -1;
295 } else if (pcmk__same_node(preferred, node2)) {
296 crm_trace("%s after %s (not preferred node)",
297 pcmk__node_name(node1), pcmk__node_name(node2));
298 return 1;
299 }
300 }
301
302 // If all else is equal, prefer node with lowest-sorting name
303equal:
304 result = strcmp(node1->priv->name, node2->priv->name);
305 if (result < 0) {
306 crm_trace("%s before %s (name)",
307 pcmk__node_name(node1), pcmk__node_name(node2));
308 return -1;
309 } else if (result > 0) {
310 crm_trace("%s after %s (name)",
311 pcmk__node_name(node1), pcmk__node_name(node2));
312 return 1;
313 }
314
315 crm_trace("%s == %s", pcmk__node_name(node1), pcmk__node_name(node2));
316 return 0;
317}
318
328GList *
329pcmk__sort_nodes(GList *nodes, pcmk_node_t *active_node)
330{
331 return g_list_sort_with_data(nodes, compare_nodes, active_node);
332}
333
343bool
344pcmk__any_node_available(GHashTable *nodes)
345{
346 GHashTableIter iter;
347 const pcmk_node_t *node = NULL;
348
349 if (nodes == NULL) {
350 return false;
351 }
352 g_hash_table_iter_init(&iter, nodes);
353 while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
354 if (pcmk__node_available(node, true, false)) {
355 return true;
356 }
357 }
358 return false;
359}
360
367void
369{
370 int base_health = 0;
371 enum pcmk__health_strategy strategy;
372 const char *strategy_str =
375
376 strategy = pcmk__parse_health_strategy(strategy_str);
377 if (strategy == pcmk__health_strategy_none) {
378 return;
379 }
380 crm_info("Applying node health strategy '%s'", strategy_str);
381
382 // The progressive strategy can use a base health score
383 if (strategy == pcmk__health_strategy_progressive) {
385 }
386
387 for (GList *iter = scheduler->nodes; iter != NULL; iter = iter->next) {
388 pcmk_node_t *node = (pcmk_node_t *) iter->data;
389 int health = pe__sum_node_health_scores(node, base_health);
390
391 // An overall health score of 0 has no effect
392 if (health == 0) {
393 continue;
394 }
395 crm_info("Overall system health of %s is %d",
396 pcmk__node_name(node), health);
397
398 // Use node health as a location score for each resource on the node
399 for (GList *r = scheduler->priv->resources; r != NULL; r = r->next) {
400 pcmk_resource_t *rsc = (pcmk_resource_t *) r->data;
401
402 bool constrain = true;
403
404 if (health < 0) {
405 /* Negative health scores do not apply to resources with
406 * PCMK_META_ALLOW_UNHEALTHY_NODES=true.
407 */
408 constrain = !crm_is_true(g_hash_table_lookup(rsc->priv->meta,
410 }
411 if (constrain) {
412 pcmk__new_location(strategy_str, rsc, health, NULL, node);
413 } else {
414 pcmk__rsc_trace(rsc, "%s is immune from health ban on %s",
415 rsc->id, pcmk__node_name(node));
416 }
417 }
418 }
419}
420
433{
434 GHashTable *allowed_nodes = NULL;
435
436 if ((rsc == NULL) || (node == NULL)) {
437 return NULL;
438 }
439
440 if (rsc->priv->parent == NULL) {
441 allowed_nodes = rsc->priv->allowed_nodes;
442 } else {
443 allowed_nodes = rsc->priv->parent->priv->allowed_nodes;
444 }
445 return g_hash_table_lookup(allowed_nodes, node->priv->id);
446}
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:80
char data[0]
Definition cpg.c:10
pcmk__health_strategy
@ pcmk__health_strategy_progressive
@ pcmk__health_strategy_none
int pcmk__health_score(const char *option, const pcmk_scheduler_t *scheduler)
Definition health.c:82
enum pcmk__health_strategy pcmk__parse_health_strategy(const char *value)
Definition health.c:46
G_GNUC_INTERNAL pcmk__location_t * pcmk__new_location(const char *id, pcmk_resource_t *rsc, int node_score, const char *discover_mode, pcmk_node_t *foo_node)
G_GNUC_INTERNAL int pcmk__compare_node_capacities(const pcmk_node_t *node1, const pcmk_node_t *node2)
#define crm_info(fmt, args...)
Definition logging.h:365
#define crm_trace(fmt, args...)
Definition logging.h:370
pcmk_scheduler_t * scheduler
@ pcmk__node_standby
void pcmk__free_node_copy(void *data)
Definition nodes.c:64
#define PCMK_VALUE_MINIMAL
Definition options.h:174
#define PCMK_VALUE_BALANCED
Definition options.h:135
#define PCMK_OPT_NODE_HEALTH_STRATEGY
Definition options.h:52
#define PCMK_META_ALLOW_UNHEALTHY_NODES
Definition options.h:82
#define PCMK_OPT_NODE_HEALTH_BASE
Definition options.h:49
const char * pcmk__cluster_option(GHashTable *options, const char *name)
Definition options.c:1410
High Level API.
pcmk__action_result_t result
Definition pcmk_fence.c:37
bool pcmk__node_available(const pcmk_node_t *node, bool consider_score, bool consider_guest)
GHashTable * pcmk__copy_node_table(GHashTable *nodes)
bool pcmk__any_node_available(GHashTable *nodes)
pcmk_node_t * pcmk__top_allowed_node(const pcmk_resource_t *rsc, const pcmk_node_t *node)
GList * pcmk__sort_nodes(GList *nodes, pcmk_node_t *active_node)
GList * pcmk__copy_node_list(const GList *list, bool reset)
void pcmk__apply_node_health(pcmk_scheduler_t *scheduler)
void pcmk__restore_node_tables(pcmk_resource_t *rsc, GHashTable *backup)
void pcmk__copy_node_tables(const pcmk_resource_t *rsc, GHashTable **copy)
pcmk_node_t node2
pcmk_node_t node1
pcmk_node_t * pe__copy_node(const pcmk_node_t *this_node)
Definition utils.c:124
int pe__sum_node_health_scores(const pcmk_node_t *node, int base_health)
Definition pe_health.c:110
@ pcmk__rsc_node_assigned
#define pcmk__assert(expr)
#define pcmk__rsc_trace(rsc, fmt, args...)
#define PCMK_SCORE_INFINITY
Integer score to use to represent "infinity".
Definition scores.h:26
gboolean crm_is_true(const char *s)
Definition strings.c:490
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition strings.c:685
@ pcmk__str_casei
gboolean shutdown
Definition nodes.h:62
gboolean online
Definition nodes.h:50
gboolean maintenance
Definition nodes.h:66
gboolean unclean
Definition nodes.h:58
pcmk_resource_t * remote
pcmk_scheduler_t * scheduler
const pcmk__rsc_methods_t * fns
pcmk__resource_private_t * priv
Definition resources.h:61
pcmk_node_t *(* location)(const pcmk_resource_t *rsc, GList **list, uint32_t target)
pcmk__scheduler_private_t * priv
Definition scheduler.h:99
GList * nodes
Definition scheduler.h:97
pcmk__node_private_t * priv
Definition nodes.h:85
struct pcmk__node_details * details
Definition nodes.h:82
struct pcmk__node_assignment * assign
Definition nodes.h:79
Wrappers for and extensions to libxml2.