├── README.md ├── img ├── distributed-memcached.png ├── hashtable.png └── how_threads_work.png └── memcached-1.4.15 ├── .tags ├── .tags_sorted_by_file ├── AUTHORS ├── COPYING ├── ChangeLog ├── Makefile.am ├── Makefile.in ├── NEWS ├── README.md ├── aclocal.m4 ├── assoc.c ├── assoc.h ├── cache.c ├── cache.h ├── compile ├── config.guess ├── config.h.in ├── config.sub ├── configure ├── configure.ac ├── daemon.c ├── depcomp ├── doc ├── CONTRIBUTORS ├── Doxyfile ├── Makefile ├── Makefile.am ├── Makefile.in ├── memcached.1 ├── protocol-binary-range.xml ├── protocol-binary.xml ├── protocol.txt ├── readme.txt ├── threads.txt └── xml2rfc │ ├── reference.RFC.0768.xml │ ├── rfc2629-noinc.xsl │ ├── rfc2629-other.ent │ ├── rfc2629-refchk.xsl │ ├── rfc2629-xhtml.ent │ └── rfc2629.dtd ├── hash.c ├── hash.h ├── install-sh ├── items.c ├── items.h ├── m4 └── c99-backport.m4 ├── memcached.c ├── memcached.h ├── memcached.spec ├── memcached_dtrace.d ├── missing ├── protocol_binary.h ├── sasl_defs.c ├── sasl_defs.h ├── scripts ├── README.damemtop ├── damemtop ├── damemtop.yaml ├── mc_slab_mover ├── memcached-init ├── memcached-tool ├── memcached.service ├── memcached.sysv └── start-memcached ├── sizes.c ├── slabs.c ├── slabs.h ├── solaris_priv.c ├── stats.c ├── stats.h ├── t ├── 00-startup.t ├── 64bit.t ├── binary-get.t ├── binary-sasl.t ├── binary.t ├── bogus-commands.t ├── cas.t ├── daemonize.t ├── dash-M.t ├── evictions.t ├── expirations.t ├── flags.t ├── flush-all.t ├── getset.t ├── incrdecr.t ├── issue_104.t ├── issue_108.t ├── issue_14.t ├── issue_140.t ├── issue_152.t ├── issue_163.t ├── issue_183.t ├── issue_22.t ├── issue_29.t ├── issue_3.t ├── issue_41.t ├── issue_42.t ├── issue_50.t ├── issue_61.t ├── issue_67.t ├── issue_68.t ├── issue_70.t ├── item_size_max.t ├── lib │ └── MemcachedTest.pm ├── line-lengths.t ├── lru.t ├── maxconns.t ├── multiversioning.t ├── noreply.t ├── sasl │ └── memcached.conf ├── slabs_reassign.t ├── stats-detail.t ├── stats.t ├── stress-memcached.pl ├── touch.t ├── udp.t ├── unixsocket.t └── whitespace.t ├── testapp.c ├── thread.c ├── timedrun.c ├── trace.h ├── util.c ├── util.h └── version.m4 /README.md: -------------------------------------------------------------------------------- 1 | [redis 源码日志](https://daoluan.github.io/redis-source-notes/) 2 | 3 | memcached 源码阅读笔记 4 | ------------- 5 | 6 | 阅读 memcached 最好有 libevent 基础, memcached 是基于 libevent 构建起来的. 通由 libevent 提供的事件驱动机制触发 memcached 中的 IO 事件. 已经有大牛剖析过 libevent 源码了,推荐阅读:[这里](http://blog.csdn.net/sparkliang/article/details/4957667) 7 | 8 | 个人认为, 阅读源码的起初最忌钻牛角尖, 如头文件里天花乱坠的结构体到底有什么用. 源文件里稀里哗啦的函数是做什么的. 刚开始并没必要事无巨细弄清楚头文件每个类型定义的具体用途; 很可能那些是不紧要的工具函数, 知道他的功能和用法就没他事了. 9 | 10 | 来看 memcached 内部做了什么事情. memcached 是用 c 语言实现, 必须有一个入口函数`main()`, memcached 的生命从这里开始. 11 | 12 | ### 初始化过程 ### 13 | 建立并初始化 main_base, 即主线程的事件中心, 这是 libevent 里面的概念, 可以把它理解为事件分发中心. 14 | 15 | 建立并初始化 memcached 内部容器数据结构. 16 | 17 | 建立并初始化空闲连接结构体数组. 18 | 19 | 建立并初始化线程结构数组, 指定每个线程的入口函数是`worker_libevent()`, 并创建工作线程. 从`worder_libevent()`的实现来看, 工作线程都会调用`event_base_loop()`进入自己的事件循环. 20 | 21 | 根据 memcached 配置, 开启以下两种服务模式中的一种: 22 | 23 | 1. 以 UNIX 域套接字的方式接受客户的请求 24 | 2. 以 TCP/UDP 套接字的方式接受客户的请求 25 | 26 | memcached 有可配置的两种模式: UNIX 域套接字和 TCP/UDP, 允许客户端以两种方式向 memcached 发起请求. 客户端和服务器在同一个主机上的情况下可以用 UNIX 域套接字, 否则可以采用 TCP/UDP 的模式. 两种模式是不兼容的. 特别的, 如果是 UNIX 域套接字或者 TCP 模式, 需要建立监听套接字, 并在事件中心注册了读事件, 回调函数是`event_handler()`, 我们会看到所有的连接都会被注册回调函数是`event_handler()`. 27 | 28 | 调用`event_base_loop()`开启 libevent 的事件循环. 到此, memcached 服务器的工作正式进入了工作. 如果遇到致命错误或者客户明令结束 memcached, 那么才会进入接下来的清理工作. 29 | 30 | ### UNIX 域套接字和 UDP/TCP 工作模式 ### 31 | 在**初始化过程**中介绍了这两种模式, memcached 这么做为的是让其能更加可配置. TCP/UDP 自不用说, UNIX 域套接字有独特的优势: 32 | 33 | 1. 在同一台主机上进行通信时,是不同主机间通信的两倍 34 | 2. UNIX 域套接口可以在同一台主机上,不同进程之间传递套接字描述符 35 | 3. UNIX 域套接字可以向服务器提供客户的凭证(用户id或者用户组id) 36 | 37 | 其他关于 UNIX 域套接字优缺点的请参看: https://pangea.stanford.edu/computing/UNIX/overview/advantages.php 38 | 39 | ### 工作线程管理和线程调配方式 ### 40 | 在`thread_init()`,`setup_thread()`函数的实现中, memcached 的意图是很清楚的. 每个线程都有自己独有的连接队列, 即 CQ, 注意这个连接队列中的对象并不是一个或者多个 memcached 命令, 它对应一个客户! 一旦一个客户交给了一个线程, 它的余生就属于这个线程了! 线程只要被唤醒就立即进入工作状态, 将自己 CQ 队列的任务所有完完成. 当然, 每一个工作线程都有自己的 libevent 事件中心. 41 | 42 | 很关键的线索是`thread_init()`的实现中, 每个工作线程都创建了读写管道, 所能给我们的提示是: 只要利用 libevent 在工作线程的事件中心注册读管道的读事件, 就可以按需唤醒线程, 完成工作, 很有意思, 而`setup_thread()`的工作正是读管道的读事件被注册到线程的事件中心, 回调函数是`thread_libevent_process()`.`thread_libevent_process()`的工作就是从工作线程自己的 CQ 队列中取出任务执行, 而往工作线程工作队列中添加任务的是`dispatch_conn_new()`, 此函数一般由主线程调用. 下面是主线程和工作线程的工作流程: 43 | 44 | ![主线程和工作线程的工作模式](/img/how_threads_work.png?raw=true) 45 | 46 | 前几天在微博上, 看到 @高端小混混 的微博, 转发了: 47 | 48 | >@高端小混混 49 | > 50 | >多任务并行处理的两种方式,一种是将所有的任务用队列存储起来,每个工作者依次去拿一个来处理,直到做完所有的>任务为止。另一种是将任务平均分给工作者,先做完任务的工作者就去别的工作者那里拿一些任务来做,同样直到所有任务做完为止。两种方式的结果如何?根据自己的场景写码验证。 51 | 52 | memcached 所采用的模式就是这里所说的第二种! 53 | memcached 的线程分配模式是:**一个主线程和多个工作线程**。主线程负责初始化和将接收的请求分派给工作线程,工作线程负责接收客户的命令请求和回复客户。 54 | 55 | ### 存储容器 ### 56 | memcached 是做缓存用的, 内部肯定有一个容器. 回到`main()`中, 调用`assoc_init()`初始化了容器--hashtable, 采用头插法插入新数据, 因为头插法是最快的. memcached 只做了一级的索引, 即 hash; 接下来的就靠 memcmp() 在链表中找数据所在的位置. memcached 容器管理的接口主要在 item.h .c 中. 57 | 58 | ![哈希表](/img/hashtable.png) 59 | 60 | ### 连接管理 ### 61 | 每个连接都会建立一个连接结构体与之对应. `main()`中会调用`conn_init()`建立连接结构体数组. 连接结构体 struct conn 记录了连接套接字, 读取的数据, 将要写入的数据, **libevent event 结构体**以及**所属的线程信息**. 62 | 63 | 当有新的连接时, 主线程会被唤醒, 主线程选定一个工作线程 thread0, 在 thread0 的写管道中写入数据, 特别的如果是接受新的连接而不是接受新的数据, 写入管道的数据是字符 'c'. 工作线程因管道中有数据可读被唤醒,`thread_libevent_process()`被调用, 新连接套接字被注册了`event_handler()`回调函数, 这些工作在`conn_new()`中完成. 因此, 客户端有命令请求的时候(譬如发起 get key 命令), 工作线程都会被触发调用`event_handler()`. 64 | 65 | 当出现致命错误或者客户命令结束服务(quit 命令), 关于此连接的结构体内部的数据会被释放(譬如曾经读取的数据), 但结构体本身不释放, 等待下一次使用. 如果有需要, 连接结构体数组会指数自增. 66 | 67 | ### 一个请求的工作流程 ### 68 | memcached 服务一个客户的时候, 是怎么一个过程, 试着去调试模拟一下. 当一个客户向 memcached 发起请求时, 主线程会被唤醒, 接受请求. 接下来的工作在**连接管理**中有说到. 69 | 70 | 客户已经与 memcached 服务器建立了连接, 客户在终端(黑框框)敲击 get key + 回车键, 一个请求包就发出去了. 从**连接管理**中已经了解到所有连接套接字都会被注册回调函数为`event_handler()`, 因此`event_handler()`会被触发调用. 71 | 72 | 73 | void event_handler(const int fd, const short which, void *arg) { 74 | conn *c; 75 | 76 | c = (conn *)arg; 77 | assert(c != NULL); 78 | 79 | c->which = which; 80 | 81 | /* sanity */ 82 | if (fd != c->sfd) { 83 | if (settings.verbose > 0) 84 | fprintf(stderr, "Catastrophic: event fd doesn't match conn fd!\n"); 85 | conn_close(c); 86 | return; 87 | } 88 | 89 | drive_machine(c); 90 | 91 | /* wait for next event */ 92 | return; 93 | } 94 | 95 | `event_handler()`调用了`drive_machine()`.`drive_machine()`是请求处理的开端, 特别的当有新的连接时, listen socket 也是有请求的, 所以建立新的连接也会调用`drive_machine()`, 这在连接管理有提到过. 下面是`drive_machine()`函数的骨架: 96 | 97 | // 请求的开端. 当有新的连接的时候 event_handler() 会调用此函数. 98 | static void drive_machine(conn *c) { 99 | bool stop = false; 100 | int sfd, flags = 1; 101 | socklen_t addrlen; 102 | struct sockaddr_storage addr; 103 | int nreqs = settings.reqs_per_event; 104 | int res; 105 | const char *str; 106 | 107 | assert(c != NULL); 108 | 109 | while (!stop) { 110 | // while 能保证一个命令被执行完成或者异常中断(譬如 IO 操作次数超出了一定的限制) 111 | 112 | switch(c->state) { 113 | // 正在连接, 还没有 accept 114 | case conn_listening: 115 | 116 | // 等待新的命令请求 117 | case conn_waiting: 118 | 119 | // 读取数据 120 | case conn_read: 121 | 122 | // 尝试解析命令 123 | case conn_parse_cmd : 124 | 125 | // 新的命令请求, 只是负责转变 conn 的状态 126 | case conn_new_cmd: 127 | 128 | // 真正执行命令的地方 129 | case conn_nread: 130 | 131 | // 读取所有的数据, 抛弃!!! 一般出错的情况下会转换到此状态 132 | case conn_swallow: 133 | 134 | // 数据回复 135 | case conn_write: 136 | 137 | case conn_mwrite: 138 | 139 | // 连接结束. 一般出错或者客户显示结束服务的情况下回转换到此状态 140 | case conn_closing: 141 | } 142 | } 143 | return; 144 | } 145 | 146 | 通过修改连接结构体状态 struct conn.state 执行相应的操作, 从而完成一个请求, 完成后 stop 会被设置为 true, 一个命令只有执行结束(无论结果如何)才会跳出这个循环. 我们看到 struct conn 有好多种状态, 一个正常执行的命令状态的转换是: 147 | 148 | conn_new_cmd->conn_waiting->conn_read->conn_parse_cmd->conn_nread->conn_mwrite->conn_close 149 | 150 | 这个过程任何一个环节出了问题都会导致状态转变为 conn_close. 带着刚开始的问题把从客户连接到一个命令执行结束的过程是怎么样的: 151 | 152 | 1. 客户`connect()`后, memcached 服务器主线程被唤醒, 接下来的调用链是`event_handler()->drive_machine()`被调用,此时主线程对应 conn 状态为 conn_listining,接受请求 153 | 154 | dispatch_conn_new(sfd, conn_new_cmd, EV_READ | EV_PERSIST,DATA_BUFFER_SIZE, tcp_transport); 155 | 156 | 2. `dispatch_conn_new()`的工作是往工作线程工作队列中添加任务(前面已经提到过), 所以其中一个沉睡的工作线程会被唤醒,`thread_libevent_process()`会被工作线程调用, 注意这些机制都是由 libevent 提供的. 157 | 3. `thread_libevent_process()`调用`conn_new()`新建 struct conn 结构体, **且状态为 conn_new_cmd**, 其对应的就是刚才`accept()`的连接套接字.`conn_new()`最关键的任务是将刚才接受的套接字在 libevent 中注册一个事件, 回调函数是`event_handler()`. 循环继续, 状态 conn_new_cmd 下的操作只是只是将 conn 的状态转换为 conn_waiting; 158 | 4. 循环继续, conn_waiting 状态下的操作只是将 conn 状态转换为 conn_read, 循环退出. 159 | 5. 此后, 如果客户端不请求服务, 那么主线程和工作线程都会沉睡, 注意这些机制都是由 libevent 提供的. 160 | 6. 客户敲击命令「get key」后, 工作线程会被唤醒,`event_handler()`被调用了. 看! 又被调用了.`event_handler()->drive_machine()`, **此时 conn 的状态为 conn_read**. conn_read 下的操作就是读数据了, 如果读取成功, conn 状态被转换为 conn_parse_cmd. 161 | 7. 循环继续, conn_parse_cmd 状态下的操作就是尝试解析命令: 可能是较为简单的命令, 就直接回复, 状态转换为 conn_close, 循环接下去就结束了; 涉及存取操作的请求会导致 conn_parse_cmd 状态转换为 conn_nread. 162 | 8. 循环继续, **conn_nread 状态下的操作是真正执行存取命令的地方**. 里面的操作无非是在内存寻找数据项, 返回数据. 所以接下来的状态 conn_mwrite, 它的操作是为客户端回复数据. 163 | 9. 状态又回到了 conn_new_cmd 迎接新的请求, 直到客户命令结束服务或者发生致命错误. 164 | 大概就是这么个过程. 165 | 166 | ### memcached 的分布式 ### 167 | memcached 的服务器没有向其他 memcached 服务器收发数据的功能, 意即就算部署多个 memcached 服务器, 他们之间也没有任何的通信. memcached 所谓的分布式部署也是并非平时所说的分布式. 所说的「分布式」是通过创建多个 memcached 服务器节点, 在客户端添加**缓存请求分发器**来实现的. memcached 的更多的时候限制是来自**网络 I/O**, 所以应该尽量减少网络 I/O. 168 | 169 | ![分布式 memcached](/img/distributed-memcached.png) 170 | 171 | 我在 github 上分享了 memcached 的源码剖析注释: [这里](https://github.com/daoluan/decode-memcached) 172 | -------------------------------------------------------------------------------- /img/distributed-memcached.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daoluan/decode-memcached/e136600d8d47f3630aea703853decbb914142e8b/img/distributed-memcached.png -------------------------------------------------------------------------------- /img/hashtable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daoluan/decode-memcached/e136600d8d47f3630aea703853decbb914142e8b/img/hashtable.png -------------------------------------------------------------------------------- /img/how_threads_work.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daoluan/decode-memcached/e136600d8d47f3630aea703853decbb914142e8b/img/how_threads_work.png -------------------------------------------------------------------------------- /memcached-1.4.15/AUTHORS: -------------------------------------------------------------------------------- 1 | Anatoly Vorobey 2 | Brad Fitzpatrick 3 | -------------------------------------------------------------------------------- /memcached-1.4.15/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2003, Danga Interactive, Inc. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following disclaimer 13 | in the documentation and/or other materials provided with the 14 | distribution. 15 | 16 | * Neither the name of the Danga Interactive nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /memcached-1.4.15/Makefile.am: -------------------------------------------------------------------------------- 1 | bin_PROGRAMS = memcached 2 | pkginclude_HEADERS = protocol_binary.h 3 | noinst_PROGRAMS = memcached-debug sizes testapp timedrun 4 | 5 | BUILT_SOURCES= 6 | 7 | testapp_SOURCES = testapp.c util.c util.h 8 | 9 | timedrun_SOURCES = timedrun.c 10 | 11 | memcached_SOURCES = memcached.c memcached.h \ 12 | hash.c hash.h \ 13 | slabs.c slabs.h \ 14 | items.c items.h \ 15 | assoc.c assoc.h \ 16 | thread.c daemon.c \ 17 | stats.c stats.h \ 18 | util.c util.h \ 19 | trace.h cache.h sasl_defs.h 20 | 21 | if BUILD_CACHE 22 | memcached_SOURCES += cache.c 23 | testapp_SOURCES += cache.c 24 | endif 25 | 26 | if BUILD_SOLARIS_PRIVS 27 | memcached_SOURCES += solaris_priv.c 28 | endif 29 | 30 | if ENABLE_SASL 31 | memcached_SOURCES += sasl_defs.c 32 | endif 33 | 34 | memcached_debug_SOURCES = $(memcached_SOURCES) 35 | memcached_CPPFLAGS = -DNDEBUG 36 | memcached_debug_LDADD = @PROFILER_LDFLAGS@ 37 | memcached_debug_CFLAGS = @PROFILER_FLAGS@ 38 | 39 | memcached_LDADD = 40 | memcached_DEPENDENCIES = 41 | memcached_debug_DEPENDENCIES = 42 | CLEANFILES= 43 | 44 | if BUILD_DTRACE 45 | BUILT_SOURCES += memcached_dtrace.h 46 | CLEANFILES += memcached_dtrace.h 47 | endif 48 | 49 | if DTRACE_INSTRUMENT_OBJ 50 | memcached_LDADD += memcached_dtrace.o 51 | memcached_DEPENDENCIES += memcached_dtrace.o 52 | memcached_debug_LDADD += memcached_debug_dtrace.o 53 | memcached_debug_DEPENDENCIES += memcached_debug_dtrace.o 54 | CLEANFILES += memcached_dtrace.o memcached_debug_dtrace.o 55 | endif 56 | 57 | memcached_dtrace.h: memcached_dtrace.d 58 | ${DTRACE} -h -s memcached_dtrace.d 59 | sed -e 's,void \*,const void \*,g' memcached_dtrace.h | \ 60 | sed -e 's,char \*,const char \*,g' | tr '\t' ' ' > mmc_dtrace.tmp 61 | mv mmc_dtrace.tmp memcached_dtrace.h 62 | 63 | memcached_dtrace.o: $(memcached_OBJECTS) 64 | $(DTRACE) $(DTRACEFLAGS) -G -o memcached_dtrace.o -s ${srcdir}/memcached_dtrace.d $(memcached_OBJECTS) 65 | 66 | memcached_debug_dtrace.o: $(memcached_debug_OBJECTS) 67 | $(DTRACE) $(DTRACEFLAGS) -G -o memcached_debug_dtrace.o -s ${srcdir}/memcached_dtrace.d $(memcached_debug_OBJECTS) 68 | 69 | 70 | SUBDIRS = doc 71 | DIST_DIRS = scripts 72 | EXTRA_DIST = doc scripts t memcached.spec memcached_dtrace.d version.m4 README.md 73 | 74 | MOSTLYCLEANFILES = *.gcov *.gcno *.gcda *.tcov 75 | 76 | test: memcached-debug sizes testapp 77 | $(srcdir)/sizes 78 | $(srcdir)/testapp 79 | prove $(srcdir)/t 80 | @if test `basename $(PROFILER)` = "gcov"; then \ 81 | for file in memcached_debug-*.gc??; do \ 82 | mv -f $$file `echo $$file | sed 's/memcached_debug-//'`; \ 83 | done && \ 84 | for file in *.gcda; do \ 85 | srcfile=`echo $$file | sed 's/.gcda/.c/'`; \ 86 | if test -n "`echo $(memcached_debug_SOURCES) | grep $$srcfile`"; then \ 87 | echo `$(PROFILER) $$srcfile` | sed 's/'$$srcfile':.*//'; \ 88 | fi \ 89 | done \ 90 | elif test `basename $(PROFILER)` = "tcov"; then \ 91 | files=`grep SRCFILE memcached-debug.profile/tcovd | sed 's/SRCFILE://' | sort | uniq` && \ 92 | $(PROFILER) -x memcached-debug.profile $$files 2>&1; \ 93 | for file in *.tcov; do \ 94 | srcfile=`echo $$file | sed 's/.tcov//'`; \ 95 | if test -n "`echo $(memcached_debug_SOURCES) | grep $$srcfile`"; then \ 96 | echo $$srcfile : `grep 'Percent of the file executed' $$file`; \ 97 | fi \ 98 | done \ 99 | else :; fi 100 | 101 | docs: 102 | (cat Doxyfile ; echo "PROJECT_NUMBER=`cat version.num`") | doxygen - 103 | 104 | dist-hook: 105 | rm -f $(distdir)/*/*~ $(distdir)/t/lib/*~ $(distdir)/*~ 106 | -------------------------------------------------------------------------------- /memcached-1.4.15/NEWS: -------------------------------------------------------------------------------- 1 | http://www.danga.com/memcached/news.bml 2 | -------------------------------------------------------------------------------- /memcached-1.4.15/README.md: -------------------------------------------------------------------------------- 1 | # Memcached 2 | 3 | ## Dependencies 4 | 5 | * libevent, http://www.monkey.org/~provos/libevent/ (libevent-dev) 6 | 7 | ## Environment 8 | 9 | ### Linux 10 | 11 | If using Linux, you need a kernel with epoll. Sure, libevent will 12 | work with normal select, but it sucks. 13 | 14 | epoll isn't in Linux 2.4, but there's a backport at: 15 | 16 | http://www.xmailserver.org/linux-patches/nio-improve.html 17 | 18 | You want the epoll-lt patch (level-triggered). 19 | 20 | ### Mac OS X 21 | 22 | If you're using MacOS, you'll want libevent 1.1 or higher to deal with 23 | a kqueue bug. 24 | 25 | Also, be warned that the -k (mlockall) option to memcached might be 26 | dangerous when using a large cache. Just make sure the memcached machines 27 | don't swap. memcached does non-blocking network I/O, but not disk. (it 28 | should never go to disk, or you've lost the whole point of it) 29 | 30 | ## Website 31 | 32 | * http://www.memcached.org 33 | 34 | ## Contributing 35 | 36 | Want to contribute? Up-to-date pointers should be at: 37 | 38 | * http://contributing.appspot.com/memcached 39 | -------------------------------------------------------------------------------- /memcached-1.4.15/assoc.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 | /* 3 | * Hash table 4 | * 5 | * The hash function used here is by Bob Jenkins, 1996: 6 | * 7 | * "By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. 8 | * You may use this code any way you wish, private, educational, 9 | * or commercial. It's free." 10 | * 11 | * The rest of the file is licensed under the BSD license. See LICENSE. 12 | */ 13 | 14 | #include "memcached.h" 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | static pthread_cond_t maintenance_cond = PTHREAD_COND_INITIALIZER; 29 | 30 | 31 | typedef unsigned long int ub4; /* unsigned 4-byte quantities */ 32 | typedef unsigned char ub1; /* unsigned 1-byte quantities */ 33 | 34 | /* how many powers of 2's worth of buckets we use */ 35 | unsigned int hashpower = HASHPOWER_DEFAULT; 36 | 37 | #define hashsize(n) ((ub4)1<<(n)) 38 | #define hashmask(n) (hashsize(n)-1) 39 | 40 | /* Main hash table. This is where we look except during expansion. */ 41 | static item** primary_hashtable = 0; 42 | 43 | /* 44 | * Previous hash table. During expansion, we look here for keys that haven't 45 | * been moved over to the primary yet. 46 | */ 47 | static item** old_hashtable = 0; 48 | 49 | /* Number of items in the hash table. */ 50 | static unsigned int hash_items = 0; 51 | 52 | /* Flag: Are we in the middle of expanding now? */ 53 | static bool expanding = false; 54 | static bool started_expanding = false; 55 | 56 | /* 57 | * During expansion we migrate values with bucket granularity; this is how 58 | * far we've gotten so far. Ranges from 0 .. hashsize(hashpower - 1) - 1. 59 | */ 60 | static unsigned int expand_bucket = 0; 61 | 62 | void assoc_init(const int hashtable_init) { 63 | if (hashtable_init) { 64 | hashpower = hashtable_init; 65 | } 66 | primary_hashtable = calloc(hashsize(hashpower), sizeof(void *)); 67 | if (! primary_hashtable) { 68 | fprintf(stderr, "Failed to init hashtable.\n"); 69 | exit(EXIT_FAILURE); 70 | } 71 | STATS_LOCK(); 72 | stats.hash_power_level = hashpower; 73 | stats.hash_bytes = hashsize(hashpower) * sizeof(void *); 74 | STATS_UNLOCK(); 75 | } 76 | 77 | item *assoc_find(const char *key, const size_t nkey, const uint32_t hv) { 78 | item *it; 79 | unsigned int oldbucket; 80 | 81 | // 得到相应的桶, bucket 82 | if (expanding && 83 | (oldbucket = (hv & hashmask(hashpower - 1))) >= expand_bucket) 84 | { 85 | it = old_hashtable[oldbucket]; 86 | } else { 87 | it = primary_hashtable[hv & hashmask(hashpower)]; 88 | } 89 | 90 | // 在桶里搜索目标 91 | item *ret = NULL; 92 | int depth = 0; 93 | while (it) { 94 | if ((nkey == it->nkey) && (memcmp(key, ITEM_key(it), nkey) == 0)) { 95 | ret = it; 96 | break; 97 | } 98 | it = it->h_next; 99 | ++depth; 100 | } 101 | MEMCACHED_ASSOC_FIND(key, nkey, depth); 102 | return ret; 103 | } 104 | 105 | /* returns the address of the item pointer before the key. if *item == 0, 106 | the item wasn't found */ 107 | 108 | static item** _hashitem_before (const char *key, const size_t nkey, const uint32_t hv) { 109 | item **pos; 110 | unsigned int oldbucket; 111 | 112 | if (expanding && 113 | (oldbucket = (hv & hashmask(hashpower - 1))) >= expand_bucket) 114 | { 115 | pos = &old_hashtable[oldbucket]; 116 | } else { 117 | pos = &primary_hashtable[hv & hashmask(hashpower)]; 118 | } 119 | 120 | while (*pos && ((nkey != (*pos)->nkey) || memcmp(key, ITEM_key(*pos), nkey))) { 121 | pos = &(*pos)->h_next; 122 | } 123 | return pos; 124 | } 125 | 126 | /* grows the hashtable to the next power of 2. */ 127 | static void assoc_expand(void) { 128 | old_hashtable = primary_hashtable; 129 | 130 | primary_hashtable = calloc(hashsize(hashpower + 1), sizeof(void *)); 131 | if (primary_hashtable) { 132 | if (settings.verbose > 1) 133 | fprintf(stderr, "Hash table expansion starting\n"); 134 | hashpower++; 135 | expanding = true; 136 | expand_bucket = 0; 137 | STATS_LOCK(); 138 | stats.hash_power_level = hashpower; 139 | stats.hash_bytes += hashsize(hashpower) * sizeof(void *); 140 | stats.hash_is_expanding = 1; 141 | STATS_UNLOCK(); 142 | } else { 143 | primary_hashtable = old_hashtable; 144 | /* Bad news, but we can keep running. */ 145 | } 146 | } 147 | 148 | static void assoc_start_expand(void) { 149 | if (started_expanding) 150 | return; 151 | started_expanding = true; 152 | pthread_cond_signal(&maintenance_cond); 153 | } 154 | 155 | /* Note: this isn't an assoc_update. The key must not already exist to call this */ 156 | int assoc_insert(item *it, const uint32_t hv) { 157 | unsigned int oldbucket; 158 | 159 | // assert(assoc_find(ITEM_key(it), it->nkey) == 0); /* shouldn't have duplicately named things defined */ 160 | 161 | // 头插法 162 | if (expanding && 163 | (oldbucket = (hv & hashmask(hashpower - 1))) >= expand_bucket) 164 | { 165 | it->h_next = old_hashtable[oldbucket]; 166 | old_hashtable[oldbucket] = it; 167 | } else { 168 | it->h_next = primary_hashtable[hv & hashmask(hashpower)]; 169 | primary_hashtable[hv & hashmask(hashpower)] = it; 170 | } 171 | 172 | hash_items++; 173 | 174 | // 适时扩张 175 | if (! expanding && hash_items > (hashsize(hashpower) * 3) / 2) { 176 | assoc_start_expand(); 177 | } 178 | 179 | MEMCACHED_ASSOC_INSERT(ITEM_key(it), it->nkey, hash_items); 180 | return 1; 181 | } 182 | 183 | void assoc_delete(const char *key, const size_t nkey, const uint32_t hv) { 184 | // 寻找到需要删除节点的前一个节点, 这是链表删除的经典操作 185 | item **before = _hashitem_before(key, nkey, hv); 186 | 187 | if (*before) { 188 | item *nxt; 189 | hash_items--; 190 | /* The DTrace probe cannot be triggered as the last instruction 191 | * due to possible tail-optimization by the compiler 192 | */ 193 | MEMCACHED_ASSOC_DELETE(key, nkey, hash_items); 194 | nxt = (*before)->h_next; 195 | (*before)->h_next = 0; /* probably pointless, but whatever. */ 196 | *before = nxt; 197 | return; 198 | } 199 | /* Note: we never actually get here. the callers don't delete things 200 | they can't find. */ 201 | assert(*before != 0); 202 | } 203 | 204 | 205 | static volatile int do_run_maintenance_thread = 1; 206 | 207 | #define DEFAULT_HASH_BULK_MOVE 1 208 | int hash_bulk_move = DEFAULT_HASH_BULK_MOVE; 209 | 210 | static void *assoc_maintenance_thread(void *arg) { 211 | 212 | while (do_run_maintenance_thread) { 213 | int ii = 0; 214 | 215 | /* Lock the cache, and bulk move multiple buckets to the new 216 | * hash table. */ 217 | item_lock_global(); 218 | mutex_lock(&cache_lock); 219 | 220 | for (ii = 0; ii < hash_bulk_move && expanding; ++ii) { 221 | item *it, *next; 222 | int bucket; 223 | 224 | for (it = old_hashtable[expand_bucket]; NULL != it; it = next) { 225 | next = it->h_next; 226 | 227 | bucket = hash(ITEM_key(it), it->nkey, 0) & hashmask(hashpower); 228 | it->h_next = primary_hashtable[bucket]; 229 | primary_hashtable[bucket] = it; 230 | } 231 | 232 | old_hashtable[expand_bucket] = NULL; 233 | 234 | expand_bucket++; 235 | if (expand_bucket == hashsize(hashpower - 1)) { 236 | expanding = false; 237 | free(old_hashtable); 238 | STATS_LOCK(); 239 | stats.hash_bytes -= hashsize(hashpower - 1) * sizeof(void *); 240 | stats.hash_is_expanding = 0; 241 | STATS_UNLOCK(); 242 | if (settings.verbose > 1) 243 | fprintf(stderr, "Hash table expansion done\n"); 244 | } 245 | } 246 | 247 | mutex_unlock(&cache_lock); 248 | item_unlock_global(); 249 | 250 | if (!expanding) { 251 | /* finished expanding. tell all threads to use fine-grained locks */ 252 | switch_item_lock_type(ITEM_LOCK_GRANULAR); 253 | slabs_rebalancer_resume(); 254 | /* We are done expanding.. just wait for next invocation */ 255 | mutex_lock(&cache_lock); 256 | started_expanding = false; 257 | pthread_cond_wait(&maintenance_cond, &cache_lock); 258 | /* Before doing anything, tell threads to use a global lock */ 259 | mutex_unlock(&cache_lock); 260 | slabs_rebalancer_pause(); 261 | switch_item_lock_type(ITEM_LOCK_GLOBAL); 262 | mutex_lock(&cache_lock); 263 | assoc_expand(); 264 | mutex_unlock(&cache_lock); 265 | } 266 | } 267 | return NULL; 268 | } 269 | 270 | static pthread_t maintenance_tid; 271 | 272 | int start_assoc_maintenance_thread() { 273 | int ret; 274 | char *env = getenv("MEMCACHED_HASH_BULK_MOVE"); 275 | if (env != NULL) { 276 | hash_bulk_move = atoi(env); 277 | if (hash_bulk_move == 0) { 278 | hash_bulk_move = DEFAULT_HASH_BULK_MOVE; 279 | } 280 | } 281 | if ((ret = pthread_create(&maintenance_tid, NULL, 282 | assoc_maintenance_thread, NULL)) != 0) { 283 | fprintf(stderr, "Can't create thread: %s\n", strerror(ret)); 284 | return -1; 285 | } 286 | return 0; 287 | } 288 | 289 | void stop_assoc_maintenance_thread() { 290 | mutex_lock(&cache_lock); 291 | do_run_maintenance_thread = 0; 292 | pthread_cond_signal(&maintenance_cond); 293 | mutex_unlock(&cache_lock); 294 | 295 | /* Wait for the maintenance thread to stop */ 296 | pthread_join(maintenance_tid, NULL); 297 | } 298 | 299 | 300 | -------------------------------------------------------------------------------- /memcached-1.4.15/assoc.h: -------------------------------------------------------------------------------- 1 | /* associative array */ 2 | // 关联数组 3 | // 在计算机科学中,关联数组(英语:Associative Array),又称映射(Map)、字典(Dictionary)是一个抽象的数据结构,它包含着类似于(键,值)的有序对。一个关联数组中的有序对可以重复(如C++中的multimap)也可以不重复(如C++中的map)。 4 | void assoc_init(const int hashpower_init); 5 | item *assoc_find(const char *key, const size_t nkey, const uint32_t hv); 6 | int assoc_insert(item *item, const uint32_t hv); 7 | void assoc_delete(const char *key, const size_t nkey, const uint32_t hv); 8 | void do_assoc_move_next_bucket(void); 9 | int start_assoc_maintenance_thread(void); 10 | void stop_assoc_maintenance_thread(void); 11 | extern unsigned int hashpower; 12 | -------------------------------------------------------------------------------- /memcached-1.4.15/cache.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 | #include 3 | #include 4 | #include 5 | 6 | #ifndef NDEBUG 7 | #include 8 | #endif 9 | 10 | #include "cache.h" 11 | 12 | #ifndef NDEBUG 13 | const uint64_t redzone_pattern = 0xdeadbeefcafebabe; 14 | int cache_error = 0; 15 | #endif 16 | 17 | const int initial_pool_size = 64; 18 | 19 | cache_t* cache_create(const char *name, size_t bufsize, size_t align, 20 | cache_constructor_t* constructor, 21 | cache_destructor_t* destructor) { 22 | cache_t* ret = calloc(1, sizeof(cache_t)); 23 | char* nm = strdup(name); 24 | void** ptr = calloc(initial_pool_size, sizeof(void*)); 25 | if (ret == NULL || nm == NULL || ptr == NULL || 26 | pthread_mutex_init(&ret->mutex, NULL) == -1) { 27 | free(ret); 28 | free(nm); 29 | free(ptr); 30 | return NULL; 31 | } 32 | 33 | ret->name = nm; 34 | ret->ptr = ptr; 35 | ret->freetotal = initial_pool_size; 36 | ret->constructor = constructor; 37 | ret->destructor = destructor; 38 | 39 | #ifndef NDEBUG 40 | ret->bufsize = bufsize + 2 * sizeof(redzone_pattern); 41 | #else 42 | ret->bufsize = bufsize; 43 | #endif 44 | 45 | return ret; 46 | } 47 | 48 | static inline void* get_object(void *ptr) { 49 | #ifndef NDEBUG 50 | uint64_t *pre = ptr; 51 | return pre + 1; 52 | #else 53 | return ptr; 54 | #endif 55 | } 56 | 57 | void cache_destroy(cache_t *cache) { 58 | while (cache->freecurr > 0) { 59 | void *ptr = cache->ptr[--cache->freecurr]; 60 | if (cache->destructor) { 61 | cache->destructor(get_object(ptr), NULL); 62 | } 63 | free(ptr); 64 | } 65 | free(cache->name); 66 | free(cache->ptr); 67 | pthread_mutex_destroy(&cache->mutex); 68 | free(cache); 69 | } 70 | 71 | void* cache_alloc(cache_t *cache) { 72 | void *ret; 73 | void *object; 74 | pthread_mutex_lock(&cache->mutex); 75 | if (cache->freecurr > 0) { 76 | ret = cache->ptr[--cache->freecurr]; 77 | object = get_object(ret); 78 | } else { 79 | object = ret = malloc(cache->bufsize); 80 | if (ret != NULL) { 81 | object = get_object(ret); 82 | 83 | if (cache->constructor != NULL && 84 | cache->constructor(object, NULL, 0) != 0) { 85 | free(ret); 86 | object = NULL; 87 | } 88 | } 89 | } 90 | pthread_mutex_unlock(&cache->mutex); 91 | 92 | #ifndef NDEBUG 93 | if (object != NULL) { 94 | /* add a simple form of buffer-check */ 95 | uint64_t *pre = ret; 96 | *pre = redzone_pattern; 97 | ret = pre+1; 98 | memcpy(((char*)ret) + cache->bufsize - (2 * sizeof(redzone_pattern)), 99 | &redzone_pattern, sizeof(redzone_pattern)); 100 | } 101 | #endif 102 | 103 | return object; 104 | } 105 | 106 | void cache_free(cache_t *cache, void *ptr) { 107 | pthread_mutex_lock(&cache->mutex); 108 | 109 | #ifndef NDEBUG 110 | /* validate redzone... */ 111 | if (memcmp(((char*)ptr) + cache->bufsize - (2 * sizeof(redzone_pattern)), 112 | &redzone_pattern, sizeof(redzone_pattern)) != 0) { 113 | raise(SIGABRT); 114 | cache_error = 1; 115 | pthread_mutex_unlock(&cache->mutex); 116 | return; 117 | } 118 | uint64_t *pre = ptr; 119 | --pre; 120 | if (*pre != redzone_pattern) { 121 | raise(SIGABRT); 122 | cache_error = -1; 123 | pthread_mutex_unlock(&cache->mutex); 124 | return; 125 | } 126 | ptr = pre; 127 | #endif 128 | if (cache->freecurr < cache->freetotal) { 129 | cache->ptr[cache->freecurr++] = ptr; 130 | } else { 131 | /* try to enlarge free connections array */ 132 | size_t newtotal = cache->freetotal * 2; 133 | void **new_free = realloc(cache->ptr, sizeof(char *) * newtotal); 134 | if (new_free) { 135 | cache->freetotal = newtotal; 136 | cache->ptr = new_free; 137 | cache->ptr[cache->freecurr++] = ptr; 138 | } else { 139 | if (cache->destructor) { 140 | cache->destructor(ptr, NULL); 141 | } 142 | free(ptr); 143 | 144 | } 145 | } 146 | pthread_mutex_unlock(&cache->mutex); 147 | } 148 | 149 | -------------------------------------------------------------------------------- /memcached-1.4.15/cache.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 | #ifndef CACHE_H 3 | #define CACHE_H 4 | #include 5 | 6 | #ifdef HAVE_UMEM_H 7 | #include 8 | #define cache_t umem_cache_t 9 | #define cache_alloc(a) umem_cache_alloc(a, UMEM_DEFAULT) 10 | #define cache_free(a, b) umem_cache_free(a, b) 11 | #define cache_create(a,b,c,d,e) umem_cache_create((char*)a, b, c, d, e, NULL, NULL, NULL, 0) 12 | #define cache_destroy(a) umem_cache_destroy(a); 13 | 14 | #else 15 | 16 | #ifndef NDEBUG 17 | /* may be used for debug purposes */ 18 | extern int cache_error; 19 | #endif 20 | 21 | /** 22 | * Constructor used to initialize allocated objects 23 | * 24 | * @param obj pointer to the object to initialized. 25 | * @param notused1 This parameter is currently not used. 26 | * @param notused2 This parameter is currently not used. 27 | * @return you should return 0, but currently this is not checked 28 | */ 29 | typedef int cache_constructor_t(void* obj, void* notused1, int notused2); 30 | /** 31 | * Destructor used to clean up allocated objects before they are 32 | * returned to the operating system. 33 | * 34 | * @param obj pointer to the object to initialized. 35 | * @param notused1 This parameter is currently not used. 36 | * @param notused2 This parameter is currently not used. 37 | * @return you should return 0, but currently this is not checked 38 | */ 39 | typedef void cache_destructor_t(void* obj, void* notused); 40 | 41 | /** 42 | * Definition of the structure to keep track of the internal details of 43 | * the cache allocator. Touching any of these variables results in 44 | * undefined behavior. 45 | */ 46 | typedef struct { 47 | /** Mutex to protect access to the structure */ 48 | pthread_mutex_t mutex; 49 | /** Name of the cache objects in this cache (provided by the caller) */ 50 | char *name; 51 | /** List of pointers to available buffers in this cache */ 52 | void **ptr; 53 | /** The size of each element in this cache */ 54 | size_t bufsize; 55 | /** The capacity of the list of elements */ 56 | int freetotal; 57 | /** The current number of free elements */ 58 | int freecurr; 59 | /** The constructor to be called each time we allocate more memory */ 60 | cache_constructor_t* constructor; 61 | /** The destructor to be called each time before we release memory */ 62 | cache_destructor_t* destructor; 63 | } cache_t; 64 | 65 | /** 66 | * Create an object cache. 67 | * 68 | * The object cache will let you allocate objects of the same size. It is fully 69 | * MT safe, so you may allocate objects from multiple threads without having to 70 | * do any syncrhonization in the application code. 71 | * 72 | * @param name the name of the object cache. This name may be used for debug purposes 73 | * and may help you track down what kind of object you have problems with 74 | * (buffer overruns, leakage etc) 75 | * @param bufsize the size of each object in the cache 76 | * @param align the alignment requirements of the objects in the cache. 77 | * @param constructor the function to be called to initialize memory when we need 78 | * to allocate more memory from the os. 79 | * @param destructor the function to be called before we release the memory back 80 | * to the os. 81 | * @return a handle to an object cache if successful, NULL otherwise. 82 | */ 83 | cache_t* cache_create(const char* name, size_t bufsize, size_t align, 84 | cache_constructor_t* constructor, 85 | cache_destructor_t* destructor); 86 | /** 87 | * Destroy an object cache. 88 | * 89 | * Destroy and invalidate an object cache. You should return all buffers allocated 90 | * with cache_alloc by using cache_free before calling this function. Not doing 91 | * so results in undefined behavior (the buffers may or may not be invalidated) 92 | * 93 | * @param handle the handle to the object cache to destroy. 94 | */ 95 | void cache_destroy(cache_t* handle); 96 | /** 97 | * Allocate an object from the cache. 98 | * 99 | * @param handle the handle to the object cache to allocate from 100 | * @return a pointer to an initialized object from the cache, or NULL if 101 | * the allocation cannot be satisfied. 102 | */ 103 | void* cache_alloc(cache_t* handle); 104 | /** 105 | * Return an object back to the cache. 106 | * 107 | * The caller should return the object in an initialized state so that 108 | * the object may be returned in an expected state from cache_alloc. 109 | * 110 | * @param handle handle to the object cache to return the object to 111 | * @param ptr pointer to the object to return. 112 | */ 113 | void cache_free(cache_t* handle, void* ptr); 114 | #endif 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /memcached-1.4.15/compile: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Wrapper for compilers which do not understand `-c -o'. 3 | 4 | scriptversion=2009-10-06.20; # UTC 5 | 6 | # Copyright (C) 1999, 2000, 2003, 2004, 2005, 2009 Free Software 7 | # Foundation, Inc. 8 | # Written by Tom Tromey . 9 | # 10 | # This program is free software; you can redistribute it and/or modify 11 | # it under the terms of the GNU General Public License as published by 12 | # the Free Software Foundation; either version 2, or (at your option) 13 | # any later version. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program. If not, see . 22 | 23 | # As a special exception to the GNU General Public License, if you 24 | # distribute this file as part of a program that contains a 25 | # configuration script generated by Autoconf, you may include it under 26 | # the same distribution terms that you use for the rest of that program. 27 | 28 | # This file is maintained in Automake, please report 29 | # bugs to or send patches to 30 | # . 31 | 32 | case $1 in 33 | '') 34 | echo "$0: No command. Try \`$0 --help' for more information." 1>&2 35 | exit 1; 36 | ;; 37 | -h | --h*) 38 | cat <<\EOF 39 | Usage: compile [--help] [--version] PROGRAM [ARGS] 40 | 41 | Wrapper for compilers which do not understand `-c -o'. 42 | Remove `-o dest.o' from ARGS, run PROGRAM with the remaining 43 | arguments, and rename the output as expected. 44 | 45 | If you are trying to build a whole package this is not the 46 | right script to run: please start by reading the file `INSTALL'. 47 | 48 | Report bugs to . 49 | EOF 50 | exit $? 51 | ;; 52 | -v | --v*) 53 | echo "compile $scriptversion" 54 | exit $? 55 | ;; 56 | esac 57 | 58 | ofile= 59 | cfile= 60 | eat= 61 | 62 | for arg 63 | do 64 | if test -n "$eat"; then 65 | eat= 66 | else 67 | case $1 in 68 | -o) 69 | # configure might choose to run compile as `compile cc -o foo foo.c'. 70 | # So we strip `-o arg' only if arg is an object. 71 | eat=1 72 | case $2 in 73 | *.o | *.obj) 74 | ofile=$2 75 | ;; 76 | *) 77 | set x "$@" -o "$2" 78 | shift 79 | ;; 80 | esac 81 | ;; 82 | *.c) 83 | cfile=$1 84 | set x "$@" "$1" 85 | shift 86 | ;; 87 | *) 88 | set x "$@" "$1" 89 | shift 90 | ;; 91 | esac 92 | fi 93 | shift 94 | done 95 | 96 | if test -z "$ofile" || test -z "$cfile"; then 97 | # If no `-o' option was seen then we might have been invoked from a 98 | # pattern rule where we don't need one. That is ok -- this is a 99 | # normal compilation that the losing compiler can handle. If no 100 | # `.c' file was seen then we are probably linking. That is also 101 | # ok. 102 | exec "$@" 103 | fi 104 | 105 | # Name of file we expect compiler to create. 106 | cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` 107 | 108 | # Create the lock directory. 109 | # Note: use `[/\\:.-]' here to ensure that we don't use the same name 110 | # that we are using for the .o file. Also, base the name on the expected 111 | # object file name, since that is what matters with a parallel build. 112 | lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d 113 | while true; do 114 | if mkdir "$lockdir" >/dev/null 2>&1; then 115 | break 116 | fi 117 | sleep 1 118 | done 119 | # FIXME: race condition here if user kills between mkdir and trap. 120 | trap "rmdir '$lockdir'; exit 1" 1 2 15 121 | 122 | # Run the compile. 123 | "$@" 124 | ret=$? 125 | 126 | if test -f "$cofile"; then 127 | test "$cofile" = "$ofile" || mv "$cofile" "$ofile" 128 | elif test -f "${cofile}bj"; then 129 | test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" 130 | fi 131 | 132 | rmdir "$lockdir" 133 | exit $ret 134 | 135 | # Local Variables: 136 | # mode: shell-script 137 | # sh-indentation: 2 138 | # eval: (add-hook 'write-file-hooks 'time-stamp) 139 | # time-stamp-start: "scriptversion=" 140 | # time-stamp-format: "%:y-%02m-%02d.%02H" 141 | # time-stamp-time-zone: "UTC" 142 | # time-stamp-end: "; # UTC" 143 | # End: 144 | -------------------------------------------------------------------------------- /memcached-1.4.15/config.h.in: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* Set to nonzero if you want to include DTRACE */ 4 | #undef ENABLE_DTRACE 5 | 6 | /* Set to nonzero if you want to include SASL */ 7 | #undef ENABLE_SASL 8 | 9 | /* Set to nonzero if you want to enable a SASL pwdb */ 10 | #undef ENABLE_SASL_PWDB 11 | 12 | /* machine is bigendian */ 13 | #undef ENDIAN_BIG 14 | 15 | /* machine is littleendian */ 16 | #undef ENDIAN_LITTLE 17 | 18 | /* Define to 1 if you have the `clock_gettime' function. */ 19 | #undef HAVE_CLOCK_GETTIME 20 | 21 | /* Define this if you have an implementation of drop_privileges() */ 22 | #undef HAVE_DROP_PRIVILEGES 23 | 24 | /* GCC Atomics available */ 25 | #undef HAVE_GCC_ATOMICS 26 | 27 | /* Define to 1 if you have the `getpagesizes' function. */ 28 | #undef HAVE_GETPAGESIZES 29 | 30 | /* Have ntohll */ 31 | #undef HAVE_HTONLL 32 | 33 | /* Define to 1 if you have the header file. */ 34 | #undef HAVE_INTTYPES_H 35 | 36 | /* Define to 1 if you have the `memcntl' function. */ 37 | #undef HAVE_MEMCNTL 38 | 39 | /* Define to 1 if you have the header file. */ 40 | #undef HAVE_MEMORY_H 41 | 42 | /* Define to 1 if you have the `mlockall' function. */ 43 | #undef HAVE_MLOCKALL 44 | 45 | /* we have sasl_callback_ft */ 46 | #undef HAVE_SASL_CALLBACK_FT 47 | 48 | /* Set to nonzero if your SASL implementation supports SASL_CB_GETCONF */ 49 | #undef HAVE_SASL_CB_GETCONF 50 | 51 | /* Define to 1 if you have the header file. */ 52 | #undef HAVE_SASL_SASL_H 53 | 54 | /* Define to 1 if you have the `setppriv' function. */ 55 | #undef HAVE_SETPPRIV 56 | 57 | /* Define to 1 if you have the `sigignore' function. */ 58 | #undef HAVE_SIGIGNORE 59 | 60 | /* Define to 1 if stdbool.h conforms to C99. */ 61 | #undef HAVE_STDBOOL_H 62 | 63 | /* Define to 1 if you have the header file. */ 64 | #undef HAVE_STDINT_H 65 | 66 | /* Define to 1 if you have the header file. */ 67 | #undef HAVE_STDLIB_H 68 | 69 | /* Define to 1 if you have the header file. */ 70 | #undef HAVE_STRINGS_H 71 | 72 | /* Define to 1 if you have the header file. */ 73 | #undef HAVE_STRING_H 74 | 75 | /* Define to 1 if you have the header file. */ 76 | #undef HAVE_SYS_STAT_H 77 | 78 | /* Define to 1 if you have the header file. */ 79 | #undef HAVE_SYS_TYPES_H 80 | 81 | /* Define this if you have umem.h */ 82 | #undef HAVE_UMEM_H 83 | 84 | /* Define to 1 if you have the header file. */ 85 | #undef HAVE_UNISTD_H 86 | 87 | /* Define to 1 if the system has the type `_Bool'. */ 88 | #undef HAVE__BOOL 89 | 90 | /* Machine need alignment */ 91 | #undef NEED_ALIGN 92 | 93 | /* Define to 1 if your C compiler doesn't accept -c and -o together. */ 94 | #undef NO_MINUS_C_MINUS_O 95 | 96 | /* Name of package */ 97 | #undef PACKAGE 98 | 99 | /* Define to the address where bug reports for this package should be sent. */ 100 | #undef PACKAGE_BUGREPORT 101 | 102 | /* Define to the full name of this package. */ 103 | #undef PACKAGE_NAME 104 | 105 | /* Define to the full name and version of this package. */ 106 | #undef PACKAGE_STRING 107 | 108 | /* Define to the one symbol short name of this package. */ 109 | #undef PACKAGE_TARNAME 110 | 111 | /* Define to the home page for this package. */ 112 | #undef PACKAGE_URL 113 | 114 | /* Define to the version of this package. */ 115 | #undef PACKAGE_VERSION 116 | 117 | /* Define to 1 if you have the ANSI C header files. */ 118 | #undef STDC_HEADERS 119 | 120 | /* Version number of package */ 121 | #undef VERSION 122 | 123 | /* find sigignore on Linux */ 124 | #undef _GNU_SOURCE 125 | 126 | /* Define to empty if `const' does not conform to ANSI C. */ 127 | #undef const 128 | 129 | /* define to int if socklen_t not available */ 130 | #undef socklen_t 131 | 132 | #if HAVE_STDBOOL_H 133 | #include 134 | #else 135 | #define bool char 136 | #define false 0 137 | #define true 1 138 | #endif 139 | 140 | #ifdef HAVE_INTTYPES_H 141 | #include 142 | #endif 143 | 144 | -------------------------------------------------------------------------------- /memcached-1.4.15/daemon.c: -------------------------------------------------------------------------------- 1 | /* $Header: /cvsroot/wikipedia/willow/src/bin/willow/daemon.c,v 1.1 2005/05/02 19:15:21 kateturner Exp $ */ 2 | /* $NetBSD: daemon.c,v 1.9 2003/08/07 16:42:46 agc Exp $ */ 3 | /*- 4 | * Copyright (c) 1990, 1993 5 | * The Regents of the University of California. All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 3. Neither the name of the University nor the names of its contributors 16 | * may be used to endorse or promote products derived from this software 17 | * without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 | * SUCH DAMAGE. 30 | */ 31 | 32 | #if defined __SUNPRO_C || defined __DECC || defined __HP_cc 33 | # pragma ident "@(#)$Header: /cvsroot/wikipedia/willow/src/bin/willow/daemon.c,v 1.1 2005/05/02 19:15:21 kateturner Exp $" 34 | # pragma ident "$NetBSD: daemon.c,v 1.9 2003/08/07 16:42:46 agc Exp $" 35 | #endif 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include "memcached.h" 43 | 44 | int daemonize(int nochdir, int noclose) 45 | { 46 | int fd; 47 | 48 | switch (fork()) { 49 | case -1: 50 | // fork() 调用不成功, 结束 51 | return (-1); 52 | case 0: 53 | // 子进程继续执行 54 | break; 55 | default: 56 | // 父进程退出 57 | _exit(EXIT_SUCCESS); 58 | } 59 | 60 | // 守护进程的一般过程 61 | if (setsid() == -1) 62 | return (-1); 63 | 64 | if (nochdir == 0) { 65 | if(chdir("/") != 0) { 66 | perror("chdir"); 67 | return (-1); 68 | } 69 | } 70 | 71 | if (noclose == 0 && (fd = open("/dev/null", O_RDWR, 0)) != -1) { 72 | if(dup2(fd, STDIN_FILENO) < 0) { 73 | perror("dup2 stdin"); 74 | return (-1); 75 | } 76 | if(dup2(fd, STDOUT_FILENO) < 0) { 77 | perror("dup2 stdout"); 78 | return (-1); 79 | } 80 | if(dup2(fd, STDERR_FILENO) < 0) { 81 | perror("dup2 stderr"); 82 | return (-1); 83 | } 84 | 85 | if (fd > STDERR_FILENO) { 86 | if(close(fd) < 0) { 87 | perror("close"); 88 | return (-1); 89 | } 90 | } 91 | } 92 | return (0); 93 | } 94 | -------------------------------------------------------------------------------- /memcached-1.4.15/doc/CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | MEMCACHED CONTRIBUTORS 2 | 3 | This file contains a list of people who have contributed code and 4 | effort to the memcached project. If you don't see your name mentioned 5 | send email to the memcached mailing list so you can be immortalized. 6 | 7 | Also see the ChangeLog for even more people who have helped over the 8 | years by submitting fixes, patches and reporting bugs. 9 | 10 | 11 | Major authors: 12 | -------------- 13 | 14 | Brad Fitzpatrick -- maintainer, original implementations 15 | 16 | Anatoly Vorobey -- lots of the modern server code 17 | 18 | Steven Grimm -- iov writing (less CPU), UDP mode, 19 | non-2.0 slab mantissas, multithread, ... 20 | 21 | Other Contributors 22 | ------------------ 23 | 24 | Evan Martin 25 | Nathan Neulinger 26 | Eric Hodel 27 | Michael Johnson 28 | Paul Querna 29 | Jamie McCarthy 30 | Philip Neustrom 31 | Andrew O'Brien 32 | Josh Rotenberg 33 | Robin H. Johnson 34 | Tim Yardley 35 | Paolo Borelli 36 | Eli Bingham 37 | Jean-Francois Bustarret 38 | Paul G 39 | Paul Lindner 40 | Dormando 41 | Dustin Sallings 42 | Chris Goffinet 43 | Tomash Brechko 44 | Brian Aker 45 | Trond Norbye 46 | -------------------------------------------------------------------------------- /memcached-1.4.15/doc/Makefile.am: -------------------------------------------------------------------------------- 1 | man_MANS = memcached.1 2 | 3 | EXTRA_DIST = *.txt 4 | 5 | BUILT_SOURCES= 6 | 7 | if BUILD_SPECIFICATIONS 8 | BUILT_SOURCES += protocol-binary.txt protocol-binary-range.txt 9 | MOSTLYCLEANFILES = protocol-binary.txt protocol-binary-range.txt 10 | endif 11 | 12 | %.txt: %.full 13 | @XML2RFC@ $< $@ 14 | 15 | %.chk: %.xml xml2rfc/rfc2629-refchk.xsl 16 | @XSLTPROC@ xml2rfc/rfc2629-refchk.xsl $< >$@ 17 | 18 | %.full: %.xml xml2rfc/rfc2629-noinc.xsl 19 | @XSLTPROC@ xml2rfc/rfc2629-noinc.xsl $< >$@ 20 | 21 | -------------------------------------------------------------------------------- /memcached-1.4.15/doc/memcached.1: -------------------------------------------------------------------------------- 1 | .TH MEMCACHED 1 "April 11, 2005" 2 | .SH NAME 3 | memcached \- high-performance memory object caching system 4 | .SH SYNOPSIS 5 | .B memcached 6 | .RI [ options ] 7 | .br 8 | .SH DESCRIPTION 9 | This manual page documents briefly the 10 | .B memcached 11 | memory object caching daemon. 12 | .PP 13 | .B memcached 14 | is a flexible memory object caching daemon designed to alleviate database load 15 | in dynamic web applications by storing objects in memory. It's based on 16 | libevent to scale to any size needed, and is specifically optimized to avoid 17 | swapping and always use non-blocking I/O. 18 | .br 19 | .SH OPTIONS 20 | These programs follow the usual GNU command line syntax. A summary of options 21 | is included below. 22 | .TP 23 | .B \-s 24 | Unix socket path to listen on (disables network support). 25 | .TP 26 | .B \-a 27 | Permissions (in octal format) for Unix socket created with \-s option. 28 | .TP 29 | .B \-l 30 | Listen on ; default to INADDR_ANY. This is an important option to 31 | consider as there is no other way to secure the installation. Binding to an 32 | internal or firewalled network interface is suggested. 33 | .TP 34 | .B \-d 35 | Run memcached as a daemon. 36 | .TP 37 | .B \-u 38 | Assume the identity of (only when run as root). 39 | .TP 40 | .B \-m 41 | Use MB memory max to use for object storage; the default is 64 megabytes. 42 | .TP 43 | .B \-c 44 | Use max simultaneous connections; the default is 1024. 45 | .TP 46 | .B \-R 47 | This option seeks to prevent client starvation by setting a limit to the 48 | number of sequential requests the server will process from an individual 49 | client connection. Once a connection has exceeded this value, the server will 50 | attempt to process I/O on other connections before handling any further 51 | request from this connection. The default value for this option is 20. 52 | .TP 53 | .B \-k 54 | Lock down all paged memory. This is a somewhat dangerous option with large 55 | caches, so consult the README and memcached homepage for configuration 56 | suggestions. 57 | .TP 58 | .B \-p 59 | Listen on TCP port , the default is port 11211. 60 | .TP 61 | .B \-U 62 | Listen on UDP port , the default is port 11211, 0 is off. 63 | .TP 64 | .B \-M 65 | Disable automatic removal of items from the cache when out of memory. 66 | Additions will not be possible until adequate space is freed up. 67 | .TP 68 | .B \-r 69 | Raise the core file size limit to the maximum allowable. 70 | .TP 71 | .B \-f 72 | Use as the multiplier for computing the sizes of memory chunks that 73 | items are stored in. A lower value may result in less wasted memory depending 74 | on the total amount of memory available and the distribution of item sizes. 75 | The default is 1.25. 76 | .TP 77 | .B \-n 78 | Allocate a minimum of bytes for the item key, value, and flags. The 79 | default is 48. If you have a lot of small keys and values, you can get a 80 | significant memory efficiency gain with a lower value. If you use a high 81 | chunk growth factor (\-f option), on the other hand, you may want to increase 82 | the size to allow a bigger percentage of your items to fit in the most densely 83 | packed (smallest) chunks. 84 | .TP 85 | .B \-C 86 | Disable the use of CAS (and reduce the per-item size by 8 bytes). 87 | .TP 88 | .B \-h 89 | Show the version of memcached and a summary of options. 90 | .TP 91 | .B \-v 92 | Be verbose during the event loop; print out errors and warnings. 93 | .TP 94 | .B \-vv 95 | Be even more verbose; same as \-v but also print client commands and 96 | responses. 97 | .TP 98 | .B \-i 99 | Print memcached and libevent licenses. 100 | .TP 101 | .B \-P 102 | Print pidfile to , only used under \-d option. 103 | .TP 104 | .B \-t 105 | Number of threads to use to process incoming requests. This option is only 106 | meaningful if memcached was compiled with thread support enabled. It is 107 | typically not useful to set this higher than the number of CPU cores on the 108 | memcached server. The default is 4. 109 | .TP 110 | .B \-D 111 | Use as the delimiter between key prefixes and IDs. This is used for 112 | per-prefix stats reporting. The default is ":" (colon). If this option is 113 | specified, stats collection is turned on automatically; if not, then it may 114 | be turned on by sending the "stats detail on" command to the server. 115 | .TP 116 | .B \-L 117 | Try to use large memory pages (if available). Increasing the memory page size 118 | could reduce the number of TLB misses and improve the performance. In order to 119 | get large pages from the OS, memcached will allocate the total item-cache in 120 | one large chunk. Only available if supported on your OS. 121 | .TP 122 | .B \-B 123 | Specify the binding protocol to use. By default, the server will 124 | autonegotiate client connections. By using this option, you can 125 | specify the protocol clients must speak. Possible options are "auto" 126 | (the default, autonegotiation behavior), "ascii" and "binary". 127 | .TP 128 | .B \-I 129 | Override the default size of each slab page. Default is 1mb. Default is 1m, 130 | minimum is 1k, max is 128m. Adjusting this value changes the item size limit. 131 | Beware that this also increases the number of slabs (use -v to view), and the 132 | overal memory usage of memcached. 133 | .TP 134 | .B \-o 135 | Comma separated list of extended or experimental options. See -h or wiki for 136 | up to date list. 137 | .br 138 | .SH LICENSE 139 | The memcached daemon is copyright Danga Interactive and is distributed under 140 | the BSD license. Note that daemon clients are licensed separately. 141 | .br 142 | .SH SEE ALSO 143 | The README file that comes with memcached 144 | .br 145 | .B http://www.danga.com/memcached 146 | .SH AUTHOR 147 | The memcached daemon was written by Anatoly Vorobey 148 | .B 149 | and Brad Fitzpatrick 150 | .B 151 | and the rest of the crew of Danga Interactive 152 | .B http://www.danga.com 153 | .br 154 | -------------------------------------------------------------------------------- /memcached-1.4.15/doc/protocol-binary-range.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Memcache Binary Protocol: Extensions for UDP 15 | 16 | 17 | Six Apart, Ltd. 18 |
19 | 20 | 548 4th Street 21 | San Francisco 22 | CA 23 | 94107 24 | USA 25 | 26 | aaron@serendipity.palo-alto.ca.us 27 |
28 |
29 | 30 | 31 | 32 | Applications 33 | 34 | memcache memcached cache udp 35 | 36 | 37 | 38 | This memo explains extensions to the memcache binary protocol for use in a UDP environment. 39 | 40 | 41 | 42 | Memcache is a high performance key-value cache. It is intentionally a 43 | dumb cache, optimized for speed only. Applications using memcache do 44 | not rely on it for data -- a persistent database with guaranteed reliability 45 | is strongly recommended -- but applications can run much faster when 46 | cached data is available in memcache. 47 | 48 | 49 |
50 | 51 | 52 |
53 | 54 | Memcache is a high performance key-value cache. It is intentionally a 55 | dumb cache, optimized for speed only. Applications using memcache do 56 | not rely on it for data -- a persistent database with guaranteed reliability 57 | is strongly recommended -- but applications can run much faster when 58 | cached data is available in memcache. 59 | 60 | 61 | Sites may find that, due to their network architecture or application usage patterns, 62 | the stateless protocol better suits their needs. This document 63 | provides extensions and descriptions of use of the memcache protocol 64 | in a UDP environment. 65 | 66 | 67 | It is a goal of this document to provide sufficient information in each UDP packet 68 | as to avoid any requirement for statefulness on the part of the server nor significant 69 | caching of outstanding packets on the part of the client. 70 | 71 |
72 | The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 73 | "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this 74 | document are to be interpreted as described in . 75 | 76 |
77 |
78 | 79 |
80 |
81 | 82 | The magic bytes remains the same as in . 83 | 84 |
85 | 86 |
87 | 88 | Additional status values: 89 | 90 | Value is larger than a single response packet 91 | 92 | 93 |
94 | 95 |
96 | 97 | Additional opcode values: 98 | 99 | Get Range 100 | Set Range 101 | 102 | 103 |
104 | 105 |
106 | 107 | There are no new data types in this extension. 108 | 109 |
110 |
111 | 112 |
113 | 114 |
115 | 116 | This section extends the behavior of the Get and GetQ commands as described in 117 | . 118 | 119 | 120 | 121 | When a Get or GetQ request is made via UDP, and the value of the key for which 122 | the request was made is larger than can be placed into a single UDP packet (noting 123 | that the protocol header must also be counted), a Get Range response packet 124 | MUST be sent instead of the Get response packet. In this instance: 125 | 126 | The Status field of the response header MUST be 0x0004. 127 | The Offset field of the GetR response extras MUST be 0. 128 | The Length field of the GetR response extras, and the data contained in 129 | the Value field of the packet, SHOULD be the maximum 130 | allowed length of a UDP packet, less the space required by the header 131 | and extras; however it MAY be any amount below this maximum. 132 | The Total value length field of the response extras MUST be the 133 | actual length of the complete value. 134 | 135 | 136 | 137 | 138 | The client, upon receipt of a Get Range response bearing Status 0x004 139 | and a Message ID corresponding to its Get request, shall then know that 140 | it has received only the first portion of the value. The client MAY choose 141 | to request the remaining portion of the value by sending one or more Get Range requests. 142 | 143 |
144 | 145 |
146 | 147 | The Get Range request is primarily intended for use over a UDP transport 148 | to request byte ranges of the value for a key. In the event that the Data version 149 | check fails to match that of the key, an error MUST be returned. 150 | 151 | 152 |
153 | Extra data for get range request: 154 | 155 | Byte/ 0 | 1 | 2 | 3 | 156 | / | | | | 157 | |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7| 158 | +---------------+---------------+---------------+---------------+ 159 | 0| Flags | 160 | +---------------+---------------+---------------+---------------+ 161 | 4| Data version check | 162 | | | 163 | +---------------+---------------+---------------+---------------+ 164 | 12| Offset | 165 | +---------------+---------------+---------------+---------------+ 166 | 16| Length | 167 | +---------------+---------------+---------------+---------------+ 168 | Total 20 bytes 169 |
170 |
171 |
172 | 173 |
174 | 175 | The Get Range request is primarily intended for use over a UDP transport 176 | to indicate the location of the bytes of the value for a key contained in 177 | a given packet. A client receives enough information in each Get Range 178 | extras to construct an appropriately sized buffer in its own memory and 179 | blindly insert the contents of the packet at the given byte offset. 180 | 181 | 182 |
183 | Extra data for get range response: 184 | 185 | Byte/ 0 | 1 | 2 | 3 | 186 | / | | | | 187 | |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7| 188 | +---------------+---------------+---------------+---------------+ 189 | 0| Flags | 190 | +---------------+---------------+---------------+---------------+ 191 | 4| Data version check | 192 | | | 193 | +---------------+---------------+---------------+---------------+ 194 | 12| Offset | 195 | +---------------+---------------+---------------+---------------+ 196 | 16| Length | 197 | +---------------+---------------+---------------+---------------+ 198 | 20| Total value length | 199 | +---------------+---------------+---------------+---------------+ 200 | Total 24 bytes 201 |
202 |
203 |
204 | 205 |
206 | 207 |
208 | 209 | This document does not introduce any new security considerations 210 | beyond those discussed in . 211 | 212 |
213 | 214 |
215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 |
226 | 227 | -------------------------------------------------------------------------------- /memcached-1.4.15/doc/readme.txt: -------------------------------------------------------------------------------- 1 | To build the documentation you need xml2rfc ( http://xml.resource.org/ ). 2 | -------------------------------------------------------------------------------- /memcached-1.4.15/doc/threads.txt: -------------------------------------------------------------------------------- 1 | WARNING: This document is currently a stub. It is incomplete, but provided to 2 | give a vague overview of how threads are implemented. 3 | 4 | Multithreading in memcached *was* originally simple: 5 | 6 | - One listener thread 7 | - N "event worker" threads 8 | - Some misc background threads 9 | 10 | Each worker thread is assigned connections, and runs its own epoll loop. The 11 | central hash table, LRU lists, and some statistics counters are covered by 12 | global locks. Protocol parsing, data transfer happens in threads. Data lookups 13 | and modifications happen under central locks. 14 | 15 | THIS HAS CHANGED! 16 | 17 | I do need to flesh this out more, and it'll need a lot more tuning, but it has 18 | changed in the following ways: 19 | 20 | - A secondary small hash table of locks is used to lock an item by its hash 21 | value. This prevents multiple threads from acting on the same item at the 22 | same time. 23 | - This secondary hash table is mapped to the central hash tables buckets. This 24 | allows multiple threads to access the hash table in parallel. Only one 25 | thread may read or write against a particular hash table bucket. 26 | - atomic refcounts per item are used to manage garbage collection and 27 | mutability. 28 | - A central lock is still held around any "item modifications" - any change to 29 | any item flags on any item, the LRU state, or refcount incrementing are 30 | still centrally locked. 31 | 32 | - When pulling an item off of the LRU tail for eviction or re-allocation, the 33 | system must attempt to lock the item's bucket, which is done with a trylock 34 | to avoid deadlocks. If a bucket is in use (and not by that thread) it will 35 | walk up the LRU a little in an attempt to fetch a non-busy item. 36 | 37 | Since I'm sick of hearing it: 38 | 39 | - If you remove the per-thread stats lock, CPU usage goes down by less than a 40 | point of a percent, and it does not improve scalability. 41 | - In my testing, the remaining global STATS_LOCK calls never seem to collide. 42 | 43 | Yes, more stats can be moved to threads, and those locks can actually be 44 | removed entirely on x86-64 systems. However my tests haven't shown that as 45 | beneficial so far, so I've prioritized other work. Apologies for the rant but 46 | it's a common question. 47 | -------------------------------------------------------------------------------- /memcached-1.4.15/doc/xml2rfc/reference.RFC.0768.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | User Datagram Protocol 7 | 8 | University of Southern California (USC)/Information Sciences Institute 9 |
10 | 11 | 4676 Admiralty Way 12 | Marina del Rey 13 | CA 14 | 90291 15 | US 16 | +1 213 822 1511
17 |
18 | 19 | 20 | 21 | 22 |
23 | -------------------------------------------------------------------------------- /memcached-1.4.15/doc/xml2rfc/rfc2629-noinc.xsl: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | .xml 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | http://xml.resource.org/public/rfc/ 51 | 52 | .xml 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /memcached-1.4.15/doc/xml2rfc/rfc2629-other.ent: -------------------------------------------------------------------------------- 1 | 20 | 21 | 22 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /memcached-1.4.15/doc/xml2rfc/rfc2629-refchk.xsl: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /memcached-1.4.15/doc/xml2rfc/rfc2629.dtd: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 17 | 18 | 19 | 34 | 35 | 36 | 39 | 40 | 41 | 44 | %rfc2629-xhtml; 45 | 46 | 49 | %rfc2629-other; 50 | 51 | 52 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 92 | 93 | 94 | 100 | 101 | 117 | 118 | 119 | 122 | 123 | 124 | 126 | 127 | 128 | 129 | 131 | 132 | 133 | 138 | 139 | 141 | 143 | 144 | 145 | 146 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 175 | 176 | 177 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 191 | 192 | 200 | 201 | 202 | 203 | 206 | 207 | 209 | 210 | 214 | 215 | 216 | 221 | 222 | 223 | 225 | 226 | 227 | 231 | 232 | 233 | 236 | 237 | 238 | 240 | 241 | 242 | 244 | 245 | 246 | 254 | 255 | 256 | 257 | 266 | 267 | 268 | 269 | 270 | 273 | 274 | 277 | 278 | 279 | 280 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 291 | 292 | 295 | 296 | 299 | 300 | 304 | 305 | -------------------------------------------------------------------------------- /memcached-1.4.15/hash.h: -------------------------------------------------------------------------------- 1 | #ifndef HASH_H 2 | #define HASH_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | uint32_t hash(const void *key, size_t length, const uint32_t initval); 9 | 10 | #ifdef __cplusplus 11 | } 12 | #endif 13 | 14 | #endif /* HASH_H */ 15 | 16 | -------------------------------------------------------------------------------- /memcached-1.4.15/items.h: -------------------------------------------------------------------------------- 1 | /* See items.c */ 2 | uint64_t get_cas_id(void); 3 | 4 | /*@null@*/ 5 | item *do_item_alloc(char *key, const size_t nkey, const int flags, const rel_time_t exptime, const int nbytes, const uint32_t cur_hv); 6 | void item_free(item *it); 7 | bool item_size_ok(const size_t nkey, const int flags, const int nbytes); 8 | 9 | int do_item_link(item *it, const uint32_t hv); /** may fail if transgresses limits */ 10 | void do_item_unlink(item *it, const uint32_t hv); 11 | void do_item_unlink_nolock(item *it, const uint32_t hv); 12 | void do_item_remove(item *it); 13 | void do_item_update(item *it); /** update LRU time to current and reposition */ 14 | int do_item_replace(item *it, item *new_it, const uint32_t hv); 15 | 16 | /*@null@*/ 17 | char *do_item_cachedump(const unsigned int slabs_clsid, const unsigned int limit, unsigned int *bytes); 18 | void do_item_stats(ADD_STAT add_stats, void *c); 19 | void do_item_stats_totals(ADD_STAT add_stats, void *c); 20 | /*@null@*/ 21 | void do_item_stats_sizes(ADD_STAT add_stats, void *c); 22 | void do_item_flush_expired(void); 23 | 24 | item *do_item_get(const char *key, const size_t nkey, const uint32_t hv); 25 | item *do_item_touch(const char *key, const size_t nkey, uint32_t exptime, const uint32_t hv); 26 | void item_stats_reset(void); 27 | extern pthread_mutex_t cache_lock; 28 | void item_stats_evictions(uint64_t *evicted); 29 | -------------------------------------------------------------------------------- /memcached-1.4.15/m4/c99-backport.m4: -------------------------------------------------------------------------------- 1 | # AC_PROG_CC_C99 ([ACTION-IF-AVAILABLE], [ACTION-IF-UNAVAILABLE]) 2 | # ---------------------------------------------------------------- 3 | # If the C compiler is not in ISO C99 mode by default, try to add an 4 | # option to output variable CC to make it so. This macro tries 5 | # various options that select ISO C99 on some system or another. It 6 | # considers the compiler to be in ISO C99 mode if it handles _Bool, 7 | # // comments, flexible array members, inline, long long int, mixed 8 | # code and declarations, named initialization of structs, restrict, 9 | # va_copy, varargs macros, variable declarations in for loops and 10 | # variable length arrays. 11 | AC_DEFUN([AC_PROG_CC_C99], 12 | [AC_C_STD_TRY([c99], 13 | [[#include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | // Check varargs macros. These examples are taken from C99 6.10.3.5. 20 | #define debug(...) fprintf (stderr, __VA_ARGS__) 21 | #define showlist(...) puts (#__VA_ARGS__) 22 | #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) 23 | static void 24 | test_varargs_macros (void) 25 | { 26 | int x = 1234; 27 | int y = 5678; 28 | debug ("Flag"); 29 | debug ("X = %d\n", x); 30 | showlist (The first, second, and third items.); 31 | report (x>y, "x is %d but y is %d", x, y); 32 | } 33 | 34 | // Check long long types. 35 | #define BIG64 18446744073709551615ull 36 | #define BIG32 4294967295ul 37 | #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) 38 | #if !BIG_OK 39 | your preprocessor is broken; 40 | #endif 41 | #if BIG_OK 42 | #else 43 | your preprocessor is broken; 44 | #endif 45 | static long long int bignum = -9223372036854775807LL; 46 | static unsigned long long int ubignum = BIG64; 47 | 48 | struct incomplete_array 49 | { 50 | int datasize; 51 | double data[]; 52 | }; 53 | 54 | struct named_init { 55 | int number; 56 | const wchar_t *name; 57 | double average; 58 | }; 59 | 60 | typedef const char *ccp; 61 | 62 | static inline int 63 | test_restrict (ccp restrict text) 64 | { 65 | // See if C++-style comments work. 66 | // Iterate through items via the restricted pointer. 67 | // Also check for declarations in for loops. 68 | for (unsigned int i = 0; *(text+i) != '\0'; ++i) 69 | continue; 70 | return 0; 71 | } 72 | 73 | // Check varargs and va_copy. 74 | static void 75 | test_varargs (const char *format, ...) 76 | { 77 | va_list args; 78 | va_start (args, format); 79 | va_list args_copy; 80 | va_copy (args_copy, args); 81 | 82 | const char *str; 83 | int number; 84 | float fnumber; 85 | 86 | while (*format) 87 | { 88 | switch (*format++) 89 | { 90 | case 's': // string 91 | str = va_arg (args_copy, const char *); 92 | break; 93 | case 'd': // int 94 | number = va_arg (args_copy, int); 95 | break; 96 | case 'f': // float 97 | fnumber = va_arg (args_copy, double); 98 | break; 99 | default: 100 | break; 101 | } 102 | } 103 | va_end (args_copy); 104 | va_end (args); 105 | } 106 | ]], 107 | [[ 108 | // Check bool. 109 | _Bool success = false; 110 | 111 | // Check restrict. 112 | if (test_restrict ("String literal") == 0) 113 | success = true; 114 | char *restrict newvar = "Another string"; 115 | 116 | // Check varargs. 117 | test_varargs ("s, d' f .", "string", 65, 34.234); 118 | test_varargs_macros (); 119 | 120 | // Check flexible array members. 121 | struct incomplete_array *ia = 122 | malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); 123 | ia->datasize = 10; 124 | for (int i = 0; i < ia->datasize; ++i) 125 | ia->data[i] = i * 1.234; 126 | 127 | // Check named initializers. 128 | struct named_init ni = { 129 | .number = 34, 130 | .name = L"Test wide string", 131 | .average = 543.34343, 132 | }; 133 | 134 | ni.number = 58; 135 | 136 | int dynamic_array[ni.number]; 137 | dynamic_array[ni.number - 1] = 543; 138 | 139 | // work around unused variable warnings 140 | return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x' 141 | || dynamic_array[ni.number - 1] != 543); 142 | ]], 143 | dnl Try 144 | dnl GCC -std=gnu99 (unused restrictive modes: -std=c99 -std=iso9899:1999) 145 | dnl AIX -qlanglvl=extc99 (unused restrictive mode: -qlanglvl=stdc99) 146 | dnl Intel ICC -c99 147 | dnl IRIX -c99 148 | dnl Solaris (unused because it causes the compiler to assume C99 semantics for 149 | dnl library functions, and this is invalid before Solaris 10: -xc99) 150 | dnl Tru64 -c99 151 | dnl with extended modes being tried first. 152 | [[-std=gnu99 -c99 -qlanglvl=extc99]], [$1], [$2])[]dnl 153 | ])# AC_PROG_CC_C99 154 | 155 | # AC_C_STD_TRY(STANDARD, TEST-PROLOGUE, TEST-BODY, OPTION-LIST, 156 | # ACTION-IF-AVAILABLE, ACTION-IF-UNAVAILABLE) 157 | # -------------------------------------------------------------- 158 | # Check whether the C compiler accepts features of STANDARD (e.g `c89', `c99') 159 | # by trying to compile a program of TEST-PROLOGUE and TEST-BODY. If this fails, 160 | # try again with each compiler option in the space-separated OPTION-LIST; if one 161 | # helps, append it to CC. If eventually successful, run ACTION-IF-AVAILABLE, 162 | # else ACTION-IF-UNAVAILABLE. 163 | AC_DEFUN([AC_C_STD_TRY], 164 | [AC_MSG_CHECKING([for $CC option to accept ISO ]m4_translit($1, [c], [C])) 165 | AC_CACHE_VAL(ac_cv_prog_cc_$1, 166 | [ac_cv_prog_cc_$1=no 167 | ac_save_CC=$CC 168 | AC_LANG_CONFTEST([AC_LANG_PROGRAM([$2], [$3])]) 169 | for ac_arg in '' $4 170 | do 171 | CC="$ac_save_CC $ac_arg" 172 | _AC_COMPILE_IFELSE([], [ac_cv_prog_cc_$1=$ac_arg]) 173 | test "x$ac_cv_prog_cc_$1" != "xno" && break 174 | done 175 | rm -f conftest.$ac_ext 176 | CC=$ac_save_CC 177 | ])# AC_CACHE_VAL 178 | case "x$ac_cv_prog_cc_$1" in 179 | x) 180 | AC_MSG_RESULT([none needed]) ;; 181 | xno) 182 | AC_MSG_RESULT([unsupported]) ;; 183 | *) 184 | CC="$CC $ac_cv_prog_cc_$1" 185 | AC_MSG_RESULT([$ac_cv_prog_cc_$1]) ;; 186 | esac 187 | AS_IF([test "x$ac_cv_prog_cc_$1" != xno], [$5], [$6]) 188 | ])# AC_C_STD_TRY 189 | -------------------------------------------------------------------------------- /memcached-1.4.15/memcached.spec: -------------------------------------------------------------------------------- 1 | Name: memcached 2 | Version: 1.4.15 3 | Release: 1%{?dist} 4 | Summary: High Performance, Distributed Memory Object Cache 5 | 6 | Group: System Environment/Daemons 7 | License: BSD 8 | URL: http://www.danga.com/memcached/ 9 | Source0: http://memcached.googlecode.com/files/%{name}-1.4.15.tar.gz 10 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) 11 | 12 | BuildRequires: libevent-devel 13 | BuildRequires: perl(Test::More) 14 | BuildRequires: /usr/bin/prove 15 | Requires: initscripts 16 | Requires(post): /sbin/chkconfig 17 | Requires(preun): /sbin/chkconfig, /sbin/service 18 | Requires(postun): /sbin/service 19 | 20 | %description 21 | memcached is a high-performance, distributed memory object caching 22 | system, generic in nature, but intended for use in speeding up dynamic 23 | web applications by alleviating database load. 24 | 25 | %prep 26 | %setup -q -n %{name}-1.4.15 27 | 28 | 29 | %build 30 | %configure 31 | 32 | make %{?_smp_mflags} 33 | 34 | %check 35 | make test 36 | 37 | %install 38 | rm -rf %{buildroot} 39 | make install DESTDIR=%{buildroot} 40 | 41 | # remove memcached-debug 42 | rm -f %{buildroot}/%{_bindir}/memcached-debug 43 | 44 | # Perl script for monitoring memcached 45 | install -Dp -m0755 scripts/memcached-tool %{buildroot}%{_bindir}/memcached-tool 46 | 47 | # Init script 48 | install -Dp -m0755 scripts/memcached.sysv %{buildroot}%{_initrddir}/memcached 49 | 50 | # Default configs 51 | mkdir -p %{buildroot}/%{_sysconfdir}/sysconfig 52 | cat <%{buildroot}/%{_sysconfdir}/sysconfig/%{name} 53 | PORT="11211" 54 | USER="nobody" 55 | MAXCONN="1024" 56 | CACHESIZE="64" 57 | OPTIONS="" 58 | EOF 59 | 60 | # pid directory 61 | mkdir -p %{buildroot}/%{_localstatedir}/run/memcached 62 | 63 | %clean 64 | rm -rf %{buildroot} 65 | 66 | 67 | %post 68 | /sbin/chkconfig --add %{name} 69 | 70 | %preun 71 | if [ "$1" = 0 ] ; then 72 | /sbin/service %{name} stop > /dev/null 2>&1 73 | /sbin/chkconfig --del %{name} 74 | fi 75 | exit 0 76 | 77 | %postun 78 | if [ "$1" -ge 1 ]; then 79 | /sbin/service %{name} condrestart > /dev/null 2>&1 80 | fi 81 | exit 0 82 | 83 | 84 | %files 85 | %defattr(-,root,root,-) 86 | %doc AUTHORS ChangeLog COPYING NEWS README.md doc/CONTRIBUTORS doc/*.txt 87 | %config(noreplace) %{_sysconfdir}/sysconfig/%{name} 88 | 89 | %dir %attr(750,nobody,nobody) %{_localstatedir}/run/memcached 90 | %{_bindir}/memcached-tool 91 | %{_bindir}/memcached 92 | %{_mandir}/man1/memcached.1* 93 | %{_initrddir}/memcached 94 | %{_includedir}/memcached 95 | 96 | %changelog 97 | * Mon Nov 2 2009 Dormando - 1.4.3-1 98 | - Fix autogen more. 99 | 100 | * Sat Aug 29 2009 Dustin Sallings - 1.4.1-1 101 | - Autogenerate the version number from tags. 102 | 103 | * Wed Jul 4 2007 Paul Lindner - 1.2.2-5 104 | - Use /var/run/memcached/ directory to hold PID file 105 | 106 | * Sat May 12 2007 Paul Lindner - 1.2.2-4 107 | - Remove tabs from spec file, rpmlint reports no more errors 108 | 109 | * Thu May 10 2007 Paul Lindner - 1.2.2-3 110 | - Enable build-time regression tests 111 | - add dependency on initscripts 112 | - remove memcached-debug (not needed in dist) 113 | - above suggestions from Bernard Johnson 114 | 115 | * Mon May 7 2007 Paul Lindner - 1.2.2-2 116 | - Tidyness improvements suggested by Ruben Kerkhof in bugzilla #238994 117 | 118 | * Fri May 4 2007 Paul Lindner - 1.2.2-1 119 | - Initial spec file created via rpmdev-newspec 120 | -------------------------------------------------------------------------------- /memcached-1.4.15/sasl_defs.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 | #include "memcached.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | char my_sasl_hostname[1025]; 9 | 10 | #ifdef HAVE_SASL_CB_GETCONF 11 | /* The locations we may search for a SASL config file if the user didn't 12 | * specify one in the environment variable SASL_CONF_PATH 13 | */ 14 | const char * const locations[] = { 15 | "/etc/sasl/memcached.conf", 16 | "/etc/sasl2/memcached.conf", 17 | NULL 18 | }; 19 | #endif 20 | 21 | #ifndef HAVE_SASL_CALLBACK_FT 22 | typedef int (*sasl_callback_ft)(void); 23 | #endif 24 | 25 | #ifdef ENABLE_SASL_PWDB 26 | #define MAX_ENTRY_LEN 256 27 | 28 | static const char *memcached_sasl_pwdb; 29 | 30 | static int sasl_server_userdb_checkpass(sasl_conn_t *conn, 31 | void *context, 32 | const char *user, 33 | const char *pass, 34 | unsigned passlen, 35 | struct propctx *propctx) 36 | { 37 | size_t unmlen = strlen(user); 38 | if ((passlen + unmlen) > (MAX_ENTRY_LEN - 4)) { 39 | fprintf(stderr, 40 | "WARNING: Failed to authenticate <%s> due to too long password (%d)\n", 41 | user, passlen); 42 | return SASL_NOAUTHZ; 43 | } 44 | 45 | FILE *pwfile = fopen(memcached_sasl_pwdb, "r"); 46 | if (pwfile == NULL) { 47 | if (settings.verbose) { 48 | vperror("WARNING: Failed to open sasl database <%s>", 49 | memcached_sasl_pwdb); 50 | } 51 | return SASL_NOAUTHZ; 52 | } 53 | 54 | char buffer[MAX_ENTRY_LEN]; 55 | bool ok = false; 56 | 57 | while ((fgets(buffer, sizeof(buffer), pwfile)) != NULL) { 58 | if (memcmp(user, buffer, unmlen) == 0 && buffer[unmlen] == ':') { 59 | /* This is the correct user */ 60 | ++unmlen; 61 | if (memcmp(pass, buffer + unmlen, passlen) == 0 && 62 | (buffer[unmlen + passlen] == ':' || /* Additional tokens */ 63 | buffer[unmlen + passlen] == '\n' || /* end of line */ 64 | buffer[unmlen + passlen] == '\r'|| /* dos format? */ 65 | buffer[unmlen + passlen] == '\0')) { /* line truncated */ 66 | ok = true; 67 | } 68 | 69 | break; 70 | } 71 | } 72 | (void)fclose(pwfile); 73 | if (ok) { 74 | return SASL_OK; 75 | } 76 | 77 | if (settings.verbose) { 78 | fprintf(stderr, "INFO: User <%s> failed to authenticate\n", user); 79 | } 80 | 81 | return SASL_NOAUTHZ; 82 | } 83 | #endif 84 | 85 | #ifdef HAVE_SASL_CB_GETCONF 86 | static int sasl_getconf(void *context, const char **path) 87 | { 88 | *path = getenv("SASL_CONF_PATH"); 89 | 90 | if (*path == NULL) { 91 | for (int i = 0; locations[i] != NULL; ++i) { 92 | if (access(locations[i], F_OK) == 0) { 93 | *path = locations[i]; 94 | break; 95 | } 96 | } 97 | } 98 | 99 | if (settings.verbose) { 100 | if (*path != NULL) { 101 | fprintf(stderr, "Reading configuration from: <%s>\n", *path); 102 | } else { 103 | fprintf(stderr, "Failed to locate a config path\n"); 104 | } 105 | 106 | } 107 | 108 | return (*path != NULL) ? SASL_OK : SASL_FAIL; 109 | } 110 | #endif 111 | 112 | static int sasl_log(void *context, int level, const char *message) 113 | { 114 | bool log = true; 115 | 116 | switch (level) { 117 | case SASL_LOG_NONE: 118 | log = false; 119 | break; 120 | case SASL_LOG_PASS: 121 | case SASL_LOG_TRACE: 122 | case SASL_LOG_DEBUG: 123 | case SASL_LOG_NOTE: 124 | if (settings.verbose < 2) { 125 | log = false; 126 | } 127 | break; 128 | case SASL_LOG_WARN: 129 | case SASL_LOG_FAIL: 130 | if (settings.verbose < 1) { 131 | log = false; 132 | } 133 | break; 134 | default: 135 | /* This is an error */ 136 | ; 137 | } 138 | 139 | if (log) { 140 | fprintf(stderr, "SASL (severity %d): %s\n", level, message); 141 | } 142 | 143 | return SASL_OK; 144 | } 145 | 146 | static sasl_callback_t sasl_callbacks[] = { 147 | #ifdef ENABLE_SASL_PWDB 148 | { SASL_CB_SERVER_USERDB_CHECKPASS, sasl_server_userdb_checkpass, NULL }, 149 | #endif 150 | 151 | { SASL_CB_LOG, (sasl_callback_ft)sasl_log, NULL }, 152 | 153 | #ifdef HAVE_SASL_CB_GETCONF 154 | { SASL_CB_GETCONF, sasl_getconf, NULL }, 155 | #endif 156 | 157 | { SASL_CB_LIST_END, NULL, NULL } 158 | }; 159 | 160 | void init_sasl(void) { 161 | #ifdef ENABLE_SASL_PWDB 162 | memcached_sasl_pwdb = getenv("MEMCACHED_SASL_PWDB"); 163 | if (memcached_sasl_pwdb == NULL) { 164 | if (settings.verbose) { 165 | fprintf(stderr, 166 | "INFO: MEMCACHED_SASL_PWDB not specified. " 167 | "Internal passwd database disabled\n"); 168 | } 169 | sasl_callbacks[0].id = SASL_CB_LIST_END; 170 | sasl_callbacks[0].proc = NULL; 171 | } 172 | #endif 173 | 174 | memset(my_sasl_hostname, 0, sizeof(my_sasl_hostname)); 175 | if (gethostname(my_sasl_hostname, sizeof(my_sasl_hostname)-1) == -1) { 176 | if (settings.verbose) { 177 | fprintf(stderr, "Error discovering hostname for SASL\n"); 178 | } 179 | my_sasl_hostname[0] = '\0'; 180 | } 181 | 182 | if (sasl_server_init(sasl_callbacks, "memcached") != SASL_OK) { 183 | fprintf(stderr, "Error initializing sasl.\n"); 184 | exit(EXIT_FAILURE); 185 | } else { 186 | if (settings.verbose) { 187 | fprintf(stderr, "Initialized SASL.\n"); 188 | } 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /memcached-1.4.15/sasl_defs.h: -------------------------------------------------------------------------------- 1 | #ifndef SASL_DEFS_H 2 | #define SASL_DEFS_H 1 3 | 4 | // Longest one I could find was ``9798-U-RSA-SHA1-ENC'' 5 | #define MAX_SASL_MECH_LEN 32 6 | 7 | #if defined(HAVE_SASL_SASL_H) && defined(ENABLE_SASL) 8 | 9 | #include 10 | void init_sasl(void); 11 | 12 | extern char my_sasl_hostname[1025]; 13 | 14 | #else /* End of SASL support */ 15 | 16 | typedef void* sasl_conn_t; 17 | 18 | #define init_sasl() {} 19 | #define sasl_dispose(x) {} 20 | #define sasl_server_new(a, b, c, d, e, f, g, h) 1 21 | #define sasl_listmech(a, b, c, d, e, f, g, h) 1 22 | #define sasl_server_start(a, b, c, d, e, f) 1 23 | #define sasl_server_step(a, b, c, d, e) 1 24 | #define sasl_getprop(a, b, c) {} 25 | 26 | #define SASL_OK 0 27 | #define SASL_CONTINUE -1 28 | 29 | #endif /* sasl compat */ 30 | 31 | #endif /* SASL_DEFS_H */ 32 | -------------------------------------------------------------------------------- /memcached-1.4.15/scripts/README.damemtop: -------------------------------------------------------------------------------- 1 | dormando's awesome memcached top 2 | 3 | A flexible 'top' like utility for viewing memcached clusters. 4 | 5 | Under development. Latest code is available at: 6 | http://github.com/dormando/damemtop 7 | 8 | See --help for full information. 9 | 10 | Requires 'AnyEvent', and 'YAML' libraries from CPAN: 11 | http://search.cpan.org/ 12 | 13 | 'AnyEvent' depends on 'common::sense' (also at CPAN). 14 | 15 | If you have a large cluster and want higher performance, find 16 | and install 'EV' from CPAN. AnyEvent will automagically use it 17 | and use epoll, kqeueue, etc, for socket handling. 18 | 19 | Pester me for questions/bugs/ideas. As of writing the util is 20 | in early release and missing many future features. 21 | -------------------------------------------------------------------------------- /memcached-1.4.15/scripts/damemtop.yaml: -------------------------------------------------------------------------------- 1 | delay: 3 2 | mode: t 3 | top_mode: 4 | sort_column: "hostname" 5 | sort_order: "asc" 6 | columns: 7 | - hostname 8 | - all_version 9 | - all_fill_rate 10 | - hit_rate 11 | - evictions 12 | - bytes_written 13 | - "2:get_hits" 14 | servers: 15 | - 127.0.0.1:11211 16 | - 127.0.0.2:11211 17 | -------------------------------------------------------------------------------- /memcached-1.4.15/scripts/mc_slab_mover: -------------------------------------------------------------------------------- 1 | #! /usr/bin/perl 2 | # See memcached for LICENSE 3 | # Copyright 2011 Dormando (dormando@rydia.net) 4 | 5 | =head1 NAME 6 | 7 | mc_slab_mover -- example utility for slab page reassignment for memcached 8 | 9 | =head1 SYNOPSIS 10 | 11 | $ mc_slab_mover --host="127.0.0.1:11211" --verbose 12 | $ mc_slab_mover --host="127.0.0.1:11211" --automove 13 | $ mc_slab_mover --host="127.0.0.1:11211" --sleep=60 --loops=4 --automove 14 | 15 | =head1 DESCRIPTION 16 | 17 | This utility is an example implementation of an algorithm for reassigning 18 | slab memory in a running memcached instance. If memcached's built-in 19 | automover isn't working for you, you may use this script as an example 20 | base and expand on it. We welcome modifications or alternatives on the 21 | mailing list. 22 | 23 | =head1 ALGORITHM 24 | 25 | The default algorithm is simple, and may serve for a common case: over 26 | time one slab may grow in use compare to others, and as evictions stop 27 | in one slab and start in another it will reassign memory. 28 | 29 | If a slab has the most evictions three times in a row, it will pull a page 30 | from a slab which has had zero evictions three times in a row. 31 | 32 | There are many traffic patterns where this does not work well. IE: If you 33 | never use expirations and rely on the LRU (so all slabs always evict), 34 | it will not be as likely to find source pages to move. 35 | 36 | =head1 OPTIONS 37 | 38 | =over 39 | 40 | =item --host="IP:PORT" 41 | 42 | The hostname to connect to. NOTE: If connection to the host breaks, script 43 | will stop. 44 | 45 | =item --sleep=10 46 | 47 | How long to wait between loops for gathering stats. 48 | 49 | =item --loops=3 50 | 51 | How many loops to run before making a decision for a move. 52 | 53 | =item --verbose 54 | 55 | Prints a formatted dump of some common statistics per loop. 56 | 57 | =item --automove 58 | 59 | Enables the automover, and will attempt to move memory around if it finds 60 | viable candidates. 61 | 62 | =back 63 | 64 | =head1 AUTHOR 65 | 66 | Dormando ELE 67 | 68 | =head1 LICENSE 69 | 70 | Licensed for use and redistribution under the same terms as Memcached itself. 71 | 72 | =cut 73 | 74 | use warnings; 75 | use strict; 76 | 77 | use IO::Socket::INET; 78 | 79 | use FindBin; 80 | use Data::Dumper qw/Dumper/; 81 | use Getopt::Long; 82 | 83 | my %opts = ('sleep' => 10, automove => 0, verbose => 0, loops => 3); 84 | GetOptions( 85 | "host=s" => \$opts{host}, 86 | "sleep=i" => \$opts{'sleep'}, 87 | "loops=i" => \$opts{loops}, 88 | "automove" => \$opts{automove}, 89 | "verbose" => \$opts{verbose}, 90 | ) or usage(); 91 | 92 | die "Must specify at least --host='127.0.0.1:11211'" unless $opts{host}; 93 | my $sock = IO::Socket::INET->new(PeerAddr => $opts{host}, 94 | Timeout => 3); 95 | die "$!\n" unless $sock; 96 | 97 | my %stats = (); 98 | my %move = (winner => 0, wins => 0); 99 | 100 | $SIG{INT} = sub { 101 | print "STATS: ", Dumper(\%stats), "\n"; 102 | exit; 103 | }; 104 | $SIG{USR1} = sub { 105 | print "STATS: ", Dumper(\%stats), "\n"; 106 | }; 107 | run(); 108 | 109 | sub usage { 110 | print qq{Usage: 111 | mc_slab_ratios --host="127.0.0.1:11211" --verbose --automove 112 | run `perldoc mc_slab_ratios` for full information 113 | 114 | }; 115 | exit 1; 116 | } 117 | 118 | sub run { 119 | my $slabs_before = grab_stats(); 120 | 121 | while (1) { 122 | sleep $opts{'sleep'}; 123 | my $slabs_after = grab_stats(); 124 | 125 | my ($totals, $sorted) = calc_results_evicted($slabs_before, $slabs_after); 126 | # my ($totals, $sorted) = calc_results_numratio($slabs_before, $slabs_after); 127 | 128 | my $pct = sub { 129 | my ($num, $divisor) = @_; 130 | return 0 unless $divisor; 131 | return ($num / $divisor); 132 | }; 133 | if ($opts{verbose}) { 134 | printf " %02s: %-8s (pct ) %-10s (pct ) %-6s (pct ) get_hits (pct ) cmd_set (pct )\n", 135 | 'sb', 'evicted', 'items', 'pages'; 136 | for my $slab (@$sorted) { 137 | printf " %02d: %-8d (%.2f%%) %-10s (%.4f%%) %-6d (%.2f%%) %-8d (%.3f%%) %-7d (%.2f%%)\n", 138 | $slab->{slab}, $slab->{evicted_d}, 139 | $pct->($slab->{evicted_d}, $totals->{evicted_d}), 140 | $slab->{number}, 141 | $pct->($slab->{number}, $totals->{number}), 142 | $slab->{total_pages}, 143 | $pct->($slab->{total_pages}, $totals->{total_pages}), 144 | $slab->{get_hits_d}, 145 | $pct->($slab->{get_hits_d}, $totals->{get_hits_d}), 146 | $slab->{cmd_set_d}, 147 | $pct->($slab->{cmd_set_d}, $totals->{cmd_set_d}); 148 | } 149 | } 150 | 151 | next unless @$sorted; 152 | my $highest = $sorted->[-1]; 153 | $stats{$highest->{slab}}++; 154 | print " (winner: ", $highest->{slab}, " wins: ", $stats{$highest->{slab}}, ")\n"; 155 | automove_basic($totals, $sorted) if ($opts{automove}); 156 | 157 | $slabs_before = $slabs_after; 158 | } 159 | } 160 | 161 | sub grab_stats { 162 | my %slabs = (); 163 | for my $stat (qw/items slabs/) { 164 | print $sock "stats $stat\r\n"; 165 | while (my $line = <$sock>) { 166 | chomp $line; 167 | last if ($line =~ m/^END/); 168 | if ($line =~ m/^STAT (?:items:)?(\d+):(\S+) (\S+)/) { 169 | my ($slab, $var, $val) = ($1, $2, $3); 170 | $slabs{$slab}->{$var} = $val; 171 | } 172 | } 173 | } 174 | 175 | return \%slabs; 176 | } 177 | 178 | # Really stupid algo, same as the initial algo built into memcached. 179 | # If a slab "wins" most evictions 3 times in a row, pick from a slab which 180 | # has had 0 evictions 3 times in a row and move it over. 181 | sub automove_basic { 182 | my ($totals, $sorted) = @_; 183 | 184 | my $source = 0; 185 | my $dest = 0; 186 | my $high = $sorted->[-1]; 187 | return unless $high->{evicted_d} > 0; 188 | if ($move{winner} == $high->{slab}) { 189 | $move{wins}++; 190 | $dest = $move{winner} if $move{wins} >= $opts{loops}; 191 | } else { 192 | $move{wins} = 1; 193 | $move{winner} = $high->{slab}; 194 | } 195 | for my $slab (@$sorted) { 196 | my $id = $slab->{slab}; 197 | if ($slab->{evicted_d} == 0 && $slab->{total_pages} > 2) { 198 | $move{zeroes}->{$id}++; 199 | $source = $id if (!$source && $move{zeroes}->{$id} >= $opts{loops}); 200 | } else { 201 | delete $move{zeroes}->{$slab->{slab}} 202 | if exists $move{zeroes}->{$slab->{slab}}; 203 | } 204 | } 205 | 206 | if ($source && $dest) { 207 | print " slabs reassign $source $dest\n"; 208 | print $sock "slabs reassign $source $dest\r\n"; 209 | my $res = <$sock>; 210 | print " RES: ", $res; 211 | } elsif ($dest && !$source) { 212 | print "FAIL: want to move memory to $dest but no valid source slab available\n"; 213 | } 214 | } 215 | 216 | # Using just the evicted stats. 217 | sub calc_results_evicted { 218 | my ($slabs, $totals) = calc_slabs(@_); 219 | my @sorted = sort { $a->{evicted_d} <=> $b->{evicted_d} } values %$slabs; 220 | return ($totals, \@sorted); 221 | } 222 | 223 | # Weighted ratios of evictions vs total stored items 224 | # Seems to fail as an experiment, but it tries to weight stats. 225 | # In this case evictions in underused classes tend to get vastly inflated 226 | sub calc_results_numratio { 227 | my ($slabs, $totals) = calc_slabs(@_, sub { 228 | my ($sb, $sa, $s) = @_; 229 | if ($s->{evicted_d}) { 230 | $s->{numratio} = $s->{evicted_d} / $s->{number}; 231 | } else { $s->{numratio} = 0; } 232 | }); 233 | my @sorted = sort { $a->{numratio} <=> $b->{numratio} } values %$slabs; 234 | return ($totals, \@sorted); 235 | } 236 | 237 | sub calc_slabs { 238 | my ($slabs_before, $slabs_after, $code) = @_; 239 | my %slabs = (); 240 | my %totals = (); 241 | for my $id (keys %$slabs_after) { 242 | my $sb = $slabs_before->{$id}; 243 | my $sa = $slabs_after->{$id}; 244 | next unless ($sb && $sa); 245 | my %slab = %$sa; 246 | for my $key (keys %slab) { 247 | # Add totals, diffs 248 | if ($slab{$key} =~ m/^\d+$/) { 249 | $totals{$key} += $slab{$key}; 250 | $slab{$key . '_d'} = $sa->{$key} - $sb->{$key}; 251 | $totals{$key . '_d'} += $sa->{$key} - $sb->{$key}; 252 | } 253 | } 254 | # External code 255 | $code->($sb, $sa, \%slab) if $code; 256 | $slab{slab} = $id; 257 | $slabs{$id} = \%slab; 258 | } 259 | return (\%slabs, \%totals); 260 | } 261 | -------------------------------------------------------------------------------- /memcached-1.4.15/scripts/memcached-init: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | ### BEGIN INIT INFO 3 | # Provides: memcached 4 | # Required-Start: $syslog 5 | # Required-Stop: $syslog 6 | # Should-Start: $local_fs 7 | # Should-Stop: $local_fs 8 | # Default-Start: 2 3 4 5 9 | # Default-Stop: 0 1 6 10 | # Short-Description: memcached - Memory caching daemon 11 | # Description: memcached - Memory caching daemon 12 | ### END INIT INFO 13 | 14 | # Usage: 15 | # cp /etc/memcached.conf /etc/memcached_server1.conf 16 | # cp /etc/memcached.conf /etc/memcached_server2.conf 17 | # start all instances: 18 | # /etc/init.d/memcached start 19 | # start one instance: 20 | # /etc/init.d/memcached start server1 21 | # stop all instances: 22 | # /etc/init.d/memcached stop 23 | # stop one instance: 24 | # /etc/init.d/memcached stop server1 25 | # There is no "status" command. 26 | 27 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 28 | DAEMON=/usr/bin/memcached 29 | DAEMONNAME=memcached 30 | DAEMONBOOTSTRAP=/usr/share/memcached/scripts/start-memcached 31 | DESC=memcached 32 | 33 | test -x $DAEMON || exit 0 34 | test -x $DAEMONBOOTSTRAP || exit 0 35 | 36 | set -e 37 | 38 | FILES=(/etc/memcached_*.conf) 39 | # check for alternative config schema 40 | if [ -r "${FILES[0]}" ]; then 41 | CONFIGS=() 42 | for FILE in "${FILES[@]}"; 43 | do 44 | # remove prefix 45 | NAME=${FILE#/etc/} 46 | # remove suffix 47 | NAME=${NAME%.conf} 48 | 49 | # check optional second param 50 | if [ $# -ne 2 ]; 51 | then 52 | # add to config array 53 | CONFIGS+=($NAME) 54 | elif [ "memcached_$2" == "$NAME" ]; 55 | then 56 | # use only one memcached 57 | CONFIGS=($NAME) 58 | break; 59 | fi; 60 | done; 61 | 62 | if [ ${#CONFIGS[@]} == 0 ]; 63 | then 64 | echo "Config not exist for: $2" >&2 65 | exit 1 66 | fi; 67 | else 68 | CONFIGS=(memcached) 69 | fi; 70 | 71 | CONFIG_NUM=${#CONFIGS[@]} 72 | for ((i=0; i < $CONFIG_NUM; i++)); do 73 | NAME=${CONFIGS[${i}]} 74 | PIDFILE="/var/run/${NAME}.pid" 75 | 76 | case "$1" in 77 | start) 78 | echo -n "Starting $DESC: " 79 | start-stop-daemon --start --quiet --exec "$DAEMONBOOTSTRAP" -- /etc/${NAME}.conf $PIDFILE 80 | echo "$NAME." 81 | ;; 82 | stop) 83 | echo -n "Stopping $DESC: " 84 | start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE --exec $DAEMON 85 | echo "$NAME." 86 | rm -f $PIDFILE 87 | ;; 88 | 89 | restart|force-reload) 90 | # 91 | # If the "reload" option is implemented, move the "force-reload" 92 | # option to the "reload" entry above. If not, "force-reload" is 93 | # just the same as "restart". 94 | # 95 | echo -n "Restarting $DESC: " 96 | start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE 97 | rm -f $PIDFILE 98 | sleep 1 99 | start-stop-daemon --start --quiet --exec "$DAEMONBOOTSTRAP" -- /etc/${NAME}.conf $PIDFILE 100 | echo "$NAME." 101 | ;; 102 | *) 103 | N=/etc/init.d/$NAME 104 | # echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 105 | echo "Usage: $N {start|stop|restart|force-reload}" >&2 106 | exit 1 107 | ;; 108 | esac 109 | done; 110 | 111 | exit 0 112 | -------------------------------------------------------------------------------- /memcached-1.4.15/scripts/memcached-tool: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # 3 | # memcached-tool: 4 | # stats/management tool for memcached. 5 | # 6 | # Author: 7 | # Brad Fitzpatrick 8 | # 9 | # License: 10 | # public domain. I give up all rights to this 11 | # tool. modify and copy at will. 12 | # 13 | 14 | use strict; 15 | use IO::Socket::INET; 16 | 17 | my $addr = shift; 18 | my $mode = shift || "display"; 19 | my ($from, $to); 20 | 21 | if ($mode eq "display") { 22 | undef $mode if @ARGV; 23 | } elsif ($mode eq "move") { 24 | $from = shift; 25 | $to = shift; 26 | undef $mode if $from < 6 || $from > 17; 27 | undef $mode if $to < 6 || $to > 17; 28 | print STDERR "ERROR: parameters out of range\n\n" unless $mode; 29 | } elsif ($mode eq 'dump') { 30 | ; 31 | } elsif ($mode eq 'stats') { 32 | ; 33 | } else { 34 | undef $mode; 35 | } 36 | 37 | undef $mode if @ARGV; 38 | 39 | die 40 | "Usage: memcached-tool [mode]\n 41 | memcached-tool 10.0.0.5:11211 display # shows slabs 42 | memcached-tool 10.0.0.5:11211 # same. (default is display) 43 | memcached-tool 10.0.0.5:11211 stats # shows general stats 44 | memcached-tool 10.0.0.5:11211 dump # dumps keys and values 45 | " unless $addr && $mode; 46 | 47 | 48 | my $sock; 49 | if ($addr =~ m:/:) { 50 | $sock = IO::Socket::UNIX->new( 51 | Peer => $addr, 52 | ); 53 | } 54 | else { 55 | $addr .= ':11211' unless $addr =~ /:\d+$/; 56 | 57 | $sock = IO::Socket::INET->new( 58 | PeerAddr => $addr, 59 | Proto => 'tcp', 60 | ); 61 | } 62 | die "Couldn't connect to $addr\n" unless $sock; 63 | 64 | if ($mode eq 'dump') { 65 | my %items; 66 | my $totalitems; 67 | 68 | print $sock "stats items\r\n"; 69 | 70 | while (<$sock>) { 71 | last if /^END/; 72 | if (/^STAT items:(\d*):number (\d*)/) { 73 | $items{$1} = $2; 74 | $totalitems += $2; 75 | } 76 | } 77 | print STDERR "Dumping memcache contents\n"; 78 | print STDERR " Number of buckets: " . scalar(keys(%items)) . "\n"; 79 | print STDERR " Number of items : $totalitems\n"; 80 | 81 | foreach my $bucket (sort(keys(%items))) { 82 | print STDERR "Dumping bucket $bucket - " . $items{$bucket} . " total items\n"; 83 | print $sock "stats cachedump $bucket $items{$bucket}\r\n"; 84 | my %keyexp; 85 | while (<$sock>) { 86 | last if /^END/; 87 | # return format looks like this 88 | # ITEM foo [6 b; 1176415152 s] 89 | if (/^ITEM (\S+) \[.* (\d+) s\]/) { 90 | $keyexp{$1} = $2; 91 | } 92 | } 93 | 94 | foreach my $k (keys(%keyexp)) { 95 | print $sock "get $k\r\n"; 96 | my $response = <$sock>; 97 | if ($response =~ /VALUE (\S+) (\d+) (\d+)/) { 98 | my $flags = $2; 99 | my $len = $3; 100 | my $val; 101 | read $sock, $val, $len; 102 | print "add $k $flags $keyexp{$k} $len\r\n$val\r\n"; 103 | # get the END 104 | $_ = <$sock>; 105 | $_ = <$sock>; 106 | } 107 | } 108 | } 109 | exit; 110 | } 111 | 112 | if ($mode eq 'stats') { 113 | my %items; 114 | 115 | print $sock "stats\r\n"; 116 | 117 | while (<$sock>) { 118 | last if /^END/; 119 | chomp; 120 | if (/^STAT\s+(\S*)\s+(.*)/) { 121 | $items{$1} = $2; 122 | } 123 | } 124 | printf ("#%-17s %5s %11s\n", $addr, "Field", "Value"); 125 | foreach my $name (sort(keys(%items))) { 126 | printf ("%24s %12s\n", $name, $items{$name}); 127 | 128 | } 129 | exit; 130 | } 131 | 132 | # display mode: 133 | 134 | my %items; # class -> { number, age, chunk_size, chunks_per_page, 135 | # total_pages, total_chunks, used_chunks, 136 | # free_chunks, free_chunks_end } 137 | 138 | print $sock "stats items\r\n"; 139 | my $max = 0; 140 | while (<$sock>) { 141 | last if /^END/; 142 | if (/^STAT items:(\d+):(\w+) (\d+)/) { 143 | $items{$1}{$2} = $3; 144 | $max = $1; 145 | } 146 | } 147 | 148 | print $sock "stats slabs\r\n"; 149 | while (<$sock>) { 150 | last if /^END/; 151 | if (/^STAT (\d+):(\w+) (\d+)/) { 152 | $items{$1}{$2} = $3; 153 | } 154 | } 155 | 156 | print " # Item_Size Max_age Pages Count Full? Evicted Evict_Time OOM\n"; 157 | foreach my $n (1..$max) { 158 | my $it = $items{$n}; 159 | next if (0 == $it->{total_pages}); 160 | my $size = $it->{chunk_size} < 1024 ? 161 | "$it->{chunk_size}B" : 162 | sprintf("%.1fK", $it->{chunk_size} / 1024.0); 163 | my $full = $it->{free_chunks_end} == 0 ? "yes" : " no"; 164 | printf("%3d %8s %9ds %7d %7d %7s %8d %8d %4d\n", 165 | $n, $size, $it->{age}, $it->{total_pages}, 166 | $it->{number}, $full, $it->{evicted}, 167 | $it->{evicted_time}, $it->{outofmemory}); 168 | } 169 | 170 | -------------------------------------------------------------------------------- /memcached-1.4.15/scripts/memcached.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=memcached daemon 3 | After=network.target 4 | 5 | [Service] 6 | EnvironmentFile=/etc/sysconfig/memcached 7 | ExecStart=/usr/bin/memcached -p ${PORT} -u ${USER} -m ${CACHESIZE} -c ${MAXCONN} $OPTIONS 8 | 9 | [Install] 10 | WantedBy=multi-user.target 11 | -------------------------------------------------------------------------------- /memcached-1.4.15/scripts/memcached.sysv: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # 3 | # chkconfig: - 55 45 4 | # description: The memcached daemon is a network memory cache service. 5 | # processname: memcached 6 | # config: /etc/sysconfig/memcached 7 | 8 | # Source function library. 9 | . /etc/rc.d/init.d/functions 10 | 11 | PORT=11211 12 | USER=nobody 13 | MAXCONN=1024 14 | CACHESIZE=64 15 | OPTIONS="" 16 | 17 | if [ -f /etc/sysconfig/memcached ];then 18 | . /etc/sysconfig/memcached 19 | fi 20 | 21 | # Check that networking is up. 22 | if [ "$NETWORKING" = "no" ] 23 | then 24 | exit 0 25 | fi 26 | 27 | RETVAL=0 28 | prog="memcached" 29 | 30 | start () { 31 | echo -n $"Starting $prog: " 32 | # insure that /var/run/memcached has proper permissions 33 | chown $USER /var/run/memcached 34 | daemon memcached -d -p $PORT -u $USER -m $CACHESIZE -c $MAXCONN -P /var/run/memcached/memcached.pid $OPTIONS 35 | RETVAL=$? 36 | echo 37 | [ $RETVAL -eq 0 ] && touch /var/lock/subsys/memcached 38 | } 39 | stop () { 40 | echo -n $"Stopping $prog: " 41 | killproc memcached 42 | RETVAL=$? 43 | echo 44 | if [ $RETVAL -eq 0 ] ; then 45 | rm -f /var/lock/subsys/memcached 46 | rm -f /var/run/memcached.pid 47 | fi 48 | } 49 | 50 | restart () { 51 | stop 52 | start 53 | } 54 | 55 | 56 | # See how we were called. 57 | case "$1" in 58 | start) 59 | start 60 | ;; 61 | stop) 62 | stop 63 | ;; 64 | status) 65 | status memcached 66 | ;; 67 | restart|reload) 68 | restart 69 | ;; 70 | condrestart) 71 | [ -f /var/lock/subsys/memcached ] && restart || : 72 | ;; 73 | *) 74 | echo $"Usage: $0 {start|stop|status|restart|reload|condrestart}" 75 | exit 1 76 | esac 77 | 78 | exit $? 79 | -------------------------------------------------------------------------------- /memcached-1.4.15/scripts/start-memcached: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | # start-memcached 4 | # 2003/2004 - Jay Bonci 5 | # This script handles the parsing of the /etc/memcached.conf file 6 | # and was originally created for the Debian distribution. 7 | # Anyone may use this little script under the same terms as 8 | # memcached itself. 9 | 10 | use POSIX qw(setsid); 11 | use strict; 12 | 13 | if($> != 0 and $< != 0) 14 | { 15 | print STDERR "Only root wants to run start-memcached.\n"; 16 | exit; 17 | } 18 | 19 | my $params; my $etchandle; my $etcfile = "/etc/memcached.conf"; 20 | 21 | # This script assumes that memcached is located at /usr/bin/memcached, and 22 | # that the pidfile is writable at /var/run/memcached.pid 23 | 24 | my $memcached = "/usr/bin/memcached"; 25 | my $pidfile = "/var/run/memcached.pid"; 26 | 27 | if (scalar(@ARGV) == 2) { 28 | $etcfile = shift(@ARGV); 29 | $pidfile = shift(@ARGV); 30 | } 31 | 32 | # If we don't get a valid logfile parameter in the /etc/memcached.conf file, 33 | # we'll just throw away all of our in-daemon output. We need to re-tie it so 34 | # that non-bash shells will not hang on logout. Thanks to Michael Renner for 35 | # the tip 36 | my $fd_reopened = "/dev/null"; 37 | 38 | sub handle_logfile 39 | { 40 | my ($logfile) = @_; 41 | $fd_reopened = $logfile; 42 | } 43 | 44 | sub reopen_logfile 45 | { 46 | my ($logfile) = @_; 47 | 48 | open *STDERR, ">>$logfile"; 49 | open *STDOUT, ">>$logfile"; 50 | open *STDIN, ">>/dev/null"; 51 | $fd_reopened = $logfile; 52 | } 53 | 54 | # This is set up in place here to support other non -[a-z] directives 55 | 56 | my $conf_directives = { 57 | "logfile" => \&handle_logfile, 58 | }; 59 | 60 | if(open $etchandle, $etcfile) 61 | { 62 | foreach my $line (<$etchandle>) 63 | { 64 | $line ||= ""; 65 | $line =~ s/\#.*//g; 66 | $line =~ s/\s+$//g; 67 | $line =~ s/^\s+//g; 68 | next unless $line; 69 | next if $line =~ /^\-[dh]/; 70 | 71 | if($line =~ /^[^\-]/) 72 | { 73 | my ($directive, $arg) = $line =~ /^(.*?)\s+(.*)/; 74 | $conf_directives->{$directive}->($arg); 75 | next; 76 | } 77 | 78 | push @$params, $line; 79 | } 80 | 81 | }else{ 82 | $params = []; 83 | } 84 | 85 | push @$params, "-u root" unless(grep "-u", @$params); 86 | $params = join " ", @$params; 87 | 88 | if(-e $pidfile) 89 | { 90 | open PIDHANDLE, "$pidfile"; 91 | my $localpid = ; 92 | close PIDHANDLE; 93 | 94 | chomp $localpid; 95 | if(-d "/proc/$localpid") 96 | { 97 | print STDERR "memcached is already running.\n"; 98 | exit; 99 | }else{ 100 | `rm -f $localpid`; 101 | } 102 | 103 | } 104 | 105 | my $pid = fork(); 106 | 107 | if($pid == 0) 108 | { 109 | # setsid makes us the session leader 110 | setsid(); 111 | reopen_logfile($fd_reopened); 112 | # must fork again now that tty is closed 113 | $pid = fork(); 114 | if ($pid) { 115 | if(open PIDHANDLE,">$pidfile") 116 | { 117 | print PIDHANDLE $pid; 118 | close PIDHANDLE; 119 | }else{ 120 | 121 | print STDERR "Can't write pidfile to $pidfile.\n"; 122 | } 123 | exit(0); 124 | } 125 | exec "$memcached $params"; 126 | exit(0); 127 | 128 | } 129 | -------------------------------------------------------------------------------- /memcached-1.4.15/sizes.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "memcached.h" 4 | 5 | static void display(const char *name, size_t size) { 6 | printf("%s\t%d\n", name, (int)size); 7 | } 8 | 9 | int main(int argc, char **argv) { 10 | 11 | display("Slab Stats", sizeof(struct slab_stats)); 12 | display("Thread stats", 13 | sizeof(struct thread_stats) 14 | - (200 * sizeof(struct slab_stats))); 15 | display("Global stats", sizeof(struct stats)); 16 | display("Settings", sizeof(struct settings)); 17 | display("Item (no cas)", sizeof(item)); 18 | display("Item (cas)", sizeof(item) + sizeof(uint64_t)); 19 | display("Libevent thread", 20 | sizeof(LIBEVENT_THREAD) - sizeof(struct thread_stats)); 21 | display("Connection", sizeof(conn)); 22 | 23 | printf("----------------------------------------\n"); 24 | 25 | display("libevent thread cumulative", sizeof(LIBEVENT_THREAD)); 26 | display("Thread stats cumulative\t", sizeof(struct thread_stats)); 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /memcached-1.4.15/slabs.h: -------------------------------------------------------------------------------- 1 | /* slabs memory allocation */ 2 | // slab 内存管理 3 | #ifndef SLABS_H 4 | #define SLABS_H 5 | 6 | /** Init the subsystem. 1st argument is the limit on no. of bytes to allocate, 7 | 0 if no limit. 2nd argument is the growth factor; each slab will use a chunk 8 | size equal to the previous slab's chunk size times this factor. 9 | 3rd argument specifies if the slab allocator should allocate all memory 10 | up front (if true), or allocate memory in chunks as it is needed (if false) 11 | */ 12 | void slabs_init(const size_t limit, const double factor, const bool prealloc); 13 | 14 | 15 | /** 16 | * Given object size, return id to use when allocating/freeing memory for object 17 | * 0 means error: can't store such a large object 18 | */ 19 | 20 | unsigned int slabs_clsid(const size_t size); 21 | 22 | /** Allocate object of given length. 0 on error */ /*@null@*/ 23 | void *slabs_alloc(const size_t size, unsigned int id); 24 | 25 | /** Free previously allocated object */ 26 | void slabs_free(void *ptr, size_t size, unsigned int id); 27 | 28 | /** Adjust the stats for memory requested */ 29 | void slabs_adjust_mem_requested(unsigned int id, size_t old, size_t ntotal); 30 | 31 | /** Return a datum for stats in binary protocol */ 32 | bool get_stats(const char *stat_type, int nkey, ADD_STAT add_stats, void *c); 33 | 34 | /** Fill buffer with stats */ /*@null@*/ 35 | void slabs_stats(ADD_STAT add_stats, void *c); 36 | 37 | int start_slab_maintenance_thread(void); 38 | void stop_slab_maintenance_thread(void); 39 | 40 | enum reassign_result_type { 41 | REASSIGN_OK=0, REASSIGN_RUNNING, REASSIGN_BADCLASS, REASSIGN_NOSPARE, 42 | REASSIGN_SRC_DST_SAME 43 | }; 44 | 45 | enum reassign_result_type slabs_reassign(int src, int dst); 46 | 47 | void slabs_rebalancer_pause(void); 48 | void slabs_rebalancer_resume(void); 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /memcached-1.4.15/solaris_priv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "memcached.h" 5 | 6 | /* 7 | * this section of code will drop all (Solaris) privileges including 8 | * those normally granted to all userland process (basic privileges). The 9 | * effect of this is that after running this code, the process will not able 10 | * to fork(), exec(), etc. See privileges(5) for more information. 11 | */ 12 | void drop_privileges(void) { 13 | priv_set_t *privs = priv_str_to_set("basic", ",", NULL); 14 | 15 | if (privs == NULL) { 16 | perror("priv_str_to_set"); 17 | exit(EXIT_FAILURE); 18 | } 19 | 20 | (void)priv_delset(privs, PRIV_FILE_LINK_ANY); 21 | (void)priv_delset(privs, PRIV_PROC_EXEC); 22 | (void)priv_delset(privs, PRIV_PROC_FORK); 23 | (void)priv_delset(privs, PRIV_PROC_INFO); 24 | (void)priv_delset(privs, PRIV_PROC_SESSION); 25 | 26 | if (setppriv(PRIV_SET, PRIV_PERMITTED, privs) != 0) { 27 | perror("setppriv(PRIV_SET, PRIV_PERMITTED)"); 28 | exit(EXIT_FAILURE); 29 | } 30 | 31 | priv_emptyset(privs); 32 | 33 | if (setppriv(PRIV_SET, PRIV_INHERITABLE, privs) != 0) { 34 | perror("setppriv(PRIV_SET, PRIV_INHERITABLE)"); 35 | exit(EXIT_FAILURE); 36 | } 37 | 38 | if (setppriv(PRIV_SET, PRIV_LIMIT, privs) != 0) { 39 | perror("setppriv(PRIV_SET, PRIV_LIMIT)"); 40 | exit(EXIT_FAILURE); 41 | } 42 | 43 | priv_freeset(privs); 44 | } 45 | -------------------------------------------------------------------------------- /memcached-1.4.15/stats.h: -------------------------------------------------------------------------------- 1 | /* stats */ 2 | void stats_prefix_init(void); 3 | void stats_prefix_clear(void); 4 | void stats_prefix_record_get(const char *key, const size_t nkey, const bool is_hit); 5 | void stats_prefix_record_delete(const char *key, const size_t nkey); 6 | void stats_prefix_record_set(const char *key, const size_t nkey); 7 | /*@null@*/ 8 | char *stats_prefix_dump(int *length); 9 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/00-startup.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 18; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | eval { 10 | my $server = new_memcached(); 11 | ok($server, "started the server"); 12 | }; 13 | is($@, '', 'Basic startup works'); 14 | 15 | eval { 16 | my $server = new_memcached("-l fooble"); 17 | }; 18 | ok($@, "Died with illegal -l args"); 19 | 20 | eval { 21 | my $server = new_memcached("-l 127.0.0.1"); 22 | }; 23 | is($@,'', "-l 127.0.0.1 works"); 24 | 25 | eval { 26 | my $server = new_memcached('-C'); 27 | my $stats = mem_stats($server->sock, 'settings'); 28 | is('no', $stats->{'cas_enabled'}); 29 | }; 30 | is($@, '', "-C works"); 31 | 32 | eval { 33 | my $server = new_memcached('-b 8675'); 34 | my $stats = mem_stats($server->sock, 'settings'); 35 | is('8675', $stats->{'tcp_backlog'}); 36 | }; 37 | is($@, '', "-b works"); 38 | 39 | foreach my $val ('auto', 'ascii') { 40 | eval { 41 | my $server = new_memcached("-B $val"); 42 | my $stats = mem_stats($server->sock, 'settings'); 43 | ok($stats->{'binding_protocol'} =~ /$val/, "$val works"); 44 | }; 45 | is($@, '', "$val works"); 46 | } 47 | 48 | # For the binary test, we just verify it starts since we don't have an easy bin client. 49 | eval { 50 | my $server = new_memcached("-B binary"); 51 | }; 52 | is($@, '', "binary works"); 53 | 54 | eval { 55 | my $server = new_memcached("-vv -B auto"); 56 | }; 57 | is($@, '', "auto works"); 58 | 59 | eval { 60 | my $server = new_memcached("-vv -B ascii"); 61 | }; 62 | is($@, '', "ascii works"); 63 | 64 | 65 | # For the binary test, we just verify it starts since we don't have an easy bin client. 66 | eval { 67 | my $server = new_memcached("-vv -B binary"); 68 | }; 69 | is($@, '', "binary works"); 70 | 71 | 72 | # Should blow up with something invalid. 73 | eval { 74 | my $server = new_memcached("-B http"); 75 | }; 76 | ok($@, "Died with illegal -B arg."); 77 | 78 | # Should not allow -t 0 79 | eval { 80 | my $server = new_memcached("-t 0"); 81 | }; 82 | ok($@, "Died with illegal 0 thread count"); 83 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/64bit.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | $ENV{T_MEMD_INITIAL_MALLOC} = "4294967328"; # 2**32 + 32 , just over 4GB 10 | $ENV{T_MEMD_SLABS_ALLOC} = 0; # don't preallocate slabs 11 | 12 | my $server = new_memcached("-m 4098 -M"); 13 | my $sock = $server->sock; 14 | 15 | my ($stats, $slabs) = @_; 16 | 17 | $stats = mem_stats($sock); 18 | 19 | if ($stats->{'pointer_size'} eq "32") { 20 | plan skip_all => 'Skipping 64-bit tests on 32-bit build'; 21 | exit 0; 22 | } else { 23 | plan tests => 6; 24 | } 25 | 26 | is($stats->{'pointer_size'}, 64, "is 64 bit"); 27 | is($stats->{'limit_maxbytes'}, "4297064448", "max bytes is 4098 MB"); 28 | 29 | $slabs = mem_stats($sock, 'slabs'); 30 | is($slabs->{'total_malloced'}, "4294967328", "expected (faked) value of total_malloced"); 31 | is($slabs->{'active_slabs'}, 0, "no active slabs"); 32 | 33 | my $hit_limit = 0; 34 | for (1..5) { 35 | my $size = 400 * 1024; 36 | my $data = "a" x $size; 37 | print $sock "set big$_ 0 0 $size\r\n$data\r\n"; 38 | my $res = <$sock>; 39 | $hit_limit = 1 if $res ne "STORED\r\n"; 40 | } 41 | ok($hit_limit, "hit size limit"); 42 | 43 | $slabs = mem_stats($sock, 'slabs'); 44 | is($slabs->{'active_slabs'}, 1, "1 active slab"); 45 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/binary-get.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 8; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $server = new_memcached(); 10 | my $sock = $server->sock; 11 | 12 | my $count = 1; 13 | 14 | foreach my $blob ("mooo\0", "mumble\0\0\0\0\r\rblarg", "\0", "\r") { 15 | my $key = "foo$count"; 16 | my $len = length($blob); 17 | print "len is $len\n"; 18 | print $sock "set $key 0 0 $len\r\n$blob\r\n"; 19 | is(scalar <$sock>, "STORED\r\n", "stored $key"); 20 | mem_get_is($sock, $key, $blob); 21 | $count++; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/bogus-commands.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 1; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $server = new_memcached(); 10 | my $sock = $server->sock; 11 | 12 | print $sock "boguscommand slkdsldkfjsd\r\n"; 13 | is(scalar <$sock>, "ERROR\r\n", "got error back"); 14 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/cas.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 43; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | 10 | my $server = new_memcached(); 11 | my $sock = $server->sock; 12 | my $sock2 = $server->new_sock; 13 | 14 | my @result; 15 | my @result2; 16 | 17 | ok($sock != $sock2, "have two different connections open"); 18 | 19 | sub check_args { 20 | my ($line, $name) = @_; 21 | 22 | my $svr = new_memcached(); 23 | my $s = $svr->sock; 24 | 25 | print $s $line; 26 | is(scalar <$s>, "CLIENT_ERROR bad command line format\r\n", $name); 27 | undef $svr; 28 | } 29 | 30 | check_args "cas bad blah 0 0 0\r\n\r\n", "bad flags"; 31 | check_args "cas bad 0 blah 0 0\r\n\r\n", "bad exp"; 32 | check_args "cas bad 0 0 blah 0\r\n\r\n", "bad cas"; 33 | check_args "cas bad 0 0 0 blah\r\n\r\n", "bad size"; 34 | 35 | # gets foo (should not exist) 36 | print $sock "gets foo\r\n"; 37 | is(scalar <$sock>, "END\r\n", "gets failed"); 38 | 39 | # set foo 40 | print $sock "set foo 0 0 6\r\nbarval\r\n"; 41 | is(scalar <$sock>, "STORED\r\n", "stored barval"); 42 | 43 | # gets foo and verify identifier exists 44 | @result = mem_gets($sock, "foo"); 45 | mem_gets_is($sock,$result[0],"foo","barval"); 46 | 47 | # cas fail 48 | print $sock "cas foo 0 0 6 123\r\nbarva2\r\n"; 49 | is(scalar <$sock>, "EXISTS\r\n", "cas failed for foo"); 50 | 51 | # gets foo - success 52 | @result = mem_gets($sock, "foo"); 53 | mem_gets_is($sock,$result[0],"foo","barval"); 54 | 55 | # cas success 56 | print $sock "cas foo 0 0 6 $result[0]\r\nbarva2\r\n"; 57 | is(scalar <$sock>, "STORED\r\n", "cas success, set foo"); 58 | 59 | # cas failure (reusing the same key) 60 | print $sock "cas foo 0 0 6 $result[0]\r\nbarva2\r\n"; 61 | is(scalar <$sock>, "EXISTS\r\n", "reusing a CAS ID"); 62 | 63 | # delete foo 64 | print $sock "delete foo\r\n"; 65 | is(scalar <$sock>, "DELETED\r\n", "deleted foo"); 66 | 67 | # cas missing 68 | print $sock "cas foo 0 0 6 $result[0]\r\nbarva2\r\n"; 69 | is(scalar <$sock>, "NOT_FOUND\r\n", "cas failed, foo does not exist"); 70 | 71 | # cas empty 72 | print $sock "cas foo 0 0 6 \r\nbarva2\r\n"; 73 | is(scalar <$sock>, "ERROR\r\n", "cas empty, throw error"); 74 | # cant parse barval2\r\n 75 | is(scalar <$sock>, "ERROR\r\n", "error out on barval2 parsing"); 76 | 77 | # set foo1 78 | print $sock "set foo1 0 0 1\r\n1\r\n"; 79 | is(scalar <$sock>, "STORED\r\n", "set foo1"); 80 | # set foo2 81 | print $sock "set foo2 0 0 1\r\n2\r\n"; 82 | is(scalar <$sock>, "STORED\r\n", "set foo2"); 83 | 84 | # gets foo1 check 85 | print $sock "gets foo1\r\n"; 86 | ok(scalar <$sock> =~ /VALUE foo1 0 1 (\d+)\r\n/, "gets foo1 regexp success"); 87 | my $foo1_cas = $1; 88 | is(scalar <$sock>, "1\r\n","gets foo1 data is 1"); 89 | is(scalar <$sock>, "END\r\n","gets foo1 END"); 90 | 91 | # gets foo2 check 92 | print $sock "gets foo2\r\n"; 93 | ok(scalar <$sock> =~ /VALUE foo2 0 1 (\d+)\r\n/,"gets foo2 regexp success"); 94 | my $foo2_cas = $1; 95 | is(scalar <$sock>, "2\r\n","gets foo2 data is 2"); 96 | is(scalar <$sock>, "END\r\n","gets foo2 END"); 97 | 98 | # validate foo1 != foo2 99 | ok($foo1_cas != $foo2_cas,"foo1 != foo2 single-gets success"); 100 | 101 | # multi-gets 102 | print $sock "gets foo1 foo2\r\n"; 103 | ok(scalar <$sock> =~ /VALUE foo1 0 1 (\d+)\r\n/, "validating first set of data is foo1"); 104 | $foo1_cas = $1; 105 | is(scalar <$sock>, "1\r\n", "validating foo1 set of data is 1"); 106 | ok(scalar <$sock> =~ /VALUE foo2 0 1 (\d+)\r\n/, "validating second set of data is foo2"); 107 | $foo2_cas = $1; 108 | is(scalar <$sock>, "2\r\n", "validating foo2 set of data is 2"); 109 | is(scalar <$sock>, "END\r\n","validating foo1,foo2 gets is over - END"); 110 | 111 | # validate foo1 != foo2 112 | ok($foo1_cas != $foo2_cas, "foo1 != foo2 multi-gets success"); 113 | 114 | ### simulate race condition with cas 115 | 116 | # gets foo1 - success 117 | @result = mem_gets($sock, "foo1"); 118 | ok($result[0] != "", "sock - gets foo1 is not empty"); 119 | 120 | # gets foo2 - success 121 | @result2 = mem_gets($sock2, "foo1"); 122 | ok($result2[0] != "","sock2 - gets foo1 is not empty"); 123 | 124 | print $sock "cas foo1 0 0 6 $result[0]\r\nbarva2\r\n"; 125 | print $sock2 "cas foo1 0 0 5 $result2[0]\r\napple\r\n"; 126 | 127 | my $res1 = <$sock>; 128 | my $res2 = <$sock2>; 129 | 130 | ok( ( $res1 eq "STORED\r\n" && $res2 eq "EXISTS\r\n") || 131 | ( $res1 eq "EXISTS\r\n" && $res2 eq "STORED\r\n"), 132 | "cas on same item from two sockets"); 133 | 134 | ### bug 15: http://code.google.com/p/memcached/issues/detail?id=15 135 | 136 | # set foo 137 | print $sock "set bug15 0 0 1\r\n0\r\n"; 138 | is(scalar <$sock>, "STORED\r\n", "stored 0"); 139 | 140 | # Check out the first gets. 141 | print $sock "gets bug15\r\n"; 142 | ok(scalar <$sock> =~ /VALUE bug15 0 1 (\d+)\r\n/, "gets bug15 regexp success"); 143 | my $bug15_cas = $1; 144 | is(scalar <$sock>, "0\r\n", "gets bug15 data is 0"); 145 | is(scalar <$sock>, "END\r\n","gets bug15 END"); 146 | 147 | # Increment 148 | print $sock "incr bug15 1\r\n"; 149 | is(scalar <$sock>, "1\r\n", "incr worked"); 150 | 151 | # Validate a changed CAS 152 | print $sock "gets bug15\r\n"; 153 | ok(scalar <$sock> =~ /VALUE bug15 0 1 (\d+)\r\n/, "gets bug15 regexp success"); 154 | my $next_bug15_cas = $1; 155 | is(scalar <$sock>, "1\r\n", "gets bug15 data is 0"); 156 | is(scalar <$sock>, "END\r\n","gets bug15 END"); 157 | 158 | ok($bug15_cas != $next_bug15_cas, "CAS changed"); 159 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/daemonize.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 7; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | use File::Temp qw(tempfile); 10 | 11 | my (undef, $tmpfn) = tempfile(); 12 | 13 | my $server = new_memcached("-d -P $tmpfn"); 14 | my $sock = $server->sock; 15 | sleep 0.5; 16 | 17 | ok(-e $tmpfn, "pid file exists"); 18 | ok(-s $tmpfn, "pid file has length"); 19 | 20 | open (my $fh, $tmpfn) or die; 21 | my $readpid = do { local $/; <$fh>; }; 22 | chomp $readpid; 23 | close ($fh); 24 | 25 | ok(kill(0, $readpid), "process is still running"); 26 | 27 | my $stats = mem_stats($sock); 28 | is($stats->{pid}, $readpid, "memcached reports same pid as file"); 29 | 30 | ok($server->new_sock, "opened new socket"); 31 | ok(kill(9, $readpid), "sent KILL signal"); 32 | sleep 0.5; 33 | ok(! $server->new_sock, "failed to open new socket"); 34 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/dash-M.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $server = new_memcached('-M -m 1'); 10 | my $sock = $server->sock; 11 | 12 | my $value = "B" x 8192; 13 | my $vallen = length($value); 14 | 15 | my $resp = "STORED\r\n"; 16 | my $key = 0; 17 | 18 | while($resp eq "STORED\r\n") { 19 | print $sock "set dash$key 0 0 $vallen\r\n$value\r\n"; 20 | $key++; 21 | $resp = scalar <$sock>; 22 | } 23 | 24 | my $max_stored = $key - 1; 25 | 26 | plan tests => $max_stored + 1; 27 | 28 | print $sock "set dash$key 0 0 $vallen\r\n$value\r\n"; 29 | is(scalar <$sock>, "SERVER_ERROR out of memory storing object\r\n", 30 | "failed to add another one."); 31 | 32 | for($key = 0; $key < $max_stored; $key++) { 33 | mem_get_is $sock, "dash$key", $value, "Failed at dash$key"; 34 | } 35 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/evictions.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Test the 'stats items' evictions counters. 3 | 4 | use strict; 5 | use Test::More tests => 92; 6 | use FindBin qw($Bin); 7 | use lib "$Bin/lib"; 8 | use MemcachedTest; 9 | 10 | my $server = new_memcached("-m 3"); 11 | my $sock = $server->sock; 12 | my $value = "B"x66560; 13 | my $key = 0; 14 | 15 | # These aren't set to expire. 16 | for ($key = 0; $key < 40; $key++) { 17 | print $sock "set key$key 0 0 66560\r\n$value\r\n"; 18 | is(scalar <$sock>, "STORED\r\n", "stored key$key"); 19 | } 20 | 21 | # These ones would expire in 600 seconds. 22 | for ($key = 0; $key < 50; $key++) { 23 | print $sock "set key$key 0 600 66560\r\n$value\r\n"; 24 | is(scalar <$sock>, "STORED\r\n", "stored key$key"); 25 | } 26 | 27 | my $stats = mem_stats($sock, "items"); 28 | my $evicted = $stats->{"items:31:evicted"}; 29 | isnt($evicted, "0", "check evicted"); 30 | my $evicted_nonzero = $stats->{"items:31:evicted_nonzero"}; 31 | isnt($evicted_nonzero, "0", "check evicted_nonzero"); 32 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/expirations.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 15; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $server = new_memcached(); 10 | my $sock = $server->sock; 11 | my $expire; 12 | 13 | sub wait_for_early_second { 14 | my $have_hires = eval "use Time::HiRes (); 1"; 15 | if ($have_hires) { 16 | my $tsh = Time::HiRes::time(); 17 | my $ts = int($tsh); 18 | return if ($tsh - $ts) < 0.5; 19 | } 20 | 21 | my $ts = int(time()); 22 | while (1) { 23 | my $t = int(time()); 24 | return if $t != $ts; 25 | select undef, undef, undef, 0.10; # 1/10th of a second sleeps until time changes. 26 | } 27 | } 28 | 29 | wait_for_early_second(); 30 | 31 | print $sock "set foo 0 1 6\r\nfooval\r\n"; 32 | is(scalar <$sock>, "STORED\r\n", "stored foo"); 33 | 34 | mem_get_is($sock, "foo", "fooval"); 35 | sleep(1.5); 36 | mem_get_is($sock, "foo", undef); 37 | 38 | $expire = time() - 1; 39 | print $sock "set foo 0 $expire 6\r\nfooval\r\n"; 40 | is(scalar <$sock>, "STORED\r\n", "stored foo"); 41 | mem_get_is($sock, "foo", undef, "already expired"); 42 | 43 | $expire = time() + 1; 44 | print $sock "set foo 0 $expire 6\r\nfoov+1\r\n"; 45 | is(scalar <$sock>, "STORED\r\n", "stored foo"); 46 | mem_get_is($sock, "foo", "foov+1"); 47 | sleep(2.2); 48 | mem_get_is($sock, "foo", undef, "now expired"); 49 | 50 | $expire = time() - 20; 51 | print $sock "set boo 0 $expire 6\r\nbooval\r\n"; 52 | is(scalar <$sock>, "STORED\r\n", "stored boo"); 53 | mem_get_is($sock, "boo", undef, "now expired"); 54 | 55 | print $sock "add add 0 2 6\r\naddval\r\n"; 56 | is(scalar <$sock>, "STORED\r\n", "stored add"); 57 | mem_get_is($sock, "add", "addval"); 58 | # second add fails 59 | print $sock "add add 0 2 7\r\naddval2\r\n"; 60 | is(scalar <$sock>, "NOT_STORED\r\n", "add failure"); 61 | sleep(2.3); 62 | print $sock "add add 0 2 7\r\naddval3\r\n"; 63 | is(scalar <$sock>, "STORED\r\n", "stored add again"); 64 | mem_get_is($sock, "add", "addval3"); 65 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/flags.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 6; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $server = new_memcached(); 10 | my $sock = $server->sock; 11 | 12 | # set foo (and should get it) 13 | for my $flags (0, 123, 2**16-1) { 14 | print $sock "set foo $flags 0 6\r\nfooval\r\n"; 15 | is(scalar <$sock>, "STORED\r\n", "stored foo"); 16 | mem_get_is({ sock => $sock, 17 | flags => $flags }, "foo", "fooval", "got flags $flags back"); 18 | } 19 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/flush-all.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 21; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $server = new_memcached(); 10 | my $sock = $server->sock; 11 | my $expire; 12 | 13 | print $sock "set foo 0 0 6\r\nfooval\r\n"; 14 | is(scalar <$sock>, "STORED\r\n", "stored foo"); 15 | 16 | mem_get_is($sock, "foo", "fooval"); 17 | print $sock "flush_all\r\n"; 18 | is(scalar <$sock>, "OK\r\n", "did flush_all"); 19 | mem_get_is($sock, "foo", undef); 20 | 21 | # Test flush_all with zero delay. 22 | print $sock "set foo 0 0 6\r\nfooval\r\n"; 23 | is(scalar <$sock>, "STORED\r\n", "stored foo"); 24 | 25 | mem_get_is($sock, "foo", "fooval"); 26 | print $sock "flush_all 0\r\n"; 27 | is(scalar <$sock>, "OK\r\n", "did flush_all"); 28 | mem_get_is($sock, "foo", undef); 29 | 30 | # check that flush_all doesn't blow away items that immediately get set 31 | print $sock "set foo 0 0 3\r\nnew\r\n"; 32 | is(scalar <$sock>, "STORED\r\n", "stored foo = 'new'"); 33 | mem_get_is($sock, "foo", 'new'); 34 | 35 | # and the other form, specifying a flush_all time... 36 | my $expire = time() + 2; 37 | print $sock "flush_all $expire\r\n"; 38 | is(scalar <$sock>, "OK\r\n", "did flush_all in future"); 39 | 40 | print $sock "set foo 0 0 4\r\n1234\r\n"; 41 | is(scalar <$sock>, "STORED\r\n", "stored foo = '1234'"); 42 | mem_get_is($sock, "foo", '1234'); 43 | sleep(3); 44 | mem_get_is($sock, "foo", undef); 45 | 46 | print $sock "set foo 0 0 5\r\n12345\r\n"; 47 | is(scalar <$sock>, "STORED\r\n", "stored foo = '12345'"); 48 | mem_get_is($sock, "foo", '12345'); 49 | print $sock "flush_all 86400\r\n"; 50 | is(scalar <$sock>, "OK\r\n", "did flush_all for far future"); 51 | # Check foo still exists. 52 | mem_get_is($sock, "foo", '12345'); 53 | print $sock "set foo2 0 0 5\r\n54321\r\n"; 54 | is(scalar <$sock>, "STORED\r\n", "stored foo2 = '54321'"); 55 | mem_get_is($sock, "foo", '12345'); 56 | mem_get_is($sock, "foo2", '54321'); 57 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/getset.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 539; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | 10 | my $server = new_memcached(); 11 | my $sock = $server->sock; 12 | 13 | 14 | # set foo (and should get it) 15 | print $sock "set foo 0 0 6\r\nfooval\r\n"; 16 | is(scalar <$sock>, "STORED\r\n", "stored foo"); 17 | mem_get_is($sock, "foo", "fooval"); 18 | 19 | # add bar (and should get it) 20 | print $sock "add bar 0 0 6\r\nbarval\r\n"; 21 | is(scalar <$sock>, "STORED\r\n", "stored barval"); 22 | mem_get_is($sock, "bar", "barval"); 23 | 24 | # add foo (but shouldn't get new value) 25 | print $sock "add foo 0 0 5\r\nfoov2\r\n"; 26 | is(scalar <$sock>, "NOT_STORED\r\n", "not stored"); 27 | mem_get_is($sock, "foo", "fooval"); 28 | 29 | # replace bar (should work) 30 | print $sock "replace bar 0 0 6\r\nbarva2\r\n"; 31 | is(scalar <$sock>, "STORED\r\n", "replaced barval 2"); 32 | 33 | # replace notexist (shouldn't work) 34 | print $sock "replace notexist 0 0 6\r\nbarva2\r\n"; 35 | is(scalar <$sock>, "NOT_STORED\r\n", "didn't replace notexist"); 36 | 37 | # delete foo. 38 | print $sock "delete foo\r\n"; 39 | is(scalar <$sock>, "DELETED\r\n", "deleted foo"); 40 | 41 | # delete foo again. not found this time. 42 | print $sock "delete foo\r\n"; 43 | is(scalar <$sock>, "NOT_FOUND\r\n", "deleted foo, but not found"); 44 | 45 | # add moo 46 | # 47 | print $sock "add moo 0 0 6\r\nmooval\r\n"; 48 | is(scalar <$sock>, "STORED\r\n", "stored barval"); 49 | mem_get_is($sock, "moo", "mooval"); 50 | 51 | # check-and-set (cas) failure case, try to set value with incorrect cas unique val 52 | print $sock "cas moo 0 0 6 0\r\nMOOVAL\r\n"; 53 | is(scalar <$sock>, "EXISTS\r\n", "check and set with invalid id"); 54 | 55 | # test "gets", grab unique ID 56 | print $sock "gets moo\r\n"; 57 | # VALUE moo 0 6 3084947704 58 | # 59 | my @retvals = split(/ /, scalar <$sock>); 60 | my $data = scalar <$sock>; # grab data 61 | my $dot = scalar <$sock>; # grab dot on line by itself 62 | is($retvals[0], "VALUE", "get value using 'gets'"); 63 | my $unique_id = $retvals[4]; 64 | # clean off \r\n 65 | $unique_id =~ s/\r\n$//; 66 | ok($unique_id =~ /^\d+$/, "unique ID '$unique_id' is an integer"); 67 | # now test that we can store moo with the correct unique id 68 | print $sock "cas moo 0 0 6 $unique_id\r\nMOOVAL\r\n"; 69 | is(scalar <$sock>, "STORED\r\n"); 70 | mem_get_is($sock, "moo", "MOOVAL"); 71 | 72 | # pipeling is okay 73 | print $sock "set foo 0 0 6\r\nfooval\r\ndelete foo\r\nset foo 0 0 6\r\nfooval\r\ndelete foo\r\n"; 74 | is(scalar <$sock>, "STORED\r\n", "pipeline set"); 75 | is(scalar <$sock>, "DELETED\r\n", "pipeline delete"); 76 | is(scalar <$sock>, "STORED\r\n", "pipeline set"); 77 | is(scalar <$sock>, "DELETED\r\n", "pipeline delete"); 78 | 79 | 80 | # Test sets up to a large size around 1MB. 81 | # Everything up to 1MB - 1k should succeed, everything 1MB +1k should fail. 82 | 83 | my $len = 1024; 84 | while ($len < 1024*1028) { 85 | my $val = "B"x$len; 86 | if ($len > (1024*1024)) { 87 | # Ensure causing a memory overflow doesn't leave stale data. 88 | print $sock "set foo_$len 0 0 3\r\nMOO\r\n"; 89 | is(scalar <$sock>, "STORED\r\n"); 90 | print $sock "set foo_$len 0 0 $len\r\n$val\r\n"; 91 | is(scalar <$sock>, "SERVER_ERROR object too large for cache\r\n", "failed to store size $len"); 92 | mem_get_is($sock, "foo_$len"); 93 | } else { 94 | print $sock "set foo_$len 0 0 $len\r\n$val\r\n"; 95 | is(scalar <$sock>, "STORED\r\n", "stored size $len"); 96 | } 97 | $len += 2048; 98 | } 99 | 100 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/incrdecr.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 23; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $server = new_memcached(); 10 | my $sock = $server->sock; 11 | 12 | # Bug 21 13 | print $sock "set bug21 0 0 19\r\n9223372036854775807\r\n"; 14 | is(scalar <$sock>, "STORED\r\n", "stored text"); 15 | print $sock "incr bug21 1\r\n"; 16 | is(scalar <$sock>, "9223372036854775808\r\n", "bug21 incr 1"); 17 | print $sock "incr bug21 1\r\n"; 18 | is(scalar <$sock>, "9223372036854775809\r\n", "bug21 incr 2"); 19 | print $sock "decr bug21 1\r\n"; 20 | is(scalar <$sock>, "9223372036854775808\r\n", "bug21 decr"); 21 | 22 | print $sock "set num 0 0 1\r\n1\r\n"; 23 | is(scalar <$sock>, "STORED\r\n", "stored num"); 24 | mem_get_is($sock, "num", 1, "stored 1"); 25 | 26 | print $sock "incr num 1\r\n"; 27 | is(scalar <$sock>, "2\r\n", "+ 1 = 2"); 28 | mem_get_is($sock, "num", 2); 29 | 30 | print $sock "incr num 8\r\n"; 31 | is(scalar <$sock>, "10\r\n", "+ 8 = 10"); 32 | mem_get_is($sock, "num", 10); 33 | 34 | print $sock "decr num 1\r\n"; 35 | is(scalar <$sock>, "9\r\n", "- 1 = 9"); 36 | 37 | print $sock "decr num 9\r\n"; 38 | is(scalar <$sock>, "0\r\n", "- 9 = 0"); 39 | 40 | print $sock "decr num 5\r\n"; 41 | is(scalar <$sock>, "0\r\n", "- 5 = 0"); 42 | 43 | printf $sock "set num 0 0 10\r\n4294967296\r\n"; 44 | is(scalar <$sock>, "STORED\r\n", "stored 2**32"); 45 | 46 | print $sock "incr num 1\r\n"; 47 | is(scalar <$sock>, "4294967297\r\n", "4294967296 + 1 = 4294967297"); 48 | 49 | printf $sock "set num 0 0 %d\r\n18446744073709551615\r\n", length("18446744073709551615"); 50 | is(scalar <$sock>, "STORED\r\n", "stored 2**64-1"); 51 | 52 | print $sock "incr num 1\r\n"; 53 | is(scalar <$sock>, "0\r\n", "(2**64 - 1) + 1 = 0"); 54 | 55 | print $sock "decr bogus 5\r\n"; 56 | is(scalar <$sock>, "NOT_FOUND\r\n", "can't decr bogus key"); 57 | 58 | print $sock "decr incr 5\r\n"; 59 | is(scalar <$sock>, "NOT_FOUND\r\n", "can't incr bogus key"); 60 | 61 | print $sock "set bigincr 0 0 1\r\n0\r\n"; 62 | is(scalar <$sock>, "STORED\r\n", "stored bigincr"); 63 | print $sock "incr bigincr 18446744073709551610\r\n"; 64 | is(scalar <$sock>, "18446744073709551610\r\n"); 65 | 66 | print $sock "set text 0 0 2\r\nhi\r\n"; 67 | is(scalar <$sock>, "STORED\r\n", "stored hi"); 68 | print $sock "incr text 1\r\n"; 69 | is(scalar <$sock>, 70 | "CLIENT_ERROR cannot increment or decrement non-numeric value\r\n", 71 | "hi - 1 = 0"); 72 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/issue_104.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 6; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $server = new_memcached(); 10 | my $sock = $server->sock; 11 | 12 | # first get should miss 13 | print $sock "get foo\r\n"; 14 | is(scalar <$sock>, "END\r\n", "get foo"); 15 | 16 | # Now set and get (should hit) 17 | print $sock "set foo 0 0 6\r\nfooval\r\n"; 18 | is(scalar <$sock>, "STORED\r\n", "stored foo"); 19 | mem_get_is($sock, "foo", "fooval"); 20 | 21 | my $stats = mem_stats($sock); 22 | is($stats->{cmd_get}, 2, "Should have 2 get requests"); 23 | is($stats->{get_hits}, 1, "Should have 1 hit"); 24 | is($stats->{get_misses}, 1, "Should have 1 miss"); 25 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/issue_108.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 4; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $server = new_memcached(); 10 | my $sock = $server->sock; 11 | my $key = "del_key"; 12 | 13 | print $sock "add $key 0 0 1\r\nx\r\n"; 14 | is (scalar <$sock>, "STORED\r\n", "Added a key"); 15 | 16 | print $sock "delete $key 0\r\n"; 17 | is (scalar <$sock>, "DELETED\r\n", "Properly deleted with 0"); 18 | 19 | print $sock "add $key 0 0 1\r\nx\r\n"; 20 | is (scalar <$sock>, "STORED\r\n", "Added again a key"); 21 | 22 | print $sock "delete $key 0 noreply\r\n"; 23 | # will not reply, but a subsequent add will succeed 24 | 25 | print $sock "add $key 0 0 1\r\nx\r\n"; 26 | is (scalar <$sock>, "STORED\r\n", "Add succeeded after quiet deletion."); 27 | 28 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/issue_14.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 21; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $server = new_memcached(); 10 | my $sock = $server->sock; 11 | my $value = "B"x66560; 12 | my $key = 0; 13 | 14 | for ($key = 0; $key < 10; $key++) { 15 | print $sock "set key$key 0 2 66560\r\n$value\r\n"; 16 | is (scalar <$sock>, "STORED\r\n", "stored key$key"); 17 | } 18 | 19 | #print $sock "stats slabs" 20 | my $first_stats = mem_stats($sock, "slabs"); 21 | my $first_malloc = $first_stats->{total_malloced}; 22 | 23 | sleep(4); 24 | 25 | for ($key = 10; $key < 20; $key++) { 26 | print $sock "set key$key 0 2 66560\r\n$value\r\n"; 27 | is (scalar <$sock>, "STORED\r\n", "stored key$key"); 28 | } 29 | 30 | my $second_stats = mem_stats($sock, "slabs"); 31 | my $second_malloc = $second_stats->{total_malloced}; 32 | 33 | 34 | is ($second_malloc, $first_malloc, "Memory grows..") 35 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/issue_140.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | plan skip_all => 'Fix for Issue 140 was only an illusion'; 10 | 11 | plan tests => 7; 12 | 13 | my $server = new_memcached(); 14 | my $sock = $server->sock; 15 | 16 | print $sock "set a 0 0 1\r\na\r\n"; 17 | is (scalar <$sock>, "STORED\r\n", "stored key"); 18 | 19 | my $stats = mem_stats($sock, "items"); 20 | my $age = $stats->{"items:1:age"}; 21 | isnt ($age, "0", "Age should not be zero"); 22 | 23 | print $sock "flush_all\r\n"; 24 | is (scalar <$sock>, "OK\r\n", "items flushed"); 25 | 26 | my $stats = mem_stats($sock, "items"); 27 | my $age = $stats->{"items:1:age"}; 28 | is ($age, undef, "all should be gone"); 29 | 30 | print $sock "set a 0 1 1\r\na\r\n"; 31 | is (scalar <$sock>, "STORED\r\n", "stored key"); 32 | 33 | my $stats = mem_stats($sock, "items"); 34 | my $age = $stats->{"items:1:age"}; 35 | isnt ($age, "0", "Age should not be zero"); 36 | 37 | sleep(3); 38 | 39 | my $stats = mem_stats($sock, "items"); 40 | my $age = $stats->{"items:1:age"}; 41 | is ($age, undef, "all should be gone"); 42 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/issue_152.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 2; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $server = new_memcached(); 10 | my $sock = $server->sock; 11 | my $key = "a"x251; 12 | 13 | print $sock "set a 1 0 1\r\na\r\n"; 14 | is (scalar <$sock>, "STORED\r\n", "Stored key"); 15 | 16 | print $sock "get a $key\r\n"; 17 | is (scalar <$sock>, "CLIENT_ERROR bad command line format\r\n", "illegal key"); 18 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/issue_163.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 7; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $server = new_memcached(); 10 | my $sock = $server->sock; 11 | my $value1 = "A"x66560; 12 | my $value2 = "B"x66570; 13 | 14 | print $sock "set key 0 1 66560\r\n$value1\r\n"; 15 | is (scalar <$sock>, "STORED\r\n", "stored key"); 16 | 17 | my $stats = mem_stats($sock, "slabs"); 18 | my $requested = $stats->{"31:mem_requested"}; 19 | isnt ($requested, "0", "We should have requested some memory"); 20 | 21 | sleep(3); 22 | print $sock "set key 0 0 66570\r\n$value2\r\n"; 23 | is (scalar <$sock>, "STORED\r\n", "stored key"); 24 | 25 | my $stats = mem_stats($sock, "items"); 26 | my $reclaimed = $stats->{"items:31:reclaimed"}; 27 | is ($reclaimed, "1", "Objects should be reclaimed"); 28 | 29 | print $sock "delete key\r\n"; 30 | is (scalar <$sock>, "DELETED\r\n", "deleted key"); 31 | 32 | print $sock "set key 0 0 66560\r\n$value1\r\n"; 33 | is (scalar <$sock>, "STORED\r\n", "stored key"); 34 | 35 | my $stats = mem_stats($sock, "slabs"); 36 | my $requested2 = $stats->{"31:mem_requested"}; 37 | is ($requested2, $requested, "we've not allocated and freed the same amont"); 38 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/issue_183.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 5; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $server = new_memcached(); 10 | my $sock = $server->sock; 11 | print $sock "set key 0 0 1\r\n1\r\n"; 12 | is (scalar <$sock>, "STORED\r\n", "stored key"); 13 | my $s1 = mem_stats($sock); 14 | my $r1 = $s1->{"reclaimed"}; 15 | is ($r1, "0", "Objects should not be reclaimed"); 16 | sleep(2); 17 | print $sock "flush_all\r\n"; 18 | is (scalar <$sock>, "OK\r\n", "Cache flushed"); 19 | print $sock "set key 0 0 1\r\n1\r\n"; 20 | is (scalar <$sock>, "STORED\r\n", "stored key"); 21 | my $s2 = mem_stats($sock); 22 | my $r2 = $s2->{"reclaimed"}; 23 | is ($r2, "1", "Objects should be reclaimed"); 24 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/issue_22.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 84; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $server = new_memcached("-m 3"); 10 | my $sock = $server->sock; 11 | my $value = "B"x66560; 12 | my $key = 0; 13 | 14 | for ($key = 0; $key < 40; $key++) { 15 | print $sock "set key$key 0 0 66560\r\n$value\r\n"; 16 | is (scalar <$sock>, "STORED\r\n", "stored key$key"); 17 | } 18 | 19 | my $first_stats = mem_stats($sock, "items"); 20 | my $first_evicted = $first_stats->{"items:31:evicted"}; 21 | # I get 1 eviction on a 32 bit binary, but 4 on a 64 binary.. 22 | # Just check that I have evictions... 23 | isnt ($first_evicted, "0", "check evicted"); 24 | 25 | print $sock "stats reset\r\n"; 26 | is (scalar <$sock>, "RESET\r\n", "Stats reset"); 27 | 28 | my $second_stats = mem_stats($sock, "items"); 29 | my $second_evicted = $second_stats->{"items:31:evicted"}; 30 | is ($second_evicted, "0", "check evicted"); 31 | 32 | for ($key = 40; $key < 80; $key++) { 33 | print $sock "set key$key 0 0 66560\r\n$value\r\n"; 34 | is (scalar <$sock>, "STORED\r\n", "stored key$key"); 35 | } 36 | 37 | my $last_stats = mem_stats($sock, "items"); 38 | my $last_evicted = $last_stats->{"items:31:evicted"}; 39 | is ($last_evicted, "40", "check evicted"); 40 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/issue_29.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 4; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $server = new_memcached(); 10 | my $sock = $server->sock; 11 | 12 | print $sock "set issue29 0 0 0\r\n\r\n"; 13 | is (scalar <$sock>, "STORED\r\n", "stored issue29"); 14 | 15 | my $first_stats = mem_stats($sock, "slabs"); 16 | my $first_used = $first_stats->{"1:used_chunks"}; 17 | 18 | is(1, $first_used, "Used one"); 19 | 20 | print $sock "set issue29_b 0 0 0\r\n\r\n"; 21 | is (scalar <$sock>, "STORED\r\n", "stored issue29_b"); 22 | 23 | my $second_stats = mem_stats($sock, "slabs"); 24 | my $second_used = $second_stats->{"1:used_chunks"}; 25 | 26 | is(2, $second_used, "Used two") 27 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/issue_3.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 8; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $server = new_memcached(); 10 | my $sock = $server->sock; 11 | my $key = "del_key"; 12 | 13 | print $sock "delete $key\r\n"; 14 | is (scalar <$sock>, "NOT_FOUND\r\n", "not found on delete"); 15 | 16 | print $sock "delete $key 10\r\n"; 17 | is (scalar <$sock>, "CLIENT_ERROR bad command line format." 18 | . " Usage: delete [noreply]\r\n", "invalid delete"); 19 | 20 | print $sock "add $key 0 0 1\r\nx\r\n"; 21 | is (scalar <$sock>, "STORED\r\n", "Add before a broken delete."); 22 | 23 | print $sock "delete $key 10 noreply\r\n"; 24 | # Does not reply 25 | # is (scalar <$sock>, "ERROR\r\n", "Even more invalid delete"); 26 | 27 | print $sock "add $key 0 0 1\r\nx\r\n"; 28 | is (scalar <$sock>, "NOT_STORED\r\n", "Failed to add after failed silent delete."); 29 | 30 | print $sock "delete $key noreply\r\n"; 31 | # Will not reply, so let's do a set and check that. 32 | 33 | print $sock "set $key 0 0 1\r\nx\r\n"; 34 | is (scalar <$sock>, "STORED\r\n", "Stored a key"); 35 | 36 | print $sock "delete $key\r\n"; 37 | is (scalar <$sock>, "DELETED\r\n", "Properly deleted"); 38 | 39 | print $sock "set $key 0 0 1\r\nx\r\n"; 40 | is (scalar <$sock>, "STORED\r\n", "Stored a key"); 41 | 42 | print $sock "delete $key noreply\r\n"; 43 | # will not reply, but a subsequent add will succeed 44 | 45 | print $sock "add $key 0 0 1\r\nx\r\n"; 46 | is (scalar <$sock>, "STORED\r\n", "Add succeeded after deletion."); 47 | 48 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/issue_41.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use warnings; 5 | use POSIX qw(ceil); 6 | use Test::More tests => 691; 7 | use FindBin qw($Bin); 8 | use lib "$Bin/lib"; 9 | use MemcachedTest; 10 | 11 | my $server = new_memcached(); 12 | my $sock = $server->sock; 13 | 14 | my $factor = 2; 15 | my $val = "x" x $factor; 16 | my $key = ''; 17 | 18 | # SET items of diverse size to the daemon so it can attempt 19 | # to return a large stats output for slabs 20 | for (my $i=0; $i<69; $i++) { 21 | for (my $j=0; $j<10; $j++) { 22 | $key = "$i:$j"; 23 | print $sock "set key$key 0 0 $factor\r\n$val\r\n"; 24 | is (scalar <$sock>, "STORED\r\n", "stored key$key"); 25 | } 26 | $factor *= 1.2; 27 | $factor = ceil($factor); 28 | $val = "x" x $factor; 29 | } 30 | 31 | # This request will kill the daemon if it has not allocated 32 | # enough memory internally. 33 | my $stats = mem_stats($sock, "slabs"); 34 | 35 | # Verify whether the daemon is still running or not by asking 36 | # it for statistics. 37 | print $sock "version\r\n"; 38 | my $v = scalar <$sock>; 39 | ok(defined $v && length($v), "memcached didn't respond"); 40 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/issue_42.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 11; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $server = new_memcached(); 10 | my $sock = $server->sock; 11 | my $value = "B"x10; 12 | my $key = 0; 13 | 14 | for ($key = 0; $key < 10; $key++) { 15 | print $sock "set key$key 0 0 10\r\n$value\r\n"; 16 | is (scalar <$sock>, "STORED\r\n", "stored key$key"); 17 | } 18 | 19 | my $first_stats = mem_stats($sock, "slabs"); 20 | my $req = $first_stats->{"1:mem_requested"}; 21 | ok ($req == "640" || $req == "800", "Check allocated size"); 22 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/issue_50.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 1; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $server = new_memcached('-B binary'); 10 | my $sock = $server->sock; 11 | 12 | $SIG{ALRM} = sub { die "alarm\n" }; 13 | alarm(2); 14 | print $sock "Here's a bunch of garbage that doesn't look like the bin prot."; 15 | my $rv = <$sock>; 16 | ok(1, "Either the above worked and quit, or hung forever."); 17 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/issue_61.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 7; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $server = new_memcached("-R 1"); 10 | my $sock = $server->sock; 11 | 12 | print $sock "set foobar 0 0 5\r\nBubba\r\nset foobar 0 0 5\r\nBubba\r\nset foobar 0 0 5\r\nBubba\r\nset foobar 0 0 5\r\nBubba\r\nset foobar 0 0 5\r\nBubba\r\nset foobar 0 0 5\r\nBubba\r\n"; 13 | is (scalar <$sock>, "STORED\r\n", "stored foobar"); 14 | is (scalar <$sock>, "STORED\r\n", "stored foobar"); 15 | is (scalar <$sock>, "STORED\r\n", "stored foobar"); 16 | is (scalar <$sock>, "STORED\r\n", "stored foobar"); 17 | is (scalar <$sock>, "STORED\r\n", "stored foobar"); 18 | is (scalar <$sock>, "STORED\r\n", "stored foobar"); 19 | my $stats = mem_stats($sock); 20 | is ($stats->{"conn_yields"}, "5", "Got a decent number of yields"); 21 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/issue_67.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 22; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | use Carp qw(croak); 9 | 10 | use Cwd; 11 | my $builddir = getcwd; 12 | 13 | $ENV{'MEMCACHED_PORT_FILENAME'} = "/tmp/ports.$$"; 14 | 15 | sub read_ports { 16 | my %rv = (); 17 | open(my $f, "/tmp/ports.$$") || die("Can't open ports file."); 18 | while(<$f>) { 19 | my ($type, $port) = split(/:\s+/); 20 | $rv{$type} = $port + 0; 21 | } 22 | unlink "/tmp/ports.$$"; 23 | return %rv; 24 | } 25 | 26 | sub validate_port { 27 | my ($name, $got, $expected) = @_; 28 | # diag "Wanted $expected, got $got"; 29 | if ($expected == -1) { 30 | ok(!defined($got), "$name expected no port, got $got"); 31 | } elsif ($expected == 0) { 32 | ok($got != 11211, "$name expected random port (got $got)"); 33 | } else { 34 | is($got, $expected, "$name"); 35 | } 36 | } 37 | 38 | sub run_server { 39 | my ($args) = @_; 40 | 41 | my $exe = "$builddir/memcached-debug"; 42 | croak("memcached binary doesn't exist. Haven't run 'make' ?\n") unless -e $exe; 43 | 44 | my $childpid = fork(); 45 | 46 | my $root = ''; 47 | $root = "-u root" if ($< == 0); 48 | my $cmd = "$builddir/timedrun 10 $exe $root $args"; 49 | 50 | unless($childpid) { 51 | exec $cmd; 52 | exit; # NOTREACHED 53 | } 54 | 55 | for (1..20) { 56 | if (-f "/tmp/ports.$$") { 57 | return Memcached::Handle->new(pid => $childpid); 58 | } 59 | select undef, undef, undef, 0.10; 60 | } 61 | croak "Failed to start server."; 62 | } 63 | 64 | sub when { 65 | my ($name, $params, $expected_tcp, $expected_udp) = @_; 66 | 67 | my $server = run_server($params); 68 | my %ports = read_ports(); 69 | 70 | validate_port($name, $ports{'TCP INET'}, $expected_tcp); 71 | validate_port($name, $ports{'UDP INET'}, $expected_udp); 72 | } 73 | 74 | # Disabling the defaults since it conflicts with a running instance. 75 | # when('no arguments', '', 11211, 11211); 76 | when('specifying tcp port', '-p 11212', 11212, 11212); 77 | when('specifying udp port', '-U 11222', 11222, 11222); 78 | when('specifying tcp ephemeral port', '-p -1', 0, 0); 79 | when('specifying udp ephemeral port', '-U -1', 0, 0); 80 | when('tcp port disabled', '-p 0', -1, -1); 81 | when('udp port disabled', '-U 0', -1, -1); 82 | when('specifying tcp and udp ports', '-p 11232 -U 11233', 11232, 11233); 83 | when('specifying tcp and disabling udp', '-p 11242 -U 0', 11242, -1); 84 | when('specifying udp and disabling tcp', '-p -1 -U 11252', 0, 11252); 85 | when('specifying tcp and ephemeral udp', '-p 11262 -U -1', 11262, 0); 86 | when('specifying udp and ephemeral tcp', '-p -1 -U 11272', 0, 11272); 87 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/issue_68.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 996; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $server = new_memcached(); 10 | my $sock = $server->sock; 11 | 12 | for (my $keyi = 1; $keyi < 250; $keyi++) { 13 | my $key = "x" x $keyi; 14 | print $sock "set $key 0 0 1\r\n9\r\n"; 15 | is (scalar <$sock>, "STORED\r\n", "stored $key"); 16 | mem_get_is($sock, $key, "9"); 17 | print $sock "incr $key 1\r\n"; 18 | is (scalar <$sock>, "10\r\n", "incr $key to 10"); 19 | mem_get_is($sock, $key, "10"); 20 | } 21 | 22 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/issue_70.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 4; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $server = new_memcached(); 10 | my $sock = $server->sock; 11 | 12 | print $sock "set issue70 0 0 0\r\n\r\n"; 13 | is (scalar <$sock>, "STORED\r\n", "stored issue70"); 14 | 15 | print $sock "set issue70 0 0 -1\r\n"; 16 | is (scalar <$sock>, "CLIENT_ERROR bad command line format\r\n"); 17 | 18 | print $sock "set issue70 0 0 4294967295\r\n"; 19 | is (scalar <$sock>, "CLIENT_ERROR bad command line format\r\n"); 20 | 21 | print $sock "set issue70 0 0 2147483647\r\nscoobyscoobydoo"; 22 | is (scalar <$sock>, "CLIENT_ERROR bad command line format\r\n"); 23 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/item_size_max.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 7; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $server = new_memcached(); 10 | my $sock = $server->sock; 11 | 12 | my $stats = mem_stats($sock, ' settings'); 13 | 14 | # Ensure default still works. 15 | is($stats->{item_size_max}, 1024 * 1024); 16 | $server->stop(); 17 | 18 | # Should die. 19 | eval { 20 | $server = new_memcached('-I 1000'); 21 | }; 22 | ok($@ && $@ =~ m/^Failed/, "Shouldn't start with < 1k item max"); 23 | 24 | eval { 25 | $server = new_memcached('-I 256m'); 26 | }; 27 | ok($@ && $@ =~ m/^Failed/, "Shouldn't start with > 128m item max"); 28 | 29 | # Minimum. 30 | $server = new_memcached('-I 1024'); 31 | my $stats = mem_stats($server->sock, ' settings'); 32 | is($stats->{item_size_max}, 1024); 33 | $server->stop(); 34 | 35 | # Reasonable but unreasonable. 36 | $server = new_memcached('-I 1049600'); 37 | my $stats = mem_stats($server->sock, ' settings'); 38 | is($stats->{item_size_max}, 1049600); 39 | $server->stop(); 40 | 41 | # Suffix kilobytes. 42 | $server = new_memcached('-I 512k'); 43 | my $stats = mem_stats($server->sock, ' settings'); 44 | is($stats->{item_size_max}, 524288); 45 | $server->stop(); 46 | 47 | # Suffix megabytes. 48 | $server = new_memcached('-I 32m'); 49 | my $stats = mem_stats($server->sock, ' settings'); 50 | is($stats->{item_size_max}, 33554432); 51 | $server->stop(); 52 | 53 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/lib/MemcachedTest.pm: -------------------------------------------------------------------------------- 1 | package MemcachedTest; 2 | use strict; 3 | use IO::Socket::INET; 4 | use IO::Socket::UNIX; 5 | use Exporter 'import'; 6 | use Carp qw(croak); 7 | use vars qw(@EXPORT); 8 | 9 | # Instead of doing the substitution with Autoconf, we assume that 10 | # cwd == builddir. 11 | use Cwd; 12 | my $builddir = getcwd; 13 | 14 | 15 | @EXPORT = qw(new_memcached sleep mem_get_is mem_gets mem_gets_is mem_stats 16 | supports_sasl free_port); 17 | 18 | sub sleep { 19 | my $n = shift; 20 | select undef, undef, undef, $n; 21 | } 22 | 23 | sub mem_stats { 24 | my ($sock, $type) = @_; 25 | $type = $type ? " $type" : ""; 26 | print $sock "stats$type\r\n"; 27 | my $stats = {}; 28 | while (<$sock>) { 29 | last if /^(\.|END)/; 30 | /^(STAT|ITEM) (\S+)\s+([^\r\n]+)/; 31 | #print " slabs: $_"; 32 | $stats->{$2} = $3; 33 | } 34 | return $stats; 35 | } 36 | 37 | sub mem_get_is { 38 | # works on single-line values only. no newlines in value. 39 | my ($sock_opts, $key, $val, $msg) = @_; 40 | my $opts = ref $sock_opts eq "HASH" ? $sock_opts : {}; 41 | my $sock = ref $sock_opts eq "HASH" ? $opts->{sock} : $sock_opts; 42 | 43 | my $expect_flags = $opts->{flags} || 0; 44 | my $dval = defined $val ? "'$val'" : ""; 45 | $msg ||= "$key == $dval"; 46 | 47 | print $sock "get $key\r\n"; 48 | if (! defined $val) { 49 | my $line = scalar <$sock>; 50 | if ($line =~ /^VALUE/) { 51 | $line .= scalar(<$sock>) . scalar(<$sock>); 52 | } 53 | Test::More::is($line, "END\r\n", $msg); 54 | } else { 55 | my $len = length($val); 56 | my $body = scalar(<$sock>); 57 | my $expected = "VALUE $key $expect_flags $len\r\n$val\r\nEND\r\n"; 58 | if (!$body || $body =~ /^END/) { 59 | Test::More::is($body, $expected, $msg); 60 | return; 61 | } 62 | $body .= scalar(<$sock>) . scalar(<$sock>); 63 | Test::More::is($body, $expected, $msg); 64 | } 65 | } 66 | 67 | sub mem_gets { 68 | # works on single-line values only. no newlines in value. 69 | my ($sock_opts, $key) = @_; 70 | my $opts = ref $sock_opts eq "HASH" ? $sock_opts : {}; 71 | my $sock = ref $sock_opts eq "HASH" ? $opts->{sock} : $sock_opts; 72 | my $val; 73 | my $expect_flags = $opts->{flags} || 0; 74 | 75 | print $sock "gets $key\r\n"; 76 | my $response = <$sock>; 77 | if ($response =~ /^END/) { 78 | return "NOT_FOUND"; 79 | } 80 | else 81 | { 82 | $response =~ /VALUE (.*) (\d+) (\d+) (\d+)/; 83 | my $flags = $2; 84 | my $len = $3; 85 | my $identifier = $4; 86 | read $sock, $val , $len; 87 | # get the END 88 | $_ = <$sock>; 89 | $_ = <$sock>; 90 | 91 | return ($identifier,$val); 92 | } 93 | 94 | } 95 | sub mem_gets_is { 96 | # works on single-line values only. no newlines in value. 97 | my ($sock_opts, $identifier, $key, $val, $msg) = @_; 98 | my $opts = ref $sock_opts eq "HASH" ? $sock_opts : {}; 99 | my $sock = ref $sock_opts eq "HASH" ? $opts->{sock} : $sock_opts; 100 | 101 | my $expect_flags = $opts->{flags} || 0; 102 | my $dval = defined $val ? "'$val'" : ""; 103 | $msg ||= "$key == $dval"; 104 | 105 | print $sock "gets $key\r\n"; 106 | if (! defined $val) { 107 | my $line = scalar <$sock>; 108 | if ($line =~ /^VALUE/) { 109 | $line .= scalar(<$sock>) . scalar(<$sock>); 110 | } 111 | Test::More::is($line, "END\r\n", $msg); 112 | } else { 113 | my $len = length($val); 114 | my $body = scalar(<$sock>); 115 | my $expected = "VALUE $key $expect_flags $len $identifier\r\n$val\r\nEND\r\n"; 116 | if (!$body || $body =~ /^END/) { 117 | Test::More::is($body, $expected, $msg); 118 | return; 119 | } 120 | $body .= scalar(<$sock>) . scalar(<$sock>); 121 | Test::More::is($body, $expected, $msg); 122 | } 123 | } 124 | 125 | sub free_port { 126 | my $type = shift || "tcp"; 127 | my $sock; 128 | my $port; 129 | while (!$sock) { 130 | $port = int(rand(20000)) + 30000; 131 | $sock = IO::Socket::INET->new(LocalAddr => '127.0.0.1', 132 | LocalPort => $port, 133 | Proto => $type, 134 | ReuseAddr => 1); 135 | } 136 | return $port; 137 | } 138 | 139 | sub supports_udp { 140 | my $output = `$builddir/memcached-debug -h`; 141 | return 0 if $output =~ /^memcached 1\.1\./; 142 | return 1; 143 | } 144 | 145 | sub supports_sasl { 146 | my $output = `$builddir/memcached-debug -h`; 147 | return 1 if $output =~ /sasl/i; 148 | return 0; 149 | } 150 | 151 | sub new_memcached { 152 | my ($args, $passed_port) = @_; 153 | my $port = $passed_port || free_port(); 154 | my $host = '127.0.0.1'; 155 | 156 | if ($ENV{T_MEMD_USE_DAEMON}) { 157 | my ($host, $port) = ($ENV{T_MEMD_USE_DAEMON} =~ m/^([^:]+):(\d+)$/); 158 | my $conn = IO::Socket::INET->new(PeerAddr => "$host:$port"); 159 | if ($conn) { 160 | return Memcached::Handle->new(conn => $conn, 161 | host => $host, 162 | port => $port); 163 | } 164 | croak("Failed to connect to specified memcached server.") unless $conn; 165 | } 166 | 167 | my $udpport = free_port("udp"); 168 | $args .= " -p $port"; 169 | if (supports_udp()) { 170 | $args .= " -U $udpport"; 171 | } 172 | if ($< == 0) { 173 | $args .= " -u root"; 174 | } 175 | 176 | my $childpid = fork(); 177 | 178 | my $exe = "$builddir/memcached-debug"; 179 | croak("memcached binary doesn't exist. Haven't run 'make' ?\n") unless -e $exe; 180 | croak("memcached binary not executable\n") unless -x _; 181 | 182 | unless ($childpid) { 183 | exec "$builddir/timedrun 600 $exe $args"; 184 | exit; # never gets here. 185 | } 186 | 187 | # unix domain sockets 188 | if ($args =~ /-s (\S+)/) { 189 | sleep 1; 190 | my $filename = $1; 191 | my $conn = IO::Socket::UNIX->new(Peer => $filename) || 192 | croak("Failed to connect to unix domain socket: $! '$filename'"); 193 | 194 | return Memcached::Handle->new(pid => $childpid, 195 | conn => $conn, 196 | domainsocket => $filename, 197 | host => $host, 198 | port => $port); 199 | } 200 | 201 | # try to connect / find open port, only if we're not using unix domain 202 | # sockets 203 | 204 | for (1..20) { 205 | my $conn = IO::Socket::INET->new(PeerAddr => "127.0.0.1:$port"); 206 | if ($conn) { 207 | return Memcached::Handle->new(pid => $childpid, 208 | conn => $conn, 209 | udpport => $udpport, 210 | host => $host, 211 | port => $port); 212 | } 213 | select undef, undef, undef, 0.10; 214 | } 215 | croak("Failed to startup/connect to memcached server."); 216 | } 217 | 218 | ############################################################################ 219 | package Memcached::Handle; 220 | sub new { 221 | my ($class, %params) = @_; 222 | return bless \%params, $class; 223 | } 224 | 225 | sub DESTROY { 226 | my $self = shift; 227 | kill 2, $self->{pid}; 228 | } 229 | 230 | sub stop { 231 | my $self = shift; 232 | kill 15, $self->{pid}; 233 | } 234 | 235 | sub host { $_[0]{host} } 236 | sub port { $_[0]{port} } 237 | sub udpport { $_[0]{udpport} } 238 | 239 | sub sock { 240 | my $self = shift; 241 | 242 | if ($self->{conn} && ($self->{domainsocket} || getpeername($self->{conn}))) { 243 | return $self->{conn}; 244 | } 245 | return $self->new_sock; 246 | } 247 | 248 | sub new_sock { 249 | my $self = shift; 250 | if ($self->{domainsocket}) { 251 | return IO::Socket::UNIX->new(Peer => $self->{domainsocket}); 252 | } else { 253 | return IO::Socket::INET->new(PeerAddr => "$self->{host}:$self->{port}"); 254 | } 255 | } 256 | 257 | sub new_udp_sock { 258 | my $self = shift; 259 | return IO::Socket::INET->new(PeerAddr => '127.0.0.1', 260 | PeerPort => $self->{udpport}, 261 | Proto => 'udp', 262 | LocalAddr => '127.0.0.1', 263 | LocalPort => MemcachedTest::free_port('udp'), 264 | ); 265 | 266 | } 267 | 268 | 1; 269 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/line-lengths.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use strict; 3 | use FindBin qw($Bin); 4 | our @files; 5 | 6 | BEGIN { 7 | chdir "$Bin/.." or die; 8 | @files = ( "doc/protocol.txt" ); 9 | } 10 | 11 | use Test::More tests => scalar(@files); 12 | 13 | foreach my $f (@files) { 14 | open(my $fh, $f) or die("Can't open $f"); 15 | my @long_lines = (); 16 | my $line_number = 0; 17 | while(<$fh>) { 18 | $line_number++; 19 | if(length($_) > 80) { 20 | push(@long_lines, $line_number); 21 | } 22 | } 23 | close($fh); 24 | ok(@long_lines == 0, "$f has a long lines: @long_lines"); 25 | } 26 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/lru.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 149; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | # assuming max slab is 1M and default mem is 64M 10 | my $server = new_memcached(); 11 | my $sock = $server->sock; 12 | 13 | # create a big value for the largest slab 14 | my $max = 1024 * 1024; 15 | my $big = 'x' x (1024 * 1024 - 250); 16 | 17 | ok(length($big) > 512 * 1024); 18 | ok(length($big) < 1024 * 1024); 19 | 20 | # test that an even bigger value is rejected while we're here 21 | my $too_big = $big . $big . $big; 22 | my $len = length($too_big); 23 | print $sock "set too_big 0 0 $len\r\n$too_big\r\n"; 24 | is(scalar <$sock>, "SERVER_ERROR object too large for cache\r\n", "too_big not stored"); 25 | 26 | # set the big value 27 | my $len = length($big); 28 | print $sock "set big 0 0 $len\r\n$big\r\n"; 29 | is(scalar <$sock>, "STORED\r\n", "stored big"); 30 | mem_get_is($sock, "big", $big); 31 | 32 | # no evictions yet 33 | my $stats = mem_stats($sock); 34 | is($stats->{"evictions"}, "0", "no evictions to start"); 35 | 36 | # set many big items, enough to get evictions 37 | for (my $i = 0; $i < 100; $i++) { 38 | print $sock "set item_$i 0 0 $len\r\n$big\r\n"; 39 | is(scalar <$sock>, "STORED\r\n", "stored item_$i"); 40 | } 41 | 42 | # some evictions should have happened 43 | my $stats = mem_stats($sock); 44 | my $evictions = int($stats->{"evictions"}); 45 | ok($evictions == 37, "some evictions happened"); 46 | 47 | # the first big value should be gone 48 | mem_get_is($sock, "big", undef); 49 | 50 | # the earliest items should be gone too 51 | for (my $i = 0; $i < $evictions - 1; $i++) { 52 | mem_get_is($sock, "item_$i", undef); 53 | } 54 | 55 | # check that the non-evicted are the right ones 56 | for (my $i = $evictions - 1; $i < $evictions + 4; $i++) { 57 | mem_get_is($sock, "item_$i", $big); 58 | } 59 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/maxconns.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # NOTE: This test never worked. Memcached would ignore maxconns requests lower 3 | # than the current ulimit. Test needs to be updated. 4 | 5 | use strict; 6 | use warnings; 7 | 8 | use Test::More tests => 11; 9 | 10 | use FindBin qw($Bin); 11 | use lib "$Bin/lib"; 12 | use MemcachedTest; 13 | 14 | 15 | # start up a server with 10 maximum connections 16 | my $server = new_memcached('-c 100'); 17 | my $sock = $server->sock; 18 | my @sockets; 19 | 20 | ok(defined($sock), 'Connection 0'); 21 | push (@sockets, $sock); 22 | 23 | 24 | foreach my $conn (1..10) { 25 | $sock = $server->new_sock; 26 | ok(defined($sock), "Made connection $conn"); 27 | push(@sockets, $sock); 28 | } 29 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/multiversioning.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 13; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $server = new_memcached(); 10 | my $sock = $server->sock; 11 | my $sock2 = $server->new_sock; 12 | 13 | ok($sock != $sock2, "have two different connections open"); 14 | 15 | # set large value 16 | my $size = 256 * 1024; # 256 kB 17 | my $bigval = "0123456789abcdef" x ($size / 16); 18 | $bigval =~ s/^0/\[/; $bigval =~ s/f$/\]/; 19 | my $bigval2 = uc($bigval); 20 | 21 | print $sock "set big 0 0 $size\r\n$bigval\r\n"; 22 | is(scalar <$sock>, "STORED\r\n", "stored foo"); 23 | mem_get_is($sock, "big", $bigval, "big value got correctly"); 24 | 25 | print $sock "get big\r\n"; 26 | my $buf; 27 | is(read($sock, $buf, $size / 2), $size / 2, "read half the answer back"); 28 | like($buf, qr/VALUE big/, "buf has big value header in it"); 29 | like($buf, qr/abcdef/, "buf has some data in it"); 30 | unlike($buf, qr/abcde\]/, "buf doesn't yet close"); 31 | 32 | # sock2 interrupts (maybe sock1 is slow) and deletes stuff: 33 | print $sock2 "delete big\r\n"; 34 | is(scalar <$sock2>, "DELETED\r\n", "deleted big from sock2 while sock1's still reading it"); 35 | mem_get_is($sock2, "big", undef, "nothing from sock2 now. gone from namespace."); 36 | print $sock2 "set big 0 0 $size\r\n$bigval2\r\n"; 37 | is(scalar <$sock2>, "STORED\r\n", "stored big w/ val2"); 38 | mem_get_is($sock2, "big", $bigval2, "big value2 got correctly"); 39 | 40 | # sock1 resumes reading... 41 | $buf .= <$sock>; 42 | $buf .= <$sock>; 43 | like($buf, qr/abcde\]/, "buf now closes"); 44 | 45 | # and if sock1 reads again, it's the uppercase version: 46 | mem_get_is($sock, "big", $bigval2, "big value2 got correctly from sock1"); 47 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/noreply.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 9; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | 10 | my $server = new_memcached(); 11 | my $sock = $server->sock; 12 | 13 | 14 | # Test that commands can take 'noreply' parameter. 15 | print $sock "flush_all noreply\r\n"; 16 | print $sock "flush_all 0 noreply\r\n"; 17 | 18 | print $sock "verbosity 0 noreply\r\n"; 19 | 20 | print $sock "add noreply:foo 0 0 1 noreply\r\n1\r\n"; 21 | mem_get_is($sock, "noreply:foo", "1"); 22 | 23 | print $sock "set noreply:foo 0 0 1 noreply\r\n2\r\n"; 24 | mem_get_is($sock, "noreply:foo", "2"); 25 | 26 | print $sock "replace noreply:foo 0 0 1 noreply\r\n3\r\n"; 27 | mem_get_is($sock, "noreply:foo", "3"); 28 | 29 | print $sock "append noreply:foo 0 0 1 noreply\r\n4\r\n"; 30 | mem_get_is($sock, "noreply:foo", "34"); 31 | 32 | print $sock "prepend noreply:foo 0 0 1 noreply\r\n5\r\n"; 33 | my @result = mem_gets($sock, "noreply:foo"); 34 | ok($result[1] eq "534"); 35 | 36 | print $sock "cas noreply:foo 0 0 1 $result[0] noreply\r\n6\r\n"; 37 | mem_get_is($sock, "noreply:foo", "6"); 38 | 39 | print $sock "incr noreply:foo 3 noreply\r\n"; 40 | mem_get_is($sock, "noreply:foo", "9"); 41 | 42 | print $sock "decr noreply:foo 2 noreply\r\n"; 43 | mem_get_is($sock, "noreply:foo", "7"); 44 | 45 | print $sock "delete noreply:foo noreply\r\n"; 46 | mem_get_is($sock, "noreply:foo"); 47 | 48 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/sasl/memcached.conf: -------------------------------------------------------------------------------- 1 | mech_list: plain cram-md5 2 | log_level: 5 3 | sasldb_path: /tmp/test-memcached.sasldb 4 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/slabs_reassign.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use warnings; 5 | use Test::More tests => 130; 6 | use FindBin qw($Bin); 7 | use lib "$Bin/lib"; 8 | use MemcachedTest; 9 | 10 | # Enable manual slab reassign, cap at 6 slabs 11 | my $server = new_memcached('-o slab_reassign -m 4'); 12 | my $stats = mem_stats($server->sock, ' settings'); 13 | is($stats->{slab_reassign}, "yes"); 14 | 15 | my $sock = $server->sock; 16 | 17 | # Fill a largeish slab until it evicts (honors the -m 6) 18 | my $bigdata = 'x' x 70000; # slab 31 19 | for (1 .. 60) { 20 | print $sock "set bfoo$_ 0 0 70000\r\n", $bigdata, "\r\n"; 21 | is(scalar <$sock>, "STORED\r\n", "stored key"); 22 | } 23 | 24 | # Fill a smaller slab until it evicts 25 | my $smalldata = 'y' x 20000; # slab 25 26 | for (1 .. 60) { 27 | print $sock "set sfoo$_ 0 0 20000\r\n", $smalldata, "\r\n"; 28 | is(scalar <$sock>, "STORED\r\n", "stored key"); 29 | } 30 | 31 | my $items_before = mem_stats($sock, "items"); 32 | isnt($items_before->{"items:31:evicted"}, 0, "slab 31 evicted is nonzero"); 33 | isnt($items_before->{"items:25:evicted"}, 0, "slab 25 evicted is nonzero"); 34 | 35 | my $slabs_before = mem_stats($sock, "slabs"); 36 | # Move a large slab to the smaller slab 37 | print $sock "slabs reassign 31 25\r\n"; 38 | is(scalar <$sock>, "OK\r\n", "slab rebalancer started"); 39 | 40 | # Still working out how/if to signal the thread. For now, just sleep. 41 | sleep 2; 42 | 43 | # Check that stats counters increased 44 | my $slabs_after = mem_stats($sock, "slabs"); 45 | $stats = mem_stats($sock); 46 | 47 | isnt($stats->{slabs_moved}, 0, "slabs moved is nonzero"); 48 | 49 | # Check that slab stats reflect the change 50 | ok($slabs_before->{"31:total_pages"} != $slabs_after->{"31:total_pages"}, 51 | "slab 31 pagecount changed"); 52 | ok($slabs_before->{"25:total_pages"} != $slabs_after->{"25:total_pages"}, 53 | "slab 25 pagecount changed"); 54 | 55 | # Try to move another slab, see that you can move two in a row 56 | print $sock "slabs reassign 31 25\r\n"; 57 | like(scalar <$sock>, qr/^OK/, "Cannot re-run against class with empty space"); 58 | 59 | # Try to move a page backwards. Should complain that source class isn't "safe" 60 | # to move from. 61 | # TODO: Wait until the above command completes, then try to move it back? 62 | # Seems pointless... 63 | #print $sock "slabs reassign 25 31\r\n"; 64 | #like(scalar <$sock>, qr/^UNSAFE/, "Cannot move an unsafe slab back"); 65 | 66 | # Try to insert items into both slabs 67 | print $sock "set bfoo51 0 0 70000\r\n", $bigdata, "\r\n"; 68 | is(scalar <$sock>, "STORED\r\n", "stored key"); 69 | 70 | print $sock "set sfoo51 0 0 20000\r\n", $smalldata, "\r\n"; 71 | is(scalar <$sock>, "STORED\r\n", "stored key"); 72 | 73 | # Do need to come up with better automated tests for this. 74 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/stats-detail.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 24; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $server = new_memcached(); 10 | my $sock = $server->sock; 11 | my $expire; 12 | 13 | print $sock "stats detail dump\r\n"; 14 | is(scalar <$sock>, "END\r\n", "verified empty stats at start"); 15 | 16 | print $sock "stats detail on\r\n"; 17 | is(scalar <$sock>, "OK\r\n", "detail collection turned on"); 18 | 19 | print $sock "set foo:123 0 0 6\r\nfooval\r\n"; 20 | is(scalar <$sock>, "STORED\r\n", "stored foo"); 21 | 22 | print $sock "stats detail dump\r\n"; 23 | is(scalar <$sock>, "PREFIX foo get 0 hit 0 set 1 del 0\r\n", "details after set"); 24 | is(scalar <$sock>, "END\r\n", "end of details"); 25 | 26 | mem_get_is($sock, "foo:123", "fooval"); 27 | print $sock "stats detail dump\r\n"; 28 | is(scalar <$sock>, "PREFIX foo get 1 hit 1 set 1 del 0\r\n", "details after get with hit"); 29 | is(scalar <$sock>, "END\r\n", "end of details"); 30 | 31 | mem_get_is($sock, "foo:124", undef); 32 | 33 | print $sock "stats detail dump\r\n"; 34 | is(scalar <$sock>, "PREFIX foo get 2 hit 1 set 1 del 0\r\n", "details after get without hit"); 35 | is(scalar <$sock>, "END\r\n", "end of details"); 36 | 37 | print $sock "delete foo:125\r\n"; 38 | is(scalar <$sock>, "NOT_FOUND\r\n", "sent delete command"); 39 | 40 | print $sock "stats detail dump\r\n"; 41 | is(scalar <$sock>, "PREFIX foo get 2 hit 1 set 1 del 1\r\n", "details after delete"); 42 | is(scalar <$sock>, "END\r\n", "end of details"); 43 | 44 | print $sock "stats reset\r\n"; 45 | is(scalar <$sock>, "RESET\r\n", "stats cleared"); 46 | 47 | print $sock "stats detail dump\r\n"; 48 | is(scalar <$sock>, "END\r\n", "empty stats after clear"); 49 | 50 | mem_get_is($sock, "foo:123", "fooval"); 51 | print $sock "stats detail dump\r\n"; 52 | is(scalar <$sock>, "PREFIX foo get 1 hit 1 set 0 del 0\r\n", "details after clear and get"); 53 | is(scalar <$sock>, "END\r\n", "end of details"); 54 | 55 | print $sock "stats detail off\r\n"; 56 | is(scalar <$sock>, "OK\r\n", "detail collection turned off"); 57 | 58 | mem_get_is($sock, "foo:124", undef); 59 | 60 | mem_get_is($sock, "foo:123", "fooval"); 61 | print $sock "stats detail dump\r\n"; 62 | is(scalar <$sock>, "PREFIX foo get 1 hit 1 set 0 del 0\r\n", "details after stats turned off"); 63 | is(scalar <$sock>, "END\r\n", "end of details"); 64 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/stats.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 95; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $server = new_memcached(); 10 | my $sock = $server->sock; 11 | 12 | 13 | ## Output looks like this: 14 | ## 15 | ## STAT pid 22969 16 | ## STAT uptime 13 17 | ## STAT time 1259170891 18 | ## STAT version 1.4.3 19 | ## STAT libevent 1.4.13-stable. 20 | ## STAT pointer_size 32 21 | ## STAT rusage_user 0.001198 22 | ## STAT rusage_system 0.003523 23 | ## STAT curr_connections 10 24 | ## STAT total_connections 11 25 | ## STAT connection_structures 11 26 | ## STAT cmd_get 0 27 | ## STAT cmd_set 0 28 | ## STAT cmd_flush 0 29 | ## STAT get_hits 0 30 | ## STAT get_misses 0 31 | ## STAT delete_misses 0 32 | ## STAT delete_hits 0 33 | ## STAT incr_misses 0 34 | ## STAT incr_hits 0 35 | ## STAT decr_misses 0 36 | ## STAT decr_hits 0 37 | ## STAT cas_misses 0 38 | ## STAT cas_hits 0 39 | ## STAT cas_badval 0 40 | ## STAT auth_cmds 0 41 | ## STAT auth_unknowns 0 42 | ## STAT bytes_read 7 43 | ## STAT bytes_written 0 44 | ## STAT limit_maxbytes 67108864 45 | ## STAT accepting_conns 1 46 | ## STAT listen_disabled_num 0 47 | ## STAT threads 4 48 | ## STAT conn_yields 0 49 | ## STAT bytes 0 50 | ## STAT curr_items 0 51 | ## STAT total_items 0 52 | ## STAT evictions 0 53 | ## STAT reclaimed 0 54 | 55 | # note that auth stats are tested in auth specfic tests 56 | 57 | 58 | my $stats = mem_stats($sock); 59 | 60 | # Test number of keys 61 | is(scalar(keys(%$stats)), 48, "48 stats values"); 62 | 63 | # Test initial state 64 | foreach my $key (qw(curr_items total_items bytes cmd_get cmd_set get_hits evictions get_misses 65 | bytes_written delete_hits delete_misses incr_hits incr_misses decr_hits 66 | decr_misses listen_disabled_num)) { 67 | is($stats->{$key}, 0, "initial $key is zero"); 68 | } 69 | is($stats->{accepting_conns}, 1, "initial accepting_conns is one"); 70 | 71 | # Do some operations 72 | 73 | print $sock "set foo 0 0 6\r\nfooval\r\n"; 74 | is(scalar <$sock>, "STORED\r\n", "stored foo"); 75 | mem_get_is($sock, "foo", "fooval"); 76 | 77 | my $stats = mem_stats($sock); 78 | 79 | foreach my $key (qw(total_items curr_items cmd_get cmd_set get_hits)) { 80 | is($stats->{$key}, 1, "after one set/one get $key is 1"); 81 | } 82 | 83 | my $cache_dump = mem_stats($sock, " cachedump 1 100"); 84 | ok(defined $cache_dump->{'foo'}, "got foo from cachedump"); 85 | 86 | print $sock "delete foo\r\n"; 87 | is(scalar <$sock>, "DELETED\r\n", "deleted foo"); 88 | 89 | my $stats = mem_stats($sock); 90 | is($stats->{delete_hits}, 1); 91 | is($stats->{delete_misses}, 0); 92 | 93 | print $sock "delete foo\r\n"; 94 | is(scalar <$sock>, "NOT_FOUND\r\n", "shouldn't delete foo again"); 95 | 96 | my $stats = mem_stats($sock); 97 | is($stats->{delete_hits}, 1); 98 | is($stats->{delete_misses}, 1); 99 | 100 | # incr stats 101 | 102 | sub check_incr_stats { 103 | my ($ih, $im, $dh, $dm) = @_; 104 | my $stats = mem_stats($sock); 105 | 106 | is($stats->{incr_hits}, $ih); 107 | is($stats->{incr_misses}, $im); 108 | is($stats->{decr_hits}, $dh); 109 | is($stats->{decr_misses}, $dm); 110 | } 111 | 112 | print $sock "incr i 1\r\n"; 113 | is(scalar <$sock>, "NOT_FOUND\r\n", "shouldn't incr a missing thing"); 114 | check_incr_stats(0, 1, 0, 0); 115 | 116 | print $sock "decr d 1\r\n"; 117 | is(scalar <$sock>, "NOT_FOUND\r\n", "shouldn't decr a missing thing"); 118 | check_incr_stats(0, 1, 0, 1); 119 | 120 | print $sock "set n 0 0 1\r\n0\r\n"; 121 | is(scalar <$sock>, "STORED\r\n", "stored n"); 122 | 123 | print $sock "incr n 3\r\n"; 124 | is(scalar <$sock>, "3\r\n", "incr works"); 125 | check_incr_stats(1, 1, 0, 1); 126 | 127 | print $sock "decr n 1\r\n"; 128 | is(scalar <$sock>, "2\r\n", "decr works"); 129 | check_incr_stats(1, 1, 1, 1); 130 | 131 | # cas stats 132 | 133 | sub check_cas_stats { 134 | my ($ch, $cm, $cb) = @_; 135 | my $stats = mem_stats($sock); 136 | 137 | is($stats->{cas_hits}, $ch); 138 | is($stats->{cas_misses}, $cm); 139 | is($stats->{cas_badval}, $cb); 140 | } 141 | 142 | check_cas_stats(0, 0, 0); 143 | 144 | print $sock "cas c 0 0 1 99999999\r\nz\r\n"; 145 | is(scalar <$sock>, "NOT_FOUND\r\n", "missed cas"); 146 | check_cas_stats(0, 1, 0); 147 | 148 | print $sock "set c 0 0 1\r\nx\r\n"; 149 | is(scalar <$sock>, "STORED\r\n", "stored c"); 150 | my ($id, $v) = mem_gets($sock, 'c'); 151 | is('x', $v, 'got the expected value'); 152 | 153 | print $sock "cas c 0 0 1 99999999\r\nz\r\n"; 154 | is(scalar <$sock>, "EXISTS\r\n", "missed cas"); 155 | check_cas_stats(0, 1, 1); 156 | my ($newid, $v) = mem_gets($sock, 'c'); 157 | is('x', $v, 'got the expected value'); 158 | 159 | print $sock "cas c 0 0 1 $id\r\nz\r\n"; 160 | is(scalar <$sock>, "STORED\r\n", "good cas"); 161 | check_cas_stats(1, 1, 1); 162 | my ($newid, $v) = mem_gets($sock, 'c'); 163 | is('z', $v, 'got the expected value'); 164 | 165 | my $settings = mem_stats($sock, ' settings'); 166 | is(1024, $settings->{'maxconns'}); 167 | is('NULL', $settings->{'domain_socket'}); 168 | is('on', $settings->{'evictions'}); 169 | is('yes', $settings->{'cas_enabled'}); 170 | is('no', $settings->{'auth_enabled_sasl'}); 171 | 172 | print $sock "stats reset\r\n"; 173 | is(scalar <$sock>, "RESET\r\n", "good stats reset"); 174 | 175 | my $stats = mem_stats($sock); 176 | is(0, $stats->{'cmd_get'}); 177 | is(0, $stats->{'cmd_set'}); 178 | is(0, $stats->{'get_hits'}); 179 | is(0, $stats->{'get_misses'}); 180 | is(0, $stats->{'delete_misses'}); 181 | is(0, $stats->{'delete_hits'}); 182 | is(0, $stats->{'incr_misses'}); 183 | is(0, $stats->{'incr_hits'}); 184 | is(0, $stats->{'decr_misses'}); 185 | is(0, $stats->{'decr_hits'}); 186 | is(0, $stats->{'cas_misses'}); 187 | is(0, $stats->{'cas_hits'}); 188 | is(0, $stats->{'cas_badval'}); 189 | is(0, $stats->{'evictions'}); 190 | is(0, $stats->{'reclaimed'}); 191 | 192 | print $sock "flush_all\r\n"; 193 | is(scalar <$sock>, "OK\r\n", "flushed"); 194 | 195 | my $stats = mem_stats($sock); 196 | is($stats->{cmd_flush}, 1, "after one flush cmd_flush is 1"); 197 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/stress-memcached.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # 3 | 4 | use strict; 5 | use lib '../../api/perl/lib'; 6 | use Cache::Memcached; 7 | use Time::HiRes qw(time); 8 | 9 | unless (@ARGV == 2) { 10 | die "Usage: stress-memcached.pl ip:port threads\n"; 11 | } 12 | 13 | my $host = shift; 14 | my $threads = shift; 15 | 16 | my $memc = new Cache::Memcached; 17 | $memc->set_servers([$host]); 18 | 19 | unless ($memc->set("foo", "bar") && 20 | $memc->get("foo") eq "bar") { 21 | die "memcached not running at $host ?\n"; 22 | } 23 | $memc->disconnect_all(); 24 | 25 | 26 | my $running = 0; 27 | while (1) { 28 | if ($running < $threads) { 29 | my $cpid = fork(); 30 | if ($cpid) { 31 | $running++; 32 | #print "Launched $cpid. Running $running threads.\n"; 33 | } else { 34 | stress(); 35 | exit 0; 36 | } 37 | } else { 38 | wait(); 39 | $running--; 40 | } 41 | } 42 | 43 | sub stress { 44 | undef $memc; 45 | $memc = new Cache::Memcached; 46 | $memc->set_servers([$host]); 47 | 48 | my ($t1, $t2); 49 | my $start = sub { $t1 = time(); }; 50 | my $stop = sub { 51 | my $op = shift; 52 | $t2 = time(); 53 | my $td = sprintf("%0.3f", $t2 - $t1); 54 | if ($td > 0.25) { print "Took $td seconds for: $op\n"; } 55 | }; 56 | 57 | my $max = rand(50); 58 | my $sets = 0; 59 | 60 | for (my $i = 0; $i < $max; $i++) { 61 | my $key = key($i); 62 | my $set = $memc->set($key, $key); 63 | $sets++ if $set; 64 | } 65 | 66 | for (1..int(rand(500))) { 67 | my $rand = int(rand($max)); 68 | my $key = key($rand); 69 | my $meth = int(rand(3)); 70 | my $exp = int(rand(3)); 71 | undef $exp unless $exp; 72 | $start->(); 73 | if ($meth == 0) { 74 | $memc->add($key, $key, $exp); 75 | $stop->("add"); 76 | } elsif ($meth == 1) { 77 | $memc->delete($key); 78 | $stop->("delete"); 79 | } else { 80 | $memc->set($key, $key, $exp); 81 | $stop->("set"); 82 | } 83 | $rand = int(rand($max)); 84 | $key = key($rand); 85 | $start->(); 86 | my $v = $memc->get($key); 87 | $stop->("get"); 88 | if ($v && $v ne $key) { die "Bogus: $v for key $rand\n"; } 89 | } 90 | 91 | $start->(); 92 | my $multi = $memc->get_multi(map { key(int(rand($max))) } (1..$max)); 93 | $stop->("get_multi"); 94 | } 95 | 96 | sub key { 97 | my $n = shift; 98 | $_ = sprintf("%04d", $n); 99 | if ($n % 2) { $_ .= "a"x20; } 100 | $_; 101 | } 102 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/touch.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 4; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | 10 | my $server = new_memcached(); 11 | my $sock = $server->sock; 12 | 13 | # set foo (and should get it) 14 | print $sock "set foo 0 2 6\r\nfooval\r\n"; 15 | is(scalar <$sock>, "STORED\r\n", "stored foo"); 16 | mem_get_is($sock, "foo", "fooval"); 17 | 18 | # touch it 19 | print $sock "touch foo 10\r\n"; 20 | is(scalar <$sock>, "TOUCHED\r\n", "touched foo"); 21 | 22 | sleep 2; 23 | mem_get_is($sock, "foo", "fooval"); 24 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/unixsocket.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 3; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $filename = "/tmp/memcachetest$$"; 10 | 11 | my $server = new_memcached("-s $filename"); 12 | my $sock = $server->sock; 13 | 14 | ok(-S $filename, "creating unix domain socket $filename"); 15 | 16 | # set foo (and should get it) 17 | print $sock "set foo 0 0 6\r\nfooval\r\n"; 18 | 19 | is(scalar <$sock>, "STORED\r\n", "stored foo"); 20 | mem_get_is($sock, "foo", "fooval"); 21 | 22 | unlink($filename); 23 | 24 | ## Just some basic stuff for now... 25 | -------------------------------------------------------------------------------- /memcached-1.4.15/t/whitespace.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use strict; 3 | use FindBin qw($Bin); 4 | our @files; 5 | 6 | BEGIN { 7 | chdir "$Bin/.." or die; 8 | 9 | my @exempted = qw(Makefile.am ChangeLog doc/Makefile.am README README.md); 10 | push(@exempted, glob("doc/*.xml")); 11 | push(@exempted, glob("doc/xml2rfc/*.xsl")); 12 | push(@exempted, glob("m4/*backport*m4")); 13 | push(@exempted, glob("*.orig")); 14 | my %exempted_hash = map { $_ => 1 } @exempted; 15 | 16 | my @stuff = split /\0/, `git ls-files -z -c -m -o --exclude-standard`; 17 | @files = grep { ! $exempted_hash{$_} } @stuff; 18 | 19 | # We won't find any files if git isn't installed. If git isn't 20 | # installed, they're probably not doing any useful development, or 21 | # at the very least am will clean up whitespace when we receive 22 | # their patch. 23 | unless (@files) { 24 | use Test::More; 25 | plan skip_all => "Skipping tests probably because you don't have git."; 26 | exit 0; 27 | } 28 | } 29 | 30 | use Test::More tests => scalar(@files); 31 | 32 | foreach my $f (@files) { 33 | open(my $fh, $f) or die "Cannot open file $f: $!"; 34 | my $before = do { local $/; <$fh>; }; 35 | close ($fh); 36 | my $after = $before; 37 | $after =~ s/\t/ /g; 38 | $after =~ s/ +$//mg; 39 | $after .= "\n" unless $after =~ /\n$/; 40 | ok ($after eq $before, "$f (see devtools/clean-whitespace.pl)"); 41 | } 42 | -------------------------------------------------------------------------------- /memcached-1.4.15/timedrun.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | static int caught = 0; 11 | 12 | static void caught_signal(int which) 13 | { 14 | caught = which; 15 | } 16 | 17 | static int wait_for_process(pid_t pid) 18 | { 19 | int rv = EX_SOFTWARE; 20 | int stats = 0; 21 | int i = 0; 22 | struct sigaction sig_handler; 23 | 24 | sig_handler.sa_handler = caught_signal; 25 | sig_handler.sa_flags = 0; 26 | 27 | sigaction(SIGALRM, &sig_handler, NULL); 28 | sigaction(SIGHUP, &sig_handler, NULL); 29 | sigaction(SIGINT, &sig_handler, NULL); 30 | sigaction(SIGTERM, &sig_handler, NULL); 31 | sigaction(SIGPIPE, &sig_handler, NULL); 32 | 33 | /* Loop forever waiting for the process to quit */ 34 | for (i = 0; ;i++) { 35 | pid_t p = waitpid(pid, &stats, 0); 36 | if (p == pid) { 37 | /* child exited. Let's get out of here */ 38 | rv = WIFEXITED(stats) ? 39 | WEXITSTATUS(stats) : 40 | (0x80 | WTERMSIG(stats)); 41 | break; 42 | } else { 43 | int sig = 0; 44 | switch (i) { 45 | case 0: 46 | /* On the first iteration, pass the signal through */ 47 | sig = caught > 0 ? caught : SIGTERM; 48 | if (caught == SIGALRM) { 49 | fprintf(stderr, "Timeout.. killing the process\n"); 50 | } 51 | break; 52 | case 1: 53 | sig = SIGTERM; 54 | break; 55 | default: 56 | sig = SIGKILL; 57 | break; 58 | } 59 | if (kill(pid, sig) < 0) { 60 | /* Kill failed. Must have lost the process. :/ */ 61 | perror("lost child when trying to kill"); 62 | } 63 | /* Wait up to 5 seconds for the pid */ 64 | alarm(5); 65 | } 66 | } 67 | return rv; 68 | } 69 | 70 | static int spawn_and_wait(char **argv) 71 | { 72 | int rv = EX_SOFTWARE; 73 | pid_t pid = fork(); 74 | 75 | switch (pid) { 76 | case -1: 77 | perror("fork"); 78 | rv = EX_OSERR; 79 | break; /* NOTREACHED */ 80 | case 0: 81 | execvp(argv[0], argv); 82 | perror("exec"); 83 | rv = EX_SOFTWARE; 84 | break; /* NOTREACHED */ 85 | default: 86 | rv = wait_for_process(pid); 87 | } 88 | return rv; 89 | } 90 | 91 | int main(int argc, char **argv) 92 | { 93 | int naptime = 0; 94 | assert(argc > 2); 95 | 96 | naptime = atoi(argv[1]); 97 | assert(naptime > 0 && naptime < 1800); 98 | 99 | alarm(naptime); 100 | 101 | return spawn_and_wait(argv+2); 102 | } 103 | -------------------------------------------------------------------------------- /memcached-1.4.15/trace.h: -------------------------------------------------------------------------------- 1 | #ifndef TRACE_H 2 | #define TRACE_H 3 | 4 | #ifdef ENABLE_DTRACE 5 | #include "memcached_dtrace.h" 6 | #else 7 | #define MEMCACHED_ASSOC_DELETE(arg0, arg1, arg2) 8 | #define MEMCACHED_ASSOC_DELETE_ENABLED() (0) 9 | #define MEMCACHED_ASSOC_FIND(arg0, arg1, arg2) 10 | #define MEMCACHED_ASSOC_FIND_ENABLED() (0) 11 | #define MEMCACHED_ASSOC_INSERT(arg0, arg1, arg2) 12 | #define MEMCACHED_ASSOC_INSERT_ENABLED() (0) 13 | #define MEMCACHED_COMMAND_ADD(arg0, arg1, arg2, arg3, arg4) 14 | #define MEMCACHED_COMMAND_ADD_ENABLED() (0) 15 | #define MEMCACHED_COMMAND_APPEND(arg0, arg1, arg2, arg3, arg4) 16 | #define MEMCACHED_COMMAND_APPEND_ENABLED() (0) 17 | #define MEMCACHED_COMMAND_CAS(arg0, arg1, arg2, arg3, arg4) 18 | #define MEMCACHED_COMMAND_CAS_ENABLED() (0) 19 | #define MEMCACHED_COMMAND_DECR(arg0, arg1, arg2, arg3) 20 | #define MEMCACHED_COMMAND_DECR_ENABLED() (0) 21 | #define MEMCACHED_COMMAND_DELETE(arg0, arg1, arg2) 22 | #define MEMCACHED_COMMAND_DELETE_ENABLED() (0) 23 | #define MEMCACHED_COMMAND_GET(arg0, arg1, arg2, arg3, arg4) 24 | #define MEMCACHED_COMMAND_GET_ENABLED() (0) 25 | #define MEMCACHED_COMMAND_TOUCH(arg0, arg1, arg2, arg3, arg4) 26 | #define MEMCACHED_COMMAND_TOUCH_ENABLED() (0) 27 | #define MEMCACHED_COMMAND_INCR(arg0, arg1, arg2, arg3) 28 | #define MEMCACHED_COMMAND_INCR_ENABLED() (0) 29 | #define MEMCACHED_COMMAND_PREPEND(arg0, arg1, arg2, arg3, arg4) 30 | #define MEMCACHED_COMMAND_PREPEND_ENABLED() (0) 31 | #define MEMCACHED_COMMAND_REPLACE(arg0, arg1, arg2, arg3, arg4) 32 | #define MEMCACHED_COMMAND_REPLACE_ENABLED() (0) 33 | #define MEMCACHED_COMMAND_SET(arg0, arg1, arg2, arg3, arg4) 34 | #define MEMCACHED_COMMAND_SET_ENABLED() (0) 35 | #define MEMCACHED_CONN_ALLOCATE(arg0) 36 | #define MEMCACHED_CONN_ALLOCATE_ENABLED() (0) 37 | #define MEMCACHED_CONN_CREATE(arg0) 38 | #define MEMCACHED_CONN_CREATE_ENABLED() (0) 39 | #define MEMCACHED_CONN_DESTROY(arg0) 40 | #define MEMCACHED_CONN_DESTROY_ENABLED() (0) 41 | #define MEMCACHED_CONN_DISPATCH(arg0, arg1) 42 | #define MEMCACHED_CONN_DISPATCH_ENABLED() (0) 43 | #define MEMCACHED_CONN_RELEASE(arg0) 44 | #define MEMCACHED_CONN_RELEASE_ENABLED() (0) 45 | #define MEMCACHED_ITEM_LINK(arg0, arg1, arg2) 46 | #define MEMCACHED_ITEM_LINK_ENABLED() (0) 47 | #define MEMCACHED_ITEM_REMOVE(arg0, arg1, arg2) 48 | #define MEMCACHED_ITEM_REMOVE_ENABLED() (0) 49 | #define MEMCACHED_ITEM_REPLACE(arg0, arg1, arg2, arg3, arg4, arg5) 50 | #define MEMCACHED_ITEM_REPLACE_ENABLED() (0) 51 | #define MEMCACHED_ITEM_UNLINK(arg0, arg1, arg2) 52 | #define MEMCACHED_ITEM_UNLINK_ENABLED() (0) 53 | #define MEMCACHED_ITEM_UPDATE(arg0, arg1, arg2) 54 | #define MEMCACHED_ITEM_UPDATE_ENABLED() (0) 55 | #define MEMCACHED_PROCESS_COMMAND_END(arg0, arg1, arg2) 56 | #define MEMCACHED_PROCESS_COMMAND_END_ENABLED() (0) 57 | #define MEMCACHED_PROCESS_COMMAND_START(arg0, arg1, arg2) 58 | #define MEMCACHED_PROCESS_COMMAND_START_ENABLED() (0) 59 | #define MEMCACHED_SLABS_ALLOCATE(arg0, arg1, arg2, arg3) 60 | #define MEMCACHED_SLABS_ALLOCATE_ENABLED() (0) 61 | #define MEMCACHED_SLABS_ALLOCATE_FAILED(arg0, arg1) 62 | #define MEMCACHED_SLABS_ALLOCATE_FAILED_ENABLED() (0) 63 | #define MEMCACHED_SLABS_FREE(arg0, arg1, arg2) 64 | #define MEMCACHED_SLABS_FREE_ENABLED() (0) 65 | #define MEMCACHED_SLABS_SLABCLASS_ALLOCATE(arg0) 66 | #define MEMCACHED_SLABS_SLABCLASS_ALLOCATE_ENABLED() (0) 67 | #define MEMCACHED_SLABS_SLABCLASS_ALLOCATE_FAILED(arg0) 68 | #define MEMCACHED_SLABS_SLABCLASS_ALLOCATE_FAILED_ENABLED() (0) 69 | #endif 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /memcached-1.4.15/util.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "memcached.h" 10 | 11 | /* Avoid warnings on solaris, where isspace() is an index into an array, and gcc uses signed chars */ 12 | #define xisspace(c) isspace((unsigned char)c) 13 | 14 | bool safe_strtoull(const char *str, uint64_t *out) { 15 | assert(out != NULL); 16 | errno = 0; 17 | *out = 0; 18 | char *endptr; 19 | unsigned long long ull = strtoull(str, &endptr, 10); 20 | if ((errno == ERANGE) || (str == endptr)) { 21 | return false; 22 | } 23 | 24 | if (xisspace(*endptr) || (*endptr == '\0' && endptr != str)) { 25 | if ((long long) ull < 0) { 26 | /* only check for negative signs in the uncommon case when 27 | * the unsigned number is so big that it's negative as a 28 | * signed number. */ 29 | if (strchr(str, '-') != NULL) { 30 | return false; 31 | } 32 | } 33 | *out = ull; 34 | return true; 35 | } 36 | return false; 37 | } 38 | 39 | bool safe_strtoll(const char *str, int64_t *out) { 40 | assert(out != NULL); 41 | errno = 0; 42 | *out = 0; 43 | char *endptr; 44 | long long ll = strtoll(str, &endptr, 10); 45 | if ((errno == ERANGE) || (str == endptr)) { 46 | return false; 47 | } 48 | 49 | if (xisspace(*endptr) || (*endptr == '\0' && endptr != str)) { 50 | *out = ll; 51 | return true; 52 | } 53 | return false; 54 | } 55 | 56 | bool safe_strtoul(const char *str, uint32_t *out) { 57 | char *endptr = NULL; 58 | unsigned long l = 0; 59 | assert(out); 60 | assert(str); 61 | *out = 0; 62 | errno = 0; 63 | 64 | l = strtoul(str, &endptr, 10); 65 | if ((errno == ERANGE) || (str == endptr)) { 66 | return false; 67 | } 68 | 69 | if (xisspace(*endptr) || (*endptr == '\0' && endptr != str)) { 70 | if ((long) l < 0) { 71 | /* only check for negative signs in the uncommon case when 72 | * the unsigned number is so big that it's negative as a 73 | * signed number. */ 74 | if (strchr(str, '-') != NULL) { 75 | return false; 76 | } 77 | } 78 | *out = l; 79 | return true; 80 | } 81 | 82 | return false; 83 | } 84 | 85 | bool safe_strtol(const char *str, int32_t *out) { 86 | assert(out != NULL); 87 | errno = 0; 88 | *out = 0; 89 | char *endptr; 90 | long l = strtol(str, &endptr, 10); 91 | if ((errno == ERANGE) || (str == endptr)) { 92 | return false; 93 | } 94 | 95 | if (xisspace(*endptr) || (*endptr == '\0' && endptr != str)) { 96 | *out = l; 97 | return true; 98 | } 99 | return false; 100 | } 101 | 102 | void vperror(const char *fmt, ...) { 103 | int old_errno = errno; 104 | char buf[1024]; 105 | va_list ap; 106 | 107 | va_start(ap, fmt); 108 | if (vsnprintf(buf, sizeof(buf), fmt, ap) == -1) { 109 | buf[sizeof(buf) - 1] = '\0'; 110 | } 111 | va_end(ap); 112 | 113 | errno = old_errno; 114 | 115 | perror(buf); 116 | } 117 | 118 | #ifndef HAVE_HTONLL 119 | static uint64_t mc_swap64(uint64_t in) { 120 | #ifdef ENDIAN_LITTLE 121 | /* Little endian, flip the bytes around until someone makes a faster/better 122 | * way to do this. */ 123 | int64_t rv = 0; 124 | int i = 0; 125 | for(i = 0; i<8; i++) { 126 | rv = (rv << 8) | (in & 0xff); 127 | in >>= 8; 128 | } 129 | return rv; 130 | #else 131 | /* big-endian machines don't need byte swapping */ 132 | return in; 133 | #endif 134 | } 135 | 136 | uint64_t ntohll(uint64_t val) { 137 | return mc_swap64(val); 138 | } 139 | 140 | uint64_t htonll(uint64_t val) { 141 | return mc_swap64(val); 142 | } 143 | #endif 144 | 145 | -------------------------------------------------------------------------------- /memcached-1.4.15/util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Wrappers around strtoull/strtoll that are safer and easier to 3 | * use. For tests and assumptions, see internal_tests.c. 4 | * 5 | * str a NULL-terminated base decimal 10 unsigned integer 6 | * out out parameter, if conversion succeeded 7 | * 8 | * returns true if conversion succeeded. 9 | */ 10 | bool safe_strtoull(const char *str, uint64_t *out); 11 | bool safe_strtoll(const char *str, int64_t *out); 12 | bool safe_strtoul(const char *str, uint32_t *out); 13 | bool safe_strtol(const char *str, int32_t *out); 14 | 15 | #ifndef HAVE_HTONLL 16 | extern uint64_t htonll(uint64_t); 17 | extern uint64_t ntohll(uint64_t); 18 | #endif 19 | 20 | #ifdef __GCC 21 | # define __gcc_attribute__ __attribute__ 22 | #else 23 | # define __gcc_attribute__(x) 24 | #endif 25 | 26 | /** 27 | * Vararg variant of perror that makes for more useful error messages 28 | * when reporting with parameters. 29 | * 30 | * @param fmt a printf format 31 | */ 32 | void vperror(const char *fmt, ...) 33 | __gcc_attribute__ ((format (printf, 1, 2))); 34 | -------------------------------------------------------------------------------- /memcached-1.4.15/version.m4: -------------------------------------------------------------------------------- 1 | m4_define([VERSION_NUMBER], [1.4.15]) 2 | --------------------------------------------------------------------------------