xref: /memcached-1.4.29/thread.c (revision f5e4d26d)
1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  * Thread management for memcached.
4  *
5  *  $Id$
6  */
7 #include "memcached.h"
8 #include <stdio.h>
9 #include <errno.h>
10 #include <stdlib.h>
11 #include <errno.h>
12 
13 #ifdef HAVE_MALLOC_H
14 #include <malloc.h>
15 #endif
16 
17 #ifdef HAVE_STRING_H
18 #include <string.h>
19 #endif
20 
21 #ifdef USE_THREADS
22 
23 #include <pthread.h>
24 
25 #define ITEMS_PER_ALLOC 64
26 
27 /* An item in the connection queue. */
28 typedef struct conn_queue_item CQ_ITEM;
29 struct conn_queue_item {
30     int     sfd;
31     int     init_state;
32     int     event_flags;
33     int     read_buffer_size;
34     int     protocol;
35     CQ_ITEM *next;
36 };
37 
38 /* A connection queue. */
39 typedef struct conn_queue CQ;
40 struct conn_queue {
41     CQ_ITEM *head;
42     CQ_ITEM *tail;
43     pthread_mutex_t lock;
44     pthread_cond_t  cond;
45 };
46 
47 /* Lock for connection freelist */
48 static pthread_mutex_t conn_lock;
49 
50 /* Lock for alternative item suffix freelist */
51 static pthread_mutex_t suffix_lock;
52 
53 /* Lock for cache operations (item_*, assoc_*) */
54 static pthread_mutex_t cache_lock;
55 
56 /* Lock for slab allocator operations */
57 static pthread_mutex_t slabs_lock;
58 
59 /* Lock for global stats */
60 static pthread_mutex_t stats_lock;
61 
62 /* Free list of CQ_ITEM structs */
63 static CQ_ITEM *cqi_freelist;
64 static pthread_mutex_t cqi_freelist_lock;
65 
66 /*
67  * Each libevent instance has a wakeup pipe, which other threads
68  * can use to signal that they've put a new connection on its queue.
69  */
70 typedef struct {
71     pthread_t thread_id;        /* unique ID of this thread */
72     struct event_base *base;    /* libevent handle this thread uses */
73     struct event notify_event;  /* listen event for notify pipe */
74     int notify_receive_fd;      /* receiving end of notify pipe */
75     int notify_send_fd;         /* sending end of notify pipe */
76     CQ  new_conn_queue;         /* queue of new connections to handle */
77 } LIBEVENT_THREAD;
78 
79 static LIBEVENT_THREAD *threads;
80 
81 /*
82  * Number of threads that have finished setting themselves up.
83  */
84 static int init_count = 0;
85 static pthread_mutex_t init_lock;
86 static pthread_cond_t init_cond;
87 
88 
89 static void thread_libevent_process(int fd, short which, void *arg);
90 
91 /*
92  * Initializes a connection queue.
93  */
94 static void cq_init(CQ *cq) {
95     pthread_mutex_init(&cq->lock, NULL);
96     pthread_cond_init(&cq->cond, NULL);
97     cq->head = NULL;
98     cq->tail = NULL;
99 }
100 
101 /*
102  * Waits for work on a connection queue.
103  */
104 static CQ_ITEM *cq_pop(CQ *cq) {
105     CQ_ITEM *item;
106 
107     pthread_mutex_lock(&cq->lock);
108     while (NULL == cq->head)
109         pthread_cond_wait(&cq->cond, &cq->lock);
110     item = cq->head;
111     cq->head = item->next;
112     if (NULL == cq->head)
113         cq->tail = NULL;
114     pthread_mutex_unlock(&cq->lock);
115 
116     return item;
117 }
118 
119 /*
120  * Looks for an item on a connection queue, but doesn't block if there isn't
121  * one.
122  * Returns the item, or NULL if no item is available
123  */
124 static CQ_ITEM *cq_peek(CQ *cq) {
125     CQ_ITEM *item;
126 
127     pthread_mutex_lock(&cq->lock);
128     item = cq->head;
129     if (NULL != item) {
130         cq->head = item->next;
131         if (NULL == cq->head)
132             cq->tail = NULL;
133     }
134     pthread_mutex_unlock(&cq->lock);
135 
136     return item;
137 }
138 
139 /*
140  * Adds an item to a connection queue.
141  */
142 static void cq_push(CQ *cq, CQ_ITEM *item) {
143     item->next = NULL;
144 
145     pthread_mutex_lock(&cq->lock);
146     if (NULL == cq->tail)
147         cq->head = item;
148     else
149         cq->tail->next = item;
150     cq->tail = item;
151     pthread_cond_signal(&cq->cond);
152     pthread_mutex_unlock(&cq->lock);
153 }
154 
155 /*
156  * Returns a fresh connection queue item.
157  */
158 static CQ_ITEM *cqi_new() {
159     CQ_ITEM *item = NULL;
160     pthread_mutex_lock(&cqi_freelist_lock);
161     if (cqi_freelist) {
162         item = cqi_freelist;
163         cqi_freelist = item->next;
164     }
165     pthread_mutex_unlock(&cqi_freelist_lock);
166 
167     if (NULL == item) {
168         int i;
169 
170         /* Allocate a bunch of items at once to reduce fragmentation */
171         item = malloc(sizeof(CQ_ITEM) * ITEMS_PER_ALLOC);
172         if (NULL == item)
173             return NULL;
174 
175         /*
176          * Link together all the new items except the first one
177          * (which we'll return to the caller) for placement on
178          * the freelist.
179          */
180         for (i = 2; i < ITEMS_PER_ALLOC; i++)
181             item[i - 1].next = &item[i];
182 
183         pthread_mutex_lock(&cqi_freelist_lock);
184         item[ITEMS_PER_ALLOC - 1].next = cqi_freelist;
185         cqi_freelist = &item[1];
186         pthread_mutex_unlock(&cqi_freelist_lock);
187     }
188 
189     return item;
190 }
191 
192 
193 /*
194  * Frees a connection queue item (adds it to the freelist.)
195  */
196 static void cqi_free(CQ_ITEM *item) {
197     pthread_mutex_lock(&cqi_freelist_lock);
198     item->next = cqi_freelist;
199     cqi_freelist = item;
200     pthread_mutex_unlock(&cqi_freelist_lock);
201 }
202 
203 
204 /*
205  * Creates a worker thread.
206  */
207 static void create_worker(void *(*func)(void *), void *arg) {
208     pthread_t       thread;
209     pthread_attr_t  attr;
210     int             ret;
211 
212     pthread_attr_init(&attr);
213 
214     if ((ret = pthread_create(&thread, &attr, func, arg)) != 0) {
215         fprintf(stderr, "Can't create thread: %s\n",
216                 strerror(ret));
217         exit(1);
218     }
219 }
220 
221 
222 /*
223  * Pulls a conn structure from the freelist, if one is available.
224  */
225 conn *mt_conn_from_freelist() {
226     conn *c;
227 
228     pthread_mutex_lock(&conn_lock);
229     c = do_conn_from_freelist();
230     pthread_mutex_unlock(&conn_lock);
231 
232     return c;
233 }
234 
235 
236 /*
237  * Adds a conn structure to the freelist.
238  *
239  * Returns 0 on success, 1 if the structure couldn't be added.
240  */
241 bool mt_conn_add_to_freelist(conn *c) {
242     bool result;
243 
244     pthread_mutex_lock(&conn_lock);
245     result = do_conn_add_to_freelist(c);
246     pthread_mutex_unlock(&conn_lock);
247 
248     return result;
249 }
250 
251 /*
252  * Pulls a suffix buffer from the freelist, if one is available.
253  */
254 char *mt_suffix_from_freelist() {
255     char *s;
256 
257     pthread_mutex_lock(&suffix_lock);
258     s = do_suffix_from_freelist();
259     pthread_mutex_unlock(&suffix_lock);
260 
261     return s;
262 }
263 
264 
265 /*
266  * Adds a suffix buffer to the freelist.
267  *
268  * Returns 0 on success, 1 if the buffer couldn't be added.
269  */
270 bool mt_suffix_add_to_freelist(char *s) {
271     bool result;
272 
273     pthread_mutex_lock(&suffix_lock);
274     result = do_suffix_add_to_freelist(s);
275     pthread_mutex_unlock(&suffix_lock);
276 
277     return result;
278 }
279 
280 
281 /****************************** LIBEVENT THREADS *****************************/
282 
283 /*
284  * Set up a thread's information.
285  */
286 static void setup_thread(LIBEVENT_THREAD *me) {
287     if (! me->base) {
288         me->base = event_init();
289         if (! me->base) {
290             fprintf(stderr, "Can't allocate event base\n");
291             exit(1);
292         }
293     }
294 
295     /* Listen for notifications from other threads */
296     event_set(&me->notify_event, me->notify_receive_fd,
297               EV_READ | EV_PERSIST, thread_libevent_process, me);
298     event_base_set(me->base, &me->notify_event);
299 
300     if (event_add(&me->notify_event, 0) == -1) {
301         fprintf(stderr, "Can't monitor libevent notify pipe\n");
302         exit(1);
303     }
304 
305     cq_init(&me->new_conn_queue);
306 }
307 
308 
309 /*
310  * Worker thread: main event loop
311  */
312 static void *worker_libevent(void *arg) {
313     LIBEVENT_THREAD *me = arg;
314 
315     /* Any per-thread setup can happen here; thread_init() will block until
316      * all threads have finished initializing.
317      */
318 
319     pthread_mutex_lock(&init_lock);
320     init_count++;
321     pthread_cond_signal(&init_cond);
322     pthread_mutex_unlock(&init_lock);
323 
324     return (void*) event_base_loop(me->base, 0);
325 }
326 
327 
328 /*
329  * Processes an incoming "handle a new connection" item. This is called when
330  * input arrives on the libevent wakeup pipe.
331  */
332 static void thread_libevent_process(int fd, short which, void *arg) {
333     LIBEVENT_THREAD *me = arg;
334     CQ_ITEM *item;
335     char buf[1];
336 
337     if (read(fd, buf, 1) != 1)
338         if (settings.verbose > 0)
339             fprintf(stderr, "Can't read from libevent pipe\n");
340 
341     item = cq_peek(&me->new_conn_queue);
342 
343     if (NULL != item) {
344         conn *c = conn_new(item->sfd, item->init_state, item->event_flags,
345                            item->read_buffer_size, item->protocol, me->base);
346         if (c == NULL) {
347             if (IS_UDP(item->protocol)) {
348                 fprintf(stderr, "Can't listen for events on UDP socket\n");
349                 exit(1);
350             } else {
351                 if (settings.verbose > 0) {
352                     fprintf(stderr, "Can't listen for events on fd %d\n",
353                         item->sfd);
354                 }
355                 close(item->sfd);
356             }
357         }
358         cqi_free(item);
359     }
360 }
361 
362 /* Which thread we assigned a connection to most recently. */
363 static int last_thread = -1;
364 
365 /*
366  * Dispatches a new connection to another thread. This is only ever called
367  * from the main thread, either during initialization (for UDP) or because
368  * of an incoming connection.
369  */
370 void dispatch_conn_new(int sfd, enum conn_states init_state, int event_flags,
371                        int read_buffer_size, enum protocol prot) {
372     CQ_ITEM *item = cqi_new();
373     int thread = (last_thread + 1) % settings.num_threads;
374 
375     last_thread = thread;
376 
377     item->sfd = sfd;
378     item->init_state = init_state;
379     item->event_flags = event_flags;
380     item->read_buffer_size = read_buffer_size;
381     item->protocol = prot;
382 
383     cq_push(&threads[thread].new_conn_queue, item);
384     if (write(threads[thread].notify_send_fd, "", 1) != 1) {
385         perror("Writing to thread notify pipe");
386     }
387 }
388 
389 /*
390  * Returns true if this is the thread that listens for new TCP connections.
391  */
392 int mt_is_listen_thread() {
393     return pthread_self() == threads[0].thread_id;
394 }
395 
396 /********************************* ITEM ACCESS *******************************/
397 
398 /*
399  * Walks through the list of deletes that have been deferred because the items
400  * were locked down at the tmie.
401  */
402 void mt_run_deferred_deletes() {
403     pthread_mutex_lock(&cache_lock);
404     do_run_deferred_deletes();
405     pthread_mutex_unlock(&cache_lock);
406 }
407 
408 /*
409  * Allocates a new item.
410  */
411 item *mt_item_alloc(char *key, size_t nkey, int flags, rel_time_t exptime, int nbytes) {
412     item *it;
413     pthread_mutex_lock(&cache_lock);
414     it = do_item_alloc(key, nkey, flags, exptime, nbytes);
415     pthread_mutex_unlock(&cache_lock);
416     return it;
417 }
418 
419 /*
420  * Returns an item if it hasn't been marked as expired or deleted,
421  * lazy-expiring as needed.
422  */
423 item *mt_item_get_notedeleted(const char *key, const size_t nkey, bool *delete_locked) {
424     item *it;
425     pthread_mutex_lock(&cache_lock);
426     it = do_item_get_notedeleted(key, nkey, delete_locked);
427     pthread_mutex_unlock(&cache_lock);
428     return it;
429 }
430 
431 /*
432  * Links an item into the LRU and hashtable.
433  */
434 int mt_item_link(item *item) {
435     int ret;
436 
437     pthread_mutex_lock(&cache_lock);
438     ret = do_item_link(item);
439     pthread_mutex_unlock(&cache_lock);
440     return ret;
441 }
442 
443 /*
444  * Decrements the reference count on an item and adds it to the freelist if
445  * needed.
446  */
447 void mt_item_remove(item *item) {
448     pthread_mutex_lock(&cache_lock);
449     do_item_remove(item);
450     pthread_mutex_unlock(&cache_lock);
451 }
452 
453 /*
454  * Replaces one item with another in the hashtable.
455  */
456 int mt_item_replace(item *old, item *new) {
457     int ret;
458 
459     pthread_mutex_lock(&cache_lock);
460     ret = do_item_replace(old, new);
461     pthread_mutex_unlock(&cache_lock);
462     return ret;
463 }
464 
465 /*
466  * Unlinks an item from the LRU and hashtable.
467  */
468 void mt_item_unlink(item *item) {
469     pthread_mutex_lock(&cache_lock);
470     do_item_unlink(item);
471     pthread_mutex_unlock(&cache_lock);
472 }
473 
474 /*
475  * Moves an item to the back of the LRU queue.
476  */
477 void mt_item_update(item *item) {
478     pthread_mutex_lock(&cache_lock);
479     do_item_update(item);
480     pthread_mutex_unlock(&cache_lock);
481 }
482 
483 /*
484  * Adds an item to the deferred-delete list so it can be reaped later.
485  */
486 char *mt_defer_delete(item *item, time_t exptime) {
487     char *ret;
488 
489     pthread_mutex_lock(&cache_lock);
490     ret = do_defer_delete(item, exptime);
491     pthread_mutex_unlock(&cache_lock);
492     return ret;
493 }
494 
495 /*
496  * Does arithmetic on a numeric item value.
497  */
498 char *mt_add_delta(item *item, int incr, const int64_t delta, char *buf) {
499     char *ret;
500 
501     pthread_mutex_lock(&cache_lock);
502     ret = do_add_delta(item, incr, delta, buf);
503     pthread_mutex_unlock(&cache_lock);
504     return ret;
505 }
506 
507 /*
508  * Stores an item in the cache (high level, obeys set/add/replace semantics)
509  */
510 int mt_store_item(item *item, int comm) {
511     int ret;
512 
513     pthread_mutex_lock(&cache_lock);
514     ret = do_store_item(item, comm);
515     pthread_mutex_unlock(&cache_lock);
516     return ret;
517 }
518 
519 /*
520  * Flushes expired items after a flush_all call
521  */
522 void mt_item_flush_expired() {
523     pthread_mutex_lock(&cache_lock);
524     do_item_flush_expired();
525     pthread_mutex_unlock(&cache_lock);
526 }
527 
528 /*
529  * Dumps part of the cache
530  */
531 char *mt_item_cachedump(unsigned int slabs_clsid, unsigned int limit, unsigned int *bytes) {
532     char *ret;
533 
534     pthread_mutex_lock(&cache_lock);
535     ret = do_item_cachedump(slabs_clsid, limit, bytes);
536     pthread_mutex_unlock(&cache_lock);
537     return ret;
538 }
539 
540 /*
541  * Dumps statistics about slab classes
542  */
543 char *mt_item_stats(int *bytes) {
544     char *ret;
545 
546     pthread_mutex_lock(&cache_lock);
547     ret = do_item_stats(bytes);
548     pthread_mutex_unlock(&cache_lock);
549     return ret;
550 }
551 
552 /*
553  * Dumps a list of objects of each size in 32-byte increments
554  */
555 char *mt_item_stats_sizes(int *bytes) {
556     char *ret;
557 
558     pthread_mutex_lock(&cache_lock);
559     ret = do_item_stats_sizes(bytes);
560     pthread_mutex_unlock(&cache_lock);
561     return ret;
562 }
563 
564 /****************************** HASHTABLE MODULE *****************************/
565 
566 void mt_assoc_move_next_bucket() {
567     pthread_mutex_lock(&cache_lock);
568     do_assoc_move_next_bucket();
569     pthread_mutex_unlock(&cache_lock);
570 }
571 
572 /******************************* SLAB ALLOCATOR ******************************/
573 
574 void *mt_slabs_alloc(size_t size, unsigned int id) {
575     void *ret;
576 
577     pthread_mutex_lock(&slabs_lock);
578     ret = do_slabs_alloc(size, id);
579     pthread_mutex_unlock(&slabs_lock);
580     return ret;
581 }
582 
583 void mt_slabs_free(void *ptr, size_t size, unsigned int id) {
584     pthread_mutex_lock(&slabs_lock);
585     do_slabs_free(ptr, size, id);
586     pthread_mutex_unlock(&slabs_lock);
587 }
588 
589 char *mt_slabs_stats(int *buflen) {
590     char *ret;
591 
592     pthread_mutex_lock(&slabs_lock);
593     ret = do_slabs_stats(buflen);
594     pthread_mutex_unlock(&slabs_lock);
595     return ret;
596 }
597 
598 #ifdef ALLOW_SLABS_REASSIGN
599 int mt_slabs_reassign(unsigned char srcid, unsigned char dstid) {
600     int ret;
601 
602     pthread_mutex_lock(&slabs_lock);
603     ret = do_slabs_reassign(srcid, dstid);
604     pthread_mutex_unlock(&slabs_lock);
605     return ret;
606 }
607 #endif
608 
609 /******************************* GLOBAL STATS ******************************/
610 
611 void mt_stats_lock() {
612     pthread_mutex_lock(&stats_lock);
613 }
614 
615 void mt_stats_unlock() {
616     pthread_mutex_unlock(&stats_lock);
617 }
618 
619 /*
620  * Initializes the thread subsystem, creating various worker threads.
621  *
622  * nthreads  Number of event handler threads to spawn
623  * main_base Event base for main thread
624  */
625 void thread_init(int nthreads, struct event_base *main_base) {
626     int         i;
627 
628     pthread_mutex_init(&cache_lock, NULL);
629     pthread_mutex_init(&conn_lock, NULL);
630     pthread_mutex_init(&slabs_lock, NULL);
631     pthread_mutex_init(&stats_lock, NULL);
632 
633     pthread_mutex_init(&init_lock, NULL);
634     pthread_cond_init(&init_cond, NULL);
635 
636     pthread_mutex_init(&cqi_freelist_lock, NULL);
637     cqi_freelist = NULL;
638 
639     threads = malloc(sizeof(LIBEVENT_THREAD) * nthreads);
640     if (! threads) {
641         perror("Can't allocate thread descriptors");
642         exit(1);
643     }
644 
645     threads[0].base = main_base;
646     threads[0].thread_id = pthread_self();
647 
648     for (i = 0; i < nthreads; i++) {
649         int fds[2];
650         if (pipe(fds)) {
651             perror("Can't create notify pipe");
652             exit(1);
653         }
654 
655         threads[i].notify_receive_fd = fds[0];
656         threads[i].notify_send_fd = fds[1];
657 
658     setup_thread(&threads[i]);
659     }
660 
661     /* Create threads after we've done all the libevent setup. */
662     for (i = 1; i < nthreads; i++) {
663         create_worker(worker_libevent, &threads[i]);
664     }
665 
666     /* Wait for all the threads to set themselves up before returning. */
667     pthread_mutex_lock(&init_lock);
668     init_count++; /* main thread */
669     while (init_count < nthreads) {
670         pthread_cond_wait(&init_cond, &init_lock);
671     }
672     pthread_mutex_unlock(&init_lock);
673 }
674 
675 #endif
676