root/opal/mca/pmix/pmix4x/pmix/src/mca/gds/gds.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


   1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
   2 /*
   3  * Copyright (c) 2016-2019 Mellanox Technologies, Inc.
   4  *                         All rights reserved.
   5  * Copyright (c) 2016-2018 Intel, Inc.  All rights reserved.
   6  * Copyright (c) 2018      IBM Corporation.  All rights reserved.
   7  * $COPYRIGHT$
   8  *
   9  * Additional copyrights may follow
  10  *
  11  * $HEADER$
  12  */
  13 
  14 #ifndef PMIX_GDS_H
  15 #define PMIX_GDS_H
  16 
  17 #include <src/include/pmix_config.h>
  18 
  19 
  20 #include <pmix_common.h>
  21 #include "src/mca/mca.h"
  22 #include "src/mca/base/pmix_mca_base_var.h"
  23 #include "src/mca/base/pmix_mca_base_framework.h"
  24 #include "src/mca/bfrops/bfrops_types.h"
  25 
  26 
  27 /* The client dictates the GDS module that will be used to interact
  28  * with the server - this module is stored in pmix_globals.mypeer->compat.gds
  29  * Because that is a long address to keep typing out, convenience macros
  30  * are provided for when that module is to be used in an operation.
  31  *
  32  * However, an application can open any number of GDS modules for
  33  * purposes other than exchanging info with the server. For example,
  34  * an application may wish to utilize a DHT module for its own
  35  * peer-to-peer data sharing. Thus, the public and private interfaces
  36  * are deliberately designed to be generic. The macros should make
  37  * things easier for the typical internal operations
  38  *
  39  * NOTE: ALTHOUGH SOME GDS COMPONENTS MAY UTILIZE THEIR OWN INTERNAL
  40  * PROGRESS THREADS, THE GDS IS NOT GUARANTEED TO BE THREAD-SAFE.
  41  * GDS FUNCTIONS SHOULD THEREFORE ALWAYS BE CALLED IN A THREAD-SAFE
  42  * CONDITION - E.G., FROM WITHIN AN EVENT
  43  */
  44 
  45 BEGIN_C_DECLS
  46 /* forward declaration */
  47 struct pmix_peer_t;
  48 struct pmix_namespace_t;
  49 
  50 /* backdoor to base verbosity */
  51 PMIX_EXPORT extern int pmix_gds_base_output;
  52 
  53 /**
  54  * Initialize the module. Returns an error if the module cannot
  55  * run, success if it can.
  56  */
  57 typedef pmix_status_t (*pmix_gds_base_module_init_fn_t)(pmix_info_t info[], size_t ninfo);
  58 
  59 /**
  60  * Finalize the module. Tear down any allocated storage, disconnect
  61  * from any system support.
  62  */
  63 typedef void (*pmix_gds_base_module_fini_fn_t)(void);
  64 
  65 /**
  66  * Assign a module per the requested directives. Modules should
  67  * review the provided directives to determine if they can support
  68  * the request. Modules are "scanned" in component priority order
  69  * and given an opportunity to respond. If a module offers itself,
  70  * it will provide a priority (which can be based on the directives
  71  * and therefore different from the component priority). The highest
  72  * returned priority received from a responder will be selected
  73  * and a pointer to its module returned */
  74 typedef pmix_status_t (*pmix_gds_base_assign_module_fn_t)(pmix_info_t *info,
  75                                                           size_t ninfo,
  76                                                           int *priority);
  77 
  78 /* SERVER FN: assemble the keys buffer for server answer */
  79 typedef pmix_status_t (*pmix_gds_base_module_assemb_kvs_req_fn_t)(const pmix_proc_t *proc,
  80                                                             pmix_list_t *kvs,
  81                                                             pmix_buffer_t *buf,
  82                                                             void *cbdata);
  83 
  84 /* define a macro for server keys answer based on peer */
  85 #define PMIX_GDS_ASSEMB_KVS_REQ(s, p, r, k, b, c)                       \
  86     do {                                                                \
  87         pmix_gds_base_module_t *_g = (p)->nptr->compat.gds;             \
  88         (s) = PMIX_SUCCESS;                                             \
  89         if (NULL != _g->assemb_kvs_req) {                               \
  90             pmix_output_verbose(1, pmix_gds_base_output,                \
  91                                 "[%s:%d] GDS ASSEMBLE REQ WITH %s",     \
  92                                 __FILE__, __LINE__, _g->name);          \
  93             (s) = _g->assemb_kvs_req(r, k, b, (void*)c);                \
  94         }                                                               \
  95     } while(0)
  96 
  97 
  98 /* CLIENT FN: unpack buffer and key processing */
  99 typedef pmix_status_t (*pmix_gds_base_module_accept_kvs_resp_fn_t)(pmix_buffer_t *buf);
 100 
 101 /* define a macro for client key processing from a server response based on peer */
 102 #define PMIX_GDS_ACCEPT_KVS_RESP(s, p, b)                                   \
 103     do {                                                                    \
 104         pmix_gds_base_module_t *_g = (p)->nptr->compat.gds;                 \
 105         (s) = PMIX_SUCCESS;                                                 \
 106         if (NULL != _g->accept_kvs_resp) {                                  \
 107             pmix_output_verbose(1, pmix_gds_base_output,                    \
 108                                 "[%s:%d] GDS ACCEPT RESP WITH %s",          \
 109                                 __FILE__, __LINE__, _g->name);              \
 110             (s) = _g->accept_kvs_resp(b);                                   \
 111         }                                                                   \
 112     } while (0)
 113 
 114 
 115 /* SERVER FN: cache job-level info in the server's GDS until client
 116  * procs connect and we discover which GDS module to use for them.
 117  * Note that this is essentially the same function as store_job_info,
 118  * only we don't have packed data on the server side, and don't want
 119  * to incur the overhead of packing it just to unpack it in the function.
 120  */
 121 typedef pmix_status_t (*pmix_gds_base_module_cache_job_info_fn_t)(struct pmix_namespace_t *ns,
 122                                                                   pmix_info_t info[], size_t ninfo);
 123 
 124 /* define a convenience macro for caching job info */
 125 #define PMIX_GDS_CACHE_JOB_INFO(s, p, n, i, ni)                             \
 126     do {                                                                    \
 127         pmix_gds_base_module_t *_g = (p)->nptr->compat.gds;                 \
 128         pmix_output_verbose(1, pmix_gds_base_output,                        \
 129                             "[%s:%d] GDS CACHE JOB INFO WITH %s",           \
 130                             __FILE__, __LINE__, _g->name);                  \
 131        (s) = _g->cache_job_info((struct pmix_namespace_t*)(n), (i), (ni));     \
 132     } while(0)
 133 
 134 /* register job-level info - this is provided as a special function
 135  * to allow for optimization. Called solely by the server. We cannot
 136  * prepare the job-level info provided at PMIx_Register_nspace, because
 137  * we don't know the GDS component to use for that application until
 138  * a local client contacts us. Thus, the module is required to process
 139  * the job-level info cached in the pmix_namespace_t for this job and
 140  * do whatever is necessary to support the client, packing any required
 141  * return message into the provided buffer.
 142  *
 143  * This function will be called once for each local client of
 144  * a given nspace. PMIx assumes that all peers of a given nspace
 145  * will use the same GDS module. Thus, the module is free to perform
 146  * any relevant optimizations (e.g., packing the data only once and
 147  * then releasing the cached buffer once all local clients have
 148  * been serviced, or storing it once in shared memory and simply
 149  * returning the shared memory rendezvous information for subsequent
 150  * calls).
 151  *
 152  * Info provided in the reply buffer will be given to the "store_job_info"
 153  * API of the GDS module on the client. Since this should match the
 154  * module used by the server, each module has full knowledge and control
 155  * over what is in the reply buffer.
 156  *
 157  * The pmix_peer_t of the requesting client is provided here so that
 158  * the module can access the job-level info cached on the corresponding
 159  * pmix_namespace_t pointed to by the pmix_peer_t
 160  */
 161 typedef pmix_status_t (*pmix_gds_base_module_register_job_info_fn_t)(struct pmix_peer_t *pr,
 162                                                                      pmix_buffer_t *reply);
 163 
 164 /* define a convenience macro for registering job info for
 165  * a given peer */
 166 #define PMIX_GDS_REGISTER_JOB_INFO(s, p, b)                         \
 167     do {                                                            \
 168         pmix_gds_base_module_t *_g = (p)->nptr->compat.gds;         \
 169         pmix_output_verbose(1, pmix_gds_base_output,                \
 170                             "[%s:%d] GDS REG JOB INFO WITH %s",     \
 171                             __FILE__, __LINE__, _g->name);          \
 172         (s) = _g->register_job_info((struct pmix_peer_t*)(p), b);   \
 173     } while(0)
 174 
 175 
 176 /* update job-level info - this is provided as a special function
 177  * to allow for optimization. Called solely by the client. The buffer
 178  * provided to this API is the same one given to the server by the
 179  * corresponding "register_job_info" function
 180  */
 181 typedef pmix_status_t (*pmix_gds_base_module_store_job_info_fn_t)(const char *nspace,
 182                                                                   pmix_buffer_t *buf);
 183 
 184 /* define a convenience macro for storing job info based on peer */
 185 #define PMIX_GDS_STORE_JOB_INFO(s, p, n, b)                         \
 186     do {                                                            \
 187         pmix_gds_base_module_t *_g = (p)->nptr->compat.gds;         \
 188         pmix_output_verbose(1, pmix_gds_base_output,                \
 189                             "[%s:%d] GDS STORE JOB INFO WITH %s",   \
 190                             __FILE__, __LINE__, _g->name);          \
 191         (s) = _g->store_job_info(n, b);                             \
 192     } while(0)
 193 
 194 
 195 /**
 196 * store key/value pair - these will either be values committed by the peer
 197 * and transmitted to the server, or values stored locally by the peer.
 198 * The format of the data depends on the GDS module. Note that data stored
 199 * with PMIX_INTERNAL scope should be stored solely within the process and
 200 * is never shared.
 201 *
 202 * @param peer   pointer to pmix_peer_t object of the peer that
 203 *               provided the data
 204 *
 205 * @param proc   the proc that the data describes
 206 *
 207 * @param scope  scope of the data
 208 *
 209 * @param kv     key/value pair.
 210 *
 211 * @return PMIX_SUCCESS on success.
 212 */
 213 typedef pmix_status_t (*pmix_gds_base_module_store_fn_t)(const pmix_proc_t *proc,
 214                                                          pmix_scope_t scope,
 215                                                          pmix_kval_t *kv);
 216 
 217 /* define a convenience macro for storing key-val pairs based on peer */
 218 #define PMIX_GDS_STORE_KV(s, p, pc, sc, k)                  \
 219     do {                                                    \
 220         pmix_gds_base_module_t *_g = (p)->nptr->compat.gds; \
 221         pmix_output_verbose(1, pmix_gds_base_output,        \
 222                             "[%s:%d] GDS STORE KV WITH %s", \
 223                             __FILE__, __LINE__, _g->name);  \
 224         (s) = _g->store(pc, sc, k);                         \
 225     } while(0)
 226 
 227 
 228 /**
 229  * unpack and store a data "blob" from a peer so that the individual
 230  * elements can later be retrieved. This is an optimization path to
 231  * avoid repeatedly storing pmix_kval_t's for multiple local procs
 232  * from the same nspace.
 233  *
 234  * ranks - a list of pmix_rank_info_t for the local ranks from this
 235  *         nspace - this is to be used to filter the cbs list
 236  *
 237  * cbdata - pointer to modex callback data
 238  *
 239  * bo - pointer to the byte object containing the data
 240  *
 241  */
 242 typedef pmix_status_t (*pmix_gds_base_module_store_modex_fn_t)(struct pmix_namespace_t *ns,
 243                                                                pmix_buffer_t *buff,
 244                                                                void *cbdata);
 245 
 246 /**
 247  * define a convenience macro for storing modex byte objects
 248  *
 249  * r - return status code
 250  *
 251  * n - pointer to the pmix_namespace_t this blob is to be stored for
 252  *
 253  * b - pointer to pmix_byte_object_t containing the data
 254  *
 255  * t - pointer to the modex server tracker
 256  */
 257 #define PMIX_GDS_STORE_MODEX(r, n, b, t)  \
 258     do {                                                                    \
 259         pmix_output_verbose(1, pmix_gds_base_output,                        \
 260                             "[%s:%d] GDS STORE MODEX WITH %s",              \
 261                             __FILE__, __LINE__, (n)->compat.gds->name);     \
 262         (r) = (n)->compat.gds->store_modex((struct pmix_namespace_t*)n, b, t); \
 263     } while (0)
 264 
 265 /**
 266 * fetch value corresponding to provided key from within the defined
 267 * scope. A NULL key returns all values committed by the given peer
 268 * for that scope.
 269 *
 270 * @param proc    namespace and rank whose info is being requested
 271 *
 272 * @param key     key.
 273 *
 274 * @param scope   scope of the data to be considered
 275 *
 276 * @param copy    true if the caller _requires_ a copy of the data. This
 277 *                is used when the requestor is off-node. If
 278 *                set to false, then the GDS component can provide
 279 *                either a copy of the data, or shmem contact info
 280 *                to the location of the data
 281 *
 282 * @param info    array of pmix_info_t the caller provided as
 283 *                qualifiers to guide the request
 284 *
 285 * @param ninfo   number of elements in the info array
 286 *
 287 * @param kvs     pointer to a list that will be populated with the
 288 *                returned pmix_kval_t data
 289 *
 290 * @return       PMIX_SUCCESS on success.
 291 *
 292 * Note: all available job-level data for a given nspace can be fetched
 293 * by passing a proc with rank=PMIX_RANK_WILDCARD and a NULL key. Similarly,
 294 * passing a NULL key for a non-wildcard rank will return all data "put"
 295 * by that rank. Scope is ignored for job-level data requests.
 296 *
 297 * When a specific rank if provided with a NULL key, then data for only
 298 * that rank is returned. If the scope is PMIX_LOCAL, then the returned
 299 * data shall include only data that was specifically "put" to local scope,
 300 * plus any data that was put to PMIX_GLOBAL scope. Similarly, a scope of
 301 * PMIX_REMOTE will return data that was "put" to remote scope, plus
 302 * any data that was put to PMIX_GLOBAL scope. A scope of PMIX_GLOBAL
 303 * will return LOCAL, REMOTE, and GLOBAL data.
 304 *
 305 * Data stored with PMIX_INTERNAL scope can be retrieved with that scope.
 306 */
 307 typedef pmix_status_t (*pmix_gds_base_module_fetch_fn_t)(const pmix_proc_t *proc,
 308                                                          pmix_scope_t scope, bool copy,
 309                                                          const char *key,
 310                                                          pmix_info_t info[], size_t ninfo,
 311                                                          pmix_list_t *kvs);
 312 
 313 /* define a convenience macro for fetch key-val pairs based on peer,
 314  * passing a pmix_cb_t containing all the required info */
 315 #define PMIX_GDS_FETCH_KV(s, p, c)      \
 316     do {                                                    \
 317         pmix_gds_base_module_t *_g = (p)->nptr->compat.gds; \
 318         pmix_output_verbose(1, pmix_gds_base_output,        \
 319                             "[%s:%d] GDS FETCH KV WITH %s", \
 320                             __FILE__, __LINE__, _g->name);  \
 321         (s) = _g->fetch((c)->proc, (c)->scope, (c)->copy,   \
 322                         (c)->key, (c)->info, (c)->ninfo,    \
 323                         &(c)->kvs);                         \
 324     } while(0)
 325 
 326 
 327 /**
 328 * Add any envars to a peer's environment that the module needs
 329 * to communicate. The API stub will rotate across all active modules, giving
 330 * each a chance to contribute
 331 *
 332 * @return PMIX_SUCCESS on success.
 333 */
 334 typedef pmix_status_t (*pmix_gds_base_module_setup_fork_fn_t)(const pmix_proc_t *proc,
 335                                                               char ***env);
 336 
 337 /**
 338 * Define a new nspace in the GDS
 339 *
 340 * @param nspace   namespace string
 341 *
 342 * @return PMIX_SUCCESS on success.
 343 */
 344 typedef pmix_status_t (*pmix_gds_base_module_add_nspace_fn_t)(const char *nspace,
 345                                                               pmix_info_t info[],
 346                                                               size_t ninfo);
 347 
 348 /* define a convenience macro for add_nspace based on peer */
 349 #define PMIX_GDS_ADD_NSPACE(s, n, i, ni)                    \
 350     do {                                                    \
 351         pmix_gds_base_active_module_t *_g;                  \
 352         pmix_status_t _s = PMIX_SUCCESS;                    \
 353         (s) = PMIX_SUCCESS;                                 \
 354         pmix_output_verbose(1, pmix_gds_base_output,        \
 355                             "[%s:%d] GDS ADD NSPACE %s",    \
 356                             __FILE__, __LINE__, (n));       \
 357         PMIX_LIST_FOREACH(_g, &pmix_gds_globals.actives,    \
 358                           pmix_gds_base_active_module_t) {  \
 359             if (NULL != _g->module->add_nspace) {           \
 360                 _s = _g->module->add_nspace(n, i, ni);      \
 361             }                                               \
 362             if (PMIX_SUCCESS != _s) {                       \
 363                 (s) = PMIX_ERROR;                           \
 364             }                                               \
 365         }                                                   \
 366     } while(0)
 367 
 368 
 369 /**
 370 * Delete nspace and its associated data
 371 *
 372 * @param nspace   namespace string
 373 *
 374 * @return PMIX_SUCCESS on success.
 375 */
 376 typedef pmix_status_t (*pmix_gds_base_module_del_nspace_fn_t)(const char* nspace);
 377 
 378 /* define a convenience macro for del_nspace based on peer */
 379 #define PMIX_GDS_DEL_NSPACE(s, n)                           \
 380     do {                                                    \
 381         pmix_gds_base_active_module_t *_g;                  \
 382         pmix_status_t _s = PMIX_SUCCESS;                    \
 383         (s) = PMIX_SUCCESS;                                 \
 384         pmix_output_verbose(1, pmix_gds_base_output,        \
 385                             "[%s:%d] GDS DEL NSPACE %s",    \
 386                             __FILE__, __LINE__, (n));       \
 387         PMIX_LIST_FOREACH(_g, &pmix_gds_globals.actives,    \
 388                           pmix_gds_base_active_module_t) {  \
 389             if (NULL != _g->module->del_nspace) {           \
 390                 _s = _g->module->del_nspace(n);             \
 391             }                                               \
 392             if (PMIX_SUCCESS != _s) {                       \
 393                 (s) = PMIX_ERROR;                           \
 394             }                                               \
 395         }                                                   \
 396     } while(0)
 397 
 398 /* define a convenience macro for is_tsafe for fetch operation */
 399 #define PMIX_GDS_FETCH_IS_TSAFE(s, p)                       \
 400     do {                                                    \
 401         pmix_gds_base_module_t *_g = (p)->nptr->compat.gds; \
 402         pmix_output_verbose(1, pmix_gds_base_output,        \
 403                 "[%s:%d] GDS FETCH IS THREAD SAFE WITH %s", \
 404                             __FILE__, __LINE__, _g->name);  \
 405         if (true == _g->is_tsafe) {                         \
 406             (s) = PMIX_SUCCESS;                             \
 407         } else {                                            \
 408             (s) = PMIX_ERR_NOT_SUPPORTED;                   \
 409         }                                                   \
 410 } while(0)
 411 
 412 /**
 413 * structure for gds modules
 414 */
 415 typedef struct {
 416     const char *name;
 417     const bool is_tsafe;
 418     pmix_gds_base_module_init_fn_t                  init;
 419     pmix_gds_base_module_fini_fn_t                  finalize;
 420     pmix_gds_base_assign_module_fn_t                assign_module;
 421     pmix_gds_base_module_cache_job_info_fn_t        cache_job_info;
 422     pmix_gds_base_module_register_job_info_fn_t     register_job_info;
 423     pmix_gds_base_module_store_job_info_fn_t        store_job_info;
 424     pmix_gds_base_module_store_fn_t                 store;
 425     pmix_gds_base_module_store_modex_fn_t           store_modex;
 426     pmix_gds_base_module_fetch_fn_t                 fetch;
 427     pmix_gds_base_module_setup_fork_fn_t            setup_fork;
 428     pmix_gds_base_module_add_nspace_fn_t            add_nspace;
 429     pmix_gds_base_module_del_nspace_fn_t            del_nspace;
 430     pmix_gds_base_module_assemb_kvs_req_fn_t        assemb_kvs_req;
 431     pmix_gds_base_module_accept_kvs_resp_fn_t       accept_kvs_resp;
 432 
 433 } pmix_gds_base_module_t;
 434 
 435 /* NOTE: there is no public GDS interface structure - all access is
 436  * done directly to/from an assigned module */
 437 
 438 /* define the component structure */
 439 struct pmix_gds_base_component_t {
 440     pmix_mca_base_component_t                       base;
 441     pmix_mca_base_component_data_t                  data;
 442     int                                             priority;
 443 };
 444 typedef struct pmix_gds_base_component_t pmix_gds_base_component_t;
 445 
 446 
 447 /*
 448  * Macro for use in components that are of type gds
 449  */
 450 #define PMIX_GDS_BASE_VERSION_1_0_0 \
 451     PMIX_MCA_BASE_VERSION_1_0_0("gds", 1, 0, 0)
 452 
 453 END_C_DECLS
 454 
 455 #endif

/* [<][>][^][v][top][bottom][index][help] */