以下为个人笔记

/**
* process_command 在memcached中是用来处理用户发送的命令的,
* 包括get set,add,delete,replace,stats,flush_all等常用的和不常用的命令,全在这进行处理的。
* 一共有两个参数,conn *c 和字符串指针 char *command ;
* 关于conn结构体就先不说了,反正它是整个memcached中最重要的结构体就行了,等以后研究明白了再说,先从整体上领会精神吧。
* 这里我想说一下的是, memcached 和 redis 在处理命令上的想法还是有很大差别的,
* 在 redis 里面,你要是想看一下一共支持多少命令,每个命令对应的函数,很方便,都在一个名叫 redisCommandTable 的结构体数组里面,一目了然;
* 但是 memcached 却不是这样,我刚开始也是按照看 redis 源码的方式去找 memcached 中的,但是找了很久也没有发现,原因就是作者把支持的所有命令都散落在下面这个函数中了。
* 先说一下 memcached 是怎么从 command 字符串中分解出具体的命令和对应的参数的。
* 在函数中用到了一个结构体数组: tokens[MAX_TOKENS] ,它其实是用来存放分析完的 command 结果用的,分析工作在函数 tokenize_command 中进行。
* 如:有一个命令 "get aaaaaaaaaa" ,分析完以后存在tokens中的就是
* tokens[3] = {{value:"get",length:3},{value:"aaaaaaaaaa",length:10},{value:NULL,length:0}};
* 函数 tokenize_command 返回的是一个int型数据 ntokens,记录了 tokens 的大小,表示从 command 命令中分解出了几条数据,
* 当然 ntokens 的值会比实际中 command 中包含的数据多1,因为字符串结尾的'\0'也要占一样。
*
* 下面说说以 "get aaaaaaaaaa" 命令为例,具体的命令分析和函数调用过程:
* 当一条命令 "get aaaaaaaaaa" 传到 process_command 中之后,先调用负责解析命令的函数tokenize_command,
* 将解析后的命令存储在tokens数组中,结果如上面的tokens[3],并返回ntokens,说明command中包含几个字段(这里得到的是3),
* 然后根据字段的数目进行判断应该到哪个条件语句去进行比对,当确认之后,就会跳到对应的条件语句中
* 所以这里应该到 tokenize_command 下面的第一个if语句中,然后使用tokens[0].value,也就是tokens数组中存储的get命令和字符串"get"进行比较,
* 匹配,则调用对应的函数,这里调用process_get_command(c, tokens, ntokens, false);
* 然后 process_command 的使命就结束了。
* 以下代码在memcached-1.4.22/memcached.c
*/
static void process_command(conn *c, char *command) { token_t tokens[MAX_TOKENS];
size_t ntokens;
int comm; assert(c != NULL); MEMCACHED_PROCESS_COMMAND_START(c->sfd, c->rcurr, c->rbytes); if (settings.verbose > )
fprintf(stderr, "<%d %s\n", c->sfd, command); /*
* for commands set/add/replace, we build an item and read the data
* directly into it, then continue in nread_complete().
*/ c->msgcurr = ;
c->msgused = ;
c->iovused = ;
if (add_msghdr(c) != ) {
out_of_memory(c, "SERVER_ERROR out of memory preparing response");
return;
} ntokens = tokenize_command(command, tokens, MAX_TOKENS);
if (ntokens >= &&
((strcmp(tokens[COMMAND_TOKEN].value, "get") == ) ||
(strcmp(tokens[COMMAND_TOKEN].value, "bget") == ))) { process_get_command(c, tokens, ntokens, false); } else if ((ntokens == || ntokens == ) &&
((strcmp(tokens[COMMAND_TOKEN].value, "add") == && (comm = NREAD_ADD)) ||
(strcmp(tokens[COMMAND_TOKEN].value, "set") == && (comm = NREAD_SET)) ||
(strcmp(tokens[COMMAND_TOKEN].value, "replace") == && (comm = NREAD_REPLACE)) ||
(strcmp(tokens[COMMAND_TOKEN].value, "prepend") == && (comm = NREAD_PREPEND)) ||
(strcmp(tokens[COMMAND_TOKEN].value, "append") == && (comm = NREAD_APPEND)) )) { process_update_command(c, tokens, ntokens, comm, false); } else if ((ntokens == || ntokens == ) && (strcmp(tokens[COMMAND_TOKEN].value, "cas") == && (comm = NREAD_CAS))) { process_update_command(c, tokens, ntokens, comm, true); } else if ((ntokens == || ntokens == ) && (strcmp(tokens[COMMAND_TOKEN].value, "incr") == )) { process_arithmetic_command(c, tokens, ntokens, ); } else if (ntokens >= && (strcmp(tokens[COMMAND_TOKEN].value, "gets") == )) { process_get_command(c, tokens, ntokens, true); } else if ((ntokens == || ntokens == ) && (strcmp(tokens[COMMAND_TOKEN].value, "decr") == )) { process_arithmetic_command(c, tokens, ntokens, ); } else if (ntokens >= && ntokens <= && (strcmp(tokens[COMMAND_TOKEN].value, "delete") == )) { process_delete_command(c, tokens, ntokens); } else if ((ntokens == || ntokens == ) && (strcmp(tokens[COMMAND_TOKEN].value, "touch") == )) { process_touch_command(c, tokens, ntokens); } else if (ntokens >= && (strcmp(tokens[COMMAND_TOKEN].value, "stats") == )) { process_stat(c, tokens, ntokens); } else if (ntokens >= && ntokens <= && (strcmp(tokens[COMMAND_TOKEN].value, "flush_all") == )) {
time_t exptime = ; set_noreply_maybe(c, tokens, ntokens); pthread_mutex_lock(&c->thread->stats.mutex);
c->thread->stats.flush_cmds++;
pthread_mutex_unlock(&c->thread->stats.mutex); if (!settings.flush_enabled) {
// flush_all is not allowed but we log it on stats
out_string(c, "CLIENT_ERROR flush_all not allowed");
return;
} if(ntokens == (c->noreply ? : )) {
settings.oldest_live = current_time - ;
item_flush_expired();
out_string(c, "OK");
return;
} exptime = strtol(tokens[].value, NULL, );
if(errno == ERANGE) {
out_string(c, "CLIENT_ERROR bad command line format");
return;
} /*
If exptime is zero realtime() would return zero too, and
realtime(exptime) - 1 would overflow to the max unsigned
value. So we process exptime == 0 the same way we do when
no delay is given at all.
*/
if (exptime > )
settings.oldest_live = realtime(exptime) - ;
else /* exptime == 0 */
settings.oldest_live = current_time - ;
item_flush_expired();
out_string(c, "OK");
return; } else if (ntokens == && (strcmp(tokens[COMMAND_TOKEN].value, "version") == )) { out_string(c, "VERSION " VERSION); } else if (ntokens == && (strcmp(tokens[COMMAND_TOKEN].value, "quit") == )) { conn_set_state(c, conn_closing); } else if (ntokens == && (strcmp(tokens[COMMAND_TOKEN].value, "shutdown") == )) { if (settings.shutdown_command) {
conn_set_state(c, conn_closing);
raise(SIGINT);
} else {
out_string(c, "ERROR: shutdown not enabled");
} } else if (ntokens > && strcmp(tokens[COMMAND_TOKEN].value, "slabs") == ) {
if (ntokens == && strcmp(tokens[COMMAND_TOKEN + ].value, "reassign") == ) {
int src, dst, rv; if (settings.slab_reassign == false) {
out_string(c, "CLIENT_ERROR slab reassignment disabled");
return;
} src = strtol(tokens[].value, NULL, );
dst = strtol(tokens[].value, NULL, ); if (errno == ERANGE) {
out_string(c, "CLIENT_ERROR bad command line format");
return;
} rv = slabs_reassign(src, dst);
switch (rv) {
case REASSIGN_OK:
out_string(c, "OK");
break;
case REASSIGN_RUNNING:
out_string(c, "BUSY currently processing reassign request");
break;
case REASSIGN_BADCLASS:
out_string(c, "BADCLASS invalid src or dst class id");
break;
case REASSIGN_NOSPARE:
out_string(c, "NOSPARE source class has no spare pages");
break;
case REASSIGN_SRC_DST_SAME:
out_string(c, "SAME src and dst class are identical");
break;
}
return;
} else if (ntokens == &&
(strcmp(tokens[COMMAND_TOKEN + ].value, "automove") == )) {
process_slabs_automove_command(c, tokens, ntokens);
} else {
out_string(c, "ERROR");
}
} else if (ntokens > && strcmp(tokens[COMMAND_TOKEN].value, "lru_crawler") == ) {
if (ntokens == && strcmp(tokens[COMMAND_TOKEN + ].value, "crawl") == ) {
int rv;
if (settings.lru_crawler == false) {
out_string(c, "CLIENT_ERROR lru crawler disabled");
return;
} rv = lru_crawler_crawl(tokens[].value);
switch(rv) {
case CRAWLER_OK:
out_string(c, "OK");
break;
case CRAWLER_RUNNING:
out_string(c, "BUSY currently processing crawler request");
break;
case CRAWLER_BADCLASS:
out_string(c, "BADCLASS invalid class id");
break;
}
return;
} else if (ntokens == && strcmp(tokens[COMMAND_TOKEN + ].value, "tocrawl") == ) {
uint32_t tocrawl;
if (!safe_strtoul(tokens[].value, &tocrawl)) {
out_string(c, "CLIENT_ERROR bad command line format");
return;
}
settings.lru_crawler_tocrawl = tocrawl;
out_string(c, "OK");
return;
} else if (ntokens == && strcmp(tokens[COMMAND_TOKEN + ].value, "sleep") == ) {
uint32_t tosleep;
if (!safe_strtoul(tokens[].value, &tosleep)) {
out_string(c, "CLIENT_ERROR bad command line format");
return;
}
if (tosleep > ) {
out_string(c, "CLIENT_ERROR sleep must be one second or less");
return;
}
settings.lru_crawler_sleep = tosleep;
out_string(c, "OK");
return;
} else if (ntokens == ) {
if ((strcmp(tokens[COMMAND_TOKEN + ].value, "enable") == )) {
if (start_item_crawler_thread() == ) {
out_string(c, "OK");
} else {
out_string(c, "ERROR failed to start lru crawler thread");
}
} else if ((strcmp(tokens[COMMAND_TOKEN + ].value, "disable") == )) {
if (stop_item_crawler_thread() == ) {
out_string(c, "OK");
} else {
out_string(c, "ERROR failed to stop lru crawler thread");
}
} else {
out_string(c, "ERROR");
}
return;
} else {
out_string(c, "ERROR");
}
} else if ((ntokens == || ntokens == ) && (strcmp(tokens[COMMAND_TOKEN].value, "verbosity") == )) {
process_verbosity_command(c, tokens, ntokens);
} else {
out_string(c, "ERROR");
}
return;
}

