diff --git a/resource/planner/c++/planner_multi.cpp b/resource/planner/c++/planner_multi.cpp index 47b8f00a3..4e83efc69 100644 --- a/resource/planner/c++/planner_multi.cpp +++ b/resource/planner/c++/planner_multi.cpp @@ -183,6 +183,51 @@ planner_multi::~planner_multi () erase (); } +void planner_multi::add_planner (int64_t base_time, uint64_t duration, + const uint64_t resource_total, + const char *resource_type, size_t i) +{ + char *type = nullptr; + planner_t *p = nullptr; + + if ( (type = strdup (resource_type)) == nullptr) { + errno = ENOMEM; + throw std::runtime_error ("ERROR in strdup\n"); + } + m_iter.counts[type] = 0; + try { + p = new planner_t (base_time, duration, + resource_total, + resource_type); + } catch (std::bad_alloc &e) { + errno = ENOMEM; + } + if (p == nullptr) + throw std::runtime_error ("ERROR adding planner_multi\n"); + + if (i > m_types_totals_planners.size ()) + m_types_totals_planners.push_back ({type, resource_total, p}); + else { + auto it = m_types_totals_planners.begin () + i; + m_types_totals_planners.insert ( + it, planner_multi_meta{type, resource_total, p}); + } + +} + +void planner_multi::delete_planners (const std::unordered_set &rtypes) +{ + auto &by_res = m_types_totals_planners.get (); + for (auto iter = by_res.begin (); iter != by_res.end ();) { + if (rtypes.find (iter->resource_type) == rtypes.end ()) { + iter = by_res.erase (iter); + // need to remove from request_multi + m_iter.counts.erase (iter->resource_type); + } else + ++iter; + } +} + planner_t *planner_multi::get_planner_at (size_t i) { return m_types_totals_planners.at (i).planner; @@ -194,6 +239,26 @@ planner_t *planner_multi::get_planner_at (const char *type) return by_res.find (strdup (type))->planner; } +void planner_multi::update_planner_index (const char *type, size_t i) +{ + std::string rtype = strdup (type); + auto by_res = m_types_totals_planners.get ().find (rtype); + auto new_idx = m_types_totals_planners.begin () + i; + auto curr_idx = m_types_totals_planners.get ().iterator_to (*by_res); + // noop if new_idx == curr_idx + m_types_totals_planners.relocate (new_idx, curr_idx); +} + +bool planner_multi::planner_at (const char *type) +{ + auto &by_res = m_types_totals_planners.get (); + auto result = by_res.find (std::string (type)); + if (result == by_res.end ()) + return false; + else + return true; +} + size_t planner_multi::get_planners_size () { return m_types_totals_planners.size (); diff --git a/resource/planner/c++/planner_multi.hpp b/resource/planner/c++/planner_multi.hpp index c606ce82b..6dcec2335 100644 --- a/resource/planner/c++/planner_multi.hpp +++ b/resource/planner/c++/planner_multi.hpp @@ -12,6 +12,7 @@ #define PLANNER_MULTI_HPP #include "planner.hpp" +#include #include #include #include @@ -64,6 +65,8 @@ class planner_multi { // Public getters and setters planner_t *get_planner_at (size_t i); planner_t *get_planner_at (const char *type); + void update_planner_index (const char *type, size_t i); + bool planner_at (const char *type); size_t get_planners_size (); uint64_t get_resource_total_at (size_t i); const char *get_resource_type_at (size_t i); @@ -79,6 +82,12 @@ class planner_multi { uint64_t get_span_counter (); void set_span_counter (uint64_t sc); void incr_span_counter (); + void add_planner (int64_t base_time, uint64_t duration, + const uint64_t resource_total, + const char *resource_type, size_t i); + // Assuming small number of resources, + // could try set, too + void delete_planners (const std::unordered_set &rtypes); private: multi_container m_types_totals_planners; diff --git a/resource/planner/c/planner_multi.h b/resource/planner/c/planner_multi.h index 2dad4f4ba..305638f45 100644 --- a/resource/planner/c/planner_multi.h +++ b/resource/planner/c/planner_multi.h @@ -292,6 +292,25 @@ size_t planner_multi_span_size (planner_multi_t *ctx); */ bool planner_multis_equal (planner_multi_t *lhs, planner_multi_t *rhs); +/*! Update the counts and resource types to support elasticity. + * + * \param resource_totals + * 64-bit unsigned integer array of size len where each + * element contains the total count of available resources + * of a single resource type. + * \param resource_types + * string array of size len where each element contains + * the resource type corresponding to each corresponding + * element in the resource_totals array. + * \return 0 on success; -1 on an error with errno set as follows: + * EINVAL: invalid argument. + */ +int planner_multi_update (planner_multi_t *ctx, + const uint64_t *resource_totals, + const char **resource_types, + size_t len); + + #ifdef __cplusplus } #endif diff --git a/resource/planner/c/planner_multi_c_interface.cpp b/resource/planner/c/planner_multi_c_interface.cpp index 2cf413828..77d0f22c2 100644 --- a/resource/planner/c/planner_multi_c_interface.cpp +++ b/resource/planner/c/planner_multi_c_interface.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "planner_multi.h" #include "resource/planner/c++/planner_multi.hpp" @@ -471,6 +472,63 @@ extern "C" bool planner_multis_equal (planner_multi_t *lhs, return (*(lhs->plan_multi) == *(rhs->plan_multi)); } +extern "C" int planner_multi_update (planner_multi_t *ctx, + const uint64_t *resource_totals, + const char **resource_types, + size_t len) +{ + int rc = -1; + size_t ntypes, ntotals, i = 0; + // Assuming small number of resources, + // could try set, too + std::unordered_set rtypes; + int64_t base_time = 0; + int64_t duration = 0; + + if (!ctx || !resource_totals || !resource_types) { + errno = EINVAL; + goto done; + } + base_time = planner_base_time ( + ctx->plan_multi->get_planner_at (static_cast (0))); + duration = planner_duration ( + ctx->plan_multi->get_planner_at (static_cast (0))); + if (duration < 0) { + errno = EINVAL; + goto done; + } + + for (i = 0; i < len; ++i) { + if (resource_totals[i] > + static_cast (std::numeric_limits::max ())) { + errno = ERANGE; + goto done; + } + rtypes.insert (resource_types[i]); + if (!ctx->plan_multi->planner_at (resource_types[i])) { + // Assume base_time same as parent + ctx->plan_multi->add_planner (base_time, static_cast (duration), + resource_totals[i], resource_types[i], i); + } else { + // Index could have changed + ctx->plan_multi->update_planner_index (resource_types[i], i); + if ( (rc = planner_update (ctx->plan_multi->get_planner_at (i), + resource_totals[i])) != 0) { + errno = EINVAL; + goto done; + } + } + } + // remove values not in new types + if (rtypes.size () > 0) + ctx->plan_multi->delete_planners (rtypes); + + rc = 0; + +done: + return rc; +} + /* * vi: ts=4 sw=4 expandtab */