首页 > 其他 > 详细

memcache研究笔记 之 item_locks锁数组

时间:2014-03-22 13:52:03      阅读:492      评论:0      收藏:0      [点我收藏+]

mc里面用了大量的锁,简直是随处可见,在确保不死锁的同时保证性能!里面精髓之处值得琢磨学习

mc用了哪些锁:conn_lock、slabs_lock、slabs_rebalance_lock、hold_lock、item_locks

本篇针对item_locks的粒度变化做了研究:

static pthread_mutex_t *item_locks;
item_lock_count = hashsize(power);    默认4个threads,threads与item_locks成正比!
item_locks = calloc(item_lock_count, sizeof(pthread_mutex_t));
item_locks[(hv & hashmask(hashpower)) % item_lock_count]   桶对应的锁

锁有两种粒度:
enum item_lock_types {  
    ITEM_LOCK_GRANULAR = 0,  细粒度的锁
    ITEM_LOCK_GLOBAL     //在扩展的时候会被切换到全局锁
}; 
memcached在扩容操作时,加的都是全局锁,就是所有item(所有hash桶中的)都是一把锁,在扩容结束时,item锁被重新切换回hash桶上的锁,这里锁是分段加锁的(几个桶一个锁,这个具体数值取决与初始的worker的数量,worker数量越多,锁越细,越少hash桶公用一个锁)。

::switch_item_lock_type
void switch_item_lock_type(enum item_lock_types type) {
    char buf[1];
    int i;
    switch (type) {
        case ITEM_LOCK_GRANULAR:
            buf[0] = ‘l‘;
            break;
        case ITEM_LOCK_GLOBAL:
            buf[0] = ‘g‘;
            break;
        default:
            fprintf(stderr, "Unknown lock type: %d\n", type);
            assert(1 == 0);
            break;
    }
    pthread_mutex_lock(&init_lock);
    init_count = 0;
    for (i = 0; i < settings.num_threads; i++) {
        if (write(threads[i].notify_send_fd, buf, 1) != 1) {  /* Listen for notifications from other threads */往管道写状态
            perror("Failed writing to notify pipe");
            /* TODO: This is a fatal problem. Can it ever happen temporarily? */
        }
    }
    wait_for_thread_registration(settings.num_threads);   //等待每个线程处理完设置完锁的类型,然后一直等待!!![标签1]
    pthread_mutex_unlock(&init_lock);
}

::setup_thread (LIBEVENT_THREAD *me)     就是在这里注册了管道读回调事件thread_libevent_process
    /* Listen for notifications from other threads */
    event_set(&me->notify_event, me->notify_receive_fdEV_READ | EV_PERSIST, thread_libevent_process, me);  
如果收到了管道读回调事件:
::thread_libevent_process
    case ‘g‘:
    me->item_lock_type = ITEM_LOCK_GLOBAL;
    register_thread_initialized();   //pthread_cond_signal(&init_cond);锁类型更新后发出条件信号告诉[标签1]类型已经改变   [标签2]
    break;

再来看下item和item_lock_types 的关系,这些明白了,在wait_for_thread_registration完成后lock_type变了,如果遇到hash表扩容的话,变成全局锁,否则使用小粒度的局部锁来管理被划定的几个桶!
void item_lock(uint32_t hv) {
    uint8_t *lock_type = pthread_getspecific(item_lock_type_key);
    if (likely(*lock_type == ITEM_LOCK_GRANULAR)) {
        mutex_lock(&item_locks[(hv & hashmask(hashpower)) % item_lock_count]);
    } else {
        mutex_lock(&item_global_lock);
    }
}

上面完成了switch_item_lock_type的意图:锁粒度的升降级




memcache研究笔记 之 item_locks锁数组,布布扣,bubuko.com

memcache研究笔记 之 item_locks锁数组

原文:http://blog.csdn.net/linxuping/article/details/21780993

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!