uint16_t as_bin_get_or_assign_id(as_namespace *ns, const char *name) { if (ns->single_bin) { cf_crash(AS_BIN, "single-bin call of as_bin_get_or_assign_id()"); } uint32_t idx; if (cf_vmapx_get_index(ns->p_bin_name_vmap, name, &idx) == CF_VMAPX_OK) { return (uint16_t)idx; } // Verify length just once here at insertion. if (strlen(name) >= BIN_NAME_MAX_SZ) { cf_crash(AS_BIN, "bin name %s too long", name); } cf_vmapx_err result = cf_vmapx_put_unique(ns->p_bin_name_vmap, name, &idx); if (! (result == CF_VMAPX_OK || result == CF_VMAPX_ERR_NAME_EXISTS)) { // Tedious to handle safely for all usage paths, so for now... cf_crash(AS_BIN, "could not add bin name %s, vmap err %d", name, result); } return (uint16_t)idx; }
uint16_t as_namespace_get_set_id(as_namespace *ns, const char *set_name) { uint32_t idx; return cf_vmapx_get_index(ns->p_sets_vmap, set_name, &idx) == CF_VMAPX_OK ? (uint16_t)(idx + 1) : INVALID_SET_ID; }
int32_t as_bin_get_index(as_storage_rd *rd, const char *name) { if (rd->ns->single_bin) { return as_bin_inuse_has(rd) ? 0 : -1; } uint32_t id; if (cf_vmapx_get_index(rd->ns->p_bin_name_vmap, name, &id) != CF_VMAPX_OK) { return -1; } for (uint16_t i = 0; i < rd->n_bins; i++) { as_bin *b = &rd->bins[i]; if (! as_bin_inuse(b)) { break; } if ((uint32_t)b->id == id) { return (int32_t)i; } } return -1; }
// At the moment this is only used by the enterprise build security feature. uint16_t as_namespace_get_create_set_id(as_namespace *ns, const char *set_name) { if (! set_name) { // Should be impossible. cf_warning(AS_NAMESPACE, "null set name"); return INVALID_SET_ID; } uint32_t idx; cf_vmapx_err result = cf_vmapx_get_index(ns->p_sets_vmap, set_name, &idx); if (result == CF_VMAPX_OK) { return (uint16_t)(idx + 1); } if (result == CF_VMAPX_ERR_NAME_NOT_FOUND) { as_set set; memset(&set, 0, sizeof(set)); // Check name length just once, here at insertion. (Other vmap calls are // safe if name is too long - they return CF_VMAPX_ERR_NAME_NOT_FOUND.) strncpy(set.name, set_name, AS_SET_NAME_MAX_SIZE); if (set.name[AS_SET_NAME_MAX_SIZE - 1]) { set.name[AS_SET_NAME_MAX_SIZE - 1] = 0; cf_warning(AS_NAMESPACE, "set name %s... too long", set.name); return INVALID_SET_ID; } set.num_elements = 0; // *not* adding an element result = cf_vmapx_put_unique(ns->p_sets_vmap, &set, &idx); if (result == CF_VMAPX_ERR_NAME_EXISTS) { return (uint16_t)(idx + 1); } if (result == CF_VMAPX_ERR_FULL) { cf_warning(AS_NAMESPACE, "at set names limit, can't add %s", set.name); return INVALID_SET_ID; } if (result != CF_VMAPX_OK) { // Currently, remaining errors are all some form of out-of-memory. cf_warning(AS_NAMESPACE, "error %d, can't add %s", result, set.name); return INVALID_SET_ID; } return (uint16_t)(idx + 1); } // Should be impossible. cf_warning(AS_NAMESPACE, "unexpected error %d", result); return INVALID_SET_ID; }
// caller-beware, name cannot be null int16_t as_bin_get_id(as_namespace *ns, const char *name) { if (ns->single_bin) { cf_crash(AS_BIN, "single-bin call of as_bin_get_or_assign_id()"); } uint32_t idx; if (cf_vmapx_get_index(ns->p_bin_name_vmap, name, &idx) == CF_VMAPX_OK) { return (uint16_t)idx; } return -1; }
// Does not check bin name length. // Checks bin name quota - use appropriately. as_bin * as_bin_get_or_create(as_storage_rd *rd, const char *name) { if (rd->ns->single_bin) { if (! as_bin_inuse_has(rd)) { as_bin_init_nameless(rd->bins); } return rd->bins; } uint32_t id = (uint32_t)-1; uint16_t i; as_bin *b; if (cf_vmapx_get_index(rd->ns->p_bin_name_vmap, name, &id) == CF_VMAPX_OK) { for (i = 0; i < rd->n_bins; i++) { b = &rd->bins[i]; if (! as_bin_inuse(b)) { break; } if ((uint32_t)b->id == id) { return b; } } } else { if (cf_vmapx_count(rd->ns->p_bin_name_vmap) >= BIN_NAMES_QUOTA) { cf_warning(AS_BIN, "{%s} bin-name quota full - can't add new bin-name %s", rd->ns->name, name); return NULL; } i = as_bin_inuse_count(rd); } if (i >= rd->n_bins) { cf_crash(AS_BIN, "ran out of allocated bins in rd"); } b = &rd->bins[i]; if (id == (uint32_t)-1) { as_bin_init(rd->ns, b, name); } else { as_bin_init_nameless(b); b->id = (uint16_t)id; } return b; }
bool as_bin_get_id_from_name_buf(as_namespace *ns, byte *buf, size_t len, uint32_t *p_id) { if (ns->single_bin) { cf_crash(AS_BIN, "single-bin call of as_bin_get_or_assign_id()"); } char name[len + 1]; memcpy(name, buf, len); name[len] = 0; return cf_vmapx_get_index(ns->p_bin_name_vmap, name, p_id) == CF_VMAPX_OK; }
as_set *as_namespace_init_set(as_namespace *ns, const char *set_name) { if (! set_name) { return NULL; } uint32_t idx; cf_vmapx_err result = cf_vmapx_get_index(ns->p_sets_vmap, set_name, &idx); if (result == CF_VMAPX_ERR_NAME_NOT_FOUND) { as_set set; memset(&set, 0, sizeof(set)); // Check name length just once, here at insertion. (Other vmap calls are // safe if name is too long - they return CF_VMAPX_ERR_NAME_NOT_FOUND.) strncpy(set.name, set_name, AS_SET_NAME_MAX_SIZE); if (set.name[AS_SET_NAME_MAX_SIZE - 1]) { set.name[AS_SET_NAME_MAX_SIZE - 1] = 0; cf_info(AS_NAMESPACE, "set name %s... too long", set.name); return NULL; } result = cf_vmapx_put_unique(ns->p_sets_vmap, &set, &idx); // Since this function can be called via info, need to handle race with // as_namespace_get_create_set() that returns CF_VMAPX_ERR_NAME_EXISTS. if (result != CF_VMAPX_OK && result != CF_VMAPX_ERR_NAME_EXISTS) { cf_warning(AS_NAMESPACE, "unexpected error %d", result); return NULL; } } else if (result != CF_VMAPX_OK) { // Should be impossible. cf_warning(AS_NAMESPACE, "unexpected error %d", result); return NULL; } as_set *p_set = NULL; if ((result = cf_vmapx_get_by_index(ns->p_sets_vmap, idx, (void**)&p_set)) != CF_VMAPX_OK) { // Should be impossible - just verified idx. cf_warning(AS_NAMESPACE, "unexpected error %d", result); return NULL; } return p_set; }
as_bin * as_bin_get(as_storage_rd *rd, const char *name) { if (rd->ns->single_bin) { return as_bin_inuse_has(rd) ? rd->bins : NULL; } uint32_t id; if (cf_vmapx_get_index(rd->ns->p_bin_name_vmap, name, &id) != CF_VMAPX_OK) { return NULL; } return as_bin_get_by_id(rd, id); }
as_bin * as_bin_get_and_reserve_name(as_storage_rd *rd, byte *name, size_t namesz, bool *p_reserved, uint32_t *p_idx) { *p_reserved = true; if (rd->ns->single_bin) { return as_bin_inuse_has(rd) ? rd->bins : NULL; } char zname[namesz + 1]; memcpy(zname, name, namesz); zname[namesz] = 0; if (cf_vmapx_get_index(rd->ns->p_bin_name_vmap, zname, p_idx) != CF_VMAPX_OK) { if (cf_vmapx_count(rd->ns->p_bin_name_vmap) >= BIN_NAMES_QUOTA) { cf_warning(AS_BIN, "{%s} bin-name quota full - can't add new bin-name %s", rd->ns->name, zname); *p_reserved = false; } else { cf_vmapx_err result = cf_vmapx_put_unique(rd->ns->p_bin_name_vmap, zname, p_idx); if (! (result == CF_VMAPX_OK || result == CF_VMAPX_ERR_NAME_EXISTS)) { cf_warning(AS_BIN, "{%s} can't add new bin name %s, vmap err %d", rd->ns->name, zname, result); *p_reserved = false; } } return NULL; } for (uint16_t i = 0; i < rd->n_bins; i++) { as_bin *b = &rd->bins[i]; if (! as_bin_inuse(b)) { break; } if ((uint32_t)b->id == *p_idx) { return b; } } return NULL; }
bool as_bin_name_within_quota(as_namespace *ns, const char *name) { // Won't exceed quota if single-bin or currently below quota. if (ns->single_bin || cf_vmapx_count(ns->p_bin_name_vmap) < BIN_NAMES_QUOTA) { return true; } // Won't exceed quota if name is found (and so would NOT be added to vmap). if (cf_vmapx_get_index(ns->p_bin_name_vmap, name, NULL) == CF_VMAPX_OK) { return true; } cf_warning(AS_BIN, "{%s} bin-name quota full - can't add new bin-name %s", ns->name, name); return false; }
int as_namespace_get_create_set(as_namespace *ns, const char *set_name, uint16_t *p_set_id, bool apply_restrictions) { if (! set_name) { // Should be impossible. cf_warning(AS_NAMESPACE, "null set name"); return -1; } uint32_t idx; cf_vmapx_err result = cf_vmapx_get_index(ns->p_sets_vmap, set_name, &idx); bool already_in_vmap = false; if (result == CF_VMAPX_OK) { already_in_vmap = true; } else if (result == CF_VMAPX_ERR_NAME_NOT_FOUND) { as_set set; memset(&set, 0, sizeof(set)); // Check name length just once, here at insertion. (Other vmap calls are // safe if name is too long - they return CF_VMAPX_ERR_NAME_NOT_FOUND.) strncpy(set.name, set_name, AS_SET_NAME_MAX_SIZE); if (set.name[AS_SET_NAME_MAX_SIZE - 1]) { set.name[AS_SET_NAME_MAX_SIZE - 1] = 0; cf_info(AS_NAMESPACE, "set name %s... too long", set.name); return -1; } set.num_elements = 1; result = cf_vmapx_put_unique(ns->p_sets_vmap, &set, &idx); if (result == CF_VMAPX_ERR_NAME_EXISTS) { already_in_vmap = true; } else if (result == CF_VMAPX_ERR_FULL) { cf_info(AS_NAMESPACE, "at set names limit, can't add %s", set.name); return -1; } else if (result != CF_VMAPX_OK) { // Currently, remaining errors are all some form of out-of-memory. cf_info(AS_NAMESPACE, "error %d, can't add %s", result, set.name); return -1; } } else { // Should be impossible. cf_warning(AS_NAMESPACE, "unexpected error %d", result); return -1; } if (already_in_vmap) { as_set *p_set; if ((result = cf_vmapx_get_by_index(ns->p_sets_vmap, idx, (void**)&p_set)) != CF_VMAPX_OK) { // Should be impossible - just verified idx. cf_warning(AS_NAMESPACE, "unexpected error %d", result); return -1; } // If requested, fail if emptying set or stop-writes limit is breached. if (apply_restrictions && (IS_SET_DELETED(p_set) || as_set_stop_writes(p_set))) { return -2; } // The set passed all tests - need to increment its num_elements. cf_atomic64_incr(&p_set->num_elements); } *p_set_id = (uint16_t)(idx + 1); return 0; }