设为首页 收藏本站
查看: 894|回复: 0

[经验分享] Memcached源码阅读之get过程

[复制链接]

尚未签到

发表于 2015-11-19 07:43:49 | 显示全部楼层 |阅读模式
  我们在前面分析过,Memcached从网络读取完数据,解析数据,如果是get操作,则执行get操作,下面我们分析下get操作的流程。
  

//根据key信息和key的长度信息读取数据
item *item_get(const char *key, const size_t nkey) {
item *it;
uint32_t hv;
hv = hash(key, nkey, 0);//获得分段锁信息,如果未进行扩容,则item的hash表是多个hash桶共用同一个锁,即是分段的锁
item_lock(hv);//执行分段加锁
it = do_item_get(key, nkey, hv);//执行get操作
item_unlock(hv);//释放锁
return it;
}
//执行分段加锁
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);
    }
}
//执行分段解锁
void item_unlock(uint32_t hv) {
    uint8_t *lock_type = pthread_getspecific(item_lock_type_key);
    if (likely(*lock_type == ITEM_LOCK_GRANULAR)) {
        mutex_unlock(&item_locks[(hv & hashmask(hashpower)) % item_lock_count]);//释放分段锁
    } else {//如果在扩容过程中
        mutex_unlock(&item_global_lock);
    }
}
//执行读取操作
item *do_item_get(const char *key, const size_t nkey, const uint32_t hv) {
    item *it = assoc_find(key, nkey, hv);//从Hash表中获取相应的结构
    if (it != NULL) {
        refcount_incr(&it->refcount);//item的引用次数+1
        if (slab_rebalance_signal && //如果正在进行slab调整,且该item是调整的对象
            ((void *)it >= slab_rebal.slab_start && (void *)it < slab_rebal.slab_end)) {
            do_item_unlink_nolock(it, hv);//将item从hashtable和LRU链中移除
            do_item_remove(it);//删除item
            it = NULL;//置为空
        }
    }
    int was_found = 0;
    //打印调试信息
    if (settings.verbose > 2) {
        if (it == NULL) {
            fprintf(stderr, &quot;> NOT FOUND %s&quot;, key);
        } else {
            fprintf(stderr, &quot;> FOUND KEY %s&quot;, ITEM_key(it));
            was_found++;
        }
    }
    if (it != NULL) {
        //判断Memcached初始化是否开启过期删除机制,如果开启,则执行删除相关操作
        if (settings.oldest_live != 0 && settings.oldest_live <= current_time &&
            it->time <= settings.oldest_live) {
            do_item_unlink(it, hv);//将item从hashtable和LRU链中移除           
            do_item_remove(it);//删除item
            it = NULL;
            if (was_found) {
                fprintf(stderr, &quot; -nuked by flush&quot;);
            }
        //判断item是否过期
        } else if (it->exptime != 0 && it->exptime <= current_time) {
            do_item_unlink(it, hv);//将item从hashtable和LRU链中移除
            do_item_remove(it);//删除item
            it = NULL;
            if (was_found) {
                fprintf(stderr, &quot; -nuked by expire&quot;);
            }
        } else {
            it->it_flags |= ITEM_FETCHED;//item的标识修改为已经读取
            DEBUG_REFCNT(it, '+');
        }
    }
    if (settings.verbose > 2)
        fprintf(stderr, &quot;\n&quot;);
    return it;
}
//移除item
void do_item_remove(item *it) {
    MEMCACHED_ITEM_REMOVE(ITEM_key(it), it->nkey, it->nbytes);
    assert((it->it_flags & ITEM_SLABBED) == 0);//判断item的状态是否正确
    if (refcount_decr(&it->refcount) == 0) {//修改item的引用次数
        item_free(it);//释放item
    }
}
//释放item
void item_free(item *it) {
    size_t ntotal = ITEM_ntotal(it);//获得item的大小
    unsigned int clsid;
    assert((it->it_flags & ITEM_LINKED) == 0);//判断item的状态是否正确
    assert(it != heads[it->slabs_clsid]);//item不能为LRU的头指针
    assert(it != tails[it->slabs_clsid]);//item不能为LRU的尾指针
    assert(it->refcount == 0);//释放时,需保证引用次数为0
    /* so slab size changer can tell later if item is already free or not */
    clsid = it->slabs_clsid;
    it->slabs_clsid = 0;//断开slabclass的链接
    DEBUG_REFCNT(it, 'F');
    slabs_free(it, ntotal, clsid);//slabclass结构执行释放
}
//slabclass结构释放
void slabs_free(void *ptr, size_t size, unsigned int id) {
    pthread_mutex_lock(&slabs_lock);//保持同步
    do_slabs_free(ptr, size, id);//执行释放
    pthread_mutex_unlock(&slabs_lock);
}
//slabclass结构释放
static void do_slabs_free(void *ptr, const size_t size, unsigned int id) {
    slabclass_t *p;
    item *it;
    assert(((item *)ptr)->slabs_clsid == 0);//判断数据是否正确
    assert(id >= POWER_SMALLEST && id <= power_largest);//判断id合法性
    if (id < POWER_SMALLEST || id > power_largest)//判断id合法性
        return;
    MEMCACHED_SLABS_FREE(size, id, ptr);
    p = &slabclass[id];
    it = (item *)ptr;
    it->it_flags |= ITEM_SLABBED;//修改item的状态标识,修改为空闲
    it->prev = 0;//断开数据链表
    it->next = p->slots;
    if (it->next) it->next->prev = it;
    p->slots = it;
    p->sl_curr++;//空闲item个数+1
    p->requested -= size;//空间增加size
    return;
}
//将item从hashtable和LRU链中移除。是do_item_link的逆操作
void do_item_unlink(item *it, const uint32_t hv) {
    MEMCACHED_ITEM_UNLINK(ITEM_key(it), it->nkey, it->nbytes);
    mutex_lock(&cache_lock);//执行同步
    if ((it->it_flags & ITEM_LINKED) != 0) {//判断状态值,保证item还在LRU队列中
        it->it_flags &= ~ITEM_LINKED;//修改状态值
        STATS_LOCK();//更新统计信息
        stats.curr_bytes -= ITEM_ntotal(it);
        stats.curr_items -= 1;
        STATS_UNLOCK();
        assoc_delete(ITEM_key(it), it->nkey, hv);//从Hash表中删除
        item_unlink_q(it);//将item从slabclass对应的LRU队列摘除
        do_item_remove(it);//移除item
    }
    mutex_unlock(&cache_lock);
}

  
  Memcached的get操作在读取数据时,会判断数据的有效性,使得不用额外去处理过期数据,get操作牵涉到Slab结构,Hash表,LRU队列的更新,我们后面专门分析这些的变更,这里暂不分析。


  



版权声明:本文为博主原创文章,未经博主允许不得转载。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-140867-1-1.html 上篇帖子: Nginx + Tomcat 7 + Memcached 集群配置 下篇帖子: Memcached分布式Cache的简单测试
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表