From 11f5a5a5090a7b983d06fe9b038480be602a0282 Mon Sep 17 00:00:00 2001 From: Alberto Miranda Date: Mon, 30 Oct 2023 18:35:50 +0100 Subject: [PATCH 1/8] [API] Add data stager info to ADM_adhoc_context_t --- examples/c/ADM_cancel_transfer.c | 4 +-- examples/c/ADM_connect_data_operation.c | 4 +-- examples/c/ADM_define_data_operation.c | 4 +-- examples/c/ADM_deploy_adhoc_storage.c | 12 ++++---- examples/c/ADM_finalize_data_operation.c | 4 +-- examples/c/ADM_get_pending_transfers.c | 4 +-- examples/c/ADM_get_qos_constraints.c | 4 +-- examples/c/ADM_get_statistics.c | 4 +-- examples/c/ADM_get_transfer_priority.c | 4 +-- .../c/ADM_link_transfer_to_data_operation.c | 4 +-- examples/c/ADM_register_adhoc_storage.c | 6 ++-- examples/c/ADM_register_job.c | 6 ++-- examples/c/ADM_remove_adhoc_storage.c | 6 ++-- examples/c/ADM_remove_job.c | 4 +-- examples/c/ADM_set_dataset_information.c | 4 +-- examples/c/ADM_set_io_resources.c | 4 +-- examples/c/ADM_set_qos_constraints.c | 4 +-- examples/c/ADM_set_transfer_priority.c | 4 +-- examples/c/ADM_terminate_adhoc_storage.c | 12 ++++---- examples/c/ADM_transfer_datasets.c | 4 +-- examples/c/ADM_update_adhoc_storage.c | 12 ++++---- examples/c/ADM_update_job.c | 4 +-- examples/c/common.c | 9 ++++-- examples/c/common.h | 2 ++ examples/cxx/ADM_cancel_transfer.cpp | 1 + examples/cxx/ADM_connect_data_operation.cpp | 1 + examples/cxx/ADM_define_data_operation.cpp | 1 + examples/cxx/ADM_deploy_adhoc_storage.cpp | 6 +++- examples/cxx/ADM_finalize_data_operation.cpp | 1 + examples/cxx/ADM_get_pending_transfers.cpp | 1 + examples/cxx/ADM_get_qos_constraints.cpp | 1 + examples/cxx/ADM_get_statistics.cpp | 9 +++--- examples/cxx/ADM_get_transfer_priority.cpp | 1 + .../ADM_link_transfer_to_data_operation.cpp | 1 + examples/cxx/ADM_ping.cpp | 1 + examples/cxx/ADM_register_adhoc_storage.cpp | 6 +++- examples/cxx/ADM_register_job.cpp | 6 +++- examples/cxx/ADM_register_pfs_storage.cpp | 1 + examples/cxx/ADM_remove_adhoc_storage.cpp | 6 +++- examples/cxx/ADM_remove_job.cpp | 6 +++- examples/cxx/ADM_remove_pfs_storage.cpp | 1 + examples/cxx/ADM_set_dataset_information.cpp | 1 + examples/cxx/ADM_set_io_resources.cpp | 1 + examples/cxx/ADM_set_qos_constraints.cpp | 1 + examples/cxx/ADM_set_transfer_priority.cpp | 1 + examples/cxx/ADM_terminate_adhoc_storage.cpp | 6 +++- examples/cxx/ADM_transfer_datasets.cpp | 6 +++- examples/cxx/ADM_update_adhoc_storage.cpp | 6 +++- examples/cxx/ADM_update_job.cpp | 3 +- examples/cxx/ADM_update_pfs_storage.cpp | 1 + examples/cxx/common.cpp | 15 +++++++--- examples/cxx/common.hpp | 2 ++ plugins/slurm/defaults.h.in | 3 ++ plugins/slurm/slurmadmcli.c | 30 ++++++++++++++++--- src/lib/scord/types.h | 5 +++- src/lib/scord/types.hpp | 23 +++++++++----- src/lib/types.c | 13 +++++++- src/lib/types.cpp | 11 +++++-- src/lib/types_private.h | 2 ++ 59 files changed, 215 insertions(+), 94 deletions(-) diff --git a/examples/c/ADM_cancel_transfer.c b/examples/c/ADM_cancel_transfer.c index 77bb2a0b..1ebafe56 100644 --- a/examples/c/ADM_cancel_transfer.c +++ b/examples/c/ADM_cancel_transfer.c @@ -69,8 +69,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, - ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, cli_args.data_stager_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_connect_data_operation.c b/examples/c/ADM_connect_data_operation.c index 8ae8f55e..b043f1c9 100644 --- a/examples/c/ADM_connect_data_operation.c +++ b/examples/c/ADM_connect_data_operation.c @@ -65,8 +65,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, - ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, cli_args.data_stager_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_define_data_operation.c b/examples/c/ADM_define_data_operation.c index 04a151c4..89edeca8 100644 --- a/examples/c/ADM_define_data_operation.c +++ b/examples/c/ADM_define_data_operation.c @@ -70,8 +70,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, - ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, cli_args.data_stager_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_deploy_adhoc_storage.c b/examples/c/ADM_deploy_adhoc_storage.c index b5317eb1..dd284cf7 100644 --- a/examples/c/ADM_deploy_adhoc_storage.c +++ b/examples/c/ADM_deploy_adhoc_storage.c @@ -82,9 +82,9 @@ main(int argc, char* argv[]) { } // 3. the adhoc storage execution context - adhoc_ctx = ADM_adhoc_context_create(cli_args.controller_address, - ADM_ADHOC_MODE_SEPARATE_NEW, - ADM_ADHOC_ACCESS_RDWR, 100, false); + adhoc_ctx = ADM_adhoc_context_create( + cli_args.controller_address, cli_args.data_stager_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); if(adhoc_ctx == NULL) { fprintf(stderr, "Fatal error preparing adhoc context\n"); @@ -115,9 +115,9 @@ main(int argc, char* argv[]) { // system, let's prepare a new execution context for the adhoc // storage system - new_adhoc_ctx = ADM_adhoc_context_create(cli_args.controller_address, - ADM_ADHOC_MODE_SEPARATE_NEW, - ADM_ADHOC_ACCESS_RDWR, 200, false); + new_adhoc_ctx = ADM_adhoc_context_create( + cli_args.controller_address, cli_args.data_stager_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 200, false); if(new_adhoc_ctx == NULL) { fprintf(stderr, "Fatal error preparing new adhoc context\n"); diff --git a/examples/c/ADM_finalize_data_operation.c b/examples/c/ADM_finalize_data_operation.c index 89c421ea..01cdb68b 100644 --- a/examples/c/ADM_finalize_data_operation.c +++ b/examples/c/ADM_finalize_data_operation.c @@ -65,8 +65,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, - ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, cli_args.data_stager_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_get_pending_transfers.c b/examples/c/ADM_get_pending_transfers.c index 6789136c..31a66c84 100644 --- a/examples/c/ADM_get_pending_transfers.c +++ b/examples/c/ADM_get_pending_transfers.c @@ -69,8 +69,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, - ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, cli_args.data_stager_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_get_qos_constraints.c b/examples/c/ADM_get_qos_constraints.c index be8498ee..bd9cefa2 100644 --- a/examples/c/ADM_get_qos_constraints.c +++ b/examples/c/ADM_get_qos_constraints.c @@ -65,8 +65,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, - ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, cli_args.data_stager_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_get_statistics.c b/examples/c/ADM_get_statistics.c index 4f0c7db5..d9924997 100644 --- a/examples/c/ADM_get_statistics.c +++ b/examples/c/ADM_get_statistics.c @@ -65,8 +65,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, - ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, cli_args.data_stager_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_get_transfer_priority.c b/examples/c/ADM_get_transfer_priority.c index 5a5957bd..b4210ecf 100644 --- a/examples/c/ADM_get_transfer_priority.c +++ b/examples/c/ADM_get_transfer_priority.c @@ -69,8 +69,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, - ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, cli_args.data_stager_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_link_transfer_to_data_operation.c b/examples/c/ADM_link_transfer_to_data_operation.c index bfab8b6b..e980989e 100644 --- a/examples/c/ADM_link_transfer_to_data_operation.c +++ b/examples/c/ADM_link_transfer_to_data_operation.c @@ -65,8 +65,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, - ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, cli_args.data_stager_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_register_adhoc_storage.c b/examples/c/ADM_register_adhoc_storage.c index 0d2ff17e..b517655e 100644 --- a/examples/c/ADM_register_adhoc_storage.c +++ b/examples/c/ADM_register_adhoc_storage.c @@ -78,9 +78,9 @@ main(int argc, char* argv[]) { } // 3. define the adhoc execution context - adhoc_ctx = ADM_adhoc_context_create(cli_args.controller_address, - ADM_ADHOC_MODE_SEPARATE_NEW, - ADM_ADHOC_ACCESS_RDWR, 100, false); + adhoc_ctx = ADM_adhoc_context_create( + cli_args.controller_address, cli_args.data_stager_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); if(adhoc_ctx == NULL) { fprintf(stderr, "Fatal error preparing adhoc context\n"); diff --git a/examples/c/ADM_register_job.c b/examples/c/ADM_register_job.c index e4be4153..93492306 100644 --- a/examples/c/ADM_register_job.c +++ b/examples/c/ADM_register_job.c @@ -88,9 +88,9 @@ main(int argc, char* argv[]) { } // 3. the adhoc storage execution context - adhoc_ctx = ADM_adhoc_context_create(cli_args.controller_address, - ADM_ADHOC_MODE_SEPARATE_NEW, - ADM_ADHOC_ACCESS_RDWR, 100, false); + adhoc_ctx = ADM_adhoc_context_create( + cli_args.controller_address, cli_args.data_stager_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); if(adhoc_ctx == NULL) { fprintf(stderr, "Fatal error preparing adhoc context\n"); diff --git a/examples/c/ADM_remove_adhoc_storage.c b/examples/c/ADM_remove_adhoc_storage.c index 17d8cf78..56dd50b5 100644 --- a/examples/c/ADM_remove_adhoc_storage.c +++ b/examples/c/ADM_remove_adhoc_storage.c @@ -80,9 +80,9 @@ main(int argc, char* argv[]) { } // 3. the adhoc storage execution context - adhoc_ctx = ADM_adhoc_context_create(cli_args.controller_address, - ADM_ADHOC_MODE_SEPARATE_NEW, - ADM_ADHOC_ACCESS_RDWR, 100, false); + adhoc_ctx = ADM_adhoc_context_create( + cli_args.controller_address, cli_args.data_stager_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); if(adhoc_ctx == NULL) { fprintf(stderr, "Fatal error preparing adhoc context\n"); diff --git a/examples/c/ADM_remove_job.c b/examples/c/ADM_remove_job.c index ddf7a2d6..d9670ba7 100644 --- a/examples/c/ADM_remove_job.c +++ b/examples/c/ADM_remove_job.c @@ -69,8 +69,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, - ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, cli_args.data_stager_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_set_dataset_information.c b/examples/c/ADM_set_dataset_information.c index 548befd8..9aa9477c 100644 --- a/examples/c/ADM_set_dataset_information.c +++ b/examples/c/ADM_set_dataset_information.c @@ -65,8 +65,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, - ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, cli_args.data_stager_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_set_io_resources.c b/examples/c/ADM_set_io_resources.c index cdf07a3b..30691cbc 100644 --- a/examples/c/ADM_set_io_resources.c +++ b/examples/c/ADM_set_io_resources.c @@ -65,8 +65,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, - ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, cli_args.data_stager_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_set_qos_constraints.c b/examples/c/ADM_set_qos_constraints.c index a7f07bc1..78b79377 100644 --- a/examples/c/ADM_set_qos_constraints.c +++ b/examples/c/ADM_set_qos_constraints.c @@ -69,8 +69,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, - ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, cli_args.data_stager_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_set_transfer_priority.c b/examples/c/ADM_set_transfer_priority.c index 8ba26be5..5b3de186 100644 --- a/examples/c/ADM_set_transfer_priority.c +++ b/examples/c/ADM_set_transfer_priority.c @@ -69,8 +69,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, - ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, cli_args.data_stager_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_terminate_adhoc_storage.c b/examples/c/ADM_terminate_adhoc_storage.c index dafd05e8..39f34a44 100644 --- a/examples/c/ADM_terminate_adhoc_storage.c +++ b/examples/c/ADM_terminate_adhoc_storage.c @@ -82,9 +82,9 @@ main(int argc, char* argv[]) { } // 3. the adhoc storage execution context - adhoc_ctx = ADM_adhoc_context_create(cli_args.controller_address, - ADM_ADHOC_MODE_SEPARATE_NEW, - ADM_ADHOC_ACCESS_RDWR, 100, false); + adhoc_ctx = ADM_adhoc_context_create( + cli_args.controller_address, cli_args.data_stager_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); if(adhoc_ctx == NULL) { fprintf(stderr, "Fatal error preparing adhoc context\n"); @@ -115,9 +115,9 @@ main(int argc, char* argv[]) { // system, let's prepare a new execution context for the adhoc // storage system - new_adhoc_ctx = ADM_adhoc_context_create(cli_args.controller_address, - ADM_ADHOC_MODE_SEPARATE_NEW, - ADM_ADHOC_ACCESS_RDWR, 200, false); + new_adhoc_ctx = ADM_adhoc_context_create( + cli_args.controller_address, cli_args.data_stager_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 200, false); if(new_adhoc_ctx == NULL) { fprintf(stderr, "Fatal error preparing new adhoc context\n"); diff --git a/examples/c/ADM_transfer_datasets.c b/examples/c/ADM_transfer_datasets.c index 343c603e..b0bc6c1f 100644 --- a/examples/c/ADM_transfer_datasets.c +++ b/examples/c/ADM_transfer_datasets.c @@ -72,8 +72,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, - ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, cli_args.data_stager_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_update_adhoc_storage.c b/examples/c/ADM_update_adhoc_storage.c index 823f5504..cb5163ba 100644 --- a/examples/c/ADM_update_adhoc_storage.c +++ b/examples/c/ADM_update_adhoc_storage.c @@ -84,9 +84,9 @@ main(int argc, char* argv[]) { } // 3. the adhoc storage execution context - adhoc_ctx = ADM_adhoc_context_create(cli_args.controller_address, - ADM_ADHOC_MODE_SEPARATE_NEW, - ADM_ADHOC_ACCESS_RDWR, 100, false); + adhoc_ctx = ADM_adhoc_context_create( + cli_args.controller_address, cli_args.data_stager_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); if(adhoc_ctx == NULL) { fprintf(stderr, "Fatal error preparing adhoc context\n"); @@ -124,9 +124,9 @@ main(int argc, char* argv[]) { goto cleanup; } - new_adhoc_ctx = ADM_adhoc_context_create(cli_args.controller_address, - ADM_ADHOC_MODE_SEPARATE_NEW, - ADM_ADHOC_ACCESS_RDWR, 200, false); + new_adhoc_ctx = ADM_adhoc_context_create( + cli_args.controller_address, cli_args.data_stager_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 200, false); if(new_adhoc_ctx == NULL) { fprintf(stderr, "Fatal error preparing new adhoc context\n"); diff --git a/examples/c/ADM_update_job.c b/examples/c/ADM_update_job.c index 25ca6735..599b3fe1 100644 --- a/examples/c/ADM_update_job.c +++ b/examples/c/ADM_update_job.c @@ -69,8 +69,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, - ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, cli_args.data_stager_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/common.c b/examples/c/common.c index b1993598..178cce7b 100644 --- a/examples/c/common.c +++ b/examples/c/common.c @@ -18,11 +18,16 @@ process_args(int argc, char* argv[], test_info_t test_info, cli_args_t* args) { ++required_args; } + if(test_info.requires_data_stager) { + ++required_args; + } + if(argc != required_args) { fprintf(stderr, "ERROR: missing arguments\n"); - fprintf(stderr, "Usage: %s%s%s\n", test_info.name, + fprintf(stderr, "Usage: %s%s%s%s\n", test_info.name, test_info.requires_server ? " " : "", - test_info.requires_controller ? " " : ""); + test_info.requires_controller ? " " : "", + test_info.requires_data_stager ? " " : ""); return -1; } diff --git a/examples/c/common.h b/examples/c/common.h index 53d47211..ca8c32ee 100644 --- a/examples/c/common.h +++ b/examples/c/common.h @@ -11,11 +11,13 @@ typedef struct { const char* name; bool requires_server; bool requires_controller; + bool requires_data_stager; } test_info_t; typedef struct { const char* server_address; const char* controller_address; + const char* data_stager_address; } cli_args_t; int diff --git a/examples/cxx/ADM_cancel_transfer.cpp b/examples/cxx/ADM_cancel_transfer.cpp index d2791147..7ed4a55c 100644 --- a/examples/cxx/ADM_cancel_transfer.cpp +++ b/examples/cxx/ADM_cancel_transfer.cpp @@ -33,6 +33,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; const auto cli_args = process_args(argc, argv, test_info); diff --git a/examples/cxx/ADM_connect_data_operation.cpp b/examples/cxx/ADM_connect_data_operation.cpp index d3bc9ac1..74499a8d 100644 --- a/examples/cxx/ADM_connect_data_operation.cpp +++ b/examples/cxx/ADM_connect_data_operation.cpp @@ -33,6 +33,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; const auto cli_args = process_args(argc, argv, test_info); diff --git a/examples/cxx/ADM_define_data_operation.cpp b/examples/cxx/ADM_define_data_operation.cpp index e34a8d05..097a8c00 100644 --- a/examples/cxx/ADM_define_data_operation.cpp +++ b/examples/cxx/ADM_define_data_operation.cpp @@ -33,6 +33,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; const auto cli_args = process_args(argc, argv, test_info); diff --git a/examples/cxx/ADM_deploy_adhoc_storage.cpp b/examples/cxx/ADM_deploy_adhoc_storage.cpp index 93030a27..0944ee1a 100644 --- a/examples/cxx/ADM_deploy_adhoc_storage.cpp +++ b/examples/cxx/ADM_deploy_adhoc_storage.cpp @@ -38,6 +38,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; const auto cli_args = process_args(argc, argv, test_info); @@ -51,8 +52,11 @@ main(int argc, char* argv[]) { std::string name = "adhoc_storage_42"; const auto adhoc_storage_ctx = scord::adhoc_storage::ctx{ cli_args.controller_address, + cli_args.data_stager_address, scord::adhoc_storage::execution_mode::separate_new, - scord::adhoc_storage::access_type::read_write, 100, false}; + scord::adhoc_storage::access_type::read_write, + 100, + false}; const auto adhoc_resources = scord::adhoc_storage::resources{adhoc_nodes}; try { diff --git a/examples/cxx/ADM_finalize_data_operation.cpp b/examples/cxx/ADM_finalize_data_operation.cpp index a9148a19..acc18a19 100644 --- a/examples/cxx/ADM_finalize_data_operation.cpp +++ b/examples/cxx/ADM_finalize_data_operation.cpp @@ -33,6 +33,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; const auto cli_args = process_args(argc, argv, test_info); diff --git a/examples/cxx/ADM_get_pending_transfers.cpp b/examples/cxx/ADM_get_pending_transfers.cpp index 60f7d9eb..e5bd97e0 100644 --- a/examples/cxx/ADM_get_pending_transfers.cpp +++ b/examples/cxx/ADM_get_pending_transfers.cpp @@ -33,6 +33,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; const auto cli_args = process_args(argc, argv, test_info); diff --git a/examples/cxx/ADM_get_qos_constraints.cpp b/examples/cxx/ADM_get_qos_constraints.cpp index 389ac2b1..04d3c62e 100644 --- a/examples/cxx/ADM_get_qos_constraints.cpp +++ b/examples/cxx/ADM_get_qos_constraints.cpp @@ -33,6 +33,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; const auto cli_args = process_args(argc, argv, test_info); diff --git a/examples/cxx/ADM_get_statistics.cpp b/examples/cxx/ADM_get_statistics.cpp index a19e506b..15a12c95 100644 --- a/examples/cxx/ADM_get_statistics.cpp +++ b/examples/cxx/ADM_get_statistics.cpp @@ -29,11 +29,10 @@ int main(int argc, char* argv[]) { - test_info test_info{ - .name = TESTNAME, - .requires_server = true, - .requires_controller = true, - }; + test_info test_info{.name = TESTNAME, + .requires_server = true, + .requires_controller = true, + .requires_data_stager = true}; const auto cli_args = process_args(argc, argv, test_info); diff --git a/examples/cxx/ADM_get_transfer_priority.cpp b/examples/cxx/ADM_get_transfer_priority.cpp index 983c39c1..6db261c9 100644 --- a/examples/cxx/ADM_get_transfer_priority.cpp +++ b/examples/cxx/ADM_get_transfer_priority.cpp @@ -33,6 +33,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; const auto cli_args = process_args(argc, argv, test_info); diff --git a/examples/cxx/ADM_link_transfer_to_data_operation.cpp b/examples/cxx/ADM_link_transfer_to_data_operation.cpp index 2227afd1..a8256cc2 100644 --- a/examples/cxx/ADM_link_transfer_to_data_operation.cpp +++ b/examples/cxx/ADM_link_transfer_to_data_operation.cpp @@ -33,6 +33,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; const auto cli_args = process_args(argc, argv, test_info); diff --git a/examples/cxx/ADM_ping.cpp b/examples/cxx/ADM_ping.cpp index ef796074..abc62596 100644 --- a/examples/cxx/ADM_ping.cpp +++ b/examples/cxx/ADM_ping.cpp @@ -33,6 +33,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = false, + .requires_data_stager = false, }; const auto cli_args = process_args(argc, argv, test_info); diff --git a/examples/cxx/ADM_register_adhoc_storage.cpp b/examples/cxx/ADM_register_adhoc_storage.cpp index 0dfd0f9b..d2c07d40 100644 --- a/examples/cxx/ADM_register_adhoc_storage.cpp +++ b/examples/cxx/ADM_register_adhoc_storage.cpp @@ -38,6 +38,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; const auto cli_args = process_args(argc, argv, test_info); @@ -51,8 +52,11 @@ main(int argc, char* argv[]) { std::string name = "adhoc_storage_42"; const auto adhoc_storage_ctx = scord::adhoc_storage::ctx{ cli_args.controller_address, + cli_args.data_stager_address, scord::adhoc_storage::execution_mode::separate_new, - scord::adhoc_storage::access_type::read_write, 100, false}; + scord::adhoc_storage::access_type::read_write, + 100, + false}; const auto adhoc_resources = scord::adhoc_storage::resources{adhoc_nodes}; try { diff --git a/examples/cxx/ADM_register_job.cpp b/examples/cxx/ADM_register_job.cpp index 55ac84d6..f56ff510 100644 --- a/examples/cxx/ADM_register_job.cpp +++ b/examples/cxx/ADM_register_job.cpp @@ -38,6 +38,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; const auto cli_args = process_args(argc, argv, test_info); @@ -52,8 +53,11 @@ main(int argc, char* argv[]) { std::string name = "adhoc_storage_42"; const auto adhoc_storage_ctx = scord::adhoc_storage::ctx{ cli_args.controller_address, + cli_args.data_stager_address, scord::adhoc_storage::execution_mode::separate_new, - scord::adhoc_storage::access_type::read_write, 100, false}; + scord::adhoc_storage::access_type::read_write, + 100, + false}; const auto adhoc_resources = scord::adhoc_storage::resources{adhoc_nodes}; try { diff --git a/examples/cxx/ADM_register_pfs_storage.cpp b/examples/cxx/ADM_register_pfs_storage.cpp index 1078262c..54ac2f00 100644 --- a/examples/cxx/ADM_register_pfs_storage.cpp +++ b/examples/cxx/ADM_register_pfs_storage.cpp @@ -34,6 +34,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = false, + .requires_data_stager = false, }; const auto cli_args = process_args(argc, argv, test_info); diff --git a/examples/cxx/ADM_remove_adhoc_storage.cpp b/examples/cxx/ADM_remove_adhoc_storage.cpp index aa496ee6..05d9d8b0 100644 --- a/examples/cxx/ADM_remove_adhoc_storage.cpp +++ b/examples/cxx/ADM_remove_adhoc_storage.cpp @@ -38,6 +38,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; const auto cli_args = process_args(argc, argv, test_info); @@ -51,8 +52,11 @@ main(int argc, char* argv[]) { std::string name = "adhoc_storage_42"; const auto adhoc_storage_ctx = scord::adhoc_storage::ctx{ cli_args.controller_address, + cli_args.data_stager_address, scord::adhoc_storage::execution_mode::separate_new, - scord::adhoc_storage::access_type::read_write, 100, false}; + scord::adhoc_storage::access_type::read_write, + 100, + false}; const auto adhoc_resources = scord::adhoc_storage::resources{adhoc_nodes}; try { diff --git a/examples/cxx/ADM_remove_job.cpp b/examples/cxx/ADM_remove_job.cpp index 4a3ae71c..9d046fea 100644 --- a/examples/cxx/ADM_remove_job.cpp +++ b/examples/cxx/ADM_remove_job.cpp @@ -38,6 +38,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; const auto cli_args = process_args(argc, argv, test_info); @@ -52,8 +53,11 @@ main(int argc, char* argv[]) { std::string name = "adhoc_storage_42"; const auto adhoc_storage_ctx = scord::adhoc_storage::ctx{ cli_args.controller_address, + cli_args.data_stager_address, scord::adhoc_storage::execution_mode::separate_new, - scord::adhoc_storage::access_type::read_write, 100, false}; + scord::adhoc_storage::access_type::read_write, + 100, + false}; const auto adhoc_resources = scord::adhoc_storage::resources{adhoc_nodes}; diff --git a/examples/cxx/ADM_remove_pfs_storage.cpp b/examples/cxx/ADM_remove_pfs_storage.cpp index 8e5bd527..21bcfddf 100644 --- a/examples/cxx/ADM_remove_pfs_storage.cpp +++ b/examples/cxx/ADM_remove_pfs_storage.cpp @@ -34,6 +34,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = false, + .requires_data_stager = false, }; const auto cli_args = process_args(argc, argv, test_info); diff --git a/examples/cxx/ADM_set_dataset_information.cpp b/examples/cxx/ADM_set_dataset_information.cpp index 863e6774..7ddc6c0d 100644 --- a/examples/cxx/ADM_set_dataset_information.cpp +++ b/examples/cxx/ADM_set_dataset_information.cpp @@ -34,6 +34,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; const auto cli_args = process_args(argc, argv, test_info); diff --git a/examples/cxx/ADM_set_io_resources.cpp b/examples/cxx/ADM_set_io_resources.cpp index 425b4642..17acf0ae 100644 --- a/examples/cxx/ADM_set_io_resources.cpp +++ b/examples/cxx/ADM_set_io_resources.cpp @@ -34,6 +34,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; const auto cli_args = process_args(argc, argv, test_info); diff --git a/examples/cxx/ADM_set_qos_constraints.cpp b/examples/cxx/ADM_set_qos_constraints.cpp index d487b576..55e6efb0 100644 --- a/examples/cxx/ADM_set_qos_constraints.cpp +++ b/examples/cxx/ADM_set_qos_constraints.cpp @@ -33,6 +33,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; const auto cli_args = process_args(argc, argv, test_info); diff --git a/examples/cxx/ADM_set_transfer_priority.cpp b/examples/cxx/ADM_set_transfer_priority.cpp index 39819b47..86416f1c 100644 --- a/examples/cxx/ADM_set_transfer_priority.cpp +++ b/examples/cxx/ADM_set_transfer_priority.cpp @@ -34,6 +34,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; const auto cli_args = process_args(argc, argv, test_info); diff --git a/examples/cxx/ADM_terminate_adhoc_storage.cpp b/examples/cxx/ADM_terminate_adhoc_storage.cpp index e7b26594..737e1d4f 100644 --- a/examples/cxx/ADM_terminate_adhoc_storage.cpp +++ b/examples/cxx/ADM_terminate_adhoc_storage.cpp @@ -38,6 +38,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; const auto cli_args = process_args(argc, argv, test_info); @@ -51,8 +52,11 @@ main(int argc, char* argv[]) { std::string name = "adhoc_storage_42"; const auto adhoc_storage_ctx = scord::adhoc_storage::ctx{ cli_args.controller_address, + cli_args.data_stager_address, scord::adhoc_storage::execution_mode::separate_new, - scord::adhoc_storage::access_type::read_write, 100, false}; + scord::adhoc_storage::access_type::read_write, + 100, + false}; const auto adhoc_resources = scord::adhoc_storage::resources{adhoc_nodes}; try { diff --git a/examples/cxx/ADM_transfer_datasets.cpp b/examples/cxx/ADM_transfer_datasets.cpp index 2b4e6f02..c6485daa 100644 --- a/examples/cxx/ADM_transfer_datasets.cpp +++ b/examples/cxx/ADM_transfer_datasets.cpp @@ -41,6 +41,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; const auto cli_args = process_args(argc, argv, test_info); @@ -60,8 +61,11 @@ main(int argc, char* argv[]) { std::string name = "adhoc_storage_42"; const auto adhoc_storage_ctx = scord::adhoc_storage::ctx{ cli_args.controller_address, + cli_args.data_stager_address, scord::adhoc_storage::execution_mode::separate_new, - scord::adhoc_storage::access_type::read_write, 100, false}; + scord::adhoc_storage::access_type::read_write, + 100, + false}; const auto adhoc_resources = scord::adhoc_storage::resources{adhoc_nodes}; try { diff --git a/examples/cxx/ADM_update_adhoc_storage.cpp b/examples/cxx/ADM_update_adhoc_storage.cpp index dbb2ac93..a7b88deb 100644 --- a/examples/cxx/ADM_update_adhoc_storage.cpp +++ b/examples/cxx/ADM_update_adhoc_storage.cpp @@ -37,6 +37,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; const auto cli_args = process_args(argc, argv, test_info); @@ -51,8 +52,11 @@ main(int argc, char* argv[]) { std::string name = "adhoc_storage_42"; const auto adhoc_storage_ctx = scord::adhoc_storage::ctx{ cli_args.controller_address, + cli_args.data_stager_address, scord::adhoc_storage::execution_mode::separate_new, - scord::adhoc_storage::access_type::read_write, 100, false}; + scord::adhoc_storage::access_type::read_write, + 100, + false}; const auto adhoc_resources = scord::adhoc_storage::resources{adhoc_nodes}; const auto new_adhoc_resources = diff --git a/examples/cxx/ADM_update_job.cpp b/examples/cxx/ADM_update_job.cpp index 1ee22d58..f83901e2 100644 --- a/examples/cxx/ADM_update_job.cpp +++ b/examples/cxx/ADM_update_job.cpp @@ -38,6 +38,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; const auto cli_args = process_args(argc, argv, test_info); @@ -53,7 +54,7 @@ main(int argc, char* argv[]) { const auto gkfs_storage = scord::register_adhoc_storage( server, "foobar", scord::adhoc_storage::type::gekkofs, scord::adhoc_storage::ctx{ - cli_args.controller_address, + cli_args.controller_address, cli_args.data_stager_address, scord::adhoc_storage::execution_mode::separate_new, scord::adhoc_storage::access_type::read_write, 100, false}, scord::adhoc_storage::resources{adhoc_nodes}); diff --git a/examples/cxx/ADM_update_pfs_storage.cpp b/examples/cxx/ADM_update_pfs_storage.cpp index 019fe110..699d0ea9 100644 --- a/examples/cxx/ADM_update_pfs_storage.cpp +++ b/examples/cxx/ADM_update_pfs_storage.cpp @@ -34,6 +34,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = false, + .requires_data_stager = false, }; const auto cli_args = process_args(argc, argv, test_info); diff --git a/examples/cxx/common.cpp b/examples/cxx/common.cpp index cf83a8a9..6ced6dcb 100644 --- a/examples/cxx/common.cpp +++ b/examples/cxx/common.cpp @@ -15,17 +15,24 @@ process_args(int argc, char* argv[], const test_info& test_info) { ++required_args; } + if(test_info.requires_data_stager) { + ++required_args; + } + if(argc != required_args) { fmt::print(stderr, "ERROR: missing arguments\n"); - fmt::print(stderr, "Usage: {}{}{}\n", test_info.name, + fmt::print(stderr, "Usage: {}{}{}{}\n", test_info.name, test_info.requires_server ? " " : "", - test_info.requires_controller ? " " - : ""); + test_info.requires_controller ? " " : "", + test_info.requires_data_stager ? " " + : ""); exit(EXIT_FAILURE); } return cli_args{test_info.requires_server ? std::string{argv[1]} : ""s, - test_info.requires_controller ? std::string{argv[2]} : ""s}; + test_info.requires_controller ? std::string{argv[2]} : ""s, + test_info.requires_data_stager ? std::string{argv[3]} + : ""s}; } std::vector diff --git a/examples/cxx/common.hpp b/examples/cxx/common.hpp index 374ad264..2a16fd21 100644 --- a/examples/cxx/common.hpp +++ b/examples/cxx/common.hpp @@ -12,11 +12,13 @@ struct test_info { std::string name; bool requires_server; bool requires_controller; + bool requires_data_stager; }; struct cli_args { std::string server_address; std::string controller_address; + std::string data_stager_address; }; cli_args diff --git a/plugins/slurm/defaults.h.in b/plugins/slurm/defaults.h.in index 0568e099..9de23bc6 100644 --- a/plugins/slurm/defaults.h.in +++ b/plugins/slurm/defaults.h.in @@ -37,6 +37,9 @@ #define SCORDCTL_PROTO_DEFAULT SCORD_PROTO_DEFAULT #define SCORDCTL_PORT_DEFAULT @SCORD_CTL_BIND_PORT@ #define SCORDCTL_TMPDIR_DEFAULT "/tmp" +#define CARGO_PROG_DEFAULT "@CARGO_PROGRAM@" +#define CARGO_PROTO_DEFAULT SCORD_PROTO_DEFAULT +#define CARGO_PORT_DEFAULT 62000 // clang-format on diff --git a/plugins/slurm/slurmadmcli.c b/plugins/slurm/slurmadmcli.c index 204c0840..4bb40e70 100644 --- a/plugins/slurm/slurmadmcli.c +++ b/plugins/slurm/slurmadmcli.c @@ -84,6 +84,7 @@ typedef struct { typedef struct { scord_server_info_t scord_info; scord_server_info_t scordctl_info; + scord_server_info_t cargo_info; } scord_plugin_config_t; @@ -97,7 +98,12 @@ static scord_plugin_config_t default_cfg = { .proto = SCORDCTL_PROTO_DEFAULT, .port = SCORDCTL_PORT_DEFAULT, .prog = SCORDCTL_PROG_DEFAULT, - .tmpdir = SCORDCTL_TMPDIR_DEFAULT}}; + .tmpdir = SCORDCTL_TMPDIR_DEFAULT}, + .cargo_info = {.addr = NULL, + .proto = CARGO_PROTO_DEFAULT, + .port = CARGO_PORT_DEFAULT, + .prog = CARGO_PROG_DEFAULT, + .tmpdir = NULL}}; static int process_opts(int tag, const char* optarg, int remote); @@ -305,6 +311,8 @@ process_config(int ac, char** av, scord_plugin_config_t* cfg) { &cfg->scordctl_info.port), EXPAND_SCORD_OPT("scordctl_tmpdir", TYPE_STR, &cfg->scordctl_info.tmpdir), + EXPAND_SCORD_OPT("cargo_prog", TYPE_STR, &cfg->cargo_info.prog), + EXPAND_SCORD_OPT("cargo_port", TYPE_INT, &cfg->cargo_info.port), }; #undef EXPAND_SCORD_OPT @@ -389,6 +397,12 @@ scord_register_job(scord_plugin_config_t cfg, scord_nodelist_t nodelist, return -1; } + /* The Cargo master will also typically reside on the first node of the + * allocation */ + cfg.cargo_info.addr = margo_address_create(cfg.cargo_info.proto, + ADM_node_get_hostname(ctl_node), + cfg.cargo_info.port); + slurm_debug("%s: %s: scord_info:", plugin_name, __func__); slurm_debug("%s: %s: addr: \"%s\",", plugin_name, __func__, cfg.scord_info.addr); @@ -405,6 +419,14 @@ scord_register_job(scord_plugin_config_t cfg, scord_nodelist_t nodelist, slurm_debug("%s: %s: port: %d,", plugin_name, __func__, cfg.scordctl_info.port); + slurm_debug("%s: %s: cargo_info:", plugin_name, __func__); + slurm_debug("%s: %s: addr: \"%s\",", plugin_name, __func__, + cfg.cargo_info.addr); + slurm_debug("%s: %s: proto: \"%s\",", plugin_name, __func__, + cfg.cargo_info.proto); + slurm_debug("%s: %s: port: %d,", plugin_name, __func__, + cfg.cargo_info.port); + /* Register the job with the scord server */ scord_server = ADM_server_create(cfg.scord_info.proto, cfg.scord_info.addr); if(!scord_server) { @@ -443,9 +465,9 @@ scord_register_job(scord_plugin_config_t cfg, scord_nodelist_t nodelist, goto end; } - adhoc_ctx = ADM_adhoc_context_create(cfg.scordctl_info.addr, adhoc_mode, - ADM_ADHOC_ACCESS_RDWR, adhoc_walltime, - false); + adhoc_ctx = ADM_adhoc_context_create( + cfg.scordctl_info.addr, cfg.cargo_info.addr, adhoc_mode, + ADM_ADHOC_ACCESS_RDWR, adhoc_walltime, false); if(!adhoc_ctx) { slurm_error("%s: adhoc_context creation failed", plugin_name); rc = -1; diff --git a/src/lib/scord/types.h b/src/lib/scord/types.h index 633f849b..e8c32fcd 100644 --- a/src/lib/scord/types.h +++ b/src/lib/scord/types.h @@ -536,6 +536,8 @@ ADM_adhoc_resources_destroy(ADM_adhoc_resources_t res); * * @param[in] ctl_address The address of the control node for the * adhoc storage system + * @param[in] stager_address The address of the data stager for the + * adhoc storage system * @param[in] exec_mode The adhoc storage system execution mode * @param[in] access_type The adhoc storage system execution type * @param[in] walltime The adhoc storage system walltime @@ -544,7 +546,8 @@ ADM_adhoc_resources_destroy(ADM_adhoc_resources_t res); * @return A valid ADM_ADHOC_CONTEXT if successful. NULL otherwise. */ ADM_adhoc_context_t -ADM_adhoc_context_create(const char* ctl_address, ADM_adhoc_mode_t exec_mode, +ADM_adhoc_context_create(const char* ctl_address, const char* stager_address, + ADM_adhoc_mode_t exec_mode, ADM_adhoc_access_t access_type, uint32_t walltime, bool should_flush); diff --git a/src/lib/scord/types.hpp b/src/lib/scord/types.hpp index 4f34f36a..10b890ad 100644 --- a/src/lib/scord/types.hpp +++ b/src/lib/scord/types.hpp @@ -236,14 +236,19 @@ struct adhoc_storage { ctx() = default; - ctx(std::string controller_address, execution_mode exec_mode, - access_type access_type, std::uint32_t walltime, bool should_flush); + ctx(std::string controller_address, std::string data_stager_address, + execution_mode exec_mode, access_type access_type, + std::uint32_t walltime, bool should_flush); explicit ctx(ADM_adhoc_context_t ctx); explicit operator ADM_adhoc_context_t() const; std::string const& controller_address() const; + + std::string const& + data_stager_address() const; + execution_mode exec_mode() const; enum access_type @@ -257,6 +262,7 @@ struct adhoc_storage { void serialize(Archive&& ar) { ar & m_controller_address; + ar & m_data_stager_address; ar & m_exec_mode; ar & m_access_type; ar & m_walltime; @@ -265,6 +271,7 @@ struct adhoc_storage { private: std::string m_controller_address; + std::string m_data_stager_address; execution_mode m_exec_mode; enum access_type m_access_type; std::uint32_t m_walltime; @@ -923,11 +930,13 @@ struct fmt::formatter : formatter { template auto format(const scord::adhoc_storage::ctx& c, FormatContext& ctx) const { - return format_to(ctx.out(), - "{{controller: {}, execution_mode: {}, " - "access_type: {}, walltime: {}, should_flush: {}}}", - std::quoted(c.controller_address()), c.exec_mode(), - c.access_type(), c.walltime(), c.should_flush()); + return format_to( + ctx.out(), + "{{controller: {}, data_stager: {}, execution_mode: {}, " + "access_type: {}, walltime: {}, should_flush: {}}}", + std::quoted(c.controller_address()), + std::quoted(c.data_stager_address()), c.exec_mode(), + c.access_type(), c.walltime(), c.should_flush()); } }; diff --git a/src/lib/types.c b/src/lib/types.c index ab439d33..65c8a560 100644 --- a/src/lib/types.c +++ b/src/lib/types.c @@ -676,7 +676,8 @@ ADM_data_operation_destroy(ADM_data_operation_t op) { } ADM_adhoc_context_t -ADM_adhoc_context_create(const char* ctl_address, ADM_adhoc_mode_t exec_mode, +ADM_adhoc_context_create(const char* ctl_address, const char* stager_address, + ADM_adhoc_mode_t exec_mode, ADM_adhoc_access_t access_type, uint32_t walltime, bool should_flush) { @@ -685,6 +686,11 @@ ADM_adhoc_context_create(const char* ctl_address, ADM_adhoc_mode_t exec_mode, return NULL; } + if(!stager_address) { + LOGGER_ERROR("The address to the stager cannot be NULL"); + return NULL; + } + struct adm_adhoc_context* adm_adhoc_context = (struct adm_adhoc_context*) malloc(sizeof(*adm_adhoc_context)); @@ -699,6 +705,11 @@ ADM_adhoc_context_create(const char* ctl_address, ADM_adhoc_mode_t exec_mode, (const char*) calloc(n + 1, sizeof(char)); strcpy((char*) adm_adhoc_context->c_ctl_address, ctl_address); + n = strlen(stager_address); + adm_adhoc_context->c_stager_address = + (const char*) calloc(n + 1, sizeof(char)); + strcpy((char*) adm_adhoc_context->c_stager_address, stager_address); + adm_adhoc_context->c_mode = exec_mode; adm_adhoc_context->c_access = access_type; adm_adhoc_context->c_walltime = walltime; diff --git a/src/lib/types.cpp b/src/lib/types.cpp index cb6782e8..9b64acdb 100644 --- a/src/lib/types.cpp +++ b/src/lib/types.cpp @@ -562,22 +562,24 @@ adhoc_storage::resources::nodes() const { } adhoc_storage::ctx::ctx(std::string controller_address, + std::string data_stager_address, adhoc_storage::execution_mode exec_mode, adhoc_storage::access_type access_type, std::uint32_t walltime, bool should_flush) : m_controller_address(std::move(controller_address)), + m_data_stager_address(std::move(data_stager_address)), m_exec_mode(exec_mode), m_access_type(access_type), m_walltime(walltime), m_should_flush(should_flush) {} adhoc_storage::ctx::ctx(ADM_adhoc_context_t ctx) - : adhoc_storage::ctx(ctx->c_ctl_address, + : adhoc_storage::ctx(ctx->c_ctl_address, ctx->c_stager_address, static_cast(ctx->c_mode), static_cast(ctx->c_access), ctx->c_walltime, ctx->c_should_bg_flush) {} adhoc_storage::ctx::operator ADM_adhoc_context_t() const { return ADM_adhoc_context_create( - m_controller_address.c_str(), + m_controller_address.c_str(), m_data_stager_address.c_str(), static_cast(m_exec_mode), static_cast(m_access_type), m_walltime, m_should_flush); @@ -588,6 +590,11 @@ adhoc_storage::ctx::controller_address() const { return m_controller_address; } +std::string const& +adhoc_storage::ctx::data_stager_address() const { + return m_data_stager_address; +} + adhoc_storage::execution_mode adhoc_storage::ctx::exec_mode() const { return m_exec_mode; diff --git a/src/lib/types_private.h b/src/lib/types_private.h index 716766e3..bc431bd8 100644 --- a/src/lib/types_private.h +++ b/src/lib/types_private.h @@ -85,6 +85,8 @@ struct adm_dataset_info { struct adm_adhoc_context { /** The address to the node responsible for this adhoc storage system */ const char* c_ctl_address; + /** The address to the data stager for this adhoc storage system */ + const char* c_stager_address; /** The adhoc storage system execution mode */ ADM_adhoc_mode_t c_mode; /** The adhoc storage system access type */ -- GitLab From 79a38579d9b8c0ce94999e9fa14afba3d1ac6fc4 Mon Sep 17 00:00:00 2001 From: Alberto Miranda Date: Mon, 30 Oct 2023 18:45:29 +0100 Subject: [PATCH 2/8] WIP: [scord] Add transfer manager and initiate transfers in Cargo --- src/scord/CMakeLists.txt | 3 +- src/scord/internal_types.cpp | 5 ++ src/scord/internal_types.hpp | 41 +++++++++++ src/scord/rpc_server.cpp | 70 ++++++++++++++++-- src/scord/rpc_server.hpp | 6 ++ src/scord/transfer_manager.hpp | 129 +++++++++++++++++++++++++++++++++ 6 files changed, 246 insertions(+), 8 deletions(-) create mode 100644 src/scord/transfer_manager.hpp diff --git a/src/scord/CMakeLists.txt b/src/scord/CMakeLists.txt index 5ccfb19e..839e283a 100644 --- a/src/scord/CMakeLists.txt +++ b/src/scord/CMakeLists.txt @@ -26,7 +26,7 @@ add_executable(scord) target_sources(scord PRIVATE scord.cpp - job_manager.hpp adhoc_storage_manager.hpp + job_manager.hpp adhoc_storage_manager.hpp transfer_manager.hpp pfs_storage_manager.hpp ${CMAKE_CURRENT_BINARY_DIR}/defaults.hpp internal_types.hpp internal_types.cpp rpc_server.hpp rpc_server.cpp) @@ -51,6 +51,7 @@ target_link_libraries( CLI11::CLI11 RedisPlusPlus::RedisPlusPlus ryml::ryml + cargo::cargo ) install(TARGETS scord DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/src/scord/internal_types.cpp b/src/scord/internal_types.cpp index 993cefb2..2f723ef6 100644 --- a/src/scord/internal_types.cpp +++ b/src/scord/internal_types.cpp @@ -79,6 +79,11 @@ adhoc_storage_metadata::controller_address() const { return m_adhoc_storage.context().controller_address(); } +std::string const& +adhoc_storage_metadata::data_stager_address() const { + return m_adhoc_storage.context().data_stager_address(); +} + void adhoc_storage_metadata::update(scord::adhoc_storage::resources new_resources) { m_adhoc_storage.update(std::move(new_resources)); diff --git a/src/scord/internal_types.hpp b/src/scord/internal_types.hpp index e22f8621..92c7ee8b 100644 --- a/src/scord/internal_types.hpp +++ b/src/scord/internal_types.hpp @@ -81,6 +81,9 @@ struct adhoc_storage_metadata { std::string const& controller_address() const; + std::string const& + data_stager_address() const; + void update(scord::adhoc_storage::resources new_resources); @@ -114,6 +117,44 @@ struct pfs_storage_metadata { std::shared_ptr m_client_info; }; +template +struct transfer_metadata { + transfer_metadata(transfer_id id, TransferHandle&& handle, + std::vector qos) + : m_id(id), m_handle(handle), m_qos(std::move(qos)) {} + + transfer_id + id() const { + return m_id; + } + + TransferHandle + transfer() const { + return m_handle; + } + + std::vector const& + qos() const { + return m_qos; + } + + float + measured_bandwidth() const { + return m_measured_bandwidth; + } + + void + update(float bandwidth) { + m_measured_bandwidth = bandwidth; + } + + transfer_id m_id; + TransferHandle m_handle; + std::vector m_qos; + float m_measured_bandwidth = -1.0; +}; + + } // namespace scord::internal #endif // SCORD_INTERNAL_TYPES_HPP diff --git a/src/scord/rpc_server.cpp b/src/scord/rpc_server.cpp index 737b9319..fca82eb5 100644 --- a/src/scord/rpc_server.cpp +++ b/src/scord/rpc_server.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include "rpc_server.hpp" template @@ -611,17 +612,72 @@ rpc_server::transfer_datasets(const network::request& req, scord::job_id job_id, "limits: {}, mapping: {}}}", rpc, job_id, sources, targets, limits, mapping); - scord::error_code ec; + const auto jm_result = m_job_manager.find(job_id); + + if(!jm_result) { + LOGGER_ERROR("rpc id: {} error_msg: \"Error finding job: {}\"", + rpc.id(), job_id); + const auto resp = response_with_id{rpc.id(), jm_result.error()}; + LOGGER_ERROR("rpc {:<} body: {{retval: {}}}", rpc, resp.error_code()); + req.respond(resp); + return; + } + + const auto& job_metadata_ptr = jm_result.value(); + + if(!job_metadata_ptr->adhoc_storage_metadata()) { + LOGGER_ERROR("rpc id: {} error_msg: \"Job has no adhoc storage\"", + rpc.id(), job_id); + const auto resp = response_with_id{rpc.id(), error_code::no_resources}; + LOGGER_ERROR("rpc {:<} body: {{retval: {}}}", rpc, resp.error_code()); + req.respond(resp); + return; + } + + const auto data_stager_address = + job_metadata_ptr->adhoc_storage_metadata()->data_stager_address(); + + // Transform the `scord::dataset`s into `cargo::dataset`s and contact the + // Cargo service associated with the job's adhoc storage instance to + // execute the transfers. + cargo::server srv{data_stager_address}; - std::optional tx_id; + std::vector inputs; + std::vector outputs; - // TODO: generate a global ID for the transfer and contact Cargo to - // actually request it - tx_id = 42; + // TODO: check type of storage tier to enable parallel transfers + std::transform(sources.cbegin(), sources.cend(), std::back_inserter(inputs), + [](const auto& src) { return cargo::dataset{src.id()}; }); - const auto resp = response_with_id{rpc.id(), ec, tx_id}; + std::transform(targets.cbegin(), targets.cend(), + std::back_inserter(outputs), + [](const auto& tgt) { return cargo::dataset{tgt.id()}; }); - LOGGER_INFO("rpc {:<} body: {{retval: {}, tx_id: {}}}", rpc, ec, tx_id); + const auto cargo_tx = cargo::transfer_datasets(srv, inputs, outputs); + + // Register the transfer into the `tranfer_manager`. + // We embed the generated `cargo::transfer` object into + // scord's `transfer_metadata` so that we can later query the Cargo + // service for the transfer's status. + const auto rv = + m_transfer_manager.create(cargo_tx, limits) + .or_else([&](auto&& ec) { + LOGGER_ERROR("rpc id: {} error_msg: \"Error creating " + "transfer: {}\"", + rpc.id(), ec); + }) + .and_then([&](auto&& transfer_metadata_ptr) + -> tl::expected { + return transfer_metadata_ptr->id(); + }); + + const auto resp = + rv ? response_with_id{rpc.id(), error_code::success, rv.value()} + : response_with_id{rpc.id(), rv.error()}; + + LOGGER_EVAL(resp.error_code(), INFO, ERROR, + "rpc {:<} body: {{retval: {}, tx_id: {}}}", rpc, + resp.error_code(), resp.value_or_none()); req.respond(resp); } diff --git a/src/scord/rpc_server.hpp b/src/scord/rpc_server.hpp index 494c85fe..f86a60c8 100644 --- a/src/scord/rpc_server.hpp +++ b/src/scord/rpc_server.hpp @@ -31,6 +31,11 @@ #include "job_manager.hpp" #include "adhoc_storage_manager.hpp" #include "pfs_storage_manager.hpp" +#include "transfer_manager.hpp" + +namespace cargo { +class transfer; +} namespace scord { @@ -103,6 +108,7 @@ private: job_manager m_job_manager; adhoc_storage_manager m_adhoc_manager; pfs_storage_manager m_pfs_manager; + transfer_manager m_transfer_manager; }; } // namespace scord diff --git a/src/scord/transfer_manager.hpp b/src/scord/transfer_manager.hpp new file mode 100644 index 00000000..6abb74f2 --- /dev/null +++ b/src/scord/transfer_manager.hpp @@ -0,0 +1,129 @@ +/****************************************************************************** + * Copyright 2021-2023, Barcelona Supercomputing Center (BSC), Spain + * + * This software was partially supported by the EuroHPC-funded project ADMIRE + * (Project ID: 956748, https://www.admire-eurohpc.eu). + * + * This file is part of scord. + * + * scord is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * scord is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with scord. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + *****************************************************************************/ + +#ifndef SCORD_TRANSFER_MANAGER_HPP +#define SCORD_TRANSFER_MANAGER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include "internal_types.hpp" + +namespace scord { + +template +struct transfer_manager { + + tl::expected< + std::shared_ptr>, + scord::error_code> + create(TransferHandle tx, std::vector limits) { + + static std::atomic_uint64_t current_id; + scord::transfer_id id = current_id++; + + abt::unique_lock lock(m_transfer_mutex); + + if(const auto it = m_transfer.find(id); it == m_transfer.end()) { + const auto& [it_transfer, inserted] = m_transfer.emplace( + id, std::make_shared< + internal::transfer_metadata>( + id, std::move(tx), std::move(limits))); + + if(!inserted) { + LOGGER_ERROR("{}: Emplace failed", __FUNCTION__); + return tl::make_unexpected(scord::error_code::snafu); + } + + return it_transfer->second; + } + + LOGGER_ERROR("{}: Transfer '{}' already exists", __FUNCTION__, id); + return tl::make_unexpected(scord::error_code::entity_exists); + } + + scord::error_code + update(scord::transfer_id id, float obtained_bw) { + + abt::unique_lock lock(m_transfer_mutex); + + if(const auto it = m_transfer.find(id); it != m_transfer.end()) { + const auto& current_transfer_info = it->second; + current_transfer_info->update(obtained_bw); + return scord::error_code::success; + } + + LOGGER_ERROR("{}: Transfer '{}' does not exist", __FUNCTION__, id); + return scord::error_code::no_such_entity; + } + + tl::expected< + std::shared_ptr>, + scord::error_code> + find(scord::transfer_id id) { + + abt::shared_lock lock(m_transfer_mutex); + + if(auto it = m_transfer.find(id); it != m_transfer.end()) { + return it->second; + } + + LOGGER_ERROR("Transfer '{}' was not registered or was already deleted", + id); + return tl::make_unexpected(scord::error_code::no_such_entity); + } + + tl::expected< + std::shared_ptr>, + scord::error_code> + remove(scord::transfer_id id) { + + abt::unique_lock lock(m_transfer_mutex); + + if(const auto it = m_transfer.find(id); it != m_transfer.end()) { + auto nh = m_transfer.extract(it); + return nh.mapped(); + } + + LOGGER_ERROR("Transfer '{}' was not registered or was already deleted", + id); + + return tl::make_unexpected(scord::error_code::no_such_entity); + } + +private: + mutable abt::shared_mutex m_transfer_mutex; + std::unordered_map< + scord::transfer_id, + std::shared_ptr>> + m_transfer; +}; + +} // namespace scord + +#endif // SCORD_TRANSFER_MANAGER_HPP -- GitLab From 755ffd5ff3dc628f3b801a63a62f913d56a40a3a Mon Sep 17 00:00:00 2001 From: Alberto Miranda Date: Tue, 31 Oct 2023 09:30:36 +0100 Subject: [PATCH 3/8] [logging] Add missing quotes in adhoc/pfs names --- src/lib/detail/impl.cpp | 4 ++-- src/scord/rpc_server.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib/detail/impl.cpp b/src/lib/detail/impl.cpp index 3ace0a2d..17c8c2c5 100644 --- a/src/lib/detail/impl.cpp +++ b/src/lib/detail/impl.cpp @@ -234,7 +234,7 @@ register_adhoc_storage(const server& srv, const std::string& name, LOGGER_INFO("rpc {:<} body: {{name: {}, type: {}, adhoc_ctx: {}, " "adhoc_resources: {}}}", - rpc, name, type, ctx, resources); + rpc, std::quoted(name), type, ctx, resources); if(const auto& call_rv = endp.call(rpc.name(), name, type, ctx, resources); @@ -336,7 +336,7 @@ register_pfs_storage(const server& srv, const std::string& name, const auto& endp = lookup_rv.value(); LOGGER_INFO("rpc {:<} body: {{name: {}, type: {}, pfs_ctx: {}}}", rpc, - name, type, ctx); + std::quoted(name), type, ctx); if(const auto& call_rv = endp.call(rpc.name(), name, type, ctx); call_rv.has_value()) { diff --git a/src/scord/rpc_server.cpp b/src/scord/rpc_server.cpp index fca82eb5..55b692f4 100644 --- a/src/scord/rpc_server.cpp +++ b/src/scord/rpc_server.cpp @@ -276,7 +276,7 @@ rpc_server::register_adhoc_storage( LOGGER_INFO("rpc {:>} body: {{name: {}, type: {}, adhoc_ctx: {}, " "adhoc_resources: {}}}", - rpc, name, type, ctx, resources); + rpc, std::quoted(name), type, ctx, resources); scord::error_code ec; std::optional adhoc_id; @@ -518,8 +518,8 @@ rpc_server::register_pfs_storage(const network::request& req, const auto rpc = rpc_info::create(RPC_NAME(), get_address(req)); - LOGGER_INFO("rpc {:>} body: {{name: {}, type: {}, pfs_ctx: {}}}", rpc, name, - type, ctx); + LOGGER_INFO("rpc {:>} body: {{name: {}, type: {}, pfs_ctx: {}}}", rpc, + std::quoted(name), type, ctx); scord::error_code ec; std::optional pfs_id = 0; -- GitLab From 20f119885da9860855d7398cf4f978958fa8789c Mon Sep 17 00:00:00 2001 From: Alberto Miranda Date: Thu, 2 Nov 2023 13:10:27 +0100 Subject: [PATCH 4/8] WIP: foo (to merge with 79a38579d9b8c0ce94999e9fa14afba3d1ac6fc4) --- examples/c/ADM_cancel_transfer.c | 22 +-- examples/c/ADM_connect_data_operation.c | 23 +-- examples/c/ADM_define_data_operation.c | 17 +- examples/c/ADM_deploy_adhoc_storage.c | 4 - examples/c/ADM_finalize_data_operation.c | 17 +- examples/c/ADM_get_pending_transfers.c | 17 +- examples/c/ADM_get_qos_constraints.c | 17 +- examples/c/ADM_get_statistics.c | 17 +- examples/c/ADM_get_transfer_priority.c | 17 +- .../c/ADM_link_transfer_to_data_operation.c | 17 +- examples/c/ADM_register_adhoc_storage.c | 4 - examples/c/ADM_register_job.c | 27 +-- examples/c/ADM_remove_adhoc_storage.c | 4 - examples/c/ADM_remove_job.c | 17 +- examples/c/ADM_set_dataset_information.c | 17 +- examples/c/ADM_set_io_resources.c | 17 +- examples/c/ADM_set_qos_constraints.c | 17 +- examples/c/ADM_set_transfer_priority.c | 17 +- examples/c/ADM_terminate_adhoc_storage.c | 4 - examples/c/ADM_transfer_datasets.c | 20 +-- examples/c/ADM_update_adhoc_storage.c | 5 - examples/c/ADM_update_job.c | 27 ++- examples/c/common.c | 46 +++++ examples/c/common.h | 16 ++ examples/cxx/ADM_register_job.cpp | 9 +- examples/cxx/ADM_remove_job.cpp | 14 +- examples/cxx/ADM_transfer_datasets.cpp | 9 +- examples/cxx/ADM_update_job.cpp | 14 +- examples/cxx/common.cpp | 13 ++ examples/cxx/common.hpp | 9 + plugins/slurm/slurmadmcli.c | 116 +++++++++--- src/lib/CMakeLists.txt | 7 +- src/lib/scord/types.h | 46 ++++- src/lib/scord/types.hpp | 81 +++++++-- src/lib/scord/utils.h | 42 +++++ src/lib/types.c | 169 +++++++++++++++++- src/lib/types.cpp | 145 +++++++++++++-- src/lib/types_private.h | 18 +- src/lib/utils.cpp | 99 ++++++++++ 39 files changed, 940 insertions(+), 257 deletions(-) create mode 100644 src/lib/scord/utils.h create mode 100644 src/lib/utils.cpp diff --git a/examples/c/ADM_cancel_transfer.c b/examples/c/ADM_cancel_transfer.c index 1ebafe56..8dd6fc82 100644 --- a/examples/c/ADM_cancel_transfer.c +++ b/examples/c/ADM_cancel_transfer.c @@ -28,11 +28,6 @@ #include #include "common.h" -#define NJOB_NODES 50 -#define NADHOC_NODES 25 -#define NINPUTS 10 -#define NOUTPUTS 5 - int main(int argc, char* argv[]) { @@ -55,10 +50,15 @@ main(int argc, char* argv[]) { assert(job_nodes); ADM_node_t* adhoc_nodes = prepare_nodes(NADHOC_NODES); assert(adhoc_nodes); - ADM_dataset_t* inputs = prepare_datasets("input-dataset-%d", NINPUTS); + ADM_dataset_route_t* inputs = + prepare_routes("%s-input-dataset-%d", NINPUTS); assert(inputs); - ADM_dataset_t* outputs = prepare_datasets("output-dataset-%d", NOUTPUTS); + ADM_dataset_route_t* outputs = + prepare_routes("%s-output-dataset-%d", NOUTPUTS); assert(outputs); + ADM_dataset_route_t* expected_outputs = + prepare_routes("%s-exp-output-dataset-%d", NEXPOUTPUTS); + assert(expected_outputs); ADM_job_resources_t job_resources = ADM_job_resources_create(job_nodes, NJOB_NODES); @@ -90,7 +90,8 @@ main(int argc, char* argv[]) { } ADM_job_requirements_t reqs = ADM_job_requirements_create( - inputs, NINPUTS, outputs, NOUTPUTS, adhoc_storage); + inputs, NINPUTS, outputs, NOUTPUTS, expected_outputs, NEXPOUTPUTS, + adhoc_storage); assert(reqs); uint64_t slurm_job_id = 42; @@ -143,7 +144,8 @@ main(int argc, char* argv[]) { cleanup: ADM_remove_job(server, job); ADM_server_destroy(server); - destroy_datasets(inputs, NINPUTS); - destroy_datasets(outputs, NOUTPUTS); + destroy_routes(inputs, NINPUTS); + destroy_routes(outputs, NOUTPUTS); + destroy_routes(expected_outputs, NEXPOUTPUTS); exit(exit_status); } diff --git a/examples/c/ADM_connect_data_operation.c b/examples/c/ADM_connect_data_operation.c index b043f1c9..b766b0e9 100644 --- a/examples/c/ADM_connect_data_operation.c +++ b/examples/c/ADM_connect_data_operation.c @@ -28,11 +28,6 @@ #include #include "common.h" -#define NJOB_NODES 50 -#define NADHOC_NODES 25 -#define NINPUTS 10 -#define NOUTPUTS 5 - int main(int argc, char* argv[]) { @@ -55,10 +50,15 @@ main(int argc, char* argv[]) { assert(job_nodes); ADM_node_t* adhoc_nodes = prepare_nodes(NADHOC_NODES); assert(adhoc_nodes); - ADM_dataset_t* inputs = prepare_datasets("input-dataset-%d", NINPUTS); + ADM_dataset_route_t* inputs = + prepare_routes("%s-input-dataset-%d", NINPUTS); assert(inputs); - ADM_dataset_t* outputs = prepare_datasets("output-dataset-%d", NOUTPUTS); + ADM_dataset_route_t* outputs = + prepare_routes("%s-output-dataset-%d", NOUTPUTS); assert(outputs); + ADM_dataset_route_t* expected_outputs = + prepare_routes("%s-exp-output-dataset-%d", NEXPOUTPUTS); + assert(expected_outputs); ADM_adhoc_resources_t adhoc_resources = ADM_adhoc_resources_create(adhoc_nodes, NADHOC_NODES); @@ -90,7 +90,8 @@ main(int argc, char* argv[]) { assert(job_resources); ADM_job_requirements_t reqs = ADM_job_requirements_create( - inputs, NINPUTS, outputs, NOUTPUTS, adhoc_storage); + inputs, NINPUTS, outputs, NOUTPUTS, expected_outputs, NEXPOUTPUTS, + adhoc_storage); assert(reqs); uint64_t slurm_job_id = 42; @@ -108,8 +109,8 @@ main(int argc, char* argv[]) { exit_status = EXIT_SUCCESS; bool should_stream = false; - ret = ADM_connect_data_operation(server, job, inputs[0], outputs[0], - should_stream); + ret = ADM_connect_data_operation(server, job, /*inputs[0]*/ NULL, + /*outputs[0]*/ NULL, should_stream); if(ret != ADM_SUCCESS) { @@ -125,6 +126,7 @@ main(int argc, char* argv[]) { "successfully\n"); cleanup: + /* for(int i = 0; i < NINPUTS; ++i) { ADM_dataset_destroy(inputs[i]); } @@ -132,6 +134,7 @@ cleanup: for(int i = 0; i < NOUTPUTS; ++i) { ADM_dataset_destroy(outputs[i]); } + */ ADM_remove_job(server, job); ADM_server_destroy(server); diff --git a/examples/c/ADM_define_data_operation.c b/examples/c/ADM_define_data_operation.c index 89edeca8..c7a225f6 100644 --- a/examples/c/ADM_define_data_operation.c +++ b/examples/c/ADM_define_data_operation.c @@ -28,11 +28,6 @@ #include #include "common.h" -#define NJOB_NODES 50 -#define NADHOC_NODES 25 -#define NINPUTS 10 -#define NOUTPUTS 5 - int main(int argc, char* argv[]) { @@ -56,10 +51,15 @@ main(int argc, char* argv[]) { assert(job_nodes); ADM_node_t* adhoc_nodes = prepare_nodes(NADHOC_NODES); assert(adhoc_nodes); - ADM_dataset_t* inputs = prepare_datasets("input-dataset-%d", NINPUTS); + ADM_dataset_route_t* inputs = + prepare_routes("%s-input-dataset-%d", NINPUTS); assert(inputs); - ADM_dataset_t* outputs = prepare_datasets("output-dataset-%d", NOUTPUTS); + ADM_dataset_route_t* outputs = + prepare_routes("%s-output-dataset-%d", NOUTPUTS); assert(outputs); + ADM_dataset_route_t* expected_outputs = + prepare_routes("%s-exp-output-dataset-%d", NEXPOUTPUTS); + assert(expected_outputs); ADM_job_resources_t job_resources = ADM_job_resources_create(job_nodes, NJOB_NODES); @@ -91,7 +91,8 @@ main(int argc, char* argv[]) { } ADM_job_requirements_t reqs = ADM_job_requirements_create( - inputs, NINPUTS, outputs, NOUTPUTS, adhoc_storage); + inputs, NINPUTS, outputs, NOUTPUTS, expected_outputs, NEXPOUTPUTS, + adhoc_storage); assert(reqs); uint64_t slurm_job_id = 42; diff --git a/examples/c/ADM_deploy_adhoc_storage.c b/examples/c/ADM_deploy_adhoc_storage.c index dd284cf7..f568818b 100644 --- a/examples/c/ADM_deploy_adhoc_storage.c +++ b/examples/c/ADM_deploy_adhoc_storage.c @@ -27,10 +27,6 @@ #include #include "common.h" -#define NADHOC_NODES 25 -#define NINPUTS 10 -#define NOUTPUTS 5 - int main(int argc, char* argv[]) { diff --git a/examples/c/ADM_finalize_data_operation.c b/examples/c/ADM_finalize_data_operation.c index 01cdb68b..f32b5e47 100644 --- a/examples/c/ADM_finalize_data_operation.c +++ b/examples/c/ADM_finalize_data_operation.c @@ -28,11 +28,6 @@ #include #include "common.h" -#define NJOB_NODES 50 -#define NADHOC_NODES 25 -#define NINPUTS 10 -#define NOUTPUTS 5 - int main(int argc, char* argv[]) { @@ -55,10 +50,15 @@ main(int argc, char* argv[]) { assert(job_nodes); ADM_node_t* adhoc_nodes = prepare_nodes(NADHOC_NODES); assert(adhoc_nodes); - ADM_dataset_t* inputs = prepare_datasets("input-dataset-%d", NINPUTS); + ADM_dataset_route_t* inputs = + prepare_routes("%s-input-dataset-%d", NINPUTS); assert(inputs); - ADM_dataset_t* outputs = prepare_datasets("output-dataset-%d", NOUTPUTS); + ADM_dataset_route_t* outputs = + prepare_routes("%s-output-dataset-%d", NOUTPUTS); assert(outputs); + ADM_dataset_route_t* expected_outputs = + prepare_routes("%s-exp-output-dataset-%d", NEXPOUTPUTS); + assert(expected_outputs); ADM_adhoc_resources_t adhoc_resources = ADM_adhoc_resources_create(adhoc_nodes, NADHOC_NODES); @@ -90,7 +90,8 @@ main(int argc, char* argv[]) { assert(job_resources); ADM_job_requirements_t reqs = ADM_job_requirements_create( - inputs, NINPUTS, outputs, NOUTPUTS, adhoc_storage); + inputs, NINPUTS, outputs, NOUTPUTS, expected_outputs, NEXPOUTPUTS, + adhoc_storage); assert(reqs); uint64_t slurm_job_id = 42; diff --git a/examples/c/ADM_get_pending_transfers.c b/examples/c/ADM_get_pending_transfers.c index 31a66c84..4184db30 100644 --- a/examples/c/ADM_get_pending_transfers.c +++ b/examples/c/ADM_get_pending_transfers.c @@ -28,11 +28,6 @@ #include #include "common.h" -#define NJOB_NODES 50 -#define NADHOC_NODES 25 -#define NINPUTS 10 -#define NOUTPUTS 5 - int main(int argc, char* argv[]) { @@ -55,10 +50,15 @@ main(int argc, char* argv[]) { assert(job_nodes); ADM_node_t* adhoc_nodes = prepare_nodes(NADHOC_NODES); assert(adhoc_nodes); - ADM_dataset_t* inputs = prepare_datasets("input-dataset-%d", NINPUTS); + ADM_dataset_route_t* inputs = + prepare_routes("%s-input-dataset-%d", NINPUTS); assert(inputs); - ADM_dataset_t* outputs = prepare_datasets("output-dataset-%d", NOUTPUTS); + ADM_dataset_route_t* outputs = + prepare_routes("%s-output-dataset-%d", NOUTPUTS); assert(outputs); + ADM_dataset_route_t* expected_outputs = + prepare_routes("%s-exp-output-dataset-%d", NEXPOUTPUTS); + assert(expected_outputs); ADM_job_resources_t job_resources = ADM_job_resources_create(job_nodes, NJOB_NODES); @@ -90,7 +90,8 @@ main(int argc, char* argv[]) { } ADM_job_requirements_t reqs = ADM_job_requirements_create( - inputs, NINPUTS, outputs, NOUTPUTS, adhoc_storage); + inputs, NINPUTS, outputs, NOUTPUTS, expected_outputs, NEXPOUTPUTS, + adhoc_storage); assert(reqs); uint64_t slurm_job_id = 42; diff --git a/examples/c/ADM_get_qos_constraints.c b/examples/c/ADM_get_qos_constraints.c index bd9cefa2..92807bcc 100644 --- a/examples/c/ADM_get_qos_constraints.c +++ b/examples/c/ADM_get_qos_constraints.c @@ -28,11 +28,6 @@ #include #include "common.h" -#define NJOB_NODES 50 -#define NADHOC_NODES 25 -#define NINPUTS 10 -#define NOUTPUTS 5 - int main(int argc, char* argv[]) { @@ -55,10 +50,15 @@ main(int argc, char* argv[]) { assert(job_nodes); ADM_node_t* adhoc_nodes = prepare_nodes(NADHOC_NODES); assert(adhoc_nodes); - ADM_dataset_t* inputs = prepare_datasets("input-dataset-%d", NINPUTS); + ADM_dataset_route_t* inputs = + prepare_routes("%s-input-dataset-%d", NINPUTS); assert(inputs); - ADM_dataset_t* outputs = prepare_datasets("output-dataset-%d", NOUTPUTS); + ADM_dataset_route_t* outputs = + prepare_routes("%s-output-dataset-%d", NOUTPUTS); assert(outputs); + ADM_dataset_route_t* expected_outputs = + prepare_routes("%s-exp-output-dataset-%d", NEXPOUTPUTS); + assert(expected_outputs); ADM_adhoc_resources_t adhoc_resources = ADM_adhoc_resources_create(adhoc_nodes, NADHOC_NODES); @@ -90,7 +90,8 @@ main(int argc, char* argv[]) { assert(job_resources); ADM_job_requirements_t reqs = ADM_job_requirements_create( - inputs, NINPUTS, outputs, NOUTPUTS, adhoc_storage); + inputs, NINPUTS, outputs, NOUTPUTS, expected_outputs, NEXPOUTPUTS, + adhoc_storage); assert(reqs); uint64_t slurm_job_id = 42; diff --git a/examples/c/ADM_get_statistics.c b/examples/c/ADM_get_statistics.c index d9924997..e657ab81 100644 --- a/examples/c/ADM_get_statistics.c +++ b/examples/c/ADM_get_statistics.c @@ -28,11 +28,6 @@ #include #include "common.h" -#define NJOB_NODES 50 -#define NADHOC_NODES 25 -#define NINPUTS 10 -#define NOUTPUTS 5 - int main(int argc, char* argv[]) { @@ -55,10 +50,15 @@ main(int argc, char* argv[]) { assert(job_nodes); ADM_node_t* adhoc_nodes = prepare_nodes(NADHOC_NODES); assert(adhoc_nodes); - ADM_dataset_t* inputs = prepare_datasets("input-dataset-%d", NINPUTS); + ADM_dataset_route_t* inputs = + prepare_routes("%s-input-dataset-%d", NINPUTS); assert(inputs); - ADM_dataset_t* outputs = prepare_datasets("output-dataset-%d", NOUTPUTS); + ADM_dataset_route_t* outputs = + prepare_routes("%s-output-dataset-%d", NOUTPUTS); assert(outputs); + ADM_dataset_route_t* expected_outputs = + prepare_routes("%s-exp-output-dataset-%d", NEXPOUTPUTS); + assert(expected_outputs); ADM_adhoc_resources_t adhoc_resources = ADM_adhoc_resources_create(adhoc_nodes, NADHOC_NODES); @@ -90,7 +90,8 @@ main(int argc, char* argv[]) { assert(job_resources); ADM_job_requirements_t reqs = ADM_job_requirements_create( - inputs, NINPUTS, outputs, NOUTPUTS, adhoc_storage); + inputs, NINPUTS, outputs, NOUTPUTS, expected_outputs, NEXPOUTPUTS, + adhoc_storage); assert(reqs); uint64_t slurm_job_id = 42; diff --git a/examples/c/ADM_get_transfer_priority.c b/examples/c/ADM_get_transfer_priority.c index b4210ecf..cb97a730 100644 --- a/examples/c/ADM_get_transfer_priority.c +++ b/examples/c/ADM_get_transfer_priority.c @@ -28,11 +28,6 @@ #include #include "common.h" -#define NJOB_NODES 50 -#define NADHOC_NODES 25 -#define NINPUTS 10 -#define NOUTPUTS 5 - int main(int argc, char* argv[]) { @@ -55,10 +50,15 @@ main(int argc, char* argv[]) { assert(job_nodes); ADM_node_t* adhoc_nodes = prepare_nodes(NADHOC_NODES); assert(adhoc_nodes); - ADM_dataset_t* inputs = prepare_datasets("input-dataset-%d", NINPUTS); + ADM_dataset_route_t* inputs = + prepare_routes("%s-input-dataset-%d", NINPUTS); assert(inputs); - ADM_dataset_t* outputs = prepare_datasets("output-dataset-%d", NOUTPUTS); + ADM_dataset_route_t* outputs = + prepare_routes("%s-output-dataset-%d", NOUTPUTS); assert(outputs); + ADM_dataset_route_t* expected_outputs = + prepare_routes("%s-exp-output-dataset-%d", NEXPOUTPUTS); + assert(expected_outputs); ADM_job_resources_t job_resources = ADM_job_resources_create(job_nodes, NJOB_NODES); @@ -90,7 +90,8 @@ main(int argc, char* argv[]) { } ADM_job_requirements_t reqs = ADM_job_requirements_create( - inputs, NINPUTS, outputs, NOUTPUTS, adhoc_storage); + inputs, NINPUTS, outputs, NOUTPUTS, expected_outputs, NEXPOUTPUTS, + adhoc_storage); assert(reqs); uint64_t slurm_job_id = 42; diff --git a/examples/c/ADM_link_transfer_to_data_operation.c b/examples/c/ADM_link_transfer_to_data_operation.c index e980989e..34552d91 100644 --- a/examples/c/ADM_link_transfer_to_data_operation.c +++ b/examples/c/ADM_link_transfer_to_data_operation.c @@ -28,11 +28,6 @@ #include #include "common.h" -#define NJOB_NODES 50 -#define NADHOC_NODES 25 -#define NINPUTS 10 -#define NOUTPUTS 5 - int main(int argc, char* argv[]) { @@ -55,10 +50,15 @@ main(int argc, char* argv[]) { assert(job_nodes); ADM_node_t* adhoc_nodes = prepare_nodes(NADHOC_NODES); assert(adhoc_nodes); - ADM_dataset_t* inputs = prepare_datasets("input-dataset-%d", NINPUTS); + ADM_dataset_route_t* inputs = + prepare_routes("%s-input-dataset-%d", NINPUTS); assert(inputs); - ADM_dataset_t* outputs = prepare_datasets("output-dataset-%d", NOUTPUTS); + ADM_dataset_route_t* outputs = + prepare_routes("%s-output-dataset-%d", NOUTPUTS); assert(outputs); + ADM_dataset_route_t* expected_outputs = + prepare_routes("%s-exp-output-dataset-%d", NEXPOUTPUTS); + assert(expected_outputs); ADM_adhoc_resources_t adhoc_resources = ADM_adhoc_resources_create(adhoc_nodes, NADHOC_NODES); @@ -90,7 +90,8 @@ main(int argc, char* argv[]) { assert(job_resources); ADM_job_requirements_t reqs = ADM_job_requirements_create( - inputs, NINPUTS, outputs, NOUTPUTS, adhoc_storage); + inputs, NINPUTS, outputs, NOUTPUTS, expected_outputs, NEXPOUTPUTS, + adhoc_storage); assert(reqs); uint64_t slurm_job_id = 42; diff --git a/examples/c/ADM_register_adhoc_storage.c b/examples/c/ADM_register_adhoc_storage.c index b517655e..b86d29a6 100644 --- a/examples/c/ADM_register_adhoc_storage.c +++ b/examples/c/ADM_register_adhoc_storage.c @@ -27,10 +27,6 @@ #include #include "common.h" -#define NADHOC_NODES 25 -#define NINPUTS 10 -#define NOUTPUTS 5 - int main(int argc, char* argv[]) { diff --git a/examples/c/ADM_register_job.c b/examples/c/ADM_register_job.c index 93492306..cbff276e 100644 --- a/examples/c/ADM_register_job.c +++ b/examples/c/ADM_register_job.c @@ -27,11 +27,6 @@ #include #include "common.h" -#define NJOB_NODES 50 -#define NADHOC_NODES 25 -#define NINPUTS 10 -#define NOUTPUTS 5 - int main(int argc, char* argv[]) { @@ -63,8 +58,9 @@ main(int argc, char* argv[]) { ADM_job_resources_t job_resources = NULL; ADM_job_requirements_t reqs = NULL; uint64_t slurm_job_id = 42; - ADM_dataset_t* inputs = NULL; - ADM_dataset_t* outputs = NULL; + ADM_dataset_route_t* inputs = NULL; + ADM_dataset_route_t* outputs = NULL; + ADM_dataset_route_t* expected_outputs = NULL; // Let's prepare all the information required by the API calls. // ADM_register_job() often requires an adhoc storage to have been @@ -137,21 +133,29 @@ main(int argc, char* argv[]) { } // 2. the job's requirements - inputs = prepare_datasets("input-dataset-%d", NINPUTS); + inputs = prepare_routes("%s-input-dataset-%d", NINPUTS); if(inputs == NULL) { fprintf(stderr, "Fatal error preparing input datasets\n"); goto cleanup; } - outputs = prepare_datasets("output-dataset-%d", NOUTPUTS); + outputs = prepare_routes("%s-output-dataset-%d", NOUTPUTS); if(outputs == NULL) { fprintf(stderr, "Fatal error preparing output datasets\n"); goto cleanup; } + expected_outputs = prepare_routes("%s-exp-output-dataset-%d", NEXPOUTPUTS); + + if(expected_outputs == NULL) { + fprintf(stderr, "Fatal error preparing expected output datasets\n"); + goto cleanup; + } + if((reqs = ADM_job_requirements_create(inputs, NINPUTS, outputs, NOUTPUTS, + expected_outputs, NEXPOUTPUTS, adhoc_storage)) == NULL) { fprintf(stderr, "ADM_job_requirements_create() failed"); goto cleanup; @@ -191,8 +195,9 @@ cleanup: ADM_server_destroy(server); ADM_job_requirements_destroy(reqs); - destroy_datasets(outputs, NOUTPUTS); - destroy_datasets(inputs, NINPUTS); + destroy_routes(outputs, NOUTPUTS); + destroy_routes(inputs, NINPUTS); + destroy_routes(expected_outputs, NEXPOUTPUTS); ADM_job_resources_destroy(job_resources); destroy_nodes(job_nodes, NJOB_NODES); diff --git a/examples/c/ADM_remove_adhoc_storage.c b/examples/c/ADM_remove_adhoc_storage.c index 56dd50b5..28f47c1b 100644 --- a/examples/c/ADM_remove_adhoc_storage.c +++ b/examples/c/ADM_remove_adhoc_storage.c @@ -27,10 +27,6 @@ #include #include "common.h" -#define NADHOC_NODES 25 -#define NINPUTS 10 -#define NOUTPUTS 5 - int main(int argc, char* argv[]) { diff --git a/examples/c/ADM_remove_job.c b/examples/c/ADM_remove_job.c index d9670ba7..7ced330c 100644 --- a/examples/c/ADM_remove_job.c +++ b/examples/c/ADM_remove_job.c @@ -28,11 +28,6 @@ #include #include "common.h" -#define NJOB_NODES 50 -#define NADHOC_NODES 25 -#define NINPUTS 10 -#define NOUTPUTS 5 - int main(int argc, char* argv[]) { @@ -55,10 +50,15 @@ main(int argc, char* argv[]) { assert(job_nodes); ADM_node_t* adhoc_nodes = prepare_nodes(NADHOC_NODES); assert(adhoc_nodes); - ADM_dataset_t* inputs = prepare_datasets("input-dataset-%d", NINPUTS); + ADM_dataset_route_t* inputs = + prepare_routes("%s-input-dataset-%d", NINPUTS); assert(inputs); - ADM_dataset_t* outputs = prepare_datasets("output-dataset-%d", NOUTPUTS); + ADM_dataset_route_t* outputs = + prepare_routes("%s-output-dataset-%d", NOUTPUTS); assert(outputs); + ADM_dataset_route_t* expected_outputs = + prepare_routes("%s-exp-output-dataset-%d", NEXPOUTPUTS); + assert(expected_outputs); ADM_job_resources_t job_resources = ADM_job_resources_create(job_nodes, NJOB_NODES); @@ -90,7 +90,8 @@ main(int argc, char* argv[]) { } ADM_job_requirements_t reqs = ADM_job_requirements_create( - inputs, NINPUTS, outputs, NOUTPUTS, adhoc_storage); + inputs, NINPUTS, outputs, NOUTPUTS, expected_outputs, NEXPOUTPUTS, + adhoc_storage); assert(reqs); uint64_t slurm_job_id = 42; diff --git a/examples/c/ADM_set_dataset_information.c b/examples/c/ADM_set_dataset_information.c index 9aa9477c..2a8b4120 100644 --- a/examples/c/ADM_set_dataset_information.c +++ b/examples/c/ADM_set_dataset_information.c @@ -28,11 +28,6 @@ #include #include "common.h" -#define NJOB_NODES 50 -#define NADHOC_NODES 25 -#define NINPUTS 10 -#define NOUTPUTS 5 - int main(int argc, char* argv[]) { @@ -55,10 +50,15 @@ main(int argc, char* argv[]) { assert(job_nodes); ADM_node_t* adhoc_nodes = prepare_nodes(NADHOC_NODES); assert(adhoc_nodes); - ADM_dataset_t* inputs = prepare_datasets("input-dataset-%d", NINPUTS); + ADM_dataset_route_t* inputs = + prepare_routes("%s-input-dataset-%d", NINPUTS); assert(inputs); - ADM_dataset_t* outputs = prepare_datasets("output-dataset-%d", NOUTPUTS); + ADM_dataset_route_t* outputs = + prepare_routes("%s-output-dataset-%d", NOUTPUTS); assert(outputs); + ADM_dataset_route_t* expected_outputs = + prepare_routes("%s-exp-output-dataset-%d", NEXPOUTPUTS); + assert(expected_outputs); ADM_adhoc_resources_t adhoc_resources = ADM_adhoc_resources_create(adhoc_nodes, NADHOC_NODES); @@ -90,7 +90,8 @@ main(int argc, char* argv[]) { assert(job_resources); ADM_job_requirements_t reqs = ADM_job_requirements_create( - inputs, NINPUTS, outputs, NOUTPUTS, adhoc_storage); + inputs, NINPUTS, outputs, NOUTPUTS, expected_outputs, NEXPOUTPUTS, + adhoc_storage); assert(reqs); uint64_t slurm_job_id = 42; diff --git a/examples/c/ADM_set_io_resources.c b/examples/c/ADM_set_io_resources.c index 30691cbc..b38a7d33 100644 --- a/examples/c/ADM_set_io_resources.c +++ b/examples/c/ADM_set_io_resources.c @@ -28,11 +28,6 @@ #include #include "common.h" -#define NJOB_NODES 50 -#define NADHOC_NODES 25 -#define NINPUTS 10 -#define NOUTPUTS 5 - int main(int argc, char* argv[]) { @@ -55,10 +50,15 @@ main(int argc, char* argv[]) { assert(job_nodes); ADM_node_t* adhoc_nodes = prepare_nodes(NADHOC_NODES); assert(adhoc_nodes); - ADM_dataset_t* inputs = prepare_datasets("input-dataset-%d", NINPUTS); + ADM_dataset_route_t* inputs = + prepare_routes("%s-input-dataset-%d", NINPUTS); assert(inputs); - ADM_dataset_t* outputs = prepare_datasets("output-dataset-%d", NOUTPUTS); + ADM_dataset_route_t* outputs = + prepare_routes("%s-output-dataset-%d", NOUTPUTS); assert(outputs); + ADM_dataset_route_t* expected_outputs = + prepare_routes("%s-exp-output-dataset-%d", NEXPOUTPUTS); + assert(expected_outputs); ADM_adhoc_resources_t adhoc_resources = ADM_adhoc_resources_create(adhoc_nodes, NADHOC_NODES); @@ -90,7 +90,8 @@ main(int argc, char* argv[]) { assert(job_resources); ADM_job_requirements_t reqs = ADM_job_requirements_create( - inputs, NINPUTS, outputs, NOUTPUTS, adhoc_storage); + inputs, NINPUTS, outputs, NOUTPUTS, expected_outputs, NEXPOUTPUTS, + adhoc_storage); assert(reqs); uint64_t slurm_job_id = 42; diff --git a/examples/c/ADM_set_qos_constraints.c b/examples/c/ADM_set_qos_constraints.c index 78b79377..80c5e6ba 100644 --- a/examples/c/ADM_set_qos_constraints.c +++ b/examples/c/ADM_set_qos_constraints.c @@ -28,11 +28,6 @@ #include #include "common.h" -#define NJOB_NODES 50 -#define NADHOC_NODES 25 -#define NINPUTS 10 -#define NOUTPUTS 5 - int main(int argc, char* argv[]) { @@ -55,10 +50,15 @@ main(int argc, char* argv[]) { assert(job_nodes); ADM_node_t* adhoc_nodes = prepare_nodes(NADHOC_NODES); assert(adhoc_nodes); - ADM_dataset_t* inputs = prepare_datasets("input-dataset-%d", NINPUTS); + ADM_dataset_route_t* inputs = + prepare_routes("%s-input-dataset-%d", NINPUTS); assert(inputs); - ADM_dataset_t* outputs = prepare_datasets("output-dataset-%d", NOUTPUTS); + ADM_dataset_route_t* outputs = + prepare_routes("%s-output-dataset-%d", NOUTPUTS); assert(outputs); + ADM_dataset_route_t* expected_outputs = + prepare_routes("%s-exp-output-dataset-%d", NEXPOUTPUTS); + assert(expected_outputs); ADM_job_resources_t job_resources = ADM_job_resources_create(job_nodes, NJOB_NODES); @@ -90,7 +90,8 @@ main(int argc, char* argv[]) { } ADM_job_requirements_t reqs = ADM_job_requirements_create( - inputs, NINPUTS, outputs, NOUTPUTS, adhoc_storage); + inputs, NINPUTS, outputs, NOUTPUTS, expected_outputs, NEXPOUTPUTS, + adhoc_storage); assert(reqs); uint64_t slurm_job_id = 42; diff --git a/examples/c/ADM_set_transfer_priority.c b/examples/c/ADM_set_transfer_priority.c index 5b3de186..2a1d06f8 100644 --- a/examples/c/ADM_set_transfer_priority.c +++ b/examples/c/ADM_set_transfer_priority.c @@ -28,11 +28,6 @@ #include #include "common.h" -#define NJOB_NODES 50 -#define NADHOC_NODES 25 -#define NINPUTS 10 -#define NOUTPUTS 5 - int main(int argc, char* argv[]) { @@ -55,10 +50,15 @@ main(int argc, char* argv[]) { assert(job_nodes); ADM_node_t* adhoc_nodes = prepare_nodes(NADHOC_NODES); assert(adhoc_nodes); - ADM_dataset_t* inputs = prepare_datasets("input-dataset-%d", NINPUTS); + ADM_dataset_route_t* inputs = + prepare_routes("%s-input-dataset-%d", NINPUTS); assert(inputs); - ADM_dataset_t* outputs = prepare_datasets("output-dataset-%d", NOUTPUTS); + ADM_dataset_route_t* outputs = + prepare_routes("%s-output-dataset-%d", NOUTPUTS); assert(outputs); + ADM_dataset_route_t* expected_outputs = + prepare_routes("%s-exp-output-dataset-%d", NEXPOUTPUTS); + assert(expected_outputs); ADM_job_resources_t job_resources = ADM_job_resources_create(job_nodes, NJOB_NODES); @@ -90,7 +90,8 @@ main(int argc, char* argv[]) { } ADM_job_requirements_t reqs = ADM_job_requirements_create( - inputs, NINPUTS, outputs, NOUTPUTS, adhoc_storage); + inputs, NINPUTS, outputs, NOUTPUTS, expected_outputs, NEXPOUTPUTS, + adhoc_storage); assert(reqs); uint64_t slurm_job_id = 42; diff --git a/examples/c/ADM_terminate_adhoc_storage.c b/examples/c/ADM_terminate_adhoc_storage.c index 39f34a44..6677c5fe 100644 --- a/examples/c/ADM_terminate_adhoc_storage.c +++ b/examples/c/ADM_terminate_adhoc_storage.c @@ -27,10 +27,6 @@ #include #include "common.h" -#define NADHOC_NODES 25 -#define NINPUTS 10 -#define NOUTPUTS 5 - int main(int argc, char* argv[]) { diff --git a/examples/c/ADM_transfer_datasets.c b/examples/c/ADM_transfer_datasets.c index b0bc6c1f..2433091f 100644 --- a/examples/c/ADM_transfer_datasets.c +++ b/examples/c/ADM_transfer_datasets.c @@ -28,14 +28,6 @@ #include #include "common.h" -#define NJOB_NODES 50 -#define NADHOC_NODES 25 -#define NINPUTS 10 -#define NOUTPUTS 5 -#define NSOURCES 5 -#define NTARGETS 5 -#define NLIMITS 3 - int main(int argc, char* argv[]) { @@ -58,10 +50,15 @@ main(int argc, char* argv[]) { assert(job_nodes); ADM_node_t* adhoc_nodes = prepare_nodes(NADHOC_NODES); assert(adhoc_nodes); - ADM_dataset_t* inputs = prepare_datasets("input-dataset-%d", NINPUTS); + ADM_dataset_route_t* inputs = + prepare_routes("%s-input-dataset-%d", NINPUTS); assert(inputs); - ADM_dataset_t* outputs = prepare_datasets("output-dataset-%d", NOUTPUTS); + ADM_dataset_route_t* outputs = + prepare_routes("%s-output-dataset-%d", NOUTPUTS); assert(outputs); + ADM_dataset_route_t* expected_outputs = + prepare_routes("%s-exp-output-dataset-%d", NEXPOUTPUTS); + assert(expected_outputs); ADM_job_resources_t job_resources = ADM_job_resources_create(job_nodes, NJOB_NODES); @@ -93,7 +90,8 @@ main(int argc, char* argv[]) { } ADM_job_requirements_t reqs = ADM_job_requirements_create( - inputs, NINPUTS, outputs, NOUTPUTS, adhoc_storage); + inputs, NINPUTS, outputs, NOUTPUTS, expected_outputs, NEXPOUTPUTS, + adhoc_storage); assert(reqs); uint64_t slurm_job_id = 42; diff --git a/examples/c/ADM_update_adhoc_storage.c b/examples/c/ADM_update_adhoc_storage.c index cb5163ba..ed33af03 100644 --- a/examples/c/ADM_update_adhoc_storage.c +++ b/examples/c/ADM_update_adhoc_storage.c @@ -27,11 +27,6 @@ #include #include "common.h" -#define NADHOC_NODES 25 -#define N_NEW_ADHOC_NODES 10 -#define NINPUTS 10 -#define NOUTPUTS 5 - int main(int argc, char* argv[]) { diff --git a/examples/c/ADM_update_job.c b/examples/c/ADM_update_job.c index 599b3fe1..70b8180c 100644 --- a/examples/c/ADM_update_job.c +++ b/examples/c/ADM_update_job.c @@ -28,11 +28,6 @@ #include #include "common.h" -#define NJOB_NODES 50 -#define NADHOC_NODES 25 -#define NINPUTS 10 -#define NOUTPUTS 5 - int main(int argc, char* argv[]) { @@ -55,10 +50,14 @@ main(int argc, char* argv[]) { assert(job_nodes); ADM_node_t* adhoc_nodes = prepare_nodes(NADHOC_NODES); assert(adhoc_nodes); - ADM_dataset_t* inputs = prepare_datasets("input-dataset-%d", NINPUTS); + ADM_dataset_route_t* inputs = + prepare_routes("%s-input-dataset-%d", NINPUTS); assert(inputs); - ADM_dataset_t* outputs = prepare_datasets("output-dataset-%d", NOUTPUTS); + ADM_dataset_route_t* outputs = + prepare_routes("%s-output-dataset-%d", NOUTPUTS); assert(outputs); + ADM_dataset_route_t* expected_outputs = + prepare_routes("%s-exp-output-dataset-%d", NEXPOUTPUTS); ADM_job_resources_t job_resources = ADM_job_resources_create(job_nodes, NJOB_NODES); @@ -90,7 +89,8 @@ main(int argc, char* argv[]) { } ADM_job_requirements_t reqs = ADM_job_requirements_create( - inputs, NINPUTS, outputs, NOUTPUTS, adhoc_storage); + inputs, NINPUTS, outputs, NOUTPUTS, expected_outputs, NEXPOUTPUTS, + adhoc_storage); assert(reqs); uint64_t slurm_job_id = 42; @@ -128,14 +128,9 @@ main(int argc, char* argv[]) { cleanup: - for(int i = 0; i < NINPUTS; ++i) { - ADM_dataset_destroy(inputs[i]); - } - - for(int i = 0; i < NOUTPUTS; ++i) { - ADM_dataset_destroy(outputs[i]); - } - + destroy_routes(inputs, NINPUTS); + destroy_routes(outputs, NOUTPUTS); + destroy_routes(expected_outputs, NEXPOUTPUTS); ADM_remove_job(server, job); ADM_server_destroy(server); exit(exit_status); diff --git a/examples/c/common.c b/examples/c/common.c index 178cce7b..af662205 100644 --- a/examples/c/common.c +++ b/examples/c/common.c @@ -114,6 +114,52 @@ destroy_datasets(ADM_dataset_t datasets[], size_t n) { free(datasets); } +ADM_dataset_route_t* +prepare_routes(const char* pattern, size_t n) { + + ADM_dataset_route_t* routes = calloc(n, sizeof(ADM_dataset_route_t)); + + if(!routes) { + return NULL; + } + + for(size_t i = 0; i < n; ++i) { + size_t len = snprintf(NULL, 0, pattern, "XXX", i); + char* id = (char*) alloca(len + 1); + snprintf(id, len + 1, pattern, "src", i); + ADM_dataset_t src = ADM_dataset_create(id); + snprintf(id, len + 1, pattern, "dst", i); + ADM_dataset_t dst = ADM_dataset_create(id); + + if(!src || !dst) { + return NULL; + } + + routes[i] = ADM_dataset_route_create(src, dst); + if(!routes[i]) { + return NULL; + } + } + + return routes; +} + +void +destroy_routes(ADM_dataset_route_t routes[], size_t n) { + + if(!routes) { + return; + } + + for(size_t i = 0; i < n; ++i) { + if(routes[i]) { + ADM_dataset_route_destroy(routes[i]); + } + } + + free(routes); +} + ADM_qos_limit_t* prepare_qos_limits(size_t n) { diff --git a/examples/c/common.h b/examples/c/common.h index ca8c32ee..08ed9a8c 100644 --- a/examples/c/common.h +++ b/examples/c/common.h @@ -3,6 +3,16 @@ #include +#define NJOB_NODES 50 +#define NADHOC_NODES 25 +#define N_NEW_ADHOC_NODES 10 +#define NINPUTS 10 +#define NOUTPUTS 5 +#define NEXPOUTPUTS 1 +#define NSOURCES 5 +#define NTARGETS 5 +#define NLIMITS 3 + #define TESTNAME \ (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 \ : __FILE__) @@ -35,6 +45,12 @@ prepare_datasets(const char* pattern, size_t n); void destroy_datasets(ADM_dataset_t datasets[], size_t n); +ADM_dataset_route_t* +prepare_routes(const char* pattern, size_t n); + +void +destroy_routes(ADM_dataset_route_t routes[], size_t n); + ADM_qos_limit_t* prepare_qos_limits(size_t n); diff --git a/examples/cxx/ADM_register_job.cpp b/examples/cxx/ADM_register_job.cpp index f56ff510..2da8de73 100644 --- a/examples/cxx/ADM_register_job.cpp +++ b/examples/cxx/ADM_register_job.cpp @@ -47,8 +47,10 @@ main(int argc, char* argv[]) { const auto job_nodes = prepare_nodes(NJOB_NODES); const auto adhoc_nodes = prepare_nodes(NADHOC_NODES); - const auto inputs = prepare_datasets("input-dataset-{}", NINPUTS); - const auto outputs = prepare_datasets("output-dataset-{}", NOUTPUTS); + const auto inputs = prepare_routes("{}-input-dataset-{}", NINPUTS); + const auto outputs = prepare_routes("{}-output-dataset-{}", NOUTPUTS); + const auto expected_outputs = + prepare_routes("{}-exp-output-dataset-{}", NEXPOUTPUTS); std::string name = "adhoc_storage_42"; const auto adhoc_storage_ctx = scord::adhoc_storage::ctx{ @@ -66,7 +68,8 @@ main(int argc, char* argv[]) { server, name, scord::adhoc_storage::type::gekkofs, adhoc_storage_ctx, adhoc_resources); - scord::job::requirements reqs(inputs, outputs, adhoc_storage); + scord::job::requirements reqs(inputs, outputs, expected_outputs, + adhoc_storage); [[maybe_unused]] const auto job = scord::register_job( server, scord::job::resources{job_nodes}, reqs, 0); diff --git a/examples/cxx/ADM_remove_job.cpp b/examples/cxx/ADM_remove_job.cpp index 9d046fea..408a16ef 100644 --- a/examples/cxx/ADM_remove_job.cpp +++ b/examples/cxx/ADM_remove_job.cpp @@ -26,11 +26,6 @@ #include #include "common.hpp" -#define NJOB_NODES 50 -#define NADHOC_NODES 25 -#define NINPUTS 10 -#define NOUTPUTS 5 - int main(int argc, char* argv[]) { @@ -47,8 +42,10 @@ main(int argc, char* argv[]) { const auto job_nodes = prepare_nodes(NJOB_NODES); const auto adhoc_nodes = prepare_nodes(NADHOC_NODES); - const auto inputs = prepare_datasets("input-dataset-{}", NINPUTS); - const auto outputs = prepare_datasets("output-dataset-{}", NOUTPUTS); + const auto inputs = prepare_routes("{}-input-dataset-{}", NINPUTS); + const auto outputs = prepare_routes("{}-output-dataset-{}", NOUTPUTS); + const auto expected_outputs = + prepare_routes("{}-exp-output-dataset-{}", NEXPOUTPUTS); std::string name = "adhoc_storage_42"; const auto adhoc_storage_ctx = scord::adhoc_storage::ctx{ @@ -67,7 +64,8 @@ main(int argc, char* argv[]) { server, name, scord::adhoc_storage::type::gekkofs, adhoc_storage_ctx, adhoc_resources); - scord::job::requirements reqs(inputs, outputs, adhoc_storage); + scord::job::requirements reqs(inputs, outputs, expected_outputs, + adhoc_storage); [[maybe_unused]] const auto job = scord::register_job( server, scord::job::resources{job_nodes}, reqs, 0); diff --git a/examples/cxx/ADM_transfer_datasets.cpp b/examples/cxx/ADM_transfer_datasets.cpp index c6485daa..1028658c 100644 --- a/examples/cxx/ADM_transfer_datasets.cpp +++ b/examples/cxx/ADM_transfer_datasets.cpp @@ -50,8 +50,10 @@ main(int argc, char* argv[]) { const auto job_nodes = prepare_nodes(NJOB_NODES); const auto adhoc_nodes = prepare_nodes(NADHOC_NODES); - const auto inputs = prepare_datasets("input-dataset-{}", NINPUTS); - const auto outputs = prepare_datasets("output-dataset-{}", NOUTPUTS); + const auto inputs = prepare_routes("{}-input-dataset-{}", NINPUTS); + const auto outputs = prepare_routes("{}-output-dataset-{}", NOUTPUTS); + const auto expected_outputs = + prepare_routes("{}-exp-output-dataset-{}", NEXPOUTPUTS); const auto sources = prepare_datasets("source-dataset-{}", NSOURCES); const auto targets = prepare_datasets("target-dataset-{}", NTARGETS); @@ -73,7 +75,8 @@ main(int argc, char* argv[]) { server, name, scord::adhoc_storage::type::gekkofs, adhoc_storage_ctx, adhoc_resources); - scord::job::requirements reqs(inputs, outputs, adhoc_storage); + scord::job::requirements reqs(inputs, outputs, expected_outputs, + adhoc_storage); const auto job = scord::register_job( server, scord::job::resources{job_nodes}, reqs, 0); diff --git a/examples/cxx/ADM_update_job.cpp b/examples/cxx/ADM_update_job.cpp index f83901e2..72533de8 100644 --- a/examples/cxx/ADM_update_job.cpp +++ b/examples/cxx/ADM_update_job.cpp @@ -26,11 +26,6 @@ #include #include "common.hpp" -#define NJOB_NODES 50 -#define NADHOC_NODES 25 -#define NINPUTS 10 -#define NOUTPUTS 5 - int main(int argc, char* argv[]) { @@ -48,8 +43,10 @@ main(int argc, char* argv[]) { const auto job_nodes = prepare_nodes(NJOB_NODES); const auto new_job_nodes = prepare_nodes(NJOB_NODES * 2); const auto adhoc_nodes = prepare_nodes(NADHOC_NODES); - const auto inputs = prepare_datasets("input-dataset-{}", NINPUTS); - const auto outputs = prepare_datasets("output-dataset-{}", NOUTPUTS); + const auto inputs = prepare_routes("{}-input-dataset-{}", NINPUTS); + const auto outputs = prepare_routes("{}-output-dataset-{}", NOUTPUTS); + const auto expected_outputs = + prepare_routes("{}-exp-output-dataset-{}", NEXPOUTPUTS); const auto gkfs_storage = scord::register_adhoc_storage( server, "foobar", scord::adhoc_storage::type::gekkofs, @@ -59,7 +56,8 @@ main(int argc, char* argv[]) { scord::adhoc_storage::access_type::read_write, 100, false}, scord::adhoc_storage::resources{adhoc_nodes}); - scord::job::requirements reqs{inputs, outputs, gkfs_storage}; + scord::job::requirements reqs{inputs, outputs, expected_outputs, + gkfs_storage}; const auto new_inputs = prepare_datasets("input-new-dataset-{}", NINPUTS); const auto new_outputs = diff --git a/examples/cxx/common.cpp b/examples/cxx/common.cpp index 6ced6dcb..bc290c1f 100644 --- a/examples/cxx/common.cpp +++ b/examples/cxx/common.cpp @@ -57,6 +57,19 @@ prepare_datasets(const std::string& pattern, size_t n) { return datasets; } +std::vector +prepare_routes(const std::string& pattern, size_t n) { + std::vector routes; + routes.reserve(n); + for(size_t i = 0; i < n; ++i) { + routes.emplace_back( + scord::dataset{fmt::format(fmt::runtime(pattern), "src", i)}, + scord::dataset{fmt::format(fmt::runtime(pattern), "dst", i)}); + } + + return routes; +} + std::vector prepare_qos_limits(size_t n) { diff --git a/examples/cxx/common.hpp b/examples/cxx/common.hpp index 2a16fd21..4cc0f836 100644 --- a/examples/cxx/common.hpp +++ b/examples/cxx/common.hpp @@ -4,6 +4,12 @@ #include #include +#define NJOB_NODES 50 +#define NADHOC_NODES 25 +#define NINPUTS 10 +#define NOUTPUTS 5 +#define NEXPOUTPUTS 1 + #define TESTNAME \ (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 \ : __FILE__) @@ -30,6 +36,9 @@ prepare_nodes(size_t n); std::vector prepare_datasets(const std::string& pattern, size_t n); +std::vector +prepare_routes(const std::string& pattern, size_t n); + std::vector prepare_qos_limits(size_t n); diff --git a/plugins/slurm/slurmadmcli.c b/plugins/slurm/slurmadmcli.c index 4bb40e70..61d10078 100644 --- a/plugins/slurm/slurmadmcli.c +++ b/plugins/slurm/slurmadmcli.c @@ -32,6 +32,7 @@ #include #include +#include #include "defaults.h" #include "utils.h" @@ -48,16 +49,16 @@ #define ADHOCID_LEN 64 #define INT32_STR_LEN 16 /* 16 chars are enough to fit an int32 in decimal */ -#define TAG_NNODES 0 -#define TAG_ADHOC_TYPE 1 -#define TAG_ADHOC_OVERLAP 2 -#define TAG_ADHOC_EXCLUSIVE 3 -#define TAG_ADHOC_DEDICATED 4 -#define TAG_ADHOC_REMOTE 5 -#define TAG_DATASET_INPUT 6 -#define TAG_DATASET_OUTPUT 7 -#define TAG_DATASET_EXPECT_OUTPUT 8 -#define TAG_DATASET_INOUT 9 +#define TAG_NNODES 0 +#define TAG_ADHOC_TYPE 1 +#define TAG_ADHOC_OVERLAP 2 +#define TAG_ADHOC_EXCLUSIVE 3 +#define TAG_ADHOC_DEDICATED 4 +#define TAG_ADHOC_REMOTE 5 +#define TAG_DATASET_INPUT 6 +#define TAG_DATASET_OUTPUT 7 +#define TAG_DATASET_EXPECTED_OUTPUT 8 +#define TAG_DATASET_EXPECTED_INOUT_DATASET 9 // clang-format off SPANK_PLUGIN (admire-cli, 1) @@ -71,6 +72,14 @@ static long adhoc_walltime = 0; static ADM_adhoc_mode_t adhoc_mode = ADM_ADHOC_MODE_IN_JOB_SHARED; static ADM_adhoc_storage_type_t adhoc_type = 0; static char adhoc_id[ADHOCID_LEN] = {0}; +ADM_dataset_route_t* input_datasets = NULL; +size_t input_datasets_count = 0; +ADM_dataset_route_t* output_datasets = NULL; +size_t output_datasets_count = 0; +ADM_dataset_route_t* expected_output_datasets = NULL; +size_t expected_output_datasets_count = 0; +ADM_dataset_route_t* expected_inout_datasets = NULL; +size_t expected_inout_datasets_count = 0; /* server-related options */ typedef struct { @@ -175,9 +184,9 @@ struct spank_option spank_opts[] = { (spank_opt_cb_f) process_opts /* callback */ }, { - "adm-input", "dataset-routing", + "adm-input-datasets", "dataset-route[,dataset-route...]", "Define datasets that should be transferred between the PFS " - "and the ad-hoc storage service. The `dataset-routing` is " + "and the ad-hoc storage service. The `dataset-route` is " "defined as `ORIGIN-TIER:PATH TARGET-TIER:PATH`. For example," "to transfer the file `input000.dat` from the Lustre PFS to " "the an on-demand GekkoFS ad-hoc storage service, the option " @@ -188,7 +197,7 @@ struct spank_option spank_opts[] = { (spank_opt_cb_f) process_opts /* callback */ }, { - "adm-output", "dataset-routing", + "adm-output-datasets", "dataset-route[,dataset-route...]", "Define datasets that should be automatically transferred " "between the ad-hoc storage system and the PFS. The ad-hoc " "storage will guarantee that the dataset is not transferred " @@ -200,22 +209,24 @@ struct spank_option spank_opts[] = { (spank_opt_cb_f) process_opts /* callback */ }, { - "adm-expect-output", "dataset-routing", + "adm-expected-output-datasets", + "dataset-route[,dataset-route...]", "Define datasets that are expected to be generated by the " "application. When using this option, the application itself " "MUST use the programmatic APIs defined in `scord-user.h`to " "explicitly request the transfer of the datasets.", 1, /* option takes an argument */ - TAG_DATASET_EXPECT_OUTPUT, /* option tag */ + TAG_DATASET_EXPECTED_OUTPUT, /* option tag */ (spank_opt_cb_f) process_opts /* callback */ }, { - "adm-expect-inout", "dataset-routing", + "adm-expected-inout-datasets", + "dataset-route[,dataset-route...]", "Define the datasets that should be transferred INTO " "the ad-hoc storage AND BACK when finished.", - 1, /* option takes an argument */ - TAG_DATASET_INOUT, /* option tag */ - (spank_opt_cb_f) process_opts /* callback */ + 1, /* option takes an argument */ + TAG_DATASET_EXPECTED_INOUT_DATASET, /* option tag */ + (spank_opt_cb_f) process_opts /* callback */ }, SPANK_OPTIONS_TABLE_END}; @@ -223,7 +234,8 @@ int process_opts(int tag, const char* optarg, int remote) { (void) remote; - slurm_debug("%s: %s() called", plugin_name, __func__); + slurm_debug("%s: %s(tag: %d, optarg: %s, remote: %d) called", plugin_name, + __func__, tag, optarg, remote); /* srun & sbatch/salloc */ spank_context_t sctx = spank_context(); @@ -284,6 +296,62 @@ process_opts(int tag, const char* optarg, int remote) { adhoc_id[ADHOCID_LEN - 1] = '\0'; return 0; + case TAG_DATASET_INPUT: + if(input_datasets) { + free(input_datasets); + } + + if(scord_utils_parse_dataset_routes(optarg, &input_datasets, + &input_datasets_count) != + ADM_SUCCESS) { + slurm_error("%s: %s: failed to parse dataset route: %s", + plugin_name, __func__, optarg); + return -1; + } + return 0; + + case TAG_DATASET_OUTPUT: + if(output_datasets) { + free(output_datasets); + } + + if(scord_utils_parse_dataset_routes(optarg, &output_datasets, + &output_datasets_count) != + ADM_SUCCESS) { + slurm_error("%s: %s: failed to parse dataset route: %s", + plugin_name, __func__, optarg); + return -1; + } + return 0; + + case TAG_DATASET_EXPECTED_OUTPUT: + if(expected_output_datasets) { + free(expected_output_datasets); + } + + if(scord_utils_parse_dataset_routes( + optarg, &expected_output_datasets, + &expected_output_datasets_count) != ADM_SUCCESS) { + slurm_error("%s: %s: failed to parse dataset route: %s", + plugin_name, __func__, optarg); + return -1; + } + return 0; + + case TAG_DATASET_EXPECTED_INOUT_DATASET: + if(expected_inout_datasets) { + free(expected_inout_datasets); + } + + if(scord_utils_parse_dataset_routes( + optarg, &expected_inout_datasets, + &expected_inout_datasets_count) != ADM_SUCCESS) { + slurm_error("%s: %s: failed to parse dataset route: %s", + plugin_name, __func__, optarg); + return -1; + } + return 0; + default: return -1; } @@ -482,8 +550,14 @@ scord_register_job(scord_plugin_config_t cfg, scord_nodelist_t nodelist, goto end; } + slurm_debug("Creating job requirements: %zu inputs, %zu outputs", + input_datasets_count, output_datasets_count); + /* no inputs or outputs */ - scord_reqs = ADM_job_requirements_create(NULL, 0, NULL, 0, adhoc_storage); + scord_reqs = ADM_job_requirements_create( + input_datasets, input_datasets_count, output_datasets, + output_datasets_count, expected_output_datasets, + expected_output_datasets_count, adhoc_storage); if(!scord_reqs) { slurm_error("%s: scord job_requirements creation", plugin_name); rc = -1; diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 08628808..cc6b1810 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -85,12 +85,13 @@ add_library(libscord SHARED) target_sources( libscord - PUBLIC scord/scord.h scord/scord.hpp - PRIVATE libscord.cpp c_wrapper.cpp detail/impl.hpp detail/impl.cpp env.hpp + PUBLIC scord/scord.h scord/scord.hpp scord/types.hpp + PRIVATE libscord.cpp c_wrapper.cpp utils.cpp detail/impl.hpp detail/impl.cpp + env.hpp ) set(public_headers, "") -list(APPEND public_headers "scord/scord.h" "scord/scord.hpp") +list(APPEND public_headers "scord/scord.h" "scord/scord.hpp" "scord/types.hpp") set_target_properties(libscord PROPERTIES PUBLIC_HEADER "${public_headers}") diff --git a/src/lib/scord/types.h b/src/lib/scord/types.h index e8c32fcd..e518cb8f 100644 --- a/src/lib/scord/types.h +++ b/src/lib/scord/types.h @@ -108,12 +108,18 @@ typedef struct adm_job_requirements* ADM_job_requirements_t; /** A dataset */ typedef struct adm_dataset* ADM_dataset_t; +/** Routing information for a dataset */ +typedef struct adm_dataset_route* ADM_dataset_route_t; + /** Information about a dataset */ typedef struct adm_dataset_info* ADM_dataset_info_t; /** A list of datasets */ typedef struct adm_dataset_list* ADM_dataset_list_t; +/** A list of dataset routes */ +typedef struct adm_dataset_route_list* ADM_dataset_route_list_t; + /** A list of QoS limits */ typedef struct adm_qos_limit_list* ADM_qos_limit_list_t; @@ -360,12 +366,16 @@ ADM_job_resources_destroy(ADM_job_resources_t res); * @remark JOB_REQUIREMENTS created by this function need to be freed by calling * ADM_job_requirements_destroy(). * - * @param[in] inputs An array of DATASET_DESCRIPTORS describing the input + * @param[in] inputs An array of DATASET_ROUTES describing the input * information required by the job. - * @param[in] inputs_len The number of DATASET_DESCRIPTORS stored in inputs. - * @param[in] outputs An array of DATASET_DESCRIPTORS describing the output + * @param[in] inputs_len The number of DATASET_ROUTES stored in inputs. + * @param[in] outputs An array of DATASET_ROUTES describing the output * information generated by the job. - * @param[in] outputs_len The number of DATASET_DESCRIPTORS stored in outputs. + * @param[in] outputs_len The number of DATASET_ROUTES stored in outputs. + * @param[in] expected_outputs An array of DATASET_ROUTES describing the + * expected output information generated by the job. + * @param[in] expected_outputs_len The number of DATASET_ROUTES stored in + * expected_outputs. * @param[in] adhoc_storage An optional ADHOC_DESCRIPTOR describing the adhoc * storage system required by the job (can be set to NULL if no adhoc storage * system is required). @@ -373,8 +383,10 @@ ADM_job_resources_destroy(ADM_job_resources_t res); * failure. */ ADM_job_requirements_t -ADM_job_requirements_create(ADM_dataset_t inputs[], size_t inputs_len, - ADM_dataset_t outputs[], size_t outputs_len, +ADM_job_requirements_create(ADM_dataset_route_t inputs[], size_t inputs_len, + ADM_dataset_route_t outputs[], size_t outputs_len, + ADM_dataset_route_t expected_outputs[], + size_t expected_outputs_len, ADM_adhoc_storage_t adhoc_storage); /** @@ -425,6 +437,28 @@ ADM_dataset_create(const char* id); ADM_return_t ADM_dataset_destroy(ADM_dataset_t dataset); +/** + * Create a dataset route from a source and destination dataset. + * + * @remark Dataset routes need to be freed by calling + * ADM_dataset_route_destroy(). + * + * @param source The source dataset + * @param destination The destination dataset + * @return A valid ADM_dataset_route_t if successful or NULL in case of failure. + */ +ADM_dataset_route_t +ADM_dataset_route_create(ADM_dataset_t source, ADM_dataset_t destination); + +/** + * Destroy a dataset route created by ADM_dataset_route_create(). + * + * @param route A valid ADM_dataset_route_t + * @return ADM_SUCCESS or corresponding ADM error code + */ +ADM_return_t +ADM_dataset_route_destroy(ADM_dataset_route_t route); + /** * Create a dataset from a user-provided id (e.g. a path for POSIX-like file * systems or key for key-value stores). diff --git a/src/lib/scord/types.hpp b/src/lib/scord/types.hpp index 10b890ad..f7445b30 100644 --- a/src/lib/scord/types.hpp +++ b/src/lib/scord/types.hpp @@ -190,6 +190,7 @@ private: }; struct dataset; +struct dataset_route; struct adhoc_storage { @@ -416,17 +417,21 @@ struct job { struct requirements { requirements(); - requirements(std::vector inputs, - std::vector outputs); - requirements(std::vector inputs, - std::vector outputs, + requirements(std::vector inputs, + std::vector outputs, + std::vector expected_outputs); + requirements(std::vector inputs, + std::vector outputs, + std::vector expected_outputs, scord::adhoc_storage adhoc_storage); explicit requirements(ADM_job_requirements_t reqs); - std::vector + std::vector const& inputs() const; - std::vector + std::vector const& outputs() const; + std::vector const& + expected_outputs() const; std::optional adhoc_storage() const; @@ -437,12 +442,14 @@ struct job { serialize(Archive& ar) { ar & m_inputs; ar & m_outputs; + ar & m_expected_outputs; ar & m_adhoc_storage; } private: - std::vector m_inputs; - std::vector m_outputs; + std::vector m_inputs; + std::vector m_outputs; + std::vector m_expected_outputs; std::optional m_adhoc_storage; }; @@ -663,6 +670,33 @@ private: std::unique_ptr m_pimpl; }; +struct dataset_route { + dataset_route(); + explicit dataset_route(scord::dataset src, scord::dataset dst); + explicit dataset_route(ADM_dataset_route_t route); + dataset_route(const dataset_route&) noexcept; + dataset_route(dataset_route&&) noexcept; + dataset_route& + operator=(const dataset_route&) noexcept; + dataset_route& + operator=(dataset_route&&) noexcept; + ~dataset_route(); + + scord::dataset const& + source() const; + + scord::dataset const& + destination() const; + + template + void + serialize(Archive& ar); + +private: + class impl; + std::unique_ptr m_pimpl; +}; + } // namespace scord @@ -726,6 +760,31 @@ struct fmt::formatter> } }; +template <> +struct fmt::formatter : formatter { + // parse is inherited from formatter. + template + auto + format(const scord::dataset_route& r, FormatContext& ctx) const { + const auto str = fmt::format("{{src: {}, dst: {}}}", r.source(), + r.destination()); + return formatter::format(str, ctx); + } +}; + +template <> +struct fmt::formatter> + : fmt::formatter { + // parse is inherited from formatter. + template + auto + format(const std::vector& v, + FormatContext& ctx) const { + const auto str = fmt::format("[{}]", fmt::join(v, ", ")); + return formatter::format(str, ctx); + } +}; + template <> struct fmt::formatter : fmt::formatter { // parse is inherited from formatter. @@ -1054,8 +1113,10 @@ struct fmt::formatter : formatter { auto format(const scord::job::requirements& r, FormatContext& ctx) const { return formatter::format( - fmt::format("{{inputs: {}, outputs: {}, adhoc_storage: {}}}", - r.inputs(), r.outputs(), r.adhoc_storage()), + fmt::format("{{inputs: {}, outputs: {}, " + "expected_outputs: {}, adhoc_storage: {}}}", + r.inputs(), r.outputs(), r.expected_outputs(), + r.adhoc_storage()), ctx); } }; diff --git a/src/lib/scord/utils.h b/src/lib/scord/utils.h new file mode 100644 index 00000000..bcdb134c --- /dev/null +++ b/src/lib/scord/utils.h @@ -0,0 +1,42 @@ +/****************************************************************************** + * Copyright 2021-2023, Barcelona Supercomputing Center (BSC), Spain + * + * This software was partially supported by the EuroHPC-funded project ADMIRE + * (Project ID: 956748, https://www.admire-eurohpc.eu). + * + * This file is part of the scord API. + * + * The scord API is free software: you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The scord API is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the Lesser GNU General Public License + * along with the scord API. If not, see . + * + * SPDX-License-Identifier: LGPL-3.0-or-later + *****************************************************************************/ + +#ifndef SCORD_UTILS_H +#define SCORD_UTILS_H + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +ADM_return_t +scord_utils_parse_dataset_routes(const char* routes, + ADM_dataset_route_t** parsed_routes, + size_t* parsed_routes_count); +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // SCORD_UTILS_H diff --git a/src/lib/types.c b/src/lib/types.c index 65c8a560..eef6ac38 100644 --- a/src/lib/types.c +++ b/src/lib/types.c @@ -264,6 +264,79 @@ ADM_dataset_destroy(ADM_dataset_t dataset) { return ret; } +ADM_dataset_route_t +ADM_dataset_route_create(ADM_dataset_t source, ADM_dataset_t destination) { + + struct adm_dataset_route* adm_dataset_route = + (struct adm_dataset_route*) malloc( + sizeof(struct adm_dataset_route)); + + if(!adm_dataset_route) { + LOGGER_ERROR("Could not allocate ADM_dataset_route_t"); + return NULL; + } + + adm_dataset_route->d_src = ADM_dataset_create(source->d_id); + + if(!adm_dataset_route->d_src) { + LOGGER_ERROR("Could not allocate ADM_dataset_t"); + return NULL; + } + + adm_dataset_route->d_dst = ADM_dataset_create(destination->d_id); + + if(!adm_dataset_route->d_dst) { + LOGGER_ERROR("Could not allocate ADM_dataset_t"); + return NULL; + } + + return adm_dataset_route; +} + +ADM_dataset_route_t +ADM_dataset_route_copy(ADM_dataset_route_t dst, const ADM_dataset_route_t src) { + + if(!src || !dst) { + return NULL; + } + + // copy all primitive types + *dst = *src; + + // duplicate copy any pointer types + if(src->d_src) { + dst->d_src = ADM_dataset_create(src->d_src->d_id); + } + + if(src->d_dst) { + dst->d_dst = ADM_dataset_create(src->d_dst->d_id); + } + + return dst; +} + +ADM_return_t +ADM_dataset_route_destroy(ADM_dataset_route_t route) { + + ADM_return_t ret = ADM_SUCCESS; + + if(!route) { + LOGGER_ERROR("Invalid ADM_dataset_route_t"); + return ADM_EBADARGS; + } + + if(route->d_src) { + ADM_dataset_destroy(route->d_src); + } + + if(route->d_dst) { + ADM_dataset_destroy(route->d_dst); + } + + free(route); + return ret; +} + ADM_qos_entity_t ADM_qos_entity_create(ADM_qos_scope_t scope, void* data) { @@ -448,6 +521,70 @@ ADM_dataset_list_destroy(ADM_dataset_list_t list) { return ret; } +ADM_dataset_route_list_t +ADM_dataset_route_list_create(ADM_dataset_route_t routes[], size_t length) { + + ADM_dataset_route_list_t p = (ADM_dataset_route_list_t) malloc(sizeof(*p)); + + if(!p) { + LOGGER_ERROR("Could not allocate ADM_dataset_route_list_t"); + return NULL; + } + + const char* error_msg = NULL; + + p->l_length = length; + p->l_routes = (struct adm_dataset_route*) calloc( + length, sizeof(struct adm_dataset_route)); + + if(!p->l_routes) { + error_msg = "Could not allocate ADM_dataset_route_list_t"; + goto cleanup_on_error; + } + + for(size_t i = 0; i < length; ++i) { + if(!ADM_dataset_route_copy(&p->l_routes[i], routes[i])) { + error_msg = "Could not allocate ADM_dataset_route_list_t"; + goto cleanup_on_error; + }; + } + + return p; + +cleanup_on_error: + if(p->l_routes) { + free(p->l_routes); + } + free(p); + + LOGGER_ERROR(error_msg); + + return NULL; +} + +ADM_return_t +ADM_dataset_route_list_destroy(ADM_dataset_route_list_t list) { + ADM_return_t ret = ADM_SUCCESS; + + if(!list) { + LOGGER_ERROR("Invalid ADM_dataset_route_list_t"); + return ADM_EBADARGS; + } + + // We cannot call ADM_dataset_route_destroy here because adm_dataset_routes + // are stored as a consecutive array in memory. Thus, we free + // the dataset route ids themselves and then the array. + if(list->l_routes) { + for(size_t i = 0; i < list->l_length; ++i) { + ADM_dataset_route_destroy(&list->l_routes[i]); + } + free(list->l_routes); + } + + free(list); + return ret; +} + ADM_adhoc_storage_t ADM_adhoc_storage_create(const char* name, ADM_adhoc_storage_type_t type, uint64_t id, ADM_adhoc_context_t adhoc_ctx, @@ -821,8 +958,10 @@ ADM_job_resources_destroy(ADM_job_resources_t res) { ADM_job_requirements_t -ADM_job_requirements_create(ADM_dataset_t inputs[], size_t inputs_len, - ADM_dataset_t outputs[], size_t outputs_len, +ADM_job_requirements_create(ADM_dataset_route_t inputs[], size_t inputs_len, + ADM_dataset_route_t outputs[], size_t outputs_len, + ADM_dataset_route_t expected_outputs[], + size_t expected_outputs_len, ADM_adhoc_storage_t adhoc_storage) { struct adm_job_requirements* adm_job_reqs = @@ -834,26 +973,36 @@ ADM_job_requirements_create(ADM_dataset_t inputs[], size_t inputs_len, return NULL; } - ADM_dataset_list_t inputs_list = NULL; - ADM_dataset_list_t outputs_list = NULL; + ADM_dataset_route_list_t inputs_list = NULL; + ADM_dataset_route_list_t outputs_list = NULL; + ADM_dataset_route_list_t expected_outputs_list = NULL; const char* error_msg = NULL; - inputs_list = ADM_dataset_list_create(inputs, inputs_len); + inputs_list = ADM_dataset_route_list_create(inputs, inputs_len); if(!inputs_list) { error_msg = "Could not allocate ADM_job_requirements_t"; goto cleanup_on_error; } - outputs_list = ADM_dataset_list_create(outputs, outputs_len); + outputs_list = ADM_dataset_route_list_create(outputs, outputs_len); if(!outputs_list) { error_msg = "Could not allocate ADM_job_requirements_t"; goto cleanup_on_error; } + expected_outputs_list = ADM_dataset_route_list_create(expected_outputs, + expected_outputs_len); + + if(!expected_outputs_list) { + error_msg = "Could not allocate ADM_job_requirements_t"; + goto cleanup_on_error; + } + adm_job_reqs->r_inputs = inputs_list; adm_job_reqs->r_outputs = outputs_list; + adm_job_reqs->r_expected_outputs = expected_outputs_list; if(!adhoc_storage) { return adm_job_reqs; @@ -889,11 +1038,15 @@ ADM_job_requirements_destroy(ADM_job_requirements_t reqs) { } if(reqs->r_inputs) { - ADM_dataset_list_destroy(reqs->r_inputs); + ADM_dataset_route_list_destroy(reqs->r_inputs); } if(reqs->r_outputs) { - ADM_dataset_list_destroy(reqs->r_outputs); + ADM_dataset_route_list_destroy(reqs->r_outputs); + } + + if(reqs->r_expected_outputs) { + ADM_dataset_route_list_destroy(reqs->r_expected_outputs); } if(reqs->r_adhoc_storage) { diff --git a/src/lib/types.cpp b/src/lib/types.cpp index 9b64acdb..e51c2a08 100644 --- a/src/lib/types.cpp +++ b/src/lib/types.cpp @@ -232,14 +232,20 @@ private: job::requirements::requirements() = default; -job::requirements::requirements(std::vector inputs, - std::vector outputs) - : m_inputs(std::move(inputs)), m_outputs(std::move(outputs)) {} +job::requirements::requirements( + std::vector inputs, + std::vector outputs, + std::vector expected_outputs) + : m_inputs(std::move(inputs)), m_outputs(std::move(outputs)), + m_expected_outputs(std::move(expected_outputs)) {} -job::requirements::requirements(std::vector inputs, - std::vector outputs, - scord::adhoc_storage adhoc_storage) +job::requirements::requirements( + std::vector inputs, + std::vector outputs, + std::vector expected_outputs, + scord::adhoc_storage adhoc_storage) : m_inputs(std::move(inputs)), m_outputs(std::move(outputs)), + m_expected_outputs(std::move(expected_outputs)), m_adhoc_storage(std::move(adhoc_storage)) {} job::requirements::requirements(ADM_job_requirements_t reqs) { @@ -247,13 +253,23 @@ job::requirements::requirements(ADM_job_requirements_t reqs) { m_inputs.reserve(reqs->r_inputs->l_length); for(size_t i = 0; i < reqs->r_inputs->l_length; ++i) { - m_inputs.emplace_back(reqs->r_inputs->l_datasets[i].d_id); + m_inputs.emplace_back(dataset{reqs->r_inputs->l_routes[i].d_src}, + dataset{reqs->r_inputs->l_routes[i].d_dst}); } m_outputs.reserve(reqs->r_outputs->l_length); for(size_t i = 0; i < reqs->r_outputs->l_length; ++i) { - m_outputs.emplace_back(reqs->r_outputs->l_datasets[i].d_id); + m_outputs.emplace_back(dataset{reqs->r_inputs->l_routes[i].d_src}, + dataset{reqs->r_inputs->l_routes[i].d_dst}); + } + + m_expected_outputs.reserve(reqs->r_expected_outputs->l_length); + + for(size_t i = 0; i < reqs->r_expected_outputs->l_length; ++i) { + m_expected_outputs.emplace_back( + dataset{reqs->r_expected_outputs->l_routes[i].d_src}, + dataset{reqs->r_expected_outputs->l_routes[i].d_dst}); } if(reqs->r_adhoc_storage) { @@ -261,16 +277,21 @@ job::requirements::requirements(ADM_job_requirements_t reqs) { } } -std::vector +std::vector const& job::requirements::inputs() const { return m_inputs; } -std::vector +std::vector const& job::requirements::outputs() const { return m_outputs; } +std::vector const& +job::requirements::expected_outputs() const { + return m_expected_outputs; +} + std::optional job::requirements::adhoc_storage() const { return m_adhoc_storage; @@ -528,6 +549,110 @@ template void dataset::serialize( network::serialization::input_archive&); +class dataset_route::impl { +public: + impl() = default; + explicit impl(dataset src, dataset dst) + : m_source(std::move(src)), m_destination(std::move(dst)) {} + impl(const impl& rhs) = default; + impl(impl&& rhs) = default; + impl& + operator=(const impl& other) noexcept = default; + impl& + operator=(impl&&) noexcept = default; + ~impl() = default; + + dataset const& + source() const { + return m_source; + } + + dataset const& + destination() const { + return m_destination; + } + + template + void + load(Archive& ar) { + ar(SCORD_SERIALIZATION_NVP(m_source)); + ar(SCORD_SERIALIZATION_NVP(m_destination)); + } + + template + void + save(Archive& ar) const { + ar(SCORD_SERIALIZATION_NVP(m_source)); + ar(SCORD_SERIALIZATION_NVP(m_destination)); + } + +private: + dataset m_source; + dataset m_destination; +}; + +dataset_route::dataset_route() = default; + +dataset_route::dataset_route(dataset src, dataset dst) + : m_pimpl(std::make_unique(std::move(src), + std::move(dst))) {} + +dataset_route::dataset_route(ADM_dataset_route_t dataset_route) + : dataset_route::dataset_route(dataset{dataset_route->d_src}, + dataset{dataset_route->d_dst}) {} + +dataset_route::dataset_route(const dataset_route& other) noexcept + : m_pimpl(std::make_unique(*other.m_pimpl)) {} + +dataset_route::dataset_route(dataset_route&&) noexcept = default; + +dataset_route& +dataset_route::operator=(const dataset_route& other) noexcept { + this->m_pimpl = std::make_unique(*other.m_pimpl); + return *this; +} + +dataset_route& +dataset_route::operator=(dataset_route&&) noexcept = default; + +dataset_route::~dataset_route() = default; + +dataset const& +dataset_route::source() const { + return m_pimpl->source(); +} + +dataset const& +dataset_route::destination() const { + return m_pimpl->destination(); +} + +// since the PIMPL class is fully defined at this point, we can now +// define the serialization function +template +inline void +dataset_route::serialize(Archive& ar) { + ar(SCORD_SERIALIZATION_NVP(m_pimpl)); +} + +// we must also explicitly instantiate our template functions for +// serialization in the desired archives +template void +dataset_route::impl::save( + network::serialization::output_archive&) const; + +template void +dataset_route::impl::load( + network::serialization::input_archive&); + +template void +dataset_route::serialize( + network::serialization::output_archive&); + +template void +dataset_route::serialize( + network::serialization::input_archive&); + adhoc_storage::resources::resources(std::vector nodes) : m_nodes(std::move(nodes)) {} diff --git a/src/lib/types_private.h b/src/lib/types_private.h index bc431bd8..3e0ba099 100644 --- a/src/lib/types_private.h +++ b/src/lib/types_private.h @@ -45,6 +45,11 @@ struct adm_dataset { const char* d_id; }; +struct adm_dataset_route { + ADM_dataset_t d_src; + ADM_dataset_t d_dst; +}; + struct adm_job { uint64_t j_id; uint64_t j_slurm_id; @@ -129,9 +134,11 @@ struct adm_data_operation { struct adm_job_requirements { /** An array of input datasets */ - ADM_dataset_list_t r_inputs; + ADM_dataset_route_list_t r_inputs; /** An array of output datasets */ - ADM_dataset_list_t r_outputs; + ADM_dataset_route_list_t r_outputs; + /** An array of expected output datasets */ + ADM_dataset_route_list_t r_expected_outputs; /** An optional definition for a specific storage instance */ ADM_adhoc_storage_t r_adhoc_storage; }; @@ -149,6 +156,13 @@ struct adm_dataset_list { size_t l_length; }; +struct adm_dataset_route_list { + /** An array of dataset routes */ + struct adm_dataset_route* l_routes; + /** The length of the array */ + size_t l_length; +}; + struct adm_qos_limit_list { /** An array of QoS limits */ struct adm_qos_limit* l_limits; diff --git a/src/lib/utils.cpp b/src/lib/utils.cpp new file mode 100644 index 00000000..846fc0eb --- /dev/null +++ b/src/lib/utils.cpp @@ -0,0 +1,99 @@ +/****************************************************************************** + * Copyright 2021-2023, Barcelona Supercomputing Center (BSC), Spain + * + * This software was partially supported by the EuroHPC-funded project ADMIRE + * (Project ID: 956748, https://www.admire-eurohpc.eu). + * + * This file is part of the scord API. + * + * The scord API is free software: you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The scord API is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the Lesser GNU General Public License + * along with the scord API. If not, see . + * + * SPDX-License-Identifier: LGPL-3.0-or-later + *****************************************************************************/ + +#include +#include +#include + + +namespace { + +std::vector +split(const std::string& text, char sep) { + std::vector tokens; + std::size_t start = 0, end; + + while((end = text.find(sep, start)) != std::string::npos) { + tokens.push_back(text.substr(start, end - start)); + start = end + 1; + } + + tokens.push_back(text.substr(start)); + return tokens; +} + +} // namespace + +extern "C" ADM_return_t +scord_utils_parse_dataset_routes(const char* routes, + ADM_dataset_route_t** parsed_routes, + size_t* parsed_routes_count) { + + std::vector tmp; + + if(routes == nullptr || parsed_routes == nullptr || + parsed_routes_count == nullptr) { + return ADM_EBADARGS; + } + + const std::string route_str(routes); + + if(route_str.empty()) { + return ADM_EBADARGS; + } + + for(auto&& rs : split(route_str, ';')) { + + const auto parts = split(rs, '='); + + if(parts.size() != 2) { + return ADM_EBADARGS; + } + + ADM_dataset_route_t dr = + ADM_dataset_route_create(ADM_dataset_create(parts[0].c_str()), + ADM_dataset_create(parts[1].c_str())); + + if(dr == nullptr) { + return ADM_ENOMEM; + } + + tmp.push_back(dr); + } + + *parsed_routes = static_cast( + malloc(tmp.size() * sizeof(ADM_dataset_route_t))); + + if(*parsed_routes == nullptr) { + return ADM_ENOMEM; + } + + *parsed_routes_count = tmp.size(); + + for(std::size_t i = 0; i < tmp.size(); i++) { + (*parsed_routes)[i] = tmp[i]; + } + + return ADM_SUCCESS; +} -- GitLab From 9150948e651e745ff2b6f5fef9a9b5a5c504f542 Mon Sep 17 00:00:00 2001 From: Ramon Nou Date: Wed, 8 Nov 2023 17:05:17 +0100 Subject: [PATCH 5/8] Solved some issues with cargo, add testing --- CMakeLists.txt | 2 +- examples/CMakeLists.txt | 17 +++++++++++++++++ examples/c/ADM_cancel_transfer.c | 1 + examples/c/ADM_connect_data_operation.c | 1 + examples/c/ADM_define_data_operation.c | 1 + examples/c/ADM_deploy_adhoc_storage.c | 1 + examples/c/ADM_finalize_data_operation.c | 1 + examples/c/ADM_get_pending_transfers.c | 1 + examples/c/ADM_get_qos_constraints.c | 1 + examples/c/ADM_get_statistics.c | 1 + examples/c/ADM_get_transfer_priority.c | 1 + .../c/ADM_link_transfer_to_data_operation.c | 1 + examples/c/ADM_register_adhoc_storage.c | 1 + examples/c/ADM_register_job.c | 5 +++-- examples/c/ADM_remove_adhoc_storage.c | 1 + examples/c/ADM_remove_job.c | 1 + examples/c/ADM_set_dataset_information.c | 1 + examples/c/ADM_set_io_resources.c | 1 + examples/c/ADM_set_qos_constraints.c | 1 + examples/c/ADM_set_transfer_priority.c | 1 + examples/c/ADM_terminate_adhoc_storage.c | 1 + examples/c/ADM_transfer_datasets.c | 1 + examples/c/ADM_transfer_datasets_user.c | 1 + examples/c/ADM_update_adhoc_storage.c | 1 + examples/c/ADM_update_job.c | 1 + examples/c/CMakeLists.txt | 5 +++-- examples/c/common.c | 4 +++- examples/cxx/CMakeLists.txt | 3 ++- src/lib/scord/types.hpp | 3 +++ src/lib/types.c | 4 ++-- tests/test.cpp | 4 ++++ 31 files changed, 60 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 86501d1b..38c83da9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,7 +157,7 @@ set(SCORD_CTL_BIND_PORT ) message(STATUS "[${PROJECT_NAME}] server bind port: ${SCORD_CTL_BIND_PORT}") -set(CARGO_PORT +set(CARGO_BIND_PORT "62000" CACHE STRING "Define the port through wich we should commmunicate with Cargo" diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 5959af25..98b35d49 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -36,6 +36,9 @@ if(SCORD_BUILD_TESTS) set(SCORD_ADDRESS_STRING ${SCORD_TRANSPORT_PROTOCOL}://${SCORD_BIND_ADDRESS}:${SCORD_BIND_PORT}) + set(DATA_STAGER_ADDRESS_STRING + ${SCORD_TRANSPORT_PROTOCOL}://${SCORD_BIND_ADDRESS}:${CARGO_BIND_PORT}) + add_test(start_scord_daemon ${CMAKE_SOURCE_DIR}/scripts/runner.sh start scord.pid ${CMAKE_BINARY_DIR}/src/scord/scord -f -c ${CMAKE_CURRENT_BINARY_DIR}/scord.conf @@ -73,6 +76,20 @@ if(SCORD_BUILD_TESTS) set_tests_properties(stop_scord_ctl PROPERTIES FIXTURES_CLEANUP scord_ctl) + + add_test(start_cargo + ${CMAKE_SOURCE_DIR}/scripts/runner.sh start cargo.pid + mpirun --allow-run-as-root -n 2 ${CARGO_BIN_INSTALL_DIR}/cargo -l ${CARGO_ADDRESS_STRING} + ) + set_tests_properties(start_cargo + PROPERTIES FIXTURES_SETUP cargo) + + add_test(stop_cargo + ${CMAKE_SOURCE_DIR}/scripts/runner.sh stop TERM cargo.pid) + + set_tests_properties(stop_cargo + PROPERTIES FIXTURES_CLEANUP cargo) + endif() add_subdirectory(c) diff --git a/examples/c/ADM_cancel_transfer.c b/examples/c/ADM_cancel_transfer.c index 8dd6fc82..76fff6aa 100644 --- a/examples/c/ADM_cancel_transfer.c +++ b/examples/c/ADM_cancel_transfer.c @@ -35,6 +35,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; cli_args_t cli_args; diff --git a/examples/c/ADM_connect_data_operation.c b/examples/c/ADM_connect_data_operation.c index b766b0e9..f860dd80 100644 --- a/examples/c/ADM_connect_data_operation.c +++ b/examples/c/ADM_connect_data_operation.c @@ -35,6 +35,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; cli_args_t cli_args; diff --git a/examples/c/ADM_define_data_operation.c b/examples/c/ADM_define_data_operation.c index c7a225f6..6f08e8b8 100644 --- a/examples/c/ADM_define_data_operation.c +++ b/examples/c/ADM_define_data_operation.c @@ -35,6 +35,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; cli_args_t cli_args; diff --git a/examples/c/ADM_deploy_adhoc_storage.c b/examples/c/ADM_deploy_adhoc_storage.c index f568818b..fdc5b331 100644 --- a/examples/c/ADM_deploy_adhoc_storage.c +++ b/examples/c/ADM_deploy_adhoc_storage.c @@ -34,6 +34,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; cli_args_t cli_args; diff --git a/examples/c/ADM_finalize_data_operation.c b/examples/c/ADM_finalize_data_operation.c index f32b5e47..2605cc69 100644 --- a/examples/c/ADM_finalize_data_operation.c +++ b/examples/c/ADM_finalize_data_operation.c @@ -35,6 +35,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; cli_args_t cli_args; diff --git a/examples/c/ADM_get_pending_transfers.c b/examples/c/ADM_get_pending_transfers.c index 4184db30..7f9e49d3 100644 --- a/examples/c/ADM_get_pending_transfers.c +++ b/examples/c/ADM_get_pending_transfers.c @@ -35,6 +35,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; cli_args_t cli_args; diff --git a/examples/c/ADM_get_qos_constraints.c b/examples/c/ADM_get_qos_constraints.c index 92807bcc..f3e0b8f8 100644 --- a/examples/c/ADM_get_qos_constraints.c +++ b/examples/c/ADM_get_qos_constraints.c @@ -35,6 +35,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; cli_args_t cli_args; diff --git a/examples/c/ADM_get_statistics.c b/examples/c/ADM_get_statistics.c index e657ab81..5ce8a715 100644 --- a/examples/c/ADM_get_statistics.c +++ b/examples/c/ADM_get_statistics.c @@ -35,6 +35,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; cli_args_t cli_args; diff --git a/examples/c/ADM_get_transfer_priority.c b/examples/c/ADM_get_transfer_priority.c index cb97a730..0442740e 100644 --- a/examples/c/ADM_get_transfer_priority.c +++ b/examples/c/ADM_get_transfer_priority.c @@ -35,6 +35,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; cli_args_t cli_args; diff --git a/examples/c/ADM_link_transfer_to_data_operation.c b/examples/c/ADM_link_transfer_to_data_operation.c index 34552d91..cbadc2a6 100644 --- a/examples/c/ADM_link_transfer_to_data_operation.c +++ b/examples/c/ADM_link_transfer_to_data_operation.c @@ -35,6 +35,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; cli_args_t cli_args; diff --git a/examples/c/ADM_register_adhoc_storage.c b/examples/c/ADM_register_adhoc_storage.c index b86d29a6..106251a0 100644 --- a/examples/c/ADM_register_adhoc_storage.c +++ b/examples/c/ADM_register_adhoc_storage.c @@ -34,6 +34,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; cli_args_t cli_args; diff --git a/examples/c/ADM_register_job.c b/examples/c/ADM_register_job.c index cbff276e..e20a3fae 100644 --- a/examples/c/ADM_register_job.c +++ b/examples/c/ADM_register_job.c @@ -34,6 +34,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; cli_args_t cli_args; @@ -195,10 +196,10 @@ cleanup: ADM_server_destroy(server); ADM_job_requirements_destroy(reqs); - destroy_routes(outputs, NOUTPUTS); destroy_routes(inputs, NINPUTS); + destroy_routes(outputs, NOUTPUTS); destroy_routes(expected_outputs, NEXPOUTPUTS); - ADM_job_resources_destroy(job_resources); + ADM_job_resources_destroy(job_resources); destroy_nodes(job_nodes, NJOB_NODES); ADM_adhoc_context_destroy(adhoc_ctx); diff --git a/examples/c/ADM_remove_adhoc_storage.c b/examples/c/ADM_remove_adhoc_storage.c index 28f47c1b..797f1d56 100644 --- a/examples/c/ADM_remove_adhoc_storage.c +++ b/examples/c/ADM_remove_adhoc_storage.c @@ -34,6 +34,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; cli_args_t cli_args; diff --git a/examples/c/ADM_remove_job.c b/examples/c/ADM_remove_job.c index 7ced330c..08c8d076 100644 --- a/examples/c/ADM_remove_job.c +++ b/examples/c/ADM_remove_job.c @@ -35,6 +35,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; cli_args_t cli_args; diff --git a/examples/c/ADM_set_dataset_information.c b/examples/c/ADM_set_dataset_information.c index 2a8b4120..3c5b77ca 100644 --- a/examples/c/ADM_set_dataset_information.c +++ b/examples/c/ADM_set_dataset_information.c @@ -35,6 +35,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; cli_args_t cli_args; diff --git a/examples/c/ADM_set_io_resources.c b/examples/c/ADM_set_io_resources.c index b38a7d33..de5547fd 100644 --- a/examples/c/ADM_set_io_resources.c +++ b/examples/c/ADM_set_io_resources.c @@ -35,6 +35,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; cli_args_t cli_args; diff --git a/examples/c/ADM_set_qos_constraints.c b/examples/c/ADM_set_qos_constraints.c index 80c5e6ba..f5929ae8 100644 --- a/examples/c/ADM_set_qos_constraints.c +++ b/examples/c/ADM_set_qos_constraints.c @@ -35,6 +35,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; cli_args_t cli_args; diff --git a/examples/c/ADM_set_transfer_priority.c b/examples/c/ADM_set_transfer_priority.c index 2a1d06f8..3d4bb8dc 100644 --- a/examples/c/ADM_set_transfer_priority.c +++ b/examples/c/ADM_set_transfer_priority.c @@ -35,6 +35,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; cli_args_t cli_args; diff --git a/examples/c/ADM_terminate_adhoc_storage.c b/examples/c/ADM_terminate_adhoc_storage.c index 6677c5fe..fa58bda3 100644 --- a/examples/c/ADM_terminate_adhoc_storage.c +++ b/examples/c/ADM_terminate_adhoc_storage.c @@ -34,6 +34,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; cli_args_t cli_args; diff --git a/examples/c/ADM_transfer_datasets.c b/examples/c/ADM_transfer_datasets.c index 2433091f..e1bc1d80 100644 --- a/examples/c/ADM_transfer_datasets.c +++ b/examples/c/ADM_transfer_datasets.c @@ -35,6 +35,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; cli_args_t cli_args; diff --git a/examples/c/ADM_transfer_datasets_user.c b/examples/c/ADM_transfer_datasets_user.c index 30356754..3d95903f 100644 --- a/examples/c/ADM_transfer_datasets_user.c +++ b/examples/c/ADM_transfer_datasets_user.c @@ -35,6 +35,7 @@ main(int argc, char** argv) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; cli_args_t cli_args; diff --git a/examples/c/ADM_update_adhoc_storage.c b/examples/c/ADM_update_adhoc_storage.c index ed33af03..dfe2bccf 100644 --- a/examples/c/ADM_update_adhoc_storage.c +++ b/examples/c/ADM_update_adhoc_storage.c @@ -34,6 +34,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; cli_args_t cli_args; diff --git a/examples/c/ADM_update_job.c b/examples/c/ADM_update_job.c index 70b8180c..401e76d4 100644 --- a/examples/c/ADM_update_job.c +++ b/examples/c/ADM_update_job.c @@ -35,6 +35,7 @@ main(int argc, char* argv[]) { .name = TESTNAME, .requires_server = true, .requires_controller = true, + .requires_data_stager = true, }; cli_args_t cli_args; diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt index 8e793a7b..2b05d5b3 100644 --- a/examples/c/CMakeLists.txt +++ b/examples/c/CMakeLists.txt @@ -83,9 +83,10 @@ if(SCORD_BUILD_TESTS) add_test(run_${TEST_NAME} ${example} ${SCORD_ADDRESS_STRING} - ${SCORD_CTL_ADDRESS_STRING}) + ${SCORD_CTL_ADDRESS_STRING} + $(DATA_STAGER_ADDRESS_STRING)) set_tests_properties(run_${TEST_NAME} - PROPERTIES FIXTURES_REQUIRED "scord_daemon;scord_ctl" + PROPERTIES FIXTURES_REQUIRED "scord_daemon;scord_ctl;cargo" ENVIRONMENT "${TEST_ENV}") add_test(validate_${TEST_NAME} diff --git a/examples/c/common.c b/examples/c/common.c index af662205..d5431c58 100644 --- a/examples/c/common.c +++ b/examples/c/common.c @@ -22,7 +22,8 @@ process_args(int argc, char* argv[], test_info_t test_info, cli_args_t* args) { ++required_args; } - if(argc != required_args) { + /* We accept more arguments than required */ + if(argc < required_args) { fprintf(stderr, "ERROR: missing arguments\n"); fprintf(stderr, "Usage: %s%s%s%s\n", test_info.name, test_info.requires_server ? " " : "", @@ -33,6 +34,7 @@ process_args(int argc, char* argv[], test_info_t test_info, cli_args_t* args) { args->server_address = test_info.requires_server ? argv[1] : NULL; args->controller_address = test_info.requires_controller ? argv[2] : NULL; + args->data_stager_address = test_info.requires_data_stager? argv[3] : NULL; return 0; } diff --git a/examples/cxx/CMakeLists.txt b/examples/cxx/CMakeLists.txt index cadabb2e..415e0f50 100644 --- a/examples/cxx/CMakeLists.txt +++ b/examples/cxx/CMakeLists.txt @@ -74,7 +74,8 @@ if(SCORD_BUILD_TESTS) add_test(run_${TEST_NAME} ${example} ${SCORD_ADDRESS_STRING} - ${SCORD_CTL_ADDRESS_STRING}) + ${SCORD_CTL_ADDRESS_STRING} + $(DATA_STAGER_ADDRESS_STRING)) set_tests_properties(run_${TEST_NAME} PROPERTIES FIXTURES_REQUIRED "scord_daemon;scord_ctl" ENVIRONMENT "${TEST_ENV}") diff --git a/src/lib/scord/types.hpp b/src/lib/scord/types.hpp index f7445b30..d6e771d1 100644 --- a/src/lib/scord/types.hpp +++ b/src/lib/scord/types.hpp @@ -51,6 +51,7 @@ struct error_code { static const error_code adhoc_dir_exists; static const error_code subprocess_error; static const error_code no_resources; + static const error_code timeout; static const error_code other; constexpr error_code() : m_value(ADM_SUCCESS) {} @@ -89,6 +90,7 @@ struct error_code { ADM_ERROR_CASE(ADM_EADHOC_DIR_CREATE_FAILED); ADM_ERROR_CASE(ADM_EADHOC_DIR_EXISTS); ADM_ERROR_CASE(ADM_ESUBPROCESS_ERROR); + ADM_ERROR_CASE(ADM_ETIMEOUT); ADM_ERROR_CASE(ADM_EOTHER); ADM_ERROR_DEFAULT_MSG("INVALID_ERROR_VALUE"); } @@ -123,6 +125,7 @@ constexpr error_code error_code::adhoc_dir_create_failed{ constexpr error_code error_code::adhoc_dir_exists{ADM_EADHOC_DIR_EXISTS}; constexpr error_code error_code::subprocess_error{ADM_ESUBPROCESS_ERROR}; constexpr error_code error_code::no_resources{ADM_ENO_RESOURCES}; +constexpr error_code error_code::timeout{ADM_ETIMEOUT}; constexpr error_code error_code::other{ADM_EOTHER}; using job_id = std::uint64_t; diff --git a/src/lib/types.c b/src/lib/types.c index eef6ac38..1e426909 100644 --- a/src/lib/types.c +++ b/src/lib/types.c @@ -332,8 +332,8 @@ ADM_dataset_route_destroy(ADM_dataset_route_t route) { if(route->d_dst) { ADM_dataset_destroy(route->d_dst); } - - free(route); + /* This causes a double free */ + //free(route); return ret; } diff --git a/tests/test.cpp b/tests/test.cpp index 31cdd319..ff2fc2de 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -46,6 +46,10 @@ SCENARIO("Error messages can be printed", "[lib][ADM_strerror]") { "Cannot allocate memory"); } + WHEN("The error number is ADM_ETIMEOUT") { + REQUIRE(std::string{ADM_strerror(ADM_ETIMEOUT)} == + "Timeout"); + } WHEN("The error number is ADM_EOTHER") { REQUIRE(std::string{ADM_strerror(ADM_EOTHER)} == "Undetermined error"); -- GitLab From 5c54edece6926770ac1bc9dc3d39c42d7b1fc352 Mon Sep 17 00:00:00 2001 From: Ramon Nou Date: Thu, 9 Nov 2023 09:48:01 +0100 Subject: [PATCH 6/8] Updates for testing cargo --- CMakeLists.txt | 2 +- examples/CMakeLists.txt | 2 +- examples/c/CMakeLists.txt | 2 +- examples/cxx/CMakeLists.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 38c83da9..622c1c16 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -303,7 +303,7 @@ find_package(RedisPlusPlus 1.3.3 REQUIRED) ### Cargo: required for transferring datasets between storage tiers message(STATUS "[${PROJECT_NAME}] Checking for Cargo") -find_package(Cargo 0.2.0 REQUIRED) +find_package(Cargo 0.3.1 REQUIRED) # ############################################################################## diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 98b35d49..6d47717c 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -79,7 +79,7 @@ if(SCORD_BUILD_TESTS) add_test(start_cargo ${CMAKE_SOURCE_DIR}/scripts/runner.sh start cargo.pid - mpirun --allow-run-as-root -n 2 ${CARGO_BIN_INSTALL_DIR}/cargo -l ${CARGO_ADDRESS_STRING} + mpirun --allow-run-as-root -n 2 ${CARGO_BIN_INSTALL_DIR}/cargo -l ${DATA_STAGER_ADDRESS_STRING} -o ${TEST_DIRECTORY}/cargo.log ) set_tests_properties(start_cargo PROPERTIES FIXTURES_SETUP cargo) diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt index 2b05d5b3..070a5713 100644 --- a/examples/c/CMakeLists.txt +++ b/examples/c/CMakeLists.txt @@ -84,7 +84,7 @@ if(SCORD_BUILD_TESTS) add_test(run_${TEST_NAME} ${example} ${SCORD_ADDRESS_STRING} ${SCORD_CTL_ADDRESS_STRING} - $(DATA_STAGER_ADDRESS_STRING)) + ${DATA_STAGER_ADDRESS_STRING}) set_tests_properties(run_${TEST_NAME} PROPERTIES FIXTURES_REQUIRED "scord_daemon;scord_ctl;cargo" ENVIRONMENT "${TEST_ENV}") diff --git a/examples/cxx/CMakeLists.txt b/examples/cxx/CMakeLists.txt index 415e0f50..86580f1f 100644 --- a/examples/cxx/CMakeLists.txt +++ b/examples/cxx/CMakeLists.txt @@ -75,7 +75,7 @@ if(SCORD_BUILD_TESTS) add_test(run_${TEST_NAME} ${example} ${SCORD_ADDRESS_STRING} ${SCORD_CTL_ADDRESS_STRING} - $(DATA_STAGER_ADDRESS_STRING)) + ${DATA_STAGER_ADDRESS_STRING}) set_tests_properties(run_${TEST_NAME} PROPERTIES FIXTURES_REQUIRED "scord_daemon;scord_ctl" ENVIRONMENT "${TEST_ENV}") -- GitLab From eb68bc07d2e6cd235951f3cf87ebfd1048034f45 Mon Sep 17 00:00:00 2001 From: Ramon Nou Date: Thu, 9 Nov 2023 12:29:23 +0100 Subject: [PATCH 7/8] added adhoc scripts --- examples/scord-ctl.conf.in | 138 ++++++++++++++++++++++++ plugins/adhoc_services.d/CMakeLists.txt | 5 +- plugins/adhoc_services.d/dataclay.sh | 3 + plugins/adhoc_services.d/expand.sh | 3 + plugins/adhoc_services.d/hercules.sh | 3 + 5 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 plugins/adhoc_services.d/dataclay.sh create mode 100644 plugins/adhoc_services.d/expand.sh create mode 100644 plugins/adhoc_services.d/hercules.sh diff --git a/examples/scord-ctl.conf.in b/examples/scord-ctl.conf.in index 58ba1616..83a02a42 100644 --- a/examples/scord-ctl.conf.in +++ b/examples/scord-ctl.conf.in @@ -35,7 +35,145 @@ config: command: @CMAKE_BINARY_DIR@/plugins/adhoc_services.d/gekkofs.sh stop --workdir {ADHOC_DIRECTORY} + expand: + environment: + command: @CMAKE_BINARY_DIR@/plugins/adhoc_services.d/gekkofs.sh + expand + --hosts {ADHOC_NODES} + + shrink: + environment: + command: @CMAKE_BINARY_DIR@/plugins/adhoc_services.d/gekkofs.sh + shrink + --hosts {ADHOC_NODES} + dataclay: + # The default working directory for adhoc instances of this type + working_directory: /tmp/dataclay + startup: + # Specific environment variables that should be set for the adhoc + # instance. These will be merged with the environment variables + # already set by Slurm. + environment: + VAR0: value0 + VAR1: value1 + # The command that `scord-ctl` will use to start an adhoc instance of + # this type. The following variables are supported that will be + # automatically replaced by scord-ctl if found between curly braces: + # * ADHOC_NODES: A comma separated list of valid job hostnames that + # can be used to start the adhoc instance. + # * ADHOC_DIRECTORY: A unique working directory for each specific + # adhoc instance. This directory will be created by scord-ctl under + # `working_directory` and automatically removed after the adhoc + # instance has been shut down. + # * ADHOC_ID: - A unique ID for the adhoc instance. + command: @CMAKE_BINARY_DIR@/plugins/adhoc_services.d/dataclay.sh + start + --hosts {ADHOC_NODES} + --workdir {ADHOC_DIRECTORY} + --datadir {ADHOC_DIRECTORY}/data + --mountdir {ADHOC_DIRECTORY}/mnt + shutdown: + environment: + command: @CMAKE_BINARY_DIR@/plugins/adhoc_services.d/dataclay.sh + stop + --workdir {ADHOC_DIRECTORY} + expand: + environment: + command: @CMAKE_BINARY_DIR@/plugins/adhoc_services.d/dataclay.sh + expand + --hosts {ADHOC_NODES} + + shrink: + environment: + command: @CMAKE_BINARY_DIR@/plugins/adhoc_services.d/dataclay.sh + shrink + --hosts {ADHOC_NODES} + + expand: + # The default working directory for adhoc instances of this type + working_directory: /tmp/expand + startup: + # Specific environment variables that should be set for the adhoc + # instance. These will be merged with the environment variables + # already set by Slurm. + environment: + VAR0: value0 + VAR1: value1 + # The command that `scord-ctl` will use to start an adhoc instance of + # this type. The following variables are supported that will be + # automatically replaced by scord-ctl if found between curly braces: + # * ADHOC_NODES: A comma separated list of valid job hostnames that + # can be used to start the adhoc instance. + # * ADHOC_DIRECTORY: A unique working directory for each specific + # adhoc instance. This directory will be created by scord-ctl under + # `working_directory` and automatically removed after the adhoc + # instance has been shut down. + # * ADHOC_ID: - A unique ID for the adhoc instance. + command: @CMAKE_BINARY_DIR@/plugins/adhoc_services.d/expand.sh + start + --hosts {ADHOC_NODES} + --workdir {ADHOC_DIRECTORY} + --datadir {ADHOC_DIRECTORY}/data + --mountdir {ADHOC_DIRECTORY}/mnt + shutdown: + environment: + command: @CMAKE_BINARY_DIR@/plugins/adhoc_services.d/expand.sh + stop + --workdir {ADHOC_DIRECTORY} + expand: + environment: + command: @CMAKE_BINARY_DIR@/plugins/adhoc_services.d/expand.sh + expand + --hosts {ADHOC_NODES} + + shrink: + environment: + command: @CMAKE_BINARY_DIR@/plugins/adhoc_services.d/expand.sh + shrink + --hosts {ADHOC_NODES} + hercules: + # The default working directory for adhoc instances of this type + working_directory: /tmp/hercules + startup: + # Specific environment variables that should be set for the adhoc + # instance. These will be merged with the environment variables + # already set by Slurm. + environment: + VAR0: value0 + VAR1: value1 + # The command that `scord-ctl` will use to start an adhoc instance of + # this type. The following variables are supported that will be + # automatically replaced by scord-ctl if found between curly braces: + # * ADHOC_NODES: A comma separated list of valid job hostnames that + # can be used to start the adhoc instance. + # * ADHOC_DIRECTORY: A unique working directory for each specific + # adhoc instance. This directory will be created by scord-ctl under + # `working_directory` and automatically removed after the adhoc + # instance has been shut down. + # * ADHOC_ID: - A unique ID for the adhoc instance. + command: @CMAKE_BINARY_DIR@/plugins/adhoc_services.d/hercules.sh + start + --hosts {ADHOC_NODES} + --workdir {ADHOC_DIRECTORY} + --datadir {ADHOC_DIRECTORY}/data + --mountdir {ADHOC_DIRECTORY}/mnt + shutdown: + environment: + command: @CMAKE_BINARY_DIR@/plugins/adhoc_services.d/hercules.sh + stop + --workdir {ADHOC_DIRECTORY} + expand: + environment: + command: @CMAKE_BINARY_DIR@/plugins/adhoc_services.d/hercules.sh + expand + --hosts {ADHOC_NODES} + + shrink: + environment: + command: @CMAKE_BINARY_DIR@/plugins/adhoc_services.d/hercules.sh + shrink + --hosts {ADHOC_NODES} # default storage tiers made available to applications storage: diff --git a/plugins/adhoc_services.d/CMakeLists.txt b/plugins/adhoc_services.d/CMakeLists.txt index 143a7e9d..2a5d0326 100644 --- a/plugins/adhoc_services.d/CMakeLists.txt +++ b/plugins/adhoc_services.d/CMakeLists.txt @@ -22,7 +22,10 @@ # SPDX-License-Identifier: GPL-3.0-or-later # ################################################################################ -list(APPEND ADHOC_SCRIPTS "${CMAKE_CURRENT_SOURCE_DIR}/gekkofs.sh") +list(APPEND ADHOC_SCRIPTS "${CMAKE_CURRENT_SOURCE_DIR}/gekkofs.sh" +"${CMAKE_CURRENT_SOURCE_DIR}/expand.sh" +"${CMAKE_CURRENT_SOURCE_DIR}/dataclay.sh" +"${CMAKE_CURRENT_SOURCE_DIR}/hercules.sh") # copy adhoc scripts to the build directory so that they can be used by tests foreach (ADHOC_SCRIPT ${ADHOC_SCRIPTS}) diff --git a/plugins/adhoc_services.d/dataclay.sh b/plugins/adhoc_services.d/dataclay.sh new file mode 100644 index 00000000..0fdcf091 --- /dev/null +++ b/plugins/adhoc_services.d/dataclay.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +exit 0 diff --git a/plugins/adhoc_services.d/expand.sh b/plugins/adhoc_services.d/expand.sh new file mode 100644 index 00000000..0fdcf091 --- /dev/null +++ b/plugins/adhoc_services.d/expand.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +exit 0 diff --git a/plugins/adhoc_services.d/hercules.sh b/plugins/adhoc_services.d/hercules.sh new file mode 100644 index 00000000..0fdcf091 --- /dev/null +++ b/plugins/adhoc_services.d/hercules.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +exit 0 -- GitLab From 98a25128cc02f21b73e69f3b6dd5f24907870586 Mon Sep 17 00:00:00 2001 From: Ramon Nou Date: Thu, 9 Nov 2023 15:41:31 +0100 Subject: [PATCH 8/8] Updated shrink-expand actions --- etc/scord-ctl.conf.in | 138 ++++++++++++++++++++++++++++ plugins/adhoc_services.d/gekkofs.sh | 2 +- src/scord-ctl/command.cpp | 46 ++++++++++ src/scord-ctl/command.hpp | 16 ++++ src/scord-ctl/config_file.cpp | 27 +++++- src/scord-ctl/config_file.hpp | 27 +++++- src/scord-ctl/rpc_server.cpp | 124 +++++++++++++++++++++++++ src/scord-ctl/rpc_server.hpp | 12 +++ src/scord/rpc_server.cpp | 80 +++++++++++++++- 9 files changed, 465 insertions(+), 7 deletions(-) diff --git a/etc/scord-ctl.conf.in b/etc/scord-ctl.conf.in index c0c12f7c..6cadeeb7 100644 --- a/etc/scord-ctl.conf.in +++ b/etc/scord-ctl.conf.in @@ -35,7 +35,145 @@ config: command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/gekkofs.sh stop --workdir {ADHOC_DIRECTORY} + expand: + environment: + command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/gekkofs.sh + expand + --hosts {ADHOC_NODES} + + shrink: + environment: + command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/gekkofs.sh + shrink + --hosts {ADHOC_NODES} + dataclay: + # The default working directory for adhoc instances of this type + working_directory: /tmp/dataclay + startup: + # Specific environment variables that should be set for the adhoc + # instance. These will be merged with the environment variables + # already set by Slurm. + environment: + VAR0: value0 + VAR1: value1 + # The command that `scord-ctl` will use to start an adhoc instance of + # this type. The following variables are supported that will be + # automatically replaced by scord-ctl if found between curly braces: + # * ADHOC_NODES: A comma separated list of valid job hostnames that + # can be used to start the adhoc instance. + # * ADHOC_DIRECTORY: A unique working directory for each specific + # adhoc instance. This directory will be created by scord-ctl under + # `working_directory` and automatically removed after the adhoc + # instance has been shut down. + # * ADHOC_ID: - A unique ID for the adhoc instance. + command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/dataclay.sh + start + --hosts {ADHOC_NODES} + --workdir {ADHOC_DIRECTORY} + --datadir {ADHOC_DIRECTORY}/data + --mountdir {ADHOC_DIRECTORY}/mnt + shutdown: + environment: + command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/dataclay.sh + stop + --workdir {ADHOC_DIRECTORY} + expand: + environment: + command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/dataclay.sh + expand + --hosts {ADHOC_NODES} + + shrink: + environment: + command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/dataclay.sh + shrink + --hosts {ADHOC_NODES} + + expand: + # The default working directory for adhoc instances of this type + working_directory: /tmp/expand + startup: + # Specific environment variables that should be set for the adhoc + # instance. These will be merged with the environment variables + # already set by Slurm. + environment: + VAR0: value0 + VAR1: value1 + # The command that `scord-ctl` will use to start an adhoc instance of + # this type. The following variables are supported that will be + # automatically replaced by scord-ctl if found between curly braces: + # * ADHOC_NODES: A comma separated list of valid job hostnames that + # can be used to start the adhoc instance. + # * ADHOC_DIRECTORY: A unique working directory for each specific + # adhoc instance. This directory will be created by scord-ctl under + # `working_directory` and automatically removed after the adhoc + # instance has been shut down. + # * ADHOC_ID: - A unique ID for the adhoc instance. + command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/expand.sh + start + --hosts {ADHOC_NODES} + --workdir {ADHOC_DIRECTORY} + --datadir {ADHOC_DIRECTORY}/data + --mountdir {ADHOC_DIRECTORY}/mnt + shutdown: + environment: + command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/expand.sh + stop + --workdir {ADHOC_DIRECTORY} + expand: + environment: + command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/expand.sh + expand + --hosts {ADHOC_NODES} + + shrink: + environment: + command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/expand.sh + shrink + --hosts {ADHOC_NODES} + hercules: + # The default working directory for adhoc instances of this type + working_directory: /tmp/hercules + startup: + # Specific environment variables that should be set for the adhoc + # instance. These will be merged with the environment variables + # already set by Slurm. + environment: + VAR0: value0 + VAR1: value1 + # The command that `scord-ctl` will use to start an adhoc instance of + # this type. The following variables are supported that will be + # automatically replaced by scord-ctl if found between curly braces: + # * ADHOC_NODES: A comma separated list of valid job hostnames that + # can be used to start the adhoc instance. + # * ADHOC_DIRECTORY: A unique working directory for each specific + # adhoc instance. This directory will be created by scord-ctl under + # `working_directory` and automatically removed after the adhoc + # instance has been shut down. + # * ADHOC_ID: - A unique ID for the adhoc instance. + command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/hercules.sh + start + --hosts {ADHOC_NODES} + --workdir {ADHOC_DIRECTORY} + --datadir {ADHOC_DIRECTORY}/data + --mountdir {ADHOC_DIRECTORY}/mnt + shutdown: + environment: + command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/hercules.sh + stop + --workdir {ADHOC_DIRECTORY} + expand: + environment: + command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/hercules.sh + expand + --hosts {ADHOC_NODES} + + shrink: + environment: + command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/hercules.sh + shrink + --hosts {ADHOC_NODES} # default storage tiers made available to applications storage: diff --git a/plugins/adhoc_services.d/gekkofs.sh b/plugins/adhoc_services.d/gekkofs.sh index 0fdcf091..6544724e 100644 --- a/plugins/adhoc_services.d/gekkofs.sh +++ b/plugins/adhoc_services.d/gekkofs.sh @@ -1,3 +1,3 @@ #!/usr/bin/env bash - +echo "GEKKOFS Script Called" exit 0 diff --git a/src/scord-ctl/command.cpp b/src/scord-ctl/command.cpp index 65f282fb..c45b5b5c 100644 --- a/src/scord-ctl/command.cpp +++ b/src/scord-ctl/command.cpp @@ -135,6 +135,52 @@ command::eval(const std::string& adhoc_id, return command{result, m_env}; } +command +command::eval(const std::string& adhoc_id, + const std::vector& adhoc_nodes) const { + + // generate a regex from a map of key/value pairs + constexpr auto regex_from_map = + [](const std::map& m) -> std::regex { + std::string result; + for(const auto& [key, value] : m) { + const auto escaped_key = + std::regex_replace(key, std::regex{R"([{}])"}, R"(\$&)"); + result += fmt::format("{}|", escaped_key); + } + result.pop_back(); + return std::regex{result}; + }; + + const std::map replacements{ + {std::string{keywords_malleability.at(0)}, adhoc_id}, + {std::string{keywords_malleability.at(1)}, + fmt::format("\"{}\"", fmt::join(adhoc_nodes, ","))}}; + + // make sure that we fail if we ever add a new keyword and forget to add + // a replacement for it + assert(replacements.size() == keywords_malleability.size()); + + std::string result; + + const auto re = regex_from_map(replacements); + auto it = std::sregex_iterator(m_cmdline.begin(), m_cmdline.end(), re); + auto end = std::sregex_iterator{}; + + std::string::size_type last_pos = 0; + + for(; it != end; ++it) { + const auto& match = *it; + result += m_cmdline.substr(last_pos, match.position() - last_pos); + result += replacements.at(match.str()); + last_pos = match.position() + match.length(); + } + + result += m_cmdline.substr(last_pos, m_cmdline.length() - last_pos); + + return command{result, m_env}; +} + std::vector command::as_vector() const { std::vector tmp; diff --git a/src/scord-ctl/command.hpp b/src/scord-ctl/command.hpp index 73ada0e8..a3551ed7 100644 --- a/src/scord-ctl/command.hpp +++ b/src/scord-ctl/command.hpp @@ -109,6 +109,8 @@ public: static constexpr std::array keywords = { "{ADHOC_ID}", "{ADHOC_DIRECTORY}", "{ADHOC_NODES}"}; + static constexpr std::array keywords_malleability = { + "{ADHOC_ID}", "{ADHOC_NODES}"}; /** * @brief Construct a command. * @@ -152,6 +154,20 @@ public: const std::filesystem::path& adhoc_directory, const std::vector& adhoc_nodes) const; + + /** + * @brief Return a copy of the current `command` where all the keywords in + * its command line template have been replaced with string + * representations of the arguments provided. + * + * @param adhoc_id The ID of the adhoc storage system. + * @param adhoc_nodes The nodes where the adhoc storage will run. + * @return The evaluated command. + */ + command + eval(const std::string& adhoc_id, + const std::vector& adhoc_nodes) const; + /** * @brief Get the command line to be executed as a vector of strings. The * command line is split on spaces with each string in the resulting diff --git a/src/scord-ctl/config_file.cpp b/src/scord-ctl/config_file.cpp index c8855ea5..bb53f653 100644 --- a/src/scord-ctl/config_file.cpp +++ b/src/scord-ctl/config_file.cpp @@ -195,6 +195,9 @@ parse_adhoc_config_node(const ryml::ConstNodeRef& node) { std::filesystem::path working_directory; std::optional startup_command; std::optional shutdown_command; + std::optional expand_command; + std::optional shrink_command; + for(const auto& child : node) { @@ -212,6 +215,10 @@ parse_adhoc_config_node(const ryml::ConstNodeRef& node) { startup_command = ::parse_command_node(child); } else if(child.key() == "shutdown") { shutdown_command = ::parse_command_node(child); + } else if(child.key() == "expand") { + expand_command = ::parse_command_node(child); + } else if(child.key() == "shrink") { + shrink_command = ::parse_command_node(child); } else { fmt::print(stderr, "WARNING: Unknown key: '{}'. Ignored.\n", child.key()); @@ -222,7 +229,8 @@ parse_adhoc_config_node(const ryml::ConstNodeRef& node) { throw std::runtime_error{"missing required `working_directory` key"}; } - return {working_directory, *startup_command, *shutdown_command}; + return {working_directory, *startup_command, *shutdown_command, + *expand_command, *shrink_command}; } /** @@ -302,10 +310,13 @@ namespace scord_ctl::config { adhoc_storage_config::adhoc_storage_config( std::filesystem::path working_directory, command startup_command, - command shutdown_command) + command shutdown_command, command expand_command, + command shrink_command) : m_working_directory(std::move(working_directory)), m_startup_command(std::move(startup_command)), - m_shutdown_command(std::move(shutdown_command)) {} + m_shutdown_command(std::move(shutdown_command)), + m_expand_command(std::move(expand_command)), + m_shrink_command(std::move(shrink_command)) {} const std::filesystem::path& adhoc_storage_config::working_directory() const { @@ -322,6 +333,16 @@ adhoc_storage_config::shutdown_command() const { return m_shutdown_command; } +const command& +adhoc_storage_config::expand_command() const { + return m_expand_command; +} + +const command& +adhoc_storage_config::shrink_command() const { + return m_shrink_command; +} + config_file::config_file(const std::filesystem::path& path) { std::ifstream input{path}; diff --git a/src/scord-ctl/config_file.hpp b/src/scord-ctl/config_file.hpp index 119c6433..ef93bc0c 100644 --- a/src/scord-ctl/config_file.hpp +++ b/src/scord-ctl/config_file.hpp @@ -46,9 +46,14 @@ public: * storage. * @param shutdown_command The command to be executed to stop the adhoc * storage. + * @param expand_command The command to be executed to expand the adhoc + * storage. + * @param shrink_command The command to be executed to shrink the adhoc + * storage. */ adhoc_storage_config(std::filesystem::path working_directory, - command startup_command, command shutdown_command); + command startup_command, command shutdown_command, + command expand_command, command shrink_command); /** * @brief Get the directory where the adhoc storage will run. @@ -74,10 +79,30 @@ public: const command& shutdown_command() const; + + /** + * @brief Get the command to be executed to expand the adhoc storage. + * + * @return The command to be executed to expand the adhoc storage. + */ + const command& + expand_command() const; + + + /** + * @brief Get the command to be executed to shrink the adhoc storage. + * + * @return The command to be executed to shrink the adhoc storage. + */ + const command& + shrink_command() const; + private: std::filesystem::path m_working_directory; command m_startup_command; command m_shutdown_command; + command m_expand_command; + command m_shrink_command; }; #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 11 diff --git a/src/scord-ctl/rpc_server.cpp b/src/scord-ctl/rpc_server.cpp index 177104f5..edff7198 100644 --- a/src/scord-ctl/rpc_server.cpp +++ b/src/scord-ctl/rpc_server.cpp @@ -44,6 +44,8 @@ rpc_server::rpc_server(std::string name, std::string address, bool daemonize, provider::define(EXPAND(ping)); provider::define(EXPAND(deploy_adhoc_storage)); + provider::define(EXPAND(expand_adhoc_storage)); + provider::define(EXPAND(shrink_adhoc_storage)); provider::define(EXPAND(terminate_adhoc_storage)); #undef EXPAND @@ -196,6 +198,128 @@ respond: req.respond(resp); } +void +rpc_server::expand_adhoc_storage( + const network::request& req, const std::string& adhoc_uuid, + enum scord::adhoc_storage::type adhoc_type, + const scord::adhoc_storage::resources& adhoc_resources) { + + using network::generic_response; + using network::get_address; + using network::rpc_info; + + const auto rpc = rpc_info::create(RPC_NAME(), get_address(req)); + std::optional adhoc_dir; + + LOGGER_INFO("rpc {:>} body: {{uuid: {}, type: {}, resources: {}}}", rpc, + std::quoted(adhoc_uuid), adhoc_type, adhoc_resources); + + auto ec = scord::error_code::success; + + if(!m_config.has_value() || m_config->adhoc_storage_configs().empty()) { + LOGGER_WARN("No adhoc storage configurations available"); + ec = scord::error_code::snafu; + goto respond; + } + + if(const auto it = m_config->adhoc_storage_configs().find(adhoc_type); + it != m_config->adhoc_storage_configs().end()) { + const auto& adhoc_cfg = it->second; + + LOGGER_DEBUG("deploy \"{:e}\" (ID: {})", adhoc_type, adhoc_uuid); + + // 1. Construct the expand command for the adhoc storage instance + std::vector hostnames; + std::ranges::transform( + adhoc_resources.nodes(), std::back_inserter(hostnames), + [](const auto& node) { return node.hostname(); }); + + const auto cmd = adhoc_cfg.expand_command().eval(adhoc_uuid, hostnames); + + // 4. Execute the startup command + try { + LOGGER_DEBUG("[{}] exec: {}", adhoc_uuid, cmd); + cmd.exec(); + } catch(const std::exception& ex) { + LOGGER_ERROR("[{}] Failed to execute expand command: {}", + adhoc_uuid, ex.what()); + ec = scord::error_code::subprocess_error; + } + } else { + LOGGER_WARN( + "Failed to find adhoc storage configuration for type '{:e}'", + adhoc_type); + ec = scord::error_code::adhoc_type_unsupported; + } + +respond: + const generic_response resp{rpc.id(), ec}; + LOGGER_INFO("rpc {:<} body: {{retval: {}}}", rpc, resp.error_code()); + req.respond(resp); +} + + +void +rpc_server::shrink_adhoc_storage( + const network::request& req, const std::string& adhoc_uuid, + enum scord::adhoc_storage::type adhoc_type, + const scord::adhoc_storage::resources& adhoc_resources) { + + using network::generic_response; + using network::get_address; + using network::rpc_info; + + const auto rpc = rpc_info::create(RPC_NAME(), get_address(req)); + std::optional adhoc_dir; + + LOGGER_INFO("rpc {:>} body: {{uuid: {}, type: {}, resources: {}}}", rpc, + std::quoted(adhoc_uuid), adhoc_type, adhoc_resources); + + auto ec = scord::error_code::success; + + if(!m_config.has_value() || m_config->adhoc_storage_configs().empty()) { + LOGGER_WARN("No adhoc storage configurations available"); + ec = scord::error_code::snafu; + goto respond; + } + + if(const auto it = m_config->adhoc_storage_configs().find(adhoc_type); + it != m_config->adhoc_storage_configs().end()) { + const auto& adhoc_cfg = it->second; + + LOGGER_DEBUG("deploy \"{:e}\" (ID: {})", adhoc_type, adhoc_uuid); + + // 1. Construct the expand command for the adhoc storage instance + std::vector hostnames; + std::ranges::transform( + adhoc_resources.nodes(), std::back_inserter(hostnames), + [](const auto& node) { return node.hostname(); }); + + const auto cmd = adhoc_cfg.shrink_command().eval(adhoc_uuid, hostnames); + + // 4. Execute the startup command + try { + LOGGER_DEBUG("[{}] exec: {}", adhoc_uuid, cmd); + cmd.exec(); + } catch(const std::exception& ex) { + LOGGER_ERROR("[{}] Failed to execute shrink command: {}", + adhoc_uuid, ex.what()); + ec = scord::error_code::subprocess_error; + } + } else { + LOGGER_WARN( + "Failed to find adhoc storage configuration for type '{:e}'", + adhoc_type); + ec = scord::error_code::adhoc_type_unsupported; + } + +respond: + const generic_response resp{rpc.id(), ec}; + LOGGER_INFO("rpc {:<} body: {{retval: {}}}", rpc, resp.error_code()); + req.respond(resp); +} + + void rpc_server::terminate_adhoc_storage( const network::request& req, const std::string& adhoc_uuid, diff --git a/src/scord-ctl/rpc_server.hpp b/src/scord-ctl/rpc_server.hpp index fa0518b4..f60eed37 100644 --- a/src/scord-ctl/rpc_server.hpp +++ b/src/scord-ctl/rpc_server.hpp @@ -56,6 +56,18 @@ private: enum scord::adhoc_storage::type adhoc_type, const scord::adhoc_storage::resources& adhoc_resources); + void + expand_adhoc_storage( + const network::request& req, const std::string& adhoc_uuid, + enum scord::adhoc_storage::type adhoc_type, + const scord::adhoc_storage::resources& adhoc_resources); + + void + shrink_adhoc_storage( + const network::request& req, const std::string& adhoc_uuid, + enum scord::adhoc_storage::type adhoc_type, + const scord::adhoc_storage::resources& adhoc_resources); + void terminate_adhoc_storage(const network::request& req, const std::string& adhoc_uuid, diff --git a/src/scord/rpc_server.cpp b/src/scord/rpc_server.cpp index 55b692f4..1448ff1f 100644 --- a/src/scord/rpc_server.cpp +++ b/src/scord/rpc_server.cpp @@ -315,6 +315,22 @@ rpc_server::update_adhoc_storage( LOGGER_INFO("rpc {:>} body: {{adhoc_id: {}, new_resources: {}}}", rpc, adhoc_id, new_resources); + + const auto pre_ec = m_adhoc_manager.find(adhoc_id); + + if(!pre_ec) { + LOGGER_ERROR( + "rpc id: {} error_msg: \"Error updating adhoc_storage: {}\"", + rpc.id(), scord::error_code::no_such_entity); + } + + const auto old_resources_size = pre_ec.value() + .get() + ->adhoc_storage() + .get_resources() + .nodes() + .size(); + const auto ec = m_adhoc_manager.update(adhoc_id, new_resources); if(!ec) { @@ -323,9 +339,69 @@ rpc_server::update_adhoc_storage( rpc.id(), ec); } - const auto resp = generic_response{rpc.id(), ec}; + bool expand = new_resources.nodes().size() > old_resources_size; - LOGGER_INFO("rpc {:<} body: {{retval: {}}}", rpc, ec); + /** + * @brief Helper lambda to contact the adhoc controller and prompt it to + * update an adhoc storage instance + * @param adhoc_storage The relevant `adhoc_storage` object with + * information about the instance to deploy. + * @return + */ + const auto update_helper = [&](const auto& adhoc_metadata_ptr) + -> tl::expected { + assert(adhoc_metadata_ptr); + const auto adhoc_storage = adhoc_metadata_ptr->adhoc_storage(); + const auto endp = lookup(adhoc_storage.context().controller_address()); + + if(!endp) { + LOGGER_ERROR("endpoint lookup failed"); + return tl::make_unexpected(scord::error_code::snafu); + } + + // const auto child_rpc = + // rpc.add_child(adhoc_storage.context().controller_address()); + + auto name = "ADM_expand_adhoc_storage"; + if(!expand) { + name = "ADM_shrink_adhoc_storage"; + } + + const auto child_rpc = rpc_info::create( + name, adhoc_storage.context().controller_address()); + + LOGGER_INFO("rpc {:<} body: {{uuid: {}, type: {}, resources: {}}}", + child_rpc, std::quoted(adhoc_metadata_ptr->uuid()), + adhoc_storage.type(), adhoc_storage.get_resources()); + + if(const auto call_rv = endp->call( + child_rpc.name(), adhoc_metadata_ptr->uuid(), + adhoc_storage.type(), adhoc_storage.get_resources()); + call_rv.has_value()) { + + const network::generic_response resp{call_rv.value()}; + + LOGGER_EVAL(resp.error_code(), INFO, ERROR, + "rpc {:>} body: {{retval: {}}} [op_id: {}]", child_rpc, + resp.error_code(), resp.op_id()); + + return resp.error_code(); + } + + LOGGER_ERROR("rpc call failed"); + return tl::make_unexpected(error_code::snafu); + }; + + const auto rv = + m_adhoc_manager.find(adhoc_id) + .or_else([](auto&&) { + LOGGER_ERROR("adhoc storage instance not found"); + }) + .and_then(update_helper); + + const auto resp = generic_response(rpc.id(), rv.value()); + + LOGGER_INFO("rpc {:<} body: {{retval: {}}}", rpc, rv.value()); req.respond(resp); } -- GitLab