以下为个人笔记

  1. /**
  2. * process_command 在memcached中是用来处理用户发送的命令的,
  3. * 包括get set,add,delete,replace,stats,flush_all等常用的和不常用的命令,全在这进行处理的。
  4. * 一共有两个参数,conn *c 和字符串指针 char *command ;
  5. * 关于conn结构体就先不说了,反正它是整个memcached中最重要的结构体就行了,等以后研究明白了再说,先从整体上领会精神吧。
  6. * 这里我想说一下的是, memcached 和 redis 在处理命令上的想法还是有很大差别的,
  7. * 在 redis 里面,你要是想看一下一共支持多少命令,每个命令对应的函数,很方便,都在一个名叫 redisCommandTable 的结构体数组里面,一目了然;
  8. * 但是 memcached 却不是这样,我刚开始也是按照看 redis 源码的方式去找 memcached 中的,但是找了很久也没有发现,原因就是作者把支持的所有命令都散落在下面这个函数中了。
  9. * 先说一下 memcached 是怎么从 command 字符串中分解出具体的命令和对应的参数的。
  10. * 在函数中用到了一个结构体数组: tokens[MAX_TOKENS] ,它其实是用来存放分析完的 command 结果用的,分析工作在函数 tokenize_command 中进行。
  11. * 如:有一个命令 "get aaaaaaaaaa" ,分析完以后存在tokens中的就是
  12. * tokens[3] = {{value:"get",length:3},{value:"aaaaaaaaaa",length:10},{value:NULL,length:0}};
  13. * 函数 tokenize_command 返回的是一个int型数据 ntokens,记录了 tokens 的大小,表示从 command 命令中分解出了几条数据,
  14. * 当然 ntokens 的值会比实际中 command 中包含的数据多1,因为字符串结尾的'\0'也要占一样。
  15. *
  16. * 下面说说以 "get aaaaaaaaaa" 命令为例,具体的命令分析和函数调用过程:
  17. * 当一条命令 "get aaaaaaaaaa" 传到 process_command 中之后,先调用负责解析命令的函数tokenize_command,
  18. * 将解析后的命令存储在tokens数组中,结果如上面的tokens[3],并返回ntokens,说明command中包含几个字段(这里得到的是3),
  19. * 然后根据字段的数目进行判断应该到哪个条件语句去进行比对,当确认之后,就会跳到对应的条件语句中
  20. * 所以这里应该到 tokenize_command 下面的第一个if语句中,然后使用tokens[0].value,也就是tokens数组中存储的get命令和字符串"get"进行比较,
  21. * 匹配,则调用对应的函数,这里调用process_get_command(c, tokens, ntokens, false);
  22. * 然后 process_command 的使命就结束了。
  23. * 以下代码在memcached-1.4.22/memcached.c
  24. */
  25. static void process_command(conn *c, char *command) {
  26.  
  27. token_t tokens[MAX_TOKENS];
  28. size_t ntokens;
  29. int comm;
  30.  
  31. assert(c != NULL);
  32.  
  33. MEMCACHED_PROCESS_COMMAND_START(c->sfd, c->rcurr, c->rbytes);
  34.  
  35. if (settings.verbose > )
  36. fprintf(stderr, "<%d %s\n", c->sfd, command);
  37.  
  38. /*
  39. * for commands set/add/replace, we build an item and read the data
  40. * directly into it, then continue in nread_complete().
  41. */
  42.  
  43. c->msgcurr = ;
  44. c->msgused = ;
  45. c->iovused = ;
  46. if (add_msghdr(c) != ) {
  47. out_of_memory(c, "SERVER_ERROR out of memory preparing response");
  48. return;
  49. }
  50.  
  51. ntokens = tokenize_command(command, tokens, MAX_TOKENS);
  52. if (ntokens >= &&
  53. ((strcmp(tokens[COMMAND_TOKEN].value, "get") == ) ||
  54. (strcmp(tokens[COMMAND_TOKEN].value, "bget") == ))) {
  55.  
  56. process_get_command(c, tokens, ntokens, false);
  57.  
  58. } else if ((ntokens == || ntokens == ) &&
  59. ((strcmp(tokens[COMMAND_TOKEN].value, "add") == && (comm = NREAD_ADD)) ||
  60. (strcmp(tokens[COMMAND_TOKEN].value, "set") == && (comm = NREAD_SET)) ||
  61. (strcmp(tokens[COMMAND_TOKEN].value, "replace") == && (comm = NREAD_REPLACE)) ||
  62. (strcmp(tokens[COMMAND_TOKEN].value, "prepend") == && (comm = NREAD_PREPEND)) ||
  63. (strcmp(tokens[COMMAND_TOKEN].value, "append") == && (comm = NREAD_APPEND)) )) {
  64.  
  65. process_update_command(c, tokens, ntokens, comm, false);
  66.  
  67. } else if ((ntokens == || ntokens == ) && (strcmp(tokens[COMMAND_TOKEN].value, "cas") == && (comm = NREAD_CAS))) {
  68.  
  69. process_update_command(c, tokens, ntokens, comm, true);
  70.  
  71. } else if ((ntokens == || ntokens == ) && (strcmp(tokens[COMMAND_TOKEN].value, "incr") == )) {
  72.  
  73. process_arithmetic_command(c, tokens, ntokens, );
  74.  
  75. } else if (ntokens >= && (strcmp(tokens[COMMAND_TOKEN].value, "gets") == )) {
  76.  
  77. process_get_command(c, tokens, ntokens, true);
  78.  
  79. } else if ((ntokens == || ntokens == ) && (strcmp(tokens[COMMAND_TOKEN].value, "decr") == )) {
  80.  
  81. process_arithmetic_command(c, tokens, ntokens, );
  82.  
  83. } else if (ntokens >= && ntokens <= && (strcmp(tokens[COMMAND_TOKEN].value, "delete") == )) {
  84.  
  85. process_delete_command(c, tokens, ntokens);
  86.  
  87. } else if ((ntokens == || ntokens == ) && (strcmp(tokens[COMMAND_TOKEN].value, "touch") == )) {
  88.  
  89. process_touch_command(c, tokens, ntokens);
  90.  
  91. } else if (ntokens >= && (strcmp(tokens[COMMAND_TOKEN].value, "stats") == )) {
  92.  
  93. process_stat(c, tokens, ntokens);
  94.  
  95. } else if (ntokens >= && ntokens <= && (strcmp(tokens[COMMAND_TOKEN].value, "flush_all") == )) {
  96. time_t exptime = ;
  97.  
  98. set_noreply_maybe(c, tokens, ntokens);
  99.  
  100. pthread_mutex_lock(&c->thread->stats.mutex);
  101. c->thread->stats.flush_cmds++;
  102. pthread_mutex_unlock(&c->thread->stats.mutex);
  103.  
  104. if (!settings.flush_enabled) {
  105. // flush_all is not allowed but we log it on stats
  106. out_string(c, "CLIENT_ERROR flush_all not allowed");
  107. return;
  108. }
  109.  
  110. if(ntokens == (c->noreply ? : )) {
  111. settings.oldest_live = current_time - ;
  112. item_flush_expired();
  113. out_string(c, "OK");
  114. return;
  115. }
  116.  
  117. exptime = strtol(tokens[].value, NULL, );
  118. if(errno == ERANGE) {
  119. out_string(c, "CLIENT_ERROR bad command line format");
  120. return;
  121. }
  122.  
  123. /*
  124. If exptime is zero realtime() would return zero too, and
  125. realtime(exptime) - 1 would overflow to the max unsigned
  126. value. So we process exptime == 0 the same way we do when
  127. no delay is given at all.
  128. */
  129. if (exptime > )
  130. settings.oldest_live = realtime(exptime) - ;
  131. else /* exptime == 0 */
  132. settings.oldest_live = current_time - ;
  133. item_flush_expired();
  134. out_string(c, "OK");
  135. return;
  136.  
  137. } else if (ntokens == && (strcmp(tokens[COMMAND_TOKEN].value, "version") == )) {
  138.  
  139. out_string(c, "VERSION " VERSION);
  140.  
  141. } else if (ntokens == && (strcmp(tokens[COMMAND_TOKEN].value, "quit") == )) {
  142.  
  143. conn_set_state(c, conn_closing);
  144.  
  145. } else if (ntokens == && (strcmp(tokens[COMMAND_TOKEN].value, "shutdown") == )) {
  146.  
  147. if (settings.shutdown_command) {
  148. conn_set_state(c, conn_closing);
  149. raise(SIGINT);
  150. } else {
  151. out_string(c, "ERROR: shutdown not enabled");
  152. }
  153.  
  154. } else if (ntokens > && strcmp(tokens[COMMAND_TOKEN].value, "slabs") == ) {
  155. if (ntokens == && strcmp(tokens[COMMAND_TOKEN + ].value, "reassign") == ) {
  156. int src, dst, rv;
  157.  
  158. if (settings.slab_reassign == false) {
  159. out_string(c, "CLIENT_ERROR slab reassignment disabled");
  160. return;
  161. }
  162.  
  163. src = strtol(tokens[].value, NULL, );
  164. dst = strtol(tokens[].value, NULL, );
  165.  
  166. if (errno == ERANGE) {
  167. out_string(c, "CLIENT_ERROR bad command line format");
  168. return;
  169. }
  170.  
  171. rv = slabs_reassign(src, dst);
  172. switch (rv) {
  173. case REASSIGN_OK:
  174. out_string(c, "OK");
  175. break;
  176. case REASSIGN_RUNNING:
  177. out_string(c, "BUSY currently processing reassign request");
  178. break;
  179. case REASSIGN_BADCLASS:
  180. out_string(c, "BADCLASS invalid src or dst class id");
  181. break;
  182. case REASSIGN_NOSPARE:
  183. out_string(c, "NOSPARE source class has no spare pages");
  184. break;
  185. case REASSIGN_SRC_DST_SAME:
  186. out_string(c, "SAME src and dst class are identical");
  187. break;
  188. }
  189. return;
  190. } else if (ntokens == &&
  191. (strcmp(tokens[COMMAND_TOKEN + ].value, "automove") == )) {
  192. process_slabs_automove_command(c, tokens, ntokens);
  193. } else {
  194. out_string(c, "ERROR");
  195. }
  196. } else if (ntokens > && strcmp(tokens[COMMAND_TOKEN].value, "lru_crawler") == ) {
  197. if (ntokens == && strcmp(tokens[COMMAND_TOKEN + ].value, "crawl") == ) {
  198. int rv;
  199. if (settings.lru_crawler == false) {
  200. out_string(c, "CLIENT_ERROR lru crawler disabled");
  201. return;
  202. }
  203.  
  204. rv = lru_crawler_crawl(tokens[].value);
  205. switch(rv) {
  206. case CRAWLER_OK:
  207. out_string(c, "OK");
  208. break;
  209. case CRAWLER_RUNNING:
  210. out_string(c, "BUSY currently processing crawler request");
  211. break;
  212. case CRAWLER_BADCLASS:
  213. out_string(c, "BADCLASS invalid class id");
  214. break;
  215. }
  216. return;
  217. } else if (ntokens == && strcmp(tokens[COMMAND_TOKEN + ].value, "tocrawl") == ) {
  218. uint32_t tocrawl;
  219. if (!safe_strtoul(tokens[].value, &tocrawl)) {
  220. out_string(c, "CLIENT_ERROR bad command line format");
  221. return;
  222. }
  223. settings.lru_crawler_tocrawl = tocrawl;
  224. out_string(c, "OK");
  225. return;
  226. } else if (ntokens == && strcmp(tokens[COMMAND_TOKEN + ].value, "sleep") == ) {
  227. uint32_t tosleep;
  228. if (!safe_strtoul(tokens[].value, &tosleep)) {
  229. out_string(c, "CLIENT_ERROR bad command line format");
  230. return;
  231. }
  232. if (tosleep > ) {
  233. out_string(c, "CLIENT_ERROR sleep must be one second or less");
  234. return;
  235. }
  236. settings.lru_crawler_sleep = tosleep;
  237. out_string(c, "OK");
  238. return;
  239. } else if (ntokens == ) {
  240. if ((strcmp(tokens[COMMAND_TOKEN + ].value, "enable") == )) {
  241. if (start_item_crawler_thread() == ) {
  242. out_string(c, "OK");
  243. } else {
  244. out_string(c, "ERROR failed to start lru crawler thread");
  245. }
  246. } else if ((strcmp(tokens[COMMAND_TOKEN + ].value, "disable") == )) {
  247. if (stop_item_crawler_thread() == ) {
  248. out_string(c, "OK");
  249. } else {
  250. out_string(c, "ERROR failed to stop lru crawler thread");
  251. }
  252. } else {
  253. out_string(c, "ERROR");
  254. }
  255. return;
  256. } else {
  257. out_string(c, "ERROR");
  258. }
  259. } else if ((ntokens == || ntokens == ) && (strcmp(tokens[COMMAND_TOKEN].value, "verbosity") == )) {
  260. process_verbosity_command(c, tokens, ntokens);
  261. } else {
  262. out_string(c, "ERROR");
  263. }
  264. return;
  265. }