以上为个人笔记

Memcached源码分析——process_command函数解析的更多相关文章

  1. Memcached源码分析之请求处理(状态机)

    作者:Calix 一)上文 在上一篇线程模型的分析中,我们知道,worker线程和主线程都调用了同一个函数,conn_new进行事件监听,并返回conn结构体对象.最终有事件到达时,调用同一个函数ev ...

  2. Memcached源码分析之从SET命令开始说起

    作者:Calix 如果直接把memcached的源码从main函数开始说,恐怕会有点头大,所以这里以一句经典的“SET”命令简单地开个头,算是回忆一下memcached的作用,后面的结构篇中关于命令解 ...

  3. Memcached源码分析之内存管理

    先再说明一下,我本次分析的memcached版本是1.4.20,有些旧的版本关于内存管理的机制和数据结构与1.4.20有一定的差异(本文中会提到). 一)模型分析在开始解剖memcached关于内存管 ...

  4. memcached源码分析-----item过期失效处理以及LRU爬虫

    memcached源码分析-----item过期失效处理以及LRU爬虫,memcached-----item 转载请注明出处:http://blog.csdn.net/luotuo44/article ...

  5. jQuery 2.0.3 源码分析Sizzle引擎解析原理

    jQuery 2.0.3 源码分析Sizzle引擎 - 解析原理 声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 先来回答博友的提问: 如何解析 div > p + ...

  6. Memcached源码分析之线程模型

    作者:Calix 一)模型分析 memcached到底是如何处理我们的网络连接的? memcached通过epoll(使用libevent,下面具体再讲)实现异步的服务器,但仍然使用多线程,主要有两种 ...

  7. Memcached源码分析

    作者:Calix,转载请注明出处:http://calixwu.com 最近研究了一下memcached的源码,在这里系统总结了一下笔记和理解,写了几 篇源码分析和大家分享,整个系列分为“结构篇”和“ ...

  8. springMVC源码分析--RequestParamMethodArgumentResolver参数解析器(三)

    之前两篇博客springMVC源码分析--HandlerMethodArgumentResolver参数解析器(一)和springMVC源码解析--HandlerMethodArgumentResol ...

  9. 性能测试分享: Jmeter的源码分析main函数参数

    性能测试分享: Jmeter的源码分析main函数参数   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大 ...

