/* * Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2004-2011 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2011-2013 Los Alamos National Security, LLC. All rights * reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ * */ #include "opal_config.h" #include "opal/constants.h" #include #include #include "opal_stdint.h" #include "opal/class/opal_hash_table.h" #include "opal/class/opal_pointer_array.h" #include "opal/dss/dss_types.h" #include "opal/util/error.h" #include "opal/util/output.h" #include "opal/util/show_help.h" #include "opal/mca/db/base/base.h" #include "db_hash.h" static int init(void); static void finalize(void); static int store(opal_identifier_t proc, opal_db_locality_t locality, const char *key, const void *object, opal_data_type_t type); static int store_pointer(opal_identifier_t proc, opal_db_locality_t locality, opal_value_t *kv); static int fetch(opal_identifier_t proc, const char *key, void **data, opal_data_type_t type); static int fetch_pointer(opal_identifier_t proc, const char *key, void **data, opal_data_type_t type); static int fetch_multiple(opal_identifier_t proc, const char *key, opal_list_t *kvs); static int remove_data(opal_identifier_t proc, const char *key); opal_db_base_module_t opal_db_hash_module = { init, finalize, store, store_pointer, fetch, fetch_pointer, fetch_multiple, remove_data, NULL }; /* Local "globals" */ static opal_hash_table_t hash_data; /** * Data for a particular opal process * The name association is maintained in the * proc_data hash table. */ typedef struct { /** Structure can be put on lists (including in hash tables) */ opal_list_item_t super; /* List of opal_value_t structures containing all data received from this process, sorted by key. */ opal_list_t data; } proc_data_t; static void proc_data_construct(proc_data_t *ptr) { OBJ_CONSTRUCT(&ptr->data, opal_list_t); } static void proc_data_destruct(proc_data_t *ptr) { opal_list_item_t *item; while (NULL != (item = opal_list_remove_first(&ptr->data))) { OBJ_RELEASE(item); } OBJ_DESTRUCT(&ptr->data); } OBJ_CLASS_INSTANCE(proc_data_t, opal_list_item_t, proc_data_construct, proc_data_destruct); static int init(void) { OBJ_CONSTRUCT(&hash_data, opal_hash_table_t); opal_hash_table_init(&hash_data, 256); return OPAL_SUCCESS; } static void finalize(void) { opal_hash_table_remove_all(&hash_data); OBJ_DESTRUCT(&hash_data); } /** * Find data for a given key in a given proc_data_t * container. */ static opal_value_t* lookup_keyval(proc_data_t *proc_data, const char *key) { opal_value_t *kv = NULL; for (kv = (opal_value_t *) opal_list_get_first(&proc_data->data); kv != (opal_value_t *) opal_list_get_end(&proc_data->data); kv = (opal_value_t *) opal_list_get_next(kv)) { if (0 == strcmp(key, kv->key)) { return kv; } } return NULL; } /** * Find proc_data_t container associated with given * opal_identifier_t. */ static proc_data_t* lookup_opal_proc(opal_hash_table_t *jtable, opal_identifier_t id) { proc_data_t *proc_data = NULL; opal_hash_table_get_value_uint64(jtable, id, (void**)&proc_data); if (NULL == proc_data) { /* The proc clearly exists, so create a data structure for it */ proc_data = OBJ_NEW(proc_data_t); if (NULL == proc_data) { opal_output(0, "db:hash:lookup_opal_proc: unable to allocate proc_data_t\n"); return NULL; } opal_hash_table_set_value_uint64(jtable, id, proc_data); } return proc_data; } static int store(const opal_identifier_t id, opal_db_locality_t locality, const char *key, const void *data, opal_data_type_t type) { proc_data_t *proc_data; opal_value_t *kv; opal_byte_object_t *boptr; /* we are at the bottom of the store priorities, so * if this fell to us, we store it */ opal_output_verbose(1, opal_db_base_framework.framework_output, "db:hash:store storing data for proc %" PRIu64 " at locality %d", id, (int)locality); /* lookup the proc data object for this proc */ if (NULL == (proc_data = lookup_opal_proc(&hash_data, id))) { /* unrecoverable error */ OPAL_OUTPUT_VERBOSE((5, opal_db_base_framework.framework_output, "db:hash:store: storing key %s[%s] for proc %" PRIu64 " unrecoverably failed", key, opal_dss.lookup_data_type(type), id)); return OPAL_ERR_OUT_OF_RESOURCE; } /* see if we already have this key in the data - means we are updating * a pre-existing value */ kv = lookup_keyval(proc_data, key); OPAL_OUTPUT_VERBOSE((5, opal_db_base_framework.framework_output, "db:hash:store: %s key %s[%s] for proc %" PRIu64 "", (NULL == kv ? "storing" : "updating"), key, opal_dss.lookup_data_type(type), id)); if (NULL != kv) { opal_list_remove_item(&proc_data->data, &kv->super); OBJ_RELEASE(kv); } kv = OBJ_NEW(opal_value_t); kv->key = strdup(key); opal_list_append(&proc_data->data, &kv->super); /* the type could come in as an OPAL one (e.g., OPAL_VPID). Since * the value is an OPAL definition, it cannot cover OPAL data * types, so convert to the underlying OPAL type */ switch (type) { case OPAL_STRING: kv->type = OPAL_STRING; if (NULL != data) { kv->data.string = strdup( (const char *) data); } else { kv->data.string = NULL; } break; case OPAL_UINT32: if (NULL == data) { OPAL_ERROR_LOG(OPAL_ERR_BAD_PARAM); return OPAL_ERR_BAD_PARAM; } kv->type = OPAL_UINT32; kv->data.uint32 = *(uint32_t*)data; break; case OPAL_UINT16: if (NULL == data) { OPAL_ERROR_LOG(OPAL_ERR_BAD_PARAM); return OPAL_ERR_BAD_PARAM; } kv->type = OPAL_UINT16; kv->data.uint16 = *(uint16_t*)(data); break; case OPAL_INT: if (NULL == data) { OPAL_ERROR_LOG(OPAL_ERR_BAD_PARAM); return OPAL_ERR_BAD_PARAM; } kv->type = OPAL_INT; kv->data.integer = *(int*)(data); break; case OPAL_UINT: if (NULL == data) { OPAL_ERROR_LOG(OPAL_ERR_BAD_PARAM); return OPAL_ERR_BAD_PARAM; } kv->type = OPAL_UINT; kv->data.uint = *(unsigned int*)(data); break; case OPAL_BYTE_OBJECT: kv->type = OPAL_BYTE_OBJECT; boptr = (opal_byte_object_t*)data; if (NULL != boptr && NULL != boptr->bytes && 0 < boptr->size) { kv->data.bo.bytes = (uint8_t *) malloc(boptr->size); memcpy(kv->data.bo.bytes, boptr->bytes, boptr->size); kv->data.bo.size = boptr->size; } else { kv->data.bo.bytes = NULL; kv->data.bo.size = 0; } break; default: OPAL_ERROR_LOG(OPAL_ERR_NOT_SUPPORTED); return OPAL_ERR_NOT_SUPPORTED; } return OPAL_SUCCESS; } static int store_pointer(opal_identifier_t id, opal_db_locality_t locality, opal_value_t *kv) { proc_data_t *proc_data; opal_value_t *k2; /* we are at the bottom of the store priorities, so * if this fell to us, we store it */ opal_output_verbose(1, opal_db_base_framework.framework_output, "db:hash:store storing data for proc %" PRIu64 " at locality %d", id, (int)locality); /* lookup the proc data object for this proc */ if (NULL == (proc_data = lookup_opal_proc(&hash_data, id))) { /* unrecoverable error */ OPAL_OUTPUT_VERBOSE((5, opal_db_base_framework.framework_output, "db:hash:store: storing key %s[%s] for proc %" PRIu64 " unrecoverably failed", kv->key, opal_dss.lookup_data_type(kv->type), id)); return OPAL_ERR_OUT_OF_RESOURCE; } /* see if we already have this key in the data - means we are updating * a pre-existing value */ k2 = lookup_keyval(proc_data, kv->key); OPAL_OUTPUT_VERBOSE((5, opal_db_base_framework.framework_output, "db:hash:store: %s pointer of key %s[%s] for proc %" PRIu64 "", (NULL == k2 ? "storing" : "updating"), kv->key, opal_dss.lookup_data_type(kv->type), id)); if (NULL != k2) { opal_list_remove_item(&proc_data->data, &k2->super); OBJ_RELEASE(k2); } opal_list_append(&proc_data->data, &kv->super); return OPAL_SUCCESS; } static int fetch(opal_identifier_t id, const char *key, void **data, opal_data_type_t type) { proc_data_t *proc_data; opal_value_t *kv; opal_byte_object_t *boptr; OPAL_OUTPUT_VERBOSE((5, opal_db_base_framework.framework_output, "db:hash:fetch: searching for key %s[%s] on proc %" PRIu64 "", (NULL == key) ? "NULL" : key, opal_dss.lookup_data_type(type), id)); /* if the key is NULL, that is an error */ if (NULL == key) { OPAL_ERROR_LOG(OPAL_ERR_BAD_PARAM); return OPAL_ERR_BAD_PARAM; } /* lookup the proc data object for this proc */ if (NULL == (proc_data = lookup_opal_proc(&hash_data, id))) { /* maybe they can find it elsewhere */ return OPAL_ERR_TAKE_NEXT_OPTION; } /* find the value */ if (NULL == (kv = lookup_keyval(proc_data, key))) { /* maybe they can find it elsewhere */ return OPAL_ERR_TAKE_NEXT_OPTION; } /* do the copy and check the type */ switch (type) { case OPAL_STRING: if (OPAL_STRING != kv->type) { return OPAL_ERR_TYPE_MISMATCH; } if (NULL != kv->data.string) { *data = strdup(kv->data.string); } else { *data = NULL; } break; case OPAL_UINT32: if (OPAL_UINT32 != kv->type) { return OPAL_ERR_TYPE_MISMATCH; } memcpy(*data, &kv->data.uint32, 4); break; case OPAL_UINT16: if (OPAL_UINT16 != kv->type) { return OPAL_ERR_TYPE_MISMATCH; } memcpy(*data, &kv->data.uint16, 2); break; case OPAL_INT: if (OPAL_INT != kv->type) { return OPAL_ERR_TYPE_MISMATCH; } memcpy(*data, &kv->data.integer, sizeof(int)); break; case OPAL_UINT: if (OPAL_UINT != kv->type) { return OPAL_ERR_TYPE_MISMATCH; } memcpy(*data, &kv->data.uint, sizeof(unsigned int)); break; case OPAL_BYTE_OBJECT: if (OPAL_BYTE_OBJECT != kv->type) { return OPAL_ERR_TYPE_MISMATCH; } boptr = (opal_byte_object_t*)malloc(sizeof(opal_byte_object_t)); if (NULL != kv->data.bo.bytes && 0 < kv->data.bo.size) { boptr->bytes = (uint8_t *) malloc(kv->data.bo.size); memcpy(boptr->bytes, kv->data.bo.bytes, kv->data.bo.size); boptr->size = kv->data.bo.size; } else { boptr->bytes = NULL; boptr->size = 0; } *data = boptr; break; default: OPAL_ERROR_LOG(OPAL_ERR_NOT_SUPPORTED); return OPAL_ERR_NOT_SUPPORTED; } return OPAL_SUCCESS; } static int fetch_pointer(opal_identifier_t id, const char *key, void **data, opal_data_type_t type) { proc_data_t *proc_data; opal_value_t *kv; OPAL_OUTPUT_VERBOSE((5, opal_db_base_framework.framework_output, "db:hash:fetch_pointer: searching for key %s on proc %" PRIu64 "", (NULL == key) ? "NULL" : key, id)); /* if the key is NULL, that is an error */ if (NULL == key) { OPAL_ERROR_LOG(OPAL_ERR_BAD_PARAM); return OPAL_ERR_BAD_PARAM; } /* lookup the proc data object for this proc */ if (NULL == (proc_data = lookup_opal_proc(&hash_data, id))) { /* look elsewhere */ return OPAL_ERR_TAKE_NEXT_OPTION; } /* find the value */ if (NULL == (kv = lookup_keyval(proc_data, key))) { /* look elsewhere */ return OPAL_ERR_TAKE_NEXT_OPTION; } switch (type) { case OPAL_STRING: if (OPAL_STRING != kv->type) { return OPAL_ERR_TYPE_MISMATCH; } *data = kv->data.string; break; case OPAL_UINT32: if (OPAL_UINT32 != kv->type) { return OPAL_ERR_TYPE_MISMATCH; } *data = &kv->data.uint32; break; case OPAL_UINT16: if (OPAL_UINT16 != kv->type) { return OPAL_ERR_TYPE_MISMATCH; } *data = &kv->data.uint16; break; case OPAL_INT: if (OPAL_INT != kv->type) { return OPAL_ERR_TYPE_MISMATCH; } *data = &kv->data.integer; break; case OPAL_UINT: if (OPAL_UINT != kv->type) { return OPAL_ERR_TYPE_MISMATCH; } *data = &kv->data.uint; break; case OPAL_BYTE_OBJECT: if (OPAL_BYTE_OBJECT != kv->type) { return OPAL_ERR_TYPE_MISMATCH; } *data = &kv->data.bo; break; default: OPAL_ERROR_LOG(OPAL_ERR_NOT_SUPPORTED); return OPAL_ERR_NOT_SUPPORTED; } return OPAL_SUCCESS; } static int fetch_multiple(opal_identifier_t id, const char *key, opal_list_t *kvs) { proc_data_t *proc_data; opal_value_t *kv, *kvnew; int rc; char *srchkey, *ptr; size_t len = 0; OPAL_OUTPUT_VERBOSE((5, opal_db_base_framework.framework_output, "db:hash:fetch_multiple: searching for key %s on proc %" PRIu64 "", (NULL == key) ? "NULL" : key, id)); /* lookup the proc data object for this proc */ if (NULL == (proc_data = lookup_opal_proc(&hash_data, id))) { /* look elsewhere */ return OPAL_ERR_TAKE_NEXT_OPTION; } /* if the key is NULL, then return all the values */ if (NULL == key) { for (kv = (opal_value_t*) opal_list_get_first(&proc_data->data); kv != (opal_value_t*) opal_list_get_end(&proc_data->data); kv = (opal_value_t*) opal_list_get_next(kv)) { if (OPAL_SUCCESS != (rc = opal_dss.copy((void**)&kvnew, kv, OPAL_VALUE))) { OPAL_ERROR_LOG(rc); return rc; } opal_list_append(kvs, &kvnew->super); } return OPAL_SUCCESS; } /* see if the key includes a wildcard */ srchkey = strdup(key); if (NULL != (ptr = strchr(srchkey, '*'))) { *ptr = '\0'; len = strlen(srchkey); } /* otherwise, find all matching keys and return them */ for (kv = (opal_value_t*) opal_list_get_first(&proc_data->data); kv != (opal_value_t*) opal_list_get_end(&proc_data->data); kv = (opal_value_t*) opal_list_get_next(kv)) { if ((0 < len && 0 == strncmp(srchkey, kv->key, len)) || (0 == len && 0 == strcmp(key, kv->key))) { if (OPAL_SUCCESS != (rc = opal_dss.copy((void**)&kvnew, kv, OPAL_VALUE))) { OPAL_ERROR_LOG(rc); return rc; } opal_list_append(kvs, &kvnew->super); } } free(srchkey); return OPAL_SUCCESS; } static int remove_data(opal_identifier_t id, const char *key) { proc_data_t *proc_data; opal_value_t *kv; /* lookup the specified proc */ if (NULL == (proc_data = lookup_opal_proc(&hash_data, id))) { /* no data for this proc */ return OPAL_SUCCESS; } /* if key is NULL, remove all data for this proc */ if (NULL == key) { while (NULL != (kv = (opal_value_t *) opal_list_remove_first(&proc_data->data))) { OBJ_RELEASE(kv); } /* remove the proc_data object itself from the jtable */ opal_hash_table_remove_value_uint64(&hash_data, id); /* cleanup */ OBJ_RELEASE(proc_data); return OPAL_SUCCESS; } /* remove this item */ for (kv = (opal_value_t*) opal_list_get_first(&proc_data->data); kv != (opal_value_t*) opal_list_get_end(&proc_data->data); kv = (opal_value_t*) opal_list_get_next(kv)) { if (0 == strcmp(key, kv->key)) { OBJ_RELEASE(kv); break; } } return OPAL_SUCCESS; }