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