随机推荐

  1. lightoj 1407 2-sat

    这题的英语either...or....很蛋疼: m中,1:x与y至少一个出席:2:x出席,y随便,x不出席,y也不出席----这有个坑,可以推出y出席x也一定出席(这个关系必须要连上):3x与y至少 ...

  2. @property 的本质是什么?ivar、getter、setter 是如何生成并添加到这个类中的

    出题者简介: 孙源(sunnyxx),目前就职于百度 整理者简介:陈奕龙(子循),目前就职于滴滴出行. 转载者:豆电雨(starain)微信:doudianyu @property 的本质是什么? @ ...

  3. python2.+进化至python3.+ 语法变动差异(不定期更新)

    1.输出 python2.+ 输出: print "" python3.+ 输出: print ("") 2.打开文件 python2.+ 打开文件: file ...

  4. C# Eval在aspx页面中的用法及作用

    Eval( " ")和Bind( " ") 这两种一个单向绑定,一个双向绑定,bind是双向绑定,但需数据源支持 ASP.NET 2.0改善了模板中的数据绑定操 ...

  5. 初识AM335X

    TI 的AM335X,linux 操作系统,全都是陌生的东东,一点一点来熟悉吧. 拿的TI代理的一开发板,直接看文档.环境由于之前一同事已经装好了,公司条件受限,没法让我们一人一台ubuntu的机子来 ...

  6. mybatis 与 ehcache 整合[转]

    1.简介 MyBatis 是支持普通SQL 查询,存储过程和高级映射的优秀持久层框架.MyBatis 消除了几乎所有的JDBC 代码和参数的手工设置以及结果集的检索. Ehcache 是现在最流行的纯 ...

  7. [PWA] 3. Devtool

    You can debug with chrom dev tool: 1. Use console to debug service worker: Swith to sw.js context th ...

  8. android 怎样内置/预置/预编译文件(运行程序,应用程序,apk, jar, lib 等随意文件)到系统中

    方法一:  如果要内置的软件名称为iperf.exe 1. 将iperf.exe放到Codebase的随意一个文件夹下(该文件夹必须可以在搜索Android.mk时被搜索到),比方system/ipe ...

  9. 图片预览(base64和blob:图片链接)和ajax上传、下载(带进度提示)

    直接上代码 html和js <!DOCTYPE html> <html> <head> <meta name="viewport" con ...

  10. JS可控制的图片自动循环播放查看效果

    JS可控制的图片自动循环播放查看效果 <html> <head> <title>JS可控制的图片自动循环播放查看效果丨芯晴网页特效丨CsrCode.Cn</t ...