Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 294 lines (245 sloc) 8.784 kb
825db0f @bradfitz stop using Judy for string mappings and use a hash table instead, which
bradfitz authored
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>
93c6642 @bradfitz whitespace changes only
bradfitz authored
7 * "By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net.
1ea89bd @bradfitz remove all trailing whitespace, not just first occurrence. :)
bradfitz authored
8 * You may use this code any way you wish, private, educational,
825db0f @bradfitz stop using Judy for string mappings and use a hash table instead, which
bradfitz authored
9 * or commercial. It's free."
10 *
11 * The rest of the file is licensed under the BSD license. See LICENSE.
12 */
56b8339 Merge multithreaded into trunk, commit #2 (first commit only did the
Steven Grimm authored
13
14 #include "memcached.h"
825db0f @bradfitz stop using Judy for string mappings and use a hash table instead, which
bradfitz authored
15 #include <sys/stat.h>
16 #include <sys/socket.h>
17 #include <sys/signal.h>
18 #include <sys/resource.h>
19 #include <fcntl.h>
c6975ef Part 1 of the Windows compatibility patch
Paul Lindner authored
20 #include <netinet/in.h>
21 #include <errno.h>
825db0f @bradfitz stop using Judy for string mappings and use a hash table instead, which
bradfitz authored
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
18a72ad @bradfitz version 1.1.6
bradfitz authored
25 #include <assert.h>
7f09e20 Do hash expansion in it's own thread
Trond Norbye authored
26 #include <pthread.h>
27
28 static pthread_cond_t maintenance_cond = PTHREAD_COND_INITIALIZER;
29
86969ea @bradfitz restore blank lines I over-zealously destroyed earlier.
bradfitz authored
30
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
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 */
1c94e12 @dormando item locks now lock hash table buckets
dormando authored
35 unsigned int hashpower = HASHPOWER_DEFAULT;
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
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. */
44ef96e gcc -pedantic changes, comments, signed/unsigned changes. also convert e...
Paul Lindner authored
50 static unsigned int hash_items = 0;
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
51
52 /* Flag: Are we in the middle of expanding now? */
44ef96e gcc -pedantic changes, comments, signed/unsigned changes. also convert e...
Paul Lindner authored
53 static bool expanding = false;
1c94e12 @dormando item locks now lock hash table buckets
dormando authored
54 static bool started_expanding = false;
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
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 */
44ef96e gcc -pedantic changes, comments, signed/unsigned changes. also convert e...
Paul Lindner authored
60 static unsigned int expand_bucket = 0;
86969ea @bradfitz restore blank lines I over-zealously destroyed earlier.
bradfitz authored
61
1db1de3 @dormando Allow setting initial size of the hash table
dormando authored
62 void assoc_init(const int hashtable_init) {
63 if (hashtable_init) {
64 hashpower = hashtable_init;
65 }
984053c @dustin Use calloc for allocating the hash table vs. malloc+memset.
dustin authored
66 primary_hashtable = calloc(hashsize(hashpower), sizeof(void *));
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
67 if (! primary_hashtable) {
825db0f @bradfitz stop using Judy for string mappings and use a hash table instead, which
bradfitz authored
68 fprintf(stderr, "Failed to init hashtable.\n");
c842507 use EXIT_* constants
Paul Lindner authored
69 exit(EXIT_FAILURE);
825db0f @bradfitz stop using Judy for string mappings and use a hash table instead, which
bradfitz authored
70 }
108e2cd @dormando expose stats for the internal hash table
dormando authored
71 STATS_LOCK();
72 stats.hash_power_level = hashpower;
73 stats.hash_bytes = hashsize(hashpower) * sizeof(void *);
74 STATS_UNLOCK();
825db0f @bradfitz stop using Judy for string mappings and use a hash table instead, which
bradfitz authored
75 }
86969ea @bradfitz restore blank lines I over-zealously destroyed earlier.
bradfitz authored
76
bab9acd @dormando move hash calls outside of cache_lock
dormando authored
77 item *assoc_find(const char *key, const size_t nkey, const uint32_t hv) {
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
78 item *it;
44ef96e gcc -pedantic changes, comments, signed/unsigned changes. also convert e...
Paul Lindner authored
79 unsigned int oldbucket;
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
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 }
86969ea @bradfitz restore blank lines I over-zealously destroyed earlier.
bradfitz authored
88
6895721 Add DTrace probes for Solaris/etc.
Trond Norbye authored
89 item *ret = NULL;
90 int depth = 0;
f6d334e @bradfitz 2003-06-10
bradfitz authored
91 while (it) {
6895721 Add DTrace probes for Solaris/etc.
Trond Norbye authored
92 if ((nkey == it->nkey) && (memcmp(key, ITEM_key(it), nkey) == 0)) {
93 ret = it;
94 break;
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
95 }
f6d334e @bradfitz 2003-06-10
bradfitz authored
96 it = it->h_next;
6895721 Add DTrace probes for Solaris/etc.
Trond Norbye authored
97 ++depth;
825db0f @bradfitz stop using Judy for string mappings and use a hash table instead, which
bradfitz authored
98 }
80ec095 Add DTrace probes to the binary protocol
Trond Norbye authored
99 MEMCACHED_ASSOC_FIND(key, nkey, depth);
6895721 Add DTrace probes for Solaris/etc.
Trond Norbye authored
100 return ret;
825db0f @bradfitz stop using Judy for string mappings and use a hash table instead, which
bradfitz authored
101 }
86969ea @bradfitz restore blank lines I over-zealously destroyed earlier.
bradfitz authored
102
7917af4 @bradfitz misc fixes as suggested by avva. lot of comment updates, mostly.
bradfitz authored
103 /* returns the address of the item pointer before the key. if *item == 0,
104 the item wasn't found */
86969ea @bradfitz restore blank lines I over-zealously destroyed earlier.
bradfitz authored
105
bab9acd @dormando move hash calls outside of cache_lock
dormando authored
106 static item** _hashitem_before (const char *key, const size_t nkey, const uint32_t hv) {
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
107 item **pos;
44ef96e gcc -pedantic changes, comments, signed/unsigned changes. also convert e...
Paul Lindner authored
108 unsigned int oldbucket;
86969ea @bradfitz restore blank lines I over-zealously destroyed earlier.
bradfitz authored
109
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
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))) {
f6d334e @bradfitz 2003-06-10
bradfitz authored
119 pos = &(*pos)->h_next;
825db0f @bradfitz stop using Judy for string mappings and use a hash table instead, which
bradfitz authored
120 }
121 return pos;
122 }
86969ea @bradfitz restore blank lines I over-zealously destroyed earlier.
bradfitz authored
123
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
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) {
56b8339 Merge multithreaded into trunk, commit #2 (first commit only did the
Steven Grimm authored
130 if (settings.verbose > 1)
131 fprintf(stderr, "Hash table expansion starting\n");
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
132 hashpower++;
44ef96e gcc -pedantic changes, comments, signed/unsigned changes. also convert e...
Paul Lindner authored
133 expanding = true;
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
134 expand_bucket = 0;
108e2cd @dormando expose stats for the internal hash table
dormando authored
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();
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
140 } else {
141 primary_hashtable = old_hashtable;
56b8339 Merge multithreaded into trunk, commit #2 (first commit only did the
Steven Grimm authored
142 /* Bad news, but we can keep running. */
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
143 }
144 }
145
1c94e12 @dormando item locks now lock hash table buckets
dormando authored
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
7917af4 @bradfitz misc fixes as suggested by avva. lot of comment updates, mostly.
bradfitz authored
153 /* Note: this isn't an assoc_update. The key must not already exist to call this */
bab9acd @dormando move hash calls outside of cache_lock
dormando authored
154 int assoc_insert(item *it, const uint32_t hv) {
44ef96e gcc -pedantic changes, comments, signed/unsigned changes. also convert e...
Paul Lindner authored
155 unsigned int oldbucket;
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
156
bab9acd @dormando move hash calls outside of cache_lock
dormando authored
157 // assert(assoc_find(ITEM_key(it), it->nkey) == 0); /* shouldn't have duplicately named things defined */
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
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) {
1c94e12 @dormando item locks now lock hash table buckets
dormando authored
171 assoc_start_expand();
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
172 }
173
80ec095 Add DTrace probes to the binary protocol
Trond Norbye authored
174 MEMCACHED_ASSOC_INSERT(ITEM_key(it), it->nkey, hash_items);
f6d334e @bradfitz 2003-06-10
bradfitz authored
175 return 1;
825db0f @bradfitz stop using Judy for string mappings and use a hash table instead, which
bradfitz authored
176 }
86969ea @bradfitz restore blank lines I over-zealously destroyed earlier.
bradfitz authored
177
bab9acd @dormando move hash calls outside of cache_lock
dormando authored
178 void assoc_delete(const char *key, const size_t nkey, const uint32_t hv) {
179 item **before = _hashitem_before(key, nkey, hv);
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
180
825db0f @bradfitz stop using Judy for string mappings and use a hash table instead, which
bradfitz authored
181 if (*before) {
6895721 Add DTrace probes for Solaris/etc.
Trond Norbye authored
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 */
80ec095 Add DTrace probes to the binary protocol
Trond Norbye authored
187 MEMCACHED_ASSOC_DELETE(key, nkey, hash_items);
6895721 Add DTrace probes for Solaris/etc.
Trond Norbye authored
188 nxt = (*before)->h_next;
f6d334e @bradfitz 2003-06-10
bradfitz authored
189 (*before)->h_next = 0; /* probably pointless, but whatever. */
190 *before = nxt;
191 return;
825db0f @bradfitz stop using Judy for string mappings and use a hash table instead, which
bradfitz authored
192 }
b80ab7c update clean-whitespace, add automated whitespace test, and clean whites...
Paul Lindner authored
193 /* Note: we never actually get here. the callers don't delete things
c08383a @bradfitz more debug asserts
bradfitz authored
194 they can't find. */
195 assert(*before != 0);
8bdbe4a @bradfitz but we do want trailing newline at end of file
bradfitz authored
196 }
7f09e20 Do hash expansion in it's own thread
Trond Norbye authored
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) {
dfc5130 @dustin Get build working under ICC.
dustin authored
207 int ii = 0;
7f09e20 Do hash expansion in it's own thread
Trond Norbye authored
208
209 /* Lock the cache, and bulk move multiple buckets to the new
210 * hash table. */
1c94e12 @dormando item locks now lock hash table buckets
dormando authored
211 item_lock_global();
45e0e95 @dormando Use spinlocks for main cache lock
dormando authored
212 mutex_lock(&cache_lock);
7f09e20 Do hash expansion in it's own thread
Trond Norbye authored
213
dfc5130 @dustin Get build working under ICC.
dustin authored
214 for (ii = 0; ii < hash_bulk_move && expanding; ++ii) {
7f09e20 Do hash expansion in it's own thread
Trond Norbye authored
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);
108e2cd @dormando expose stats for the internal hash table
dormando authored
232 STATS_LOCK();
233 stats.hash_bytes -= hashsize(hashpower - 1) * sizeof(void *);
234 stats.hash_is_expanding = 0;
235 STATS_UNLOCK();
7f09e20 Do hash expansion in it's own thread
Trond Norbye authored
236 if (settings.verbose > 1)
237 fprintf(stderr, "Hash table expansion done\n");
238 }
239 }
240
1c94e12 @dormando item locks now lock hash table buckets
dormando authored
241 mutex_unlock(&cache_lock);
242 item_unlock_global();
243
7f09e20 Do hash expansion in it's own thread
Trond Norbye authored
244 if (!expanding) {
1c94e12 @dormando item locks now lock hash table buckets
dormando authored
245 /* finished expanding. tell all threads to use fine-grained locks */
246 switch_item_lock_type(ITEM_LOCK_GRANULAR);
247 slabs_rebalancer_resume();
7f09e20 Do hash expansion in it's own thread
Trond Norbye authored
248 /* We are done expanding.. just wait for next invocation */
8963836 @dormando don't wait on condition without holding the lock
dormando authored
249 mutex_lock(&cache_lock);
250 started_expanding = false;
7f09e20 Do hash expansion in it's own thread
Trond Norbye authored
251 pthread_cond_wait(&maintenance_cond, &cache_lock);
1c94e12 @dormando item locks now lock hash table buckets
dormando authored
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);
7f09e20 Do hash expansion in it's own thread
Trond Norbye authored
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() {
45e0e95 @dormando Use spinlocks for main cache lock
dormando authored
284 mutex_lock(&cache_lock);
7f09e20 Do hash expansion in it's own thread
Trond Norbye authored
285 do_run_maintenance_thread = 0;
286 pthread_cond_signal(&maintenance_cond);
890dfb7 @dormando call mutex_unlock() when we use mutex_lock()
dormando authored
287 mutex_unlock(&cache_lock);
7f09e20 Do hash expansion in it's own thread
Trond Norbye authored
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.