From e60efb14804b16fdad8aea4defa8f932d689fef5 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Tue, 5 Jun 2012 01:58:37 +0200 Subject: [PATCH] feature #1288: Generic Quota Management --- include/Quota.h | 68 +++++++++++-- include/QuotaDatastore.h | 4 +- src/um/Quota.cc | 205 ++++++++++++++++++++++++++++++++++++--- src/um/SConstruct | 2 +- 4 files changed, 254 insertions(+), 25 deletions(-) diff --git a/include/Quota.h b/include/Quota.h index 846a3c47ff..9dc8d9a00c 100644 --- a/include/Quota.h +++ b/include/Quota.h @@ -59,14 +59,51 @@ protected: virtual ~Quota(){}; - /** - * Sets new limit values for the quota - * @param quota to be updated - * @param va attribute with the new limits - * @return 0 on success or -1 if wrong limits + /** + * Generic Quota Names + * + * template_name = [ + * ID = "ID to identify the resource", + * metrics[0] = "Limit for the first metric" + * metrics[0]_USED = "Usage for metric" + * ] + * + * ID & counter fields are optional */ - virtual int update_limits(VectorAttribute* quota, - const VectorAttribute* va) = 0; + + /** + * Name of the quota used in the templates + */ + char * template_name; + + /** + * The name of the quota metrics + */ + char ** metrics; + + /** + * Length o + */ + int num_metrics; + + /** + * Check a given quota for an usage request and update counters if the + * request does not exceed quota limits + * @param qid id that identifies the quota, to be used by get_quota + * @param usage_req usage for each metric + * @return true if the request does not exceed current limits + */ + bool check_quota(const string& qid, + map& usage_req, + string& error); + + /** + * Reduce usage from a given quota based on the current consumption + * @param qid id that identifies the quota, to be used by get_quota + * @param usage_req usage for each metric + */ + void del_quota(const string& qid, + map& usage_req); /** * Creates an empty quota based on the given attribute. The attribute va @@ -81,7 +118,7 @@ protected: * @param id of the quota * @return a pointer to the quota or 0 if not found */ - virtual VectorAttribute * get_quota(const string& id); + virtual int get_quota(const string& id, VectorAttribute **va); /** * Adds a new quota, it also updates an internal index for fast accessing @@ -97,6 +134,21 @@ protected: * @param num value to add to the current quota; */ void add_to_quota(VectorAttribute * attr, const string& va_name, int num); + + /** + * Sets new limit values for the quota + * @param quota to be updated + * @param va attribute with the new limits + * @return 0 on success or -1 if wrong limits + */ + int update_limits(VectorAttribute* quota, const VectorAttribute* va); + + /** + * Extract the limits from a given attribute + * @param va the attribute with the limits + * @param + */ + int get_limits(const VectorAttribute * va, map& limits); }; #endif /*QUOTA_H_*/ diff --git a/include/QuotaDatastore.h b/include/QuotaDatastore.h index 0876a857d5..e40cf75cf9 100644 --- a/include/QuotaDatastore.h +++ b/include/QuotaDatastore.h @@ -63,8 +63,8 @@ protected: * @param va attribute with the new limits * @return 0 on success or -1 if wrong limits */ - int update_limits(VectorAttribute* quota, - const VectorAttribute* va); + /*int update_limits(VectorAttribute* quota, + const VectorAttribute* va);*/ /** * Creates an empty quota based on the given attribute. The attribute va diff --git a/src/um/Quota.cc b/src/um/Quota.cc index 124bc0639f..5d0e5ba166 100644 --- a/src/um/Quota.cc +++ b/src/um/Quota.cc @@ -19,14 +19,16 @@ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -VectorAttribute * Quota::get_quota(const string& id) +int Quota::get_quota(const string& id, VectorAttribute ** va) { map::iterator it; VectorAttribute * q; + *va = 0; + if ( id.empty() ) { - return 0; + return -1; } for ( it = attributes.begin(); it != attributes.end(); it++) @@ -35,7 +37,8 @@ VectorAttribute * Quota::get_quota(const string& id) if (q->vector_value("ID") == id) { - return q; + *va = q; + return 0; } } @@ -47,15 +50,6 @@ VectorAttribute * Quota::get_quota(const string& id) void Quota::add(VectorAttribute * nq) { - string id; - - id = nq->vector_value("ID"); - - if ( id.empty() ) - { - return; - } - attributes.insert(make_pair(nq->name(), nq)); } @@ -93,7 +87,10 @@ int Quota::set(vector * new_quotas, string& error) { id = (*it)->vector_value("ID"); - tq = get_quota(id); + if ( get_quota(id, &tq) == -1 ) + { + goto error_limits; + } if ( tq == 0 ) { @@ -111,7 +108,7 @@ int Quota::set(vector * new_quotas, string& error) if (update_limits(tq, *it)) { goto error_limits; - } + } } } @@ -127,3 +124,183 @@ error_limits: /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ + +bool Quota::check_quota(const string& qid, + map& usage_req, + string& error) +{ + VectorAttribute * q; + map::iterator it; + + bool check; + int limit; + int usage; + + if ( get_quota(qid, &q) == -1 ) + { + return false; + } + + // ------------------------------------------------------------------------- + // Quota does not exist, create a new one + // ------------------------------------------------------------------------- + if ( q == 0 ) + { + map values; + + for (int i=0; i < num_metrics; i++) + { + ostringstream usage_req_str; + string metrics_used = metrics[i]; + + metrics_used += "_USED"; + + it = usage_req.find(metrics[i]); + + if (it == usage_req.end()) + { + usage_req_str << "0"; + } + else + { + usage_req_str << it->second; + } + + values.insert(make_pair(metrics[i], "0")); + values.insert(make_pair(metrics_used, usage_req_str.str())); + } + + if (!qid.empty()) + { + values.insert(make_pair("ID", qid)); + } + + add(new VectorAttribute(template_name, values)); + + return true; + } + + // ------------------------------------------------------------------------- + // Check the quotas for each usage request + // ------------------------------------------------------------------------- + for (int i=0; i < num_metrics; i++) + { + string metrics_used = metrics[i]; + + metrics_used += "_USED"; + + it = usage_req.find(metrics[i]); + + if (it == usage_req.end()) + { + continue; + } + + q->vector_value(metrics[i], limit); + q->vector_value(metrics_used.c_str(), usage); + + check = ( limit == 0 ) || ( ( usage + it->second ) <= limit ); + + if ( !check ) + { + ostringstream oss; + + oss << "Limit (" << limit << ") reached for " << metrics[i] + << " in quota " << template_name; + + if ( !qid.empty() ) + { + oss << "with ID: " << qid; + } + + error = oss.str(); + + return false; + } + } + + // ------------------------------------------------------------------------- + // Add resource usage to quotas + // ------------------------------------------------------------------------- + for (int i=0; i < num_metrics; i++) + { + string metrics_used = metrics[i]; + + metrics_used += "_USED"; + + it = usage_req.find(metrics[i]); + + if (it == usage_req.end()) + { + continue; + } + + add_to_quota(q, metrics_used, it->second); + } + + return true; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void Quota::del_quota(const string& qid, map& usage_req) +{ + VectorAttribute * q; + map::iterator it; + + if ( get_quota(qid, &q) == -1) + { + return; + } + + if ( q == 0 ) + { + return; + } + + for (int i=0; i < num_metrics; i++) + { + string metrics_used = metrics[i]; + + metrics_used += "_USED"; + + it = usage_req.find(metrics[i]); + + if (it == usage_req.end()) + { + continue; + } + + add_to_quota(q, metrics_used, -it->second); + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int Quota::update_limits(VectorAttribute * quota, const VectorAttribute * va) +{ + string limit; + int limit_i; + + for (int i=0; i < num_metrics; i++) + { + limit = va->vector_value(metrics[i], limit_i); + + if ( !limit.empty() ) + { + if ( limit_i < 0 ) + { + return -1; + } + + quota->replace(metrics[i], limit); + } + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ diff --git a/src/um/SConstruct b/src/um/SConstruct index ebee5078b7..af1fe543bc 100644 --- a/src/um/SConstruct +++ b/src/um/SConstruct @@ -25,7 +25,7 @@ source_files=[ 'User.cc', 'UserPool.cc', 'Quota.cc', - 'QuotaDatastore.cc' +# 'QuotaDatastore.cc' ] # Build library