xref: /memcached-1.4.29/thread.c (revision fe2629fd)
1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  * Thread management for memcached.
4  */
5 #include "memcached.h"
6 #include <assert.h>
7 #include <stdio.h>
8 #include <errno.h>
9 #include <stdlib.h>
10 #include <errno.h>
11 #include <string.h>
12 #include <pthread.h>
13 
14 #ifdef __sun
15 #include <atomic.h>
16 #endif
17 
18 #define ITEMS_PER_ALLOC 64
19 
20 /* An item in the connection queue. */
21 typedef struct conn_queue_item CQ_ITEM;
22 struct conn_queue_item {
23     int               sfd;
24     enum conn_states  init_state;
25     int               event_flags;
26     int               read_buffer_size;
27     enum network_transport     transport;
28     CQ_ITEM          *next;
29 };
30 
31 /* A connection queue. */
32 typedef struct conn_queue CQ;
33 struct conn_queue {
34     CQ_ITEM *head;
35     CQ_ITEM *tail;
36     pthread_mutex_t lock;
37 };
38 
39 /* Lock for cache operations (item_*, assoc_*) */
40 pthread_mutex_t cache_lock;
41 
42 /* Connection lock around accepting new connections */
43 pthread_mutex_t conn_lock = PTHREAD_MUTEX_INITIALIZER;
44 
45 #if !defined(HAVE_GCC_ATOMICS) && !defined(__sun)
46 pthread_mutex_t atomics_mutex = PTHREAD_MUTEX_INITIALIZER;
47 #endif
48 
49 /* Lock for global stats */
50 static pthread_mutex_t stats_lock;
51 
52 /* Free list of CQ_ITEM structs */
53 static CQ_ITEM *cqi_freelist;
54 static pthread_mutex_t cqi_freelist_lock;
55 
56 static pthread_mutex_t *item_locks;
57 /* size of the item lock hash table */
58 static uint32_t item_lock_count;
59 static unsigned int item_lock_hashpower;
60 #define hashsize(n) ((unsigned long int)1<<(n))
61 #define hashmask(n) (hashsize(n)-1)
62 /* this lock is temporarily engaged during a hash table expansion */
63 static pthread_mutex_t item_global_lock;
64 /* thread-specific variable for deeply finding the item lock type */
65 static pthread_key_t item_lock_type_key;
66 
67 static LIBEVENT_DISPATCHER_THREAD dispatcher_thread;
68 
69 /*
70  * Each libevent instance has a wakeup pipe, which other threads
71  * can use to signal that they've put a new connection on its queue.
72  */
73 static LIBEVENT_THREAD *threads;
74 
75 /*
76  * Number of worker threads that have finished setting themselves up.
77  */
78 static int init_count = 0;
79 static pthread_mutex_t init_lock;
80 static pthread_cond_t init_cond;
81 
82 
83 static void thread_libevent_process(int fd, short which, void *arg);
84 
85 unsigned short refcount_incr(unsigned short *refcount) {
86 #ifdef HAVE_GCC_ATOMICS
87     return __sync_add_and_fetch(refcount, 1);
88 #elif defined(__sun)
89     return atomic_inc_ushort_nv(refcount);
90 #else
91     unsigned short res;
92     mutex_lock(&atomics_mutex);
93     (*refcount)++;
94     res = *refcount;
95     mutex_unlock(&atomics_mutex);
96     return res;
97 #endif
98 }
99 
100 unsigned short refcount_decr(unsigned short *refcount) {
101 #ifdef HAVE_GCC_ATOMICS
102     return __sync_sub_and_fetch(refcount, 1);
103 #elif defined(__sun)
104     return atomic_dec_ushort_nv(refcount);
105 #else
106     unsigned short res;
107     mutex_lock(&atomics_mutex);
108     (*refcount)--;
109     res = *refcount;
110     mutex_unlock(&atomics_mutex);
111     return res;
112 #endif
113 }
114 
115 /* Convenience functions for calling *only* when in ITEM_LOCK_GLOBAL mode */
116 void item_lock_global(void) {
117     mutex_lock(&item_global_lock);
118 }
119 
120 void item_unlock_global(void) {
121     mutex_unlock(&item_global_lock);
122 }
123 
124 void item_lock(uint32_t hv) {
125     uint8_t *lock_type = pthread_getspecific(item_lock_type_key);
126     if (likely(*lock_type == ITEM_LOCK_GRANULAR)) {
127         mutex_lock(&item_locks[hv & hashmask(item_lock_hashpower)]);
128     } else {
129         mutex_lock(&item_global_lock);
130     }
131 }
132 
133 /* Special case. When ITEM_LOCK_GLOBAL mode is enabled, this should become a
134  * no-op, as it's only called from within the item lock if necessary.
135  * However, we can't mix a no-op and threads which are still synchronizing to
136  * GLOBAL. So instead we just always try to lock. When in GLOBAL mode this
137  * turns into an effective no-op. Threads re-synchronize after the power level
138  * switch so it should stay safe.
139  */
140 void *item_trylock(uint32_t hv) {
141     pthread_mutex_t *lock = &item_locks[hv & hashmask(item_lock_hashpower)];
142     if (pthread_mutex_trylock(lock) == 0) {
143         return lock;
144     }
145     return NULL;
146 }
147 
148 void item_trylock_unlock(void *lock) {
149     mutex_unlock((pthread_mutex_t *) lock);
150 }
151 
152 void item_unlock(uint32_t hv) {
153     uint8_t *lock_type = pthread_getspecific(item_lock_type_key);
154     if (likely(*lock_type == ITEM_LOCK_GRANULAR)) {
155         mutex_unlock(&item_locks[hv & hashmask(item_lock_hashpower)]);
156     } else {
157         mutex_unlock(&item_global_lock);
158     }
159 }
160 
161 static void wait_for_thread_registration(int nthreads) {
162     while (init_count < nthreads) {
163         pthread_cond_wait(&init_cond, &init_lock);
164     }
165 }
166 
167 static void register_thread_initialized(void) {
168     pthread_mutex_lock(&init_lock);
169     init_count++;
170     pthread_cond_signal(&init_cond);
171     pthread_mutex_unlock(&init_lock);
172 }
173 
174 void switch_item_lock_type(enum item_lock_types type) {
175     char buf[1];
176     int i;
177 
178     switch (type) {
179         case ITEM_LOCK_GRANULAR:
180             buf[0] = 'l';
181             break;
182         case ITEM_LOCK_GLOBAL:
183             buf[0] = 'g';
184             break;
185         default:
186             fprintf(stderr, "Unknown lock type: %d\n", type);
187             assert(1 == 0);
188             break;
189     }
190 
191     pthread_mutex_lock(&init_lock);
192     init_count = 0;
193     for (i = 0; i < settings.num_threads; i++) {
194         if (write(threads[i].notify_send_fd, buf, 1) != 1) {
195             perror("Failed writing to notify pipe");
196             /* TODO: This is a fatal problem. Can it ever happen temporarily? */
197         }
198     }
199     wait_for_thread_registration(settings.num_threads);
200     pthread_mutex_unlock(&init_lock);
201 }
202 
203 /*
204  * Initializes a connection queue.
205  */
206 static void cq_init(CQ *cq) {
207     pthread_mutex_init(&cq->lock, NULL);
208     cq->head = NULL;
209     cq->tail = NULL;
210 }
211 
212 /*
213  * Looks for an item on a connection queue, but doesn't block if there isn't
214  * one.
215  * Returns the item, or NULL if no item is available
216  */
217 static CQ_ITEM *cq_pop(CQ *cq) {
218     CQ_ITEM *item;
219 
220     pthread_mutex_lock(&cq->lock);
221     item = cq->head;
222     if (NULL != item) {
223         cq->head = item->next;
224         if (NULL == cq->head)
225             cq->tail = NULL;
226     }
227     pthread_mutex_unlock(&cq->lock);
228 
229     return item;
230 }
231 
232 /*
233  * Adds an item to a connection queue.
234  */
235 static void cq_push(CQ *cq, CQ_ITEM *item) {
236     item->next = NULL;
237 
238     pthread_mutex_lock(&cq->lock);
239     if (NULL == cq->tail)
240         cq->head = item;
241     else
242         cq->tail->next = item;
243     cq->tail = item;
244     pthread_mutex_unlock(&cq->lock);
245 }
246 
247 /*
248  * Returns a fresh connection queue item.
249  */
250 static CQ_ITEM *cqi_new(void) {
251     CQ_ITEM *item = NULL;
252     pthread_mutex_lock(&cqi_freelist_lock);
253     if (cqi_freelist) {
254         item = cqi_freelist;
255         cqi_freelist = item->next;
256     }
257     pthread_mutex_unlock(&cqi_freelist_lock);
258 
259     if (NULL == item) {
260         int i;
261 
262         /* Allocate a bunch of items at once to reduce fragmentation */
263         item = malloc(sizeof(CQ_ITEM) * ITEMS_PER_ALLOC);
264         if (NULL == item) {
265             STATS_LOCK();
266             stats.malloc_fails++;
267             STATS_UNLOCK();
268             return NULL;
269         }
270 
271         /*
272          * Link together all the new items except the first one
273          * (which we'll return to the caller) for placement on
274          * the freelist.
275          */
276         for (i = 2; i < ITEMS_PER_ALLOC; i++)
277             item[i - 1].next = &item[i];
278 
279         pthread_mutex_lock(&cqi_freelist_lock);
280         item[ITEMS_PER_ALLOC - 1].next = cqi_freelist;
281         cqi_freelist = &item[1];
282         pthread_mutex_unlock(&cqi_freelist_lock);
283     }
284 
285     return item;
286 }
287 
288 
289 /*
290  * Frees a connection queue item (adds it to the freelist.)
291  */
292 static void cqi_free(CQ_ITEM *item) {
293     pthread_mutex_lock(&cqi_freelist_lock);
294     item->next = cqi_freelist;
295     cqi_freelist = item;
296     pthread_mutex_unlock(&cqi_freelist_lock);
297 }
298 
299 
300 /*
301  * Creates a worker thread.
302  */
303 static void create_worker(void *(*func)(void *), void *arg) {
304     pthread_t       thread;
305     pthread_attr_t  attr;
306     int             ret;
307 
308     pthread_attr_init(&attr);
309 
310     if ((ret = pthread_create(&thread, &attr, func, arg)) != 0) {
311         fprintf(stderr, "Can't create thread: %s\n",
312                 strerror(ret));
313         exit(1);
314     }
315 }
316 
317 /*
318  * Sets whether or not we accept new connections.
319  */
320 void accept_new_conns(const bool do_accept) {
321     pthread_mutex_lock(&conn_lock);
322     do_accept_new_conns(do_accept);
323     pthread_mutex_unlock(&conn_lock);
324 }
325 /****************************** LIBEVENT THREADS *****************************/
326 
327 /*
328  * Set up a thread's information.
329  */
330 static void setup_thread(LIBEVENT_THREAD *me) {
331     me->base = event_init();
332     if (! me->base) {
333         fprintf(stderr, "Can't allocate event base\n");
334         exit(1);
335     }
336 
337     /* Listen for notifications from other threads */
338     event_set(&me->notify_event, me->notify_receive_fd,
339               EV_READ | EV_PERSIST, thread_libevent_process, me);
340     event_base_set(me->base, &me->notify_event);
341 
342     if (event_add(&me->notify_event, 0) == -1) {
343         fprintf(stderr, "Can't monitor libevent notify pipe\n");
344         exit(1);
345     }
346 
347     me->new_conn_queue = malloc(sizeof(struct conn_queue));
348     if (me->new_conn_queue == NULL) {
349         perror("Failed to allocate memory for connection queue");
350         exit(EXIT_FAILURE);
351     }
352     cq_init(me->new_conn_queue);
353 
354     if (pthread_mutex_init(&me->stats.mutex, NULL) != 0) {
355         perror("Failed to initialize mutex");
356         exit(EXIT_FAILURE);
357     }
358 
359     me->suffix_cache = cache_create("suffix", SUFFIX_SIZE, sizeof(char*),
360                                     NULL, NULL);
361     if (me->suffix_cache == NULL) {
362         fprintf(stderr, "Failed to create suffix cache\n");
363         exit(EXIT_FAILURE);
364     }
365 }
366 
367 /*
368  * Worker thread: main event loop
369  */
370 static void *worker_libevent(void *arg) {
371     LIBEVENT_THREAD *me = arg;
372 
373     /* Any per-thread setup can happen here; thread_init() will block until
374      * all threads have finished initializing.
375      */
376 
377     /* set an indexable thread-specific memory item for the lock type.
378      * this could be unnecessary if we pass the conn *c struct through
379      * all item_lock calls...
380      */
381     me->item_lock_type = ITEM_LOCK_GRANULAR;
382     pthread_setspecific(item_lock_type_key, &me->item_lock_type);
383 
384     register_thread_initialized();
385 
386     event_base_loop(me->base, 0);
387     return NULL;
388 }
389 
390 
391 /*
392  * Processes an incoming "handle a new connection" item. This is called when
393  * input arrives on the libevent wakeup pipe.
394  */
395 static void thread_libevent_process(int fd, short which, void *arg) {
396     LIBEVENT_THREAD *me = arg;
397     CQ_ITEM *item;
398     char buf[1];
399 
400     if (read(fd, buf, 1) != 1)
401         if (settings.verbose > 0)
402             fprintf(stderr, "Can't read from libevent pipe\n");
403 
404     switch (buf[0]) {
405     case 'c':
406     item = cq_pop(me->new_conn_queue);
407 
408     if (NULL != item) {
409         conn *c = conn_new(item->sfd, item->init_state, item->event_flags,
410                            item->read_buffer_size, item->transport, me->base);
411         if (c == NULL) {
412             if (IS_UDP(item->transport)) {
413                 fprintf(stderr, "Can't listen for events on UDP socket\n");
414                 exit(1);
415             } else {
416                 if (settings.verbose > 0) {
417                     fprintf(stderr, "Can't listen for events on fd %d\n",
418                         item->sfd);
419                 }
420                 close(item->sfd);
421             }
422         } else {
423             c->thread = me;
424         }
425         cqi_free(item);
426     }
427         break;
428     /* we were told to flip the lock type and report in */
429     case 'l':
430     me->item_lock_type = ITEM_LOCK_GRANULAR;
431     register_thread_initialized();
432         break;
433     case 'g':
434     me->item_lock_type = ITEM_LOCK_GLOBAL;
435     register_thread_initialized();
436         break;
437     }
438 }
439 
440 /* Which thread we assigned a connection to most recently. */
441 static int last_thread = -1;
442 
443 /*
444  * Dispatches a new connection to another thread. This is only ever called
445  * from the main thread, either during initialization (for UDP) or because
446  * of an incoming connection.
447  */
448 void dispatch_conn_new(int sfd, enum conn_states init_state, int event_flags,
449                        int read_buffer_size, enum network_transport transport) {
450     CQ_ITEM *item = cqi_new();
451     char buf[1];
452     if (item == NULL) {
453         close(sfd);
454         /* given that malloc failed this may also fail, but let's try */
455         fprintf(stderr, "Failed to allocate memory for connection object\n");
456         return ;
457     }
458 
459     int tid = (last_thread + 1) % settings.num_threads;
460 
461     LIBEVENT_THREAD *thread = threads + tid;
462 
463     last_thread = tid;
464 
465     item->sfd = sfd;
466     item->init_state = init_state;
467     item->event_flags = event_flags;
468     item->read_buffer_size = read_buffer_size;
469     item->transport = transport;
470 
471     cq_push(thread->new_conn_queue, item);
472 
473     MEMCACHED_CONN_DISPATCH(sfd, thread->thread_id);
474     buf[0] = 'c';
475     if (write(thread->notify_send_fd, buf, 1) != 1) {
476         perror("Writing to thread notify pipe");
477     }
478 }
479 
480 /*
481  * Returns true if this is the thread that listens for new TCP connections.
482  */
483 int is_listen_thread() {
484     return pthread_self() == dispatcher_thread.thread_id;
485 }
486 
487 /********************************* ITEM ACCESS *******************************/
488 
489 /*
490  * Allocates a new item.
491  */
492 item *item_alloc(char *key, size_t nkey, int flags, rel_time_t exptime, int nbytes) {
493     item *it;
494     /* do_item_alloc handles its own locks */
495     it = do_item_alloc(key, nkey, flags, exptime, nbytes, 0);
496     return it;
497 }
498 
499 /*
500  * Returns an item if it hasn't been marked as expired,
501  * lazy-expiring as needed.
502  */
503 item *item_get(const char *key, const size_t nkey) {
504     item *it;
505     uint32_t hv;
506     hv = hash(key, nkey);
507     item_lock(hv);
508     it = do_item_get(key, nkey, hv);
509     item_unlock(hv);
510     return it;
511 }
512 
513 item *item_touch(const char *key, size_t nkey, uint32_t exptime) {
514     item *it;
515     uint32_t hv;
516     hv = hash(key, nkey);
517     item_lock(hv);
518     it = do_item_touch(key, nkey, exptime, hv);
519     item_unlock(hv);
520     return it;
521 }
522 
523 /*
524  * Links an item into the LRU and hashtable.
525  */
526 int item_link(item *item) {
527     int ret;
528     uint32_t hv;
529 
530     hv = hash(ITEM_key(item), item->nkey);
531     item_lock(hv);
532     ret = do_item_link(item, hv);
533     item_unlock(hv);
534     return ret;
535 }
536 
537 /*
538  * Decrements the reference count on an item and adds it to the freelist if
539  * needed.
540  */
541 void item_remove(item *item) {
542     uint32_t hv;
543     hv = hash(ITEM_key(item), item->nkey);
544 
545     item_lock(hv);
546     do_item_remove(item);
547     item_unlock(hv);
548 }
549 
550 /*
551  * Replaces one item with another in the hashtable.
552  * Unprotected by a mutex lock since the core server does not require
553  * it to be thread-safe.
554  */
555 int item_replace(item *old_it, item *new_it, const uint32_t hv) {
556     return do_item_replace(old_it, new_it, hv);
557 }
558 
559 /*
560  * Unlinks an item from the LRU and hashtable.
561  */
562 void item_unlink(item *item) {
563     uint32_t hv;
564     hv = hash(ITEM_key(item), item->nkey);
565     item_lock(hv);
566     do_item_unlink(item, hv);
567     item_unlock(hv);
568 }
569 
570 /*
571  * Moves an item to the back of the LRU queue.
572  */
573 void item_update(item *item) {
574     uint32_t hv;
575     hv = hash(ITEM_key(item), item->nkey);
576 
577     item_lock(hv);
578     do_item_update(item);
579     item_unlock(hv);
580 }
581 
582 /*
583  * Does arithmetic on a numeric item value.
584  */
585 enum delta_result_type add_delta(conn *c, const char *key,
586                                  const size_t nkey, int incr,
587                                  const int64_t delta, char *buf,
588                                  uint64_t *cas) {
589     enum delta_result_type ret;
590     uint32_t hv;
591 
592     hv = hash(key, nkey);
593     item_lock(hv);
594     ret = do_add_delta(c, key, nkey, incr, delta, buf, cas, hv);
595     item_unlock(hv);
596     return ret;
597 }
598 
599 /*
600  * Stores an item in the cache (high level, obeys set/add/replace semantics)
601  */
602 enum store_item_type store_item(item *item, int comm, conn* c) {
603     enum store_item_type ret;
604     uint32_t hv;
605 
606     hv = hash(ITEM_key(item), item->nkey);
607     item_lock(hv);
608     ret = do_store_item(item, comm, c, hv);
609     item_unlock(hv);
610     return ret;
611 }
612 
613 /*
614  * Flushes expired items after a flush_all call
615  */
616 void item_flush_expired() {
617     mutex_lock(&cache_lock);
618     do_item_flush_expired();
619     mutex_unlock(&cache_lock);
620 }
621 
622 /*
623  * Dumps part of the cache
624  */
625 char *item_cachedump(unsigned int slabs_clsid, unsigned int limit, unsigned int *bytes) {
626     char *ret;
627 
628     mutex_lock(&cache_lock);
629     ret = do_item_cachedump(slabs_clsid, limit, bytes);
630     mutex_unlock(&cache_lock);
631     return ret;
632 }
633 
634 /*
635  * Dumps statistics about slab classes
636  */
637 void  item_stats(ADD_STAT add_stats, void *c) {
638     mutex_lock(&cache_lock);
639     do_item_stats(add_stats, c);
640     mutex_unlock(&cache_lock);
641 }
642 
643 void  item_stats_totals(ADD_STAT add_stats, void *c) {
644     mutex_lock(&cache_lock);
645     do_item_stats_totals(add_stats, c);
646     mutex_unlock(&cache_lock);
647 }
648 
649 /*
650  * Dumps a list of objects of each size in 32-byte increments
651  */
652 void  item_stats_sizes(ADD_STAT add_stats, void *c) {
653     mutex_lock(&cache_lock);
654     do_item_stats_sizes(add_stats, c);
655     mutex_unlock(&cache_lock);
656 }
657 
658 /******************************* GLOBAL STATS ******************************/
659 
660 void STATS_LOCK() {
661     pthread_mutex_lock(&stats_lock);
662 }
663 
664 void STATS_UNLOCK() {
665     pthread_mutex_unlock(&stats_lock);
666 }
667 
668 void threadlocal_stats_reset(void) {
669     int ii, sid;
670     for (ii = 0; ii < settings.num_threads; ++ii) {
671         pthread_mutex_lock(&threads[ii].stats.mutex);
672 
673         threads[ii].stats.get_cmds = 0;
674         threads[ii].stats.get_misses = 0;
675         threads[ii].stats.touch_cmds = 0;
676         threads[ii].stats.touch_misses = 0;
677         threads[ii].stats.delete_misses = 0;
678         threads[ii].stats.incr_misses = 0;
679         threads[ii].stats.decr_misses = 0;
680         threads[ii].stats.cas_misses = 0;
681         threads[ii].stats.bytes_read = 0;
682         threads[ii].stats.bytes_written = 0;
683         threads[ii].stats.flush_cmds = 0;
684         threads[ii].stats.conn_yields = 0;
685         threads[ii].stats.auth_cmds = 0;
686         threads[ii].stats.auth_errors = 0;
687 
688         for(sid = 0; sid < MAX_NUMBER_OF_SLAB_CLASSES; sid++) {
689             threads[ii].stats.slab_stats[sid].set_cmds = 0;
690             threads[ii].stats.slab_stats[sid].get_hits = 0;
691             threads[ii].stats.slab_stats[sid].touch_hits = 0;
692             threads[ii].stats.slab_stats[sid].delete_hits = 0;
693             threads[ii].stats.slab_stats[sid].incr_hits = 0;
694             threads[ii].stats.slab_stats[sid].decr_hits = 0;
695             threads[ii].stats.slab_stats[sid].cas_hits = 0;
696             threads[ii].stats.slab_stats[sid].cas_badval = 0;
697         }
698 
699         pthread_mutex_unlock(&threads[ii].stats.mutex);
700     }
701 }
702 
703 void threadlocal_stats_aggregate(struct thread_stats *stats) {
704     int ii, sid;
705 
706     /* The struct has a mutex, but we can safely set the whole thing
707      * to zero since it is unused when aggregating. */
708     memset(stats, 0, sizeof(*stats));
709 
710     for (ii = 0; ii < settings.num_threads; ++ii) {
711         pthread_mutex_lock(&threads[ii].stats.mutex);
712 
713         stats->get_cmds += threads[ii].stats.get_cmds;
714         stats->get_misses += threads[ii].stats.get_misses;
715         stats->touch_cmds += threads[ii].stats.touch_cmds;
716         stats->touch_misses += threads[ii].stats.touch_misses;
717         stats->delete_misses += threads[ii].stats.delete_misses;
718         stats->decr_misses += threads[ii].stats.decr_misses;
719         stats->incr_misses += threads[ii].stats.incr_misses;
720         stats->cas_misses += threads[ii].stats.cas_misses;
721         stats->bytes_read += threads[ii].stats.bytes_read;
722         stats->bytes_written += threads[ii].stats.bytes_written;
723         stats->flush_cmds += threads[ii].stats.flush_cmds;
724         stats->conn_yields += threads[ii].stats.conn_yields;
725         stats->auth_cmds += threads[ii].stats.auth_cmds;
726         stats->auth_errors += threads[ii].stats.auth_errors;
727 
728         for (sid = 0; sid < MAX_NUMBER_OF_SLAB_CLASSES; sid++) {
729             stats->slab_stats[sid].set_cmds +=
730                 threads[ii].stats.slab_stats[sid].set_cmds;
731             stats->slab_stats[sid].get_hits +=
732                 threads[ii].stats.slab_stats[sid].get_hits;
733             stats->slab_stats[sid].touch_hits +=
734                 threads[ii].stats.slab_stats[sid].touch_hits;
735             stats->slab_stats[sid].delete_hits +=
736                 threads[ii].stats.slab_stats[sid].delete_hits;
737             stats->slab_stats[sid].decr_hits +=
738                 threads[ii].stats.slab_stats[sid].decr_hits;
739             stats->slab_stats[sid].incr_hits +=
740                 threads[ii].stats.slab_stats[sid].incr_hits;
741             stats->slab_stats[sid].cas_hits +=
742                 threads[ii].stats.slab_stats[sid].cas_hits;
743             stats->slab_stats[sid].cas_badval +=
744                 threads[ii].stats.slab_stats[sid].cas_badval;
745         }
746 
747         pthread_mutex_unlock(&threads[ii].stats.mutex);
748     }
749 }
750 
751 void slab_stats_aggregate(struct thread_stats *stats, struct slab_stats *out) {
752     int sid;
753 
754     out->set_cmds = 0;
755     out->get_hits = 0;
756     out->touch_hits = 0;
757     out->delete_hits = 0;
758     out->incr_hits = 0;
759     out->decr_hits = 0;
760     out->cas_hits = 0;
761     out->cas_badval = 0;
762 
763     for (sid = 0; sid < MAX_NUMBER_OF_SLAB_CLASSES; sid++) {
764         out->set_cmds += stats->slab_stats[sid].set_cmds;
765         out->get_hits += stats->slab_stats[sid].get_hits;
766         out->touch_hits += stats->slab_stats[sid].touch_hits;
767         out->delete_hits += stats->slab_stats[sid].delete_hits;
768         out->decr_hits += stats->slab_stats[sid].decr_hits;
769         out->incr_hits += stats->slab_stats[sid].incr_hits;
770         out->cas_hits += stats->slab_stats[sid].cas_hits;
771         out->cas_badval += stats->slab_stats[sid].cas_badval;
772     }
773 }
774 
775 /*
776  * Initializes the thread subsystem, creating various worker threads.
777  *
778  * nthreads  Number of worker event handler threads to spawn
779  * main_base Event base for main thread
780  */
781 void thread_init(int nthreads, struct event_base *main_base) {
782     int         i;
783     int         power;
784 
785     pthread_mutex_init(&cache_lock, NULL);
786     pthread_mutex_init(&stats_lock, NULL);
787 
788     pthread_mutex_init(&init_lock, NULL);
789     pthread_cond_init(&init_cond, NULL);
790 
791     pthread_mutex_init(&cqi_freelist_lock, NULL);
792     cqi_freelist = NULL;
793 
794     /* Want a wide lock table, but don't waste memory */
795     if (nthreads < 3) {
796         power = 10;
797     } else if (nthreads < 4) {
798         power = 11;
799     } else if (nthreads < 5) {
800         power = 12;
801     } else {
802         /* 8192 buckets, and central locks don't scale much past 5 threads */
803         power = 13;
804     }
805 
806     item_lock_count = hashsize(power);
807     item_lock_hashpower = power;
808 
809     item_locks = calloc(item_lock_count, sizeof(pthread_mutex_t));
810     if (! item_locks) {
811         perror("Can't allocate item locks");
812         exit(1);
813     }
814     for (i = 0; i < item_lock_count; i++) {
815         pthread_mutex_init(&item_locks[i], NULL);
816     }
817     pthread_key_create(&item_lock_type_key, NULL);
818     pthread_mutex_init(&item_global_lock, NULL);
819 
820     threads = calloc(nthreads, sizeof(LIBEVENT_THREAD));
821     if (! threads) {
822         perror("Can't allocate thread descriptors");
823         exit(1);
824     }
825 
826     dispatcher_thread.base = main_base;
827     dispatcher_thread.thread_id = pthread_self();
828 
829     for (i = 0; i < nthreads; i++) {
830         int fds[2];
831         if (pipe(fds)) {
832             perror("Can't create notify pipe");
833             exit(1);
834         }
835 
836         threads[i].notify_receive_fd = fds[0];
837         threads[i].notify_send_fd = fds[1];
838 
839         setup_thread(&threads[i]);
840         /* Reserve three fds for the libevent base, and two for the pipe */
841         stats.reserved_fds += 5;
842     }
843 
844     /* Create threads after we've done all the libevent setup. */
845     for (i = 0; i < nthreads; i++) {
846         create_worker(worker_libevent, &threads[i]);
847     }
848 
849     /* Wait for all the threads to set themselves up before returning. */
850     pthread_mutex_lock(&init_lock);
851     wait_for_thread_registration(nthreads);
852     pthread_mutex_unlock(&init_lock);
853 }
854 
855