dhodovsk / source-git / pacemaker

Forked from source-git/pacemaker 3 years ago
Clone

Blame daemons/controld/controld_throttle.c

rpm-build 3ee90c
/*
rpm-build 3ee90c
 * Copyright 2013-2019 the Pacemaker project contributors
rpm-build 3ee90c
 *
rpm-build 3ee90c
 * The version control history for this file may have further details.
rpm-build 3ee90c
 *
rpm-build 3ee90c
 * This source code is licensed under the GNU General Public License version 2
rpm-build 3ee90c
 * or later (GPLv2+) WITHOUT ANY WARRANTY.
rpm-build 3ee90c
 */
rpm-build 3ee90c
rpm-build 3ee90c
#include <crm_internal.h>
rpm-build 3ee90c
rpm-build 3ee90c
#include <sys/types.h>
rpm-build 3ee90c
#include <sys/stat.h>
rpm-build 3ee90c
rpm-build 3ee90c
#include <unistd.h>
rpm-build 3ee90c
#include <ctype.h>
rpm-build 3ee90c
#include <dirent.h>
rpm-build 3ee90c
rpm-build 3ee90c
#include <crm/crm.h>
rpm-build 3ee90c
#include <crm/msg_xml.h>
rpm-build 3ee90c
#include <crm/cluster.h>
rpm-build 3ee90c
rpm-build 3ee90c
#include <pacemaker-controld.h>
rpm-build 3ee90c
rpm-build 3ee90c
/* These values don't need to be bits, but these particular values must be kept
rpm-build 3ee90c
 * for backward compatibility during rolling upgrades.
rpm-build 3ee90c
 */
rpm-build 3ee90c
enum throttle_state_e {
rpm-build 3ee90c
    throttle_none       = 0x0000,
rpm-build 3ee90c
    throttle_low        = 0x0001,
rpm-build 3ee90c
    throttle_med        = 0x0010,
rpm-build 3ee90c
    throttle_high       = 0x0100,
rpm-build 3ee90c
    throttle_extreme    = 0x1000,
rpm-build 3ee90c
};
rpm-build 3ee90c
rpm-build 3ee90c
struct throttle_record_s {
rpm-build 3ee90c
    int max;
rpm-build 3ee90c
    enum throttle_state_e mode;
rpm-build 3ee90c
    char *node;
rpm-build 3ee90c
};
rpm-build 3ee90c
rpm-build 3ee90c
static int throttle_job_max = 0;
rpm-build 3ee90c
static float throttle_load_target = 0.0;
rpm-build 3ee90c
rpm-build 3ee90c
#define THROTTLE_FACTOR_LOW    1.2
rpm-build 3ee90c
#define THROTTLE_FACTOR_MEDIUM 1.6
rpm-build 3ee90c
#define THROTTLE_FACTOR_HIGH   2.0
rpm-build 3ee90c
rpm-build 3ee90c
static GHashTable *throttle_records = NULL;
rpm-build 3ee90c
static mainloop_timer_t *throttle_timer = NULL;
rpm-build 3ee90c
rpm-build 3ee90c
static const char *
rpm-build 3ee90c
load2str(enum throttle_state_e mode)
rpm-build 3ee90c
{
rpm-build 3ee90c
    switch (mode) {
rpm-build 3ee90c
        case throttle_extreme:  return "extreme";
rpm-build 3ee90c
        case throttle_high:     return "high";
rpm-build 3ee90c
        case throttle_med:      return "medium";
rpm-build 3ee90c
        case throttle_low:      return "low";
rpm-build 3ee90c
        case throttle_none:     return "negligible";
rpm-build 3ee90c
        default:                return "undetermined";
rpm-build 3ee90c
    }
rpm-build 3ee90c
}
rpm-build 3ee90c
rpm-build 3ee90c
#if SUPPORT_PROCFS
rpm-build 3ee90c
/*!
rpm-build 3ee90c
 * \internal
rpm-build 3ee90c
 * \brief Return name of /proc file containing the CIB daemon's load statistics
rpm-build 3ee90c
 *
rpm-build 3ee90c
 * \return Newly allocated memory with file name on success, NULL otherwise
rpm-build 3ee90c
 *
rpm-build 3ee90c
 * \note It is the caller's responsibility to free the return value.
rpm-build 3ee90c
 *       This will return NULL if the daemon is being run via valgrind.
rpm-build 3ee90c
 *       This should be called only on Linux systems.
rpm-build 3ee90c
 */
