root/opal/mca/pmix/pmix4x/pmix/src/util/hash.c

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

DEFINITIONS

This source file includes following definitions.
  1. pdcon
  2. pddes
  3. pmix_hash_store
  4. pmix_hash_fetch
  5. pmix_hash_fetch_by_key
  6. pmix_hash_remove_data
  7. lookup_keyval
  8. lookup_proc

   1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
   2 /*
   3  * Copyright (c) 2010      Cisco Systems, Inc.  All rights reserved.
   4  * Copyright (c) 2004-2011 The University of Tennessee and The University
   5  *                         of Tennessee Research Foundation.  All rights
   6  *                         reserved.
   7  * Copyright (c) 2011-2014 Los Alamos National Security, LLC.  All rights
   8  *                         reserved.
   9  * Copyright (c) 2014-2018 Intel, Inc.  All rights reserved.
  10  * Copyright (c) 2015-2018 Research Organization for Information Science
  11  *                         and Technology (RIST). All rights reserved.
  12  * Copyright (c) 2016      Mellanox Technologies, Inc.
  13  *                         All rights reserved.
  14  * Copyright (c) 2016      IBM Corporation.  All rights reserved.
  15  * $COPYRIGHT$
  16  *
  17  * Additional copyrights may follow
  18  *
  19  * $HEADER$
  20  *
  21  */
  22 
  23 #include <src/include/pmix_config.h>
  24 
  25 #include <src/include/pmix_stdint.h>
  26 #include <src/include/hash_string.h>
  27 
  28 #include <string.h>
  29 
  30 #include "src/include/pmix_globals.h"
  31 #include "src/class/pmix_hash_table.h"
  32 #include "src/class/pmix_pointer_array.h"
  33 #include "src/mca/bfrops/bfrops.h"
  34 #include "src/util/error.h"
  35 #include "src/util/output.h"
  36 
  37 #include "src/util/hash.h"
  38 
  39 /**
  40  * Data for a particular pmix process
  41  * The name association is maintained in the
  42  * proc_data hash table.
  43  */
  44 typedef struct {
  45     /** Structure can be put on lists (including in hash tables) */
  46     pmix_list_item_t super;
  47     /* List of pmix_kval_t structures containing all data
  48        received from this process */
  49     pmix_list_t data;
  50 } pmix_proc_data_t;
  51 static void pdcon(pmix_proc_data_t *p)
  52 {
  53     PMIX_CONSTRUCT(&p->data, pmix_list_t);
  54 }
  55 static void pddes(pmix_proc_data_t *p)
  56 {
  57     PMIX_LIST_DESTRUCT(&p->data);
  58 }
  59 static PMIX_CLASS_INSTANCE(pmix_proc_data_t,
  60                            pmix_list_item_t,
  61                            pdcon, pddes);
  62 
  63 static pmix_kval_t* lookup_keyval(pmix_list_t *data,
  64                                   const char *key);
  65 static pmix_proc_data_t* lookup_proc(pmix_hash_table_t *jtable,
  66                                      uint64_t id, bool create);
  67 
  68 pmix_status_t pmix_hash_store(pmix_hash_table_t *table,
  69                               pmix_rank_t rank, pmix_kval_t *kin)
  70 {
  71     pmix_proc_data_t *proc_data;
  72     uint64_t id;
  73     pmix_kval_t *hv;
  74 
  75     pmix_output_verbose(10, pmix_globals.debug_output,
  76                         "HASH:STORE rank %d key %s",
  77                         rank, (NULL == kin) ? "NULL KVAL" : kin->key);
  78 
  79     if (NULL == kin) {
  80         return PMIX_ERR_BAD_PARAM;
  81     }
  82 
  83     id = (uint64_t)rank;
  84 
  85     /* lookup the proc data object for this proc - create
  86      * it if we don't already have it */
  87     if (NULL == (proc_data = lookup_proc(table, id, true))) {
  88         return PMIX_ERR_OUT_OF_RESOURCE;
  89     }
  90 
  91     /* see if we already have this key-value */
  92     hv = lookup_keyval(&proc_data->data, kin->key);
  93     if (NULL != hv) {
  94         /* yes we do - so remove the current value
  95          * and replace it */
  96         pmix_list_remove_item(&proc_data->data, &hv->super);
  97         PMIX_RELEASE(hv);
  98     }
  99     PMIX_RETAIN(kin);
 100     pmix_list_append(&proc_data->data, &kin->super);
 101 
 102     return PMIX_SUCCESS;
 103 }
 104 
 105 pmix_status_t pmix_hash_fetch(pmix_hash_table_t *table, pmix_rank_t rank,
 106                               const char *key, pmix_value_t **kvs)
 107 {
 108     pmix_status_t rc = PMIX_SUCCESS;
 109     pmix_proc_data_t *proc_data;
 110     pmix_kval_t *hv;
 111     uint64_t id;
 112     char *node;
 113     pmix_info_t *info;
 114     size_t ninfo, n;
 115     pmix_value_t *val;
 116 
 117     pmix_output_verbose(10, pmix_globals.debug_output,
 118                         "HASH:FETCH rank %d key %s",
 119                         rank, (NULL == key) ? "NULL" : key);
 120 
 121     id = (uint64_t)rank;
 122 
 123     /* - PMIX_RANK_UNDEF should return following statuses
 124      *     PMIX_ERR_PROC_ENTRY_NOT_FOUND | PMIX_SUCCESS
 125      * - specified rank can return following statuses
 126      *     PMIX_ERR_PROC_ENTRY_NOT_FOUND | PMIX_ERR_NOT_FOUND | PMIX_SUCCESS
 127      * special logic is basing on these statuses on a client and a server */
 128     if (PMIX_RANK_UNDEF == rank) {
 129         rc = pmix_hash_table_get_first_key_uint64(table, &id,
 130                 (void**)&proc_data, (void**)&node);
 131         if (PMIX_SUCCESS != rc) {
 132             pmix_output_verbose(10, pmix_globals.debug_output,
 133                                 "HASH:FETCH proc data for rank %d not found",
 134                                 rank);
 135             return PMIX_ERR_PROC_ENTRY_NOT_FOUND;
 136         }
 137     }
 138 
 139     while (PMIX_SUCCESS == rc) {
 140         proc_data = lookup_proc(table, id, false);
 141         if (NULL == proc_data) {
 142             pmix_output_verbose(10, pmix_globals.debug_output,
 143                                 "HASH:FETCH proc data for rank %d not found",
 144                                 rank);
 145             return PMIX_ERR_PROC_ENTRY_NOT_FOUND;
 146         }
 147 
 148         /* if the key is NULL, then the user wants -all- data
 149          * put by the specified rank */
 150         if (NULL == key) {
 151             /* we will return the data as an array of pmix_info_t
 152              * in the kvs pmix_value_t */
 153             val = (pmix_value_t*)malloc(sizeof(pmix_value_t));
 154             if (NULL == val) {
 155                 return PMIX_ERR_NOMEM;
 156             }
 157             val->type = PMIX_DATA_ARRAY;
 158             val->data.darray = (pmix_data_array_t*)malloc(sizeof(pmix_data_array_t));
 159             if (NULL == val->data.darray) {
 160                 PMIX_VALUE_RELEASE(val);
 161                 return PMIX_ERR_NOMEM;
 162             }
 163             val->data.darray->type = PMIX_INFO;
 164             val->data.darray->size = 0;
 165             val->data.darray->array = NULL;
 166             ninfo = pmix_list_get_size(&proc_data->data);
 167             PMIX_INFO_CREATE(info, ninfo);
 168             if (NULL == info) {
 169                 PMIX_VALUE_RELEASE(val);
 170                 return PMIX_ERR_NOMEM;
 171             }
 172             /* copy the list elements */
 173             n=0;
 174             PMIX_LIST_FOREACH(hv, &proc_data->data, pmix_kval_t) {
 175                 pmix_strncpy(info[n].key, hv->key, PMIX_MAX_KEYLEN);
 176                 pmix_value_xfer(&info[n].value, hv->value);
 177                 ++n;
 178             }
 179             val->data.darray->size = ninfo;
 180             val->data.darray->array = info;
 181             *kvs = val;
 182             return PMIX_SUCCESS;
 183         } else {
 184             /* find the value from within this proc_data object */
 185             hv = lookup_keyval(&proc_data->data, key);
 186             if (NULL != hv) {
 187                 /* create the copy */
 188                 PMIX_BFROPS_COPY(rc, pmix_globals.mypeer,
 189                                  (void**)kvs, hv->value, PMIX_VALUE);
 190                 if (PMIX_SUCCESS != rc) {
 191                     PMIX_ERROR_LOG(rc);
 192                     return rc;
 193                 }
 194                 break;
 195             } else if (PMIX_RANK_UNDEF != rank) {
 196                 pmix_output_verbose(10, pmix_globals.debug_output,
 197                                     "HASH:FETCH data for key %s not found", key);
 198                 return PMIX_ERR_NOT_FOUND;
 199             }
 200         }
 201 
 202         rc = pmix_hash_table_get_next_key_uint64(table, &id,
 203                 (void**)&proc_data, node, (void**)&node);
 204         if (PMIX_SUCCESS != rc) {
 205             pmix_output_verbose(10, pmix_globals.debug_output,
 206                                 "HASH:FETCH data for key %s not found", key);
 207             return PMIX_ERR_PROC_ENTRY_NOT_FOUND;
 208         }
 209     }
 210 
 211     return rc;
 212 }
 213 
 214 pmix_status_t pmix_hash_fetch_by_key(pmix_hash_table_t *table, const char *key,
 215                                      pmix_rank_t *rank, pmix_value_t **kvs, void **last)
 216 {
 217     pmix_status_t rc = PMIX_SUCCESS;
 218     pmix_proc_data_t *proc_data;
 219     pmix_kval_t *hv;
 220     uint64_t id;
 221     char *node;
 222     static const char *key_r = NULL;
 223 
 224     if (key == NULL && (node = *last) == NULL) {
 225         return PMIX_ERR_PROC_ENTRY_NOT_FOUND;
 226     }
 227 
 228     if (key == NULL && key_r == NULL) {
 229         return PMIX_ERR_PROC_ENTRY_NOT_FOUND;
 230     }
 231 
 232     if (key) {
 233         rc = pmix_hash_table_get_first_key_uint64(table, &id,
 234                 (void**)&proc_data, (void**)&node);
 235         key_r = key;
 236     } else {
 237         rc = pmix_hash_table_get_next_key_uint64(table, &id,
 238                 (void**)&proc_data, node, (void**)&node);
 239     }
 240 
 241     pmix_output_verbose(10, pmix_globals.debug_output,
 242                         "HASH:FETCH BY KEY rank %d key %s",
 243                         (int)id, key_r);
 244 
 245     if (PMIX_SUCCESS != rc) {
 246         pmix_output_verbose(10, pmix_globals.debug_output,
 247                             "HASH:FETCH proc data for key %s not found",
 248                             key_r);
 249         return PMIX_ERR_PROC_ENTRY_NOT_FOUND;
 250     }
 251 
 252     /* find the value from within this proc_data object */
 253     hv = lookup_keyval(&proc_data->data, key_r);
 254     if (hv) {
 255         /* create the copy */
 256         PMIX_BFROPS_COPY(rc, pmix_globals.mypeer,
 257                          (void**)kvs, hv->value, PMIX_VALUE);
 258         if (PMIX_SUCCESS != rc) {
 259             PMIX_ERROR_LOG(rc);
 260             return rc;
 261         }
 262     } else {
 263         return PMIX_ERR_NOT_FOUND;
 264     }
 265 
 266     *rank = (int)id;
 267     *last = node;
 268 
 269     return PMIX_SUCCESS;
 270 }
 271 
 272 pmix_status_t pmix_hash_remove_data(pmix_hash_table_t *table,
 273                                     pmix_rank_t rank, const char *key)
 274 {
 275     pmix_status_t rc = PMIX_SUCCESS;
 276     pmix_proc_data_t *proc_data;
 277     pmix_kval_t *kv;
 278     uint64_t id;
 279     char *node;
 280 
 281     id = (uint64_t)rank;
 282 
 283     /* if the rank is wildcard, we want to apply this to
 284      * all rank entries */
 285     if (PMIX_RANK_WILDCARD == rank) {
 286         rc = pmix_hash_table_get_first_key_uint64(table, &id,
 287                 (void**)&proc_data, (void**)&node);
 288         while (PMIX_SUCCESS == rc) {
 289             if (NULL != proc_data) {
 290                 if (NULL == key) {
 291                     PMIX_RELEASE(proc_data);
 292                 } else {
 293                     PMIX_LIST_FOREACH(kv, &proc_data->data, pmix_kval_t) {
 294                         if (0 == strcmp(key, kv->key)) {
 295                             pmix_list_remove_item(&proc_data->data, &kv->super);
 296                             PMIX_RELEASE(kv);
 297                             break;
 298                         }
 299                     }
 300                 }
 301             }
 302             rc = pmix_hash_table_get_next_key_uint64(table, &id,
 303                     (void**)&proc_data, node, (void**)&node);
 304         }
 305         return PMIX_SUCCESS;
 306     }
 307 
 308     /* lookup the specified proc */
 309     if (NULL == (proc_data = lookup_proc(table, id, false))) {
 310         /* no data for this proc */
 311         return PMIX_SUCCESS;
 312     }
 313 
 314     /* if key is NULL, remove all data for this proc */
 315     if (NULL == key) {
 316         while (NULL != (kv = (pmix_kval_t*)pmix_list_remove_first(&proc_data->data))) {
 317             PMIX_RELEASE(kv);
 318         }
 319         /* remove the proc_data object itself from the jtable */
 320         pmix_hash_table_remove_value_uint64(table, id);
 321         /* cleanup */
 322         PMIX_RELEASE(proc_data);
 323         return PMIX_SUCCESS;
 324     }
 325 
 326     /* remove this item */
 327     PMIX_LIST_FOREACH(kv, &proc_data->data, pmix_kval_t) {
 328         if (0 == strcmp(key, kv->key)) {
 329             pmix_list_remove_item(&proc_data->data, &kv->super);
 330             PMIX_RELEASE(kv);
 331             break;
 332         }
 333     }
 334 
 335     return PMIX_SUCCESS;
 336 }
 337 
 338 /**
 339  * Find data for a given key in a given pmix_list_t.
 340  */
 341 static pmix_kval_t* lookup_keyval(pmix_list_t *data,
 342                                   const char *key)
 343 {
 344     pmix_kval_t *kv;
 345 
 346     PMIX_LIST_FOREACH(kv, data, pmix_kval_t) {
 347         if (0 == strcmp(key, kv->key)) {
 348             return kv;
 349         }
 350     }
 351     return NULL;
 352 }
 353 
 354 
 355 /**
 356  * Find proc_data_t container associated with given
 357  * pmix_identifier_t.
 358  */
 359 static pmix_proc_data_t* lookup_proc(pmix_hash_table_t *jtable,
 360                                      uint64_t id, bool create)
 361 {
 362     pmix_proc_data_t *proc_data = NULL;
 363 
 364     pmix_hash_table_get_value_uint64(jtable, id, (void**)&proc_data);
 365     if (NULL == proc_data && create) {
 366         /* The proc clearly exists, so create a data structure for it */
 367         proc_data = PMIX_NEW(pmix_proc_data_t);
 368         if (NULL == proc_data) {
 369             pmix_output(0, "pmix:client:hash:lookup_pmix_proc: unable to allocate proc_data_t\n");
 370             return NULL;
 371         }
 372         pmix_hash_table_set_value_uint64(jtable, id, proc_data);
 373     }
 374 
 375     return proc_data;
 376 }

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