ENGINE_ERROR_CODE assoc_prefix_link(struct default_engine *engine, hash_item *it, const size_t item_size, prefix_t **pfx_item) { assert(it->nprefix == 0); const char *key = item_get_key(it); size_t nkey = it->nkey; int prefix_depth = 0; int i = 0; char *token; prefix_t *pt = NULL; prefix_t_list_elem prefix_list[DEFAULT_PREFIX_MAX_DEPTH]; // prefix discovering: we don't even know prefix existence at this time while ((token = memchr(key + i + 1, engine->config.prefix_delimiter, nkey - i - 1)) != NULL) { i = token - key; prefix_list[prefix_depth].nprefix = i; prefix_depth++; if (prefix_depth >= DEFAULT_PREFIX_MAX_DEPTH) { break; } } if (prefix_depth == 0) { pt = root_pt; time(&pt->create_time); it->nprefix = nkey; } else { for (i = prefix_depth - 1; i >= 0; i--) { prefix_list[i].hash = engine->server.core->hash(key, prefix_list[i].nprefix, 0); pt = assoc_prefix_find(engine, prefix_list[i].hash, key, prefix_list[i].nprefix); if (pt != NULL) break; } if (i < (prefix_depth - 1)) { if (prefix_depth == 1) { if (!mc_isvalidname(key, prefix_list[0].nprefix)) { return ENGINE_PREFIX_ENAME; /* Invalid prefix name */ } } // need building prefixes if (pt != NULL && i >= 0) { prefix_list[i].pt = pt; // i >= 0 } for (int j = i + 1; j < prefix_depth; j++) { pt = (prefix_t*)malloc(sizeof(prefix_t) + prefix_list[j].nprefix + 1); if (pt == NULL) { for (j = j - 1; j >= i + 1; j--) { assert(prefix_list[j].pt != NULL); _prefix_delete(engine, prefix_list[j].hash, key, prefix_list[j].nprefix); } return ENGINE_ENOMEM; } // building a prefix_t memset(pt, 0, sizeof(prefix_t)); memcpy(pt + 1, key, prefix_list[j].nprefix); memcpy((char*)pt+sizeof(prefix_t)+prefix_list[j].nprefix, "\0", 1); pt->nprefix = prefix_list[j].nprefix; pt->parent_prefix = (j == 0 ? root_pt : prefix_list[j-1].pt); time(&pt->create_time); // registering allocated prefixes to prefix hastable _prefix_insert(engine, prefix_list[j].hash, pt); prefix_list[j].pt = pt; } } // update item information about prefix length it->nprefix = pt->nprefix; } assert(pt != NULL); // update prefix information if ((it->iflag & ITEM_IFLAG_LIST) != 0) { pt->list_hash_items++; pt->list_hash_items_bytes += item_size; } else if ((it->iflag & ITEM_IFLAG_SET) != 0) { pt->set_hash_items++; pt->set_hash_items_bytes += item_size; } else if ((it->iflag & ITEM_IFLAG_BTREE) != 0) { pt->btree_hash_items++; pt->btree_hash_items_bytes += item_size; } else { pt->hash_items++; pt->hash_items_bytes += item_size; } #if 0 // might be used later if (1) { curr_pt = pt->parent_prefix; while (curr_pt != NULL) { curr_pt->tot_hash_items++; curr_pt->tot_hash_items_bytes += item_size; curr_pt = curr_pt->parent_prefix; } } #endif *pfx_item = pt; return ENGINE_SUCCESS; }
/*@null@*/ static PREFIX_STATS *stats_prefix_find(const char *key, const size_t nkey) { PREFIX_STATS *pfs; uint32_t hashval; size_t length; char *token = NULL; int i = 0; int prefix_depth = 0; assert(key != NULL); while ((token = memchr(key + i + 1, settings.prefix_delimiter, nkey - i - 1)) != NULL) { i = token - key; prefix_depth++; if (prefix_depth >= PREFIX_MAX_DEPTH) { break; } } if (prefix_depth <= 0) { length = 0; } else { length = i; } hashval = mc_hash(key, length, 0) % PREFIX_HASH_SIZE; for (pfs = prefix_stats[hashval]; NULL != pfs; pfs = pfs->next) { if ((pfs->prefix_len==length) && (length==0 || strncmp(pfs->prefix, key, length)==0)) return pfs; } if (length > 0) { if (!mc_isvalidname(key, length)) { /* Invalid prefix name */ return NULL; } } pfs = calloc(sizeof(PREFIX_STATS), 1); if (NULL == pfs) { perror("Can't allocate space for stats structure: calloc"); return NULL; } pfs->prefix = malloc(length + 1); if (NULL == pfs->prefix) { perror("Can't allocate space for copy of prefix: malloc"); free(pfs); return NULL; } if (length > 0) strncpy(pfs->prefix, key, length); pfs->prefix[length] = '\0'; /* because strncpy() sucks */ pfs->prefix_len = length; pfs->next = prefix_stats[hashval]; prefix_stats[hashval] = pfs; num_prefixes++; if (length > 0) total_prefix_size += length; else /* length == 0 */ total_prefix_size += strlen(null_prefix_str); return pfs; }
ENGINE_ERROR_CODE assoc_prefix_link(struct default_engine *engine, hash_item *it, const size_t item_size) { const char *key = item_get_key(it); size_t nkey = it->nkey; int prefix_depth = 0; int i = 0; char *token; prefix_t *pt = NULL; prefix_t_list_elem prefix_list[DEFAULT_PREFIX_MAX_DEPTH]; // prefix discovering: we don't even know prefix existence at this time while ((token = memchr(key+i+1, engine->config.prefix_delimiter, nkey-i-1)) != NULL) { i = token - key; prefix_list[prefix_depth].nprefix = i; prefix_depth++; if (prefix_depth >= DEFAULT_PREFIX_MAX_DEPTH) { break; } } if (prefix_depth == 0) { pt = root_pt; time(&pt->create_time); /* save prefix pointer in hash_item */ it->pfxptr = pt; } else { for (i = prefix_depth - 1; i >= 0; i--) { prefix_list[i].hash = engine->server.core->hash(key, prefix_list[i].nprefix, 0); pt = assoc_prefix_find(engine, prefix_list[i].hash, key, prefix_list[i].nprefix); if (pt != NULL) break; } if (i < (prefix_depth - 1)) { if (prefix_depth == 1) { if (!mc_isvalidname(key, prefix_list[0].nprefix)) { return ENGINE_PREFIX_ENAME; /* Invalid prefix name */ } } // need building prefixes if (pt != NULL && i >= 0) { prefix_list[i].pt = pt; // i >= 0 } for (int j = i + 1; j < prefix_depth; j++) { pt = (prefix_t*)malloc(sizeof(prefix_t) + prefix_list[j].nprefix + 1); if (pt == NULL) { for (j = j - 1; j >= i + 1; j--) { assert(prefix_list[j].pt != NULL); _prefix_delete(engine, prefix_list[j].hash, key, prefix_list[j].nprefix); } return ENGINE_ENOMEM; } // building a prefix_t memset(pt, 0, sizeof(prefix_t)); memcpy(pt + 1, key, prefix_list[j].nprefix); memcpy((char*)pt+sizeof(prefix_t)+prefix_list[j].nprefix, "\0", 1); pt->nprefix = prefix_list[j].nprefix; if (PREFIX_IS_RSVD(key, pt->nprefix)) { pt->internal = 1; /* internal prefix */ } pt->parent_prefix = (j == 0 ? root_pt : prefix_list[j-1].pt); time(&pt->create_time); // registering allocated prefixes to prefix hastable _prefix_insert(engine, prefix_list[j].hash, pt); prefix_list[j].pt = pt; } } /* save prefix pointer in hash_item */ it->pfxptr = pt; } assert(pt != NULL); /* update prefix information */ int item_type = GET_ITEM_TYPE(it); pt->items_count[item_type] += 1; pt->items_bytes[item_type] += item_size; pt->total_count_exclusive += 1; pt->total_bytes_exclusive += item_size; #if 0 // might be used later if (1) { prefix_t *curr_pt = pt->parent_prefix; while (curr_pt != NULL) { curr_pt->total_count_inclusive += 1; curr_pt->total_bytes_inclusive += item_size; curr_pt = curr_pt->parent_prefix; } } #endif return ENGINE_SUCCESS; }