diff -r c81e55653fba include/crm/msg_xml.h --- a/include/crm/msg_xml.h Fri Oct 16 14:26:27 2009 +0200 +++ b/include/crm/msg_xml.h Fri Nov 06 15:20:33 2009 +0800 @@ -130,6 +130,7 @@ #define XML_TAG_ATTRS "attributes" #define XML_TAG_PARAMS "parameters" #define XML_TAG_PARAM "param" +#define XML_TAG_UTILIZATION "utilization" #define XML_TAG_RESOURCE_REF "resource_ref" #define XML_CIB_TAG_RESOURCE "primitive" diff -r c81e55653fba include/crm/pengine/status.h --- a/include/crm/pengine/status.h Fri Oct 16 14:26:27 2009 +0200 +++ b/include/crm/pengine/status.h Fri Nov 06 15:20:33 2009 +0800 @@ -58,6 +58,8 @@ #define pe_flag_start_failure_fatal 0x00001000ULL #define pe_flag_remove_after_stop 0x00002000ULL +#define pe_flag_limit_utilization 0x00010000ULL + typedef struct pe_working_set_s { @@ -116,6 +118,8 @@ GHashTable *attrs; /* char* => char* */ enum node_type type; + + GHashTable *utilization; }; struct node_s { @@ -186,6 +190,7 @@ GHashTable *meta; GHashTable *parameters; + GHashTable *utilization; GListPtr children; /* resource_t* */ }; diff -r c81e55653fba lib/pengine/common.c --- a/lib/pengine/common.c Fri Oct 16 14:26:27 2009 +0200 +++ b/lib/pengine/common.c Fri Nov 06 15:20:33 2009 +0800 @@ -147,6 +147,10 @@ { "node-health-red", NULL, "integer", NULL, "-INFINITY", &check_number, "The score 'red' translates to in rsc_location constraints", "Only used when node-health-strategy is set to custom or progressive." }, + + /*Resource utilization*/ + { "limit-utilization", NULL, "boolean", NULL, "false", &check_boolean, + "Limit the resource utilization of nodes to avoid being overloaded", NULL}, }; void diff -r c81e55653fba lib/pengine/complex.c --- a/lib/pengine/complex.c Fri Oct 16 14:26:27 2009 +0200 +++ b/lib/pengine/complex.c Fri Nov 06 15:20:33 2009 +0800 @@ -371,6 +371,12 @@ if(safe_str_eq(class, "stonith")) { set_bit_inplace(data_set->flags, pe_flag_have_stonith_resource); } + + (*rsc)->utilization = g_hash_table_new_full( + g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); + + unpack_instance_attributes(data_set->input, (*rsc)->xml, XML_TAG_UTILIZATION, NULL, + (*rsc)->utilization, NULL, FALSE, data_set->now); /* data_set->resources = g_list_append(data_set->resources, (*rsc)); */ return TRUE; @@ -451,6 +457,9 @@ if(rsc->meta != NULL) { g_hash_table_destroy(rsc->meta); } + if(rsc->utilization != NULL) { + g_hash_table_destroy(rsc->utilization); + } if(rsc->parent == NULL && is_set(rsc->flags, pe_rsc_orphan)) { free_xml(rsc->xml); } diff -r c81e55653fba lib/pengine/status.c --- a/lib/pengine/status.c Fri Oct 16 14:26:27 2009 +0200 +++ b/lib/pengine/status.c Fri Nov 06 15:20:33 2009 +0800 @@ -159,6 +159,9 @@ if(details->attrs != NULL) { g_hash_table_destroy(details->attrs); } + if(details->utilization != NULL) { + g_hash_table_destroy(details->utilization); + } pe_free_shallow_adv(details->running_rsc, FALSE); pe_free_shallow_adv(details->allocated_rsc, FALSE); crm_free(details); diff -r c81e55653fba lib/pengine/unpack.c --- a/lib/pengine/unpack.c Fri Oct 16 14:26:27 2009 +0200 +++ b/lib/pengine/unpack.c Fri Nov 06 15:20:33 2009 +0800 @@ -165,6 +165,10 @@ crm_info("Node scores: 'red' = %s, 'yellow' = %s, 'green' = %s", score2char(node_score_red),score2char(node_score_yellow), score2char(node_score_green)); + + set_config_flag(data_set, "limit-utilization", pe_flag_limit_utilization); + crm_debug_2("Limit resource utilization: %s", + is_set(data_set->flags, pe_flag_limit_utilization)?"true":"false"); return TRUE; } @@ -233,6 +237,9 @@ new_node->details->attrs = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); + new_node->details->utilization = g_hash_table_new_full( + g_str_hash, g_str_equal, + g_hash_destroy_str, g_hash_destroy_str); /* if(data_set->have_quorum == FALSE */ /* && data_set->no_quorum_policy == no_quorum_stop) { */ @@ -258,6 +265,10 @@ } add_node_attrs(xml_obj, new_node, FALSE, data_set); + unpack_instance_attributes( + data_set->input, xml_obj, XML_TAG_UTILIZATION, NULL, + new_node->details->utilization, NULL, FALSE, data_set->now); + data_set->nodes = g_list_append(data_set->nodes, new_node); crm_debug_3("Done with node %s", crm_element_value(xml_obj, XML_ATTR_UNAME)); diff -r c81e55653fba pengine/native.c --- a/pengine/native.c Fri Oct 16 14:26:27 2009 +0200 +++ b/pengine/native.c Fri Nov 06 15:20:33 2009 +0800 @@ -250,6 +250,11 @@ native_color(resource_t *rsc, pe_working_set_t *data_set) { int alloc_details = scores_log_level+1; + GHashTableIter iter; + const char *key = NULL; + const char *value = NULL; + const char *capacity = NULL; + if(rsc->parent && is_not_set(rsc->parent->flags, pe_rsc_allocating)) { /* never allocate children on their own */ crm_debug("Escalating allocation of %s to its parent: %s", @@ -289,6 +294,24 @@ constraint->rsc_lh, rsc->id, rsc->allowed_nodes, constraint->node_attribute, constraint->score/INFINITY, TRUE); ); + + if (is_set(data_set->flags, pe_flag_limit_utilization)) { + slist_iter( + node, node_t, data_set->nodes, lpc, + g_hash_table_iter_init(&iter, rsc->utilization); + while (g_hash_table_iter_next(&iter, (gpointer)&key, (gpointer)&value)) { + capacity = g_hash_table_lookup(node->details->utilization, key); + if (capacity == NULL || + crm_parse_int(capacity, "0") < crm_parse_int(value, "0")) { + crm_debug("Resource %s cannot be allocated to node %s: none of enough capacity", + rsc->id, node->details->uname); + resource_location(rsc, node, -INFINITY, "__limit_utilization_", data_set); + break; + } + } + ); + dump_node_scores(alloc_details, rsc, "Post-utilization", rsc->allowed_nodes); + } print_resource(LOG_DEBUG_2, "Allocating: ", rsc, FALSE); if(rsc->next_role == RSC_ROLE_STOPPED) { diff -r c81e55653fba pengine/utils.c --- a/pengine/utils.c Fri Oct 16 14:26:27 2009 +0200 +++ b/pengine/utils.c Fri Nov 06 15:20:33 2009 +0800 @@ -256,6 +256,12 @@ gboolean native_assign_node(resource_t *rsc, GListPtr nodes, node_t *chosen, gboolean force) { + GHashTableIter iter; + const char *key = NULL; + const char *value = NULL; + const char *capacity = NULL; + char *remain_capacity = NULL; + CRM_ASSERT(rsc->variant == pe_native); clear_bit(rsc->flags, pe_rsc_provisional); @@ -284,6 +290,15 @@ old->details->allocated_rsc, rsc); old->details->num_resources--; old->count--; + + g_hash_table_iter_init(&iter, rsc->utilization); + while (g_hash_table_iter_next(&iter, (gpointer)&key, (gpointer)&value)) { + capacity = g_hash_table_lookup(old->details->utilization, key); + if (capacity) { + remain_capacity = crm_itoa(crm_parse_int(capacity, "0") + crm_parse_int(value, "0")); + g_hash_table_replace(old->details->utilization, crm_strdup(key), remain_capacity); + } + } } crm_debug("Assigning %s to %s", chosen->details->uname, rsc->id); @@ -293,6 +308,15 @@ chosen->details->allocated_rsc = g_list_append(chosen->details->allocated_rsc, rsc); chosen->details->num_resources++; chosen->count++; + + g_hash_table_iter_init(&iter, rsc->utilization); + while (g_hash_table_iter_next(&iter, (gpointer)&key, (gpointer)&value)) { + capacity = g_hash_table_lookup(chosen->details->utilization, key); + if (capacity) { + remain_capacity = crm_itoa(crm_parse_int(capacity, "0") - crm_parse_int(value, "0")); + g_hash_table_replace(chosen->details->utilization, crm_strdup(key), remain_capacity); + } + } return TRUE; } diff -r c81e55653fba xml/pacemaker.rng.in --- a/xml/pacemaker.rng.in Fri Oct 16 14:26:27 2009 +0200 +++ b/xml/pacemaker.rng.in Fri Nov 06 15:20:33 2009 +0800 @@ -104,9 +104,14 @@ - - - + + + + + + + + diff -r c81e55653fba xml/resources.rng.in --- a/xml/resources.rng.in Fri Oct 16 14:26:27 2009 +0200 +++ b/xml/resources.rng.in Fri Nov 06 15:20:33 2009 +0800 @@ -39,6 +39,11 @@ + + + + +