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)
99 logger->
log(EXTENSION_LOG_WARNING, NULL,
100 "Can't create thread: %s\n", strerror(ret));
101 engine->assoc.hashpower--;
102 engine->assoc.expanding =
false;
103 free(engine->assoc.primary_hashtable);
104 engine->assoc.primary_hashtable =engine->assoc.old_hashtable;
107 engine->assoc.primary_hashtable = engine->assoc.old_hashtable;
114 unsigned int oldbucket;
116 assert(assoc_find(engine, hash, item_get_key(it), it->
nkey) == 0);
118 if (engine->assoc.expanding &&
119 (oldbucket = (hash & hashmask(engine->assoc.hashpower - 1))) >= engine->assoc.expand_bucket)
121 it->h_next = engine->assoc.old_hashtable[oldbucket];
122 engine->assoc.old_hashtable[oldbucket] = it;
124 it->h_next = engine->assoc.primary_hashtable[hash & hashmask(engine->assoc.hashpower)];
125 engine->assoc.primary_hashtable[hash & hashmask(engine->assoc.hashpower)] = it;
128 engine->assoc.hash_items++;
129 if (! engine->assoc.expanding && engine->assoc.hash_items > (hashsize(engine->assoc.hashpower) * 3) / 2) {
130 assoc_expand(engine);
133 MEMCACHED_ASSOC_INSERT(item_get_key(it), it->
nkey, engine->assoc.hash_items);
137 void assoc_delete(
struct default_engine *engine, uint32_t hash,
const char *key,
const size_t nkey) {
138 hash_item **before = _hashitem_before(engine, hash, key, nkey);
142 engine->assoc.hash_items--;
146 MEMCACHED_ASSOC_DELETE(key, nkey, engine->assoc.hash_items);
147 nxt = (*before)->h_next;
148 (*before)->h_next = 0;
154 assert(*before != 0);
159 #define DEFAULT_HASH_BULK_MOVE 1
160 int hash_bulk_move = DEFAULT_HASH_BULK_MOVE;
162 static void *assoc_maintenance_thread(
void *arg) {
169 for (ii = 0; ii < hash_bulk_move && engine->assoc.expanding; ++ii) {
173 for (it = engine->assoc.old_hashtable[engine->assoc.expand_bucket];
174 NULL != it; it = next) {
177 bucket = engine->server.core->
hash(item_get_key(it), it->
nkey, 0)
178 & hashmask(engine->assoc.hashpower);
179 it->h_next = engine->assoc.primary_hashtable[bucket];
180 engine->assoc.primary_hashtable[bucket] = it;
183 engine->assoc.old_hashtable[engine->assoc.expand_bucket] = NULL;
184 engine->assoc.expand_bucket++;
185 if (engine->assoc.expand_bucket == hashsize(engine->assoc.hashpower - 1)) {
186 engine->assoc.expanding =
false;
187 free(engine->assoc.old_hashtable);
188 if (engine->config.verbose > 1) {
191 logger->
log(EXTENSION_LOG_INFO, NULL,
192 "Hash table expansion done\n");
196 if (!engine->assoc.expanding) {