// this is only used when this node is the first node in the cluster, and we need to create some new empty buckets. void buckets_init(hash_t mask, struct event_base *evbase) { int i; assert(_evbase == NULL); assert(evbase); _evbase = evbase; assert(_mask == 0); assert(mask >= _mask); _mask = mask; assert(_mask > 0); _buckets = calloc(_mask+1, sizeof(bucket_t *)); assert(_buckets); assert(_primary_buckets == 0); assert(_secondary_buckets == 0); // for starters we will need to create a bucket for each hash. for (i=0; i<=_mask; i++) { _buckets[i] = bucket_new(i); _primary_buckets ++; _buckets[i]->level = 0; // send out a message to all connected clients, to let them know that the buckets have changed. update_hashmasks(_buckets[i]); // all_hashmask(i, 0); } // indicate that we have buckets that do not have backup copies on other nodes. _nobackup_buckets = _mask + 1; }
/* * heap_buckets_init -- (internal) initializes bucket instances */ int heap_buckets_init(struct palloc_heap *heap) { struct heap_rt *h = heap->rt; for (uint8_t i = 0; i < MAX_ALLOCATION_CLASSES; ++i) { struct alloc_class *c = alloc_class_by_id(h->alloc_classes, i); if (c != NULL) { if (heap_create_alloc_class_buckets(heap, c) != 0) goto error_bucket_create; } } h->default_bucket = bucket_new(container_new_ctree(heap), alloc_class_by_id(h->alloc_classes, DEFAULT_ALLOC_CLASS_ID)); if (h->default_bucket == NULL) goto error_bucket_create; heap_populate_buckets(heap); return 0; error_bucket_create: for (unsigned i = 0; i < h->ncaches; ++i) bucket_group_destroy(h->caches[i].buckets); return -1; }
int htable_add(htable* ht, void* key, size_t keylen, void* data, size_t dlen) { // {{{ if (htable_load_factor(ht) > LOAD_FACTOR) htable_grow(ht); int hval; bucket** b = htable_find_pbucket(ht, key, keylen, &hval); if (*b) return HTABLE_NOT_FOUND; *b = bucket_new(key, keylen, data, dlen, hval); ht->entries++; return HTABLE_FOUND; } // }}}
void htable_set(htable* ht, void* key, size_t keylen, void* data, size_t dlen) { // {{{ if (htable_load_factor(ht) > LOAD_FACTOR) htable_grow(ht); int hval; bucket** b = htable_find_pbucket(ht, key, keylen, &hval); if (*b) { free(b[0]->data); b[0]->data = xmemdup(data, dlen); b[0]->dlen = dlen; } else { *b = bucket_new(key, keylen, data, dlen, hval); ht->entries++; } } // }}}
/* * heap_create_alloc_class_buckets -- (internal) allocates all cache bucket * instances of the specified type */ static int heap_create_alloc_class_buckets(struct palloc_heap *heap, struct alloc_class *c) { struct heap_rt *h = heap->rt; int i; for (i = 0; i < (int)h->ncaches; ++i) { h->caches[i].buckets[c->id] = bucket_new( container_new_seglists(heap), c); if (h->caches[i].buckets[c->id] == NULL) goto error_cache_bucket_new; } return 0; error_cache_bucket_new: for (i -= 1; i >= 0; --i) { bucket_delete(h->caches[i].buckets[c->id]); } return -1; }
void dict_set(dict* d, char* key, void* item) { int index = hash(key, d->size); struct bucket* b = d->buckets[index]; struct bucket** p = &d->buckets[index]; while(true) { if (b == NULL) { *p = bucket_new(key, item); return; } if( strcmp(b->key, key) == 0) { b->item = item; return; } p = &b->next; b = b->next; } }
int test_file(FILE *fp, int argc, char **argv) { char buf[65535 + 1]; char *pos; unsigned int strategy = 0; /* what bucketing strategy we're using */ void *ptr = NULL; unsigned int bucketsize = 0; struct params params = {0}; struct chash *hash = NULL; char name[256]; if (!parse_params(argc, argv, ¶ms)) { fprintf(stderr, "failed to parse params\n"); return 0; } while (fgets((char *) buf, 65535, fp)) { str_rtrim(buf); pos = (char *) str_ltrim(buf); if (!str_casecmp(pos, "new")) { /* creating a new bucket */ unsigned int size = -1; if (ptr) { chash_delete(hash); free(ptr); } /* read parameters */ if ((fscanf(fp, "%255s %u %u", name, &strategy, &size) == 3) && (size <= 65535) && (bucketsize = size) && (ptr = malloc(size)) && (hash = chash_ptr_new(1, 2.0, /* some fn pointer casting dodginess */ (unsigned int (*)(const void *)) str_len, (int (*)(const void *, const void *)) str_cmp)) && (bucket_new(ptr, bucketsize, strategy))) { /* succeeded, do nothing */ if (params.verbose) { printf("%s: new bucket with size %u strategy %u\n", name, size, strategy); } } else { fprintf(stderr, "%s: failed to create bucket\n", name); return 0; } } else if (!str_casecmp(pos, "add")) { /* adding a term to the bucket */ void *ret; unsigned int veclen, succeed, len; int toobig; if (!ptr) { return 0; } /* read parameters */ if ((fscanf(fp, "%65535s %u %u", buf, &veclen, &succeed) == 3) && (veclen <= 65535)) { len = str_len(buf); if ((((ret = bucket_alloc(ptr, bucketsize, strategy, buf, len, veclen, &toobig, NULL)) && succeed) || (!ret && !succeed))) { /* do nothing */ if (params.verbose) { printf("%s: added term '%s'\n", name, buf); } } else if (succeed) { fprintf(stderr, "%s: failed to add '%s' to bucket\n", name, buf); return 0; } else if (!succeed) { fprintf(stderr, "%s: add '%s' succeeded but shouldn't " "have\n", name, buf); return 0; } } else { fprintf(stderr, "%s: failed to add\n", name); return 0; } } else if (!str_casecmp(pos, "ls")) { /* matching stuff in the bucket */ unsigned int numterms, i, len, veclen, veclen2, state; void *addr; struct chash *tmphash; const char *term; void **tmpptr, *tmp; if (!ptr) { return 0; } if (!(tmphash = chash_ptr_new(1, 2.0, /* some fn pointer casting dodginess */ (unsigned int (*)(const void *)) str_len, (int (*)(const void *, const void *)) str_cmp))) { fprintf(stderr, "%s: failed to init hashtable\n", name); return 0; } /* first, fill hashtable with all terms from bucket */ state = 0; while ((term = bucket_next_term(ptr, bucketsize, strategy, &state, &len, &addr, &veclen))) { if (!((term = str_ndup(term, len)) && (chash_ptr_ptr_insert(tmphash, term, (void*) term) == CHASH_OK))) { fprintf(stderr, "%s: failed to init hashtable\n", name); return 0; } } /* now, take terms from file, comparing them with hashtable * entries */ if (fscanf(fp, "%u", &numterms)) { for (i = 0; i < numterms; i++) { if (fscanf(fp, "%65535s %u ", buf, &veclen)) { if (params.verbose) { printf("%s: ls checking %s\n", name, buf); } if ((addr = bucket_find(ptr, bucketsize, strategy, buf, str_len(buf), &veclen2, NULL)) /* remove it from hashtable */ && chash_ptr_ptr_find(tmphash, buf, &tmpptr) == CHASH_OK && chash_ptr_ptr_remove(tmphash, *tmpptr, &tmp) == CHASH_OK && (free(tmp), 1) && (veclen <= 65535) && (veclen2 == veclen) && fread(buf, veclen, 1, fp) && ((buf[veclen] = '\0'), 1) && (!params.verbose || printf("%s: ls check read '%s'\n", name, buf)) && !memcmp(buf, addr, veclen)) { /* do nothing */ } else { unsigned int j; fprintf(stderr, "%s: ls failed cmp '%s' with '", name, buf); for (j = 0; j < veclen; j++) { putc(((char *) addr)[j], stderr); } fprintf(stderr, "'\n"); return 0; } } else { fprintf(stderr, "%s: ls failed\n", name); return 0; } } if (chash_size(tmphash)) { fprintf(stderr, "%s: ls failed\n", name); return 0; } } else { fprintf(stderr, "%s: ls failed\n", name); return 0; } chash_delete(tmphash); if (params.verbose) { printf("%s: matched all (%u) entries\n", name, numterms); } } else if (!str_casecmp(pos, "set")) { /* setting the vector for a term in the bucket */ unsigned int veclen, reallen; void *addr; if (!ptr) { return 0; } /* read parameters */ if ((fscanf(fp, "%65535s %u ", buf, &veclen) == 2) && (veclen <= 65535)) { addr = bucket_find(ptr, bucketsize, strategy, buf, str_len(buf), &reallen, NULL); if (addr && (reallen == veclen) && fread(addr, 1, veclen, fp)) { /* do nothing */ if (params.verbose) { unsigned int j; printf("%s: set term '%s' to '", name, buf); for (j = 0; j < reallen; j++) { putc(((char *) addr)[j], stdout); } printf("'\n"); } } else { fprintf(stderr, "%s: failed to set!\n", name); return 0; } } else { fprintf(stderr, "%s: failed to set\n", name); return 0; } } else if (!str_casecmp(pos, "realloc")) { /* reallocating a term in the bucket */ unsigned int veclen, succeed; int toobig; if (!ptr) { return 0; } /* read parameters */ if ((fscanf(fp, "%65535s %u %u", buf, &veclen, &succeed) == 3) && (veclen <= 65535)) { if (!bucket_realloc(ptr, bucketsize, strategy, buf, str_len(buf), veclen, &toobig)) { fprintf(stderr, "%s: failed to realloc!\n", name); return 0; } } else { fprintf(stderr, "%s: failed to realloc\n", name); return 0; } if (params.verbose) { printf("%s: realloc'd term '%s'\n", name, buf); } } else if (!str_casecmp(pos, "rm")) { /* removing something from the bucket */ unsigned int succeed; if (!ptr) { return 0; } if (fscanf(fp, "%65535s %u", buf, &succeed) == 2) { if (succeed) { if (!(bucket_remove(ptr, bucketsize, strategy, buf, str_len(buf)))) { fprintf(stderr, "%s: failed to rm '%s'\n", name, buf); return 0; } else if (params.verbose) { printf("%s: rm term '%s'\n", name, buf); } } else if (succeed) { fprintf(stderr, "%s: failed to rm\n", name); return 0; } } else { fprintf(stderr, "%s: failed to rm\n", name); return 0; } } else if (!str_casecmp(pos, "print")) { /* printing out the bucket contents */ unsigned int state = 0, len, veclen; const char *term; char format[100]; void *addr; if (!ptr) { printf("can't print, no bucket\n"); } else { do { term = bucket_next_term(ptr, bucketsize, strategy, &state, &len, &addr, &veclen); } while (term && memcpy(buf, term, len) && ((buf[len] = '\0') || 1) && snprintf(format, 100, "%%.%us (%%u): '%%.%us' (%%u) " "(off %%u)\n", len, veclen) && printf(format, term, len, (char*) addr, veclen, ((char *) addr) - (char *) ptr)); if (!state) { printf("(empty)\n"); } printf("%u entries, %u data, %u string, %u overhead, %u free\n", bucket_entries(ptr, bucketsize, strategy), bucket_utilised(ptr, bucketsize, strategy), bucket_string(ptr, bucketsize, strategy), bucket_overhead(ptr, bucketsize, strategy), bucket_unused(ptr, bucketsize, strategy)); } } else if (!str_casecmp(pos, "match")) { unsigned int veclen, veclen2; void *addr; if (fscanf(fp, "%65535s %u ", buf, &veclen)) { if ((addr = bucket_find(ptr, bucketsize, strategy, buf, str_len(buf), &veclen2, NULL)) && (veclen <= 65535) && (veclen2 >= veclen) && (!params.verbose || printf("%s: match on '%s' ", name, buf)) && fread(buf, veclen, 1, fp) && !memcmp(buf, addr, veclen)) { if (params.verbose) { printf("content succeeded\n"); } } else { fprintf(stderr, "%s: match failed (%s vs %s)\n", name, buf, (char *) addr); return 0; } } else { fprintf(stderr, "%s: match failed\n", name); return 0; } } else if ((*pos != '#') && str_len(pos)) { fprintf(stderr, "%s: unknown command '%s'\n", name, pos); return 0; } } if (ptr) { chash_delete(hash); free(ptr); } return 1; }
int buckets_accept_bucket(client_t *client, hash_t mask, hash_t hashmask) { int accepted = -1; assert(client); assert(mask > 0); if (_bucket_transfer) { // we are currently transferring another bucket, therefore we cannot accept another one. logger(LOG_WARN, "cant accept bucket, already transferring one."); accepted = 0; } else { assert(_bucket_transfer == NULL); if (mask != _mask) { // the masks are different, we cannot accept a bucket unless our masks match... which should // balance out once hashmasks have proceeded through all the nodes. logger(LOG_WARN, "cant accept bucket, masks are not compatible."); accepted = 0; } else { // now we need to check that this bucket isn't already handled by this server. assert(hashmask <= mask); assert(_mask == mask); // if we dont currently have a buckets list, we need to create one. if (_buckets == NULL) { _buckets = calloc(_mask + 1, sizeof(bucket_t *)); assert(_buckets); assert(_buckets[0] == NULL); assert(_primary_buckets == 0); assert(_secondary_buckets == 0); } assert(_buckets); if (_buckets[hashmask]) { logger(LOG_ERROR, "cant accept bucket, already have that bucket."); accepted = 0; } else { logger(LOG_INFO, "accepting bucket. (%#llx/%#llx)", mask, hashmask); // need to create the bucket, and mark it as in-transit. bucket_t *bucket = bucket_new(hashmask); assert(bucket); _buckets[hashmask] = bucket; assert(data_in_transit() == 0); assert(bucket->transfer_client == NULL); assert(client->node); logger(LOG_DEBUG, "Setting transfer client ('%s') to bucket %#llx.", node_name(client->node), bucket->hashmask); bucket->transfer_client = client; assert(bucket->level < 0); accepted = 1; assert(_bucket_transfer == NULL); _bucket_transfer = bucket; } } } assert(accepted == 0 || accepted == 1); return(accepted); }
// this function will take the current array, and put it aside, creating a new array based on the // new mask supplied (we can only make the mask bigger, and cannot shrink it). // We create a new array, and for each entry, we compare it against the old mask, and use // the data for that hash from the old list. // NOTE: We may be starting off with an empty lists. If this is the first time we've // received some hashmasks. To implement this easily, if we dont already have hashmasks, we // may need to create one that has a dummy entry in it. void buckets_split_mask(hash_t current_mask, hash_t new_mask) { bucket_t **newbuckets = NULL; bucket_t **oldbuckets = NULL; int i; int index; assert(new_mask > current_mask); logger(LOG_INFO, "Splitting Mask: Old Mask: %#llx, New Mask; %#llx", current_mask, new_mask); // grab a copy of the existing buckets as the 'oldbuckets'; oldbuckets = _buckets; _buckets = NULL; // make an appropriate sized new buckets list; newbuckets = malloc(sizeof(bucket_t *) * (new_mask+1)); assert(newbuckets); // go through every hash for this mask. for (i=0; i<=new_mask; i++) { // determine what the old index is. index = i & current_mask; // create the new bucket ONLY if we already have a bucket object for that index. if (oldbuckets == NULL || oldbuckets[index] == NULL) { newbuckets[i] = NULL; } else { // we have a bucket for this old index. So we need to create a new one for this index. newbuckets[i] = bucket_new(i); assert(newbuckets[i]->data); assert(newbuckets[i]->data->next == NULL); assert(oldbuckets[index]->data); assert(oldbuckets[index]->data->ref > 0); newbuckets[i]->data->next = oldbuckets[index]->data; oldbuckets[index]->data->ref ++; assert(newbuckets[i]->hashmask == i); newbuckets[i]->level = oldbuckets[index]->level; newbuckets[i]->source_node = oldbuckets[index]->source_node; newbuckets[i]->backup_node = oldbuckets[index]->backup_node; newbuckets[i]->logging_node = oldbuckets[index]->logging_node; newbuckets[i]->primary_node = oldbuckets[index]->primary_node; newbuckets[i]->secondary_node = oldbuckets[index]->secondary_node; assert(data_in_transit() == 0); } } assert(_mask >= 0); assert(new_mask > _mask); _mask = new_mask; // clean up the old buckets list. if (oldbuckets) { for (i=0; i<=_mask; i++) { if (oldbuckets[i]) { assert(oldbuckets[i]->data); assert(oldbuckets[i]->data->ref > 1); oldbuckets[i]->data->ref --; assert(oldbuckets[i]->data->ref > 0); oldbuckets[i]->data = NULL; bucket_close(oldbuckets[i]); } } } _buckets = newbuckets; assert(_buckets); }
/* * heap_buckets_init -- (internal) initializes bucket instances */ static int heap_buckets_init(PMEMobjpool *pop) { struct pmalloc_heap *h = pop->heap; int i; //printf("calling heap_buckets_init \n"); bucket_proto[0].unit_max = RUN_UNIT_MAX; /* * To take use of every single bit available in the run the unit size * would have to be calculated using following expression: * (RUNSIZE / (MAX_BITMAP_VALUES * BITS_PER_VALUE)), but to preserve * cacheline alignment a little bit of memory at the end of the run * is left unused. */ bucket_proto[0].unit_size = MIN_RUN_SIZE; for (i = 1; i < MAX_BUCKETS - 1; ++i) { bucket_proto[i].unit_max = RUN_UNIT_MAX; bucket_proto[i].unit_size = bucket_proto[i - 1].unit_size * bucket_proto[i - 1].unit_max; } bucket_proto[i].unit_max = -1; bucket_proto[i].unit_size = CHUNKSIZE; h->last_run_max_size = bucket_proto[i - 1].unit_size * (bucket_proto[i - 1].unit_max - 1); h->bucket_map = Malloc(sizeof (*h->bucket_map) * h->last_run_max_size); if (h->bucket_map == NULL) goto error_bucket_map_malloc; for (i = 0; i < MAX_BUCKETS; ++i) { h->buckets[i] = bucket_new(bucket_proto[i].unit_size, bucket_proto[i].unit_max); if (h->buckets[i] == NULL) goto error_bucket_new; } /* XXX better way to fill the bucket map */ for (i = 0; i < h->last_run_max_size; ++i) { for (int j = 0; j < MAX_BUCKETS - 1; ++j) { /* * Skip the last unit, so that the distribution * of buckets in the map is better. */ if ((bucket_proto[j].unit_size * ((bucket_proto[j].unit_max - 1))) >= i) { h->bucket_map[i] = h->buckets[j]; break; } } } heap_populate_buckets(pop); return 0; error_bucket_new: Free(h->bucket_map); for (i = i - 1; i >= 0; --i) bucket_delete(h->buckets[i]); error_bucket_map_malloc: return ENOMEM; }