Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 273 lines (225 sloc) 8.017 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 */
1db1de3 @dormando Allow setting initial size of the hash table
dormando authored
35 static 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 conver…
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 conver…
Paul Lindner authored
53 static bool expanding = false;
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
54
55 /*
56 * During expansion we migrate values with bucket granularity; this is how
57 * far we've gotten so far. Ranges from 0 .. hashsize(hashpower - 1) - 1.
58 */
44ef96e gcc -pedantic changes, comments, signed/unsigned changes. also conver…
Paul Lindner authored
59 static unsigned int expand_bucket = 0;
86969ea @bradfitz restore blank lines I over-zealously destroyed earlier.
bradfitz authored
60
1db1de3 @dormando Allow setting initial size of the hash table
dormando authored
61 void assoc_init(const int hashtable_init) {
62 if (hashtable_init) {
63 hashpower = hashtable_init;
64 }
984053c @dustin Use calloc for allocating the hash table vs. malloc+memset.
dustin authored
65 primary_hashtable = calloc(hashsize(hashpower), sizeof(void *));
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
66 if (! primary_hashtable) {
825db0f @bradfitz stop using Judy for string mappings and use a hash table instead, which
bradfitz authored
67 fprintf(stderr, "Failed to init hashtable.\n");
c842507 use EXIT_* constants
Paul Lindner authored
68 exit(EXIT_FAILURE);
825db0f @bradfitz stop using Judy for string mappings and use a hash table instead, which
bradfitz authored
69 }
108e2cd @dormando expose stats for the internal hash table
dormando authored
70 STATS_LOCK();
71 stats.hash_power_level = hashpower;
72 stats.hash_bytes = hashsize(hashpower) * sizeof(void *);
73 STATS_UNLOCK();
825db0f @bradfitz stop using Judy for string mappings and use a hash table instead, which
bradfitz authored
74 }
86969ea @bradfitz restore blank lines I over-zealously destroyed earlier.
bradfitz authored
75
bab9acd @dormando move hash calls outside of cache_lock
dormando authored
76 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
77 item *it;
44ef96e gcc -pedantic changes, comments, signed/unsigned changes. also conver…
Paul Lindner authored
78 unsigned int oldbucket;
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
79
80 if (expanding &&
81 (oldbucket = (hv & hashmask(hashpower - 1))) >= expand_bucket)
82 {
83 it = old_hashtable[oldbucket];
84 } else {
85 it = primary_hashtable[hv & hashmask(hashpower)];
86 }
86969ea @bradfitz restore blank lines I over-zealously destroyed earlier.
bradfitz authored
87
6895721 Add DTrace probes for Solaris/etc.
Trond Norbye authored
88 item *ret = NULL;
89 int depth = 0;
f6d334e @bradfitz 2003-06-10
bradfitz authored
90 while (it) {
6895721 Add DTrace probes for Solaris/etc.
Trond Norbye authored
91 if ((nkey == it->nkey) && (memcmp(key, ITEM_key(it), nkey) == 0)) {
92 ret = it;
93 break;
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
94 }
f6d334e @bradfitz 2003-06-10
bradfitz authored
95 it = it->h_next;
6895721 Add DTrace probes for Solaris/etc.
Trond Norbye authored
96 ++depth;
825db0f @bradfitz stop using Judy for string mappings and use a hash table instead, which
bradfitz authored
97 }
80ec095 Add DTrace probes to the binary protocol
Trond Norbye authored
98 MEMCACHED_ASSOC_FIND(key, nkey, depth);
6895721 Add DTrace probes for Solaris/etc.
Trond Norbye authored
99 return ret;
825db0f @bradfitz stop using Judy for string mappings and use a hash table instead, which
bradfitz authored
100 }
86969ea @bradfitz restore blank lines I over-zealously destroyed earlier.
bradfitz authored
101
7917af4 @bradfitz misc fixes as suggested by avva. lot of comment updates, mostly.
bradfitz authored
102 /* returns the address of the item pointer before the key. if *item == 0,
103 the item wasn't found */
86969ea @bradfitz restore blank lines I over-zealously destroyed earlier.
bradfitz authored
104
bab9acd @dormando move hash calls outside of cache_lock
dormando authored
105 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
106 item **pos;
44ef96e gcc -pedantic changes, comments, signed/unsigned changes. also conver…
Paul Lindner authored
107 unsigned int oldbucket;
86969ea @bradfitz restore blank lines I over-zealously destroyed earlier.
bradfitz authored
108
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
109 if (expanding &&
110 (oldbucket = (hv & hashmask(hashpower - 1))) >= expand_bucket)
111 {
112 pos = &old_hashtable[oldbucket];
113 } else {
114 pos = &primary_hashtable[hv & hashmask(hashpower)];
115 }
116
117 while (*pos && ((nkey != (*pos)->nkey) || memcmp(key, ITEM_key(*pos), nkey))) {
f6d334e @bradfitz 2003-06-10
bradfitz authored
118 pos = &(*pos)->h_next;
825db0f @bradfitz stop using Judy for string mappings and use a hash table instead, which
bradfitz authored
119 }
120 return pos;
121 }
86969ea @bradfitz restore blank lines I over-zealously destroyed earlier.
bradfitz authored
122
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
123 /* grows the hashtable to the next power of 2. */
124 static void assoc_expand(void) {
125 old_hashtable = primary_hashtable;
126
127 primary_hashtable = calloc(hashsize(hashpower + 1), sizeof(void *));
128 if (primary_hashtable) {
56b8339 Merge multithreaded into trunk, commit #2 (first commit only did the
Steven Grimm authored
129 if (settings.verbose > 1)
130 fprintf(stderr, "Hash table expansion starting\n");
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
131 hashpower++;
44ef96e gcc -pedantic changes, comments, signed/unsigned changes. also conver…
Paul Lindner authored
132 expanding = true;
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
133 expand_bucket = 0;
108e2cd @dormando expose stats for the internal hash table
dormando authored
134 STATS_LOCK();
135 stats.hash_power_level = hashpower;
136 stats.hash_bytes += hashsize(hashpower) * sizeof(void *);
137 stats.hash_is_expanding = 1;
138 STATS_UNLOCK();
7f09e20 Do hash expansion in it's own thread
Trond Norbye authored
139 pthread_cond_signal(&maintenance_cond);
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
7917af4 @bradfitz misc fixes as suggested by avva. lot of comment updates, mostly.
bradfitz authored
146 /* 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
147 int assoc_insert(item *it, const uint32_t hv) {
44ef96e gcc -pedantic changes, comments, signed/unsigned changes. also conver…
Paul Lindner authored
148 unsigned int oldbucket;
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
149
bab9acd @dormando move hash calls outside of cache_lock
dormando authored
150 // 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
151
152 if (expanding &&
153 (oldbucket = (hv & hashmask(hashpower - 1))) >= expand_bucket)
154 {
155 it->h_next = old_hashtable[oldbucket];
156 old_hashtable[oldbucket] = it;
157 } else {
158 it->h_next = primary_hashtable[hv & hashmask(hashpower)];
159 primary_hashtable[hv & hashmask(hashpower)] = it;
160 }
161
162 hash_items++;
163 if (! expanding && hash_items > (hashsize(hashpower) * 3) / 2) {
164 assoc_expand();
165 }
166
80ec095 Add DTrace probes to the binary protocol
Trond Norbye authored
167 MEMCACHED_ASSOC_INSERT(ITEM_key(it), it->nkey, hash_items);
f6d334e @bradfitz 2003-06-10
bradfitz authored
168 return 1;
825db0f @bradfitz stop using Judy for string mappings and use a hash table instead, which
bradfitz authored
169 }
86969ea @bradfitz restore blank lines I over-zealously destroyed earlier.
bradfitz authored
170
bab9acd @dormando move hash calls outside of cache_lock
dormando authored
171 void assoc_delete(const char *key, const size_t nkey, const uint32_t hv) {
172 item **before = _hashitem_before(key, nkey, hv);
217dcce Incorporate changes from "performance" branch (revisions 414-419).
Steven Grimm authored
173
825db0f @bradfitz stop using Judy for string mappings and use a hash table instead, which
bradfitz authored
174 if (*before) {
6895721 Add DTrace probes for Solaris/etc.
Trond Norbye authored
175 item *nxt;
176 hash_items--;
177 /* The DTrace probe cannot be triggered as the last instruction
178 * due to possible tail-optimization by the compiler
179 */
80ec095 Add DTrace probes to the binary protocol
Trond Norbye authored
180 MEMCACHED_ASSOC_DELETE(key, nkey, hash_items);
6895721 Add DTrace probes for Solaris/etc.
Trond Norbye authored
181 nxt = (*before)->h_next;
f6d334e @bradfitz 2003-06-10
bradfitz authored
182 (*before)->h_next = 0; /* probably pointless, but whatever. */
183 *before = nxt;
184 return;
825db0f @bradfitz stop using Judy for string mappings and use a hash table instead, which
bradfitz authored
185 }
b80ab7c update clean-whitespace, add automated whitespace test, and clean whi…
Paul Lindner authored
186 /* Note: we never actually get here. the callers don't delete things
c08383a @bradfitz more debug asserts
bradfitz authored
187 they can't find. */
188 assert(*before != 0);
8bdbe4a @bradfitz but we do want trailing newline at end of file
bradfitz authored
189 }
7f09e20 Do hash expansion in it's own thread
Trond Norbye authored
190
191
192 static volatile int do_run_maintenance_thread = 1;
193
194 #define DEFAULT_HASH_BULK_MOVE 1
195 int hash_bulk_move = DEFAULT_HASH_BULK_MOVE;
196
197 static void *assoc_maintenance_thread(void *arg) {
198
199 while (do_run_maintenance_thread) {
dfc5130 @dustin Get build working under ICC.
dustin authored
200 int ii = 0;
7f09e20 Do hash expansion in it's own thread
Trond Norbye authored
201
202 /* Lock the cache, and bulk move multiple buckets to the new
203 * hash table. */
45e0e95 @dormando Use spinlocks for main cache lock
dormando authored
204 mutex_lock(&cache_lock);
7f09e20 Do hash expansion in it's own thread
Trond Norbye authored
205
dfc5130 @dustin Get build working under ICC.
dustin authored
206 for (ii = 0; ii < hash_bulk_move && expanding; ++ii) {
7f09e20 Do hash expansion in it's own thread
Trond Norbye authored
207 item *it, *next;
208 int bucket;
209
210 for (it = old_hashtable[expand_bucket]; NULL != it; it = next) {
211 next = it->h_next;
212
213 bucket = hash(ITEM_key(it), it->nkey, 0) & hashmask(hashpower);
214 it->h_next = primary_hashtable[bucket];
215 primary_hashtable[bucket] = it;
216 }
217
218 old_hashtable[expand_bucket] = NULL;
219
220 expand_bucket++;
221 if (expand_bucket == hashsize(hashpower - 1)) {
222 expanding = false;
223 free(old_hashtable);
108e2cd @dormando expose stats for the internal hash table
dormando authored
224 STATS_LOCK();
225 stats.hash_bytes -= hashsize(hashpower - 1) * sizeof(void *);
226 stats.hash_is_expanding = 0;
227 STATS_UNLOCK();
7f09e20 Do hash expansion in it's own thread
Trond Norbye authored
228 if (settings.verbose > 1)
229 fprintf(stderr, "Hash table expansion done\n");
230 }
231 }
232
233 if (!expanding) {
234 /* We are done expanding.. just wait for next invocation */
235 pthread_cond_wait(&maintenance_cond, &cache_lock);
236 }
237
890dfb7 @dormando call mutex_unlock() when we use mutex_lock()
dormando authored
238 mutex_unlock(&cache_lock);
7f09e20 Do hash expansion in it's own thread
Trond Norbye authored
239 }
240 return NULL;
241 }
242
243 static pthread_t maintenance_tid;
244
245 int start_assoc_maintenance_thread() {
246 int ret;
247 char *env = getenv("MEMCACHED_HASH_BULK_MOVE");
248 if (env != NULL) {
249 hash_bulk_move = atoi(env);
250 if (hash_bulk_move == 0) {
251 hash_bulk_move = DEFAULT_HASH_BULK_MOVE;
252 }
253 }
254 if ((ret = pthread_create(&maintenance_tid, NULL,
255 assoc_maintenance_thread, NULL)) != 0) {
256 fprintf(stderr, "Can't create thread: %s\n", strerror(ret));
257 return -1;
258 }
259 return 0;
260 }
261
262 void stop_assoc_maintenance_thread() {
45e0e95 @dormando Use spinlocks for main cache lock
dormando authored
263 mutex_lock(&cache_lock);
7f09e20 Do hash expansion in it's own thread
Trond Norbye authored
264 do_run_maintenance_thread = 0;
265 pthread_cond_signal(&maintenance_cond);
890dfb7 @dormando call mutex_unlock() when we use mutex_lock()
dormando authored
266 mutex_unlock(&cache_lock);
7f09e20 Do hash expansion in it's own thread
Trond Norbye authored
267
268 /* Wait for the maintenance thread to stop */
269 pthread_join(maintenance_tid, NULL);
270 }
271
272
Something went wrong with that request. Please try again.