rpm-build 3ee90c
static char *
rpm-build 3ee90c
find_cib_loadfile(void)
rpm-build 3ee90c
{
rpm-build 3ee90c
    int pid = crm_procfs_pid_of("pacemaker-based");
rpm-build 3ee90c
rpm-build 3ee90c
    return pid? crm_strdup_printf("/proc/%d/stat", pid) : NULL;
rpm-build 3ee90c
}
rpm-build 3ee90c
rpm-build 3ee90c
static bool
rpm-build 3ee90c
throttle_cib_load(float *load)
rpm-build 3ee90c
{
rpm-build 3ee90c
/*
rpm-build 3ee90c
       /proc/[pid]/stat
rpm-build 3ee90c
              Status information about the process.  This is used by ps(1).  It is defined in /usr/src/linux/fs/proc/array.c.
rpm-build 3ee90c
rpm-build 3ee90c
              The fields, in order, with their proper scanf(3) format specifiers, are:
rpm-build 3ee90c
rpm-build 3ee90c
              pid %d      (1) The process ID.
rpm-build 3ee90c
rpm-build 3ee90c
              comm %s     (2) The filename of the executable, in parentheses.  This is visible whether or not the executable is swapped out.
rpm-build 3ee90c
rpm-build 3ee90c
              state %c    (3) One character from the string "RSDZTW" where R is running, S is sleeping in an interruptible wait, D is waiting in uninterruptible disk sleep, Z is zombie, T is traced or stopped (on a signal), and W is paging.
rpm-build 3ee90c
rpm-build 3ee90c
              ppid %d     (4) The PID of the parent.
rpm-build 3ee90c
rpm-build 3ee90c
              pgrp %d     (5) The process group ID of the process.
rpm-build 3ee90c
rpm-build 3ee90c
              session %d  (6) The session ID of the process.
rpm-build 3ee90c
rpm-build 3ee90c
              tty_nr %d   (7) The controlling terminal of the process.  (The minor device number is contained in the combination of bits 31 to 20 and 7 to 0; the major device number is in bits 15 to 8.)
rpm-build 3ee90c
rpm-build 3ee90c
              tpgid %d    (8) The ID of the foreground process group of the controlling terminal of the process.
rpm-build 3ee90c
rpm-build 3ee90c
              flags %u (%lu before Linux 2.6.22)
rpm-build 3ee90c
                          (9) The kernel flags word of the process.  For bit meanings, see the PF_* defines in the Linux kernel source file include/linux/sched.h.  Details depend on the kernel version.
rpm-build 3ee90c
rpm-build 3ee90c
              minflt %lu  (10) The number of minor faults the process has made which have not required loading a memory page from disk.
rpm-build 3ee90c
rpm-build 3ee90c
              cminflt %lu (11) The number of minor faults that the process's waited-for children have made.
rpm-build 3ee90c
rpm-build 3ee90c
              majflt %lu  (12) The number of major faults the process has made which have required loading a memory page from disk.
rpm-build 3ee90c
rpm-build 3ee90c
              cmajflt %lu (13) The number of major faults that the process's waited-for children have made.
rpm-build 3ee90c
rpm-build 3ee90c
              utime %lu   (14) Amount of time that this process has been scheduled in user mode, measured in clock ticks (divide by sysconf(_SC_CLK_TCK)).  This includes guest time, guest_time (time spent running a virtual CPU, see below), so that applications that are not aware of the guest time field do not lose that time from their calculations.
rpm-build 3ee90c
rpm-build 3ee90c
              stime %lu   (15) Amount of time that this process has been scheduled in kernel mode, measured in clock ticks (divide by sysconf(_SC_CLK_TCK)).
rpm-build 3ee90c
 */
rpm-build 3ee90c
rpm-build 3ee90c
    static char *loadfile = NULL;
rpm-build 3ee90c
    static time_t last_call = 0;
rpm-build 3ee90c
    static long ticks_per_s = 0;
rpm-build 3ee90c
    static unsigned long last_utime, last_stime;
rpm-build 3ee90c
rpm-build 3ee90c
    char buffer[64*1024];
rpm-build 3ee90c
    FILE *stream = NULL;
rpm-build 3ee90c
    time_t now = time(NULL);
rpm-build 3ee90c
rpm-build 3ee90c
    if(load == NULL) {
rpm-build 3ee90c
        return FALSE;
rpm-build 3ee90c
    } else {
rpm-build 3ee90c
        *load = 0.0;
rpm-build 3ee90c
    }
rpm-build 3ee90c
rpm-build 3ee90c
    if(loadfile == NULL) {
rpm-build 3ee90c
        last_call = 0;
rpm-build 3ee90c
        last_utime = 0;
rpm-build 3ee90c
        last_stime = 0;
rpm-build 3ee90c
        loadfile = find_cib_loadfile();
rpm-build 3ee90c
        if (loadfile == NULL) {
rpm-build 3ee90c
            crm_warn("Couldn't find CIB load file");
rpm-build 3ee90c
            return FALSE;
rpm-build 3ee90c
        }
rpm-build 3ee90c
        ticks_per_s = sysconf(_SC_CLK_TCK);
rpm-build 3ee90c
        crm_trace("Found %s", loadfile);
rpm-build 3ee90c
    }
rpm-build 3ee90c
rpm-build 3ee90c
    stream = fopen(loadfile, "r");
rpm-build 3ee90c
    if(stream == NULL) {
rpm-build 3ee90c
        int rc = errno;
rpm-build 3ee90c
rpm-build 3ee90c
        crm_warn("Couldn't read %s: %s (%d)", loadfile, pcmk_strerror(rc), rc);
rpm-build 3ee90c
        free(loadfile); loadfile = NULL;
rpm-build 3ee90c
        return FALSE;
rpm-build 3ee90c
    }
rpm-build 3ee90c
rpm-build 3ee90c
    if(fgets(buffer, sizeof(buffer), stream)) {
rpm-build 3ee90c
        char *comm = calloc(1, 256);
rpm-build 3ee90c
        char state = 0;
rpm-build 3ee90c
        int rc = 0, pid = 0, ppid = 0, pgrp = 0, session = 0, tty_nr = 0, tpgid = 0;
rpm-build 3ee90c
        unsigned long flags = 0, minflt = 0, cminflt = 0, majflt = 0, cmajflt = 0, utime = 0, stime = 0;
rpm-build 3ee90c
rpm-build 3ee90c
        rc = sscanf(buffer,  "%d %[^ ] %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu",
rpm-build 3ee90c
                    &pid, comm, &state,
rpm-build 3ee90c
                    &ppid, &pgrp, &session, &tty_nr, &tpgid,
rpm-build 3ee90c
                    &flags, &minflt, &cminflt, &majflt, &cmajflt, &utime, &stime);
rpm-build 3ee90c
        free(comm);
rpm-build 3ee90c
rpm-build 3ee90c
        if(rc != 15) {
rpm-build 3ee90c
            crm_err("Only %d of 15 fields found in %s", rc, loadfile);
rpm-build 3ee90c
            fclose(stream);
rpm-build 3ee90c
            return FALSE;
rpm-build 3ee90c
rpm-build 3ee90c
        } else if(last_call > 0
rpm-build 3ee90c
           && last_call < now
rpm-build 3ee90c
           && last_utime <= utime
rpm-build 3ee90c
           && last_stime <= stime) {
rpm-build 3ee90c
rpm-build 3ee90c
            time_t elapsed = now - last_call;
rpm-build 3ee90c
            unsigned long delta_utime = utime - last_utime;
rpm-build 3ee90c
            unsigned long delta_stime = stime - last_stime;
rpm-build 3ee90c
rpm-build 3ee90c
            *load = (delta_utime + delta_stime); /* Cast to a float before division */
rpm-build 3ee90c
            *load /= ticks_per_s;
rpm-build 3ee90c
            *load /= elapsed;
rpm-build 3ee90c
            crm_debug("cib load: %f (%lu ticks in %lds)", *load, delta_utime + delta_stime, (long)elapsed);
rpm-build 3ee90c
rpm-build 3ee90c
        } else {
rpm-build 3ee90c
            crm_debug("Init %lu + %lu ticks at %ld (%lu tps)", utime, stime, (long)now, ticks_per_s);
rpm-build 3ee90c
        }
rpm-build 3ee90c
rpm-build 3ee90c
        last_call = now;
rpm-build 3ee90c
        last_utime = utime;
rpm-build 3ee90c
        last_stime = stime;
rpm-build 3ee90c
rpm-build 3ee90c
        fclose(stream);
rpm-build 3ee90c
        return TRUE;
rpm-build 3ee90c
    }
rpm-build 3ee90c
rpm-build 3ee90c
    fclose(stream);
rpm-build 3ee90c
    return FALSE;
rpm-build 3ee90c
}
rpm-build 3ee90c
rpm-build 3ee90c
static bool
rpm-build 3ee90c
throttle_load_avg(float *load)
rpm-build 3ee90c
{
rpm-build 3ee90c
    char buffer[256];
rpm-build 3ee90c
    FILE *stream = NULL;
rpm-build 3ee90c
    const char *loadfile = "/proc/loadavg";
rpm-build 3ee90c
rpm-build 3ee90c
    if(load == NULL) {
rpm-build 3ee90c
        return FALSE;
rpm-build 3ee90c
    }
rpm-build 3ee90c
rpm-build 3ee90c
    stream = fopen(loadfile, "r");
rpm-build 3ee90c
    if(stream == NULL) {
rpm-build 3ee90c
        int rc = errno;
rpm-build 3ee90c
        crm_warn("Couldn't read %s: %s (%d)", loadfile, pcmk_strerror(rc), rc);
rpm-build 3ee90c
        return FALSE;
rpm-build 3ee90c
    }
rpm-build 3ee90c
rpm-build 3ee90c
    if(fgets(buffer, sizeof(buffer), stream)) {
rpm-build 3ee90c
        char *nl = strstr(buffer, "\n");
rpm-build 3ee90c
rpm-build 3ee90c
        /* Grab the 1-minute average, ignore the rest */
rpm-build 3ee90c
        *load = strtof(buffer, NULL);
rpm-build 3ee90c
        if(nl) { nl[0] = 0; }
rpm-build 3ee90c
rpm-build 3ee90c
        fclose(stream);
rpm-build 3ee90c
        return TRUE;
rpm-build 3ee90c
    }
rpm-build 3ee90c
rpm-build 3ee90c
    fclose(stream);
rpm-build 3ee90c
    return FALSE;
rpm-build 3ee90c
}
rpm-build 3ee90c
rpm-build 3ee90c
/*!
rpm-build 3ee90c
 * \internal
rpm-build 3ee90c
 * \brief Check a load value against throttling thresholds
rpm-build 3ee90c
 *
rpm-build 3ee90c
 * \param[in] load        Load value to check
rpm-build 3ee90c
 * \param[in] desc        Description of metric (for logging)
rpm-build 3ee90c
 * \param[in] thresholds  Low/medium/high/extreme thresholds
rpm-build 3ee90c
 *
rpm-build 3ee90c
 * \return Throttle mode corresponding to load value
rpm-build 3ee90c
 */
