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

[经验分享] Memcached源码分析之set操作

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2014-3-31 09:57:21 | 显示全部楼层 |阅读模式
之前分析了Memcached的get操作,下面分析set操作的流程。
//存储item  
enum store_item_type store_item(item *item, int comm, conn* c) {  
    enum store_item_type ret;  
    uint32_t hv;  

    hv = hash(ITEM_key(item), item->nkey, 0);//获取Hash表的分段锁  
    item_lock(hv);//执行数据同步  
    ret = do_store_item(item, comm, c, hv);//存储item  
    item_unlock(hv);  
    return ret;  
}  
//存储item  
enum store_item_type do_store_item(item *it, int comm, conn *c,const uint32_t hv)  
{  
    char *key = ITEM_key(it);//读取item对应的key  
    item *old_it = do_item_get(key, it->nkey, hv);//读取相应的item,如果没有相关的数据,old_it为NULL  
    enum store_item_type stored = NOT_STORED;//item状态标记  

    item *new_it = NULL;  
    int flags;  

    if (old_it != NULL && comm == NREAD_ADD)//如果old_it不为NULL,且操作为add操作  
    {  
        do_item_update(old_it);//更新数据  
    }  
    else if (!old_it  
            && (comm == NREAD_REPLACE || comm == NREAD_APPEND  
                    || comm == NREAD_PREPEND)) //old_it为空,且操作为REPLACE,则什么都不做  
    {  
          //memcached的Replace操作是替换已有的数据,如果没有相关数据,则不做任何操作  
    }  
    else if (comm == NREAD_CAS)//以cas方式读取  
    {  
        if (old_it == NULL) //为空  
        {  
            // LRU expired  
            stored = NOT_FOUND;//修改状态  
            pthread_mutex_lock(&c->thread->stats.mutex);//更新Worker线程统计数据  
            c->thread->stats.cas_misses++;  
            pthread_mutex_unlock(&c->thread->stats.mutex);  
        }  
        else if (ITEM_get_cas(it) == ITEM_get_cas(old_it))//old_it不为NULL,且cas属性一致  
        {  
            pthread_mutex_lock(&c->thread->stats.mutex);  
            c->thread->stats.slab_stats[old_it->slabs_clsid].cas_hits++;//更新Worker线程统计信息  
            pthread_mutex_unlock(&c->thread->stats.mutex);  

            item_replace(old_it, it, hv);//执行item的替换操作,用新的item替换老的item  
            stored = STORED;//修改状态值  
        }  
        else//old_it不为NULL,且cas属性不一致  
        {  
            pthread_mutex_lock(&c->thread->stats.mutex);  
            c->thread->stats.slab_stats[old_it->slabs_clsid].cas_badval++;//更新Worker线程统计信息  
            pthread_mutex_unlock(&c->thread->stats.mutex);  

            if (settings.verbose > 1)  
            {  
                fprintf(stderr, "CAS:  failure: expected %llu, got %llu\n",  
                        (unsigned long long) ITEM_get_cas(old_it),  
                        (unsigned long long) ITEM_get_cas(it));  
            }  
            stored = EXISTS;//修改状态值,修改状态值为已经存在,且不存储最新的数据  
        }  
    }  
    else //执行其他操作的写  
    {  
        if (comm == NREAD_APPEND || comm == NREAD_PREPEND)//以追加的方式执行写  
        {  

            if (ITEM_get_cas(it) != 0)//验证cas有效性  
            {  
                if (ITEM_get_cas(it) != ITEM_get_cas(old_it))//cas验证不通过  
                {  
                    stored = EXISTS;//修改状态值为已存在  
                }  
            }  

            if (stored == NOT_STORED)//状态值为没有存储,也就是cas验证通过,则执行写操作  
            {  
                flags = (int) strtol(ITEM_suffix(old_it), (char **) NULL, 10);  
                //申请新的空间  
                new_it = do_item_alloc(key, it->nkey, flags, old_it->exptime,it->nbytes + old_it->nbytes - 2 , hv);  

                if (new_it == NULL)  
                {  
                    //空间不足  
                    if (old_it != NULL)  
                        do_item_remove(old_it);//删除老的item  

                    return NOT_STORED;  
                }  

                if (comm == NREAD_APPEND)//追加方式  
                {     
                    memcpy(ITEM_data(new_it), ITEM_data(old_it),old_it->nbytes);//老数据拷贝到新数据中  
                    memcpy(ITEM_data(new_it) + old_it->nbytes - 2,ITEM_data(it), it->nbytes);//同时拷贝最近缓冲区已有的数据  
                }  
                else  
                {  
                    //这里和具体协议相关  
                    memcpy(ITEM_data(new_it), ITEM_data(it), it->nbytes);//拷贝it的数据到new_it中  
                    memcpy(ITEM_data(new_it) + it->nbytes - 2 ,ITEM_data(old_it), old_it->nbytes);//同时拷贝最近缓冲区已有的数据  
                }  

                it = new_it;  
            }  
        }  

        if (stored == NOT_STORED)  
        {  
            if (old_it != NULL)//如果old_it不为空  
                item_replace(old_it, it, hv);//替换老的值  
            else  
                do_item_link(it, hv);//重新存储数据  

            c->cas = ITEM_get_cas(it);//获取cas值  

            stored = STORED;  
        }  
    }  

    if (old_it != NULL)  
        do_item_remove(old_it);//释放空间  
    if (new_it != NULL)  
        do_item_remove(new_it);//释放空间  

    if (stored == STORED)//如果已经存储了  
    {  
        c->cas = ITEM_get_cas(it);//获取cas属性  
    }  

    return stored;  
}  
//更新item,这个只更新时间  
void do_item_update(item *it) {  
    MEMCACHED_ITEM_UPDATE(ITEM_key(it), it->nkey, it->nbytes);  
    if (it->time < current_time - ITEM_UPDATE_INTERVAL) {//更新有时间限制  
        assert((it->it_flags & ITEM_SLABBED) == 0);  

        mutex_lock(&cache_lock);//保持同步  
        if ((it->it_flags & ITEM_LINKED) != 0) {//更新LRU队列的Item  
            item_unlink_q(it);//断开连接  
            it->time = current_time;//更新item的时间  
            item_link_q(it);//重新添加  
        }  
        mutex_unlock(&cache_lock);  
    }  
}   
//用新的item替换老的item  
int do_item_replace(item *it, item *new_it, const uint32_t hv) {  
    MEMCACHED_ITEM_REPLACE(ITEM_key(it), it->nkey, it->nbytes,  
                           ITEM_key(new_it), new_it->nkey, new_it->nbytes);  
    assert((it->it_flags & ITEM_SLABBED) == 0);//判断it是已经分配过的,如果未分配,则断言失败  

    do_item_unlink(it, hv);//断开连接  
    return do_item_link(new_it, hv);//重新添加  
}  
有些item的操作已经在get操作中有分析,我们此处不做分析,我们下一篇分析下Memcached内部如何选择合适的空间来存放item.



运维网声明 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-16504-1-1.html 上篇帖子: memcache 键名的命名规则以及和memcached的区别 下篇帖子: Memcached源码解析之cas属性
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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

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

扫描微信二维码查看详情

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


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


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


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



合作伙伴: 青云cloud

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