#include "src/include/pmix_config.h"
#include "src/include/pmix_stdint.h"
#include "include/pmix.h"
#include "src/include/pmix_globals.h"
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#include <fcntl.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
#ifdef HAVE_SYS_UN_H
# include <sys/un.h>
#endif
#ifdef HAVE_SYS_UIO_H
# include <sys/uio.h>
#endif
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#include <event.h>
#include "src/class/pmix_list.h"
#include "src/mca/bfrops/bfrops.h"
#include "src/mca/gds/gds.h"
#include "src/mca/pcompress/base/base.h"
#include "src/mca/ptl/base/base.h"
#include "src/threads/pmix_threads.h"
#include "src/util/pmix_argv.h"
#include "src/util/pmix_error.h"
#include "src/util/pmix_name_fns.h"
#include "src/util/pmix_output.h"
#include "pmix_client_ops.h"
static pmix_buffer_t *_pack_get(pmix_cb_t *cb,
pmix_rank_t rank,
pmix_cmd_t cmd);
static void get_data(int sd, short args, void *cbdata);
static void _getnb_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr,
pmix_buffer_t *buf, void *cbdata);
static void _value_cbfunc(pmix_status_t status, pmix_value_t *kv, void *cbdata);
static pmix_status_t process_values(pmix_cb_t *cb);
static pmix_status_t refresh_cache(const pmix_proc_t *proc);
static pmix_status_t process_request(const pmix_proc_t *proc, const char key[],
const pmix_info_t info[], size_t ninfo,
pmix_get_logic_t *lg, pmix_value_t **val)
{
pmix_status_t rc;
pmix_value_t *ival;
size_t n, nprocs;
pmix_proc_t *procs;
if (NULL == proc && NULL == key) {
pmix_output_verbose(2, pmix_client_globals.get_output,
"pmix: get_nb value error - both proc and key are NULL");
return PMIX_ERR_BAD_PARAM;
}
if (NULL != proc && PMIX_RANK_WILDCARD == proc->rank && NULL == key) {
pmix_output_verbose(2, pmix_client_globals.get_output,
"pmix: get_nb value error - WILDCARD rank and key is NULL");
return PMIX_ERR_BAD_PARAM;
}
if (NULL != key) {
if (pmix_check_node_info(key)) {
lg->nodeinfo = true;
} else if (pmix_check_app_info(key)) {
lg->appinfo = true;
} else if (pmix_check_session_info(key)) {
lg->sessioninfo = true;
}
}
for (n = 0; n < ninfo; n++) {
if (PMIX_CHECK_KEY(&info[n], PMIX_GET_POINTER_VALUES)) {
if (NULL == val) {
return PMIX_ERR_BAD_PARAM;
}
lg->pntrval = PMIX_INFO_TRUE(&info[n]);
} else if (PMIX_CHECK_KEY(&info[n], PMIX_GET_STATIC_VALUES)) {
if (NULL == val || NULL == *val) {
return PMIX_ERR_BAD_PARAM;
}
lg->stval = PMIX_INFO_TRUE(&info[n]);
} else if (PMIX_CHECK_KEY(&info[n], PMIX_OPTIONAL)) {
lg->optional = PMIX_INFO_TRUE(&info[n]);
} else if (PMIX_CHECK_KEY(&info[n], PMIX_IMMEDIATE)) {
lg->immediate = PMIX_INFO_TRUE(&info[n]);
} else if (PMIX_CHECK_KEY(&info[n], PMIX_DATA_SCOPE)) {
lg->scope = info[n].value.data.scope;
} else if (PMIX_CHECK_KEY(&info[n], PMIX_GET_REFRESH_CACHE)) {
lg->refresh_cache = PMIX_INFO_TRUE(&info[n]);
} else if (PMIX_CHECK_KEY(&info[n], PMIX_JOB_INFO)) {
lg->nodeinfo = false;
lg->appinfo = false;
lg->sessioninfo = false;
} else if (PMIX_CHECK_KEY(&info[n], PMIX_NODE_INFO)) {
lg->nodedirective = true;
lg->nodeinfo = true;
lg->appinfo = false;
lg->sessioninfo = false;
} else if (PMIX_CHECK_KEY(&info[n], PMIX_APP_INFO)) {
lg->appdirective = true;
lg->appinfo = true;
lg->nodeinfo = false;
lg->sessioninfo = false;
} else if (PMIX_CHECK_KEY(info, PMIX_SESSION_INFO)) {
lg->sessiondirective = true;
lg->sessioninfo = true;
lg->nodeinfo = false;
lg->appinfo = false;
} else if (PMIX_CHECK_KEY(&info[n], PMIX_HOSTNAME)) {
lg->hostname = info[n].value.data.string;
} else if (PMIX_CHECK_KEY(&info[n], PMIX_NODEID)) {
PMIX_VALUE_GET_NUMBER(rc, &info[n].value, lg->nodeid, uint32_t);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
return rc;
}
} else if (PMIX_CHECK_KEY(&info[n], PMIX_APPNUM)) {
PMIX_VALUE_GET_NUMBER(rc, &info[n].value, lg->appnum, uint32_t);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
return rc;
}
} else if (PMIX_CHECK_KEY(&info[n], PMIX_SESSION_ID)) {
PMIX_VALUE_GET_NUMBER(rc, &info[n].value, lg->sessionid, uint32_t);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
return rc;
}
}
}
if (NULL == proc && PMIx_Check_key(key, PMIX_PROCID)) {
if (lg->stval) {
ival = *val;
ival->type = PMIX_PROC;
ival->data.proc = (pmix_proc_t *) malloc(sizeof(pmix_proc_t));
PMIX_LOAD_PROCID(ival->data.proc, pmix_globals.myid.nspace, pmix_globals.myid.rank);
} else if (lg->pntrval) {
(*val) = &pmix_globals.myidval;
} else {
PMIX_VALUE_CREATE(ival, 1);
if (NULL == ival) {
return PMIX_ERR_NOMEM;
}
ival->type = PMIX_PROC;
ival->data.proc = (pmix_proc_t *) malloc(sizeof(pmix_proc_t));
PMIX_LOAD_PROCID(ival->data.proc, pmix_globals.myid.nspace, pmix_globals.myid.rank);
*val = ival;
}
return PMIX_OPERATION_SUCCEEDED;
}
if (NULL != key && PMIx_Check_key(key, PMIX_VERSION_NUMERIC)) {
if (lg->stval) {
ival = *val;
ival->type = PMIX_UINT32;
ival->data.uint32 = PMIX_NUMERIC_VERSION;
} else {
PMIX_VALUE_CREATE(ival, 1);
if (NULL == ival) {
return PMIX_ERR_NOMEM;
}
ival->type = PMIX_UINT32;
ival->data.uint32 = PMIX_NUMERIC_VERSION;
*val = ival;
}
return PMIX_OPERATION_SUCCEEDED;
}
if (NULL == proc || 0 == strlen(proc->nspace)) {
PMIX_LOAD_NSPACE(lg->p.nspace, pmix_globals.myid.nspace);
} else {
PMIX_LOAD_NSPACE(lg->p.nspace, proc->nspace);
}
if (NULL == proc) {
if (lg->nodeinfo || lg->appinfo) {
lg->p.rank = pmix_globals.myid.rank;
} else {
lg->p.rank = PMIX_RANK_UNDEF;
}
} else {
lg->p.rank = proc->rank;
}
if (PMIX_RANK_INVALID == lg->p.rank &&
PMIX_CHECK_NSPACE(lg->p.nspace, pmix_globals.myid.nspace) &&
NULL != key && PMIx_Check_key(key, PMIX_RANK)) {
if (lg->stval) {
ival = *val;
ival->type = PMIX_PROC_RANK;
ival->data.rank = pmix_globals.myid.rank;
} else if (lg->pntrval) {
(*val) = &pmix_globals.myrankval;
} else {
PMIX_VALUE_CREATE(ival, 1);
if (NULL == ival) {
return PMIX_ERR_NOMEM;
}
ival->type = PMIX_PROC_RANK;
ival->data.rank = pmix_globals.myid.rank;
*val = ival;
}
return PMIX_OPERATION_SUCCEEDED;
}
if (!PMIX_PEER_IS_SERVER(pmix_globals.mypeer) &&
proc != NULL && 0 != strlen(proc->nspace)) {
rc = pmix_client_convert_group_procs(proc, 1, &procs, &nprocs);
if (PMIX_SUCCESS != rc) {
return rc;
}
if (1 < nprocs) {
PMIX_PROC_FREE(procs, nprocs);
return PMIX_ERR_BAD_PARAM;
}
memcpy(&lg->p, &procs[0], sizeof(pmix_proc_t));
PMIX_PROC_FREE(procs, nprocs);
}
return PMIX_SUCCESS;
}
PMIX_EXPORT pmix_status_t PMIx_Get(const pmix_proc_t *proc, const char key[],
const pmix_info_t info[], size_t ninfo, pmix_value_t **val)
{
pmix_cb_t *cb;
pmix_get_logic_t *lg;
pmix_status_t rc;
PMIX_ACQUIRE_THREAD(&pmix_global_lock);
if (pmix_globals.init_cntr <= 0) {
PMIX_RELEASE_THREAD(&pmix_global_lock);
return PMIX_ERR_INIT;
}
PMIX_RELEASE_THREAD(&pmix_global_lock);
pmix_output_verbose(2, pmix_client_globals.get_output, "pmix:client get for %s key %s",
(NULL == proc) ? "NULL" : PMIX_NAME_PRINT(proc),
(NULL == key) ? "NULL" : key);
if (NULL != key && PMIX_MAX_KEYLEN < pmix_keylen(key)) {
return PMIX_ERR_BAD_PARAM;
}
lg = PMIX_NEW(pmix_get_logic_t);
rc = process_request(proc, key, info, ninfo, lg, val);
if (PMIX_OPERATION_SUCCEEDED == rc) {
PMIX_RELEASE(lg);
return PMIX_SUCCESS;
} else if (PMIX_SUCCESS != rc) {
*val = NULL;
PMIX_RELEASE(lg);
return rc;
}
if (lg->refresh_cache) {
rc = refresh_cache(proc);
if (PMIX_SUCCESS != rc) {
PMIX_RELEASE(lg);
return rc;
}
}
cb = PMIX_NEW(pmix_cb_t);
cb->lg = lg;
cb->key = (char*)key;
cb->info = (pmix_info_t*)info;
cb->ninfo = ninfo;
cb->cbfunc.valuefn = _value_cbfunc;
cb->cbdata = cb;
PMIX_THREADSHIFT(cb, get_data);
PMIX_WAIT_THREAD(&cb->lock);
rc = cb->status;
if (PMIX_OPERATION_SUCCEEDED == rc) {
rc = PMIX_SUCCESS;
}
if (PMIX_SUCCESS == rc && NULL != cb->value) {
*val = cb->value;
cb->value = NULL;
} else {
*val = NULL;
}
PMIX_RELEASE(lg);
PMIX_RELEASE(cb);
pmix_output_verbose(2, pmix_client_globals.get_output,
"pmix:client get completed with status %s", PMIx_Error_string(rc));
return rc;
}
static void gcbfn(int sd, short args, void *cbdata)
{
pmix_cb_t *cb = (pmix_cb_t *) cbdata;
PMIX_HIDE_UNUSED_PARAMS(sd, args);
cb->cbfunc.valuefn(cb->status, cb->value, cb->cbdata);
PMIX_RELEASE(cb->lg);
PMIX_RELEASE(cb);
}
PMIX_EXPORT pmix_status_t PMIx_Get_nb(const pmix_proc_t *proc, const char key[],
const pmix_info_t info[], size_t ninfo,
pmix_value_cbfunc_t cbfunc, void *cbdata)
{
pmix_cb_t *cb;
pmix_status_t rc;
pmix_get_logic_t *lg;
pmix_value_t *val;
PMIX_ACQUIRE_THREAD(&pmix_global_lock);
if (pmix_globals.init_cntr <= 0) {
PMIX_RELEASE_THREAD(&pmix_global_lock);
return PMIX_ERR_INIT;
}
PMIX_RELEASE_THREAD(&pmix_global_lock);
if (NULL == cbfunc) {
return PMIX_ERR_BAD_PARAM;
}
if (NULL != key && PMIX_MAX_KEYLEN < pmix_keylen(key)) {
return PMIX_ERR_BAD_PARAM;
}
lg = PMIX_NEW(pmix_get_logic_t);
rc = process_request(proc, key, info, ninfo, lg, &val);
if (PMIX_OPERATION_SUCCEEDED == rc) {
cb = PMIX_NEW(pmix_cb_t);
cb->status = PMIX_SUCCESS;
cb->value = val;
cb->cbfunc.valuefn = cbfunc;
cb->cbdata = cbdata;
PMIX_THREADSHIFT(cb, gcbfn);
return PMIX_SUCCESS;
} else if (PMIX_SUCCESS != rc) {
PMIX_RELEASE(lg);
return rc;
}
if (lg->refresh_cache) {
rc = refresh_cache(proc);
if (PMIX_SUCCESS != rc) {
PMIX_RELEASE(lg);
return rc;
}
}
cb = PMIX_NEW(pmix_cb_t);
cb->lg = lg;
cb->key = (char*)key;
cb->info = (pmix_info_t*)info;
cb->ninfo = ninfo;
cb->scope = lg->scope;
cb->cbfunc.valuefn = cbfunc;
cb->cbdata = cbdata;
cb->checked = true;
PMIX_THREADSHIFT(cb, get_data);
pmix_output_verbose(2, pmix_client_globals.get_output,
"pmix:client get_nb in progress");
return rc;
}
static void _value_cbfunc(pmix_status_t status, pmix_value_t *kv, void *cbdata)
{
pmix_cb_t *cb;
pmix_status_t rc;
PMIX_ACQUIRE_OBJECT(cb);
cb = (pmix_cb_t *) cbdata;
cb->status = status;
if (PMIX_SUCCESS == status) {
PMIX_BFROPS_COPY(rc, pmix_client_globals.myserver, (void **)&cb->value, kv, PMIX_VALUE);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
}
}
PMIX_POST_OBJECT(cb);
PMIX_WAKEUP_THREAD(&cb->lock);
}
static pmix_buffer_t *_pack_get(pmix_cb_t *cb,
pmix_rank_t rank,
pmix_cmd_t cmd)
{
pmix_buffer_t *msg;
pmix_status_t rc;
pmix_info_t *immediate;
size_t n, nimm;
char *nspace = cb->proc->nspace;
msg = PMIX_NEW(pmix_buffer_t);
PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
PMIX_RELEASE(msg);
return NULL;
}
PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &nspace, 1, PMIX_STRING);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
PMIX_RELEASE(msg);
return NULL;
}
PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &rank, 1, PMIX_PROC_RANK);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
PMIX_RELEASE(msg);
return NULL;
}
if (cb->lg->add_immediate) {
nimm = cb->ninfo + 1;
PMIX_INFO_CREATE(immediate, nimm);
for (n=0; n < cb->ninfo; n++) {
PMIX_INFO_XFER(&immediate[n], &cb->info[n]);
}
PMIX_INFO_LOAD(&immediate[n], PMIX_IMMEDIATE, NULL, PMIX_BOOL);
cb->info = immediate;
cb->ninfo = nimm;
cb->infocopy = true;
}
PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cb->ninfo, 1, PMIX_SIZE);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
PMIX_RELEASE(msg);
return NULL;
}
if (0 < cb->ninfo) {
PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, cb->info, cb->ninfo, PMIX_INFO);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
PMIX_RELEASE(msg);
return NULL;
}
}
if (NULL != cb->key) {
PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cb->key, 1, PMIX_STRING);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
PMIX_RELEASE(msg);
return NULL;
}
}
return msg;
}
static void _getnb_cbfunc(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr,
pmix_buffer_t *buf, void *cbdata)
{
pmix_cb_t *cb = (pmix_cb_t *) cbdata;
pmix_cb_t *cb2;
pmix_status_t rc, ret = PMIX_ERR_NOT_FOUND;
pmix_value_t *val = NULL;
int32_t cnt;
pmix_kval_t *kv;
pmix_get_logic_t *lg;
PMIX_ACQUIRE_OBJECT(cb);
PMIX_HIDE_UNUSED_PARAMS(pr, hdr);
pmix_output_verbose(2, pmix_client_globals.get_output,
"pmix: get_nb callback recvd");
if (NULL == cb || NULL == cb->lg) {
PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM);
return;
}
lg = cb->lg;
if (PMIX_BUFFER_IS_EMPTY(buf)) {
pmix_output_verbose(2, pmix_client_globals.get_output,
"pmix: get_nb server lost connection");
goto done;
}
cnt = 1;
PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &ret, &cnt, PMIX_STATUS);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
pmix_list_remove_item(&pmix_client_globals.pending_requests, &cb->super);
PMIX_RELEASE(cb);
return;
}
if (PMIX_SUCCESS != ret) {
pmix_output_verbose(2, pmix_client_globals.get_output,
"pmix: get_nb server returned %s",
PMIx_Error_string(ret));
goto done;
}
PMIX_GDS_ACCEPT_KVS_RESP(rc, pmix_globals.mypeer, buf);
done:
pmix_output_verbose(2, pmix_client_globals.get_output,
"pmix: get_nb looking for requested key");
PMIX_LIST_FOREACH_SAFE (cb, cb2, &pmix_client_globals.pending_requests, pmix_cb_t) {
if (PMIX_CHECK_NSPACE(lg->p.nspace, cb->pname.nspace) && cb->pname.rank == lg->p.rank) {
pmix_list_remove_item(&pmix_client_globals.pending_requests, &cb->super);
if (PMIX_SUCCESS != ret) {
if (cb->checked) {
cb->status = ret;
gcbfn(0, 0, cb);
} else {
cb->cbfunc.valuefn(ret, NULL, cb->cbdata);
}
continue;
}
cb->proc = &lg->p;
cb->scope = PMIX_SCOPE_UNDEF;
pmix_output_verbose(2, pmix_client_globals.get_output,
"pmix: get_nb searching for key %s for rank %s", cb->key,
PMIX_RANK_PRINT(cb->proc->rank));
PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, cb);
if (PMIX_OPERATION_SUCCEEDED == rc) {
rc = PMIX_SUCCESS;
} else if (PMIX_SUCCESS != rc && PMIX_RANK_UNDEF == cb->proc->rank) {
pmix_rank_t saverank;
saverank = cb->proc->rank;
cb->proc->rank = PMIX_RANK_WILDCARD;
PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, cb);
if (PMIX_OPERATION_SUCCEEDED == rc) {
rc = PMIX_SUCCESS;
}
cb->proc->rank = saverank;
}
if (PMIX_SUCCESS != rc) {
if (!PMIX_GDS_CHECK_COMPONENT(pmix_client_globals.myserver, "hash")) {
pmix_output_verbose(2, pmix_client_globals.get_output,
"pmix: get_nb searching for key %s for proc %s, - %s",
cb->key, PMIX_NAME_PRINT(cb->proc), pmix_client_globals.myserver->nptr->compat.gds->name);
PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, cb);
if (PMIX_OPERATION_SUCCEEDED == rc) {
rc = PMIX_SUCCESS;
} else if (PMIX_SUCCESS != rc && PMIX_RANK_UNDEF == cb->proc->rank) {
pmix_rank_t saverank;
saverank = cb->proc->rank;
cb->proc->rank = PMIX_RANK_WILDCARD;
PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, cb);
if (PMIX_OPERATION_SUCCEEDED == rc) {
rc = PMIX_SUCCESS;
}
cb->proc->rank = saverank;
}
}
}
if (PMIX_SUCCESS == rc) {
if (1 != pmix_list_get_size(&cb->kvs)) {
rc = PMIX_ERR_INVALID_VAL;
val = NULL;
} else {
kv = (pmix_kval_t *) pmix_list_remove_first(&cb->kvs);
val = kv->value;
kv->value = NULL; PMIX_RELEASE(kv);
}
}
if (cb->checked) {
cb->status = rc;
cb->value = val;
gcbfn(0, 0, cb);
} else {
cb->cbfunc.valuefn(rc, val, cb->cbdata);
}
}
}
}
static pmix_status_t process_values(pmix_cb_t *cb)
{
pmix_list_t *kvs = &cb->kvs;
pmix_kval_t *kv;
pmix_value_t *val;
pmix_info_t *info;
size_t ninfo, n;
if (NULL != cb->key && 1 == pmix_list_get_size(kvs)) {
kv = (pmix_kval_t *) pmix_list_get_first(kvs);
cb->value = kv->value;
kv->value = NULL; return PMIX_SUCCESS;
}
PMIX_VALUE_CREATE(val, 1);
if (NULL == val) {
return PMIX_ERR_NOMEM;
}
val->type = PMIX_DATA_ARRAY;
val->data.darray = (pmix_data_array_t *) malloc(sizeof(pmix_data_array_t));
if (NULL == val->data.darray) {
PMIX_VALUE_RELEASE(val);
return PMIX_ERR_NOMEM;
}
val->data.darray->type = PMIX_INFO;
val->data.darray->size = 0;
val->data.darray->array = NULL;
ninfo = pmix_list_get_size(kvs);
PMIX_INFO_CREATE(info, ninfo);
if (NULL == info) {
PMIX_VALUE_RELEASE(val);
return PMIX_ERR_NOMEM;
}
n = 0;
PMIX_LIST_FOREACH (kv, kvs, pmix_kval_t) {
pmix_strncpy(info[n].key, kv->key, PMIX_MAX_KEYLEN);
PMIx_Value_xfer(&info[n].value, kv->value);
++n;
}
val->data.darray->size = ninfo;
val->data.darray->array = info;
cb->value = val;
return PMIX_SUCCESS;
}
static void get_data(int sd, short args, void *cbdata)
{
pmix_cb_t *cb, cb2;
pmix_cb_t *cbret;
pmix_buffer_t *msg;
pmix_status_t rc;
pmix_proc_t proc;
pmix_get_logic_t *lg;
pmix_info_t optional, *iptr;
size_t nfo, n;
pmix_kval_t *kv;
PMIX_HIDE_UNUSED_PARAMS(sd, args);
PMIX_ACQUIRE_OBJECT(cb);
cb = (pmix_cb_t*)cbdata;
lg = cb->lg;
iptr = cb->info;
nfo = cb->ninfo;
pmix_output_verbose(2, pmix_client_globals.get_output,
"pmix:client:get_data value for proc %s key %s",
PMIX_NAME_PRINT(&lg->p), (NULL == cb->key) ? "NULL" : cb->key);
cb->proc = &lg->p;
cb->scope = lg->scope;
PMIX_INFO_LOAD(&optional, PMIX_OPTIONAL, NULL, PMIX_BOOL);
if (lg->nodeinfo) {
pmix_output_verbose(2, pmix_client_globals.get_output,
"pmix:client:get_data value requesting node-level info for proc %s key %s",
PMIX_NAME_PRINT(&lg->p), (NULL == cb->key) ? "NULL" : cb->key);
if (NULL == lg->hostname && UINT32_MAX == lg->nodeid) {
if (PMIX_RANK_IS_VALID(cb->proc->rank)) {
if (PMIX_CHECK_PROCID(cb->proc, &pmix_globals.myid)) {
if (NULL != pmix_globals.hostname) {
lg->hostname = strdup(pmix_globals.hostname);
}
if (UINT32_MAX != pmix_globals.nodeid) {
lg->nodeid = pmix_globals.nodeid;
}
}
if (NULL == lg->hostname) {
PMIX_CONSTRUCT(&cb2, pmix_cb_t);
cb2.proc = cb->proc;
cb2.key = PMIX_HOSTNAME;
cb2.info = &optional;
cb2.ninfo = 1;
if (PMIX_PEER_IS_CLIENT(pmix_globals.mypeer)) {
PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, &cb2);
} else {
PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb2);
}
if (PMIX_SUCCESS == rc || PMIX_OPERATION_SUCCEEDED == rc) {
kv = (pmix_kval_t*)pmix_list_remove_first(&cb2.kvs);
PMIX_DESTRUCT(&cb2);
if (NULL != kv) { lg->hostname = strdup(kv->value->data.string);
PMIX_RELEASE(kv);
} else {
lg->hostname = strdup("unknown");
}
}
}
if (UINT32_MAX == lg->nodeid) {
PMIX_CONSTRUCT(&cb2, pmix_cb_t);
cb2.proc = cb->proc;
cb2.key = PMIX_NODEID;
cb2.info = &optional;
cb2.ninfo = 1;
if (PMIX_PEER_IS_CLIENT(pmix_globals.mypeer)) {
PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, &cb2);
} else {
PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb2);
}
if (PMIX_SUCCESS == rc || PMIX_OPERATION_SUCCEEDED == rc) {
kv = (pmix_kval_t*)pmix_list_remove_first(&cb2.kvs);
PMIX_DESTRUCT(&cb2);
if (NULL != kv) { PMIX_VALUE_GET_NUMBER(rc, kv->value, lg->nodeid, uint32_t);
PMIX_RELEASE(kv);
} else {
rc = PMIX_ERROR;
}
if (PMIX_SUCCESS != rc) {
cb->status = rc;
goto done;
}
}
}
cb->proc->rank = PMIX_RANK_UNDEF;
} else {
cb->proc->rank = PMIX_RANK_UNDEF;
lg->hostname = strdup(pmix_globals.hostname);
lg->nodeid = pmix_globals.nodeid;
}
}
if (PMIx_Check_key(cb->key, PMIX_HOSTNAME)) {
if (NULL != lg->hostname) {
cb->status = PMIX_SUCCESS;
PMIX_VALUE_CREATE(cb->value, 1);
PMIX_VALUE_LOAD(cb->value, lg->hostname, PMIX_STRING);
} else {
cb->status = PMIX_ERR_NOT_FOUND;
}
goto done;
}
if (PMIx_Check_key(cb->key, PMIX_NODEID)) {
if (UINT32_MAX != lg->nodeid) {
cb->status = PMIX_SUCCESS;
PMIX_VALUE_CREATE(cb->value, 1);
PMIX_VALUE_LOAD(cb->value, &lg->nodeid, PMIX_UINT32);
} else {
cb->status = PMIX_ERR_NOT_FOUND;
}
goto done;
}
if (lg->nodedirective) {
nfo = cb->ninfo + 2;
PMIX_INFO_CREATE(iptr, nfo);
for (n=0; n < cb->ninfo; n++) {
PMIX_INFO_XFER(&iptr[n], &cb->info[n]);
}
if (NULL != lg->hostname) {
PMIX_INFO_LOAD(&iptr[cb->ninfo], PMIX_HOSTNAME, lg->hostname, PMIX_STRING);
} else {
PMIX_INFO_LOAD(&iptr[cb->ninfo], PMIX_NODEID, &lg->nodeid, PMIX_UINT32);
}
PMIX_INFO_LOAD(&iptr[cb->ninfo+1], PMIX_OPTIONAL, NULL, PMIX_BOOL);
cb->infocopy = true;
} else {
nfo = cb->ninfo + 3;
PMIX_INFO_CREATE(iptr, nfo);
for (n=0; n < cb->ninfo; n++) {
PMIX_INFO_XFER(&iptr[n], &cb->info[n]);
}
PMIX_INFO_LOAD(&iptr[cb->ninfo], PMIX_NODE_INFO, NULL, PMIX_BOOL);
if (NULL != lg->hostname) {
PMIX_INFO_LOAD(&iptr[cb->ninfo+1], PMIX_HOSTNAME, lg->hostname, PMIX_STRING);
} else {
PMIX_INFO_LOAD(&iptr[cb->ninfo+1], PMIX_HOSTNAME, &lg->nodeid, PMIX_UINT32);
}
PMIX_INFO_LOAD(&iptr[cb->ninfo+2], PMIX_OPTIONAL, NULL, PMIX_BOOL);
cb->infocopy = true;
}
goto doget;
}
if (lg->appinfo) {
if (UINT32_MAX == lg->appnum) {
if (PMIX_RANK_IS_VALID(cb->proc->rank)) {
if (PMIX_CHECK_PROCID(cb->proc, &pmix_globals.myid)) {
lg->appnum = pmix_globals.appnum;
} else {
PMIX_CONSTRUCT(&cb2, pmix_cb_t);
cb2.proc = cb->proc;
cb2.key = PMIX_APPNUM;
cb2.info = &optional;
cb2.ninfo = 1;
if (PMIX_PEER_IS_CLIENT(pmix_globals.mypeer)) {
PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, &cb2);
} else {
PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb2);
}
if (PMIX_SUCCESS == rc || PMIX_OPERATION_SUCCEEDED == rc) {
kv = (pmix_kval_t*)pmix_list_remove_first(&cb2.kvs);
PMIX_DESTRUCT(&cb2);
PMIX_VALUE_GET_NUMBER(rc, kv->value, lg->appnum, uint32_t);
PMIX_RELEASE(kv);
if (PMIX_SUCCESS != rc) {
cb->status = rc;
goto done;
}
} else {
cb->status = PMIX_ERR_NOT_FOUND;
goto done;
}
}
cb->proc->rank = PMIX_RANK_UNDEF;
} else {
cb->proc->rank = PMIX_RANK_UNDEF;
lg->appnum = pmix_globals.appnum;
}
}
if (0 == strcmp(cb->key, PMIX_APPNUM)) {
cb->status = PMIX_SUCCESS;
PMIX_VALUE_CREATE(cb->value, 1);
PMIX_VALUE_LOAD(cb->value, &lg->appnum, PMIX_UINT32);
goto done;
}
if (lg->appdirective) {
nfo = cb->ninfo + 2;
PMIX_INFO_CREATE(iptr, nfo);
for (n=0; n < cb->ninfo; n++) {
PMIX_INFO_XFER(&iptr[n], &cb->info[n]);
}
PMIX_INFO_LOAD(&iptr[cb->ninfo], PMIX_APPNUM, &lg->appnum, PMIX_UINT32);
PMIX_INFO_LOAD(&iptr[cb->ninfo+1], PMIX_OPTIONAL, NULL, PMIX_BOOL);
cb->infocopy = true;
} else {
nfo = cb->ninfo + 3;
PMIX_INFO_CREATE(iptr, nfo);
for (n=0; n < cb->ninfo; n++) {
PMIX_INFO_XFER(&iptr[n], &cb->info[n]);
}
PMIX_INFO_LOAD(&iptr[cb->ninfo], PMIX_APP_INFO, NULL, PMIX_BOOL);
PMIX_INFO_LOAD(&iptr[cb->ninfo+1], PMIX_APPNUM, &lg->appnum, PMIX_UINT32);
PMIX_INFO_LOAD(&iptr[cb->ninfo+2], PMIX_OPTIONAL, NULL, PMIX_BOOL);
cb->infocopy = true;
}
goto doget;
}
if (lg->sessioninfo) {
if (UINT32_MAX == lg->sessionid) {
if (PMIX_RANK_IS_VALID(cb->proc->rank)) {
if (PMIX_CHECK_PROCID(cb->proc, &pmix_globals.myid)) {
lg->sessionid = pmix_globals.sessionid;
} else {
PMIX_CONSTRUCT(&cb2, pmix_cb_t);
cb2.proc = cb->proc;
cb2.key = PMIX_SESSION_ID;
cb2.info = &optional;
cb2.ninfo = 1;
PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb2);
if (PMIX_SUCCESS == rc || PMIX_OPERATION_SUCCEEDED == rc) {
kv = (pmix_kval_t*)pmix_list_remove_first(&cb2.kvs);
PMIX_DESTRUCT(&cb2);
PMIX_VALUE_GET_NUMBER(rc, kv->value, lg->sessionid, uint32_t);
PMIX_RELEASE(kv);
if (PMIX_SUCCESS != rc) {
cb->status = rc;
goto done;
}
}
}
} else {
cb->proc->rank = PMIX_RANK_UNDEF;
lg->sessionid = pmix_globals.sessionid;
}
}
if (0 == strcmp(cb->key, PMIX_SESSION_ID)) {
cb->status = PMIX_SUCCESS;
PMIX_VALUE_CREATE(cb->value, 1);
PMIX_VALUE_LOAD(cb->value, &lg->sessionid, PMIX_UINT32);
goto done;
}
if (lg->sessiondirective) {
nfo = cb->ninfo + 2;
PMIX_INFO_CREATE(iptr, nfo);
for (n=0; n < cb->ninfo; n++) {
PMIX_INFO_XFER(&iptr[n], &cb->info[n]);
}
PMIX_INFO_LOAD(&iptr[cb->ninfo], PMIX_SESSION_ID, &lg->sessionid, PMIX_UINT32);
PMIX_INFO_LOAD(&iptr[cb->ninfo+1], PMIX_OPTIONAL, NULL, PMIX_BOOL);
cb->infocopy = true;
} else {
nfo = cb->ninfo + 3;
PMIX_INFO_CREATE(iptr, nfo);
for (n=0; n < cb->ninfo; n++) {
PMIX_INFO_XFER(&iptr[n], &cb->info[n]);
}
PMIX_INFO_LOAD(&iptr[cb->ninfo], PMIX_SESSION_INFO, NULL, PMIX_BOOL);
PMIX_INFO_LOAD(&iptr[cb->ninfo+1], PMIX_SESSION_ID, &lg->sessionid, PMIX_UINT32);
PMIX_INFO_LOAD(&iptr[cb->ninfo+2], PMIX_OPTIONAL, NULL, PMIX_BOOL);
cb->infocopy = true;
}
goto doget;
}
doget:
cb->info = iptr;
cb->ninfo = nfo;
PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, cb);
if (PMIX_SUCCESS == rc) {
pmix_output_verbose(5, pmix_client_globals.get_output,
"pmix:client data found in server-provided data");
cb->status = process_values(cb);
goto done;
}
pmix_output_verbose(5, pmix_client_globals.get_output,
"pmix:client data NOT found in server-provided data");
if (!PMIX_GDS_CHECK_COMPONENT(pmix_client_globals.myserver, "hash")) {
PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, cb);
if (PMIX_SUCCESS == rc) {
pmix_output_verbose(5, pmix_client_globals.get_output,
"pmix:client data found in internal hash data");
cb->status = process_values(cb);
goto done;
}
}
pmix_output_verbose(5, pmix_client_globals.get_output,
"pmix:client job-level data NOT found");
memcpy(&proc, &lg->p, sizeof(pmix_proc_t));
cb->pname.nspace = strdup(lg->p.nspace);
cb->pname.rank = lg->p.rank;
if (NULL == cb->key) {
if (PMIX_PEER_IS_EARLIER(pmix_client_globals.myserver, 3, 1, 100) ||
!PMIX_CHECK_NSPACE(lg->p.nspace, pmix_globals.myid.nspace)) {
proc.rank = PMIX_RANK_WILDCARD;
}
} else if (PMIX_CHECK_RESERVED_KEY(cb->key)) {
pmix_output_verbose(5, pmix_client_globals.get_output,
"pmix:client reserved key not locally found");
if (!lg->immediate) {
lg->add_immediate = true;
}
}
if ((PMIX_PEER_IS_SERVER(pmix_globals.mypeer) &&
!PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) ||
!pmix_globals.connected) {
cb->status = PMIX_ERR_NOT_FOUND;
goto done;
}
if (PMIX_ERR_EXISTS_OUTSIDE_SCOPE == rc) {
cb->status = rc;
goto done;
}
if (lg->optional) {
pmix_output_verbose(2, pmix_client_globals.get_output,
"PMIx_Get key=%s for rank = %u, namespace = %s was not found - request was optional",
cb->key, cb->pname.rank, cb->pname.nspace);
cb->status = PMIX_ERR_NOT_FOUND;
goto done;
}
PMIX_LIST_FOREACH (cbret, &pmix_client_globals.pending_requests, pmix_cb_t) {
if (PMIX_CHECK_NAMES(&cbret->pname, &proc)) {
pmix_output_verbose(2, pmix_client_globals.get_output,
"%s ADDING REQUEST TO PENDING %s:%s KEY %s",
PMIX_NAME_PRINT(&pmix_globals.myid), cb->proc->nspace,
PMIX_RANK_PRINT(proc.rank), cb->key);
pmix_list_append(&pmix_client_globals.pending_requests, &cb->super);
return;
}
}
msg = _pack_get(cb, proc.rank, PMIX_GETNB_CMD);
if (NULL == msg) {
cb->status = PMIX_ERROR;
PMIX_ERROR_LOG(cb->status);
goto done;
}
pmix_output_verbose(2, pmix_client_globals.get_output,
"%s REQUESTING DATA FROM SERVER FOR %s:%s KEY %s",
PMIX_NAME_PRINT(&pmix_globals.myid), cb->proc->nspace,
PMIX_RANK_PRINT(proc.rank), PMIx_Get_attribute_string(cb->key));
pmix_list_append(&pmix_client_globals.pending_requests, &cb->super);
PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, _getnb_cbfunc, (void *) cb);
if (PMIX_SUCCESS != rc) {
pmix_list_remove_item(&pmix_client_globals.pending_requests, &cb->super);
cb->status = PMIX_ERROR;
goto done;
}
return;
done:
PMIX_POST_OBJECT(cb);
if (cb->checked) {
gcbfn(0, 0, cb);
} else {
cb->cbfunc.valuefn(cb->status, cb->value, cb->cbdata);
}
return;
}
static void refcb(struct pmix_peer_t *pr, pmix_ptl_hdr_t *hdr,
pmix_buffer_t *buf, void *cbdata)
{
pmix_cb_t *cb = (pmix_cb_t *) cbdata;
int32_t cnt;
pmix_status_t rc, ret;
pmix_kval_t kv;
PMIX_HIDE_UNUSED_PARAMS(pr, hdr);
PMIX_ACQUIRE_OBJECT(cb);
if (NULL == cb) {
PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM);
return;
}
if (PMIX_BUFFER_IS_EMPTY(buf)) {
pmix_output_verbose(2, pmix_client_globals.get_output,
"pmix: refcb server lost connection");
ret = PMIX_ERR_LOST_CONNECTION;
goto done;
}
cnt = 1;
PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &ret, &cnt, PMIX_STATUS);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
ret = rc;
goto done;
}
PMIX_CONSTRUCT(&kv, pmix_kval_t);
cnt = 1;
PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &kv, &cnt, PMIX_KVAL);
while (PMIX_SUCCESS == rc) {
PMIX_GDS_STORE_KV(rc, pmix_globals.mypeer, cb->proc, PMIX_INTERNAL, &kv);
PMIX_DESTRUCT(&kv);
PMIX_CONSTRUCT(&kv, pmix_kval_t);
cnt = 1;
PMIX_BFROPS_UNPACK(rc, pmix_client_globals.myserver, buf, &kv, &cnt, PMIX_KVAL);
}
PMIX_DESTRUCT(&kv);
if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER == rc) {
ret = PMIX_SUCCESS;
} else {
ret = rc;
}
done:
cb->status = ret;
PMIX_POST_OBJECT(cb);
PMIX_WAKEUP_THREAD(&cb->lock);
return;
}
static pmix_status_t refresh_cache(const pmix_proc_t *p)
{
pmix_cb_t *cb;
pmix_buffer_t *msg;
pmix_status_t rc;
pmix_cmd_t cmd = PMIX_REFRESH_CACHE;
char *nspace = (char*)p->nspace;
pmix_output_verbose(2, pmix_client_globals.get_output,
"%s REQUESTING CACHE REFRESH BY SERVER FOR PROC %s",
PMIX_NAME_PRINT(&pmix_globals.myid),
PMIX_NAME_PRINT(p));
if (0 != strcmp(pmix_client_globals.myserver->nptr->compat.gds->name, "hash")) {
return PMIX_SUCCESS;
}
msg = PMIX_NEW(pmix_buffer_t);
PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
PMIX_RELEASE(msg);
return rc;
}
PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &nspace, 1, PMIX_STRING);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
PMIX_RELEASE(msg);
return rc;
}
PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &p->rank, 1, PMIX_PROC_RANK);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
PMIX_RELEASE(msg);
return rc;
}
cb = PMIX_NEW(pmix_cb_t);
cb->proc = (pmix_proc_t*)p;
PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, refcb, (void *)cb);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
PMIX_RELEASE(cb);
return rc;
}
PMIX_WAIT_THREAD(&cb->lock);
rc = cb->status;
PMIX_RELEASE(cb);
return rc;
}