rpm-build 3ee90c
static enum throttle_state_e
rpm-build 3ee90c
throttle_check_thresholds(float load, const char *desc, float thresholds[4])
rpm-build 3ee90c
{
rpm-build 3ee90c
    if (load > thresholds[3]) {
rpm-build 3ee90c
        crm_notice("Extreme %s detected: %f", desc, load);
rpm-build 3ee90c
        return throttle_extreme;
rpm-build 3ee90c
rpm-build 3ee90c
    } else if (load > thresholds[2]) {
rpm-build 3ee90c
        crm_notice("High %s detected: %f", desc, load);
rpm-build 3ee90c
        return throttle_high;
rpm-build 3ee90c
rpm-build 3ee90c
    } else if (load > thresholds[1]) {
rpm-build 3ee90c
        crm_info("Moderate %s detected: %f", desc, load);
rpm-build 3ee90c
        return throttle_med;
rpm-build 3ee90c
rpm-build 3ee90c
    } else if (load > thresholds[0]) {
rpm-build 3ee90c
        crm_debug("Noticeable %s detected: %f", desc, load);
rpm-build 3ee90c
        return throttle_low;
rpm-build 3ee90c
    }
rpm-build 3ee90c
rpm-build 3ee90c
    crm_trace("Negligible %s detected: %f", desc, load);
rpm-build 3ee90c
    return throttle_none;
rpm-build 3ee90c
}
rpm-build 3ee90c
rpm-build 3ee90c
static enum throttle_state_e
rpm-build 3ee90c
throttle_handle_load(float load, const char *desc, int cores)
rpm-build 3ee90c
{
rpm-build 3ee90c
    float normalize;
rpm-build 3ee90c
    float thresholds[4];
rpm-build 3ee90c
rpm-build 3ee90c
    if (cores == 1) {
rpm-build 3ee90c
        /* On a single core machine, a load of 1.0 is already too high */
rpm-build 3ee90c
        normalize = 0.6;
rpm-build 3ee90c
rpm-build 3ee90c
    } else {
rpm-build 3ee90c
        /* Normalize the load to be per-core */
rpm-build 3ee90c
        normalize = cores;
rpm-build 3ee90c
    }
rpm-build 3ee90c
    thresholds[0] = throttle_load_target * normalize * THROTTLE_FACTOR_LOW;
rpm-build 3ee90c
    thresholds[1] = throttle_load_target * normalize * THROTTLE_FACTOR_MEDIUM;
rpm-build 3ee90c
    thresholds[2] = throttle_load_target * normalize * THROTTLE_FACTOR_HIGH;
rpm-build 3ee90c
    thresholds[3] = load + 1.0; /* never extreme */
rpm-build 3ee90c
rpm-build 3ee90c
    return throttle_check_thresholds(load, desc, thresholds);
rpm-build 3ee90c
}
rpm-build 3ee90c
#endif
rpm-build 3ee90c
rpm-build 3ee90c
static enum throttle_state_e
rpm-build 3ee90c
throttle_mode(void)
rpm-build 3ee90c
{
rpm-build 3ee90c
    enum throttle_state_e mode = throttle_none;
rpm-build 3ee90c
rpm-build 3ee90c
#if SUPPORT_PROCFS
rpm-build 3ee90c
    unsigned int cores;
rpm-build 3ee90c
    float load;
rpm-build 3ee90c
    float thresholds[4];
rpm-build 3ee90c
rpm-build 3ee90c
    cores = crm_procfs_num_cores();
rpm-build 3ee90c
    if(throttle_cib_load(&load)) {
rpm-build 3ee90c
        float cib_max_cpu = 0.95;
rpm-build 3ee90c
rpm-build 3ee90c
        /* The CIB is a single-threaded task and thus cannot consume
rpm-build 3ee90c
         * more than 100% of a CPU (and 1/cores of the overall system
rpm-build 3ee90c
         * load).
rpm-build 3ee90c
         *
rpm-build 3ee90c
         * On a many-cored system, the CIB might therefore be maxed out
rpm-build 3ee90c
         * (causing operations to fail or appear to fail) even though
rpm-build 3ee90c
         * the overall system load is still reasonable.
rpm-build 3ee90c
         *
rpm-build 3ee90c
         * Therefore, the 'normal' thresholds can not apply here, and we
rpm-build 3ee90c
         * need a special case.
rpm-build 3ee90c
         */
rpm-build 3ee90c
        if(cores == 1) {
rpm-build 3ee90c
            cib_max_cpu = 0.4;
rpm-build 3ee90c
        }
rpm-build 3ee90c
        if(throttle_load_target > 0.0 && throttle_load_target < cib_max_cpu) {
rpm-build 3ee90c
            cib_max_cpu = throttle_load_target;
rpm-build 3ee90c
        }
rpm-build 3ee90c
rpm-build 3ee90c
        thresholds[0] = cib_max_cpu * 0.8;
rpm-build 3ee90c
        thresholds[1] = cib_max_cpu * 0.9;
rpm-build 3ee90c
        thresholds[2] = cib_max_cpu;
rpm-build 3ee90c
        /* Can only happen on machines with a low number of cores */
rpm-build 3ee90c
        thresholds[3] = cib_max_cpu * 1.5;
rpm-build 3ee90c
rpm-build 3ee90c
        mode = throttle_check_thresholds(load, "CIB load", thresholds);
rpm-build 3ee90c
    }
rpm-build 3ee90c
rpm-build 3ee90c
    if(throttle_load_target <= 0) {
rpm-build 3ee90c
        /* If we ever make this a valid value, the cluster will at least behave as expected */
rpm-build 3ee90c
        return mode;
rpm-build 3ee90c
    }
rpm-build 3ee90c
rpm-build 3ee90c
    if(throttle_load_avg(&load)) {
rpm-build 3ee90c
        enum throttle_state_e cpu_load;
rpm-build 3ee90c
rpm-build 3ee90c
        cpu_load = throttle_handle_load(load, "CPU load", cores);
rpm-build 3ee90c
        if (cpu_load > mode) {
rpm-build 3ee90c
            mode = cpu_load;
rpm-build 3ee90c
        }
rpm-build 3ee90c
        crm_debug("Current load is %f across %u core(s)", load, cores);
rpm-build 3ee90c
    }
rpm-build 3ee90c
#endif // SUPPORT_PROCFS
rpm-build 3ee90c
    return mode;
rpm-build 3ee90c
}
rpm-build 3ee90c
rpm-build 3ee90c
static void
rpm-build 3ee90c
throttle_send_command(enum throttle_state_e mode)
rpm-build 3ee90c
{
rpm-build 3ee90c
    xmlNode *xml = NULL;
rpm-build 3ee90c
    static enum throttle_state_e last = -1;
rpm-build 3ee90c
rpm-build 3ee90c
    if(mode != last) {
rpm-build 3ee90c
        crm_info("New throttle mode: %s load (was %s)",
rpm-build 3ee90c
                 load2str(mode), load2str(last));
rpm-build 3ee90c
        last = mode;
rpm-build 3ee90c
rpm-build 3ee90c
        xml = create_request(CRM_OP_THROTTLE, NULL, NULL, CRM_SYSTEM_CRMD, CRM_SYSTEM_CRMD, NULL);
rpm-build 3ee90c
        crm_xml_add_int(xml, F_CRM_THROTTLE_MODE, mode);
rpm-build 3ee90c
        crm_xml_add_int(xml, F_CRM_THROTTLE_MAX, throttle_job_max);
rpm-build 3ee90c
rpm-build 3ee90c
        send_cluster_message(NULL, crm_msg_crmd, xml, TRUE);
rpm-build 3ee90c
        free_xml(xml);
rpm-build 3ee90c
    }
rpm-build 3ee90c
}
rpm-build 3ee90c
rpm-build 3ee90c
static gboolean
rpm-build 3ee90c
throttle_timer_cb(gpointer data)
rpm-build 3ee90c
{
rpm-build 3ee90c
    throttle_send_command(throttle_mode());
rpm-build 3ee90c
    return TRUE;
rpm-build 3ee90c
}
rpm-build 3ee90c
rpm-build 3ee90c
static void
rpm-build 3ee90c
throttle_record_free(gpointer p)
rpm-build 3ee90c
{
rpm-build 3ee90c
    struct throttle_record_s *r = p;
rpm-build 3ee90c
    free(r->node);
rpm-build 3ee90c
    free(r);
rpm-build 3ee90c
}
rpm-build 3ee90c
rpm-build 3ee90c
void
rpm-build 3ee90c
throttle_set_load_target(float target)
rpm-build 3ee90c
{
rpm-build 3ee90c
    throttle_load_target = target;
rpm-build 3ee90c
}
rpm-build 3ee90c
rpm-build 3ee90c
void
rpm-build 3ee90c
throttle_update_job_max(const char *preference)
rpm-build 3ee90c
{
rpm-build 3ee90c
    int max = 0;
rpm-build 3ee90c
rpm-build 3ee90c
    throttle_job_max = 2 * crm_procfs_num_cores();
rpm-build 3ee90c
rpm-build 3ee90c
    if(preference) {
rpm-build 3ee90c
        /* Global preference from the CIB */
rpm-build 3ee90c
        max = crm_int_helper(preference, NULL);
rpm-build 3ee90c
        if(max > 0) {
rpm-build 3ee90c
            throttle_job_max = max;
rpm-build 3ee90c
        }
rpm-build 3ee90c
    }
rpm-build 3ee90c
rpm-build 3ee90c
    preference = getenv("PCMK_node_action_limit");
rpm-build 3ee90c
    if(preference) {
rpm-build 3ee90c
        /* Per-node override */
rpm-build 3ee90c
        max = crm_int_helper(preference, NULL);
rpm-build 3ee90c
        if(max > 0) {
rpm-build 3ee90c
            throttle_job_max = max;
rpm-build 3ee90c
        }
rpm-build 3ee90c
    }
rpm-build 3ee90c
}
rpm-build 3ee90c
rpm-build 3ee90c
void
rpm-build 3ee90c
throttle_init(void)
rpm-build 3ee90c
{
rpm-build 3ee90c
    if(throttle_records == NULL) {
rpm-build 3ee90c
        throttle_records = g_hash_table_new_full(
rpm-build 3ee90c
            crm_str_hash, g_str_equal, NULL, throttle_record_free);
rpm-build 3ee90c
        throttle_timer = mainloop_timer_add("throttle", 30 * 1000, TRUE, throttle_timer_cb, NULL);
rpm-build 3ee90c
    }
rpm-build 3ee90c
rpm-build 3ee90c
    throttle_update_job_max(NULL);
rpm-build 3ee90c
    mainloop_timer_start(throttle_timer);
rpm-build 3ee90c
}
rpm-build 3ee90c
rpm-build 3ee90c
void
rpm-build 3ee90c
throttle_fini(void)
rpm-build 3ee90c
{
rpm-build 3ee90c
    if (throttle_timer != NULL) {
rpm-build 3ee90c
        mainloop_timer_del(throttle_timer);
rpm-build 3ee90c
        throttle_timer = NULL;
rpm-build 3ee90c
    }
rpm-build 3ee90c
    if (throttle_records != NULL) {
rpm-build 3ee90c
        g_hash_table_destroy(throttle_records);
rpm-build 3ee90c
        throttle_records = NULL;
rpm-build 3ee90c
    }
rpm-build 3ee90c
}
rpm-build 3ee90c
rpm-build 3ee90c
int
rpm-build 3ee90c
throttle_get_total_job_limit(int l)
rpm-build 3ee90c
{
rpm-build 3ee90c
    /* Cluster-wide limit */
rpm-build 3ee90c
    GHashTableIter iter;
rpm-build 3ee90c
    int limit = l;
rpm-build 3ee90c
    int peers = crm_active_peers();
rpm-build 3ee90c
    struct throttle_record_s *r = NULL;
rpm-build 3ee90c
rpm-build 3ee90c
    g_hash_table_iter_init(&iter, throttle_records);
rpm-build 3ee90c
rpm-build 3ee90c
    while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &r)) {
rpm-build 3ee90c
        switch(r->mode) {
rpm-build 3ee90c
rpm-build 3ee90c
            case throttle_extreme:
rpm-build 3ee90c
                if(limit == 0 || limit > peers/4) {
rpm-build 3ee90c
                    limit = QB_MAX(1, peers/4);
rpm-build 3ee90c
                }
rpm-build 3ee90c
                break;
rpm-build 3ee90c
rpm-build 3ee90c
            case throttle_high:
rpm-build 3ee90c
                if(limit == 0 || limit > peers/2) {
rpm-build 3ee90c
                    limit = QB_MAX(1, peers/2);
rpm-build 3ee90c
                }
rpm-build 3ee90c
                break;
rpm-build 3ee90c
            default:
rpm-build 3ee90c
                break;
rpm-build 3ee90c
        }
rpm-build 3ee90c
    }
