From f1a0c5dc7a06e7387bf192038f496d7f2a81305d Mon Sep 17 00:00:00 2001 From: Daniel Milroy Date: Thu, 31 Oct 2024 12:07:09 -0700 Subject: [PATCH 1/7] reader: update JGF reader comment --- resource/readers/resource_reader_jgf.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/resource/readers/resource_reader_jgf.cpp b/resource/readers/resource_reader_jgf.cpp index 2661c0b58..9e5243e78 100644 --- a/resource/readers/resource_reader_jgf.cpp +++ b/resource/readers/resource_reader_jgf.cpp @@ -1351,10 +1351,7 @@ int resource_reader_jgf_t::unpack_at (resource_graph_t &g, const std::string &str, int rank) { - /* This functionality is currently experimental, as resource graph - * growth causes a resize of the boost vecS vertex container type. - * Resizing the vecS results in lost job allocations and reservations - * as there is no copy constructor for planner. + /* This functionality is currently experimental. * vtx_t vtx is not implemented and may be used in the future * for optimization. */ From 1cc7d5083971976662c57650511c03464e439cfe Mon Sep 17 00:00:00 2001 From: Daniel Milroy Date: Tue, 14 Jan 2025 17:20:22 -0800 Subject: [PATCH 2/7] reapi: fix C API error message output --- resource/reapi/bindings/c/reapi_cli.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/resource/reapi/bindings/c/reapi_cli.cpp b/resource/reapi/bindings/c/reapi_cli.cpp index 6bec44ca9..bc1297a94 100644 --- a/resource/reapi/bindings/c/reapi_cli.cpp +++ b/resource/reapi/bindings/c/reapi_cli.cpp @@ -259,11 +259,13 @@ extern "C" const char *reapi_cli_get_err_msg (reapi_cli_ctx_t *ctx) { std::string err_buf = ""; - if (ctx->rqt) - err_buf = ctx->rqt->get_resource_query_err_msg () + reapi_cli_t::get_err_message () - + ctx->err_msg; - else - err_buf = reapi_cli_t::get_err_message () + ctx->err_msg; + if (!ctx || !ctx->rqt) { + errno = EINVAL; + return "ERROR: REAPI context and/or rqt null \n"; + } + + err_buf = + ctx->rqt->get_resource_query_err_msg () + reapi_cli_t::get_err_message () + ctx->err_msg; return strdup (err_buf.c_str ()); } From 727f28de5a1ce26d6215b4089188312c4c81d951 Mon Sep 17 00:00:00 2001 From: Daniel Milroy Date: Tue, 14 Jan 2025 17:21:09 -0800 Subject: [PATCH 3/7] reapi: add grow function to C API --- resource/reapi/bindings/c/reapi_cli.cpp | 9 +++++++++ resource/reapi/bindings/c/reapi_cli.h | 11 +++++++++++ 2 files changed, 20 insertions(+) diff --git a/resource/reapi/bindings/c/reapi_cli.cpp b/resource/reapi/bindings/c/reapi_cli.cpp index bc1297a94..fcf9fa41e 100644 --- a/resource/reapi/bindings/c/reapi_cli.cpp +++ b/resource/reapi/bindings/c/reapi_cli.cpp @@ -186,6 +186,15 @@ extern "C" int reapi_cli_update_allocate (reapi_cli_ctx_t *ctx, return rc; } +extern "C" int reapi_cli_grow (reapi_cli_ctx_t *ctx, const char *R_subgraph) +{ + if (!ctx || !ctx->rqt || !R_subgraph) { + errno = EINVAL; + return -1; + } + return reapi_cli_t::grow (ctx->rqt, R_subgraph); +} + extern "C" int reapi_cli_cancel (reapi_cli_ctx_t *ctx, const uint64_t jobid, bool noent_ok) { if (!ctx || !ctx->rqt) { diff --git a/resource/reapi/bindings/c/reapi_cli.h b/resource/reapi/bindings/c/reapi_cli.h index eeca639dd..f2efa30a9 100644 --- a/resource/reapi/bindings/c/reapi_cli.h +++ b/resource/reapi/bindings/c/reapi_cli.h @@ -140,6 +140,17 @@ int reapi_cli_update_allocate (reapi_cli_ctx_t *ctx, double *ov, const char **R_out); +/*! Grow the resource graph with R. + * + * \param h Opaque handle. How it is used is an implementation + * detail. However, when it is used within a Flux's + * service module, it is expected to be a pointer + * to a flux_t object. + * \param R_subgraph R string of subgraph to attach to existing resources + * \return 0 on success; -1 on error. + */ +int reapi_cli_grow (reapi_cli_ctx_t *ctx, const char *R_subgraph); + /*! Cancel the allocation or reservation corresponding to jobid. * * \param ctx reapi_cli_ctx_t context object From e9cc58ecb7c860349464a235f570095d2c7d1231 Mon Sep 17 00:00:00 2001 From: Daniel Milroy Date: Thu, 31 Oct 2024 12:08:50 -0700 Subject: [PATCH 4/7] reapi: add C++ API grow functionality --- resource/reapi/bindings/c++/reapi.hpp | 14 ++++++ resource/reapi/bindings/c++/reapi_cli.hpp | 2 + .../reapi/bindings/c++/reapi_cli_impl.hpp | 49 +++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/resource/reapi/bindings/c++/reapi.hpp b/resource/reapi/bindings/c++/reapi.hpp index cf5eec3e9..eee25b58b 100644 --- a/resource/reapi/bindings/c++/reapi.hpp +++ b/resource/reapi/bindings/c++/reapi.hpp @@ -190,6 +190,20 @@ class reapi_t { return -1; } + /*! Update the resource state with R. + * + * \param h Opaque handle. How it is used is an implementation + * detail. However, when it is used within a Flux's + * service module, it is expected to be a pointer + * to a flux_t object. + * \param R_subgraph R string of subgraph to attach to existing resources + * \return 0 on success; -1 on error. + */ + static int grow (void *h, const std::string &R_subgraph) + { + return -1; + } + /*! Cancel the allocation or reservation corresponding to jobid. * * \param h Opaque handle. How it is used is an implementation diff --git a/resource/reapi/bindings/c++/reapi_cli.hpp b/resource/reapi/bindings/c++/reapi_cli.hpp index 5edb8393c..1892b0131 100644 --- a/resource/reapi/bindings/c++/reapi_cli.hpp +++ b/resource/reapi/bindings/c++/reapi_cli.hpp @@ -89,6 +89,7 @@ class resource_query_t { void set_job (const uint64_t jobid, const std::shared_ptr &job); int remove_job (const uint64_t jobid); int remove_job (const uint64_t jobid, const std::string &R, bool &full_removal); + int grow (const std::string &R_subgraph); void incr_job_counter (); /* Run the traverser to match the jobspec */ @@ -148,6 +149,7 @@ class reapi_cli_t : public reapi_t { int64_t &at, double &ov, std::string &R_out); + static int grow (void *h, const std::string &R_subgraph); static int cancel (void *h, const uint64_t jobid, bool noent_ok); static int cancel (void *h, const uint64_t jobid, diff --git a/resource/reapi/bindings/c++/reapi_cli_impl.hpp b/resource/reapi/bindings/c++/reapi_cli_impl.hpp index e9fda8306..5e3335a0d 100644 --- a/resource/reapi/bindings/c++/reapi_cli_impl.hpp +++ b/resource/reapi/bindings/c++/reapi_cli_impl.hpp @@ -165,6 +165,19 @@ int reapi_cli_t::update_allocate (void *h, return NOT_YET_IMPLEMENTED; } +int reapi_cli_t::grow (void *h, const std::string &R_subgraph) +{ + resource_query_t *rq = static_cast (h); + int rc = -1; + + if ((rc = rq->grow (R_subgraph)) != 0) { + m_err_msg += __FUNCTION__; + m_err_msg += ": ERROR: grow error: " + std::string (strerror (errno)) + "\n"; + } + + return rc; +} + int reapi_cli_t::match_allocate_multi (void *h, bool orelse_reserve, const char *jobs, @@ -720,6 +733,42 @@ int resource_query_t::remove_job (const uint64_t jobid, const std::string &R, bo return rc; } +int resource_query_t::grow (const std::string &R_subgraph) +{ + int rc = -1; + std::shared_ptr reader; + vtx_t v = boost::graph_traits::null_vertex (); + + if (R_subgraph == "") { + errno = EINVAL; + return rc; + } + if (params.load_format != "jgf") { + m_err_msg = __FUNCTION__; + m_err_msg += ": ERROR: growing a resource graph not "; + m_err_msg += " initialized with JGF is unsupported\n"; + errno = ENOTSUP; + return rc; + } + if ((reader = create_resource_reader ("jgf")) == nullptr) { + m_err_msg = __FUNCTION__; + m_err_msg += ": ERROR: can't create JGF reader\n"; + return rc; + } + if ((rc = reader->unpack_at (db->resource_graph, db->metadata, v, R_subgraph, -1)) != 0) { + m_err_msg = __FUNCTION__; + m_err_msg += ": ERROR: reader returned error: "; + m_err_msg += reader->err_message () + "\n"; + return rc; + } + if ((rc = traverser->initialize (db, matcher)) != 0) { + m_err_msg = __FUNCTION__; + m_err_msg += ": ERROR: reinitialize traverser after grow. "; + m_err_msg += reader->err_message () + "\n"; + } + return rc; +} + void resource_query_t::incr_job_counter () { jobid_counter++; From 0550f535972ba24a1b00e69dcd21f08f3f04cf7f Mon Sep 17 00:00:00 2001 From: Daniel Milroy Date: Wed, 11 Dec 2024 16:31:06 -0800 Subject: [PATCH 5/7] resource-query: reinitialize the traverser after attach --- resource/utilities/command.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/resource/utilities/command.cpp b/resource/utilities/command.cpp index 94e9ecc06..d637358bf 100644 --- a/resource/utilities/command.cpp +++ b/resource/utilities/command.cpp @@ -558,7 +558,10 @@ static int remove (std::shared_ptr &ctx, std::vectorerr_message (); return -1; } - // TODO: reinitialize the traverser, see issue #1075 + if (ctx->traverser->initialize (ctx->db, ctx->matcher) != 0) { + std::cerr << "ERROR: can't reinitialize traverser after attach" << std::endl; + return -1; + } return 0; } From c24268ad276cd856d9fdc51d1a6d684cbd8c542a Mon Sep 17 00:00:00 2001 From: Daniel Milroy Date: Tue, 14 Jan 2025 18:23:20 -0800 Subject: [PATCH 6/7] reapi: add shrink function to C API --- resource/reapi/bindings/c/reapi_cli.cpp | 9 +++++++++ resource/reapi/bindings/c/reapi_cli.h | 13 +++++++++++++ 2 files changed, 22 insertions(+) diff --git a/resource/reapi/bindings/c/reapi_cli.cpp b/resource/reapi/bindings/c/reapi_cli.cpp index fcf9fa41e..683a79318 100644 --- a/resource/reapi/bindings/c/reapi_cli.cpp +++ b/resource/reapi/bindings/c/reapi_cli.cpp @@ -195,6 +195,15 @@ extern "C" int reapi_cli_grow (reapi_cli_ctx_t *ctx, const char *R_subgraph) return reapi_cli_t::grow (ctx->rqt, R_subgraph); } +extern "C" int reapi_cli_shrink (reapi_cli_ctx_t *ctx, const char *subgraph_path) +{ + if (!ctx || !ctx->rqt || !subgraph_path) { + errno = EINVAL; + return -1; + } + return reapi_cli_t::shrink (ctx->rqt, subgraph_path); +} + extern "C" int reapi_cli_cancel (reapi_cli_ctx_t *ctx, const uint64_t jobid, bool noent_ok) { if (!ctx || !ctx->rqt) { diff --git a/resource/reapi/bindings/c/reapi_cli.h b/resource/reapi/bindings/c/reapi_cli.h index f2efa30a9..39a257182 100644 --- a/resource/reapi/bindings/c/reapi_cli.h +++ b/resource/reapi/bindings/c/reapi_cli.h @@ -151,6 +151,19 @@ int reapi_cli_update_allocate (reapi_cli_ctx_t *ctx, */ int reapi_cli_grow (reapi_cli_ctx_t *ctx, const char *R_subgraph); +/*! Shrink the resource graph with a path. + * + * \param h Opaque handle. How it is used is an implementation + * detail. However, when it is used within a Flux's + * service module, it is expected to be a pointer + * to a flux_t object. + * \param subgraph_path String representing the path from the cluster root + * to the root of the subgraph to be removed from + * the resource graph + * \return 0 on success; -1 on error. + */ +int reapi_cli_shrink (reapi_cli_ctx_t *ctx, const char *subgraph_path); + /*! Cancel the allocation or reservation corresponding to jobid. * * \param ctx reapi_cli_ctx_t context object From c614801401d55cbc7deee133576a9c87d780238f Mon Sep 17 00:00:00 2001 From: Daniel Milroy Date: Tue, 14 Jan 2025 18:23:56 -0800 Subject: [PATCH 7/7] reapi: add shrink functionality to C++ API --- resource/reapi/bindings/c++/reapi.hpp | 16 +++++++ resource/reapi/bindings/c++/reapi_cli.hpp | 2 + .../reapi/bindings/c++/reapi_cli_impl.hpp | 44 +++++++++++++++++++ 3 files changed, 62 insertions(+) diff --git a/resource/reapi/bindings/c++/reapi.hpp b/resource/reapi/bindings/c++/reapi.hpp index eee25b58b..5fd344033 100644 --- a/resource/reapi/bindings/c++/reapi.hpp +++ b/resource/reapi/bindings/c++/reapi.hpp @@ -204,6 +204,22 @@ class reapi_t { return -1; } + /*! Update the resource state with R. + * + * \param h Opaque handle. How it is used is an implementation + * detail. However, when it is used within a Flux's + * service module, it is expected to be a pointer + * to a flux_t object. + * \param subgraph_path String representing the path from the cluster root + * to the root of the subgraph to be removed from + * the resource graph + * \return 0 on success; -1 on error. + */ + static int shrink (void *h, const std::string &subgraph_path) + { + return -1; + } + /*! Cancel the allocation or reservation corresponding to jobid. * * \param h Opaque handle. How it is used is an implementation diff --git a/resource/reapi/bindings/c++/reapi_cli.hpp b/resource/reapi/bindings/c++/reapi_cli.hpp index 1892b0131..77e5fcee0 100644 --- a/resource/reapi/bindings/c++/reapi_cli.hpp +++ b/resource/reapi/bindings/c++/reapi_cli.hpp @@ -90,6 +90,7 @@ class resource_query_t { int remove_job (const uint64_t jobid); int remove_job (const uint64_t jobid, const std::string &R, bool &full_removal); int grow (const std::string &R_subgraph); + int shrink (const std::string &subgraph_path); void incr_job_counter (); /* Run the traverser to match the jobspec */ @@ -150,6 +151,7 @@ class reapi_cli_t : public reapi_t { double &ov, std::string &R_out); static int grow (void *h, const std::string &R_subgraph); + static int shrink (void *h, const std::string &subgraph_path); static int cancel (void *h, const uint64_t jobid, bool noent_ok); static int cancel (void *h, const uint64_t jobid, diff --git a/resource/reapi/bindings/c++/reapi_cli_impl.hpp b/resource/reapi/bindings/c++/reapi_cli_impl.hpp index 5e3335a0d..cf8067bd9 100644 --- a/resource/reapi/bindings/c++/reapi_cli_impl.hpp +++ b/resource/reapi/bindings/c++/reapi_cli_impl.hpp @@ -178,6 +178,19 @@ int reapi_cli_t::grow (void *h, const std::string &R_subgraph) return rc; } +int reapi_cli_t::shrink (void *h, const std::string &subgraph_path) +{ + resource_query_t *rq = static_cast (h); + int rc = -1; + + if ((rc = rq->shrink (subgraph_path)) != 0) { + m_err_msg += __FUNCTION__; + m_err_msg += ": ERROR: shrink error: " + std::string (strerror (errno)) + "\n"; + } + + return rc; +} + int reapi_cli_t::match_allocate_multi (void *h, bool orelse_reserve, const char *jobs, @@ -769,6 +782,37 @@ int resource_query_t::grow (const std::string &R_subgraph) return rc; } +int resource_query_t::shrink (const std::string &subgraph_path) +{ + int rc = -1; + std::shared_ptr reader; + + if (subgraph_path == "") { + errno = EINVAL; + return rc; + } + // No need to check if params.load_format != "jgf" since + // remove_subgraph takes a subgraph path, which is + // supported by any resource graph + if ((reader = create_resource_reader ("jgf")) == nullptr) { + m_err_msg = __FUNCTION__; + m_err_msg += ": ERROR: can't create JGF reader\n"; + return rc; + } + if ((rc = reader->remove_subgraph (db->resource_graph, db->metadata, subgraph_path)) != 0) { + m_err_msg = __FUNCTION__; + m_err_msg += ": ERROR: reader returned error: "; + m_err_msg += reader->err_message () + "\n"; + return rc; + } + if ((rc = traverser->initialize (db, matcher)) != 0) { + m_err_msg = __FUNCTION__; + m_err_msg += ": ERROR: reinitialize traverser after shrink. "; + m_err_msg += reader->err_message () + "\n"; + } + return rc; +} + void resource_query_t::incr_job_counter () { jobid_counter++;