15 #include "default_engine.h"
17 #define hashsize(n) ((uint32_t)1<<(n))
18 #define hashmask(n) (hashsize(n)-1)
21 engine->assoc.primary_hashtable = calloc(hashsize(engine->assoc.hashpower),
sizeof(
void *));
22 return (engine->assoc.primary_hashtable != NULL) ? ENGINE_SUCCESS : ENGINE_ENOMEM;
27 unsigned int oldbucket;
29 if (engine->assoc.expanding &&
30 (oldbucket = (hash & hashmask(engine->assoc.hashpower - 1))) >= engine->assoc.expand_bucket)
32 it = engine->assoc.old_hashtable[oldbucket];
34 it = engine->assoc.primary_hashtable[hash & hashmask(engine->assoc.hashpower)];
40 if ((nkey == it->
nkey) && (memcmp(key, item_get_key(it), nkey) == 0)) {
47 MEMCACHED_ASSOC_FIND(key, nkey, depth);
59 unsigned int oldbucket;
61 if (engine->assoc.expanding &&
62 (oldbucket = (hash & hashmask(engine->assoc.hashpower - 1))) >= engine->assoc.expand_bucket)
64 pos = &engine->assoc.old_hashtable[oldbucket];
66 pos = &engine->assoc.primary_hashtable[hash & hashmask(engine->assoc.hashpower)];
69 while (*pos && ((nkey != (*pos)->nkey) || memcmp(key, item_get_key(*pos), nkey))) {
70 pos = &(*pos)->h_next;
75 static void *assoc_maintenance_thread(
void *arg);
79 engine->assoc.old_hashtable = engine->assoc.primary_hashtable;
81 engine->assoc.primary_hashtable = calloc(hashsize(engine->assoc.hashpower + 1),
sizeof(
void *));
82 if (engine->assoc.primary_hashtable) {
83 engine->assoc.hashpower++;
84 engine->assoc.expanding =
true;
85 engine->assoc.expand_bucket = 0;
92 if (pthread_attr_init(&attr) != 0 ||
93 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0 ||
94 (ret = pthread_create(&tid, &attr,
95 assoc_maintenance_thread, engine)) != 0)
97 fprintf(stderr,
"Can't create thread: %s\n", strerror(ret));
98 engine->assoc.hashpower--;
99 engine->assoc.expanding =
false;
100 free(engine->assoc.primary_hashtable);
101 engine->assoc.primary_hashtable =engine->assoc.old_hashtable;
104 engine->assoc.primary_hashtable = engine->assoc.old_hashtable;
111 unsigned int oldbucket;
113 assert(assoc_find(engine, hash, item_get_key(it), it->
nkey) == 0);
115 if (engine->assoc.expanding &&
116 (oldbucket = (hash & hashmask(engine->assoc.hashpower - 1))) >= engine->assoc.expand_bucket)
118 it->h_next = engine->assoc.old_hashtable[oldbucket];
119 engine->assoc.old_hashtable[oldbucket] = it;
121 it->h_next = engine->assoc.primary_hashtable[hash & hashmask(engine->assoc.hashpower)];
122 engine->assoc.primary_hashtable[hash & hashmask(engine->assoc.hashpower)] = it;
125 engine->assoc.hash_items++;
126 if (! engine->assoc.expanding && engine->assoc.hash_items > (hashsize(engine->assoc.hashpower) * 3) / 2) {
127 assoc_expand(engine);
130 MEMCACHED_ASSOC_INSERT(item_get_key(it), it->
nkey, engine->assoc.hash_items);
134 void assoc_delete(
struct default_engine *engine, uint32_t hash,
const char *key,
const size_t nkey) {
135 hash_item **before = _hashitem_before(engine, hash, key, nkey);
139 engine->assoc.hash_items--;
143 MEMCACHED_ASSOC_DELETE(key, nkey, engine->assoc.hash_items);
144 nxt = (*before)->h_next;
145 (*before)->h_next = 0;
151 assert(*before != 0);
156 #define DEFAULT_HASH_BULK_MOVE 1
157 int hash_bulk_move = DEFAULT_HASH_BULK_MOVE;
159 static void *assoc_maintenance_thread(
void *arg) {
166 for (ii = 0; ii < hash_bulk_move && engine->assoc.expanding; ++ii) {
170 for (it = engine->assoc.old_hashtable[engine->assoc.expand_bucket];
171 NULL != it; it = next) {
174 bucket = engine->server.core->
hash(item_get_key(it), it->
nkey, 0)
175 & hashmask(engine->assoc.hashpower);
176 it->h_next = engine->assoc.primary_hashtable[bucket];
177 engine->assoc.primary_hashtable[bucket] = it;
180 engine->assoc.old_hashtable[engine->assoc.expand_bucket] = NULL;
181 engine->assoc.expand_bucket++;
182 if (engine->assoc.expand_bucket == hashsize(engine->assoc.hashpower - 1)) {
183 engine->assoc.expanding =
false;
184 free(engine->assoc.old_hashtable);
185 if (engine->config.verbose > 1) {
186 fprintf(stderr,
"Hash table expansion done\n");
190 if (!engine->assoc.expanding) {