Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/lib/common/scheduler.c b/lib/common/scheduler.c
index d280383402..ceaa570b0f 100644
--- a/lib/common/scheduler.c
+++ b/lib/common/scheduler.c
@@ -1,417 +1,416 @@
/*
* Copyright 2004-2025 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU Lesser General Public License
* version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <stdint.h> // uint32_t
#include <errno.h> // EINVAL
#include <glib.h> // gboolean, FALSE, etc.
#include <libxml/tree.h> // xmlNode
#include <crm/common/scheduler.h>
uint32_t pcmk__warnings = 0;
/*!
* \brief Create a new object to hold scheduler data
*
* \return New, initialized scheduler data, or NULL on memory error
* \note Only pcmk_scheduler_t objects created with this function (as opposed
* to statically declared or directly allocated) should be used with the
* functions in this library, to allow for future extensions to the
* data type. The caller is responsible for freeing the memory with
* pcmk_free_scheduler() when the instance is no longer needed.
*/
pcmk_scheduler_t *
pcmk_new_scheduler(void)
{
pcmk_scheduler_t *scheduler = calloc(1, sizeof(pcmk_scheduler_t));
if (scheduler == NULL) {
return NULL;
}
scheduler->priv = calloc(1, sizeof(pcmk__scheduler_private_t));
if (scheduler->priv == NULL) {
free(scheduler);
return NULL;
}
pcmk__set_scheduler_defaults(scheduler);
return scheduler;
}
/*!
* \internal
* \brief Set non-zero default values in scheduler data
*
* \param[in,out] scheduler Scheduler data to modify
*
* \note Values that default to NULL or 0 will remain unchanged
*/
void
pcmk__set_scheduler_defaults(pcmk_scheduler_t *scheduler)
{
pcmk__assert(scheduler != NULL);
scheduler->flags = 0U;
#if PCMK__CONCURRENT_FENCING_DEFAULT_TRUE
pcmk__set_scheduler_flags(scheduler,
pcmk__sched_symmetric_cluster
|pcmk__sched_concurrent_fencing
|pcmk__sched_stop_removed_resources
|pcmk__sched_cancel_removed_actions);
#else
pcmk__set_scheduler_flags(scheduler,
pcmk__sched_symmetric_cluster
|pcmk__sched_stop_removed_resources
|pcmk__sched_cancel_removed_actions);
#endif
scheduler->no_quorum_policy = pcmk_no_quorum_stop;
scheduler->priv->next_action_id = 1;
scheduler->priv->next_ordering_id = 1;
}
/*!
* \brief Reset scheduler data to defaults
*
* Free scheduler data except the local node name and output object, and reset
* all other values to defaults, so the data is suitable for rerunning status
*
* \param[in,out] scheduler Scheduler data to reset
*/
void
pcmk_reset_scheduler(pcmk_scheduler_t *scheduler)
{
if (scheduler == NULL) {
return;
}
/* Be careful about the order of freeing members. Many contain references to
* other members that will become dangling if those members are freed first.
* For example, the node name and ID of Pacemaker Remote nodes are pointers
* into resource objects. Ensure that earlier-freed members are not needed
* by any of the free functions for later-freed members.
*/
scheduler->dc_node = NULL;
g_list_free_full(scheduler->nodes, pcmk__free_node);
scheduler->nodes = NULL;
// Do not reset local_node_name or out
crm_time_free(scheduler->priv->now);
scheduler->priv->now = NULL;
if (scheduler->priv->options != NULL) {
g_hash_table_destroy(scheduler->priv->options);
scheduler->priv->options = NULL;
}
scheduler->priv->fence_action = NULL;
scheduler->priv->fence_timeout_ms = 0U;
scheduler->priv->priority_fencing_ms = 0U;
scheduler->priv->shutdown_lock_ms = 0U;
scheduler->priv->node_pending_ms = 0U;
scheduler->priv->placement_strategy = NULL;
scheduler->priv->rsc_defaults = NULL;
scheduler->priv->op_defaults = NULL;
g_list_free_full(scheduler->priv->resources, pcmk__free_resource);
scheduler->priv->resources = NULL;
if (scheduler->priv->templates != NULL) {
g_hash_table_destroy(scheduler->priv->templates);
scheduler->priv->templates = NULL;
}
if (scheduler->priv->tags != NULL) {
g_hash_table_destroy(scheduler->priv->tags);
scheduler->priv->tags = NULL;
}
g_list_free_full(scheduler->priv->actions, pcmk__free_action);
scheduler->priv->actions = NULL;
if (scheduler->priv->singletons != NULL) {
g_hash_table_destroy(scheduler->priv->singletons);
scheduler->priv->singletons = NULL;
}
pcmk__xml_free(scheduler->priv->failed);
scheduler->priv->failed = NULL;
pcmk__free_param_checks(scheduler);
g_list_free(scheduler->priv->stop_needed);
scheduler->priv->stop_needed = NULL;
g_list_free_full(scheduler->priv->location_constraints,
pcmk__free_location);
scheduler->priv->location_constraints = NULL;
g_list_free_full(scheduler->priv->colocation_constraints, free);
scheduler->priv->colocation_constraints = NULL;
g_list_free_full(scheduler->priv->ordering_constraints,
pcmk__free_action_relation);
scheduler->priv->ordering_constraints = NULL;
if (scheduler->priv->ticket_constraints != NULL) {
g_hash_table_destroy(scheduler->priv->ticket_constraints);
scheduler->priv->ticket_constraints = NULL;
}
scheduler->priv->ninstances = 0;
scheduler->priv->blocked_resources = 0;
scheduler->priv->disabled_resources = 0;
scheduler->priv->recheck_by = 0;
pcmk__xml_free(scheduler->priv->graph);
scheduler->priv->graph = NULL;
scheduler->priv->synapse_count = 0;
pcmk__xml_free(scheduler->input);
scheduler->input = NULL;
pcmk__set_scheduler_defaults(scheduler);
- /* @TODO We should probably reset pcmk__config_has_warning and
- * pcmk__config_has_error as well
- */
+ pcmk__config_has_error = false;
+ pcmk__config_has_warning = false;
}
/*!
* \brief Free scheduler data
*
* \param[in,out] scheduler Scheduler data to free
*/
void
pcmk_free_scheduler(pcmk_scheduler_t *scheduler)
{
if (scheduler != NULL) {
pcmk_reset_scheduler(scheduler);
free(scheduler->priv->local_node_name);
free(scheduler->priv);
free(scheduler);
}
}
/*!
* \internal
* \brief Get the Designated Controller node from scheduler data
*
* \param[in] scheduler Scheduler data
*
* \return Designated Controller node from scheduler data, or NULL if none
*/
pcmk_node_t *
pcmk_get_dc(const pcmk_scheduler_t *scheduler)
{
return (scheduler == NULL)? NULL : scheduler->dc_node;
}
/*!
* \internal
* \brief Get the no quorum policy from scheduler data
*
* \param[in] scheduler Scheduler data
*
* \return No quorum policy from scheduler data
*/
enum pe_quorum_policy
pcmk_get_no_quorum_policy(const pcmk_scheduler_t *scheduler)
{
if (scheduler == NULL) {
return pcmk_no_quorum_stop; // The default
}
return scheduler->no_quorum_policy;
}
/*!
* \internal
* \brief Set CIB XML as scheduler input in scheduler data
*
* \param[out] scheduler Scheduler data
* \param[in] cib CIB XML to set as scheduler input
*
* \return Standard Pacemaker return code (EINVAL if \p scheduler is NULL,
* otherwise pcmk_rc_ok)
* \note This will not free any previously set scheduler CIB.
*/
int
pcmk_set_scheduler_cib(pcmk_scheduler_t *scheduler, xmlNode *cib)
{
if (scheduler == NULL) {
return EINVAL;
}
scheduler->input = cib;
return pcmk_rc_ok;
}
/*!
* \internal
* \brief Check whether cluster has quorum
*
* \param[in] scheduler Scheduler data
*
* \return true if cluster has quorum, otherwise false
*/
bool
pcmk_has_quorum(const pcmk_scheduler_t *scheduler)
{
if (scheduler == NULL) {
return false;
}
return pcmk_is_set(scheduler->flags, pcmk__sched_quorate);
}
/*!
* \brief Find a node by name in scheduler data
*
* \param[in] scheduler Scheduler data
* \param[in] node_name Name of node to find
*
* \return Node from scheduler data that matches \p node_name if any,
* otherwise NULL
*/
pcmk_node_t *
pcmk_find_node(const pcmk_scheduler_t *scheduler, const char *node_name)
{
if ((scheduler == NULL) || (node_name == NULL)) {
return NULL;
}
return pcmk__find_node_in_list(scheduler->nodes, node_name);
}
/*!
* \internal
* \brief Get scheduler data's "now" in epoch time
*
* \param[in,out] scheduler Scheduler data
*
* \return Scheduler data's "now" as seconds since epoch (defaulting to current
* time)
*/
time_t
pcmk__scheduler_epoch_time(pcmk_scheduler_t *scheduler)
{
if (scheduler == NULL) {
return time(NULL);
}
if (scheduler->priv->now == NULL) {
crm_trace("Scheduler 'now' set to current time");
scheduler->priv->now = crm_time_new(NULL);
}
return crm_time_get_seconds_since_epoch(scheduler->priv->now);
}
/*!
* \internal
* \brief Update "recheck by" time in scheduler data
*
* \param[in] recheck Epoch time when recheck should happen
* \param[in,out] scheduler Scheduler data
* \param[in] reason What time is being updated for (for logs)
*/
void
pcmk__update_recheck_time(time_t recheck, pcmk_scheduler_t *scheduler,
const char *reason)
{
pcmk__assert(scheduler != NULL);
if ((recheck > pcmk__scheduler_epoch_time(scheduler))
&& ((scheduler->priv->recheck_by == 0)
|| (scheduler->priv->recheck_by > recheck))) {
scheduler->priv->recheck_by = recheck;
crm_debug("Updated next scheduler recheck to %s for %s",
pcmk__trim(ctime(&recheck)),
pcmk__s(reason, "some reason"));
}
}
/* Fail count clearing for parameter changes normally happens when unpacking
* history, before resources are unpacked. However, for bundles using the
* REMOTE_CONTAINER_HACK, we can't check the conditions until after unpacking
* the bundle, so those parameter checks are deferred using the APIs below.
*/
// History entry to be checked later for fail count clearing
struct param_check {
const xmlNode *rsc_history; // History entry XML
pcmk_resource_t *rsc; // Resource corresponding to history entry
pcmk_node_t *node; // Node corresponding to history entry
enum pcmk__check_parameters check_type; // What needs checking
};
/*!
* \internal
* \brief Add a deferred parameter check
*
* \param[in] rsc_history Resource history XML to check later
* \param[in,out] rsc Resource that history is for
* \param[in] node Node that history is for
* \param[in] flag What needs to be checked later
*/
void
pcmk__add_param_check(const xmlNode *rsc_history, pcmk_resource_t *rsc,
pcmk_node_t *node, enum pcmk__check_parameters flag)
{
struct param_check *param_check = NULL;
CRM_CHECK((rsc_history != NULL) && (rsc != NULL) && (node != NULL), return);
crm_trace("Deferring checks of %s until after assignment",
pcmk__xe_id(rsc_history));
param_check = pcmk__assert_alloc(1, sizeof(struct param_check));
param_check->rsc_history = rsc_history;
param_check->rsc = rsc;
param_check->node = node;
param_check->check_type = flag;
rsc->priv->scheduler->priv->param_check =
g_list_prepend(rsc->priv->scheduler->priv->param_check, param_check);
}
/*!
* \internal
* \brief Call a function for each deferred parameter check
*
* \param[in,out] scheduler Scheduler data
* \param[in] cb Function to be called
*/
void
pcmk__foreach_param_check(pcmk_scheduler_t *scheduler,
void (*cb)(pcmk_resource_t*, pcmk_node_t*,
const xmlNode*,
enum pcmk__check_parameters))
{
CRM_CHECK((scheduler != NULL) && (cb != NULL), return);
for (GList *item = scheduler->priv->param_check;
item != NULL; item = item->next) {
struct param_check *param_check = item->data;
cb(param_check->rsc, param_check->node, param_check->rsc_history,
param_check->check_type);
}
}
/*!
* \internal
* \brief Free all deferred parameter checks
*
* \param[in,out] scheduler Scheduler data
*/
void
pcmk__free_param_checks(pcmk_scheduler_t *scheduler)
{
if ((scheduler != NULL) && (scheduler->priv->param_check != NULL)) {
g_list_free_full(scheduler->priv->param_check, free);
scheduler->priv->param_check = NULL;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, Jan 25, 12:33 PM (13 h, 29 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1316073
Default Alt Text
(13 KB)

Event Timeline