Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 291 lines (245 sloc) 8.784 kb
825db0f9 » bradfitz
2003-06-20 stop using Judy for string mappings and use a hash table instead, which
1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 * Hash table
4 *
5 * The hash function used here is by Bob Jenkins, 1996:
6 * <http://burtleburtle.net/bob/hash/doobs.html>
93c6642e » bradfitz
2006-09-04 whitespace changes only
7 * "By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net.
1ea89bd5 » bradfitz
2006-09-04 remove all trailing whitespace, not just first occurrence. :)
8 * You may use this code any way you wish, private, educational,
825db0f9 » bradfitz
2003-06-20 stop using Judy for string mappings and use a hash table instead, which
9 * or commercial. It's free."
10 *
11 * The rest of the file is licensed under the BSD license. See LICENSE.
12 */
56b8339e » Steven Grimm
2007-04-16 Merge multithreaded into trunk, commit #2 (first commit only did the
13
14 #include "memcached.h"
825db0f9 » bradfitz
2003-06-20 stop using Judy for string mappings and use a hash table instead, which
15 #include <sys/stat.h>
16 #include <sys/socket.h>
17 #include <sys/signal.h>
18 #include <sys/resource.h>
19 #include <fcntl.h>
c6975ef4 » Paul Lindner
2007-04-16 Part 1 of the Windows compatibility patch
20 #include <netinet/in.h>
21 #include <errno.h>
825db0f9 » bradfitz
2003-06-20 stop using Judy for string mappings and use a hash table instead, which
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
18a72ad2 » bradfitz
2003-06-27 version 1.1.6
25 #include <assert.h>
7f09e20b » Trond Norbye
2009-01-27 Do hash expansion in it's own thread
26 #include <pthread.h>
27
28 static pthread_cond_t maintenance_cond = PTHREAD_COND_INITIALIZER;
29
86969ea4 » bradfitz
2006-09-04 restore blank lines I over-zealously destroyed earlier.
30
217dcce0 » Steven Grimm
2006-11-26 Incorporate changes from "performance" branch (revisions 414-419).
31 typedef unsigned long int ub4; /* unsigned 4-byte quantities */
32 typedef unsigned char ub1; /* unsigned 1-byte quantities */
33
34 /* how many powers of 2's worth of buckets we use */
1c94e12c » dormando
2012-08-18 item locks now lock hash table buckets
35 unsigned int hashpower = HASHPOWER_DEFAULT;
217dcce0 » Steven Grimm
2006-11-26 Incorporate changes from "performance" branch (revisions 414-419).
36
37 #define hashsize(n) ((ub4)1<<(n))
38 #define hashmask(n) (hashsize(n)-1)
39
40 /* Main hash table. This is where we look except during expansion. */
41 static item** primary_hashtable = 0;
42
43 /*
44 * Previous hash table. During expansion, we look here for keys that haven't
45 * been moved over to the primary yet.
46 */
47 static item** old_hashtable = 0;
48
49 /* Number of items in the hash table. */
44ef96ee » Paul Lindner
2007-07-09 gcc -pedantic changes, comments, signed/unsigned changes. also conver…
50 static unsigned int hash_items = 0;
217dcce0 » Steven Grimm
2006-11-26 Incorporate changes from "performance" branch (revisions 414-419).
51
52 /* Flag: Are we in the middle of expanding now? */
44ef96ee » Paul Lindner
2007-07-09 gcc -pedantic changes, comments, signed/unsigned changes. also conver…
53 static bool expanding = false;
1c94e12c » dormando
2012-08-18 item locks now lock hash table buckets
54 static bool started_expanding = false;
217dcce0 » Steven Grimm
2006-11-26 Incorporate changes from "performance" branch (revisions 414-419).
55
56 /*
57 * During expansion we migrate values with bucket granularity; this is how
58 * far we've gotten so far. Ranges from 0 .. hashsize(hashpower - 1) - 1.
59 */
44ef96ee » Paul Lindner
2007-07-09 gcc -pedantic changes, comments, signed/unsigned changes. also conver…
60 static unsigned int expand_bucket = 0;
86969ea4 » bradfitz
2006-09-04 restore blank lines I over-zealously destroyed earlier.
61
1db1de38 » dormando
2011-09-28 Allow setting initial size of the hash table
62 void assoc_init(const int hashtable_init) {
63 if (hashtable_init) {
64 hashpower = hashtable_init;
65 }
984053cd » dustin
2008-06-18 Use calloc for allocating the hash table vs. malloc+memset.
66 primary_hashtable = calloc(hashsize(hashpower), sizeof(void *));
217dcce0 » Steven Grimm
2006-11-26 Incorporate changes from "performance" branch (revisions 414-419).
67 if (! primary_hashtable) {
825db0f9 » bradfitz
2003-06-20 stop using Judy for string mappings and use a hash table instead, which
68 fprintf(stderr, "Failed to init hashtable.\n");
c8425072 » Paul Lindner
2007-04-12 use EXIT_* constants
69 exit(EXIT_FAILURE);
825db0f9 » bradfitz
2003-06-20 stop using Judy for string mappings and use a hash table instead, which
70 }
108e2cd6 » dormando
2011-09-28 expose stats for the internal hash table
71 STATS_LOCK();
72 stats.hash_power_level = hashpower;
73 stats.hash_bytes = hashsize(hashpower) * sizeof(void *);
74 STATS_UNLOCK();
825db0f9 » bradfitz
2003-06-20 stop using Judy for string mappings and use a hash table instead, which
75 }
86969ea4 » bradfitz
2006-09-04 restore blank lines I over-zealously destroyed earlier.
76
bab9acd1 » dormando
2011-10-02 move hash calls outside of cache_lock
77 item *assoc_find(const char *key, const size_t nkey, const uint32_t hv) {
217dcce0 » Steven Grimm
2006-11-26 Incorporate changes from "performance" branch (revisions 414-419).
78 item *it;
44ef96ee » Paul Lindner
2007-07-09 gcc -pedantic changes, comments, signed/unsigned changes. also conver…
79 unsigned int oldbucket;
217dcce0 » Steven Grimm
2006-11-26 Incorporate changes from "performance" branch (revisions 414-419).
80
81 if (expanding &&
82 (oldbucket = (hv & hashmask(hashpower - 1))) >= expand_bucket)
83 {
84 it = old_hashtable[oldbucket];
85 } else {
86 it = primary_hashtable[hv & hashmask(hashpower)];
87 }
86969ea4 » bradfitz
2006-09-04 restore blank lines I over-zealously destroyed earlier.
88
68957214 » Trond Norbye
2008-07-23 Add DTrace probes for Solaris/etc.
89 item *ret = NULL;
90 int depth = 0;
f6d334e0 » bradfitz
2003-06-20 2003-06-10
91 while (it) {
68957214 » Trond Norbye
2008-07-23 Add DTrace probes for Solaris/etc.
92 if ((nkey == it->nkey) && (memcmp(key, ITEM_key(it), nkey) == 0)) {
93 ret = it;
94 break;
217dcce0 » Steven Grimm
2006-11-26 Incorporate changes from "performance" branch (revisions 414-419).
95 }
f6d334e0 » bradfitz
2003-06-20 2003-06-10
96 it = it->h_next;
68957214 » Trond Norbye
2008-07-23 Add DTrace probes for Solaris/etc.
97 ++depth;
825db0f9 » bradfitz
2003-06-20 stop using Judy for string mappings and use a hash table instead, which
98 }
80ec0955 » Trond Norbye
2008-10-02 Add DTrace probes to the binary protocol
99 MEMCACHED_ASSOC_FIND(key, nkey, depth);
68957214 » Trond Norbye
2008-07-23 Add DTrace probes for Solaris/etc.
100 return ret;
825db0f9 » bradfitz
2003-06-20 stop using Judy for string mappings and use a hash table instead, which
101 }
86969ea4 » bradfitz
2006-09-04 restore blank lines I over-zealously destroyed earlier.
102
7917af40 » bradfitz
2003-06-22 misc fixes as suggested by avva. lot of comment updates, mostly.
103 /* returns the address of the item pointer before the key. if *item == 0,
104 the item wasn't found */
86969ea4 » bradfitz
2006-09-04 restore blank lines I over-zealously destroyed earlier.
105
bab9acd1 » dormando
2011-10-02 move hash calls outside of cache_lock
106 static item** _hashitem_before (const char *key, const size_t nkey, const uint32_t hv) {
217dcce0 » Steven Grimm
2006-11-26 Incorporate changes from "performance" branch (revisions 414-419).
107 item **pos;
44ef96ee » Paul Lindner
2007-07-09 gcc -pedantic changes, comments, signed/unsigned changes. also conver…
108 unsigned int oldbucket;
86969ea4 » bradfitz
2006-09-04 restore blank lines I over-zealously destroyed earlier.
109
217dcce0 » Steven Grimm
2006-11-26 Incorporate changes from "performance" branch (revisions 414-419).
110 if (expanding &&
111 (oldbucket = (hv & hashmask(hashpower - 1))) >= expand_bucket)
112 {
113 pos = &old_hashtable[oldbucket];
114 } else {
115 pos = &primary_hashtable[hv & hashmask(hashpower)];
116 }
117
118 while (*pos && ((nkey != (*pos)->nkey) || memcmp(key, ITEM_key(*pos), nkey))) {
f6d334e0 » bradfitz
2003-06-20 2003-06-10
119 pos = &(*pos)->h_next;
825db0f9 » bradfitz
2003-06-20 stop using Judy for string mappings and use a hash table instead, which
120 }
121 return pos;
122 }
86969ea4 » bradfitz
2006-09-04 restore blank lines I over-zealously destroyed earlier.
123
217dcce0 » Steven Grimm
2006-11-26 Incorporate changes from "performance" branch (revisions 414-419).
124 /* grows the hashtable to the next power of 2. */
125 static void assoc_expand(void) {
126 old_hashtable = primary_hashtable;
127
128 primary_hashtable = calloc(hashsize(hashpower + 1), sizeof(void *));
129 if (primary_hashtable) {
56b8339e » Steven Grimm
2007-04-16 Merge multithreaded into trunk, commit #2 (first commit only did the
130 if (settings.verbose > 1)
131 fprintf(stderr, "Hash table expansion starting\n");
217dcce0 » Steven Grimm
2006-11-26 Incorporate changes from "performance" branch (revisions 414-419).
132 hashpower++;
44ef96ee » Paul Lindner
2007-07-09 gcc -pedantic changes, comments, signed/unsigned changes. also conver…
133 expanding = true;
217dcce0 » Steven Grimm
2006-11-26 Incorporate changes from "performance" branch (revisions 414-419).
134 expand_bucket = 0;
108e2cd6 » dormando
2011-09-28 expose stats for the internal hash table
135 STATS_LOCK();
136 stats.hash_power_level = hashpower;
137 stats.hash_bytes += hashsize(hashpower) * sizeof(void *);
138 stats.hash_is_expanding = 1;
139 STATS_UNLOCK();
217dcce0 » Steven Grimm
2006-11-26 Incorporate changes from "performance" branch (revisions 414-419).
140 } else {
141 primary_hashtable = old_hashtable;
56b8339e » Steven Grimm
2007-04-16 Merge multithreaded into trunk, commit #2 (first commit only did the
142 /* Bad news, but we can keep running. */
217dcce0 » Steven Grimm
2006-11-26 Incorporate changes from "performance" branch (revisions 414-419).
143 }
144 }
145
1c94e12c » dormando
2012-08-18 item locks now lock hash table buckets
146 static void assoc_start_expand(void) {
147 if (started_expanding)
148 return;
149 started_expanding = true;
150 pthread_cond_signal(&maintenance_cond);
151 }
152
7917af40 » bradfitz
2003-06-22 misc fixes as suggested by avva. lot of comment updates, mostly.
153 /* Note: this isn't an assoc_update. The key must not already exist to call this */
bab9acd1 » dormando
2011-10-02 move hash calls outside of cache_lock
154 int assoc_insert(item *it, const uint32_t hv) {
44ef96ee » Paul Lindner
2007-07-09 gcc -pedantic changes, comments, signed/unsigned changes. also conver…
155 unsigned int oldbucket;
217dcce0 » Steven Grimm
2006-11-26 Incorporate changes from "performance" branch (revisions 414-419).
156
bab9acd1 » dormando
2011-10-02 move hash calls outside of cache_lock
157 // assert(assoc_find(ITEM_key(it), it->nkey) == 0); /* shouldn't have duplicately named things defined */
217dcce0 » Steven Grimm
2006-11-26 Incorporate changes from "performance" branch (revisions 414-419).
158
159 if (expanding &&
160 (oldbucket = (hv & hashmask(hashpower - 1))) >= expand_bucket)
161 {
162 it->h_next = old_hashtable[oldbucket];
163 old_hashtable[oldbucket] = it;
164 } else {
165 it->h_next = primary_hashtable[hv & hashmask(hashpower)];
166 primary_hashtable[hv & hashmask(hashpower)] = it;
167 }
168
169 hash_items++;
170 if (! expanding && hash_items > (hashsize(hashpower) * 3) / 2) {
1c94e12c » dormando
2012-08-18 item locks now lock hash table buckets
171 assoc_start_expand();
217dcce0 » Steven Grimm
2006-11-26 Incorporate changes from "performance" branch (revisions 414-419).
172 }
173
80ec0955 » Trond Norbye
2008-10-02 Add DTrace probes to the binary protocol
174 MEMCACHED_ASSOC_INSERT(ITEM_key(it), it->nkey, hash_items);
f6d334e0 » bradfitz
2003-06-20 2003-06-10
175 return 1;
825db0f9 » bradfitz
2003-06-20 stop using Judy for string mappings and use a hash table instead, which
176 }
86969ea4 » bradfitz
2006-09-04 restore blank lines I over-zealously destroyed earlier.
177
bab9acd1 » dormando
2011-10-02 move hash calls outside of cache_lock
178 void assoc_delete(const char *key, const size_t nkey, const uint32_t hv) {
179 item **before = _hashitem_before(key, nkey, hv);
217dcce0 » Steven Grimm
2006-11-26 Incorporate changes from "performance" branch (revisions 414-419).
180
825db0f9 » bradfitz
2003-06-20 stop using Judy for string mappings and use a hash table instead, which
181 if (*before) {
68957214 » Trond Norbye
2008-07-23 Add DTrace probes for Solaris/etc.
182 item *nxt;
183 hash_items--;
184 /* The DTrace probe cannot be triggered as the last instruction
185 * due to possible tail-optimization by the compiler
186 */
80ec0955 » Trond Norbye
2008-10-02 Add DTrace probes to the binary protocol
187 MEMCACHED_ASSOC_DELETE(key, nkey, hash_items);
68957214 » Trond Norbye
2008-07-23 Add DTrace probes for Solaris/etc.
188 nxt = (*before)->h_next;
f6d334e0 » bradfitz
2003-06-20 2003-06-10
189 (*before)->h_next = 0; /* probably pointless, but whatever. */
190 *before = nxt;
191 return;
825db0f9 » bradfitz
2003-06-20 stop using Judy for string mappings and use a hash table instead, which
192 }
b80ab7cf » Paul Lindner
2007-04-10 update clean-whitespace, add automated whitespace test, and clean whi…
193 /* Note: we never actually get here. the callers don't delete things
c08383af » bradfitz
2003-06-27 more debug asserts
194 they can't find. */
195 assert(*before != 0);
8bdbe4a3 » bradfitz
2006-09-04 but we do want trailing newline at end of file
196 }
7f09e20b » Trond Norbye
2009-01-27 Do hash expansion in it's own thread
197
198
199 static volatile int do_run_maintenance_thread = 1;
200
201 #define DEFAULT_HASH_BULK_MOVE 1
202 int hash_bulk_move = DEFAULT_HASH_BULK_MOVE;
203
204 static void *assoc_maintenance_thread(void *arg) {
205
206 while (do_run_maintenance_thread) {
dfc5130e » dustin
2009-02-03 Get build working under ICC.
207 int ii = 0;
7f09e20b » Trond Norbye
2009-01-27 Do hash expansion in it's own thread
208
209 /* Lock the cache, and bulk move multiple buckets to the new
210 * hash table. */
1c94e12c » dormando
2012-08-18 item locks now lock hash table buckets
211 item_lock_global();
45e0e950 » dormando
2011-10-02 Use spinlocks for main cache lock
212 mutex_lock(&cache_lock);
7f09e20b » Trond Norbye
2009-01-27 Do hash expansion in it's own thread
213
dfc5130e » dustin
2009-02-03 Get build working under ICC.
214 for (ii = 0; ii < hash_bulk_move && expanding; ++ii) {
7f09e20b » Trond Norbye
2009-01-27 Do hash expansion in it's own thread
215 item *it, *next;
216 int bucket;
217
218 for (it = old_hashtable[expand_bucket]; NULL != it; it = next) {
219 next = it->h_next;
220
221 bucket = hash(ITEM_key(it), it->nkey, 0) & hashmask(hashpower);
222 it->h_next = primary_hashtable[bucket];
223 primary_hashtable[bucket] = it;
224 }
225
226 old_hashtable[expand_bucket] = NULL;
227
228 expand_bucket++;
229 if (expand_bucket == hashsize(hashpower - 1)) {
230 expanding = false;
231 free(old_hashtable);
108e2cd6 » dormando
2011-09-28 expose stats for the internal hash table
232 STATS_LOCK();
233 stats.hash_bytes -= hashsize(hashpower - 1) * sizeof(void *);
234 stats.hash_is_expanding = 0;
235 STATS_UNLOCK();
7f09e20b » Trond Norbye
2009-01-27 Do hash expansion in it's own thread
236 if (settings.verbose > 1)
237 fprintf(stderr, "Hash table expansion done\n");
238 }
239 }
240
1c94e12c » dormando
2012-08-18 item locks now lock hash table buckets
241 mutex_unlock(&cache_lock);
242 item_unlock_global();
243
7f09e20b » Trond Norbye
2009-01-27 Do hash expansion in it's own thread
244 if (!expanding) {
1c94e12c » dormando
2012-08-18 item locks now lock hash table buckets
245 /* finished expanding. tell all threads to use fine-grained locks */
246 switch_item_lock_type(ITEM_LOCK_GRANULAR);
247 slabs_rebalancer_resume();
7f09e20b » Trond Norbye
2009-01-27 Do hash expansion in it's own thread
248 /* We are done expanding.. just wait for next invocation */
8963836c » dormando
2012-09-02 don't wait on condition without holding the lock
249 mutex_lock(&cache_lock);
250 started_expanding = false;
7f09e20b » Trond Norbye
2009-01-27 Do hash expansion in it's own thread
251 pthread_cond_wait(&maintenance_cond, &cache_lock);
1c94e12c » dormando
2012-08-18 item locks now lock hash table buckets
252 /* Before doing anything, tell threads to use a global lock */
253 mutex_unlock(&cache_lock);
254 slabs_rebalancer_pause();
255 switch_item_lock_type(ITEM_LOCK_GLOBAL);
256 mutex_lock(&cache_lock);
257 assoc_expand();
258 mutex_unlock(&cache_lock);
7f09e20b » Trond Norbye
2009-01-27 Do hash expansion in it's own thread
259 }
260 }
261 return NULL;
262 }
263
264 static pthread_t maintenance_tid;
265
266 int start_assoc_maintenance_thread() {
267 int ret;
268 char *env = getenv("MEMCACHED_HASH_BULK_MOVE");
269 if (env != NULL) {
270 hash_bulk_move = atoi(env);
271 if (hash_bulk_move == 0) {
272 hash_bulk_move = DEFAULT_HASH_BULK_MOVE;
273 }
274 }
275 if ((ret = pthread_create(&maintenance_tid, NULL,
276 assoc_maintenance_thread, NULL)) != 0) {
277 fprintf(stderr, "Can't create thread: %s\n", strerror(ret));
278 return -1;
279 }
280 return 0;
281 }
282
283 void stop_assoc_maintenance_thread() {
45e0e950 » dormando
2011-10-02 Use spinlocks for main cache lock
284 mutex_lock(&cache_lock);
7f09e20b » Trond Norbye
2009-01-27 Do hash expansion in it's own thread
285 do_run_maintenance_thread = 0;
286 pthread_cond_signal(&maintenance_cond);
890dfb75 » dormando
2012-07-30 call mutex_unlock() when we use mutex_lock()
287 mutex_unlock(&cache_lock);
7f09e20b » Trond Norbye
2009-01-27 Do hash expansion in it's own thread
288
289 /* Wait for the maintenance thread to stop */
290 pthread_join(maintenance_tid, NULL);
291 }
292
293
Something went wrong with that request. Please try again.