├── .gitignore ├── ChangeLog ├── LICENSE ├── Makefile.am ├── NOTICE ├── README.md ├── conf └── vire.conf ├── configure.ac ├── dep ├── .gitignore ├── Makefile.am ├── ae │ ├── Makefile.am │ ├── ae.c │ ├── ae.h │ ├── ae_epoll.c │ ├── ae_evport.c │ ├── ae_kqueue.c │ └── ae_select.c ├── darray │ ├── Makefile.am │ ├── darray.c │ └── darray.h ├── dhashkit │ ├── Makefile.am │ ├── dcrc16.c │ ├── dcrc32.c │ ├── dfnv.c │ ├── dhashkit.h │ ├── dhsieh.c │ ├── djenkins.c │ ├── dketama.c │ ├── dmd5.c │ ├── dmodula.c │ ├── dmurmur.c │ ├── done_at_a_time.c │ ├── drandom.c │ └── dsha1.c ├── dlist │ ├── Makefile.am │ ├── dlist.c │ ├── dlist.h │ ├── dlockqueue.c │ ├── dlockqueue.h │ ├── dmtqueue.c │ └── dmtqueue.h ├── dmalloc │ ├── Makefile.am │ ├── dmalloc.c │ └── dmalloc.h ├── himemcached-0.1.0 │ ├── Makefile.am │ ├── himcdep │ │ ├── sds.c │ │ └── sds.h │ ├── himcread.c │ ├── himcread.h │ ├── himemcached.c │ └── himemcached.h ├── hiredis-0.13.3.tar.gz ├── hiredis-0.13.3 │ └── .gitignore ├── jemalloc-4.2.0.tar.bz2 ├── jemalloc-4.2.0 │ └── .gitignore ├── sds │ ├── Makefile.am │ ├── sds.c │ ├── sds.h │ └── sdsalloc.h └── util │ ├── Makefile.am │ ├── dlog.c │ ├── dlog.h │ ├── dspecialconfig.h │ ├── dutil.c │ └── dutil.h ├── m4 └── .gitignore ├── notes ├── c-styleguide.txt ├── debug.txt ├── kqueue.pdf └── socket.txt ├── scripts └── .gitignore ├── src ├── Makefile.am ├── vr.c ├── vr_aof.c ├── vr_aof.h ├── vr_backend.c ├── vr_backend.h ├── vr_bitops.c ├── vr_bitops.h ├── vr_block.c ├── vr_block.h ├── vr_client.c ├── vr_client.h ├── vr_command.c ├── vr_command.h ├── vr_conf.c ├── vr_conf.h ├── vr_connection.c ├── vr_connection.h ├── vr_core.c ├── vr_core.h ├── vr_db.c ├── vr_db.h ├── vr_dict.c ├── vr_dict.h ├── vr_eventloop.c ├── vr_eventloop.h ├── vr_hyperloglog.c ├── vr_hyperloglog.h ├── vr_intset.c ├── vr_intset.h ├── vr_listen.c ├── vr_listen.h ├── vr_lzf.h ├── vr_lzfP.h ├── vr_lzf_c.c ├── vr_lzf_d.c ├── vr_master.c ├── vr_master.h ├── vr_multi.c ├── vr_multi.h ├── vr_notify.c ├── vr_notify.h ├── vr_object.c ├── vr_object.h ├── vr_pubsub.c ├── vr_pubsub.h ├── vr_quicklist.c ├── vr_quicklist.h ├── vr_rbtree.c ├── vr_rbtree.h ├── vr_rdb.c ├── vr_rdb.h ├── vr_replication.c ├── vr_replication.h ├── vr_scripting.c ├── vr_scripting.h ├── vr_server.c ├── vr_server.h ├── vr_signal.c ├── vr_signal.h ├── vr_slowlog.c ├── vr_slowlog.h ├── vr_stats.c ├── vr_stats.h ├── vr_t_hash.c ├── vr_t_hash.h ├── vr_t_list.c ├── vr_t_list.h ├── vr_t_set.c ├── vr_t_set.h ├── vr_t_string.c ├── vr_t_string.h ├── vr_t_zset.c ├── vr_t_zset.h ├── vr_thread.c ├── vr_thread.h ├── vr_util.c ├── vr_util.h ├── vr_worker.c ├── vr_worker.h ├── vr_ziplist.c ├── vr_ziplist.h ├── vr_zipmap.c └── vr_zipmap.h ├── tests ├── .gitignore ├── Makefile.am ├── vrabtest.c ├── vrabtest.h ├── vrt_backend.c ├── vrt_backend.h ├── vrt_benchmark.c ├── vrt_check_data.c ├── vrt_check_data.h ├── vrt_dispatch_data.c ├── vrt_dispatch_data.h ├── vrt_produce_data.c ├── vrt_produce_data.h ├── vrt_public.c ├── vrt_public.h ├── vrt_simple.c ├── vrt_simple.h ├── vrt_util.c ├── vrt_util.h └── vrtest.c └── tools └── .gitignore /.gitignore: -------------------------------------------------------------------------------- 1 | # pyc 2 | *.pyc 3 | 4 | # Compiled Object files 5 | *.lo 6 | *.o 7 | 8 | # Compiled Dynamic libraries 9 | *.so 10 | 11 | # Compiled Static libraries 12 | *.la 13 | *.a 14 | 15 | # Compiled misc 16 | *.dep 17 | *.gcda 18 | *.gcno 19 | *.gcov 20 | 21 | # Packages 22 | *.tar.gz 23 | *.tar.bz2 24 | 25 | # Logs 26 | *.log 27 | 28 | # vire 29 | *.swp 30 | *.~ 31 | *.project 32 | *.cproject 33 | 34 | # Core and executable 35 | core* 36 | vire 37 | 38 | # extracted jemalloc 39 | !/dep/jemalloc-* 40 | 41 | # Autotools 42 | .deps 43 | .libs 44 | 45 | /aclocal.m4 46 | /autom4te.cache 47 | /stamp-h1 48 | /autoscan.log 49 | /libtool 50 | 51 | /config/config.guess 52 | /config/config.sub 53 | /config/depcomp 54 | /config/install-sh 55 | /config/ltmain.sh 56 | /config/missing 57 | /config 58 | 59 | /config.h 60 | /config.h.in 61 | /config.h.in~ 62 | /config.log 63 | /config.status 64 | /configure.scan 65 | /configure 66 | 67 | Makefile 68 | Makefile.in 69 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2016-10-25 deep011 2 | * vire: version 1.0.0 release 3 | vire (pronounced "vip-redis") is a multithread redis(based on redis-3.2.0) maintains in vipshop. 4 | multi-threads support. 5 | command type CONNECTION supported: ping,quit,echo,select,auth,admin. 6 | command type SERVER supported: info,flushall,flushdb,time,dbsize,command,config,client,slowlog. 7 | command type KEY supported: del,exists,ttl,pttl,expire,expireat,pexpire,pexpireat,persist,randomkey,type,keys,scan,object. 8 | command type STRING supported: get,set,setnx,setex,psetex,incr,decr,incrby,decrby,append,strlen,getset,incrbyfloat,setbit,getbit,setrange,getrange,bitcount,bitpos,mget,mset. 9 | command type HASH supported: hset,hget,hlen,hdel,hexists,hkeys,hvals,hgetall,hincrby,hincrbyfloat,hmget,hmset,hsetnx,hstrlen,hscan. 10 | command type LIST supported: rpush,lpush,lrange,rpop,lpop,llen,lrem,ltrim,lindex,lset. 11 | command type SET supported: sadd,smembers,scard,srem,spop,sismember,sscan,sunion,sunionstore,sdiff,sdiffstore,sinter,sinterstore. 12 | command type SORTEDSET supported: zadd,zincrby,zrange,zrevrange,zrem,zcard,zcount,zrangebyscore,zrevrangebyscore,zrank,zrevrank,zscore,zremrangebyscore,zremrangebyrank,zremrangebylex,zscan. 13 | command type HYPERLOGLOG supported: pfadd,pfcount. 14 | config option added(used for config file and 'config get/set' command): port,databases,internal-dbs-per-databases,requirepass,adminpass,commands-need-adminpass,maxclients,maxmemory,maxmemory-policy,maxmemory-samples,max-time-complexity-limit,slowlog-log-slower-than,slowlog-max-len. 15 | viretest added that is for unit test. 16 | vireabtest added that is for compare command execution and data consistency with redis-3.2.0. 17 | vire-benchmark added that is modified from redis-benchmark but multi-threads supported and pressure test vire. -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | MAINTAINERCLEANFILES = Makefile.in aclocal.m4 configure config.h.in config.h.in~ stamp-h.in 2 | 3 | ACLOCAL_AMFLAGS = -I m4 4 | 5 | SUBDIRS = dep src tests 6 | 7 | EXTRA_DIST = README.md NOTICE LICENSE ChangeLog conf scripts notes 8 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vipshop/vire/fdb7db80f875877098cb5e7feaeb618ee2ddbb7b/NOTICE -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vire 2 | 3 | **vire** (pronounced "vip-redis") is a multithread redis(based on redis-3.2.0) maintains in vipshop. 4 | 5 | ### QQ交流群:276406429 6 | 7 | ## Dependence 8 | 9 | Please install automake, libtool, autoconf and bzip2 at first. 10 | 11 | ## Build 12 | 13 | To build vire from source with _debug logs enabled_ and _assertions enabled_: 14 | 15 | $ git clone https://github.com/vipshop/vire.git 16 | $ cd vire 17 | $ autoreconf -fvi 18 | $ ./configure --enable-debug=full 19 | $ make 20 | $ src/vire -h 21 | 22 | A quick checklist: 23 | 24 | + Use newer version of gcc (older version of gcc has problems) 25 | + Use CFLAGS="-O1" ./configure && make 26 | + Use CFLAGS="-O3 -fno-strict-aliasing" ./configure && make 27 | + `autoreconf -fvi && ./configure` needs `automake` and `libtool` to be installed 28 | 29 | ## Run 30 | 31 | $ src/vire -c conf/vire.conf -o log -T 6 -d 32 | 33 | ## Features 34 | 35 | + Multithread. 36 | + Fast. 37 | + Works with Linux, *BSD, OS X and SmartOS (Solaris) 38 | 39 | ## Help 40 | 41 | Usage: vire [-?hVdt] [-v verbosity level] [-o output file] 42 | [-c conf file] [-p pid file] 43 | [-T worker threads number] 44 | 45 | Options: 46 | -h, --help : this help 47 | -V, --version : show version and exit 48 | -t, --test-conf : test configuration for syntax errors and exit 49 | -d, --daemonize : run as a daemon 50 | -v, --verbose=N : set logging level (default: 5, min: 0, max: 11) 51 | -o, --output=S : set logging file (default: stderr) 52 | -c, --conf-file=S : set configuration file (default: conf/vire.conf) 53 | -p, --pid-file=S : set pid file (default: off) 54 | -T, --thread_num=N : set the worker threads number (default: 6) 55 | 56 | ## Support redis command so far 57 | 58 | #### Connection 59 | 60 | + ping 61 | + quit 62 | + echo 63 | + select 64 | + auth 65 | + admin 66 | 67 | #### Server 68 | 69 | + info 70 | + flushall 71 | + flushdb 72 | + time 73 | + dbsize 74 | + command 75 | + config 76 | + client 77 | + slowlog 78 | 79 | #### Key 80 | 81 | + del 82 | + exists 83 | + ttl 84 | + pttl 85 | + expire 86 | + expireat 87 | + pexpire 88 | + pexpireat 89 | + persist 90 | + randomkey 91 | + type 92 | + keys 93 | + scan 94 | + object 95 | 96 | #### String 97 | 98 | + get 99 | + set 100 | + setnx 101 | + setex 102 | + psetex 103 | + incr 104 | + decr 105 | + incrby 106 | + decrby 107 | + append 108 | + strlen 109 | + getset 110 | + incrbyfloat 111 | + setbit 112 | + getbit 113 | + setrange 114 | + getrange 115 | + bitcount 116 | + bitpos 117 | + mget 118 | + mset 119 | 120 | #### Hash 121 | 122 | + hset 123 | + hget 124 | + hlen 125 | + hdel 126 | + hexists 127 | + hkeys 128 | + hvals 129 | + hgetall 130 | + hincrby 131 | + hincrbyfloat 132 | + hmget 133 | + hmset 134 | + hsetnx 135 | + hstrlen 136 | + hscan 137 | 138 | #### List 139 | 140 | + rpush 141 | + lpush 142 | + lrange 143 | + rpop 144 | + lpop 145 | + llen 146 | + lrem 147 | + ltrim 148 | + lindex 149 | + lset 150 | 151 | #### Set 152 | 153 | + sadd 154 | + smembers 155 | + scard 156 | + srem 157 | + spop 158 | + sismember 159 | + sscan 160 | + sunion 161 | + sunionstore 162 | + sdiff 163 | + sdiffstore 164 | + sinter 165 | + sinterstore 166 | 167 | #### SortedSet 168 | 169 | + zadd 170 | + zincrby 171 | + zrange 172 | + zrevrange 173 | + zrem 174 | + zcard 175 | + zcount 176 | + zrangebyscore 177 | + zrevrangebyscore 178 | + zrank 179 | + zrevrank 180 | + zscore 181 | + zremrangebyscore 182 | + zremrangebyrank 183 | + zremrangebylex 184 | + zscan 185 | 186 | #### HyperLogLog 187 | 188 | + pfadd 189 | + pfcount 190 | 191 | ## License 192 | 193 | Copyright © 2016 VIPSHOP Inc. 194 | 195 | Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 196 | -------------------------------------------------------------------------------- /dep/.gitignore: -------------------------------------------------------------------------------- 1 | !*.tar.gz -------------------------------------------------------------------------------- /dep/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = jemalloc-4.2.0 hiredis-0.13.3 himemcached-0.1.0 util dhashkit dmalloc ae sds dlist darray 2 | 3 | EXTRA_DIST = jemalloc-4.2.0.tar.bz2 hiredis-0.13.3.tar.gz 4 | -------------------------------------------------------------------------------- /dep/ae/Makefile.am: -------------------------------------------------------------------------------- 1 | MAINTAINERCLEANFILES = Makefile.in 2 | 3 | AM_CPPFLAGS = 4 | if !OS_SOLARIS 5 | AM_CPPFLAGS += -D_GNU_SOURCE 6 | endif 7 | AM_CPPFLAGS += -I $(top_srcdir)/dep/util 8 | AM_CPPFLAGS += -I $(top_srcdir)/dep/jemalloc-4.2.0/include 9 | AM_CPPFLAGS += -I $(top_srcdir)/dep/dmalloc 10 | 11 | AM_CFLAGS = -Wall -Wshadow 12 | AM_CFLAGS += -Wno-unused-parameter -Wno-unused-value 13 | 14 | noinst_LIBRARIES = libae.a 15 | 16 | noinst_HEADERS = ae.h 17 | 18 | libae_a_SOURCES = \ 19 | ae.c ae.h -------------------------------------------------------------------------------- /dep/ae/ae.h: -------------------------------------------------------------------------------- 1 | /* A simple event-driven programming library. Originally I wrote this code 2 | * for the Jim's event-loop (Jim is a Tcl interpreter) but later translated 3 | * it in form of a library for easy reuse. 4 | * 5 | * Copyright (c) 2006-2012, Salvatore Sanfilippo 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 11 | * * Redistributions of source code must retain the above copyright notice, 12 | * this list of conditions and the following disclaimer. 13 | * * Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * * Neither the name of Redis nor the names of its contributors may be used 17 | * to endorse or promote products derived from this software without 18 | * specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | * POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #ifndef __AE_H__ 34 | #define __AE_H__ 35 | 36 | #include 37 | 38 | #define AE_OK 0 39 | #define AE_ERR -1 40 | 41 | #define AE_NONE 0 42 | #define AE_READABLE 1 43 | #define AE_WRITABLE 2 44 | 45 | #define AE_FILE_EVENTS 1 46 | #define AE_TIME_EVENTS 2 47 | #define AE_ALL_EVENTS (AE_FILE_EVENTS|AE_TIME_EVENTS) 48 | #define AE_DONT_WAIT 4 49 | 50 | #define AE_NOMORE -1 51 | #define AE_DELETED_EVENT_ID -1 52 | 53 | /* Macros */ 54 | #define AE_NOTUSED(V) ((void) V) 55 | 56 | struct aeEventLoop; 57 | 58 | /* Types and data structures */ 59 | typedef void aeFileProc(struct aeEventLoop *eventLoop, int fd, void *clientData, int mask); 60 | typedef int aeTimeProc(struct aeEventLoop *eventLoop, long long id, void *clientData); 61 | typedef void aeEventFinalizerProc(struct aeEventLoop *eventLoop, void *clientData); 62 | typedef void aeBeforeSleepProc(struct aeEventLoop *eventLoop, void *private_data); 63 | 64 | /* File event structure */ 65 | typedef struct aeFileEvent { 66 | int mask; /* one of AE_(READABLE|WRITABLE) */ 67 | aeFileProc *rfileProc; 68 | aeFileProc *wfileProc; 69 | void *clientData; 70 | } aeFileEvent; 71 | 72 | /* Time event structure */ 73 | typedef struct aeTimeEvent { 74 | long long id; /* time event identifier. */ 75 | long when_sec; /* seconds */ 76 | long when_ms; /* milliseconds */ 77 | aeTimeProc *timeProc; 78 | aeEventFinalizerProc *finalizerProc; 79 | void *clientData; 80 | struct aeTimeEvent *next; 81 | } aeTimeEvent; 82 | 83 | /* A fired event */ 84 | typedef struct aeFiredEvent { 85 | int fd; 86 | int mask; 87 | } aeFiredEvent; 88 | 89 | /* State of an event based program */ 90 | typedef struct aeEventLoop { 91 | int maxfd; /* highest file descriptor currently registered */ 92 | int setsize; /* max number of file descriptors tracked */ 93 | long long timeEventNextId; 94 | time_t lastTime; /* Used to detect system clock skew */ 95 | aeFileEvent *events; /* Registered events */ 96 | aeFiredEvent *fired; /* Fired events */ 97 | aeTimeEvent *timeEventHead; 98 | int stop; 99 | void *apidata; /* This is used for polling API specific data */ 100 | aeBeforeSleepProc *beforesleep; 101 | void *bsdata; /* This is used for beforesleep private data */ 102 | } aeEventLoop; 103 | 104 | /* Prototypes */ 105 | aeEventLoop *aeCreateEventLoop(int setsize); 106 | void aeDeleteEventLoop(aeEventLoop *eventLoop); 107 | void aeStop(aeEventLoop *eventLoop); 108 | int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask, 109 | aeFileProc *proc, void *clientData); 110 | void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask); 111 | int aeGetFileEvents(aeEventLoop *eventLoop, int fd); 112 | long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds, 113 | aeTimeProc *proc, void *clientData, 114 | aeEventFinalizerProc *finalizerProc); 115 | int aeDeleteTimeEvent(aeEventLoop *eventLoop, long long id); 116 | int aeProcessEvents(aeEventLoop *eventLoop, int flags); 117 | int aeWait(int fd, int mask, long long milliseconds); 118 | void aeMain(aeEventLoop *eventLoop); 119 | char *aeGetApiName(void); 120 | void aeSetBeforeSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *beforesleep, void *private_data); 121 | int aeGetSetSize(aeEventLoop *eventLoop); 122 | int aeResizeSetSize(aeEventLoop *eventLoop, int setsize); 123 | 124 | #endif 125 | -------------------------------------------------------------------------------- /dep/ae/ae_epoll.c: -------------------------------------------------------------------------------- 1 | /* Linux epoll(2) based ae.c module 2 | * 3 | * Copyright (c) 2009-2012, Salvatore Sanfilippo 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of Redis nor the names of its contributors may be used 15 | * to endorse or promote products derived from this software without 16 | * specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | 32 | #include 33 | 34 | typedef struct aeApiState { 35 | int epfd; 36 | struct epoll_event *events; 37 | } aeApiState; 38 | 39 | static int aeApiCreate(aeEventLoop *eventLoop) { 40 | aeApiState *state = dalloc(sizeof(aeApiState)); 41 | 42 | if (!state) return -1; 43 | state->events = dalloc(sizeof(struct epoll_event)*eventLoop->setsize); 44 | if (!state->events) { 45 | dfree(state); 46 | return -1; 47 | } 48 | state->epfd = epoll_create(1024); /* 1024 is just a hint for the kernel */ 49 | if (state->epfd == -1) { 50 | dfree(state->events); 51 | dfree(state); 52 | return -1; 53 | } 54 | eventLoop->apidata = state; 55 | return 0; 56 | } 57 | 58 | static int aeApiResize(aeEventLoop *eventLoop, int setsize) { 59 | aeApiState *state = eventLoop->apidata; 60 | 61 | state->events = drealloc(state->events, sizeof(struct epoll_event)*setsize); 62 | return 0; 63 | } 64 | 65 | static void aeApiFree(aeEventLoop *eventLoop) { 66 | aeApiState *state = eventLoop->apidata; 67 | 68 | close(state->epfd); 69 | dfree(state->events); 70 | dfree(state); 71 | } 72 | 73 | static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) { 74 | aeApiState *state = eventLoop->apidata; 75 | struct epoll_event ee = {0}; /* avoid valgrind warning */ 76 | /* If the fd was already monitored for some event, we need a MOD 77 | * operation. Otherwise we need an ADD operation. */ 78 | int op = eventLoop->events[fd].mask == AE_NONE ? 79 | EPOLL_CTL_ADD : EPOLL_CTL_MOD; 80 | 81 | ee.events = 0; 82 | mask |= eventLoop->events[fd].mask; /* Merge old events */ 83 | if (mask & AE_READABLE) ee.events |= EPOLLIN; 84 | if (mask & AE_WRITABLE) ee.events |= EPOLLOUT; 85 | ee.data.fd = fd; 86 | if (epoll_ctl(state->epfd,op,fd,&ee) == -1) return -1; 87 | return 0; 88 | } 89 | 90 | static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int delmask) { 91 | aeApiState *state = eventLoop->apidata; 92 | struct epoll_event ee = {0}; /* avoid valgrind warning */ 93 | int mask = eventLoop->events[fd].mask & (~delmask); 94 | 95 | ee.events = 0; 96 | if (mask & AE_READABLE) ee.events |= EPOLLIN; 97 | if (mask & AE_WRITABLE) ee.events |= EPOLLOUT; 98 | ee.data.fd = fd; 99 | if (mask != AE_NONE) { 100 | epoll_ctl(state->epfd,EPOLL_CTL_MOD,fd,&ee); 101 | } else { 102 | /* Note, Kernel < 2.6.9 requires a non null event pointer even for 103 | * EPOLL_CTL_DEL. */ 104 | epoll_ctl(state->epfd,EPOLL_CTL_DEL,fd,&ee); 105 | } 106 | } 107 | 108 | static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) { 109 | aeApiState *state = eventLoop->apidata; 110 | int retval, numevents = 0; 111 | 112 | retval = epoll_wait(state->epfd,state->events,eventLoop->setsize, 113 | tvp ? (tvp->tv_sec*1000 + tvp->tv_usec/1000) : -1); 114 | if (retval > 0) { 115 | int j; 116 | 117 | numevents = retval; 118 | for (j = 0; j < numevents; j++) { 119 | int mask = 0; 120 | struct epoll_event *e = state->events+j; 121 | 122 | if (e->events & EPOLLIN) mask |= AE_READABLE; 123 | if (e->events & EPOLLOUT) mask |= AE_WRITABLE; 124 | if (e->events & EPOLLERR) mask |= AE_WRITABLE; 125 | if (e->events & EPOLLHUP) mask |= AE_WRITABLE; 126 | eventLoop->fired[j].fd = e->data.fd; 127 | eventLoop->fired[j].mask = mask; 128 | } 129 | } 130 | return numevents; 131 | } 132 | 133 | static char *aeApiName(void) { 134 | return "epoll"; 135 | } 136 | -------------------------------------------------------------------------------- /dep/ae/ae_kqueue.c: -------------------------------------------------------------------------------- 1 | /* Kqueue(2)-based ae.c module 2 | * 3 | * Copyright (C) 2009 Harish Mallipeddi - harish.mallipeddi@gmail.com 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of Redis nor the names of its contributors may be used 15 | * to endorse or promote products derived from this software without 16 | * specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | typedef struct aeApiState { 37 | int kqfd; 38 | struct kevent *events; 39 | } aeApiState; 40 | 41 | static int aeApiCreate(aeEventLoop *eventLoop) { 42 | aeApiState *state = dalloc(sizeof(aeApiState)); 43 | 44 | if (!state) return -1; 45 | state->events = dalloc(sizeof(struct kevent)*eventLoop->setsize); 46 | if (!state->events) { 47 | dfree(state); 48 | return -1; 49 | } 50 | state->kqfd = kqueue(); 51 | if (state->kqfd == -1) { 52 | dfree(state->events); 53 | dfree(state); 54 | return -1; 55 | } 56 | eventLoop->apidata = state; 57 | return 0; 58 | } 59 | 60 | static int aeApiResize(aeEventLoop *eventLoop, int setsize) { 61 | aeApiState *state = eventLoop->apidata; 62 | 63 | state->events = drealloc(state->events, sizeof(struct kevent)*setsize); 64 | return 0; 65 | } 66 | 67 | static void aeApiFree(aeEventLoop *eventLoop) { 68 | aeApiState *state = eventLoop->apidata; 69 | 70 | close(state->kqfd); 71 | dfree(state->events); 72 | dfree(state); 73 | } 74 | 75 | static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) { 76 | aeApiState *state = eventLoop->apidata; 77 | struct kevent ke; 78 | 79 | if (mask & AE_READABLE) { 80 | EV_SET(&ke, fd, EVFILT_READ, EV_ADD, 0, 0, NULL); 81 | if (kevent(state->kqfd, &ke, 1, NULL, 0, NULL) == -1) return -1; 82 | } 83 | if (mask & AE_WRITABLE) { 84 | EV_SET(&ke, fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL); 85 | if (kevent(state->kqfd, &ke, 1, NULL, 0, NULL) == -1) return -1; 86 | } 87 | return 0; 88 | } 89 | 90 | static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) { 91 | aeApiState *state = eventLoop->apidata; 92 | struct kevent ke; 93 | 94 | if (mask & AE_READABLE) { 95 | EV_SET(&ke, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); 96 | kevent(state->kqfd, &ke, 1, NULL, 0, NULL); 97 | } 98 | if (mask & AE_WRITABLE) { 99 | EV_SET(&ke, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); 100 | kevent(state->kqfd, &ke, 1, NULL, 0, NULL); 101 | } 102 | } 103 | 104 | static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) { 105 | aeApiState *state = eventLoop->apidata; 106 | int retval, numevents = 0; 107 | 108 | if (tvp != NULL) { 109 | struct timespec timeout; 110 | timeout.tv_sec = tvp->tv_sec; 111 | timeout.tv_nsec = tvp->tv_usec * 1000; 112 | retval = kevent(state->kqfd, NULL, 0, state->events, eventLoop->setsize, 113 | &timeout); 114 | } else { 115 | retval = kevent(state->kqfd, NULL, 0, state->events, eventLoop->setsize, 116 | NULL); 117 | } 118 | 119 | if (retval > 0) { 120 | int j; 121 | 122 | numevents = retval; 123 | for(j = 0; j < numevents; j++) { 124 | int mask = 0; 125 | struct kevent *e = state->events+j; 126 | 127 | if (e->filter == EVFILT_READ) mask |= AE_READABLE; 128 | if (e->filter == EVFILT_WRITE) mask |= AE_WRITABLE; 129 | eventLoop->fired[j].fd = e->ident; 130 | eventLoop->fired[j].mask = mask; 131 | } 132 | } 133 | return numevents; 134 | } 135 | 136 | static char *aeApiName(void) { 137 | return "kqueue"; 138 | } 139 | -------------------------------------------------------------------------------- /dep/ae/ae_select.c: -------------------------------------------------------------------------------- 1 | /* Select()-based ae.c module. 2 | * 3 | * Copyright (c) 2009-2012, Salvatore Sanfilippo 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of Redis nor the names of its contributors may be used 15 | * to endorse or promote products derived from this software without 16 | * specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | 32 | #include 33 | 34 | typedef struct aeApiState { 35 | fd_set rfds, wfds; 36 | /* We need to have a copy of the fd sets as it's not safe to reuse 37 | * FD sets after select(). */ 38 | fd_set _rfds, _wfds; 39 | } aeApiState; 40 | 41 | static int aeApiCreate(aeEventLoop *eventLoop) { 42 | aeApiState *state = dalloc(sizeof(aeApiState)); 43 | 44 | if (!state) return -1; 45 | FD_ZERO(&state->rfds); 46 | FD_ZERO(&state->wfds); 47 | eventLoop->apidata = state; 48 | return 0; 49 | } 50 | 51 | static int aeApiResize(aeEventLoop *eventLoop, int setsize) { 52 | /* Just ensure we have enough room in the fd_set type. */ 53 | if (setsize >= FD_SETSIZE) return -1; 54 | return 0; 55 | } 56 | 57 | static void aeApiFree(aeEventLoop *eventLoop) { 58 | dfree(eventLoop->apidata); 59 | } 60 | 61 | static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) { 62 | aeApiState *state = eventLoop->apidata; 63 | 64 | if (mask & AE_READABLE) FD_SET(fd,&state->rfds); 65 | if (mask & AE_WRITABLE) FD_SET(fd,&state->wfds); 66 | return 0; 67 | } 68 | 69 | static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) { 70 | aeApiState *state = eventLoop->apidata; 71 | 72 | if (mask & AE_READABLE) FD_CLR(fd,&state->rfds); 73 | if (mask & AE_WRITABLE) FD_CLR(fd,&state->wfds); 74 | } 75 | 76 | static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) { 77 | aeApiState *state = eventLoop->apidata; 78 | int retval, j, numevents = 0; 79 | 80 | memcpy(&state->_rfds,&state->rfds,sizeof(fd_set)); 81 | memcpy(&state->_wfds,&state->wfds,sizeof(fd_set)); 82 | 83 | retval = select(eventLoop->maxfd+1, 84 | &state->_rfds,&state->_wfds,NULL,tvp); 85 | if (retval > 0) { 86 | for (j = 0; j <= eventLoop->maxfd; j++) { 87 | int mask = 0; 88 | aeFileEvent *fe = &eventLoop->events[j]; 89 | 90 | if (fe->mask == AE_NONE) continue; 91 | if (fe->mask & AE_READABLE && FD_ISSET(j,&state->_rfds)) 92 | mask |= AE_READABLE; 93 | if (fe->mask & AE_WRITABLE && FD_ISSET(j,&state->_wfds)) 94 | mask |= AE_WRITABLE; 95 | eventLoop->fired[numevents].fd = j; 96 | eventLoop->fired[numevents].mask = mask; 97 | numevents++; 98 | } 99 | } 100 | return numevents; 101 | } 102 | 103 | static char *aeApiName(void) { 104 | return "select"; 105 | } 106 | -------------------------------------------------------------------------------- /dep/darray/Makefile.am: -------------------------------------------------------------------------------- 1 | MAINTAINERCLEANFILES = Makefile.in 2 | 3 | AM_CPPFLAGS = 4 | if !OS_SOLARIS 5 | AM_CPPFLAGS += -D_GNU_SOURCE 6 | endif 7 | AM_CPPFLAGS += -I $(top_srcdir)/dep/util 8 | AM_CPPFLAGS += -I $(top_srcdir)/dep/jemalloc-4.2.0/include 9 | AM_CPPFLAGS += -I $(top_srcdir)/dep/dmalloc 10 | 11 | AM_CFLAGS = -Wall -Wshadow 12 | AM_CFLAGS += -Wno-unused-parameter -Wno-unused-value 13 | 14 | noinst_LIBRARIES = libdarray.a 15 | 16 | noinst_HEADERS = darray.h 17 | 18 | libdarray_a_SOURCES = \ 19 | darray.c darray.h -------------------------------------------------------------------------------- /dep/darray/darray.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | darray * 8 | darray_create(unsigned long long n, size_t size) 9 | { 10 | darray *a; 11 | 12 | a = dalloc(sizeof(*a)); 13 | if (a == NULL) { 14 | return NULL; 15 | } 16 | 17 | a->elem = dalloc(n * size); 18 | if (a->elem == NULL) { 19 | dfree(a); 20 | return NULL; 21 | } 22 | 23 | a->nelem = 0; 24 | a->size = size; 25 | a->nalloc = n; 26 | 27 | return a; 28 | } 29 | 30 | void 31 | darray_destroy(darray *a) 32 | { 33 | darray_deinit(a); 34 | dfree(a); 35 | } 36 | 37 | int 38 | darray_init(darray *a, unsigned long long n, size_t size) 39 | { 40 | a->elem = dalloc(n * size); 41 | if (a->elem == NULL) { 42 | return -1; 43 | } 44 | 45 | a->nelem = 0; 46 | a->size = size; 47 | a->nalloc = n; 48 | 49 | return 0; 50 | } 51 | 52 | void 53 | darray_deinit(darray *a) 54 | { 55 | if (a->elem != NULL) { 56 | dfree(a->elem); 57 | } 58 | } 59 | 60 | unsigned long long 61 | darray_idx(darray *a, void *elem) 62 | { 63 | char *p, *q; 64 | unsigned long long off, idx; 65 | 66 | p = a->elem; 67 | q = elem; 68 | off = (unsigned long long)(q - p); 69 | 70 | idx = off / (unsigned long long)a->size; 71 | 72 | return idx; 73 | } 74 | 75 | void * 76 | darray_push(darray *a) 77 | { 78 | void *elem, *new; 79 | size_t size; 80 | 81 | if (a->nelem == a->nalloc) { 82 | 83 | /* the array is full; allocate new array */ 84 | size = a->size * a->nalloc; 85 | new = drealloc(a->elem, 2 * size); 86 | if (new == NULL) { 87 | return NULL; 88 | } 89 | 90 | a->elem = new; 91 | a->nalloc *= 2; 92 | } 93 | 94 | elem = (char *)a->elem + a->size * a->nelem; 95 | a->nelem++; 96 | 97 | return elem; 98 | } 99 | 100 | void * 101 | darray_pop(darray *a) 102 | { 103 | void *elem; 104 | 105 | a->nelem--; 106 | elem = (char *)a->elem + a->size * a->nelem; 107 | 108 | return elem; 109 | } 110 | 111 | void * 112 | darray_get(darray *a, unsigned long long idx) 113 | { 114 | void *elem; 115 | 116 | elem = (char *)a->elem + (a->size * idx); 117 | 118 | return elem; 119 | } 120 | 121 | void * 122 | darray_top(darray *a) 123 | { 124 | return darray_get(a, a->nelem - 1); 125 | } 126 | 127 | void 128 | darray_swap(darray *a, darray *b) 129 | { 130 | darray tmp; 131 | 132 | tmp = *a; 133 | *a = *b; 134 | *b = tmp; 135 | } 136 | 137 | /* 138 | * Sort nelem elements of the array in ascending order based on the 139 | * compare comparator. 140 | */ 141 | void 142 | darray_sort(darray *a, darray_compare_t compare) 143 | { 144 | qsort(a->elem, a->nelem, a->size, compare); 145 | } 146 | 147 | /* 148 | * Calls the func once for each element in the array as long as func returns 149 | * success. On failure short-circuits and returns the error status. 150 | */ 151 | int 152 | darray_each(darray *a, darray_each_t func, void *data) 153 | { 154 | unsigned long long i, nelem; 155 | 156 | for (i = 0, nelem = darray_n(a); i < nelem; i++) { 157 | void *elem = darray_get(a, i); 158 | int ret; 159 | 160 | ret = func(elem, data); 161 | if (ret != 0) { 162 | return -1; 163 | } 164 | } 165 | 166 | return 0; 167 | } 168 | -------------------------------------------------------------------------------- /dep/darray/darray.h: -------------------------------------------------------------------------------- 1 | #ifndef _DARRAY_H_ 2 | #define _DARRAY_H_ 3 | 4 | typedef int (*darray_compare_t)(const void *, const void *); 5 | typedef int (*darray_each_t)(void *, void *); 6 | 7 | typedef struct darray { 8 | unsigned long long nelem; /* # element */ 9 | void *elem; /* element */ 10 | size_t size; /* element size */ 11 | unsigned long long nalloc; /* # allocated element */ 12 | } darray; 13 | 14 | #define null_darray { 0, NULL, 0, 0 } 15 | 16 | static inline void 17 | darray_null(darray *a) 18 | { 19 | a->nelem = 0; 20 | a->elem = NULL; 21 | a->size = 0; 22 | a->nalloc = 0; 23 | } 24 | 25 | static inline void 26 | darray_set(darray *a, void *elem, size_t size, unsigned long long nalloc) 27 | { 28 | a->nelem = 0; 29 | a->elem = elem; 30 | a->size = size; 31 | a->nalloc = nalloc; 32 | } 33 | 34 | static inline unsigned long long 35 | darray_n(const darray *a) 36 | { 37 | return a->nelem; 38 | } 39 | 40 | darray *darray_create(unsigned long long n, size_t size); 41 | void darray_destroy(darray *a); 42 | int darray_init(darray *a, unsigned long long n, size_t size); 43 | void darray_deinit(darray *a); 44 | 45 | unsigned long long darray_idx(darray *a, void *elem); 46 | void *darray_push(darray *a); 47 | void *darray_pop(darray *a); 48 | void *darray_get(darray *a, unsigned long long idx); 49 | void *darray_top(darray *a); 50 | void darray_swap(darray *a, darray *b); 51 | void darray_sort(darray *a, darray_compare_t compare); 52 | int darray_each(darray *a, darray_each_t func, void *data); 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /dep/dhashkit/Makefile.am: -------------------------------------------------------------------------------- 1 | MAINTAINERCLEANFILES = Makefile.in 2 | 3 | AM_CFLAGS = -Wall -Wshadow 4 | AM_CFLAGS += -Wno-unused-parameter -Wno-unused-value 5 | 6 | noinst_LIBRARIES = libdhashkit.a 7 | 8 | noinst_HEADERS = dhashkit.h 9 | 10 | libdhashkit_a_SOURCES = \ 11 | dhashkit.h \ 12 | dcrc16.c \ 13 | dcrc32.c \ 14 | dfnv.c \ 15 | dhsieh.c \ 16 | djenkins.c \ 17 | dketama.c \ 18 | dmd5.c \ 19 | dmodula.c \ 20 | dmurmur.c \ 21 | done_at_a_time.c \ 22 | drandom.c \ 23 | dsha1.c -------------------------------------------------------------------------------- /dep/dhashkit/dcrc16.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static const uint16_t crc16tab[256] = { 4 | 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 5 | 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 6 | 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 7 | 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 8 | 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 9 | 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 10 | 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 11 | 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 12 | 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 13 | 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 14 | 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 15 | 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 16 | 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 17 | 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 18 | 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 19 | 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 20 | 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 21 | 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 22 | 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 23 | 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 24 | 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 25 | 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 26 | 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 27 | 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 28 | 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 29 | 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 30 | 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 31 | 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 32 | 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 33 | 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 34 | 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 35 | 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0, 36 | }; 37 | 38 | uint32_t 39 | hash_crc16(const char *key, size_t key_length) 40 | { 41 | uint64_t x; 42 | uint32_t crc = 0; 43 | 44 | for (x=0; x < key_length; x++) { 45 | crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ *key++) & 0x00ff]; 46 | } 47 | 48 | return crc; 49 | } 50 | -------------------------------------------------------------------------------- /dep/dhashkit/dcrc32.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static const uint32_t crc32tab[256] = { 4 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 5 | 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 6 | 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 7 | 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 8 | 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 9 | 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 10 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 11 | 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 12 | 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 13 | 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 14 | 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 15 | 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 16 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 17 | 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 18 | 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 19 | 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 20 | 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 21 | 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 22 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 23 | 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 24 | 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 25 | 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 26 | 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 27 | 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 28 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 29 | 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 30 | 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 31 | 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 32 | 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 33 | 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 34 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 35 | 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 36 | 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 37 | 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 38 | 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 39 | 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 40 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 41 | 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 42 | 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 43 | 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 44 | 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 45 | 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 46 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 47 | 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 48 | 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 49 | 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 50 | 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 51 | 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 52 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 53 | 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 54 | 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 55 | 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 56 | 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 57 | 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 58 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 59 | 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 60 | 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 61 | 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 62 | 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 63 | 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 64 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 65 | 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 66 | 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 67 | 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, 68 | }; 69 | 70 | /* 71 | * CRC-32 implementation compatible with libmemcached library. Unfortunately 72 | * this implementation does not return CRC-32 as per spec. 73 | */ 74 | uint32_t 75 | hash_crc32(const char *key, size_t key_length) 76 | { 77 | uint64_t x; 78 | uint32_t crc = UINT32_MAX; 79 | 80 | for (x = 0; x < key_length; x++) { 81 | crc = (crc >> 8) ^ crc32tab[(crc ^ (uint64_t)key[x]) & 0xff]; 82 | } 83 | 84 | return ((~crc) >> 16) & 0x7fff; 85 | } 86 | 87 | uint32_t 88 | hash_crc32a(const char *key, size_t key_length) 89 | { 90 | const uint8_t *p = key; 91 | uint32_t crc; 92 | 93 | crc = ~0U; 94 | while (key_length--) { 95 | crc = crc32tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); 96 | } 97 | 98 | return crc ^ ~0U; 99 | } 100 | -------------------------------------------------------------------------------- /dep/dhashkit/dfnv.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static uint64_t FNV_64_INIT = UINT64_C(0xcbf29ce484222325); 4 | static uint64_t FNV_64_PRIME = UINT64_C(0x100000001b3); 5 | static uint32_t FNV_32_INIT = 2166136261UL; 6 | static uint32_t FNV_32_PRIME = 16777619; 7 | 8 | uint32_t 9 | hash_fnv1_64(const char *key, size_t key_length) 10 | { 11 | uint64_t hash = FNV_64_INIT; 12 | size_t x; 13 | 14 | for (x = 0; x < key_length; x++) { 15 | hash *= FNV_64_PRIME; 16 | hash ^= (uint64_t)key[x]; 17 | } 18 | 19 | return (uint32_t)hash; 20 | } 21 | 22 | uint32_t 23 | hash_fnv1a_64(const char *key, size_t key_length) 24 | { 25 | uint32_t hash = (uint32_t) FNV_64_INIT; 26 | size_t x; 27 | 28 | for (x = 0; x < key_length; x++) { 29 | uint32_t val = (uint32_t)key[x]; 30 | hash ^= val; 31 | hash *= (uint32_t) FNV_64_PRIME; 32 | } 33 | 34 | return hash; 35 | } 36 | 37 | uint32_t 38 | hash_fnv1_32(const char *key, size_t key_length) 39 | { 40 | uint32_t hash = FNV_32_INIT; 41 | size_t x; 42 | 43 | for (x = 0; x < key_length; x++) { 44 | uint32_t val = (uint32_t)key[x]; 45 | hash *= FNV_32_PRIME; 46 | hash ^= val; 47 | } 48 | 49 | return hash; 50 | } 51 | 52 | uint32_t 53 | hash_fnv1a_32(const char *key, size_t key_length) 54 | { 55 | uint32_t hash = FNV_32_INIT; 56 | size_t x; 57 | 58 | for (x= 0; x < key_length; x++) { 59 | uint32_t val = (uint32_t)key[x]; 60 | hash ^= val; 61 | hash *= FNV_32_PRIME; 62 | } 63 | 64 | return hash; 65 | } 66 | -------------------------------------------------------------------------------- /dep/dhashkit/dhashkit.h: -------------------------------------------------------------------------------- 1 | #ifndef _DHASHKIT_H_ 2 | #define _DHASHKIT_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | struct continuum { 10 | uint32_t index; /* server index */ 11 | uint32_t value; /* hash value */ 12 | }; 13 | 14 | #define HASH_CODEC(ACTION) \ 15 | ACTION( HASH_ONE_AT_A_TIME, one_at_a_time ) \ 16 | ACTION( HASH_MD5, md5 ) \ 17 | ACTION( HASH_CRC16, crc16 ) \ 18 | ACTION( HASH_CRC32, crc32 ) \ 19 | ACTION( HASH_CRC32A, crc32a ) \ 20 | ACTION( HASH_FNV1_64, fnv1_64 ) \ 21 | ACTION( HASH_FNV1A_64, fnv1a_64 ) \ 22 | ACTION( HASH_FNV1_32, fnv1_32 ) \ 23 | ACTION( HASH_FNV1A_32, fnv1a_32 ) \ 24 | ACTION( HASH_HSIEH, hsieh ) \ 25 | ACTION( HASH_MURMUR, murmur ) \ 26 | ACTION( HASH_JENKINS, jenkins ) \ 27 | 28 | #define DIST_CODEC(ACTION) \ 29 | ACTION( DIST_KETAMA, ketama ) \ 30 | ACTION( DIST_MODULA, modula ) \ 31 | ACTION( DIST_RANDOM, random ) \ 32 | 33 | #define DEFINE_ACTION(_hash, _name) _hash, 34 | typedef enum hash_type { 35 | HASH_CODEC( DEFINE_ACTION ) 36 | HASH_SENTINEL 37 | } hash_type_t; 38 | #undef DEFINE_ACTION 39 | 40 | #define DEFINE_ACTION(_dist, _name) _dist, 41 | typedef enum dist_type { 42 | DIST_CODEC( DEFINE_ACTION ) 43 | DIST_SENTINEL 44 | } dist_type_t; 45 | #undef DEFINE_ACTION 46 | 47 | uint32_t hash_one_at_a_time(const char *key, size_t key_length); 48 | void md5_signature(const unsigned char *key, unsigned long length, unsigned char *result); 49 | uint32_t hash_md5(const char *key, size_t key_length); 50 | uint32_t hash_crc16(const char *key, size_t key_length); 51 | uint32_t hash_crc32(const char *key, size_t key_length); 52 | uint32_t hash_crc32a(const char *key, size_t key_length); 53 | uint32_t hash_fnv1_64(const char *key, size_t key_length); 54 | uint32_t hash_fnv1a_64(const char *key, size_t key_length); 55 | uint32_t hash_fnv1_32(const char *key, size_t key_length); 56 | uint32_t hash_fnv1a_32(const char *key, size_t key_length); 57 | uint32_t hash_hsieh(const char *key, size_t key_length); 58 | uint32_t hash_jenkins(const char *key, size_t length); 59 | uint32_t hash_murmur(const char *key, size_t length); 60 | 61 | uint32_t ketama_dispatch(struct continuum *continuum, uint32_t ncontinuum, uint32_t hash); 62 | uint32_t modula_dispatch(struct continuum *continuum, uint32_t ncontinuum, uint32_t hash); 63 | uint32_t random_dispatch(struct continuum *continuum, uint32_t ncontinuum, uint32_t hash); 64 | 65 | 66 | /*SHA-1 in CBy Steve Reid 100% Public Domain*/ 67 | typedef struct { 68 | uint32_t state[5]; 69 | uint32_t count[2]; 70 | unsigned char buffer[64]; 71 | } SHA1_CTX; 72 | 73 | void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]); 74 | void SHA1Init(SHA1_CTX* context); 75 | void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len); 76 | void SHA1Final(unsigned char digest[20], SHA1_CTX* context); 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /dep/dhashkit/dhsieh.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #undef get16bits 4 | #if (defined(__GNUC__) && defined(__i386__)) 5 | #define get16bits(d) (*((const uint16_t *) (d))) 6 | #endif 7 | 8 | #if !defined (get16bits) 9 | #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\ 10 | +(uint32_t)(((const uint8_t *)(d))[0]) ) 11 | #endif 12 | 13 | uint32_t 14 | hash_hsieh(const char *key, size_t key_length) 15 | { 16 | uint32_t hash = 0, tmp; 17 | int rem; 18 | 19 | if (key_length <= 0 || key == NULL) { 20 | return 0; 21 | } 22 | 23 | rem = key_length & 3; 24 | key_length >>= 2; 25 | 26 | /* Main loop */ 27 | for (;key_length > 0; key_length--) { 28 | hash += get16bits (key); 29 | tmp = (get16bits (key+2) << 11) ^ hash; 30 | hash = (hash << 16) ^ tmp; 31 | key += 2*sizeof (uint16_t); 32 | hash += hash >> 11; 33 | } 34 | 35 | /* Handle end cases */ 36 | switch (rem) { 37 | case 3: 38 | hash += get16bits (key); 39 | hash ^= hash << 16; 40 | hash ^= (uint32_t)key[sizeof (uint16_t)] << 18; 41 | hash += hash >> 11; 42 | break; 43 | 44 | case 2: 45 | hash += get16bits (key); 46 | hash ^= hash << 11; 47 | hash += hash >> 17; 48 | break; 49 | 50 | case 1: 51 | hash += (unsigned char)(*key); 52 | hash ^= hash << 10; 53 | hash += hash >> 1; 54 | 55 | default: 56 | break; 57 | } 58 | 59 | /* Force "avalanching" of final 127 bits */ 60 | hash ^= hash << 3; 61 | hash += hash >> 5; 62 | hash ^= hash << 4; 63 | hash += hash >> 17; 64 | hash ^= hash << 25; 65 | hash += hash >> 6; 66 | 67 | return hash; 68 | } 69 | -------------------------------------------------------------------------------- /dep/dhashkit/dketama.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #define KETAMA_CONTINUUM_ADDITION 10 /* # extra slots to build into continuum */ 8 | #define KETAMA_POINTS_PER_SERVER 160 /* 40 points per hash */ 9 | #define KETAMA_MAX_HOSTLEN 86 10 | 11 | static uint32_t 12 | ketama_hash(const char *key, size_t key_length, uint32_t alignment) 13 | { 14 | unsigned char results[16]; 15 | 16 | md5_signature((const unsigned char*)key, (unsigned long)key_length, results); 17 | 18 | return ((uint32_t) (results[3 + alignment * 4] & 0xFF) << 24) 19 | | ((uint32_t) (results[2 + alignment * 4] & 0xFF) << 16) 20 | | ((uint32_t) (results[1 + alignment * 4] & 0xFF) << 8) 21 | | (results[0 + alignment * 4] & 0xFF); 22 | } 23 | 24 | static int 25 | ketama_item_cmp(const void *t1, const void *t2) 26 | { 27 | const struct continuum *ct1 = t1, *ct2 = t2; 28 | 29 | if (ct1->value == ct2->value) { 30 | return 0; 31 | } else if (ct1->value > ct2->value) { 32 | return 1; 33 | } else { 34 | return -1; 35 | } 36 | } 37 | 38 | uint32_t 39 | ketama_dispatch(struct continuum *continuum, uint32_t ncontinuum, uint32_t hash) 40 | { 41 | struct continuum *begin, *end, *left, *right, *middle; 42 | 43 | ASSERT(continuum != NULL); 44 | ASSERT(ncontinuum != 0); 45 | 46 | begin = left = continuum; 47 | end = right = continuum + ncontinuum; 48 | 49 | while (left < right) { 50 | middle = left + (right - left) / 2; 51 | if (middle->value < hash) { 52 | left = middle + 1; 53 | } else { 54 | right = middle; 55 | } 56 | } 57 | 58 | if (right == end) { 59 | right = begin; 60 | } 61 | 62 | return right->index; 63 | } 64 | -------------------------------------------------------------------------------- /dep/dhashkit/dmodula.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #define MODULA_CONTINUUM_ADDITION 10 /* # extra slots to build into continuum */ 7 | #define MODULA_POINTS_PER_SERVER 1 8 | 9 | uint32_t 10 | modula_dispatch(struct continuum *continuum, uint32_t ncontinuum, uint32_t hash) 11 | { 12 | struct continuum *c; 13 | 14 | ASSERT(continuum != NULL); 15 | ASSERT(ncontinuum != 0); 16 | 17 | c = continuum + hash % ncontinuum; 18 | 19 | return c->index; 20 | } 21 | -------------------------------------------------------------------------------- /dep/dhashkit/dmurmur.c: -------------------------------------------------------------------------------- 1 | /* 2 | * "Murmur" hash provided by Austin, tanjent@gmail.com 3 | * http://murmurhash.googlepages.com/ 4 | * 5 | * Note - This code makes a few assumptions about how your machine behaves - 6 | * 7 | * 1. We can read a 4-byte value from any address without crashing 8 | * 2. sizeof(int) == 4 9 | * 10 | * And it has a few limitations - 11 | * 1. It will not work incrementally. 12 | * 2. It will not produce the same results on little-endian and big-endian 13 | * machines. 14 | * 15 | * Updated to murmur2 hash - BP 16 | */ 17 | 18 | #include 19 | 20 | uint32_t 21 | hash_murmur(const char *key, size_t length) 22 | { 23 | /* 24 | * 'm' and 'r' are mixing constants generated offline. They're not 25 | * really 'magic', they just happen to work well. 26 | */ 27 | 28 | const unsigned int m = 0x5bd1e995; 29 | const uint32_t seed = (0xdeadbeef * (uint32_t)length); 30 | const int r = 24; 31 | 32 | 33 | /* Initialize the hash to a 'random' value */ 34 | 35 | uint32_t h = seed ^ (uint32_t)length; 36 | 37 | /* Mix 4 bytes at a time into the hash */ 38 | 39 | const unsigned char * data = (const unsigned char *)key; 40 | 41 | while (length >= 4) { 42 | unsigned int k = *(unsigned int *)data; 43 | 44 | k *= m; 45 | k ^= k >> r; 46 | k *= m; 47 | 48 | h *= m; 49 | h ^= k; 50 | 51 | data += 4; 52 | length -= 4; 53 | } 54 | 55 | /* Handle the last few bytes of the input array */ 56 | 57 | switch(length) { 58 | case 3: 59 | h ^= ((uint32_t)data[2]) << 16; 60 | 61 | case 2: 62 | h ^= ((uint32_t)data[1]) << 8; 63 | 64 | case 1: 65 | h ^= data[0]; 66 | h *= m; 67 | 68 | default: 69 | break; 70 | }; 71 | 72 | /* 73 | * Do a few final mixes of the hash to ensure the last few bytes are 74 | * well-incorporated. 75 | */ 76 | 77 | h ^= h >> 13; 78 | h *= m; 79 | h ^= h >> 15; 80 | 81 | return h; 82 | } 83 | -------------------------------------------------------------------------------- /dep/dhashkit/done_at_a_time.c: -------------------------------------------------------------------------------- 1 | /* 2 | * HashKit 3 | * Copyright (C) 2009 Brian Aker 4 | * All rights reserved. 5 | * 6 | * Use and distribution licensed under the BSD license. See 7 | * the COPYING file in the parent directory for full text. 8 | */ 9 | 10 | /* 11 | * This has is Jenkin's "One at A time Hash". 12 | * http://en.wikipedia.org/wiki/Jenkins_hash_function 13 | */ 14 | 15 | #include 16 | 17 | uint32_t 18 | hash_one_at_a_time(const char *key, size_t key_length) 19 | { 20 | const char *ptr = key; 21 | uint32_t value = 0; 22 | 23 | while (key_length--) { 24 | uint32_t val = (uint32_t) *ptr++; 25 | value += val; 26 | value += (value << 10); 27 | value ^= (value >> 6); 28 | } 29 | value += (value << 3); 30 | value ^= (value >> 11); 31 | value += (value << 15); 32 | 33 | return value; 34 | } 35 | -------------------------------------------------------------------------------- /dep/dhashkit/drandom.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #define RANDOM_CONTINUUM_ADDITION 10 /* # extra slots to build into continuum */ 7 | #define RANDOM_POINTS_PER_SERVER 1 8 | 9 | uint32_t 10 | random_dispatch(struct continuum *continuum, uint32_t ncontinuum, uint32_t hash) 11 | { 12 | struct continuum *c; 13 | 14 | ASSERT(continuum != NULL); 15 | ASSERT(ncontinuum != 0); 16 | 17 | c = continuum + random() % ncontinuum; 18 | 19 | return c->index; 20 | } 21 | -------------------------------------------------------------------------------- /dep/dlist/Makefile.am: -------------------------------------------------------------------------------- 1 | MAINTAINERCLEANFILES = Makefile.in 2 | 3 | AM_CPPFLAGS = 4 | if !OS_SOLARIS 5 | AM_CPPFLAGS += -D_GNU_SOURCE 6 | endif 7 | AM_CPPFLAGS += -I $(top_srcdir)/dep/util 8 | AM_CPPFLAGS += -I $(top_srcdir)/dep/jemalloc-4.2.0/include 9 | AM_CPPFLAGS += -I $(top_srcdir)/dep/dmalloc 10 | 11 | AM_CFLAGS = -Wall -Wshadow 12 | AM_CFLAGS += -Wno-unused-parameter -Wno-unused-value 13 | 14 | noinst_LIBRARIES = libdlist.a 15 | 16 | noinst_HEADERS = dlist.h dmtqueue.h dlockqueue.h 17 | 18 | libdlist_a_SOURCES = \ 19 | dlist.c dlist.h \ 20 | dmtqueue.c dmtqueue.h \ 21 | dlockqueue.c dlockqueue.h -------------------------------------------------------------------------------- /dep/dlist/dlist.h: -------------------------------------------------------------------------------- 1 | #ifndef _DLIST_H__ 2 | #define _DLIST_H__ 3 | 4 | /* Node, List, and Iterator are the only data structures used currently. */ 5 | 6 | typedef struct dlistNode { 7 | struct dlistNode *prev; 8 | struct dlistNode *next; 9 | void *value; 10 | } dlistNode; 11 | 12 | typedef struct dlistIter { 13 | dlistNode *next; 14 | int direction; 15 | } dlistIter; 16 | 17 | typedef struct dlist { 18 | dlistNode *head; 19 | dlistNode *tail; 20 | void *(*dup)(void *ptr); 21 | void (*free)(void *ptr); 22 | int (*match)(void *ptr, void *key); 23 | unsigned long len; 24 | } dlist; 25 | 26 | /* Functions implemented as macros */ 27 | #define dlistLength(l) ((l)->len) 28 | #define dlistFirst(l) ((l)->head) 29 | #define dlistLast(l) ((l)->tail) 30 | #define dlistPrevNode(n) ((n)->prev) 31 | #define dlistNextNode(n) ((n)->next) 32 | #define dlistNodeValue(n) ((n)->value) 33 | 34 | #define dlistSetDupMethod(l,m) ((l)->dup = (m)) 35 | #define dlistSetFreeMethod(l,m) ((l)->free = (m)) 36 | #define dlistSetMatchMethod(l,m) ((l)->match = (m)) 37 | 38 | #define dlistGetDupMethod(l) ((l)->dup) 39 | #define dlistGetFree(l) ((l)->free) 40 | #define dlistGetMatchMethod(l) ((l)->match) 41 | 42 | /* Prototypes */ 43 | dlist *dlistCreate(void); 44 | void dlistRelease(dlist *list); 45 | dlist *dlistAddNodeHead(dlist *list, void *value); 46 | dlist *dlistAddNodeTail(dlist *list, void *value); 47 | dlist *dlistInsertNode(dlist *list, dlistNode *old_node, void *value, int after); 48 | void dlistDelNode(dlist *list, dlistNode *node); 49 | dlistIter *dlistGetIterator(dlist *list, int direction); 50 | dlistNode *dlistNext(dlistIter *iter); 51 | void dlistReleaseIterator(dlistIter *iter); 52 | dlist *dlistDup(dlist *orig); 53 | dlistNode *dlistSearchKey(dlist *list, void *key); 54 | dlistNode *dlistIndex(dlist *list, long index); 55 | void dlistRewind(dlist *list, dlistIter *li); 56 | void dlistRewindTail(dlist *list, dlistIter *li); 57 | void dlistRotate(dlist *list); 58 | dlist *dlistPush(dlist *list, void *value); 59 | void *dlistPop(dlist *list); 60 | 61 | /* Directions for iterators */ 62 | #define AL_START_HEAD 0 63 | #define AL_START_TAIL 1 64 | 65 | #endif /* __ADLIST_H__ */ 66 | -------------------------------------------------------------------------------- /dep/dlist/dlockqueue.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | dlockqueue *dlockqueue_create(void) 12 | { 13 | dlockqueue *lqueue; 14 | 15 | lqueue = dalloc(sizeof(*lqueue)); 16 | if (lqueue == NULL) { 17 | return NULL; 18 | } 19 | 20 | lqueue->maxlen = -1; 21 | lqueue->maxlen_policy = MAX_LENGTH_POLICY_REJECT; 22 | pthread_mutex_init(&lqueue->lmutex,NULL); 23 | 24 | lqueue->l = dlistCreate(); 25 | if (lqueue->l == NULL) { 26 | dlockqueue_destroy(lqueue); 27 | return NULL; 28 | } 29 | 30 | return lqueue; 31 | } 32 | 33 | long long dlockqueue_push(void *q, void *value) 34 | { 35 | dlockqueue *lqueue = q; 36 | dlist *list; 37 | long long length; 38 | 39 | pthread_mutex_lock(&lqueue->lmutex); 40 | length = (long long)dlistLength(lqueue->l); 41 | if (lqueue->maxlen >0 && length >= lqueue->maxlen) { 42 | if (lqueue->maxlen_policy == MAX_LENGTH_POLICY_REJECT) { 43 | length = -1; 44 | } else if (lqueue->maxlen_policy == MAX_LENGTH_POLICY_EVICT_HEAD) { 45 | while (length >= lqueue->maxlen) { 46 | dlistNode *ln = dlistFirst(lqueue->l); 47 | dlistDelNode(lqueue->l,ln); 48 | length = (long long)dlistLength(lqueue->l); 49 | } 50 | list = dlistAddNodeTail(lqueue->l, value); 51 | length ++; 52 | } else if (lqueue->maxlen_policy == MAX_LENGTH_POLICY_EVICT_END) { 53 | while (length >= lqueue->maxlen) { 54 | dlistNode *ln = dlistLast(lqueue->l); 55 | dlistDelNode(lqueue->l,ln); 56 | length = (long long)dlistLength(lqueue->l); 57 | } 58 | list = dlistAddNodeTail(lqueue->l, value); 59 | length ++; 60 | } 61 | } else { 62 | list = dlistAddNodeTail(lqueue->l, value); 63 | length ++; 64 | } 65 | pthread_mutex_unlock(&lqueue->lmutex); 66 | 67 | if (list == NULL) { 68 | return -1; 69 | } 70 | 71 | return length; 72 | } 73 | 74 | void *dlockqueue_pop(void *q) 75 | { 76 | dlockqueue *lqueue = q; 77 | dlistNode *node; 78 | void *value; 79 | 80 | if (lqueue == NULL || lqueue->l == NULL) { 81 | return NULL; 82 | } 83 | 84 | pthread_mutex_lock(&lqueue->lmutex); 85 | 86 | node = dlistFirst(lqueue->l); 87 | if (node == NULL) { 88 | pthread_mutex_unlock(&lqueue->lmutex); 89 | return NULL; 90 | } 91 | 92 | value = dlistNodeValue(node); 93 | 94 | dlistDelNode(lqueue->l, node); 95 | 96 | pthread_mutex_unlock(&lqueue->lmutex); 97 | 98 | return value; 99 | } 100 | 101 | void dlockqueue_destroy(void *q) 102 | { 103 | dlockqueue *lqueue = q; 104 | if (lqueue == NULL) { 105 | return; 106 | } 107 | 108 | if (lqueue->l != NULL) { 109 | dlistRelease(lqueue->l); 110 | } 111 | 112 | pthread_mutex_destroy(&lqueue->lmutex); 113 | 114 | dfree(lqueue); 115 | } 116 | 117 | long long dlockqueue_length(void *q) 118 | { 119 | dlockqueue *lqueue = q; 120 | long long length; 121 | 122 | if (lqueue == NULL || lqueue->l == NULL) { 123 | return -1; 124 | } 125 | 126 | pthread_mutex_lock(&lqueue->lmutex); 127 | length = dlistLength(lqueue->l); 128 | pthread_mutex_unlock(&lqueue->lmutex); 129 | 130 | return length; 131 | } 132 | -------------------------------------------------------------------------------- /dep/dlist/dlockqueue.h: -------------------------------------------------------------------------------- 1 | #ifndef _DLOCKQUEUE_H_ 2 | #define _DLOCKQUEUE_H_ 3 | 4 | struct dlist; 5 | 6 | typedef struct dlockqueue{ 7 | struct dlist *l; 8 | long long maxlen; 9 | int maxlen_policy; 10 | pthread_mutex_t lmutex; 11 | } dlockqueue; 12 | 13 | dlockqueue *dlockqueue_create(void); 14 | long long dlockqueue_push(void *q, void *value); 15 | void *dlockqueue_pop(void *q); 16 | void dlockqueue_destroy(void *q); 17 | long long dlockqueue_length(void *q); 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /dep/dlist/dmtqueue.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | /******** multi-thread safe queue interface ********/ 10 | dmtqueue *dmtqueue_create(void) 11 | { 12 | dmtqueue *q; 13 | 14 | q = dalloc(sizeof(*q)); 15 | if (q == NULL) { 16 | return NULL; 17 | } 18 | 19 | q->l = NULL; 20 | q->lock_push = NULL; 21 | q->lock_pop = NULL; 22 | q->destroy = NULL; 23 | q->length = NULL; 24 | 25 | return q; 26 | } 27 | 28 | void dmtqueue_destroy(dmtqueue *q) 29 | { 30 | if (q == NULL) { 31 | return; 32 | } 33 | 34 | if (q->destroy) { 35 | q->destroy(q->l); 36 | } 37 | 38 | dfree(q); 39 | } 40 | 41 | long long dmtqueue_push(dmtqueue *q, void *value) 42 | { 43 | if(q == NULL || q->l == NULL 44 | || q->lock_push == NULL) 45 | { 46 | return -1; 47 | } 48 | 49 | return q->lock_push(q->l, value); 50 | } 51 | 52 | void *dmtqueue_pop(dmtqueue *q) 53 | { 54 | if(q == NULL || q->l == NULL 55 | || q->lock_pop == NULL) 56 | { 57 | return NULL; 58 | } 59 | 60 | return q->lock_pop(q->l); 61 | } 62 | 63 | int dmtqueue_empty(dmtqueue *q) 64 | { 65 | if(q == NULL || q->l == NULL 66 | || q->length == NULL) 67 | { 68 | return -1; 69 | } 70 | 71 | if(q->length(q->l) > 0) 72 | { 73 | return 0; 74 | } 75 | 76 | return 1; 77 | } 78 | 79 | long long dmtqueue_length(dmtqueue *q) 80 | { 81 | if(q == NULL || q->l == NULL 82 | || q->length == NULL) 83 | { 84 | return -1; 85 | } 86 | 87 | return q->length(q->l); 88 | } 89 | 90 | /******** multi-thread safe queue implement ********/ 91 | 92 | /** 93 | * This is multi-thread safe queue. 94 | * This lock list's performance is not good, but it is safe. 95 | */ 96 | int dmtqueue_init_with_lockqueue(dmtqueue *q, dlockqueue_freefunc freefunc) 97 | { 98 | dlockqueue *lq; 99 | 100 | if (q == NULL) { 101 | return -1; 102 | } 103 | 104 | lq = dlockqueue_create(); 105 | if (lq == NULL) { 106 | return -1; 107 | } 108 | 109 | lq->l->free = freefunc; 110 | 111 | q->l = lq; 112 | q->lock_push = dlockqueue_push; 113 | q->lock_pop = dlockqueue_pop; 114 | q->destroy = dlockqueue_destroy; 115 | q->length = dlockqueue_length; 116 | 117 | return 0; 118 | } 119 | -------------------------------------------------------------------------------- /dep/dlist/dmtqueue.h: -------------------------------------------------------------------------------- 1 | #ifndef _DMTQUEUE_H_ 2 | #define _DMTQUEUE_H_ 3 | 4 | #define MAX_LENGTH_POLICY_REJECT 0 5 | #define MAX_LENGTH_POLICY_EVICT_HEAD 1 6 | #define MAX_LENGTH_POLICY_EVICT_END 2 7 | 8 | /* Multi-thread safe queue */ 9 | typedef struct dmtqueue{ 10 | void *l; 11 | long long (*lock_push)(void *q, void *value); 12 | void *(*lock_pop)(void *q); 13 | void (*destroy)(void *q); 14 | long long (*length)(void *q); 15 | } dmtqueue; 16 | 17 | #define dmtqueueSetMaxlength(q,l) ((q)->l->maxlen = (l)) 18 | #define dmtqueueSetMaxlengthPolicy(q,p) ((q)->l->maxlen = (p)) 19 | 20 | typedef int (*dmtqueue_init)(dmtqueue *); 21 | 22 | /******** multi-thread safe list interface ********/ 23 | 24 | dmtqueue *dmtqueue_create(void); 25 | void dmtqueue_destroy(dmtqueue *q); 26 | long long dmtqueue_push(dmtqueue *q, void *value); 27 | void *dmtqueue_pop(dmtqueue *q); 28 | int dmtqueue_empty(dmtqueue *q); 29 | long long dmtqueue_length(dmtqueue *q); 30 | 31 | /******** multi-thread safe list implement ********/ 32 | 33 | typedef void (*dlockqueue_freefunc)(void *); 34 | int dmtqueue_init_with_lockqueue(dmtqueue *l, dlockqueue_freefunc freefunc); 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /dep/dmalloc/Makefile.am: -------------------------------------------------------------------------------- 1 | MAINTAINERCLEANFILES = Makefile.in 2 | 3 | AM_CPPFLAGS = 4 | if !OS_SOLARIS 5 | AM_CPPFLAGS += -D_GNU_SOURCE 6 | endif 7 | AM_CPPFLAGS += -I $(top_srcdir)/dep/jemalloc-4.2.0/include 8 | AM_CPPFLAGS += -I $(top_srcdir)/dep/util 9 | 10 | AM_CFLAGS = -Wall -Wshadow 11 | AM_CFLAGS += -Wno-unused-parameter -Wno-unused-value 12 | 13 | noinst_LIBRARIES = libdmalloc.a 14 | 15 | noinst_HEADERS = dmalloc.h 16 | 17 | libdmalloc_a_SOURCES = \ 18 | dmalloc.c dmalloc.h -------------------------------------------------------------------------------- /dep/dmalloc/dmalloc.h: -------------------------------------------------------------------------------- 1 | #ifndef _DMALLOC_H_ 2 | #define _DMALLOC_H_ 3 | 4 | #ifdef HAVE_CONFIG_H 5 | # include 6 | #endif 7 | 8 | #include 9 | 10 | #ifdef HAVE_JEMALLOC 11 | # define DUSE_JEMALLOC 1 12 | #endif 13 | 14 | /* 15 | * Memory allocation and free wrappers. 16 | * 17 | * These wrappers enables us to loosely detect double free, dangling 18 | * pointer access and zero-byte alloc. 19 | */ 20 | #if defined(DUSE_JEMALLOC) 21 | #define DMALLOC_LIB ("jemalloc-" __xstr(JEMALLOC_VERSION_MAJOR) "." __xstr(JEMALLOC_VERSION_MINOR) "." __xstr(JEMALLOC_VERSION_BUGFIX)) 22 | #include 23 | #if (JEMALLOC_VERSION_MAJOR == 2 && JEMALLOC_VERSION_MINOR >= 1) || (JEMALLOC_VERSION_MAJOR > 2) 24 | #define HAVE_MALLOC_SIZE 1 25 | #define dmalloc_size(p) je_malloc_usable_size(p) 26 | #else 27 | #error "Newer version of jemalloc required" 28 | #endif 29 | #elif defined(__APPLE__) 30 | #include 31 | #define HAVE_MALLOC_SIZE 1 32 | #define dmalloc_size(p) malloc_size(p) 33 | #endif 34 | 35 | #ifndef DMALLOC_LIB 36 | #define DMALLOC_LIB "libc" 37 | #endif 38 | 39 | #define dalloc(_s) \ 40 | _dalloc((size_t)(_s), __FILE__, __LINE__) 41 | 42 | #define dzalloc(_s) \ 43 | _dzalloc((size_t)(_s), __FILE__, __LINE__) 44 | 45 | #define dcalloc(_n, _s) \ 46 | _dcalloc((size_t)(_n), (size_t)(_s), __FILE__, __LINE__) 47 | 48 | #define drealloc(_p, _s) \ 49 | _drealloc(_p, (size_t)(_s), __FILE__, __LINE__) 50 | 51 | #define dfree(_p) do { \ 52 | _dfree(_p, __FILE__, __LINE__); \ 53 | } while (0) 54 | 55 | char *dmalloc_lock_type(void); 56 | 57 | #ifndef HAVE_MALLOC_SIZE 58 | size_t dmalloc_size(void *ptr); 59 | #endif 60 | 61 | void *_dalloc(size_t size, const char *name, int line); 62 | void *_dzalloc(size_t size, const char *name, int line); 63 | void *_dcalloc(size_t nmemb, size_t size, const char *name, int line); 64 | void *_drealloc(void *ptr, size_t size, const char *name, int line); 65 | void _dfree(void *ptr, const char *name, int line); 66 | 67 | size_t dalloc_used_memory(void); 68 | 69 | size_t dalloc_get_memory_size(void); 70 | 71 | size_t dalloc_get_rss(void); 72 | float dalloc_get_fragmentation_ratio(size_t rss); 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /dep/himemcached-0.1.0/Makefile.am: -------------------------------------------------------------------------------- 1 | MAINTAINERCLEANFILES = Makefile.in 2 | 3 | AM_CFLAGS = -Wall -Wshadow 4 | AM_CFLAGS += -Wno-unused-parameter -Wno-unused-value 5 | 6 | noinst_LIBRARIES = libhimemcached.a 7 | 8 | noinst_HEADERS = himemcached.h himcread.h himcdep/sds.h 9 | 10 | libhimemcached_a_SOURCES = \ 11 | himcdep/sds.c himcdep/sds.h \ 12 | himcread.c himcread.h \ 13 | himemcached.c himemcached.h -------------------------------------------------------------------------------- /dep/himemcached-0.1.0/himcdep/sds.h: -------------------------------------------------------------------------------- 1 | /* SDS (Simple Dynamic Strings), A C dynamic strings library. 2 | * 3 | * Copyright (c) 2006-2014, Salvatore Sanfilippo 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of Redis nor the names of its contributors may be used 15 | * to endorse or promote products derived from this software without 16 | * specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef __SDS_H 32 | #define __SDS_H 33 | 34 | #define SDS_MAX_PREALLOC (1024*1024) 35 | 36 | #include 37 | #include 38 | #ifdef _MSC_VER 39 | #include "win32.h" 40 | #endif 41 | 42 | typedef char *sds; 43 | 44 | struct sdshdr { 45 | int len; 46 | int free; 47 | char buf[]; 48 | }; 49 | 50 | static inline size_t sdslen(const sds s) { 51 | struct sdshdr *sh = (struct sdshdr *)(s-sizeof *sh); 52 | return sh->len; 53 | } 54 | 55 | static inline size_t sdsavail(const sds s) { 56 | struct sdshdr *sh = (struct sdshdr *)(s-sizeof *sh); 57 | return sh->free; 58 | } 59 | 60 | sds sdsnewlen(const void *init, size_t initlen); 61 | sds sdsnew(const char *init); 62 | sds sdsempty(void); 63 | size_t sdslen(const sds s); 64 | sds sdsdup(const sds s); 65 | void sdsfree(sds s); 66 | size_t sdsavail(const sds s); 67 | sds sdsgrowzero(sds s, size_t len); 68 | sds sdscatlen(sds s, const void *t, size_t len); 69 | sds sdscat(sds s, const char *t); 70 | sds sdscatsds(sds s, const sds t); 71 | sds sdscpylen(sds s, const char *t, size_t len); 72 | sds sdscpy(sds s, const char *t); 73 | 74 | sds sdscatvprintf(sds s, const char *fmt, va_list ap); 75 | #ifdef __GNUC__ 76 | sds sdscatprintf(sds s, const char *fmt, ...) 77 | __attribute__((format(printf, 2, 3))); 78 | #else 79 | sds sdscatprintf(sds s, const char *fmt, ...); 80 | #endif 81 | 82 | sds sdscatfmt(sds s, char const *fmt, ...); 83 | void sdstrim(sds s, const char *cset); 84 | void sdsrange(sds s, int start, int end); 85 | void sdsupdatelen(sds s); 86 | void sdsclear(sds s); 87 | int sdscmp(const sds s1, const sds s2); 88 | sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count); 89 | void sdsfreesplitres(sds *tokens, int count); 90 | void sdstolower(sds s); 91 | void sdstoupper(sds s); 92 | sds sdsfromlonglong(long long value); 93 | sds sdscatrepr(sds s, const char *p, size_t len); 94 | sds *sdssplitargs(const char *line, int *argc); 95 | sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen); 96 | sds sdsjoin(char **argv, int argc, char *sep, size_t seplen); 97 | sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen); 98 | 99 | /* Low level functions exposed to the user API */ 100 | sds sdsMakeRoomFor(sds s, size_t addlen); 101 | void sdsIncrLen(sds s, int incr); 102 | sds sdsRemoveFreeSpace(sds s); 103 | size_t sdsAllocSize(sds s); 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /dep/himemcached-0.1.0/himcread.h: -------------------------------------------------------------------------------- 1 | #ifndef _HIMC_READ_H_ 2 | #define _HIMC_READ_H_ 3 | #include /* for size_t */ 4 | 5 | #include 6 | 7 | #define MC_ERR -1 8 | #define MC_OK 0 9 | 10 | /* When an error occurs, the err flag in a context is set to hold the type of 11 | * error that occured. REDIS_ERR_IO means there was an I/O error and you 12 | * should use the "errno" variable to find out what is wrong. 13 | * For other values, the "errstr" field will hold a description. */ 14 | #define MC_ERR_IO 1 /* Error in read or write */ 15 | #define MC_ERR_EOF 3 /* End of file */ 16 | #define MC_ERR_PROTOCOL 4 /* Protocol error */ 17 | #define MC_ERR_OOM 5 /* Out of memory */ 18 | #define MC_ERR_OTHER 2 /* Everything else... */ 19 | 20 | #define MC_REPLY_STRING 1 21 | #define MC_REPLY_ARRAY 2 22 | #define MC_REPLY_INTEGER 3 23 | #define MC_REPLY_NIL 4 24 | #define MC_REPLY_STATUS 5 25 | #define MC_REPLY_ERROR 6 26 | 27 | #define MC_READER_MAX_BUF (1024*16) /* Default max unused reader buffer. */ 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | typedef struct mcReplyObjectFunctions { 34 | void *(*createString)(int, char*, size_t, char*, size_t, int, long long); 35 | void *(*createArray)(size_t, void **); 36 | void *(*createInteger)(long long); 37 | void *(*createNil)(void); 38 | void (*freeObject)(void*); 39 | } mcReplyObjectFunctions; 40 | 41 | typedef struct mcReader { 42 | int err; /* Error flags, 0 when there is no error */ 43 | char errstr[128]; /* String representation of error when applicable */ 44 | 45 | char *buf; /* Read buffer */ 46 | size_t pos; /* Buffer cursor */ 47 | size_t len; /* Buffer length */ 48 | size_t maxbuf; /* Max length of unused buffer */ 49 | 50 | void *subreply; /* Temporary reply for array type */ 51 | size_t alloc_len; /* Temporary reply array alloc length */ 52 | size_t elements; /* Temporary reply array length */ 53 | void **element; /* Temporary reply array */ 54 | 55 | char *str; 56 | size_t strlen; 57 | int kflags; /* Used for key flags (get/gets command reply) */ 58 | long long kversion; /* Used for key version (gets command reply) */ 59 | 60 | int state; /* Current parser state */ 61 | char *token; /* Token marker */ 62 | 63 | long long integer; /* Cache the integer if need */ 64 | 65 | int type; /* Response type */ 66 | int result; /* Parsing result */ 67 | 68 | mcReplyObjectFunctions *fn; 69 | void *privdata; 70 | } mcReader; 71 | 72 | /* Public API for the protocol parser. */ 73 | mcReader *memcachedReaderCreateWithFunctions(mcReplyObjectFunctions *fn); 74 | void memcachedReaderFree(mcReader *r); 75 | int memcachedReaderFeed(mcReader *r, const char *buf, size_t len); 76 | int memcachedReaderGetReply(mcReader *r, void **reply); 77 | 78 | #ifdef __cplusplus 79 | } 80 | #endif 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /dep/himemcached-0.1.0/himemcached.h: -------------------------------------------------------------------------------- 1 | #ifndef _HIMEMCACHED_H_ 2 | #define _HIMEMCACHED_H_ 3 | 4 | #include "himcread.h" 5 | #include "himcdep/sds.h" 6 | 7 | #define HIMC_MAJOR 0 8 | #define HIMC_MINOR 13 9 | #define HIMC_PATCH 1 10 | 11 | /* Connection type can be blocking or non-blocking and is set in the 12 | * least significant bit of the flags field in redisContext. */ 13 | #define MC_BLOCK 0x1 14 | 15 | /* Connection may be disconnected before being free'd. The second bit 16 | * in the flags field is set when the context is connected. */ 17 | #define MC_CONNECTED 0x2 18 | 19 | /* The async API might try to disconnect cleanly and flush the output 20 | * buffer and read all subsequent replies before disconnecting. 21 | * This flag means no new commands can come in and the connection 22 | * should be terminated once all replies have been read. */ 23 | #define MC_DISCONNECTING 0x4 24 | 25 | /* Flag specific to the async API which means that the context should be clean 26 | * up as soon as possible. */ 27 | #define MC_FREEING 0x8 28 | 29 | /* Flag that is set when an async callback is executed. */ 30 | #define MC_IN_CALLBACK 0x10 31 | 32 | /* Flag that is set when the async context has one or more subscriptions. */ 33 | #define MC_SUBSCRIBED 0x20 34 | 35 | /* Flag that is set when monitor mode is active */ 36 | #define MC_MONITORING 0x40 37 | 38 | /* Flag that is set when we should set SO_REUSEADDR before calling bind() */ 39 | #define MC_REUSEADDR 0x80 40 | 41 | #define MC_KEEPALIVE_INTERVAL 15 /* seconds */ 42 | 43 | /* number of times we retry to connect in the case of EADDRNOTAVAIL and 44 | * SO_REUSEADDR is being used. */ 45 | #define MC_CONNECT_RETRIES 10 46 | 47 | /* This is the reply object returned by memcachedCommand() */ 48 | typedef struct mcReply { 49 | int type; /* MC_REPLY_* */ 50 | long long integer; /* The integer when type is MC_REPLY_INTEGER */ 51 | int keylen; /* Length of key */ 52 | char *key; /* Key string */ 53 | int len; /* Length of string */ 54 | char *str; /* Used for both REDIS_REPLY_ERROR and MC_REPLY_STRING */ 55 | int flags; 56 | long long version; 57 | size_t elements; /* number of elements, for MC_REPLY_ARRAY */ 58 | struct mcReply **element; /* elements vector for MC_REPLY_ARRAY */ 59 | } mcReply; 60 | 61 | mcReader *memcachedReaderCreate(void); 62 | 63 | /* Function to free the reply objects hiredis returns by default. */ 64 | void freeMcReplyObject(void *reply); 65 | 66 | enum mcConnectionType { 67 | MC_CONN_TCP, 68 | MC_CONN_UNIX, 69 | }; 70 | 71 | /* Context for a connection to Memcached */ 72 | typedef struct mcContext { 73 | int err; /* Error flags, 0 when there is no error */ 74 | char errstr[128]; /* String representation of error when applicable */ 75 | int fd; 76 | int flags; 77 | char *obuf; /* Write buffer */ 78 | mcReader *reader; /* Protocol reader */ 79 | 80 | enum mcConnectionType connection_type; 81 | struct timeval *timeout; 82 | 83 | struct { 84 | char *host; 85 | char *source_addr; 86 | int port; 87 | } tcp; 88 | 89 | struct { 90 | char *path; 91 | } unix_sock; 92 | } mcContext; 93 | 94 | int memcachedBufferWrite(mcContext *c, int *done); 95 | int memcachedBufferRead(mcContext *c); 96 | 97 | int memcachedGetReplyFromReader(mcContext *c, void **reply); 98 | int memcachedGetReply(mcContext *c, void **reply); 99 | 100 | mcContext *memcachedContextInit(void); 101 | void memcachedFree(mcContext *c) ; 102 | 103 | int memcachedFormatCommandSdsArgv(char **target, int argc, const sds *argv); 104 | int memcachedvFormatCommand(char **target, const char *format, va_list ap); 105 | int memcachedFormatCommand(char **target, const char *format, ...); 106 | int memcachedFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen); 107 | 108 | #endif /* _HIMEMCACHED_H_ */ 109 | -------------------------------------------------------------------------------- /dep/hiredis-0.13.3.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vipshop/vire/fdb7db80f875877098cb5e7feaeb618ee2ddbb7b/dep/hiredis-0.13.3.tar.gz -------------------------------------------------------------------------------- /dep/hiredis-0.13.3/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /dep/jemalloc-4.2.0.tar.bz2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vipshop/vire/fdb7db80f875877098cb5e7feaeb618ee2ddbb7b/dep/jemalloc-4.2.0.tar.bz2 -------------------------------------------------------------------------------- /dep/jemalloc-4.2.0/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /dep/sds/Makefile.am: -------------------------------------------------------------------------------- 1 | MAINTAINERCLEANFILES = Makefile.in 2 | 3 | AM_CPPFLAGS = 4 | if !OS_SOLARIS 5 | AM_CPPFLAGS += -D_GNU_SOURCE 6 | endif 7 | AM_CPPFLAGS += -I $(top_srcdir)/dep/util 8 | AM_CPPFLAGS += -I $(top_srcdir)/dep/jemalloc-4.2.0/include 9 | AM_CPPFLAGS += -I $(top_srcdir)/dep/dmalloc 10 | 11 | AM_CFLAGS = -Wall -Wshadow 12 | AM_CFLAGS += -Wno-unused-parameter -Wno-unused-value 13 | 14 | noinst_LIBRARIES = libsds.a 15 | 16 | noinst_HEADERS = sds.h sdsalloc.h 17 | 18 | libsds_a_SOURCES = \ 19 | sdsalloc.h \ 20 | sds.c sds.h -------------------------------------------------------------------------------- /dep/sds/sdsalloc.h: -------------------------------------------------------------------------------- 1 | /* SDSLib 2.0 -- A C dynamic strings library 2 | * 3 | * Copyright (c) 2006-2015, Salvatore Sanfilippo 4 | * Copyright (c) 2015, Redis Labs, Inc 5 | * 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 are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * 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 | * * Neither the name of Redis nor the names of its contributors may be used 16 | * to endorse or promote products derived from this software without 17 | * specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND 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 COPYRIGHT OWNER OR CONTRIBUTORS BE 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | /* SDS allocator selection. 33 | * 34 | * This file is used in order to change the SDS allocator at compile time. 35 | * Just define the following defines to what you want to use. Also add 36 | * the include of your alternate allocator if needed (not needed in order 37 | * to use the default libc allocator). */ 38 | 39 | #include 40 | 41 | #define s_malloc dalloc 42 | #define s_realloc drealloc 43 | #define s_free dfree 44 | -------------------------------------------------------------------------------- /dep/util/Makefile.am: -------------------------------------------------------------------------------- 1 | MAINTAINERCLEANFILES = Makefile.in 2 | 3 | AM_CFLAGS = -Wall -Wshadow 4 | AM_CFLAGS += -Wno-unused-parameter -Wno-unused-value 5 | 6 | noinst_LIBRARIES = libdutil.a 7 | 8 | noinst_HEADERS = dspecialconfig.h dutil.h dlog.h 9 | 10 | libdutil_a_SOURCES = \ 11 | dspecialconfig.h \ 12 | dutil.c dutil.h \ 13 | dlog.c dlog.h -------------------------------------------------------------------------------- /dep/util/dlog.h: -------------------------------------------------------------------------------- 1 | #ifndef _DLOG_H_ 2 | #define _DLOG_H_ 3 | 4 | #ifdef HAVE_CONFIG_H 5 | # include 6 | #endif 7 | 8 | struct logger { 9 | char *name; /* log file name */ 10 | int level; /* log level */ 11 | int fd; /* log file descriptor */ 12 | int nerror; /* # log error */ 13 | }; 14 | 15 | #define LOG_EMERG 0 /* system in unusable */ 16 | #define LOG_ALERT 1 /* action must be taken immediately */ 17 | #define LOG_CRIT 2 /* critical conditions */ 18 | #define LOG_ERR 3 /* error conditions */ 19 | #define LOG_WARN 4 /* warning conditions */ 20 | #define LOG_NOTICE 5 /* normal but significant condition (default) */ 21 | #define LOG_INFO 6 /* informational */ 22 | #define LOG_DEBUG 7 /* debug messages */ 23 | #define LOG_VERB 8 /* verbose messages */ 24 | #define LOG_VVERB 9 /* verbose messages on crack */ 25 | #define LOG_VVVERB 10 /* verbose messages on ganga */ 26 | #define LOG_PVERB 11 /* periodic verbose messages on crack */ 27 | 28 | #define LOG_MAX_LEN 256 /* max length of log message */ 29 | 30 | /* 31 | * log_stderr - log to stderr 32 | * loga - log always 33 | * loga_hexdump - log hexdump always 34 | * log_error - error log messages 35 | * log_warn - warning log messages 36 | * log_panic - log messages followed by a panic 37 | * ... 38 | * log_debug - debug log messages based on a log level 39 | * log_hexdump - hexadump -C of a log buffer 40 | */ 41 | #ifdef HAVE_DEBUG_LOG 42 | 43 | #define log_debug(_level, ...) do { \ 44 | if (log_loggable(_level) != 0) { \ 45 | _log(__FILE__, __LINE__, _level, 0, __VA_ARGS__); \ 46 | } \ 47 | } while (0) 48 | 49 | #else 50 | 51 | #define log_debug(_level, ...) 52 | 53 | #endif 54 | 55 | #define log_hexdump(_level, _data, _datalen, ...) do { \ 56 | if (log_loggable(_level) != 0) { \ 57 | _log(__FILE__, __LINE__, _level, 0, __VA_ARGS__); \ 58 | _log_hexdump(__FILE__, __LINE__, (char *)(_data), (int)(_datalen), \ 59 | __VA_ARGS__); \ 60 | } \ 61 | } while (0) 62 | 63 | #define log_stderr(...) do { \ 64 | _log_stderr(__VA_ARGS__); \ 65 | } while (0) 66 | 67 | #define log_stdout(...) do { \ 68 | _log_stdout(__VA_ARGS__); \ 69 | } while (0) 70 | 71 | #define log_safe(...) do { \ 72 | _log_safe(__VA_ARGS__); \ 73 | } while (0) 74 | 75 | #define log_stderr_safe(...) do { \ 76 | _log_stderr_safe(__VA_ARGS__); \ 77 | } while (0) 78 | 79 | #define loga(...) do { \ 80 | _log(__FILE__, __LINE__, LOG_EMERG, 0, __VA_ARGS__); \ 81 | } while (0) 82 | 83 | #define loga_hexdump(_data, _datalen, ...) do { \ 84 | _log(__FILE__, __LINE__, LOG_EMERG, 0, __VA_ARGS__); \ 85 | _log_hexdump(__FILE__, __LINE__, (char *)(_data), (int)(_datalen), \ 86 | __VA_ARGS__); \ 87 | } while (0) \ 88 | 89 | #define log_error(...) do { \ 90 | if (log_loggable(LOG_ERR) != 0) { \ 91 | _log(__FILE__, __LINE__, LOG_ERR, 0, __VA_ARGS__); \ 92 | } \ 93 | } while (0) 94 | 95 | #define log_warn(...) do { \ 96 | if (log_loggable(LOG_WARN) != 0) { \ 97 | _log(__FILE__, __LINE__, LOG_WARN, 0, __VA_ARGS__); \ 98 | } \ 99 | } while (0) 100 | 101 | #define log_notice(...) do { \ 102 | if (log_loggable(LOG_NOTICE) != 0) { \ 103 | _log(__FILE__, __LINE__, LOG_NOTICE, 0, __VA_ARGS__); \ 104 | } \ 105 | } while (0) 106 | 107 | #define log_panic(...) do { \ 108 | if (log_loggable(LOG_EMERG) != 0) { \ 109 | _log(__FILE__, __LINE__, LOG_EMERG, 1, __VA_ARGS__); \ 110 | } \ 111 | } while (0) 112 | 113 | int log_init(int level, char *filename); 114 | void log_deinit(void); 115 | void log_level_up(void); 116 | void log_level_down(void); 117 | void log_level_set(int level); 118 | void log_stacktrace(void); 119 | void log_reopen(void); 120 | int log_loggable(int level); 121 | 122 | void _log(const char *file, int line, int level, int panic, const char *fmt, ...); 123 | void _log_stderr(const char *fmt, ...); 124 | void _log_stdout(const char *fmt, ...); 125 | void _log_safe(const char *fmt, ...); 126 | void _log_stderr_safe(const char *fmt, ...); 127 | void _log_hexdump(const char *file, int line, char *data, int datalen, const char *fmt, ...); 128 | 129 | void log_write_len(char * str, size_t len); 130 | 131 | #endif 132 | -------------------------------------------------------------------------------- /dep/util/dspecialconfig.h: -------------------------------------------------------------------------------- 1 | #ifndef _DSPECIALCONFIG_H_ 2 | #define _DSPECIALCONFIG_H_ 3 | 4 | #ifdef __APPLE__ 5 | #include 6 | #endif 7 | 8 | #ifdef __linux__ 9 | #include 10 | #include 11 | #endif 12 | 13 | #if (__i386 || __amd64 || __powerpc__) && __GNUC__ 14 | #define GNUC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) 15 | #if defined(__clang__) 16 | #define HAVE_ATOMIC 17 | #endif 18 | #if (defined(__GLIBC__) && defined(__GLIBC_PREREQ)) 19 | #if (GNUC_VERSION >= 40100 && __GLIBC_PREREQ(2, 6)) 20 | #define HAVE_ATOMIC 21 | #endif 22 | #endif 23 | #endif 24 | 25 | 26 | #if defined(__sun) 27 | #if defined(__GNUC__) 28 | #include 29 | #undef isnan 30 | #define isnan(x) \ 31 | __extension__({ __typeof (x) __x_a = (x); \ 32 | __builtin_expect(__x_a != __x_a, 0); }) 33 | 34 | #undef isfinite 35 | #define isfinite(x) \ 36 | __extension__ ({ __typeof (x) __x_f = (x); \ 37 | __builtin_expect(!isnan(__x_f - __x_f), 1); }) 38 | 39 | #undef isinf 40 | #define isinf(x) \ 41 | __extension__ ({ __typeof (x) __x_i = (x); \ 42 | __builtin_expect(!isnan(__x_i) && !isfinite(__x_i), 0); }) 43 | 44 | #define u_int uint 45 | #define u_int32_t uint32_t 46 | #endif /* __GNUC__ */ 47 | #endif /* __sun */ 48 | 49 | 50 | /* Test for proc filesystem */ 51 | #ifdef __linux__ 52 | #define HAVE_PROC_STAT 1 53 | #define HAVE_PROC_MAPS 1 54 | #define HAVE_PROC_SMAPS 1 55 | #define HAVE_PROC_SOMAXCONN 1 56 | #endif 57 | 58 | /* Test for task_info() */ 59 | #if defined(__APPLE__) 60 | #define HAVE_TASKINFO 1 61 | #endif 62 | 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /m4/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything 2 | * 3 | 4 | # Except me 5 | !.gitignore 6 | -------------------------------------------------------------------------------- /notes/kqueue.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vipshop/vire/fdb7db80f875877098cb5e7feaeb618ee2ddbb7b/notes/kqueue.pdf -------------------------------------------------------------------------------- /scripts/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.out 3 | *.log 4 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | MAINTAINERCLEANFILES = Makefile.in 2 | 3 | AM_CPPFLAGS = 4 | if !OS_SOLARIS 5 | AM_CPPFLAGS += -D_GNU_SOURCE 6 | endif 7 | AM_CPPFLAGS += -I $(top_srcdir)/dep/dhashkit 8 | AM_CPPFLAGS += -I $(top_srcdir)/dep/ae 9 | AM_CPPFLAGS += -I $(top_srcdir)/dep/util 10 | AM_CPPFLAGS += -I $(top_srcdir)/dep/jemalloc-4.2.0/include 11 | AM_CPPFLAGS += -I $(top_srcdir)/dep/dmalloc 12 | AM_CPPFLAGS += -I $(top_srcdir)/dep/sds 13 | AM_CPPFLAGS += -I $(top_srcdir)/dep/darray 14 | AM_CPPFLAGS += -I $(top_srcdir)/dep/dlist 15 | 16 | AM_CFLAGS = 17 | AM_CFLAGS += -fno-strict-aliasing 18 | AM_CFLAGS += -Wall -Wshadow 19 | AM_CFLAGS += -Wpointer-arith 20 | AM_CFLAGS += -Winline 21 | AM_CFLAGS += -Wunused-function -Wunused-variable -Wunused-value 22 | AM_CFLAGS += -Wno-unused-parameter -Wno-unused-value 23 | AM_CFLAGS += -Wconversion -Wsign-compare 24 | AM_CFLAGS += -Wstrict-prototypes -Wmissing-prototypes -Wredundant-decls -Wmissing-declarations 25 | 26 | AM_LDFLAGS = 27 | AM_LDFLAGS += -lm -lpthread -rdynamic 28 | if !OS_DARWIN 29 | AM_LDFLAGS += -lrt 30 | endif 31 | if OS_SOLARIS 32 | AM_LDFLAGS += -lnsl -lsocket 33 | endif 34 | if OS_FREEBSD 35 | AM_LDFLAGS += -lexecinfo 36 | endif 37 | 38 | sbin_PROGRAMS = vire 39 | 40 | vire_SOURCES = \ 41 | vr_aof.c vr_aof.h \ 42 | vr_block.c vr_block.h \ 43 | vr_client.c vr_client.h \ 44 | vr_command.c vr_command.h \ 45 | vr_conf.c vr_conf.h \ 46 | vr_connection.c vr_connection.h \ 47 | vr_core.c vr_core.h \ 48 | vr_db.c vr_db.h \ 49 | vr_dict.c vr_dict.h \ 50 | vr_eventloop.c vr_eventloop.h \ 51 | vr_intset.c vr_intset.h \ 52 | vr_listen.c vr_listen.h \ 53 | vr_lzf.h vr_lzfP.h \ 54 | vr_lzf_c.c vr_lzf_d.c \ 55 | vr_master.c vr_master.h \ 56 | vr_multi.c vr_multi.h \ 57 | vr_notify.c vr_notify.h \ 58 | vr_object.c vr_object.h \ 59 | vr_pubsub.c vr_pubsub.h \ 60 | vr_quicklist.c vr_quicklist.h \ 61 | vr_rbtree.c vr_rbtree.h \ 62 | vr_rdb.c vr_rdb.h \ 63 | vr_replication.c vr_replication.h \ 64 | vr_scripting.c vr_scripting.h \ 65 | vr_server.c vr_server.h \ 66 | vr_signal.c vr_signal.h \ 67 | vr_slowlog.c vr_slowlog.h \ 68 | vr_specialconfig.h \ 69 | vr_stats.c vr_stats.h \ 70 | vr_thread.c vr_thread.h \ 71 | vr_t_hash.c vr_t_hash.h \ 72 | vr_t_list.c vr_t_list.h \ 73 | vr_t_set.c vr_t_set.h \ 74 | vr_t_string.c vr_t_string.h \ 75 | vr_t_zset.c vr_t_zset.h \ 76 | vr_util.c vr_util.h \ 77 | vr_worker.c vr_worker.h \ 78 | vr_backend.c vr_backend.h \ 79 | vr_ziplist.c vr_ziplist.h \ 80 | vr_zipmap.c vr_zipmap.h \ 81 | vr_bitops.c vr_bitops.h \ 82 | vr_hyperloglog.c vr_hyperloglog.h \ 83 | vr.c 84 | 85 | vire_LDADD = $(top_builddir)/dep/util/libdutil.a 86 | vire_LDADD += $(top_builddir)/dep/ae/libae.a 87 | vire_LDADD += $(top_builddir)/dep/sds/libsds.a 88 | vire_LDADD += $(top_builddir)/dep/darray/libdarray.a 89 | vire_LDADD += $(top_builddir)/dep/dlist/libdlist.a 90 | vire_LDADD += $(top_builddir)/dep/dhashkit/libdhashkit.a 91 | vire_LDADD += $(top_builddir)/dep/jemalloc-4.2.0/lib/libjemalloc.a 92 | vire_LDADD += $(top_builddir)/dep/dmalloc/libdmalloc.a -------------------------------------------------------------------------------- /src/vr_aof.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_AOF_H_ 2 | #define _VR_AOF_H_ 3 | 4 | /* AOF states */ 5 | #define AOF_OFF 0 /* AOF is off */ 6 | #define AOF_ON 1 /* AOF is on */ 7 | #define AOF_WAIT_REWRITE 2 /* AOF waits rewrite to start appending */ 8 | 9 | #define AOF_AUTOSYNC_BYTES (1024*1024*32) /* fdatasync every 32MB */ 10 | 11 | /* ---------------------------------------------------------------------------- 12 | * AOF rewrite buffer implementation. 13 | * 14 | * The following code implement a simple buffer used in order to accumulate 15 | * changes while the background process is rewriting the AOF file. 16 | * 17 | * We only need to append, but can't just use realloc with a large block 18 | * because 'huge' reallocs are not always handled as one could expect 19 | * (via remapping of pages at OS level) but may involve copying data. 20 | * 21 | * For this reason we use a list of blocks, every block is 22 | * AOF_RW_BUF_BLOCK_SIZE bytes. 23 | * ------------------------------------------------------------------------- */ 24 | 25 | #define AOF_RW_BUF_BLOCK_SIZE (1024*1024*10) /* 10 MB per block */ 26 | 27 | typedef struct aofrwblock { 28 | unsigned long used, free; 29 | char buf[AOF_RW_BUF_BLOCK_SIZE]; 30 | } aofrwblock; 31 | 32 | unsigned long aofRewriteBufferSize(void); 33 | void aofChildWriteDiffData(aeEventLoop *el, int fd, void *privdata, int mask); 34 | sds catAppendOnlyExpireAtCommand(sds buf, struct redisCommand *cmd, robj *key, robj *seconds); 35 | sds catAppendOnlyGenericCommand(sds dst, int argc, robj **argv); 36 | void aofRewriteBufferAppend(unsigned char *s, unsigned long len); 37 | void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int argc); 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/vr_backend.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Which thread we assigned a connection to most recently. */ 4 | static int num_backend_threads; 5 | 6 | struct darray backends; 7 | 8 | static void *backend_thread_run(void *args); 9 | 10 | int 11 | vr_backend_init(vr_backend *backend) 12 | { 13 | rstatus_t status; 14 | int threads_num; 15 | 16 | if (backend == NULL) { 17 | return VR_ERROR; 18 | } 19 | 20 | backend->id = 0; 21 | backend->current_db = 0; 22 | backend->timelimit_exit = 0; 23 | backend->last_fast_cycle = 0; 24 | backend->resize_db = 0; 25 | backend->rehash_db = 0; 26 | 27 | vr_eventloop_init(&backend->vel, 10); 28 | backend->vel.thread.fun_run = backend_thread_run; 29 | backend->vel.thread.data = backend; 30 | 31 | return VR_OK; 32 | } 33 | 34 | void 35 | vr_backend_deinit(vr_backend *backend) 36 | { 37 | if (backend == NULL) { 38 | return; 39 | } 40 | 41 | vr_eventloop_deinit(&backend->vel); 42 | } 43 | 44 | static int 45 | backend_cron(struct aeEventLoop *eventLoop, long long id, void *clientData) { 46 | vr_worker *backend = clientData; 47 | vr_eventloop *vel = &backend->vel; 48 | size_t stat_used_memory, stats_peak_memory; 49 | 50 | UNUSED(eventLoop); 51 | UNUSED(id); 52 | UNUSED(clientData); 53 | 54 | ASSERT(eventLoop == vel->el); 55 | 56 | vel->unixtime = time(NULL); 57 | vel->mstime = vr_msec_now(); 58 | 59 | /* Record the max memory used since the server was started. */ 60 | stat_used_memory = dalloc_used_memory(); 61 | update_stats_get(vel->stats, peak_memory, &stats_peak_memory); 62 | if (stat_used_memory > stats_peak_memory) { 63 | update_stats_set(vel->stats, peak_memory, stat_used_memory); 64 | } 65 | 66 | databasesCron(backend); 67 | 68 | /* Update the config cache */ 69 | run_with_period(1000, vel->cronloops) { 70 | conf_cache_update(&vel->cc); 71 | } 72 | 73 | vel->cronloops ++; 74 | return 1000/vel->hz; 75 | } 76 | 77 | static int 78 | setup_backend(vr_backend *backend) 79 | { 80 | /* Create the serverCron() time event, that's our main way to process 81 | * background operations. */ 82 | if(aeCreateTimeEvent(backend->vel.el, 1, backend_cron, backend, NULL) == AE_ERR) { 83 | serverPanic("Can't create the serverCron time event."); 84 | return VR_ERROR; 85 | } 86 | 87 | return VR_OK; 88 | } 89 | 90 | static void * 91 | backend_thread_run(void *args) 92 | { 93 | vr_worker *backend = args; 94 | 95 | /* vire worker run */ 96 | aeMain(backend->vel.el); 97 | 98 | return NULL; 99 | } 100 | 101 | int 102 | backends_init(uint32_t backend_count) 103 | { 104 | rstatus_t status; 105 | uint32_t idx; 106 | vr_backend *backend; 107 | 108 | darray_init(&backends, backend_count, sizeof(vr_backend)); 109 | 110 | for (idx = 0; idx < backend_count; idx ++) { 111 | backend = darray_push(&backends); 112 | vr_backend_init(backend); 113 | backend->id = idx; 114 | status = setup_backend(backend); 115 | if (status != VR_OK) { 116 | exit(1); 117 | } 118 | } 119 | 120 | num_backend_threads = (int)darray_n(&backends); 121 | 122 | return VR_OK; 123 | } 124 | 125 | int 126 | backends_run(void) 127 | { 128 | uint32_t i, thread_count; 129 | vr_backend *backend; 130 | 131 | thread_count = (uint32_t)num_backend_threads; 132 | 133 | for (i = 0; i < thread_count; i ++) { 134 | backend = darray_get(&backends, i); 135 | vr_thread_start(&backend->vel.thread); 136 | } 137 | 138 | return VR_OK; 139 | } 140 | 141 | int 142 | backends_wait(void) 143 | { 144 | uint32_t i, thread_count; 145 | vr_backend *backend; 146 | 147 | thread_count = (uint32_t)num_backend_threads; 148 | 149 | for (i = 0; i < thread_count; i ++) { 150 | backend = darray_get(&backends, i); 151 | pthread_join(backend->vel.thread.thread_id, NULL); 152 | } 153 | 154 | return VR_OK; 155 | } 156 | 157 | void 158 | backends_deinit(void) 159 | { 160 | vr_backend *backend; 161 | 162 | while(darray_n(&backends)) { 163 | backend = darray_pop(&backends); 164 | vr_backend_deinit(backend); 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/vr_backend.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_BACKEND_H_ 2 | #define _VR_BACKEND_H_ 3 | 4 | typedef struct vr_backend { 5 | 6 | int id; 7 | vr_eventloop vel; 8 | 9 | /* Some global state in order to continue the work incrementally 10 | * across calls for activeExpireCycle() to expire some keys. */ 11 | unsigned int current_db; /* Last DB tested. */ 12 | int timelimit_exit; /* Time limit hit in previous call? */ 13 | long long last_fast_cycle; /* When last fast cycle ran. */ 14 | 15 | /* We use global counters so if we stop the computation at a given 16 | * DB we'll be able to start from the successive in the next 17 | * cron loop iteration for databasesCron() to resize and reshash db. */ 18 | unsigned int resize_db; 19 | unsigned int rehash_db; 20 | }vr_backend; 21 | 22 | extern struct darray backends; 23 | 24 | int backends_init(uint32_t backend_count); 25 | int backends_run(void); 26 | int backends_wait(void); 27 | void backends_deinit(void); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/vr_bitops.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_BITOPS_H_ 2 | #define _VR_BITOPS_H_ 3 | 4 | size_t redisPopcount(void *s, long count); 5 | long redisBitpos(void *s, unsigned long count, int bit); 6 | void setUnsignedBitfield(unsigned char *p, uint64_t offset, uint64_t bits, uint64_t value); 7 | void setSignedBitfield(unsigned char *p, uint64_t offset, uint64_t bits, int64_t value); 8 | uint64_t getUnsignedBitfield(unsigned char *p, uint64_t offset, uint64_t bits); 9 | int64_t getSignedBitfield(unsigned char *p, uint64_t offset, uint64_t bits); 10 | int checkUnsignedBitfieldOverflow(uint64_t value, int64_t incr, uint64_t bits, int owtype, uint64_t *limit); 11 | int checkSignedBitfieldOverflow(int64_t value, int64_t incr, uint64_t bits, int owtype, int64_t *limit); 12 | void printBits(unsigned char *p, unsigned long count); 13 | int getBitOffsetFromArgument(struct client *c, robj *o, size_t *offset, int hash, int bits); 14 | int getBitfieldTypeFromArgument(struct client *c, robj *o, int *sign, int *bits); 15 | robj *lookupStringForBitCommand(struct client *c, size_t maxbit, int *expired); 16 | void setbitCommand(struct client *c); 17 | void getbitCommand(struct client *c); 18 | void bitopCommand(struct client *c); 19 | void bitcountCommand(struct client *c); 20 | void bitposCommand(struct client *c); 21 | void bitfieldCommand(client *c); 22 | #endif 23 | -------------------------------------------------------------------------------- /src/vr_block.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | /* Unblock a client calling the right function depending on the kind 5 | * of operation the client is blocking for. */ 6 | void unblockClient(client *c) { 7 | if (c->btype == BLOCKED_LIST) { 8 | unblockClientWaitingData(c); 9 | } else if (c->btype == BLOCKED_WAIT) { 10 | unblockClientWaitingReplicas(c); 11 | } else { 12 | serverPanic("Unknown btype in unblockClient()."); 13 | } 14 | /* Clear the flags, and put the client in the unblocked list so that 15 | * we'll process new commands in its query buffer ASAP. */ 16 | c->flags &= ~CLIENT_BLOCKED; 17 | c->btype = BLOCKED_NONE; 18 | c->vel->bpop_blocked_clients--; 19 | /* The client may already be into the unblocked list because of a previous 20 | * blocking operation, don't add back it into the list multiple times. */ 21 | if (!(c->flags & CLIENT_UNBLOCKED)) { 22 | c->flags |= CLIENT_UNBLOCKED; 23 | dlistAddNodeTail(c->vel->unblocked_clients,c); 24 | } 25 | } 26 | 27 | /* Get a timeout value from an object and store it into 'timeout'. 28 | * The final timeout is always stored as milliseconds as a time where the 29 | * timeout will expire, however the parsing is performed according to 30 | * the 'unit' that can be seconds or milliseconds. 31 | * 32 | * Note that if the timeout is zero (usually from the point of view of 33 | * commands API this means no timeout) the value stored into 'timeout' 34 | * is zero. */ 35 | int getTimeoutFromObjectOrReply(client *c, robj *object, long long *timeout, int unit) { 36 | long long tval; 37 | 38 | if (getLongLongFromObjectOrReply(c,object,&tval, 39 | "timeout is not an integer or out of range") != VR_OK) 40 | return VR_ERROR; 41 | 42 | if (tval < 0) { 43 | addReplyError(c,"timeout is negative"); 44 | return VR_ERROR; 45 | } 46 | 47 | if (tval > 0) { 48 | if (unit == UNIT_SECONDS) tval *= 1000; 49 | tval += vr_msec_now(); 50 | } 51 | *timeout = tval; 52 | 53 | return VR_OK; 54 | } 55 | 56 | /* Block a client for the specific operation type. Once the CLIENT_BLOCKED 57 | * flag is set client query buffer is not longer processed, but accumulated, 58 | * and will be processed when the client is unblocked. */ 59 | void blockClient(client *c, int btype) { 60 | c->flags |= CLIENT_BLOCKED; 61 | c->btype = btype; 62 | c->vel->bpop_blocked_clients++; 63 | } 64 | -------------------------------------------------------------------------------- /src/vr_block.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_BLOCK_H_ 2 | #define _VR_BLOCK_H_ 3 | 4 | /* This structure holds the blocking operation state for a client. 5 | * The fields used depend on client->btype. */ 6 | typedef struct blockingState { 7 | /* Generic fields. */ 8 | long long timeout; /* Blocking operation timeout. If UNIX current time 9 | * is > timeout then the operation timed out. */ 10 | 11 | /* BLOCKED_LIST */ 12 | dict *keys; /* The keys we are waiting to terminate a blocking 13 | * operation such as BLPOP. Otherwise NULL. */ 14 | robj *target; /* The key that should receive the element, 15 | * for BRPOPLPUSH. */ 16 | 17 | /* BLOCKED_WAIT */ 18 | int numreplicas; /* Number of replicas we are waiting for ACK. */ 19 | long long reploffset; /* Replication offset to reach. */ 20 | } blockingState; 21 | 22 | void blockClient(struct client *c, int btype); 23 | void unblockClient(struct client *c); 24 | int getTimeoutFromObjectOrReply(struct client *c, robj *object, long long *timeout, int unit); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/vr_command.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_COMMAND_H_ 2 | #define _VR_COMMAND_H_ 3 | 4 | /* Command flags. Please check the command table defined in the redis.c file 5 | * for more information about the meaning of every flag. */ 6 | #define CMD_WRITE 1 /* "w" flag */ 7 | #define CMD_READONLY 2 /* "r" flag */ 8 | #define CMD_DENYOOM 4 /* "m" flag */ 9 | #define CMD_NOT_USED_1 8 /* no longer used flag */ 10 | #define CMD_ADMIN 16 /* "a" flag */ 11 | #define CMD_PUBSUB 32 /* "p" flag */ 12 | #define CMD_NOSCRIPT 64 /* "s" flag */ 13 | #define CMD_RANDOM 128 /* "R" flag */ 14 | #define CMD_SORT_FOR_SCRIPT 256 /* "S" flag */ 15 | #define CMD_LOADING 512 /* "l" flag */ 16 | #define CMD_STALE 1024 /* "t" flag */ 17 | #define CMD_SKIP_MONITOR 2048 /* "M" flag */ 18 | #define CMD_ASKING 4096 /* "k" flag */ 19 | #define CMD_FAST 8192 /* "F" flag */ 20 | 21 | /* Command call flags, see call() function */ 22 | #define CMD_CALL_NONE 0 23 | #define CMD_CALL_SLOWLOG (1<<0) 24 | #define CMD_CALL_STATS (1<<1) 25 | #define CMD_CALL_PROPAGATE_AOF (1<<2) 26 | #define CMD_CALL_PROPAGATE_REPL (1<<3) 27 | #define CMD_CALL_PROPAGATE (CMD_CALL_PROPAGATE_AOF|CMD_CALL_PROPAGATE_REPL) 28 | #define CMD_CALL_FULL (CMD_CALL_SLOWLOG | CMD_CALL_STATS | CMD_CALL_PROPAGATE) 29 | 30 | /* Command propagation flags, see propagate() function */ 31 | #define PROPAGATE_NONE 0 32 | #define PROPAGATE_AOF 1 33 | #define PROPAGATE_REPL 2 34 | 35 | /* SHUTDOWN flags */ 36 | #define SHUTDOWN_NOFLAGS 0 /* No flags. */ 37 | #define SHUTDOWN_SAVE 1 /* Force SAVE on SHUTDOWN even if no save 38 | points are configured. */ 39 | #define SHUTDOWN_NOSAVE 2 /* Don't SAVE on SHUTDOWN. */ 40 | 41 | typedef void redisCommandProc(struct client *c); 42 | typedef int *redisGetKeysProc(struct redisCommand *cmd, robj **argv, int argc, int *numkeys); 43 | struct redisCommand { 44 | char *name; 45 | redisCommandProc *proc; 46 | int arity; 47 | char *sflags; /* Flags as string representation, one char per flag. */ 48 | int flags; /* The actual flags, obtained from the 'sflags' field. */ 49 | /* Use a function to determine keys arguments in a command line. 50 | * Used for Redis Cluster redirect. */ 51 | redisGetKeysProc *getkeys_proc; 52 | /* What keys should be loaded in background when calling this command? */ 53 | int firstkey; /* The first argument that's a key (0 = no keys) */ 54 | int lastkey; /* The last argument that's a key */ 55 | int keystep; /* The step between first and last key */ 56 | int idx; 57 | int needadmin; 58 | }; 59 | 60 | typedef struct commandStats { 61 | char *name; 62 | long long microseconds; 63 | long long calls; 64 | }commandStats; 65 | 66 | /* The redisOp structure defines a Redis Operation, that is an instance of 67 | * a command with an argument vector, database ID, propagation target 68 | * (PROPAGATE_*), and command pointer. 69 | * 70 | * Currently only used to additionally propagate more commands to AOF/Replication 71 | * after the propagation of the executed command. */ 72 | typedef struct redisOp { 73 | robj **argv; 74 | int argc, dbid, target; 75 | struct redisCommand *cmd; 76 | } redisOp; 77 | 78 | /* Defines an array of Redis operations. There is an API to add to this 79 | * structure in a easy way. 80 | * 81 | * redisOpArrayInit(); 82 | * redisOpArrayAppend(); 83 | * redisOpArrayFree(); 84 | */ 85 | typedef struct redisOpArray { 86 | redisOp *ops; 87 | int numops; 88 | } redisOpArray; 89 | 90 | extern dictType commandTableDictType; 91 | 92 | void populateCommandTable(void); 93 | int populateCommandsNeedAdminpass(void); 94 | 95 | struct redisCommand *lookupCommand(sds name); 96 | struct redisCommand *lookupCommandOrOriginal(sds name); 97 | struct redisCommand *lookupCommandByCString(char *s); 98 | 99 | void call(struct client *c, int flags); 100 | int processCommand(struct client *c); 101 | 102 | void redisOpArrayInit(redisOpArray *oa); 103 | int redisOpArrayAppend(redisOpArray *oa, struct redisCommand *cmd, int dbid, robj **argv, int argc, int target); 104 | void redisOpArrayFree(redisOpArray *oa); 105 | 106 | void propagate(struct redisCommand *cmd, int dbid, robj **argv, int argc, int flags); 107 | void alsoPropagate(struct redisCommand *cmd, int dbid, robj **argv, int argc, int target); 108 | void forceCommandPropagation(struct client *c, int flags); 109 | void preventCommandPropagation(struct client *c); 110 | void preventCommandAOF(struct client *c); 111 | void preventCommandReplication(struct client *c); 112 | 113 | void commandCommand(struct client *c); 114 | 115 | struct darray *commandStatsTableCreate(void); 116 | void commandStatsTableDestroy(struct darray *cstatstable); 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /src/vr_connection.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_CONNECTION_H_ 2 | #define _VR_CONNECTION_H_ 3 | 4 | typedef struct conn_base { 5 | dlist *free_connq; /* free conn q */ 6 | uint64_t ntotal_conn; /* total # connections counter from start */ 7 | uint32_t ncurr_conn; /* current # connections */ 8 | uint32_t ncurr_cconn; /* current # client connections */ 9 | }conn_base; 10 | 11 | struct conn { 12 | void *owner; /* connection owner */ 13 | 14 | conn_base *cb; /* connect base */ 15 | 16 | int sd; /* socket descriptor */ 17 | 18 | size_t recv_bytes; /* received (read) bytes */ 19 | size_t send_bytes; /* sent (written) bytes */ 20 | 21 | err_t err; /* connection errno */ 22 | unsigned recv_active:1; /* recv active? */ 23 | unsigned recv_ready:1; /* recv ready? */ 24 | unsigned send_active:1; /* send active? */ 25 | unsigned send_ready:1; /* send ready? */ 26 | 27 | unsigned connecting:1; /* connecting? */ 28 | unsigned connected:1; /* connected? */ 29 | unsigned eof:1; /* eof? aka passive close? */ 30 | unsigned done:1; /* done? aka close? */ 31 | 32 | dlist *inqueue; /* incoming request queue */ 33 | dlist *outqueue; /* outputing response queue */ 34 | }; 35 | 36 | struct conn *conn_get(conn_base *cb); 37 | void conn_put(struct conn *conn); 38 | 39 | int conn_init(conn_base *cb); 40 | void conn_deinit(conn_base *cb); 41 | 42 | ssize_t conn_recv(struct conn *conn, void *buf, size_t size); 43 | ssize_t conn_send(struct conn *conn, void *buf, size_t nsend); 44 | ssize_t conn_sendv(struct conn *conn, struct darray *sendv, size_t nsend); 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/vr_core.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | static uint32_t reserved_fds = 0; 7 | 8 | -------------------------------------------------------------------------------- /src/vr_core.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_CORE_H_ 2 | #define _VR_CORE_H_ 3 | 4 | #ifdef HAVE_CONFIG_H 5 | # include 6 | #endif 7 | 8 | #include 9 | 10 | #ifdef HAVE_STATS 11 | # define VR_STATS 1 12 | #else 13 | # define VR_STATS 0 14 | #endif 15 | 16 | #ifdef HAVE_LITTLE_ENDIAN 17 | # define VR_LITTLE_ENDIAN 1 18 | #endif 19 | 20 | #ifdef HAVE_BACKTRACE 21 | # define VR_HAVE_BACKTRACE 1 22 | #endif 23 | 24 | #ifdef HAVE_SPINLOCK 25 | # define VR_USE_SPINLOCK 1 26 | #endif 27 | 28 | #define VR_OK 0 29 | #define VR_ERROR -1 30 | #define VR_EAGAIN -2 31 | #define VR_ENOMEM -3 32 | 33 | /* reserved fds for std streams, log, stats fd, epoll etc. */ 34 | #define RESERVED_FDS 32 35 | 36 | typedef int rstatus_t; /* return type */ 37 | typedef int err_t; /* error type */ 38 | 39 | typedef long long mstime_t; /* millisecond time type. */ 40 | 41 | struct instance; 42 | struct darray; 43 | struct conn; 44 | struct client; 45 | struct clientBufferLimitsConfig; 46 | struct redisCommand; 47 | struct vr_worker; 48 | 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | #include 75 | #include 76 | 77 | #include 78 | #include 79 | 80 | #include 81 | #include 82 | #include 83 | #include 84 | #include 85 | #include 86 | 87 | #include 88 | #include 89 | 90 | #include 91 | 92 | #include 93 | #include 94 | 95 | #include 96 | #include 97 | 98 | #include 99 | #include 100 | #include 101 | #include 102 | #include 103 | 104 | #include 105 | #include 106 | 107 | #include 108 | #include 109 | #include 110 | #include 111 | 112 | #include 113 | #include 114 | 115 | #include 116 | #include 117 | #include 118 | #include 119 | 120 | #include 121 | #include 122 | #include 123 | #include 124 | #include 125 | 126 | #include 127 | 128 | #include 129 | 130 | #include 131 | 132 | struct instance { 133 | int log_level; /* log level */ 134 | char *log_filename; /* log filename */ 135 | char *conf_filename; /* configuration filename */ 136 | char hostname[VR_MAXHOSTNAMELEN]; /* hostname */ 137 | size_t mbuf_chunk_size; /* mbuf chunk size */ 138 | pid_t pid; /* process id */ 139 | char *pid_filename; /* pid filename */ 140 | unsigned pidfile:1; /* pid file created? */ 141 | int thread_num; /* the thread number */ 142 | }; 143 | 144 | #endif 145 | -------------------------------------------------------------------------------- /src/vr_db.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_DB_H_ 2 | #define _VR_DB_H_ 3 | 4 | /* To improve the quality of the LRU approximation we take a set of keys 5 | * that are good candidate for eviction across freeMemoryIfNeeded() calls. 6 | * 7 | * Entries inside the eviciton pool are taken ordered by idle time, putting 8 | * greater idle times to the right (ascending order). 9 | * 10 | * Empty entries have the key pointer set to NULL. */ 11 | #define MAXMEMORY_EVICTION_POOL_SIZE 16 12 | struct evictionPoolEntry { 13 | unsigned long long idle; /* Object idle time. */ 14 | sds key; /* Key name. */ 15 | }; 16 | 17 | /* Vire database representation. There are multiple databases identified 18 | * by integers from 0 (the default database) up to the max configured 19 | * database. The database number is the 'id' field in the structure. */ 20 | typedef struct redisDb { 21 | dict *dict; /* The keyspace for this DB */ 22 | dict *expires; /* Timeout of keys with a timeout set */ 23 | dict *blocking_keys; /* Keys with clients waiting for data (BLPOP) */ 24 | dict *ready_keys; /* Blocked keys that received a PUSH */ 25 | dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS */ 26 | struct evictionPoolEntry *eviction_pool; /* Eviction pool of keys */ 27 | int id; /* Database ID */ 28 | long long avg_ttl; /* Average TTL, just for stats */ 29 | 30 | pthread_rwlock_t rwl; /* read write lock */ 31 | } redisDb; 32 | 33 | extern dictType dbDictType; 34 | extern dictType keyptrDictType; 35 | extern dictType keylistDictType; 36 | 37 | int redisDbInit(redisDb *db); 38 | int redisDbDeinit(redisDb *db); 39 | 40 | int lockDbRead(redisDb *db); 41 | int lockDbWrite(redisDb *db); 42 | int unlockDb(redisDb *db); 43 | 44 | robj *lookupKey(redisDb *db, robj *key); 45 | robj *lookupKeyRead(redisDb *db, robj *key); 46 | robj *lookupKeyWrite(redisDb *db, robj *key, int *expired); 47 | robj *lookupKeyReadOrReply(struct client *c, robj *key, robj *reply); 48 | robj *lookupKeyWriteOrReply(struct client *c, robj *key, robj *reply, int *expired); 49 | void dbAdd(redisDb *db, robj *key, robj *val); 50 | void dbOverwrite(redisDb *db, robj *key, robj *val); 51 | void setKey(redisDb *db, robj *key, robj *val, int *expired); 52 | int dbExists(redisDb *db, robj *key); 53 | robj *dbRandomKey(redisDb *db); 54 | int dbDelete(redisDb *db, robj *key); 55 | robj *dbUnshareStringValue(redisDb *db, robj *key, robj *o); 56 | long long emptyDb(void(callback)(void*)); 57 | int selectDb(struct client *c, int id); 58 | void signalModifiedKey(redisDb *db, robj *key); 59 | void signalFlushedDb(int dbid); 60 | void flushdbCommand(struct client *c); 61 | void flushallCommand(struct client *c); 62 | void delCommand(struct client *c); 63 | void existsCommand(struct client *c); 64 | void selectCommand(struct client *c); 65 | void randomkeyCommand(struct client *c); 66 | void keysCommand(struct client *c); 67 | void scanCallback(void *privdata, const dictEntry *de); 68 | int parseScanCursorOrReply(struct client *c, robj *o, unsigned long *cursor); 69 | void scanGenericCommand(struct client *c, int scantype); 70 | void scanCommand(struct client *c); 71 | void dbsizeCommand(struct client *c); 72 | void lastsaveCommand(struct client *c); 73 | void typeCommand(struct client *c); 74 | void shutdownCommand(struct client *c); 75 | void renameGenericCommand(struct client *c, int nx); 76 | void renameCommand(struct client *c); 77 | void renamenxCommand(struct client *c); 78 | void moveCommand(struct client *c); 79 | int removeExpire(redisDb *db, robj *key); 80 | void setExpire(redisDb *db, robj *key, long long when); 81 | long long getExpire(redisDb *db, robj *key); 82 | void propagateExpire(redisDb *db, robj *key); 83 | int checkIfExpired(redisDb *db, robj *key); 84 | int expireIfNeeded(redisDb *db, robj *key); 85 | void expireGenericCommand(struct client *c, long long basetime, int unit); 86 | void expireCommand(struct client *c); 87 | void expireatCommand(struct client *c); 88 | void pexpireCommand(struct client *c); 89 | void pexpireatCommand(struct client *c); 90 | void ttlGenericCommand(struct client *c, int output_ms); 91 | void ttlCommand(struct client *c); 92 | void pttlCommand(struct client *c); 93 | void persistCommand(struct client *c); 94 | int *getKeysUsingCommandTable(struct redisCommand *cmd,robj **argv, int argc, int *numkeys); 95 | int *getKeysFromCommand(struct redisCommand *cmd, robj **argv, int argc, int *numkeys); 96 | void getKeysFreeResult(int *result); 97 | int *zunionInterGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys); 98 | int *evalGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys); 99 | int *sortGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys); 100 | int *migrateGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys); 101 | 102 | int fetchInternalDbByKey(struct client *c, robj *key); 103 | int fetchInternalDbById(struct client *c, int idx); 104 | 105 | void tryResizeHashTablesForDb(int dbid); 106 | int incrementallyRehashForDb(int dbid); 107 | void activeExpireCycle(vr_backend *backend, int type); 108 | int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now); 109 | void databasesCron(vr_backend *backend); 110 | 111 | #endif 112 | -------------------------------------------------------------------------------- /src/vr_dict.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_DICT_H_ 2 | #define _VR_DICT_H_ 3 | 4 | #include 5 | 6 | #define DICT_OK 0 7 | #define DICT_ERR 1 8 | 9 | /* Unused arguments generate annoying warnings... */ 10 | #define DICT_NOTUSED(V) ((void) V) 11 | 12 | typedef struct dictEntry { 13 | void *key; 14 | union { 15 | void *val; 16 | uint64_t u64; 17 | int64_t s64; 18 | double d; 19 | } v; 20 | struct dictEntry *next; 21 | } dictEntry; 22 | 23 | typedef struct dictType { 24 | unsigned int (*hashFunction)(const void *key); 25 | void *(*keyDup)(void *privdata, const void *key); 26 | void *(*valDup)(void *privdata, const void *obj); 27 | int (*keyCompare)(void *privdata, const void *key1, const void *key2); 28 | void (*keyDestructor)(void *privdata, void *key); 29 | void (*valDestructor)(void *privdata, void *obj); 30 | } dictType; 31 | 32 | /* This is our hash table structure. Every dictionary has two of this as we 33 | * implement incremental rehashing, for the old to the new table. */ 34 | typedef struct dictht { 35 | dictEntry **table; 36 | unsigned long size; 37 | unsigned long sizemask; 38 | unsigned long used; 39 | } dictht; 40 | 41 | typedef struct dict { 42 | dictType *type; 43 | void *privdata; 44 | dictht ht[2]; 45 | long rehashidx; /* rehashing not in progress if rehashidx == -1 */ 46 | int iterators; /* number of iterators currently running */ 47 | } dict; 48 | 49 | /* If safe is set to 1 this is a safe iterator, that means, you can call 50 | * dictAdd, dictFind, and other functions against the dictionary even while 51 | * iterating. Otherwise it is a non safe iterator, and only dictNext() 52 | * should be called while iterating. */ 53 | typedef struct dictIterator { 54 | dict *d; 55 | long index; 56 | int table, safe; 57 | dictEntry *entry, *nextEntry; 58 | /* unsafe iterator fingerprint for misuse detection. */ 59 | long long fingerprint; 60 | } dictIterator; 61 | 62 | typedef void (dictScanFunction)(void *privdata, const dictEntry *de); 63 | 64 | /* This is the initial size of every hash table */ 65 | #define DICT_HT_INITIAL_SIZE 4 66 | 67 | /* ------------------------------- Macros ------------------------------------*/ 68 | #define dictFreeVal(d, entry) \ 69 | if ((d)->type->valDestructor) \ 70 | (d)->type->valDestructor((d)->privdata, (entry)->v.val) 71 | 72 | #define dictSetVal(d, entry, _val_) do { \ 73 | if ((d)->type->valDup) \ 74 | entry->v.val = (d)->type->valDup((d)->privdata, _val_); \ 75 | else \ 76 | entry->v.val = (_val_); \ 77 | } while(0) 78 | 79 | #define dictSetSignedIntegerVal(entry, _val_) \ 80 | do { entry->v.s64 = _val_; } while(0) 81 | 82 | #define dictSetUnsignedIntegerVal(entry, _val_) \ 83 | do { entry->v.u64 = _val_; } while(0) 84 | 85 | #define dictSetDoubleVal(entry, _val_) \ 86 | do { entry->v.d = _val_; } while(0) 87 | 88 | #define dictFreeKey(d, entry) \ 89 | if ((d)->type->keyDestructor) \ 90 | (d)->type->keyDestructor((d)->privdata, (entry)->key) 91 | 92 | #define dictSetKey(d, entry, _key_) do { \ 93 | if ((d)->type->keyDup) \ 94 | entry->key = (d)->type->keyDup((d)->privdata, _key_); \ 95 | else \ 96 | entry->key = (_key_); \ 97 | } while(0) 98 | 99 | #define dictCompareKeys(d, key1, key2) \ 100 | (((d)->type->keyCompare) ? \ 101 | (d)->type->keyCompare((d)->privdata, key1, key2) : \ 102 | (key1) == (key2)) 103 | 104 | #define dictHashKey(d, key) (d)->type->hashFunction(key) 105 | #define dictGetKey(he) ((he)->key) 106 | #define dictGetVal(he) ((he)->v.val) 107 | #define dictGetSignedIntegerVal(he) ((he)->v.s64) 108 | #define dictGetUnsignedIntegerVal(he) ((he)->v.u64) 109 | #define dictGetDoubleVal(he) ((he)->v.d) 110 | #define dictSlots(d) ((d)->ht[0].size+(d)->ht[1].size) 111 | #define dictSize(d) ((d)->ht[0].used+(d)->ht[1].used) 112 | #define dictIsRehashing(d) ((d)->rehashidx != -1) 113 | 114 | /* API */ 115 | dict *dictCreate(dictType *type, void *privDataPtr); 116 | int dictExpand(dict *d, unsigned long size); 117 | int dictAdd(dict *d, void *key, void *val); 118 | dictEntry *dictAddRaw(dict *d, void *key); 119 | int dictReplace(dict *d, void *key, void *val); 120 | dictEntry *dictReplaceRaw(dict *d, void *key); 121 | int dictDelete(dict *d, const void *key); 122 | int dictDeleteNoFree(dict *d, const void *key); 123 | void dictRelease(dict *d); 124 | dictEntry * dictFind(dict *d, const void *key); 125 | void *dictFetchValue(dict *d, const void *key); 126 | int dictResize(dict *d); 127 | dictIterator *dictGetIterator(dict *d); 128 | dictIterator *dictGetSafeIterator(dict *d); 129 | dictEntry *dictNext(dictIterator *iter); 130 | void dictReleaseIterator(dictIterator *iter); 131 | dictEntry *dictGetRandomKey(dict *d); 132 | unsigned int dictGetSomeKeys(dict *d, dictEntry **des, unsigned int count); 133 | void dictGetStats(char *buf, size_t bufsize, dict *d); 134 | unsigned int dictGenHashFunction(const void *key, int len); 135 | unsigned int dictGenCaseHashFunction(const unsigned char *buf, int len); 136 | void dictEmpty(dict *d, void(callback)(void*)); 137 | void dictEnableResize(void); 138 | void dictDisableResize(void); 139 | int dictRehash(dict *d, int n); 140 | int dictRehashMilliseconds(dict *d, int ms); 141 | void dictSetHashFunctionSeed(unsigned int initval); 142 | unsigned int dictGetHashFunctionSeed(void); 143 | unsigned long dictScan(dict *d, unsigned long v, dictScanFunction *fn, void *privdata); 144 | 145 | /* Hash table types */ 146 | extern dictType dictTypeHeapStringCopyKey; 147 | extern dictType dictTypeHeapStrings; 148 | extern dictType dictTypeHeapStringCopyKeyValue; 149 | 150 | #endif /* _VR_DICT_H_ */ 151 | -------------------------------------------------------------------------------- /src/vr_eventloop.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int 4 | vr_eventloop_init(vr_eventloop *vel, int filelimit) 5 | { 6 | rstatus_t status; 7 | int maxclients, threads_num; 8 | 9 | if (vel == NULL || filelimit <= 0) { 10 | return VR_ERROR; 11 | } 12 | 13 | vr_thread_init(&vel->thread); 14 | vel->el = NULL; 15 | vel->hz = 10; 16 | vel->cronloops = 0; 17 | vel->unixtime = time(NULL); 18 | vel->mstime = vr_msec_now(); 19 | vel->lruclock = getLRUClock(); 20 | vel->cb = NULL; 21 | vel->next_client_id = 1; /* Client IDs, start from 1 .*/ 22 | vel->current_client = NULL; 23 | vel->clients = NULL; 24 | vel->clients_pending_write = NULL; 25 | vel->clients_to_close = NULL; 26 | vel->clients_paused = 0; 27 | vel->clients_pause_end_time = 0; 28 | vel->stats = NULL; 29 | vel->resident_set_size = 0; 30 | vel->dirty = 0; 31 | vel->bpop_blocked_clients = 0; 32 | vel->unblocked_clients = NULL; 33 | vel->clients_waiting_acks = NULL; 34 | vel->pubsub_channels = NULL; 35 | vel->pubsub_patterns = NULL; 36 | vel->notify_keyspace_events = 0; 37 | vel->cstable = NULL; 38 | 39 | vel->el = aeCreateEventLoop(filelimit); 40 | if (vel->el == NULL) { 41 | log_error("create eventloop failed."); 42 | return VR_ERROR; 43 | } 44 | 45 | vel->cb = dalloc(sizeof(conn_base)); 46 | if (vel->cb == NULL) { 47 | log_error("create conn_base failed: out of memory"); 48 | return VR_ENOMEM; 49 | } 50 | status = conn_init(vel->cb); 51 | if (status != VR_OK) { 52 | log_error("init conn_base failed"); 53 | return VR_ERROR; 54 | } 55 | 56 | vel->clients = dlistCreate(); 57 | if (vel->clients == NULL) { 58 | log_error("create list failed: out of memory"); 59 | return VR_ENOMEM; 60 | } 61 | 62 | vel->clients_pending_write = dlistCreate(); 63 | if (vel->clients_pending_write == NULL) { 64 | log_error("create list failed: out of memory"); 65 | return VR_ENOMEM; 66 | } 67 | 68 | vel->clients_to_close = dlistCreate(); 69 | if (vel->clients_to_close == NULL) { 70 | log_error("create list failed: out of memory"); 71 | return VR_ENOMEM; 72 | } 73 | 74 | vel->unblocked_clients = dlistCreate(); 75 | if (vel->unblocked_clients == NULL) { 76 | log_error("create list failed: out of memory"); 77 | return VR_ENOMEM; 78 | } 79 | 80 | vel->stats = dalloc(sizeof(vr_stats)); 81 | if (vel->stats == NULL) { 82 | log_error("out of memory"); 83 | return VR_ENOMEM; 84 | } 85 | 86 | vr_stats_init(vel->stats); 87 | 88 | conf_cache_init(&vel->cc); 89 | 90 | return VR_OK; 91 | } 92 | 93 | void 94 | vr_eventloop_deinit(vr_eventloop *vel) 95 | { 96 | if (vel == NULL) { 97 | return; 98 | } 99 | 100 | vr_thread_deinit(&vel->thread); 101 | 102 | if (vel->el != NULL) { 103 | aeDeleteEventLoop(vel->el); 104 | vel->el = NULL; 105 | } 106 | 107 | if (vel->clients != NULL) { 108 | client *c; 109 | while (c = dlistPop(vel->clients)) { 110 | freeClient(c); 111 | } 112 | dlistRelease(vel->clients); 113 | vel->clients = NULL; 114 | } 115 | 116 | if (vel->clients_pending_write != NULL) { 117 | client *c; 118 | while (c = dlistPop(vel->clients_pending_write)) {} 119 | dlistRelease(vel->clients_pending_write); 120 | vel->clients_pending_write = NULL; 121 | } 122 | 123 | if (vel->clients_to_close != NULL) { 124 | client *c; 125 | while (c = dlistPop(vel->clients_to_close)) { 126 | freeClient(c); 127 | } 128 | dlistRelease(vel->clients_to_close); 129 | vel->clients_to_close = NULL; 130 | } 131 | 132 | if (vel->unblocked_clients != NULL) { 133 | client *c; 134 | while (c = dlistPop(vel->unblocked_clients)) {} 135 | dlistRelease(vel->unblocked_clients); 136 | vel->unblocked_clients = NULL; 137 | } 138 | 139 | if (vel->cb != NULL) { 140 | conn_deinit(vel->cb); 141 | dfree(vel->cb); 142 | vel->cb = NULL; 143 | } 144 | 145 | if (vel->stats != NULL) { 146 | vr_stats_deinit(vel->stats); 147 | dfree(vel->stats); 148 | vel->stats = NULL; 149 | } 150 | 151 | if (vel->cstable != NULL) { 152 | commandStatsTableDestroy(vel->cstable); 153 | vel->cstable = NULL; 154 | } 155 | 156 | conf_cache_deinit(&vel->cc); 157 | } 158 | 159 | -------------------------------------------------------------------------------- /src/vr_eventloop.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_EVENTLOOP_H_ 2 | #define _VR_EVENTLOOP_H_ 3 | 4 | typedef struct vr_eventloop { 5 | vr_thread thread; 6 | 7 | aeEventLoop *el; 8 | int hz; /* cron() calls frequency in hertz */ 9 | int cronloops; /* Number of times the cron function run */ 10 | 11 | /* time cache */ 12 | time_t unixtime; /* Unix time sampled every cron cycle. */ 13 | long long mstime; /* Like 'unixtime' but with milliseconds resolution. */ 14 | 15 | unsigned lruclock:LRU_BITS; /* Clock for LRU eviction */ 16 | 17 | conn_base *cb; 18 | 19 | uint64_t next_client_id; /* Next client unique ID. Incremental. */ 20 | struct client *current_client; /* Current client, only used on crash report */ 21 | dlist *clients; /* List of active clients */ 22 | dlist *clients_pending_write;/* There is to write or install handler. */ 23 | dlist *clients_to_close; /* Clients to close asynchronously */ 24 | 25 | int clients_paused; /* True if clients are currently paused */ 26 | long long clients_pause_end_time; /* Time when we undo clients_paused */ 27 | 28 | vr_stats *stats; /* stats for this thread */ 29 | size_t resident_set_size; /* RSS sampled in workerCron(). */ 30 | 31 | long long dirty; /* Changes to DB from the last save */ 32 | 33 | /* Blocked clients */ 34 | unsigned int bpop_blocked_clients; /* Number of clients blocked by lists */ 35 | dlist *unblocked_clients; /* list of clients to unblock before next loop */ 36 | 37 | /* Synchronous replication. */ 38 | dlist *clients_waiting_acks; /* Clients waiting in WAIT command. */ 39 | 40 | /* Pubsub */ 41 | dict *pubsub_channels; /* Map channels to list of subscribed clients */ 42 | dlist *pubsub_patterns; /* A list of pubsub_patterns */ 43 | int notify_keyspace_events; /* Events to propagate via Pub/Sub. This is an 44 | xor of NOTIFY_... flags. */ 45 | 46 | conf_cache cc; /* Cache the hot config option to improve vire speed. */ 47 | 48 | struct darray *cstable; /* type: commandStats */ 49 | }vr_eventloop; 50 | 51 | int vr_eventloop_init(vr_eventloop *vel, int filelimit); 52 | void vr_eventloop_deinit(vr_eventloop *vel); 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /src/vr_hyperloglog.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_HYPERLOGLOG_H_ 2 | #define _VR_HYPERLOGLOG_H_ 3 | 4 | uint64_t MurmurHash64A (const void * key, int len, unsigned int seed); 5 | int hllPatLen(unsigned char *ele, size_t elesize, long *regp); 6 | int hllDenseAdd(uint8_t *registers, unsigned char *ele, size_t elesize); 7 | double hllDenseSum(uint8_t *registers, double *PE, int *ezp); 8 | int hllSparseToDense(robj *o); 9 | int hllSparseAdd(robj *o, unsigned char *ele, size_t elesize); 10 | double hllSparseSum(uint8_t *sparse, int sparselen, double *PE, int *ezp, int *invalid); 11 | double hllRawSum(uint8_t *registers, double *PE, int *ezp); 12 | int hllAdd(robj *o, unsigned char *ele, size_t elesize); 13 | int hllMerge(uint8_t *max, robj *hll); 14 | robj *createHLLObject(void); 15 | int isHLLObjectOrReply(struct client *c, robj *o); 16 | void pfaddCommand(struct client *c); 17 | void pfcountCommand(struct client *c); 18 | void pfmergeCommand(struct client *c); 19 | void pfselftestCommand(struct client *c); 20 | void pfdebugCommand(struct client *c); 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /src/vr_intset.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_INTSET_H_ 2 | #define _VR_INTSET_H_ 3 | 4 | #include 5 | 6 | typedef struct intset { 7 | uint32_t encoding; 8 | uint32_t length; 9 | int8_t contents[]; 10 | } intset; 11 | 12 | intset *intsetNew(void); 13 | intset *intsetAdd(intset *is, int64_t value, uint8_t *success); 14 | intset *intsetRemove(intset *is, int64_t value, int *success); 15 | uint8_t intsetFind(intset *is, int64_t value); 16 | int64_t intsetRandom(intset *is); 17 | uint8_t intsetGet(intset *is, uint32_t pos, int64_t *value); 18 | uint32_t intsetLen(intset *is); 19 | size_t intsetBlobLen(intset *is); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /src/vr_listen.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_LISTEN_H_ 2 | #define _VR_LISTEN_H_ 3 | 4 | typedef struct vr_listen { 5 | sds name; /* hostname:port */ 6 | int port; /* port */ 7 | mode_t perm; /* socket permissions */ 8 | struct sockinfo info; /* listen socket info */ 9 | int sd; /* socket descriptor */ 10 | }vr_listen; 11 | 12 | vr_listen *vr_listen_create(sds linten_str); 13 | void vr_listen_destroy(vr_listen *vliston); 14 | rstatus_t vr_listen_begin(struct vr_listen *vlisten); 15 | int vr_listen_accept(vr_listen *vlisten); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/vr_lzf.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_LZF_H_ 2 | #define _VR_LZF_H_ 3 | 4 | /*********************************************************************** 5 | ** 6 | ** lzf -- an extremely fast/free compression/decompression-method 7 | ** http://liblzf.plan9.de/ 8 | ** 9 | ** This algorithm is believed to be patent-free. 10 | ** 11 | ***********************************************************************/ 12 | 13 | #define LZF_VERSION 0x0105 /* 1.5, API version */ 14 | 15 | /* 16 | * Compress in_len bytes stored at the memory block starting at 17 | * in_data and write the result to out_data, up to a maximum length 18 | * of out_len bytes. 19 | * 20 | * If the output buffer is not large enough or any error occurs return 0, 21 | * otherwise return the number of bytes used, which might be considerably 22 | * more than in_len (but less than 104% of the original size), so it 23 | * makes sense to always use out_len == in_len - 1), to ensure _some_ 24 | * compression, and store the data uncompressed otherwise (with a flag, of 25 | * course. 26 | * 27 | * lzf_compress might use different algorithms on different systems and 28 | * even different runs, thus might result in different compressed strings 29 | * depending on the phase of the moon or similar factors. However, all 30 | * these strings are architecture-independent and will result in the 31 | * original data when decompressed using lzf_decompress. 32 | * 33 | * The buffers must not be overlapping. 34 | * 35 | * If the option LZF_STATE_ARG is enabled, an extra argument must be 36 | * supplied which is not reflected in this header file. Refer to lzfP.h 37 | * and lzf_c.c. 38 | * 39 | */ 40 | unsigned int 41 | lzf_compress (const void *const in_data, unsigned int in_len, 42 | void *out_data, unsigned int out_len); 43 | 44 | /* 45 | * Decompress data compressed with some version of the lzf_compress 46 | * function and stored at location in_data and length in_len. The result 47 | * will be stored at out_data up to a maximum of out_len characters. 48 | * 49 | * If the output buffer is not large enough to hold the decompressed 50 | * data, a 0 is returned and errno is set to E2BIG. Otherwise the number 51 | * of decompressed bytes (i.e. the original length of the data) is 52 | * returned. 53 | * 54 | * If an error in the compressed data is detected, a zero is returned and 55 | * errno is set to EINVAL. 56 | * 57 | * This function is very fast, about as fast as a copying loop. 58 | */ 59 | unsigned int 60 | lzf_decompress (const void *const in_data, unsigned int in_len, 61 | void *out_data, unsigned int out_len); 62 | 63 | #endif 64 | 65 | -------------------------------------------------------------------------------- /src/vr_lzfP.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_LZFP_H_ 2 | #define _VR_LZFP_H_ 3 | 4 | #define STANDALONE 1 /* at the moment, this is ok. */ 5 | 6 | #ifndef STANDALONE 7 | #include 8 | #endif 9 | 10 | /* 11 | * Size of hashtable is (1 << HLOG) * sizeof (char *) 12 | * decompression is independent of the hash table size 13 | * the difference between 15 and 14 is very small 14 | * for small blocks (and 14 is usually a bit faster). 15 | * For a low-memory/faster configuration, use HLOG == 13; 16 | * For best compression, use 15 or 16 (or more, up to 22). 17 | */ 18 | #ifndef HLOG 19 | # define HLOG 16 20 | #endif 21 | 22 | /* 23 | * Sacrifice very little compression quality in favour of compression speed. 24 | * This gives almost the same compression as the default code, and is 25 | * (very roughly) 15% faster. This is the preferred mode of operation. 26 | */ 27 | #ifndef VERY_FAST 28 | # define VERY_FAST 1 29 | #endif 30 | 31 | /* 32 | * Sacrifice some more compression quality in favour of compression speed. 33 | * (roughly 1-2% worse compression for large blocks and 34 | * 9-10% for small, redundant, blocks and >>20% better speed in both cases) 35 | * In short: when in need for speed, enable this for binary data, 36 | * possibly disable this for text data. 37 | */ 38 | #ifndef ULTRA_FAST 39 | # define ULTRA_FAST 0 40 | #endif 41 | 42 | /* 43 | * Unconditionally aligning does not cost very much, so do it if unsure 44 | */ 45 | #ifndef STRICT_ALIGN 46 | # define STRICT_ALIGN !(defined(__i386) || defined (__amd64)) 47 | #endif 48 | 49 | /* 50 | * You may choose to pre-set the hash table (might be faster on some 51 | * modern cpus and large (>>64k) blocks, and also makes compression 52 | * deterministic/repeatable when the configuration otherwise is the same). 53 | */ 54 | #ifndef INIT_HTAB 55 | # define INIT_HTAB 0 56 | #endif 57 | 58 | /* 59 | * Avoid assigning values to errno variable? for some embedding purposes 60 | * (linux kernel for example), this is necessary. NOTE: this breaks 61 | * the documentation in lzf.h. Avoiding errno has no speed impact. 62 | */ 63 | #ifndef AVOID_ERRNO 64 | # define AVOID_ERRNO 0 65 | #endif 66 | 67 | /* 68 | * Whether to pass the LZF_STATE variable as argument, or allocate it 69 | * on the stack. For small-stack environments, define this to 1. 70 | * NOTE: this breaks the prototype in lzf.h. 71 | */ 72 | #ifndef LZF_STATE_ARG 73 | # define LZF_STATE_ARG 0 74 | #endif 75 | 76 | /* 77 | * Whether to add extra checks for input validity in lzf_decompress 78 | * and return EINVAL if the input stream has been corrupted. This 79 | * only shields against overflowing the input buffer and will not 80 | * detect most corrupted streams. 81 | * This check is not normally noticeable on modern hardware 82 | * (<1% slowdown), but might slow down older cpus considerably. 83 | */ 84 | #ifndef CHECK_INPUT 85 | # define CHECK_INPUT 1 86 | #endif 87 | 88 | /* 89 | * Whether to store pointers or offsets inside the hash table. On 90 | * 64 bit architetcures, pointers take up twice as much space, 91 | * and might also be slower. Default is to autodetect. 92 | */ 93 | /*#define LZF_USER_OFFSETS autodetect */ 94 | 95 | /*****************************************************************************/ 96 | /* nothing should be changed below */ 97 | 98 | #ifdef __cplusplus 99 | # include 100 | # include 101 | using namespace std; 102 | #else 103 | # include 104 | # include 105 | #endif 106 | 107 | #ifndef LZF_USE_OFFSETS 108 | # if defined (WIN32) 109 | # define LZF_USE_OFFSETS defined(_M_X64) 110 | # else 111 | # if __cplusplus > 199711L 112 | # include 113 | # else 114 | # include 115 | # endif 116 | # define LZF_USE_OFFSETS (UINTPTR_MAX > 0xffffffffU) 117 | # endif 118 | #endif 119 | 120 | typedef unsigned char u8; 121 | 122 | #if LZF_USE_OFFSETS 123 | # define LZF_HSLOT_BIAS ((const u8 *)in_data) 124 | typedef unsigned int LZF_HSLOT; 125 | #else 126 | # define LZF_HSLOT_BIAS 0 127 | typedef const u8 *LZF_HSLOT; 128 | #endif 129 | 130 | typedef LZF_HSLOT LZF_STATE[1 << (HLOG)]; 131 | 132 | #if !STRICT_ALIGN 133 | /* for unaligned accesses we need a 16 bit datatype. */ 134 | # if USHRT_MAX == 65535 135 | typedef unsigned short u16; 136 | # elif UINT_MAX == 65535 137 | typedef unsigned int u16; 138 | # else 139 | # undef STRICT_ALIGN 140 | # define STRICT_ALIGN 1 141 | # endif 142 | #endif 143 | 144 | #if ULTRA_FAST 145 | # undef VERY_FAST 146 | #endif 147 | 148 | #endif 149 | 150 | -------------------------------------------------------------------------------- /src/vr_lzf_d.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if AVOID_ERRNO 4 | # define SET_ERRNO(n) 5 | #else 6 | # include 7 | # define SET_ERRNO(n) errno = (n) 8 | #endif 9 | 10 | #if USE_REP_MOVSB /* small win on amd, big loss on intel */ 11 | #if (__i386 || __amd64) && __GNUC__ >= 3 12 | # define lzf_movsb(dst, src, len) \ 13 | asm ("rep movsb" \ 14 | : "=D" (dst), "=S" (src), "=c" (len) \ 15 | : "0" (dst), "1" (src), "2" (len)); 16 | #endif 17 | #endif 18 | 19 | unsigned int 20 | lzf_decompress (const void *const in_data, unsigned int in_len, 21 | void *out_data, unsigned int out_len) 22 | { 23 | u8 const *ip = (const u8 *)in_data; 24 | u8 *op = (u8 *)out_data; 25 | u8 const *const in_end = ip + in_len; 26 | u8 *const out_end = op + out_len; 27 | 28 | do 29 | { 30 | unsigned int ctrl = *ip++; 31 | 32 | if (ctrl < (1 << 5)) /* literal run */ 33 | { 34 | ctrl++; 35 | 36 | if (op + ctrl > out_end) 37 | { 38 | SET_ERRNO (E2BIG); 39 | return 0; 40 | } 41 | 42 | #if CHECK_INPUT 43 | if (ip + ctrl > in_end) 44 | { 45 | SET_ERRNO (EINVAL); 46 | return 0; 47 | } 48 | #endif 49 | 50 | #ifdef lzf_movsb 51 | lzf_movsb (op, ip, ctrl); 52 | #else 53 | switch (ctrl) 54 | { 55 | case 32: *op++ = *ip++; case 31: *op++ = *ip++; case 30: *op++ = *ip++; case 29: *op++ = *ip++; 56 | case 28: *op++ = *ip++; case 27: *op++ = *ip++; case 26: *op++ = *ip++; case 25: *op++ = *ip++; 57 | case 24: *op++ = *ip++; case 23: *op++ = *ip++; case 22: *op++ = *ip++; case 21: *op++ = *ip++; 58 | case 20: *op++ = *ip++; case 19: *op++ = *ip++; case 18: *op++ = *ip++; case 17: *op++ = *ip++; 59 | case 16: *op++ = *ip++; case 15: *op++ = *ip++; case 14: *op++ = *ip++; case 13: *op++ = *ip++; 60 | case 12: *op++ = *ip++; case 11: *op++ = *ip++; case 10: *op++ = *ip++; case 9: *op++ = *ip++; 61 | case 8: *op++ = *ip++; case 7: *op++ = *ip++; case 6: *op++ = *ip++; case 5: *op++ = *ip++; 62 | case 4: *op++ = *ip++; case 3: *op++ = *ip++; case 2: *op++ = *ip++; case 1: *op++ = *ip++; 63 | } 64 | #endif 65 | } 66 | else /* back reference */ 67 | { 68 | unsigned int len = ctrl >> 5; 69 | 70 | u8 *ref = op - ((ctrl & 0x1f) << 8) - 1; 71 | 72 | #if CHECK_INPUT 73 | if (ip >= in_end) 74 | { 75 | SET_ERRNO (EINVAL); 76 | return 0; 77 | } 78 | #endif 79 | if (len == 7) 80 | { 81 | len += *ip++; 82 | #if CHECK_INPUT 83 | if (ip >= in_end) 84 | { 85 | SET_ERRNO (EINVAL); 86 | return 0; 87 | } 88 | #endif 89 | } 90 | 91 | ref -= *ip++; 92 | 93 | if (op + len + 2 > out_end) 94 | { 95 | SET_ERRNO (E2BIG); 96 | return 0; 97 | } 98 | 99 | if (ref < (u8 *)out_data) 100 | { 101 | SET_ERRNO (EINVAL); 102 | return 0; 103 | } 104 | 105 | #ifdef lzf_movsb 106 | len += 2; 107 | lzf_movsb (op, ref, len); 108 | #else 109 | switch (len) 110 | { 111 | default: 112 | len += 2; 113 | 114 | if (op >= ref + len) 115 | { 116 | /* disjunct areas */ 117 | memcpy (op, ref, len); 118 | op += len; 119 | } 120 | else 121 | { 122 | /* overlapping, use octte by octte copying */ 123 | do 124 | *op++ = *ref++; 125 | while (--len); 126 | } 127 | 128 | break; 129 | 130 | case 9: *op++ = *ref++; 131 | case 8: *op++ = *ref++; 132 | case 7: *op++ = *ref++; 133 | case 6: *op++ = *ref++; 134 | case 5: *op++ = *ref++; 135 | case 4: *op++ = *ref++; 136 | case 3: *op++ = *ref++; 137 | case 2: *op++ = *ref++; 138 | case 1: *op++ = *ref++; 139 | case 0: *op++ = *ref++; /* two octets more */ 140 | *op++ = *ref++; 141 | } 142 | #endif 143 | } 144 | } 145 | while (ip < in_end); 146 | 147 | return op - (u8 *)out_data; 148 | } 149 | 150 | -------------------------------------------------------------------------------- /src/vr_master.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_MASTER_H_ 2 | #define _VR_MASTER_H_ 3 | 4 | typedef struct vr_master { 5 | 6 | vr_eventloop vel; 7 | 8 | struct darray listens; /* type: vr_listen */ 9 | 10 | dlist *cbsul; /* Connect back swap unit list */ 11 | pthread_mutex_t cbsullock; /* swap unit list locker */ 12 | }vr_master; 13 | 14 | extern vr_master master; 15 | 16 | int master_init(vr_conf *conf); 17 | void master_deinit(void); 18 | 19 | void dispatch_conn_exist(struct client *c, int tid); 20 | 21 | int master_run(void); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /src/vr_multi.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_MULTI_H_ 2 | #define _VR_MULTI_H_ 3 | 4 | /* Client MULTI/EXEC state */ 5 | typedef struct multiCmd { 6 | robj **argv; 7 | int argc; 8 | struct redisCommand *cmd; 9 | } multiCmd; 10 | 11 | typedef struct multiState { 12 | multiCmd *commands; /* Array of MULTI commands */ 13 | int count; /* Total number of MULTI commands */ 14 | int minreplicas; /* MINREPLICAS for synchronous replication */ 15 | time_t minreplicas_timeout; /* MINREPLICAS timeout as unixtime. */ 16 | } multiState; 17 | 18 | void unwatchAllKeys(struct client *c); 19 | void initClientMultiState(struct client *c); 20 | void freeClientMultiState(struct client *c); 21 | void queueMultiCommand(struct client *c); 22 | 23 | void flagTransaction(struct client *c); 24 | void execCommand(struct client *c); 25 | void discardCommand(struct client *c); 26 | void discardTransaction(struct client *c); 27 | void multiCommand(struct client *c); 28 | void watchForKey(struct client *c, robj *key); 29 | void watchCommand(struct client *c); 30 | void touchWatchedKey(redisDb *db, robj *key); 31 | void touchWatchedKeysOnFlush(int dbid) ; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/vr_notify.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* This file implements keyspace events notification via Pub/Sub ad 4 | * described at http://redis.io/topics/keyspace-events. */ 5 | 6 | /* Turn a string representing notification classes into an integer 7 | * representing notification classes flags xored. 8 | * 9 | * The function returns -1 if the input contains characters not mapping to 10 | * any class. */ 11 | int keyspaceEventsStringToFlags(char *classes) { 12 | char *p = classes; 13 | int c, flags = 0; 14 | 15 | while((c = *p++) != '\0') { 16 | switch(c) { 17 | case 'A': flags |= NOTIFY_ALL; break; 18 | case 'g': flags |= NOTIFY_GENERIC; break; 19 | case '$': flags |= NOTIFY_STRING; break; 20 | case 'l': flags |= NOTIFY_LIST; break; 21 | case 's': flags |= NOTIFY_SET; break; 22 | case 'h': flags |= NOTIFY_HASH; break; 23 | case 'z': flags |= NOTIFY_ZSET; break; 24 | case 'x': flags |= NOTIFY_EXPIRED; break; 25 | case 'e': flags |= NOTIFY_EVICTED; break; 26 | case 'K': flags |= NOTIFY_KEYSPACE; break; 27 | case 'E': flags |= NOTIFY_KEYEVENT; break; 28 | default: return -1; 29 | } 30 | } 31 | return flags; 32 | } 33 | 34 | /* This function does exactly the revese of the function above: it gets 35 | * as input an integer with the xored flags and returns a string representing 36 | * the selected classes. The string returned is an sds string that needs to 37 | * be released with sdsfree(). */ 38 | sds keyspaceEventsFlagsToString(int flags) { 39 | sds res; 40 | 41 | res = sdsempty(); 42 | if ((flags & NOTIFY_ALL) == NOTIFY_ALL) { 43 | res = sdscatlen(res,"A",1); 44 | } else { 45 | if (flags & NOTIFY_GENERIC) res = sdscatlen(res,"g",1); 46 | if (flags & NOTIFY_STRING) res = sdscatlen(res,"$",1); 47 | if (flags & NOTIFY_LIST) res = sdscatlen(res,"l",1); 48 | if (flags & NOTIFY_SET) res = sdscatlen(res,"s",1); 49 | if (flags & NOTIFY_HASH) res = sdscatlen(res,"h",1); 50 | if (flags & NOTIFY_ZSET) res = sdscatlen(res,"z",1); 51 | if (flags & NOTIFY_EXPIRED) res = sdscatlen(res,"x",1); 52 | if (flags & NOTIFY_EVICTED) res = sdscatlen(res,"e",1); 53 | } 54 | if (flags & NOTIFY_KEYSPACE) res = sdscatlen(res,"K",1); 55 | if (flags & NOTIFY_KEYEVENT) res = sdscatlen(res,"E",1); 56 | return res; 57 | } 58 | 59 | /* The API provided to the rest of the Redis core is a simple function: 60 | * 61 | * notifyKeyspaceEvent(char *event, robj *key, int dbid); 62 | * 63 | * 'event' is a C string representing the event name. 64 | * 'key' is a Redis object representing the key name. 65 | * 'dbid' is the database ID where the key lives. */ 66 | void notifyKeyspaceEvent(int type, char *event, robj *key, int dbid) { 67 | sds chan; 68 | robj *chanobj, *eventobj; 69 | int len = -1; 70 | char buf[24]; 71 | 72 | /* If notifications for this class of events are off, return ASAP. */ 73 | if (!(server.notify_keyspace_events & type)) return; 74 | 75 | eventobj = createStringObject(event,strlen(event)); 76 | 77 | /* __keyspace@__: notifications. */ 78 | if (server.notify_keyspace_events & NOTIFY_KEYSPACE) { 79 | chan = sdsnewlen("__keyspace@",11); 80 | len = ll2string(buf,sizeof(buf),dbid); 81 | chan = sdscatlen(chan, buf, len); 82 | chan = sdscatlen(chan, "__:", 3); 83 | chan = sdscatsds(chan, key->ptr); 84 | chanobj = createObject(OBJ_STRING, chan); 85 | pubsubPublishMessage(chanobj, eventobj); 86 | decrRefCount(chanobj); 87 | } 88 | 89 | /* __keyevente@__: notifications. */ 90 | if (server.notify_keyspace_events & NOTIFY_KEYEVENT) { 91 | chan = sdsnewlen("__keyevent@",11); 92 | if (len == -1) len = ll2string(buf,sizeof(buf),dbid); 93 | chan = sdscatlen(chan, buf, len); 94 | chan = sdscatlen(chan, "__:", 3); 95 | chan = sdscatsds(chan, eventobj->ptr); 96 | chanobj = createObject(OBJ_STRING, chan); 97 | pubsubPublishMessage(chanobj, key); 98 | decrRefCount(chanobj); 99 | } 100 | decrRefCount(eventobj); 101 | } 102 | 103 | 104 | -------------------------------------------------------------------------------- /src/vr_notify.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_NOTIFY_H_ 2 | #define _VR_NOTIFY_H_ 3 | 4 | /* Keyspace changes notification classes. Every class is associated with a 5 | * character for configuration purposes. */ 6 | #define NOTIFY_KEYSPACE (1<<0) /* K */ 7 | #define NOTIFY_KEYEVENT (1<<1) /* E */ 8 | #define NOTIFY_GENERIC (1<<2) /* g */ 9 | #define NOTIFY_STRING (1<<3) /* $ */ 10 | #define NOTIFY_LIST (1<<4) /* l */ 11 | #define NOTIFY_SET (1<<5) /* s */ 12 | #define NOTIFY_HASH (1<<6) /* h */ 13 | #define NOTIFY_ZSET (1<<7) /* z */ 14 | #define NOTIFY_EXPIRED (1<<8) /* x */ 15 | #define NOTIFY_EVICTED (1<<9) /* e */ 16 | #define NOTIFY_ALL (NOTIFY_GENERIC | NOTIFY_STRING | NOTIFY_LIST | NOTIFY_SET | NOTIFY_HASH | NOTIFY_ZSET | NOTIFY_EXPIRED | NOTIFY_EVICTED) /* A */ 17 | 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /src/vr_object.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_OBJECT_H_ 2 | #define _VR_OBJECT_H_ 3 | 4 | #define OBJ_SHARED_INTEGERS 10000 5 | #define OBJ_SHARED_BULKHDR_LEN 32 6 | 7 | /* Object types */ 8 | #define OBJ_STRING 0 9 | #define OBJ_LIST 1 10 | #define OBJ_SET 2 11 | #define OBJ_ZSET 3 12 | #define OBJ_HASH 4 13 | 14 | /* Objects encoding. Some kind of objects like Strings and Hashes can be 15 | * internally represented in multiple ways. The 'encoding' field of the object 16 | * is set to one of this fields for this object. */ 17 | #define OBJ_ENCODING_RAW 0 /* Raw representation */ 18 | #define OBJ_ENCODING_INT 1 /* Encoded as integer */ 19 | #define OBJ_ENCODING_HT 2 /* Encoded as hash table */ 20 | #define OBJ_ENCODING_ZIPMAP 3 /* Encoded as zipmap */ 21 | #define OBJ_ENCODING_LINKEDLIST 4 /* Encoded as regular linked list */ 22 | #define OBJ_ENCODING_ZIPLIST 5 /* Encoded as ziplist */ 23 | #define OBJ_ENCODING_INTSET 6 /* Encoded as intset */ 24 | #define OBJ_ENCODING_SKIPLIST 7 /* Encoded as skiplist */ 25 | #define OBJ_ENCODING_EMBSTR 8 /* Embedded sds string encoding */ 26 | #define OBJ_ENCODING_QUICKLIST 9 /* Encoded as linked list of ziplists */ 27 | 28 | #define OBJ_HASH_KEY 1 29 | #define OBJ_HASH_VALUE 2 30 | 31 | #define sdsEncodedObject(objptr) (objptr->encoding == OBJ_ENCODING_RAW || objptr->encoding == OBJ_ENCODING_EMBSTR) 32 | 33 | /* The actual Redis Object */ 34 | #define LRU_BITS 24 35 | #define LRU_CLOCK_MAX ((1<lru */ 36 | #define LRU_CLOCK_RESOLUTION 1000 /* LRU clock resolution in ms */ 37 | typedef struct vr_object { 38 | unsigned type:4; 39 | unsigned encoding:4; 40 | unsigned lru:LRU_BITS; /* lru time (relative to server.lruclock) */ 41 | unsigned constant:1; 42 | int refcount; 43 | void *ptr; 44 | } robj; 45 | 46 | void decrRefCount(robj *o); 47 | void decrRefCountVoid(void *o); 48 | void incrRefCount(robj *o); 49 | robj *resetRefCount(robj *obj); 50 | void freeObject(robj *o); 51 | void freeObjectVoid(void *o); 52 | void freeStringObject(robj *o); 53 | void freeListObject(robj *o); 54 | void freeSetObject(robj *o); 55 | void freeZsetObject(robj *o); 56 | void freeHashObject(robj *o); 57 | robj *createObject(int type, void *ptr); 58 | robj *createStringObject(const char *ptr, size_t len); 59 | robj *createRawStringObject(const char *ptr, size_t len); 60 | robj *createEmbeddedStringObject(const char *ptr, size_t len); 61 | robj *dupStringObject(robj *o); 62 | robj *dupStringObjectUnconstant(robj *o); 63 | int isObjectRepresentableAsLongLong(robj *o, long long *llongval); 64 | robj *tryObjectEncoding(robj *o); 65 | robj *getDecodedObject(robj *o); 66 | size_t stringObjectLen(robj *o); 67 | robj *createStringObjectFromLongLong(long long value); 68 | robj *createStringObjectFromLongDouble(long double value, int humanfriendly); 69 | robj *createQuicklistObject(void); 70 | robj *createZiplistObject(void); 71 | robj *createSetObject(void); 72 | robj *createIntsetObject(void); 73 | robj *createHashObject(void); 74 | robj *createZsetObject(void); 75 | robj *createZsetZiplistObject(void); 76 | int getLongFromObjectOrReply(struct client *c, robj *o, long *target, const char *msg); 77 | int checkType(struct client *c, robj *o, int type); 78 | int getLongLongFromObjectOrReply(struct client *c, robj *o, long long *target, const char *msg); 79 | int getDoubleFromObjectOrReply(struct client *c, robj *o, double *target, const char *msg); 80 | int getLongLongFromObject(robj *o, long long *target); 81 | int getLongDoubleFromObject(robj *o, long double *target); 82 | int getLongDoubleFromObjectOrReply(struct client *c, robj *o, long double *target, const char *msg); 83 | char *strEncoding(int encoding); 84 | int compareStringObjects(robj *a, robj *b); 85 | int collateStringObjects(robj *a, robj *b); 86 | int equalStringObjects(robj *a, robj *b); 87 | unsigned long long estimateObjectIdleTime(robj *o); 88 | 89 | size_t getStringObjectSdsUsedMemory(robj *o); 90 | 91 | robj *objectCommandLookup(struct client *c, robj *key); 92 | robj *objectCommandLookupOrReply(struct client *c, robj *key, robj *reply); 93 | void objectCommand(struct client *c); 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /src/vr_pubsub.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_PUBSUB_H_ 2 | #define _VR_PUBSUB_H_ 3 | 4 | typedef struct pubsubPattern { 5 | client *client; 6 | robj *pattern; 7 | } pubsubPattern; 8 | 9 | int pubsubUnsubscribeChannel(client *c, robj *channel, int notify); 10 | int pubsubUnsubscribeAllChannels(client *c, int notify); 11 | int pubsubUnsubscribePattern(client *c, robj *pattern, int notify); 12 | int pubsubUnsubscribeAllPatterns(client *c, int notify); 13 | int pubsubSubscribeChannel(client *c, robj *channel); 14 | int clientSubscriptionsCount(client *c); 15 | void subscribeCommand(client *c); 16 | void unsubscribeCommand(client *c); 17 | void psubscribeCommand(client *c); 18 | void punsubscribeCommand(client *c); 19 | int pubsubSubscribePattern(client *c, robj *pattern); 20 | int pubsubPublishMessage(robj *channel, robj *message); 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /src/vr_rbtree.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_RBTREE_ 2 | #define _VR_RBTREE_ 3 | 4 | #define rbtree_red(_node) ((_node)->color = 1) 5 | #define rbtree_black(_node) ((_node)->color = 0) 6 | #define rbtree_is_red(_node) ((_node)->color) 7 | #define rbtree_is_black(_node) (!rbtree_is_red(_node)) 8 | #define rbtree_copy_color(_n1, _n2) ((_n1)->color = (_n2)->color) 9 | 10 | struct rbnode { 11 | struct rbnode *left; /* left link */ 12 | struct rbnode *right; /* right link */ 13 | struct rbnode *parent; /* parent link */ 14 | int64_t key; /* key for ordering */ 15 | void *data; /* opaque data */ 16 | uint8_t color; /* red | black */ 17 | }; 18 | 19 | struct rbtree { 20 | struct rbnode *root; /* root node */ 21 | struct rbnode *sentinel; /* nil node */ 22 | }; 23 | 24 | void rbtree_node_init(struct rbnode *node); 25 | void rbtree_init(struct rbtree *tree, struct rbnode *node); 26 | struct rbnode *rbtree_min(struct rbtree *tree); 27 | void rbtree_insert(struct rbtree *tree, struct rbnode *node); 28 | void rbtree_delete(struct rbtree *tree, struct rbnode *node); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/vr_rdb.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Save the DB on disk. Return C_ERR on error, C_OK on success. */ 4 | int rdbSave(char *filename) { 5 | return VR_OK; 6 | } 7 | 8 | void rdbRemoveTempFile(pid_t childpid) { 9 | char tmpfile[256]; 10 | 11 | snprintf(tmpfile,sizeof(tmpfile),"temp-%d.rdb", (int) childpid); 12 | unlink(tmpfile); 13 | } 14 | -------------------------------------------------------------------------------- /src/vr_rdb.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_RDB_H_ 2 | #define _VR_RDB_H_ 3 | 4 | /* Defines related to the dump file format. To store 32 bits lengths for short 5 | * keys requires a lot of space, so we check the most significant 2 bits of 6 | * the first byte to interpreter the length: 7 | * 8 | * 00|000000 => if the two MSB are 00 the len is the 6 bits of this byte 9 | * 01|000000 00000000 => 01, the len is 14 byes, 6 bits + 8 bits of next byte 10 | * 10|000000 [32 bit integer] => if it's 10, a full 32 bit len will follow 11 | * 11|000000 this means: specially encoded object will follow. The six bits 12 | * number specify the kind of object that follows. 13 | * See the RDB_ENC_* defines. 14 | * 15 | * Lengths up to 63 are stored using a single byte, most DB keys, and may 16 | * values, will fit inside. */ 17 | #define RDB_6BITLEN 0 18 | #define RDB_14BITLEN 1 19 | #define RDB_32BITLEN 2 20 | #define RDB_ENCVAL 3 21 | #define RDB_LENERR UINT_MAX 22 | 23 | /* When a length of a string object stored on disk has the first two bits 24 | * set, the remaining two bits specify a special encoding for the object 25 | * accordingly to the following defines: */ 26 | #define RDB_ENC_INT8 0 /* 8 bit signed integer */ 27 | #define RDB_ENC_INT16 1 /* 16 bit signed integer */ 28 | #define RDB_ENC_INT32 2 /* 32 bit signed integer */ 29 | #define RDB_ENC_LZF 3 /* string compressed with FASTLZ */ 30 | 31 | struct saveparam { 32 | time_t seconds; 33 | int changes; 34 | }; 35 | 36 | int rdbSave(char *filename); 37 | void rdbRemoveTempFile(pid_t childpid); 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/vr_scripting.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void scriptCommand(client *c) { 4 | addReply(c,shared.ok); 5 | } 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/vr_scripting.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_SCRIPTING_H_ 2 | #define _VR_SCRIPTING_H_ 3 | 4 | void scriptCommand(client *c); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /src/vr_signal.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | static struct signal signals[] = { 8 | { SIGUSR1, "SIGUSR1", 0, signal_handler }, 9 | { SIGUSR2, "SIGUSR2", 0, signal_handler }, 10 | { SIGTTIN, "SIGTTIN", 0, signal_handler }, 11 | { SIGTTOU, "SIGTTOU", 0, signal_handler }, 12 | { SIGHUP, "SIGHUP", 0, signal_handler }, 13 | { SIGINT, "SIGINT", 0, signal_handler }, 14 | { SIGSEGV, "SIGSEGV", (int)SA_RESETHAND, signal_handler }, 15 | { SIGPIPE, "SIGPIPE", 0, SIG_IGN }, 16 | { 0, NULL, 0, NULL } 17 | }; 18 | 19 | rstatus_t 20 | signal_init(void) 21 | { 22 | struct signal *sig; 23 | 24 | for (sig = signals; sig->signo != 0; sig++) { 25 | rstatus_t status; 26 | struct sigaction sa; 27 | 28 | memset(&sa, 0, sizeof(sa)); 29 | sa.sa_handler = sig->handler; 30 | sa.sa_flags = sig->flags; 31 | sigemptyset(&sa.sa_mask); 32 | 33 | status = sigaction(sig->signo, &sa, NULL); 34 | if (status < 0) { 35 | log_error("sigaction(%s) failed: %s", sig->signame, 36 | strerror(errno)); 37 | return VR_ERROR; 38 | } 39 | } 40 | 41 | return VR_OK; 42 | } 43 | 44 | void 45 | signal_deinit(void) 46 | { 47 | } 48 | 49 | void 50 | signal_handler(int signo) 51 | { 52 | struct signal *sig; 53 | void (*action)(void); 54 | char *actionstr; 55 | bool done; 56 | 57 | for (sig = signals; sig->signo != 0; sig++) { 58 | if (sig->signo == signo) { 59 | break; 60 | } 61 | } 62 | ASSERT(sig->signo != 0); 63 | 64 | actionstr = ""; 65 | action = NULL; 66 | done = false; 67 | 68 | switch (signo) { 69 | case SIGUSR1: 70 | break; 71 | 72 | case SIGUSR2: 73 | break; 74 | 75 | case SIGTTIN: 76 | actionstr = ", up logging level"; 77 | action = log_level_up; 78 | break; 79 | 80 | case SIGTTOU: 81 | actionstr = ", down logging level"; 82 | action = log_level_down; 83 | break; 84 | 85 | case SIGHUP: 86 | actionstr = ", reopening log file"; 87 | action = log_reopen; 88 | break; 89 | 90 | case SIGINT: 91 | done = true; 92 | actionstr = ", exiting"; 93 | break; 94 | 95 | case SIGSEGV: 96 | log_stacktrace(); 97 | actionstr = ", core dumping"; 98 | raise(SIGSEGV); 99 | break; 100 | 101 | default: 102 | NOT_REACHED(); 103 | } 104 | 105 | log_safe("signal %d (%s) received%s", signo, sig->signame, actionstr); 106 | 107 | if (action != NULL) { 108 | action(); 109 | } 110 | 111 | if (done) { 112 | exit(1); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/vr_signal.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_SIGNAL_H_ 2 | #define _VR_SIGNAL_H_ 3 | 4 | struct signal { 5 | int signo; 6 | char *signame; 7 | int flags; 8 | void (*handler)(int signo); 9 | }; 10 | 11 | rstatus_t signal_init(void); 12 | void signal_deinit(void); 13 | void signal_handler(int signo); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /src/vr_slowlog.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static pthread_rwlock_t rwlocker; 4 | static dlist *slowlog; /* SLOWLOG list of commands */ 5 | static long long slowlog_entry_id; /* SLOWLOG current entry ID */ 6 | 7 | /* Create a new slowlog entry. 8 | * Incrementing the ref count of all the objects retained is up to 9 | * this function. */ 10 | slowlogEntry *slowlogCreateEntry(robj **argv, int argc, long long duration) { 11 | slowlogEntry *se = dalloc(sizeof(*se)); 12 | int j, slargc = argc; 13 | 14 | if (slargc > SLOWLOG_ENTRY_MAX_ARGC) slargc = SLOWLOG_ENTRY_MAX_ARGC; 15 | se->argc = slargc; 16 | se->argv = dalloc(sizeof(robj*)*slargc); 17 | for (j = 0; j < slargc; j++) { 18 | /* Logging too many arguments is a useless memory waste, so we stop 19 | * at SLOWLOG_ENTRY_MAX_ARGC, but use the last argument to specify 20 | * how many remaining arguments there were in the original command. */ 21 | if (slargc != argc && j == slargc-1) { 22 | se->argv[j] = createObject(OBJ_STRING, 23 | sdscatprintf(sdsempty(),"... (%d more arguments)", 24 | argc-slargc+1)); 25 | } else { 26 | /* Trim too long strings as well... */ 27 | if (argv[j]->type == OBJ_STRING && 28 | sdsEncodedObject(argv[j]) && 29 | sdslen(argv[j]->ptr) > SLOWLOG_ENTRY_MAX_STRING) 30 | { 31 | sds s = sdsnewlen(argv[j]->ptr, SLOWLOG_ENTRY_MAX_STRING); 32 | 33 | s = sdscatprintf(s,"... (%lu more bytes)", 34 | (unsigned long) 35 | sdslen(argv[j]->ptr) - SLOWLOG_ENTRY_MAX_STRING); 36 | se->argv[j] = createObject(OBJ_STRING,s); 37 | } else { 38 | se->argv[j] = dupStringObjectUnconstant(argv[j]); 39 | } 40 | } 41 | } 42 | se->time = time(NULL); 43 | se->duration = duration; 44 | return se; 45 | } 46 | 47 | /* Free a slow log entry. The argument is void so that the prototype of this 48 | * function matches the one of the 'free' method of adlist.c. 49 | * 50 | * This function will take care to release all the retained object. */ 51 | void slowlogFreeEntry(void *septr) { 52 | slowlogEntry *se = septr; 53 | int j; 54 | 55 | for (j = 0; j < se->argc; j++) 56 | freeObject(se->argv[j]); 57 | dfree(se->argv); 58 | dfree(se); 59 | } 60 | 61 | /* Initialize the slow log. This function should be called a single time 62 | * at server startup. */ 63 | void slowlogInit(void) { 64 | pthread_rwlock_init(&rwlocker,NULL); 65 | slowlog = dlistCreate(); 66 | slowlog_entry_id = 0; 67 | dlistSetFreeMethod(slowlog,slowlogFreeEntry); 68 | } 69 | 70 | /* Push a new entry into the slow log. 71 | * This function will make sure to trim the slow log accordingly to the 72 | * configured max length. */ 73 | void slowlogPushEntryIfNeeded(vr_eventloop *vel, robj **argv, int argc, long long duration) { 74 | long long slowlog_log_slower_than; 75 | int slowlog_max_len; 76 | 77 | slowlog_log_slower_than = vel->cc.slowlog_log_slower_than; 78 | if (slowlog_log_slower_than < 0) return; /* Slowlog disabled */ 79 | if (duration >= slowlog_log_slower_than) { 80 | slowlogEntry *se = slowlogCreateEntry(argv,argc,duration); 81 | pthread_rwlock_wrlock(&rwlocker); 82 | se->id = slowlog_entry_id++; 83 | dlistAddNodeHead(slowlog,se); 84 | pthread_rwlock_unlock(&rwlocker); 85 | } 86 | 87 | conf_server_get(CONFIG_SOPN_SLOWLOGML,&slowlog_max_len); 88 | /* Remove old entries if needed. */ 89 | pthread_rwlock_wrlock(&rwlocker); 90 | while (dlistLength(slowlog) > slowlog_max_len) 91 | dlistDelNode(slowlog,dlistLast(slowlog)); 92 | pthread_rwlock_unlock(&rwlocker); 93 | } 94 | 95 | /* Remove all the entries from the current slow log. */ 96 | void slowlogReset(void) { 97 | pthread_rwlock_wrlock(&rwlocker); 98 | while (dlistLength(slowlog) > 0) 99 | dlistDelNode(slowlog,dlistLast(slowlog)); 100 | pthread_rwlock_unlock(&rwlocker); 101 | } 102 | 103 | /* The SLOWLOG command. Implements all the subcommands needed to handle the 104 | * Redis slow log. */ 105 | void slowlogCommand(client *c) { 106 | if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"reset")) { 107 | slowlogReset(); 108 | addReply(c,shared.ok); 109 | } else if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"len")) { 110 | unsigned long len; 111 | pthread_rwlock_rdlock(&rwlocker); 112 | len = dlistLength(slowlog); 113 | pthread_rwlock_unlock(&rwlocker); 114 | addReplyLongLong(c,len); 115 | } else if ((c->argc == 2 || c->argc == 3) && 116 | !strcasecmp(c->argv[1]->ptr,"get")) 117 | { 118 | long count = 10, sent = 0; 119 | dlistIter li; 120 | void *totentries; 121 | dlistNode *ln; 122 | slowlogEntry *se; 123 | 124 | if (c->argc == 3 && 125 | getLongFromObjectOrReply(c,c->argv[2],&count,NULL) != VR_OK) 126 | return; 127 | 128 | pthread_rwlock_rdlock(&rwlocker); 129 | dlistRewind(slowlog,&li); 130 | totentries = addDeferredMultiBulkLength(c); 131 | while(count-- && (ln = dlistNext(&li))) { 132 | int j; 133 | 134 | se = ln->value; 135 | addReplyMultiBulkLen(c,4); 136 | addReplyLongLong(c,se->id); 137 | addReplyLongLong(c,se->time); 138 | addReplyLongLong(c,se->duration); 139 | addReplyMultiBulkLen(c,se->argc); 140 | for (j = 0; j < se->argc; j++) 141 | addReplyBulk(c,se->argv[j]); 142 | sent++; 143 | } 144 | pthread_rwlock_unlock(&rwlocker); 145 | setDeferredMultiBulkLength(c,totentries,sent); 146 | } else { 147 | addReplyError(c, 148 | "Unknown SLOWLOG subcommand or wrong # of args. Try GET, RESET, LEN."); 149 | } 150 | } 151 | 152 | -------------------------------------------------------------------------------- /src/vr_slowlog.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_SLOWLOG_H_ 2 | #define _VR_SLOWLOG_H_ 3 | 4 | #define SLOWLOG_ENTRY_MAX_ARGC 32 5 | #define SLOWLOG_ENTRY_MAX_STRING 128 6 | 7 | /* This structure defines an entry inside the slow log list */ 8 | typedef struct slowlogEntry { 9 | robj **argv; 10 | int argc; 11 | long long id; /* Unique entry identifier. */ 12 | long long duration; /* Time spent by the query, in nanoseconds. */ 13 | time_t time; /* Unix time at which the query was executed. */ 14 | } slowlogEntry; 15 | 16 | /* Exported API */ 17 | void slowlogInit(void); 18 | void slowlogPushEntryIfNeeded(vr_eventloop *vel, robj **argv, int argc, long long duration); 19 | 20 | /* Exported commands */ 21 | void slowlogCommand(client *c); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /src/vr_stats.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int 4 | vr_stats_init(vr_stats *stats) 5 | { 6 | rstatus_t ret; 7 | 8 | if (stats == NULL) { 9 | return VR_ERROR; 10 | } 11 | 12 | stats->starttime = 0; 13 | stats->numcommands = 0; 14 | stats->numconnections = 0; 15 | stats->expiredkeys = 0; 16 | stats->evictedkeys = 0; 17 | stats->keyspace_hits = 0; 18 | stats->keyspace_misses = 0; 19 | stats->rejected_conn = 0; 20 | stats->sync_full = 0; 21 | stats->sync_partial_ok = 0; 22 | stats->sync_partial_err = 0; 23 | stats->net_input_bytes = 0; 24 | stats->net_output_bytes = 0; 25 | stats->peak_memory = 0; 26 | 27 | #if !defined(STATS_ATOMIC_FIRST) || (!defined(__ATOMIC_RELAXED) && !defined(HAVE_ATOMIC)) 28 | ret = pthread_spin_init(&stats->statslock, 0); 29 | if (ret != 0) { 30 | return VR_ERROR; 31 | } 32 | #endif 33 | 34 | stats->starttime = time(NULL); 35 | 36 | return VR_OK; 37 | } 38 | 39 | void 40 | vr_stats_deinit(vr_stats *stats) 41 | { 42 | if (stats == NULL) { 43 | return; 44 | } 45 | 46 | stats->starttime = 0; 47 | stats->numcommands = 0; 48 | stats->numconnections = 0; 49 | stats->expiredkeys = 0; 50 | stats->evictedkeys = 0; 51 | stats->keyspace_hits = 0; 52 | stats->keyspace_misses = 0; 53 | stats->rejected_conn = 0; 54 | stats->sync_full = 0; 55 | stats->sync_partial_ok = 0; 56 | stats->sync_partial_err = 0; 57 | stats->net_input_bytes = 0; 58 | stats->net_output_bytes = 0; 59 | 60 | #if !defined(STATS_ATOMIC_FIRST) || (!defined(__ATOMIC_RELAXED) && !defined(HAVE_ATOMIC)) 61 | pthread_spin_destroy(&stats->statslock); 62 | #endif 63 | } 64 | 65 | /* Add a sample to the operations per second array of samples. */ 66 | void trackInstantaneousMetric(vr_stats *stats, int metric, long long current_reading) { 67 | long long t = vr_msec_now() - stats->inst_metric[metric].last_sample_time; 68 | long long ops = current_reading - 69 | stats->inst_metric[metric].last_sample_count; 70 | long long ops_sec; 71 | 72 | ops_sec = t > 0 ? (ops*1000/t) : 0; 73 | 74 | update_stats_set(stats,inst_metric[metric].samples[stats->inst_metric[metric].idx],ops_sec); 75 | stats->inst_metric[metric].idx++; 76 | stats->inst_metric[metric].idx %= STATS_METRIC_SAMPLES; 77 | stats->inst_metric[metric].last_sample_time = vr_msec_now(); 78 | stats->inst_metric[metric].last_sample_count = current_reading; 79 | } 80 | 81 | /* Return the mean of all the samples. */ 82 | long long getInstantaneousMetric(vr_stats *stats, int metric) { 83 | int j; 84 | long long sum = 0; 85 | 86 | for (j = 0; j < STATS_METRIC_SAMPLES; j++) { 87 | long long value; 88 | update_stats_get(stats, inst_metric[metric].samples[j], &value); 89 | sum += value; 90 | } 91 | return sum / STATS_METRIC_SAMPLES; 92 | } 93 | -------------------------------------------------------------------------------- /src/vr_stats.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_STATS_H_ 2 | #define _VR_STATS_H_ 3 | 4 | #if 1 5 | #define STATS_ATOMIC_FIRST 1 6 | #endif 7 | 8 | /* Instantaneous metrics tracking. */ 9 | #define STATS_METRIC_SAMPLES 16 /* Number of samples per metric. */ 10 | #define STATS_METRIC_COMMAND 0 /* Number of commands executed. */ 11 | #define STATS_METRIC_NET_INPUT 1 /* Bytes read to network .*/ 12 | #define STATS_METRIC_NET_OUTPUT 2 /* Bytes written to network. */ 13 | #define STATS_METRIC_COUNT 3 14 | 15 | typedef struct vr_stats { 16 | /* Fields used only for stats */ 17 | time_t starttime; /* Server start time */ 18 | long long numcommands; /* Number of processed commands */ 19 | long long numconnections; /* Number of connections received */ 20 | long long expiredkeys; /* Number of expired keys */ 21 | long long evictedkeys; /* Number of evicted keys (maxmemory) */ 22 | long long keyspace_hits; /* Number of successful lookups of keys */ 23 | long long keyspace_misses; /* Number of failed lookups of keys */ 24 | long long rejected_conn; /* Clients rejected because of maxclients */ 25 | long long sync_full; /* Number of full resyncs with slaves. */ 26 | long long sync_partial_ok; /* Number of accepted PSYNC requests. */ 27 | long long sync_partial_err;/* Number of unaccepted PSYNC requests. */ 28 | long long net_input_bytes; /* Bytes read from network. */ 29 | long long net_output_bytes; /* Bytes written to network. */ 30 | size_t peak_memory; /* Max used memory record */ 31 | 32 | /* The following two are used to track instantaneous metrics, like 33 | * number of operations per second, network traffic. */ 34 | struct { 35 | long long last_sample_time; /* Timestamp of last sample in ms */ 36 | long long last_sample_count;/* Count in last sample */ 37 | long long samples[STATS_METRIC_SAMPLES]; 38 | int idx; 39 | } inst_metric[STATS_METRIC_COUNT]; 40 | 41 | #if !defined(STATS_ATOMIC_FIRST) || (!defined(__ATOMIC_RELAXED) && !defined(HAVE_ATOMIC)) 42 | pthread_spinlock_t statslock; 43 | #endif 44 | }vr_stats; 45 | 46 | /* GCC version >= 4.7 */ 47 | #if defined(__ATOMIC_RELAXED) && defined(STATS_ATOMIC_FIRST) 48 | #define update_stats_add(_stats, _field, _n) __atomic_add_fetch(&(_stats)->_field, (_n), __ATOMIC_RELAXED) 49 | #define update_stats_sub(_stats, _field, _n) __atomic_sub_fetch(&(_stats)->_field, (_n), __ATOMIC_RELAXED) 50 | #define update_stats_set(_stats, _field, _n) __atomic_store_n(&(_stats)->_field, (_n), __ATOMIC_RELAXED) 51 | #define update_stats_get(_stats, _field, _v) do { \ 52 | __atomic_load(&(_stats)->_field, _v, __ATOMIC_RELAXED); \ 53 | } while(0) 54 | 55 | #define STATS_LOCK_TYPE "__ATOMIC_RELAXED" 56 | /* GCC version >= 4.1 */ 57 | #elif defined(HAVE_ATOMIC) && defined(STATS_ATOMIC_FIRST) 58 | #define update_stats_add(_stats, _field, _n) __sync_add_and_fetch(&(_stats)->_field, (_n)) 59 | #define update_stats_sub(_stats, _field, _n) __sync_sub_and_fetch(&(_stats)->_field, (_n)) 60 | #define update_stats_set(_stats, _field, _n) __sync_lock_test_and_set(&(_stats)->_field, (_n)) 61 | #define update_stats_get(_stats, _field, _v) do { \ 62 | (*_v) = __sync_add_and_fetch(&(_stats)->_field, 0); \ 63 | } while(0) 64 | 65 | #define STATS_LOCK_TYPE "HAVE_ATOMIC" 66 | #else 67 | #define update_stats_add(_stats, _field, _n) do { \ 68 | pthread_spin_lock(&(_stats)->statslock); \ 69 | (_stats)->_field += (_n); \ 70 | pthread_spin_unlock(&(_stats)->statslock); \ 71 | } while(0) 72 | 73 | #define update_stats_sub(_stats, _field, _n) do { \ 74 | pthread_spin_lock(&(_stats)->statslock); \ 75 | (_stats)->_field -= (_n); \ 76 | pthread_spin_unlock(&(_stats)->statslock); \ 77 | } while(0) 78 | 79 | #define update_stats_set(_stats, _field, _n) do { \ 80 | pthread_spin_lock(&(_stats)->statslock); \ 81 | (_stats)->_field = (_n); \ 82 | pthread_spin_unlock(&(_stats)->statslock); \ 83 | } while(0) 84 | 85 | #define update_stats_get(_stats, _field, _v) do { \ 86 | pthread_spin_lock(&(_stats)->statslock); \ 87 | (*_v) = (_stats)->_field; \ 88 | pthread_spin_unlock(&(_stats)->statslock); \ 89 | } while(0) 90 | 91 | #define STATS_LOCK_TYPE "pthread_spin_lock" 92 | #endif 93 | 94 | int vr_stats_init(vr_stats *stats); 95 | void vr_stats_deinit(vr_stats *stats); 96 | 97 | void trackInstantaneousMetric(vr_stats *stats, int metric, long long current_reading); 98 | long long getInstantaneousMetric(vr_stats *stats, int metric); 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /src/vr_t_hash.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_T_HASH_H_ 2 | #define _VR_T_HASH_H_ 3 | 4 | void hashTypeTryConversion(robj *o, robj **argv, int start, int end); 5 | void hashTypeTryObjectEncoding(robj *subject, robj **o1, robj **o2); 6 | int hashTypeGetFromZiplist(robj *o, robj *field, unsigned char **vstr, unsigned int *vlen, long long *vll); 7 | int hashTypeGetFromHashTable(robj *o, robj *field, robj **value); 8 | robj *hashTypeGetObject(robj *o, robj *field); 9 | size_t hashTypeGetValueLength(robj *o, robj *field); 10 | int hashTypeExists(robj *o, robj *field); 11 | int hashTypeSet(robj *o, robj *field, robj *value); 12 | int hashTypeDelete(robj *o, robj *field); 13 | unsigned long hashTypeLength(robj *o); 14 | hashTypeIterator *hashTypeInitIterator(robj *subject); 15 | void hashTypeReleaseIterator(hashTypeIterator *hi); 16 | int hashTypeNext(hashTypeIterator *hi); 17 | void hashTypeCurrentFromZiplist(hashTypeIterator *hi, int what, unsigned char **vstr, unsigned int *vlen, long long *vll); 18 | void hashTypeCurrentFromHashTable(hashTypeIterator *hi, int what, robj **dst); 19 | robj *hashTypeCurrentObject(hashTypeIterator *hi, int what); 20 | robj *hashTypeLookupWriteOrCreate(client *c, robj *key, int *expired); 21 | void hashTypeConvertZiplist(robj *o, int enc); 22 | void hashTypeConvert(robj *o, int enc); 23 | void hsetCommand(client *c); 24 | void hsetnxCommand(client *c); 25 | void hmsetCommand(client *c); 26 | void hincrbyCommand(client *c); 27 | void hincrbyfloatCommand(client *c); 28 | void hgetCommand(client *c); 29 | void hmgetCommand(client *c); 30 | void hdelCommand(client *c); 31 | void hlenCommand(client *c); 32 | void hstrlenCommand(client *c); 33 | void genericHgetallCommand(client *c, int flags); 34 | void hkeysCommand(client *c); 35 | void hvalsCommand(client *c); 36 | void hgetallCommand(client *c); 37 | void hexistsCommand(client *c); 38 | void hscanCommand(client *c); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/vr_t_list.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_T_LIST_H_ 2 | #define _VR_T_LIST_H_ 3 | 4 | void listTypePush(robj *subject, robj *value, int where); 5 | void *listPopSaver(unsigned char *data, unsigned int sz); 6 | robj *listTypePop(robj *subject, int where); 7 | unsigned long listTypeLength(robj *subject); 8 | listTypeIterator *listTypeInitIterator(robj *subject, long index, unsigned char direction); 9 | void listTypeReleaseIterator(listTypeIterator *li); 10 | int listTypeNext(listTypeIterator *li, listTypeEntry *entry); 11 | robj *listTypeGet(listTypeEntry *entry); 12 | void listTypeInsert(listTypeEntry *entry, robj *value, int where); 13 | int listTypeEqual(listTypeEntry *entry, robj *o); 14 | void listTypeDelete(listTypeIterator *iter, listTypeEntry *entry); 15 | void listTypeConvert(robj *subject, int enc); 16 | void pushGenericCommand(client *c, int where); 17 | void lpushCommand(client *c); 18 | void rpushCommand(client *c); 19 | void pushxGenericCommand(client *c, robj *refval, robj *val, int where); 20 | void lpushxCommand(client *c); 21 | void rpushxCommand(client *c); 22 | void linsertCommand(client *c); 23 | void llenCommand(client *c); 24 | void lindexCommand(client *c); 25 | void lsetCommand(client *c); 26 | void popGenericCommand(client *c, int where); 27 | void lpopCommand(client *c); 28 | void rpopCommand(client *c); 29 | void lrangeCommand(client *c); 30 | void ltrimCommand(client *c); 31 | void lremCommand(client *c); 32 | void rpoplpushHandlePush(client *c, robj *dstkey, robj *dstobj, robj *value); 33 | void rpoplpushCommand(client *c); 34 | void blockForKeys(client *c, robj **keys, int numkeys, mstime_t timeout, robj *target); 35 | void unblockClientWaitingData(client *c); 36 | void signalListAsReady(redisDb *db, robj *key); 37 | int serveClientBlockedOnList(client *receiver, robj *key, robj *dstkey, redisDb *db, robj *value, int where); 38 | void handleClientsBlockedOnLists(void); 39 | void blockingPopGenericCommand(client *c, int where); 40 | void blpopCommand(client *c); 41 | void brpopCommand(client *c); 42 | void brpoplpushCommand(client *c); 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/vr_t_set.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_T_SET_H_ 2 | #define _VR_T_SET_H_ 3 | 4 | robj *setTypeCreate(robj *value); 5 | int setTypeAdd(robj *subject, robj *value); 6 | int setTypeRemove(robj *setobj, robj *value); 7 | int setTypeIsMember(robj *subject, robj *value); 8 | setTypeIterator *setTypeInitIterator(robj *subject); 9 | void setTypeReleaseIterator(setTypeIterator *si); 10 | int setTypeNext(setTypeIterator *si, robj **objele, int64_t *llele); 11 | robj *setTypeNextObject(setTypeIterator *si); 12 | int setTypeRandomElement(robj *setobj, robj **objele, int64_t *llele); 13 | 14 | unsigned long setTypeSize(robj *subject); 15 | void setTypeConvert(robj *setobj, int enc); 16 | void saddCommand(client *c); 17 | void sremCommand(client *c); 18 | void smoveCommand(client *c); 19 | void sismemberCommand(client *c); 20 | void scardCommand(client *c); 21 | void spopWithCountCommand(client *c); 22 | void spopCommand(client *c); 23 | void srandmemberWithCountCommand(client *c); 24 | void srandmemberCommand(client *c); 25 | void smembersCommand(client *c); 26 | int qsortCompareSetsByCardinality(const void *s1, const void *s2); 27 | int qsortCompareSetsByRevCardinality(const void *s1, const void *s2); 28 | void sinterGenericCommand(client *c, robj **setkeys, unsigned long setnum, robj *dstkey); 29 | void sinterCommand(client *c); 30 | void sinterstoreCommand(client *c); 31 | void sunionDiffGenericCommand(client *c, robj **setkeys, int setnum, robj *dstkey, int op); 32 | void sunionCommand(client *c); 33 | void sunionstoreCommand(client *c); 34 | void sdiffCommand(client *c); 35 | void sdiffstoreCommand(client *c); 36 | void sscanCommand(client *c); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/vr_t_string.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_T_STRING_H_ 2 | #define _VR_T_STRING_H_ 3 | 4 | void setGenericCommand(client *c, int flags, robj *key, robj *val, robj *expire, int unit, robj *ok_reply, robj *abort_reply); 5 | void setCommand(client *c); 6 | void setnxCommand(client *c); 7 | void setexCommand(client *c); 8 | void psetexCommand(client *c); 9 | int getGenericCommand(client *c); 10 | void getCommand(client *c); 11 | void getsetCommand(client *c); 12 | void setrangeCommand(client *c); 13 | void getrangeCommand(client *c); 14 | void mgetCommand(client *c); 15 | void msetGenericCommand(client *c, int nx); 16 | void msetCommand(client *c); 17 | void msetnxCommand(client *c); 18 | void incrDecrCommand(client *c, long long incr); 19 | void incrCommand(client *c); 20 | void decrCommand(client *c); 21 | void incrbyCommand(client *c); 22 | void decrbyCommand(client *c); 23 | void incrbyfloatCommand(client *c); 24 | void appendCommand(client *c); 25 | void strlenCommand(client *c); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/vr_thread.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int 4 | vr_thread_init(vr_thread *thread) 5 | { 6 | if (thread == NULL) { 7 | return VR_ERROR; 8 | } 9 | 10 | thread->id = 0; 11 | thread->thread_id = 0; 12 | thread->fun_run = NULL; 13 | thread->data = NULL; 14 | 15 | return VR_OK; 16 | } 17 | 18 | void 19 | vr_thread_deinit(vr_thread *thread) 20 | { 21 | if (thread == NULL) { 22 | return; 23 | } 24 | 25 | thread->id = 0; 26 | thread->thread_id = 0; 27 | thread->fun_run = NULL; 28 | thread->data = NULL; 29 | } 30 | 31 | static void *vr_thread_run(void *data) 32 | { 33 | vr_thread *thread = data; 34 | srand(vr_usec_now()^(int)pthread_self()); 35 | 36 | thread->fun_run(thread->data); 37 | } 38 | 39 | int vr_thread_start(vr_thread *thread) 40 | { 41 | pthread_attr_t attr; 42 | pthread_attr_init(&attr); 43 | 44 | if (thread == NULL || thread->fun_run == NULL) { 45 | return VR_ERROR; 46 | } 47 | 48 | pthread_create(&thread->thread_id, 49 | &attr, vr_thread_run, thread); 50 | 51 | return VR_OK; 52 | } 53 | -------------------------------------------------------------------------------- /src/vr_thread.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_THREAD_H_ 2 | #define _VR_THREAD_H_ 3 | 4 | typedef void *(*vr_thread_func_t)(void *data); 5 | 6 | typedef struct vr_thread { 7 | int id; 8 | pthread_t thread_id; 9 | 10 | vr_thread_func_t fun_run; 11 | void *data; 12 | }vr_thread; 13 | 14 | int vr_thread_init(vr_thread *thread); 15 | void vr_thread_deinit(vr_thread *thread); 16 | int vr_thread_start(vr_thread *thread); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /src/vr_worker.h: -------------------------------------------------------------------------------- 1 | #ifndef _VR_WORKER_H_ 2 | #define _VR_WORKER_H_ 3 | 4 | typedef struct vr_worker { 5 | 6 | int id; 7 | vr_eventloop vel; 8 | 9 | int socketpairs[2]; /*0: belong to master thread, 1: belong to myself*/ 10 | 11 | dlist *csul; /* Connect swap unit list */ 12 | pthread_mutex_t csullock; /* swap unit list locker */ 13 | 14 | /* Some global state in order to continue the work incrementally 15 | * across calls for activeExpireCycle() to expire some keys. */ 16 | unsigned int current_db; /* Last DB tested. */ 17 | int timelimit_exit; /* Time limit hit in previous call? */ 18 | long long last_fast_cycle; /* When last fast cycle ran. */ 19 | 20 | /* We use global counters so if we stop the computation at a given 21 | * DB we'll be able to start from the successive in the next 22 | * cron loop iteration for databasesCron() to resize and reshash db. */ 23 | unsigned int resize_db; 24 | unsigned int rehash_db; 25 | }vr_worker; 26 | 27 | struct connswapunit { 28 | int num; 29 | void *data; 30 | struct connswapunit *next; 31 | }; 32 | 33 | extern struct darray workers; 34 | 35 | int workers_init(uint32_t worker_count); 36 | int workers_run(void); 37 | int workers_wait(void); 38 | void workers_deinit(void); 39 | 40 | struct connswapunit *csui_new(void); 41 | void csui_free(struct connswapunit *item); 42 | 43 | void csul_push(vr_worker *worker, struct connswapunit *su); 44 | struct connswapunit *csul_pop(vr_worker *worker); 45 | 46 | int worker_get_next_idx(int curidx); 47 | 48 | void dispatch_conn_new(vr_listen *vlisten, int sd); 49 | 50 | void worker_before_sleep(struct aeEventLoop *eventLoop, void *private_data); 51 | int worker_cron(struct aeEventLoop *eventLoop, long long id, void *clientData); 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/vr_ziplist.h: -------------------------------------------------------------------------------- 1 | #ifndef _ZIPLIST_H 2 | #define _ZIPLIST_H 3 | 4 | #define ZIPLIST_HEAD 0 5 | #define ZIPLIST_TAIL 1 6 | 7 | unsigned char *ziplistNew(void); 8 | unsigned char *ziplistMerge(unsigned char **first, unsigned char **second); 9 | unsigned char *ziplistPush(unsigned char *zl, unsigned char *s, unsigned int slen, int where); 10 | unsigned char *ziplistIndex(unsigned char *zl, int index); 11 | unsigned char *ziplistNext(unsigned char *zl, unsigned char *p); 12 | unsigned char *ziplistPrev(unsigned char *zl, unsigned char *p); 13 | unsigned int ziplistGet(unsigned char *p, unsigned char **sval, unsigned int *slen, long long *lval); 14 | unsigned char *ziplistInsert(unsigned char *zl, unsigned char *p, unsigned char *s, unsigned int slen); 15 | unsigned char *ziplistDelete(unsigned char *zl, unsigned char **p); 16 | unsigned char *ziplistDeleteRange(unsigned char *zl, int index, unsigned int num); 17 | unsigned int ziplistCompare(unsigned char *p, unsigned char *s, unsigned int slen); 18 | unsigned char *ziplistFind(unsigned char *p, unsigned char *vstr, unsigned int vlen, unsigned int skip); 19 | unsigned int ziplistLen(unsigned char *zl); 20 | size_t ziplistBlobLen(unsigned char *zl); 21 | 22 | #ifdef REDIS_TEST 23 | int ziplistTest(int argc, char *argv[]); 24 | #endif 25 | 26 | #endif /* _ZIPLIST_H */ 27 | -------------------------------------------------------------------------------- /src/vr_zipmap.h: -------------------------------------------------------------------------------- 1 | #ifndef _ZIPMAP_H 2 | #define _ZIPMAP_H 3 | 4 | unsigned char *zipmapNew(void); 5 | unsigned char *zipmapSet(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned char *val, unsigned int vlen, int *update); 6 | unsigned char *zipmapDel(unsigned char *zm, unsigned char *key, unsigned int klen, int *deleted); 7 | unsigned char *zipmapRewind(unsigned char *zm); 8 | unsigned char *zipmapNext(unsigned char *zm, unsigned char **key, unsigned int *klen, unsigned char **value, unsigned int *vlen); 9 | int zipmapGet(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned char **value, unsigned int *vlen); 10 | int zipmapExists(unsigned char *zm, unsigned char *key, unsigned int klen); 11 | unsigned int zipmapLen(unsigned char *zm); 12 | size_t zipmapBlobLen(unsigned char *zm); 13 | void zipmapRepr(unsigned char *p); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.out 3 | *.log -------------------------------------------------------------------------------- /tests/Makefile.am: -------------------------------------------------------------------------------- 1 | MAINTAINERCLEANFILES = Makefile.in 2 | 3 | AM_CPPFLAGS = 4 | if !OS_SOLARIS 5 | AM_CPPFLAGS += -D_GNU_SOURCE 6 | endif 7 | AM_CPPFLAGS += -I $(top_srcdir)/dep/ae 8 | AM_CPPFLAGS += -I $(top_srcdir)/dep/jemalloc-4.2.0/include 9 | AM_CPPFLAGS += -I $(top_srcdir)/dep/hiredis-0.13.3 10 | AM_CPPFLAGS += -I $(top_srcdir)/dep/dhashkit 11 | AM_CPPFLAGS += -I $(top_srcdir)/dep/dlist 12 | AM_CPPFLAGS += -I $(top_srcdir)/dep/darray 13 | AM_CPPFLAGS += -I $(top_srcdir)/dep/util 14 | AM_CPPFLAGS += -I $(top_srcdir)/dep/himemcached-0.1.0 15 | 16 | AM_CFLAGS = 17 | AM_CFLAGS += -fno-strict-aliasing 18 | AM_CFLAGS += -Wall -Wshadow 19 | AM_CFLAGS += -Wpointer-arith 20 | AM_CFLAGS += -Winline 21 | AM_CFLAGS += -Wunused-function -Wunused-variable -Wunused-value 22 | AM_CFLAGS += -Wno-unused-parameter -Wno-unused-value 23 | AM_CFLAGS += -Wconversion -Wsign-compare 24 | AM_CFLAGS += -Wstrict-prototypes -Wmissing-prototypes -Wredundant-decls -Wmissing-declarations 25 | 26 | AM_LDFLAGS = 27 | AM_LDFLAGS += -lm -lpthread -rdynamic 28 | if !OS_DARWIN 29 | AM_LDFLAGS += -lrt 30 | endif 31 | if OS_SOLARIS 32 | AM_LDFLAGS += -lnsl -lsocket 33 | endif 34 | if OS_FREEBSD 35 | AM_LDFLAGS += -lexecinfo 36 | endif 37 | 38 | noinst_PROGRAMS = viretest 39 | 40 | viretest_SOURCES = \ 41 | vrt_util.c vrt_util.h \ 42 | vrt_public.c vrt_public.h \ 43 | vrt_simple.c vrt_simple.h \ 44 | vrtest.c 45 | 46 | viretest_LDADD = $(top_builddir)/dep/ae/libae.a 47 | viretest_LDADD += $(top_builddir)/dep/hiredis-0.13.3/libhiredis.a 48 | viretest_LDADD += $(top_builddir)/dep/darray/libdarray.a 49 | viretest_LDADD += $(top_builddir)/dep/dmalloc/libdmalloc.a 50 | viretest_LDADD += $(top_builddir)/dep/util/libdutil.a 51 | viretest_LDADD += $(top_builddir)/dep/jemalloc-4.2.0/lib/libjemalloc.a 52 | 53 | noinst_PROGRAMS += vireabtest 54 | 55 | vireabtest_SOURCES = \ 56 | vrt_util.c vrt_util.h \ 57 | vrt_public.c vrt_public.h \ 58 | vrt_produce_data.c vrt_produce_data.h \ 59 | vrt_dispatch_data.c vrt_dispatch_data.h \ 60 | vrt_check_data.c vrt_check_data.h \ 61 | vrt_backend.c vrt_backend.h \ 62 | vrabtest.c vrabtest.h 63 | 64 | vireabtest_LDADD = $(top_builddir)/dep/ae/libae.a 65 | vireabtest_LDADD += $(top_builddir)/dep/hiredis-0.13.3/libhiredis.a 66 | vireabtest_LDADD += $(top_builddir)/dep/dhashkit/libdhashkit.a 67 | vireabtest_LDADD += $(top_builddir)/dep/dlist/libdlist.a 68 | vireabtest_LDADD += $(top_builddir)/dep/darray/libdarray.a 69 | vireabtest_LDADD += $(top_builddir)/dep/dmalloc/libdmalloc.a 70 | vireabtest_LDADD += $(top_builddir)/dep/util/libdutil.a 71 | vireabtest_LDADD += $(top_builddir)/dep/jemalloc-4.2.0/lib/libjemalloc.a 72 | 73 | noinst_PROGRAMS += vire-benchmark 74 | 75 | vire_benchmark_SOURCES = \ 76 | vrt_util.c vrt_util.h \ 77 | vrt_public.c vrt_public.h \ 78 | vrt_benchmark.c 79 | 80 | vire_benchmark_LDADD = $(top_builddir)/dep/ae/libae.a 81 | vire_benchmark_LDADD += $(top_builddir)/dep/hiredis-0.13.3/libhiredis.a 82 | vire_benchmark_LDADD += $(top_builddir)/dep/himemcached-0.1.0/libhimemcached.a 83 | vire_benchmark_LDADD += $(top_builddir)/dep/dlist/libdlist.a 84 | vire_benchmark_LDADD += $(top_builddir)/dep/darray/libdarray.a 85 | vire_benchmark_LDADD += $(top_builddir)/dep/dmalloc/libdmalloc.a 86 | vire_benchmark_LDADD += $(top_builddir)/dep/util/libdutil.a 87 | vire_benchmark_LDADD += $(top_builddir)/dep/jemalloc-4.2.0/lib/libjemalloc.a -------------------------------------------------------------------------------- /tests/vrabtest.h: -------------------------------------------------------------------------------- 1 | #ifndef _VRABTEST_H_ 2 | #define _VRABTEST_H_ 3 | 4 | #include 5 | 6 | struct redisContext; 7 | struct redisAsyncContext; 8 | struct abtest_group; 9 | 10 | typedef struct conn_context { 11 | struct redisContext *ctx; 12 | struct redisAsyncContext *actx; 13 | } conn_context; 14 | 15 | typedef struct abtest_server { 16 | sds host; 17 | int port; 18 | 19 | darray *conn_contexts; /* connection context */ 20 | 21 | void *data; 22 | } abtest_server; 23 | 24 | typedef unsigned int (*backend_server_idx_t)(struct abtest_group*, char *, size_t); 25 | typedef abtest_server *(*backend_server_t)(struct abtest_group*, char *, size_t); 26 | 27 | typedef struct abtest_group { 28 | int type; 29 | 30 | darray abtest_servers; /* type: abtest_server */ 31 | 32 | backend_server_idx_t get_backend_server_idx; 33 | backend_server_t get_backend_server; 34 | } abtest_group; 35 | 36 | extern int expire_enabled; 37 | extern long long test_interval; 38 | extern long long last_test_begin_time; 39 | 40 | darray *abtest_groups_create(char *groups_string); 41 | void abtest_groups_destroy(darray *abgs); 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /tests/vrt_backend.h: -------------------------------------------------------------------------------- 1 | #ifndef _VRT_BACKEND_H_ 2 | #define _VRT_BACKEND_H_ 3 | 4 | #include 5 | 6 | struct abtest_group; 7 | struct dlist; 8 | struct dmtlist; 9 | struct data_unit; 10 | struct aeEventLoop; 11 | 12 | typedef struct backend_thread { 13 | int id; 14 | pthread_t thread_id; 15 | 16 | struct aeEventLoop *el; 17 | int hz; 18 | int cronloops; /* Number of times the cron function run */ 19 | 20 | darray *abgs; /* type is abtest_group */ 21 | 22 | int deleting; 23 | int pause; 24 | } backend_thread; 25 | 26 | extern int backend_threads_count; 27 | 28 | extern int backend_threads_pause_finished_count; 29 | 30 | int vrt_backend_init(int threads_count, char *test_target_groups); 31 | void vrt_backend_deinit(void); 32 | 33 | int vrt_start_backend(void); 34 | int vrt_wait_backend(void); 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /tests/vrt_check_data.h: -------------------------------------------------------------------------------- 1 | #ifndef _VRT_CHECK_DATA_H_ 2 | #define _VRT_CHECK_DATA_H_ 3 | 4 | int vrt_data_checker_init(char *checker, char *test_target_groups); 5 | void vrt_data_checker_deinit(void); 6 | 7 | int vrt_start_data_checker(void); 8 | int vrt_wait_data_checker(void); 9 | 10 | int test_if_need_pause(void); 11 | void test_can_continue(void); 12 | void test_need_to_pause(void); 13 | 14 | void one_produce_thread_paused(void); 15 | void one_dispatch_thread_paused(void); 16 | void one_backend_thread_paused(void); 17 | 18 | int all_produce_threads_paused(void); 19 | int all_dispatch_threads_paused(void); 20 | int all_backend_threads_paused(void); 21 | int all_threads_paused(void); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /tests/vrt_dispatch_data.h: -------------------------------------------------------------------------------- 1 | #ifndef _VRT_DISPATCH_DATA_H_ 2 | #define _VRT_DISPATCH_DATA_H_ 3 | 4 | #include 5 | 6 | struct abtest_group; 7 | struct dlist; 8 | struct dmtqueue; 9 | struct data_unit; 10 | struct aeEventLoop; 11 | 12 | typedef struct dispatch_data_thread { 13 | int id; 14 | pthread_t thread_id; 15 | 16 | struct aeEventLoop *el; 17 | int hz; 18 | int cronloops; /* Number of times the cron function run */ 19 | 20 | struct dmtqueue *datas; /* Value is data_unit, used receive data 21 | from produce data thread, and send to the abtest groups. */ 22 | struct dlist *rdatas; /* Value is reply_unit, used to cache data 23 | that has not received from abtest groups completely */ 24 | 25 | darray *abgs; /* type is abtest_group */ 26 | 27 | int pause; 28 | 29 | int count_wait_for_reply; 30 | 31 | long long reply_total_count_per_cycle; 32 | long long reply_type_err_count_per_cycle; 33 | } dispatch_data_thread; 34 | 35 | extern int dispatch_data_threads_count; 36 | 37 | extern int dispatch_threads_pause_finished_count; 38 | 39 | long long get_total_tested_commands_count_per_cycle(void); 40 | long long get_total_reply_err_count_per_cycle(void); 41 | void reset_total_count_per_cycle(void); 42 | 43 | int vrt_dispatch_data_init(int threads_count, char *test_target_groups, int connections); 44 | void vrt_dispatch_data_deinit(void); 45 | 46 | int vrt_start_dispatch_data(void); 47 | int vrt_wait_dispatch_data(void); 48 | 49 | int data_dispatch(struct data_unit *du); 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /tests/vrt_produce_data.h: -------------------------------------------------------------------------------- 1 | #ifndef _VRT_PRODUCE_DATA_H_ 2 | #define _VRT_PRODUCE_DATA_H_ 3 | 4 | /* Producer flags. Please check the producer table defined in the vrt_produce_data.c file 5 | * for more information about the meaning of every flag. 6 | * This is the meaning of the flags: 7 | * 8 | * w: write command (may modify the key space). 9 | * r: read command (will never modify the key space). 10 | * m: may increase memory usage once called. Don't allow if out of memory. 11 | * a: admin command, like SAVE or SHUTDOWN. 12 | * p: Pub/Sub related command. 13 | * f: force replication of this command, regardless of server.dirty. 14 | * s: command not allowed in scripts. 15 | * R: random command. Command is not deterministic, that is, the same command 16 | * with the same arguments, with the same key space, may have different 17 | * results. For instance SPOP and RANDOMKEY are two random commands. 18 | * S: Sort command output array if called from script, so that the output 19 | * is deterministic. 20 | * l: Allow command while loading the database. 21 | * t: Allow command while a slave has stale data but is not allowed to 22 | * server this data. Normally no command is accepted in this condition 23 | * but just a few. 24 | * M: Do not automatically propagate the command on MONITOR. 25 | * k: Perform an implicit ASKING for this command, so the command will be 26 | * accepted in cluster mode if the slot is marked as 'importing'. 27 | * F: Fast command: O(1) or O(log(N)) command that should never delay 28 | * its execution as long as the kernel scheduler is giving us time. 29 | * Note that commands that may trigger a DEL as a side effect (like SET) 30 | * are not fast commands. 31 | * A: Add a new key if the key was not exist before. 32 | */ 33 | 34 | #define PRO_WRITE 1 /* "w" flag */ 35 | #define PRO_READONLY 2 /* "r" flag */ 36 | #define PRO_DENYOOM 4 /* "m" flag */ 37 | #define PRO_NOT_USED_1 8 /* no longer used flag */ 38 | #define PRO_ADMIN 16 /* "a" flag */ 39 | #define PRO_PUBSUB 32 /* "p" flag */ 40 | #define PRO_NOSCRIPT 64 /* "s" flag */ 41 | #define PRO_RANDOM 128 /* "R" flag */ 42 | #define PRO_SORT_FOR_SCRIPT 256 /* "S" flag */ 43 | #define PRO_LOADING 512 /* "l" flag */ 44 | #define PRO_STALE 1024 /* "t" flag */ 45 | #define PRO_SKIP_MONITOR 2048 /* "M" flag */ 46 | #define PRO_ASKING 4096 /* "k" flag */ 47 | #define PRO_FAST 8192 /* "F" flag */ 48 | #define PRO_ADD 16384 /* "A" flag */ 49 | 50 | struct data_producer; 51 | struct produce_scheme; 52 | struct key_cache_array; 53 | 54 | typedef struct data_unit *redis_command_proc(struct data_producer *dp, struct produce_scheme *ps); 55 | typedef int *redis_get_keys_proc(struct data_producer *dp, sds *argv, int argc, int *numkeys); 56 | typedef int produce_need_cache_key_proc(struct redisReply *reply); 57 | typedef struct data_producer { 58 | char *name; /* Command name */ 59 | redis_command_proc *proc; 60 | int arity; 61 | 62 | char *sflags; /* Flags as string representation, one char per flag. */ 63 | int flags; /* The actual flags, obtained from the 'sflags' field. */ 64 | 65 | /* Use a function to determine keys arguments in a command line. */ 66 | redis_get_keys_proc *getkeys_proc; 67 | /* What keys should be loaded in background when calling this command? */ 68 | int firstkey; /* The first argument that's a key (0 = no keys) */ 69 | int lastkey; /* The last argument that's a key */ 70 | int keystep; /* The step between first and last key */ 71 | int cmd_type; 72 | produce_need_cache_key_proc *need_cache_key_proc; 73 | } data_producer; 74 | 75 | typedef struct data_unit { 76 | data_producer *dp; 77 | int argc; /* Num of arguments of current command. */ 78 | sds *argv; /* Arguments of current command. */ 79 | 80 | unsigned int hashvalue; 81 | 82 | void *data; 83 | } data_unit; 84 | 85 | typedef struct produce_scheme { 86 | darray *kcps; /* Key cached pools for every type command. */ 87 | 88 | int hit_ratio; /* Hit ratio for the read commands. [0%,100%] */ 89 | int hit_ratio_idx; /* [0,hit_ratio_array_len-1] */ 90 | int hit_ratio_array_len; /* 100 usually */ 91 | int *hit_ratio_array; /* Stored 0 or 1 for every element, 1 means used key in the cached keys array. */ 92 | } produce_scheme; 93 | 94 | extern data_producer *delete_data_producer; 95 | 96 | extern int produce_data_threads_count; 97 | 98 | extern int produce_threads_pause_finished_count; 99 | 100 | struct key_cache_array *kcp_get_from_ps(produce_scheme *ps, data_producer *dp); 101 | 102 | data_unit *data_unit_get(void); 103 | void data_unit_put(data_unit *du); 104 | 105 | int vrt_produce_data_init(int key_length_range_min, int key_length_range_max, 106 | int string_max_length,int fields_max_count, 107 | int produce_cmd_types,darray *produce_cmd_blacklist,darray *produce_cmd_whitelist, 108 | unsigned int produce_threads_count, long long cached_keys, 109 | int hit_ratio); 110 | void vrt_produce_data_deinit(void); 111 | 112 | int vrt_start_produce_data(void); 113 | int vrt_wait_produce_data(void); 114 | 115 | int *get_keys_from_data_producer(data_producer *dp, sds *argv, int argc, int *numkeys); 116 | 117 | sds get_one_key_from_data_unit(data_unit *du); 118 | 119 | void print_producer_command(data_unit *du); 120 | 121 | #endif 122 | -------------------------------------------------------------------------------- /tests/vrt_public.h: -------------------------------------------------------------------------------- 1 | #ifndef _VRT_PUBLIC_H_ 2 | #define _VRT_PUBLIC_H_ 3 | 4 | #ifdef HAVE_CONFIG_H 5 | # include 6 | #endif 7 | 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | 14 | struct darray; 15 | struct key_cache_pool; 16 | 17 | #define VRT_TEST_OK 0 18 | #define VRT_TEST_ERR 1 19 | 20 | #define TEST_CMD_TYPE_STRING (1<<0) 21 | #define TEST_CMD_TYPE_LIST (1<<1) 22 | #define TEST_CMD_TYPE_SET (1<<2) 23 | #define TEST_CMD_TYPE_ZSET (1<<3) 24 | #define TEST_CMD_TYPE_HASH (1<<4) 25 | #define TEST_CMD_TYPE_SERVER (1<<5) 26 | #define TEST_CMD_TYPE_KEY (1<<6) 27 | #define TEST_CMD_TYPE_EXPIRE (1<<7) 28 | 29 | /* key types */ 30 | #define REDIS_STRING 0 31 | #define REDIS_LIST 1 32 | #define REDIS_SET 2 33 | #define REDIS_ZSET 3 34 | #define REDIS_HASH 4 35 | 36 | /* State control API */ 37 | /* GCC version >= 4.7 */ 38 | #if defined(__ATOMIC_RELAXED) 39 | #define update_state_add(_value, _n) __atomic_add_fetch(&_value, (_n), __ATOMIC_RELAXED) 40 | #define update_state_sub(_value, _n) __atomic_sub_fetch(&_value, (_n), __ATOMIC_RELAXED) 41 | #define update_state_set(_value, _n) __atomic_store_n(&_value, (_n), __ATOMIC_RELAXED) 42 | #define update_state_get(_value, _v) do { \ 43 | __atomic_load(&_value, _v, __ATOMIC_RELAXED); \ 44 | } while(0) 45 | 46 | #define TEST_STATE_LOCK_TYPE "__ATOMIC_RELAXED" 47 | /* GCC version >= 4.1 */ 48 | #elif defined(HAVE_ATOMIC) 49 | #define update_state_add(_value, _n) __sync_add_and_fetch(&_value, (_n)) 50 | #define update_state_sub(_value, _n) __sync_sub_and_fetch(&_value, (_n)) 51 | #define update_state_set(_value, _n) __sync_lock_test_and_set(&_value, (_n)) 52 | #define update_state_get(_value, _v) do { \ 53 | (*_v) = __sync_add_and_fetch(&_value, 0); \ 54 | } while(0) 55 | 56 | #define TEST_STATE_LOCK_TYPE "HAVE_ATOMIC" 57 | #else 58 | extern pthread_mutex_t state_locker; 59 | 60 | #define update_state_add(_value, _n) do { \ 61 | pthread_mutex_lock(&state_locker); \ 62 | _value += (_n); \ 63 | pthread_mutex_unlock(&state_locker); \ 64 | } while(0) 65 | 66 | #define update_state_sub(_value, _n) do { \ 67 | pthread_mutex_lock(&state_locker); \ 68 | _value -= (_n); \ 69 | pthread_mutex_unlock(&state_locker); \ 70 | } while(0) 71 | 72 | #define update_state_set(_value, _n) do { \ 73 | pthread_mutex_lock(&state_locker); \ 74 | _value = (_n); \ 75 | pthread_mutex_unlock(&state_locker); \ 76 | } while(0) 77 | 78 | #define update_state_get(_value, _v) do { \ 79 | pthread_mutex_lock(&state_locker); \ 80 | (*_v) = _value; \ 81 | pthread_mutex_unlock(&state_locker); \ 82 | } while(0) 83 | 84 | #define TEST_STATE_LOCK_TYPE "pthread_mutex_lock" 85 | #endif 86 | 87 | typedef struct vire_instance { 88 | sds host; 89 | int port; 90 | 91 | sds dir; 92 | sds conf_file; 93 | sds pid_file; 94 | sds log_file; 95 | 96 | int running; 97 | int pid; 98 | redisContext *ctx; 99 | } vire_instance; 100 | 101 | void set_execute_file(char *file); 102 | 103 | vire_instance *vire_instance_create(int port); 104 | void vire_instance_destroy(vire_instance *vi); 105 | 106 | int vire_server_run(vire_instance *vi); 107 | void vire_server_stop(vire_instance *vi); 108 | 109 | int create_work_dir(void); 110 | int destroy_work_dir(void); 111 | 112 | vire_instance *start_one_vire_instance(void); 113 | 114 | void show_test_result(int result,char *test_content,char *errmsg); 115 | 116 | typedef struct key_cache_array { 117 | long long cached_keys_count; 118 | long long ckeys_write_idx; 119 | long long max_pool_size; /* Max keys count that can be cached in the ckeys array. */ 120 | sds *ckeys; /* Cached keys that may exist in the target redis/vire servers. */ 121 | pthread_mutex_t pmutex; 122 | } key_cache_array; 123 | 124 | key_cache_array *key_cache_array_create(long long max_pool_size); 125 | void key_cache_array_destroy(key_cache_array *kca); 126 | int key_cache_array_input(key_cache_array *kca, char *key, size_t keylen); 127 | sds key_cache_array_random(key_cache_array *kca); 128 | 129 | long long get_longlong_from_info_reply(redisReply *reply, char *name); 130 | 131 | redisReply *steal_hiredis_redisreply(redisReply *r); 132 | int check_two_replys_if_same(redisReply *reply1, redisReply *reply2); 133 | int sort_array_by_step(void **element, size_t elements, int step, int idx_cmp, int (*fcmp)(const void *,const void *)); 134 | int reply_string_binary_compare(const void *r1,const void *r2); 135 | 136 | int parse_command_types(char *command_types_str); 137 | struct darray *parse_command_list(char *command_list_str); 138 | 139 | char *get_key_type_string(int keytype); 140 | 141 | #endif 142 | -------------------------------------------------------------------------------- /tests/vrt_simple.h: -------------------------------------------------------------------------------- 1 | #ifndef _VRT_SIMPLE_H_ 2 | #define _VRT_SIMPLE_H_ 3 | 4 | int simple_test(void); 5 | 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /tests/vrt_util.h: -------------------------------------------------------------------------------- 1 | #ifndef _VRT_UTIL_H_ 2 | #define _VRT_UTIL_H_ 3 | 4 | #ifdef HAVE_CONFIG_H 5 | # include 6 | #endif 7 | 8 | #ifdef HAVE_DEBUG_LOG 9 | # define VRT_DEBUG_LOG 1 10 | #endif 11 | 12 | #include 13 | 14 | #include 15 | 16 | #define VRT_OK 0 17 | #define VRT_ERROR -1 18 | 19 | #define VRT_UINT8_MAXLEN (3 + 1) 20 | #define VRT_UINT16_MAXLEN (5 + 1) 21 | #define VRT_UINT32_MAXLEN (10 + 1) 22 | #define VRT_UINT64_MAXLEN (20 + 1) 23 | #define VRT_UINTMAX_MAXLEN VRT_UINT64_MAXLEN 24 | 25 | #define VRT_MAXHOSTNAMELEN 256 26 | 27 | #define LF (uint8_t) 10 28 | #define CR (uint8_t) 13 29 | #define CRLF "\x0d\x0a" 30 | #define CRLF_LEN (sizeof("\x0d\x0a") - 1) 31 | 32 | #define LOG_MAX_LEN 256 /* max length of log message */ 33 | 34 | void _test_log_error(const char *file, int line, const char *fmt, ...); 35 | void _test_log_out(const char *fmt, ...); 36 | #if defined(VRT_DEBUG_LOG) 37 | #define test_log_debug(...) do { \ 38 | _test_log_error(__FILE__, __LINE__, __VA_ARGS__); \ 39 | } while (0) 40 | #else 41 | #define test_log_debug(...) 42 | #endif 43 | #define test_log_error(...) do { \ 44 | _test_log_error(__FILE__, __LINE__, __VA_ARGS__); \ 45 | } while (0) 46 | #define test_log_out(...) do { \ 47 | _test_log_out(__VA_ARGS__); \ 48 | } while (0) 49 | 50 | void vrt_assert(const char *cond, const char *file, int line, int panic); 51 | 52 | #define ASSERT(_x) do { \ 53 | if (!(_x)) { \ 54 | vrt_assert(#_x, __FILE__, __LINE__, 1); \ 55 | } \ 56 | } while (0) 57 | 58 | int vrt_scnprintf(char *buf, size_t size, const char *fmt, ...); 59 | 60 | int64_t vrt_usec_now(void); 61 | int64_t vrt_msec_now(void); 62 | int64_t vrt_sec_now(void); 63 | 64 | sds getAbsolutePath(char *filename); 65 | 66 | int ll2string(char* dst, size_t dstlen, long long svalue); 67 | int string2ll(const char *s, size_t slen, long long *value); 68 | int string2l(const char *s, size_t slen, long *lval); 69 | int d2string(char *buf, size_t len, double value); 70 | 71 | int create_dir(char *path); 72 | int destroy_dir(char *dir); 73 | 74 | int get_pid_from_reply(struct redisContext *redisctx, char *host, int port); 75 | 76 | long long *get_range_from_string(char *str, size_t len, int *count); 77 | 78 | sds get_host_port_from_address_string(char *address, int *port); 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /tests/vrtest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | struct config { 17 | char *pid_filename; 18 | 19 | int pidfile; 20 | int pid; 21 | }; 22 | 23 | static struct config config; 24 | 25 | static int show_help; 26 | static int show_version; 27 | 28 | static struct option long_options[] = { 29 | { "help", no_argument, NULL, 'h' }, 30 | { "version", no_argument, NULL, 'V' }, 31 | { "execute-file", required_argument, NULL, 'e' }, 32 | { "pid-file", required_argument, NULL, 'p' }, 33 | { NULL, 0, NULL, 0 } 34 | }; 35 | 36 | static char short_options[] = "hVe:p:"; 37 | 38 | static void 39 | vr_show_usage(void) 40 | { 41 | printf( 42 | "Usage: viretest [-?hV] [-e execute-file] [-p pid-file]" CRLF 43 | "" CRLF); 44 | printf( 45 | "Options:" CRLF 46 | " -h, --help : this help" CRLF 47 | " -V, --version : show version and exit" CRLF 48 | " -e, --execute-file : vire execute file, default is src/vire" CRLF 49 | " -p, --pid-file : pid file" CRLF 50 | "" CRLF); 51 | } 52 | 53 | static void 54 | vr_set_default_options(void) 55 | { 56 | config.pid_filename = NULL; 57 | } 58 | 59 | static int 60 | vr_get_options(int argc, char **argv) 61 | { 62 | int c; 63 | 64 | opterr = 0; 65 | 66 | for (;;) { 67 | c = getopt_long(argc, argv, short_options, long_options, NULL); 68 | if (c == -1) { 69 | /* no more options */ 70 | break; 71 | } 72 | 73 | switch (c) { 74 | case 'h': 75 | show_version = 1; 76 | show_help = 1; 77 | break; 78 | 79 | case 'V': 80 | show_version = 1; 81 | break; 82 | 83 | case 'e': 84 | set_execute_file(optarg); 85 | break; 86 | 87 | case 'p': 88 | config.pid_filename = optarg; 89 | break; 90 | 91 | case '?': 92 | switch (optopt) { 93 | case 'e': 94 | case 'p': 95 | test_log_error("vire: option -%c requires string", 96 | optopt); 97 | break; 98 | 99 | default: 100 | test_log_error("vire: invalid option -- '%c'", optopt); 101 | break; 102 | } 103 | return VRT_ERROR; 104 | 105 | default: 106 | test_log_error("vire: invalid option -- '%c'", optopt); 107 | return VRT_ERROR; 108 | 109 | } 110 | } 111 | 112 | return VRT_OK; 113 | } 114 | 115 | int 116 | main(int argc, char **argv) 117 | { 118 | int ret; 119 | int ok_count = 0, all_count = 0; 120 | 121 | vr_set_default_options(); 122 | 123 | ret = vr_get_options(argc, argv); 124 | if (ret != VRT_OK) { 125 | vr_show_usage(); 126 | exit(1); 127 | } 128 | 129 | if (show_version) { 130 | test_log_out("This is viretest-%s", VR_VERSION_STRING); 131 | if (show_help) { 132 | vr_show_usage(); 133 | } 134 | exit(0); 135 | } 136 | 137 | create_work_dir(); 138 | 139 | test_log_out("Testing Vire version %s \n", VR_VERSION_STRING); 140 | 141 | ok_count+=simple_test(); all_count++; 142 | 143 | clean: 144 | destroy_work_dir(); 145 | 146 | if (ok_count == all_count) 147 | test_log_out("\n\\o/ \033[32;1mAll tests passed without errors!\033[0m\n"); 148 | return VRT_OK; 149 | } 150 | -------------------------------------------------------------------------------- /tools/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.out 3 | *.log 4 | --------------------------------------------------------------------------------