rpm-build 3ee90c
    if(limit == l) {
rpm-build 3ee90c
        /* crm_trace("No change to batch-limit=%d", limit); */
rpm-build 3ee90c
rpm-build 3ee90c
    } else if(l == 0) {
rpm-build 3ee90c
        crm_trace("Using batch-limit=%d", limit);
rpm-build 3ee90c
rpm-build 3ee90c
    } else {
rpm-build 3ee90c
        crm_trace("Using batch-limit=%d instead of %d", limit, l);
rpm-build 3ee90c
    }
rpm-build 3ee90c
    return limit;
rpm-build 3ee90c
}
rpm-build 3ee90c
rpm-build 3ee90c
int
rpm-build 3ee90c
throttle_get_job_limit(const char *node)
rpm-build 3ee90c
{
rpm-build 3ee90c
    int jobs = 1;
rpm-build 3ee90c
    struct throttle_record_s *r = NULL;
rpm-build 3ee90c
rpm-build 3ee90c
    r = g_hash_table_lookup(throttle_records, node);
rpm-build 3ee90c
    if(r == NULL) {
rpm-build 3ee90c
        r = calloc(1, sizeof(struct throttle_record_s));
rpm-build 3ee90c
        r->node = strdup(node);
rpm-build 3ee90c
        r->mode = throttle_low;
rpm-build 3ee90c
        r->max = throttle_job_max;
rpm-build 3ee90c
        crm_trace("Defaulting to local values for unknown node %s", node);
rpm-build 3ee90c
rpm-build 3ee90c
        g_hash_table_insert(throttle_records, r->node, r);
rpm-build 3ee90c
    }
rpm-build 3ee90c
rpm-build 3ee90c
    switch(r->mode) {
rpm-build 3ee90c
        case throttle_extreme:
rpm-build 3ee90c
        case throttle_high:
rpm-build 3ee90c
            jobs = 1; /* At least one job must always be allowed */
rpm-build 3ee90c
            break;
rpm-build 3ee90c
        case throttle_med:
rpm-build 3ee90c
            jobs = QB_MAX(1, r->max / 4);
rpm-build 3ee90c
            break;
rpm-build 3ee90c
        case throttle_low:
rpm-build 3ee90c
            jobs = QB_MAX(1, r->max / 2);
rpm-build 3ee90c
            break;
rpm-build 3ee90c
        case throttle_none:
rpm-build 3ee90c
            jobs = QB_MAX(1, r->max);
rpm-build 3ee90c
            break;
rpm-build 3ee90c
        default:
rpm-build 3ee90c
            crm_err("Unknown throttle mode %.4x on %s", r->mode, node);
rpm-build 3ee90c
            break;
rpm-build 3ee90c
    }
rpm-build 3ee90c
    return jobs;
rpm-build 3ee90c
}
rpm-build 3ee90c
rpm-build 3ee90c
void
rpm-build 3ee90c
throttle_update(xmlNode *xml)
rpm-build 3ee90c
{
rpm-build 3ee90c
    int max = 0;
rpm-build 3ee90c
    int mode = 0;
rpm-build 3ee90c
    struct throttle_record_s *r = NULL;
rpm-build 3ee90c
    const char *from = crm_element_value(xml, F_CRM_HOST_FROM);
rpm-build 3ee90c
rpm-build 3ee90c
    crm_element_value_int(xml, F_CRM_THROTTLE_MODE, &mode);
rpm-build 3ee90c
    crm_element_value_int(xml, F_CRM_THROTTLE_MAX, &max;;
rpm-build 3ee90c
rpm-build 3ee90c
    r = g_hash_table_lookup(throttle_records, from);
rpm-build 3ee90c
rpm-build 3ee90c
    if(r == NULL) {
rpm-build 3ee90c
        r = calloc(1, sizeof(struct throttle_record_s));
rpm-build 3ee90c
        r->node = strdup(from);
rpm-build 3ee90c
        g_hash_table_insert(throttle_records, r->node, r);
rpm-build 3ee90c
    }
rpm-build 3ee90c
rpm-build 3ee90c
    r->max = max;
rpm-build 3ee90c
    r->mode = (enum throttle_state_e) mode;
rpm-build 3ee90c
rpm-build 3ee90c
    crm_debug("Node %s has %s load and supports at most %d jobs; new job limit %d",
rpm-build 3ee90c
              from, load2str((enum throttle_state_e) mode), max,
rpm-build 3ee90c
              throttle_get_job_limit(from));
rpm-build 3ee90c
}