以上为个人笔记

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. bzoj 1787 [Ahoi2008]Meet 紧急集合(1832 [AHOI2008]聚会)

    1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 1841  Solved: 857[Submit][ ...

  2. xcode4的workspace里各lib工程与app工程联编之runscript简介

    copy from:http://www.cnblogs.com/xiaouisme/archive/2012/02/06/2339470.html 本文讲解怎么在xcode4的workspace里配 ...

  3. 最小生成树 10.1.5.253 1505 poj 1258 http://poj.org/problem?id=1258

    #include <iostream>// poj 1258 10.1.5.253 1505 using namespace std; #define N 105 // 顶点的最大个数 ( ...

  4. Fire Net(深搜 和一前不一样的深搜)

    /* http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=1162 本题妙处: 用一个数对行取商是 ...

  5. 【最短路】血色先锋军(scarlet) 解题报告

    问题来源 BYVoid魔兽世界模拟赛 [问题描述] 巫妖王的天灾军团终于卷土重来,血色十字军组织了一支先锋军前往诺森德大陆对抗天灾军团,以及一切沾有亡灵气息的生物.孤立于联盟和部落的血色先锋军很快就遭 ...

  6. OpenRisc-43-or1200的IF模块分析

    引言 “喂饱饥饿的CPU”,是计算机体系结构设计者时刻要考虑的问题.要解决这个问题,方法大体可分为两部分,第一就是利用principle of locality而引进的cache技术,缩短取指时间,第 ...

  7. 在javascript中使用媒体查询media query

    由于需要,我们可能会在js中用到一些media query,从而针对不同的分辨率做一些操作. //全兼容的 事件绑定 and 阻止默认事件 var EventUtil = { //Notice: ty ...

  8. css分割线 文字居中的7种实现方式

    最近开始研究前端,会不定期更新一些小块代码,写下自己的学习笔记,也希望能和大家一起进步! 1.单个标签实现分隔线: <html> <head lang="en"& ...

  9. Web日程管理FullCalendar

    fullcalendar是一款jQuery日程管理控件,提供了丰富的属性设置和方法调用,官网下载地址http://fullcalendar.io/download,眼下最新版本号是2.3.2. 仅仅要 ...

  10. C/C++ Linux 程序员必须了解的 10 个工具

    1. 基本命令http://mally.stanford.edu/~sr/computing/basic-unix.htmlhttp://pangea.stanford.edu/computing/u ...