xref: /f-stack/app/redis-5.0.5/src/server.c (revision 572c4311)
1*572c4311Sfengbojiang /*
2*572c4311Sfengbojiang  * Copyright (c) 2009-2016, Salvatore Sanfilippo <antirez at gmail dot com>
3*572c4311Sfengbojiang  * All rights reserved.
4*572c4311Sfengbojiang  *
5*572c4311Sfengbojiang  * Redistribution and use in source and binary forms, with or without
6*572c4311Sfengbojiang  * modification, are permitted provided that the following conditions are met:
7*572c4311Sfengbojiang  *
8*572c4311Sfengbojiang  *   * Redistributions of source code must retain the above copyright notice,
9*572c4311Sfengbojiang  *     this list of conditions and the following disclaimer.
10*572c4311Sfengbojiang  *   * Redistributions in binary form must reproduce the above copyright
11*572c4311Sfengbojiang  *     notice, this list of conditions and the following disclaimer in the
12*572c4311Sfengbojiang  *     documentation and/or other materials provided with the distribution.
13*572c4311Sfengbojiang  *   * Neither the name of Redis nor the names of its contributors may be used
14*572c4311Sfengbojiang  *     to endorse or promote products derived from this software without
15*572c4311Sfengbojiang  *     specific prior written permission.
16*572c4311Sfengbojiang  *
17*572c4311Sfengbojiang  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18*572c4311Sfengbojiang  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*572c4311Sfengbojiang  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*572c4311Sfengbojiang  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21*572c4311Sfengbojiang  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22*572c4311Sfengbojiang  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23*572c4311Sfengbojiang  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*572c4311Sfengbojiang  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25*572c4311Sfengbojiang  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26*572c4311Sfengbojiang  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27*572c4311Sfengbojiang  * POSSIBILITY OF SUCH DAMAGE.
28*572c4311Sfengbojiang  */
29*572c4311Sfengbojiang 
30*572c4311Sfengbojiang #include "server.h"
31*572c4311Sfengbojiang #include "cluster.h"
32*572c4311Sfengbojiang #include "slowlog.h"
33*572c4311Sfengbojiang #include "bio.h"
34*572c4311Sfengbojiang #include "latency.h"
35*572c4311Sfengbojiang #include "atomicvar.h"
36*572c4311Sfengbojiang 
37*572c4311Sfengbojiang #ifdef HAVE_FF_KQUEUE
38*572c4311Sfengbojiang #include "ff_api.h"
39*572c4311Sfengbojiang #include "anet_ff.h"
40*572c4311Sfengbojiang #endif
41*572c4311Sfengbojiang 
42*572c4311Sfengbojiang #include <time.h>
43*572c4311Sfengbojiang #include <signal.h>
44*572c4311Sfengbojiang #include <sys/wait.h>
45*572c4311Sfengbojiang #include <errno.h>
46*572c4311Sfengbojiang #include <assert.h>
47*572c4311Sfengbojiang #include <ctype.h>
48*572c4311Sfengbojiang #include <stdarg.h>
49*572c4311Sfengbojiang #include <arpa/inet.h>
50*572c4311Sfengbojiang #include <sys/stat.h>
51*572c4311Sfengbojiang #include <fcntl.h>
52*572c4311Sfengbojiang #include <sys/time.h>
53*572c4311Sfengbojiang #include <sys/resource.h>
54*572c4311Sfengbojiang #include <sys/uio.h>
55*572c4311Sfengbojiang #include <sys/un.h>
56*572c4311Sfengbojiang #include <limits.h>
57*572c4311Sfengbojiang #include <float.h>
58*572c4311Sfengbojiang #include <math.h>
59*572c4311Sfengbojiang #include <sys/resource.h>
60*572c4311Sfengbojiang #include <sys/utsname.h>
61*572c4311Sfengbojiang #include <locale.h>
62*572c4311Sfengbojiang #include <sys/socket.h>
63*572c4311Sfengbojiang 
64*572c4311Sfengbojiang /* Our shared "common" objects */
65*572c4311Sfengbojiang 
66*572c4311Sfengbojiang struct sharedObjectsStruct shared;
67*572c4311Sfengbojiang 
68*572c4311Sfengbojiang /* Global vars that are actually used as constants. The following double
69*572c4311Sfengbojiang  * values are used for double on-disk serialization, and are initialized
70*572c4311Sfengbojiang  * at runtime to avoid strange compiler optimizations. */
71*572c4311Sfengbojiang 
72*572c4311Sfengbojiang double R_Zero, R_PosInf, R_NegInf, R_Nan;
73*572c4311Sfengbojiang 
74*572c4311Sfengbojiang /*================================= Globals ================================= */
75*572c4311Sfengbojiang 
76*572c4311Sfengbojiang /* Global vars */
77*572c4311Sfengbojiang struct redisServer server; /* Server global state */
78*572c4311Sfengbojiang volatile unsigned long lru_clock; /* Server global current LRU time. */
79*572c4311Sfengbojiang 
80*572c4311Sfengbojiang /* Our command table.
81*572c4311Sfengbojiang  *
82*572c4311Sfengbojiang  * Every entry is composed of the following fields:
83*572c4311Sfengbojiang  *
84*572c4311Sfengbojiang  * name: a string representing the command name.
85*572c4311Sfengbojiang  * function: pointer to the C function implementing the command.
86*572c4311Sfengbojiang  * arity: number of arguments, it is possible to use -N to say >= N
87*572c4311Sfengbojiang  * sflags: command flags as string. See below for a table of flags.
88*572c4311Sfengbojiang  * flags: flags as bitmask. Computed by Redis using the 'sflags' field.
89*572c4311Sfengbojiang  * get_keys_proc: an optional function to get key arguments from a command.
90*572c4311Sfengbojiang  *                This is only used when the following three fields are not
91*572c4311Sfengbojiang  *                enough to specify what arguments are keys.
92*572c4311Sfengbojiang  * first_key_index: first argument that is a key
93*572c4311Sfengbojiang  * last_key_index: last argument that is a key
94*572c4311Sfengbojiang  * key_step: step to get all the keys from first to last argument. For instance
95*572c4311Sfengbojiang  *           in MSET the step is two since arguments are key,val,key,val,...
96*572c4311Sfengbojiang  * microseconds: microseconds of total execution time for this command.
97*572c4311Sfengbojiang  * calls: total number of calls of this command.
98*572c4311Sfengbojiang  *
99*572c4311Sfengbojiang  * The flags, microseconds and calls fields are computed by Redis and should
100*572c4311Sfengbojiang  * always be set to zero.
101*572c4311Sfengbojiang  *
102*572c4311Sfengbojiang  * Command flags are expressed using strings where every character represents
103*572c4311Sfengbojiang  * a flag. Later the populateCommandTable() function will take care of
104*572c4311Sfengbojiang  * populating the real 'flags' field using this characters.
105*572c4311Sfengbojiang  *
106*572c4311Sfengbojiang  * This is the meaning of the flags:
107*572c4311Sfengbojiang  *
108*572c4311Sfengbojiang  * w: write command (may modify the key space).
109*572c4311Sfengbojiang  * r: read command  (will never modify the key space).
110*572c4311Sfengbojiang  * m: may increase memory usage once called. Don't allow if out of memory.
111*572c4311Sfengbojiang  * a: admin command, like SAVE or SHUTDOWN.
112*572c4311Sfengbojiang  * p: Pub/Sub related command.
113*572c4311Sfengbojiang  * f: force replication of this command, regardless of server.dirty.
114*572c4311Sfengbojiang  * s: command not allowed in scripts.
115*572c4311Sfengbojiang  * R: random command. Command is not deterministic, that is, the same command
116*572c4311Sfengbojiang  *    with the same arguments, with the same key space, may have different
117*572c4311Sfengbojiang  *    results. For instance SPOP and RANDOMKEY are two random commands.
118*572c4311Sfengbojiang  * S: Sort command output array if called from script, so that the output
119*572c4311Sfengbojiang  *    is deterministic.
120*572c4311Sfengbojiang  * l: Allow command while loading the database.
121*572c4311Sfengbojiang  * t: Allow command while a slave has stale data but is not allowed to
122*572c4311Sfengbojiang  *    server this data. Normally no command is accepted in this condition
123*572c4311Sfengbojiang  *    but just a few.
124*572c4311Sfengbojiang  * M: Do not automatically propagate the command on MONITOR.
125*572c4311Sfengbojiang  * k: Perform an implicit ASKING for this command, so the command will be
126*572c4311Sfengbojiang  *    accepted in cluster mode if the slot is marked as 'importing'.
127*572c4311Sfengbojiang  * F: Fast command: O(1) or O(log(N)) command that should never delay
128*572c4311Sfengbojiang  *    its execution as long as the kernel scheduler is giving us time.
129*572c4311Sfengbojiang  *    Note that commands that may trigger a DEL as a side effect (like SET)
130*572c4311Sfengbojiang  *    are not fast commands.
131*572c4311Sfengbojiang  */
132*572c4311Sfengbojiang struct redisCommand redisCommandTable[] = {
133*572c4311Sfengbojiang     {"module",moduleCommand,-2,"as",0,NULL,0,0,0,0,0},
134*572c4311Sfengbojiang     {"get",getCommand,2,"rF",0,NULL,1,1,1,0,0},
135*572c4311Sfengbojiang     {"set",setCommand,-3,"wm",0,NULL,1,1,1,0,0},
136*572c4311Sfengbojiang     {"setnx",setnxCommand,3,"wmF",0,NULL,1,1,1,0,0},
137*572c4311Sfengbojiang     {"setex",setexCommand,4,"wm",0,NULL,1,1,1,0,0},
138*572c4311Sfengbojiang     {"psetex",psetexCommand,4,"wm",0,NULL,1,1,1,0,0},
139*572c4311Sfengbojiang     {"append",appendCommand,3,"wm",0,NULL,1,1,1,0,0},
140*572c4311Sfengbojiang     {"strlen",strlenCommand,2,"rF",0,NULL,1,1,1,0,0},
141*572c4311Sfengbojiang     {"del",delCommand,-2,"w",0,NULL,1,-1,1,0,0},
142*572c4311Sfengbojiang     {"unlink",unlinkCommand,-2,"wF",0,NULL,1,-1,1,0,0},
143*572c4311Sfengbojiang     {"exists",existsCommand,-2,"rF",0,NULL,1,-1,1,0,0},
144*572c4311Sfengbojiang     {"setbit",setbitCommand,4,"wm",0,NULL,1,1,1,0,0},
145*572c4311Sfengbojiang     {"getbit",getbitCommand,3,"rF",0,NULL,1,1,1,0,0},
146*572c4311Sfengbojiang     {"bitfield",bitfieldCommand,-2,"wm",0,NULL,1,1,1,0,0},
147*572c4311Sfengbojiang     {"setrange",setrangeCommand,4,"wm",0,NULL,1,1,1,0,0},
148*572c4311Sfengbojiang     {"getrange",getrangeCommand,4,"r",0,NULL,1,1,1,0,0},
149*572c4311Sfengbojiang     {"substr",getrangeCommand,4,"r",0,NULL,1,1,1,0,0},
150*572c4311Sfengbojiang     {"incr",incrCommand,2,"wmF",0,NULL,1,1,1,0,0},
151*572c4311Sfengbojiang     {"decr",decrCommand,2,"wmF",0,NULL,1,1,1,0,0},
152*572c4311Sfengbojiang     {"mget",mgetCommand,-2,"rF",0,NULL,1,-1,1,0,0},
153*572c4311Sfengbojiang     {"rpush",rpushCommand,-3,"wmF",0,NULL,1,1,1,0,0},
154*572c4311Sfengbojiang     {"lpush",lpushCommand,-3,"wmF",0,NULL,1,1,1,0,0},
155*572c4311Sfengbojiang     {"rpushx",rpushxCommand,-3,"wmF",0,NULL,1,1,1,0,0},
156*572c4311Sfengbojiang     {"lpushx",lpushxCommand,-3,"wmF",0,NULL,1,1,1,0,0},
157*572c4311Sfengbojiang     {"linsert",linsertCommand,5,"wm",0,NULL,1,1,1,0,0},
158*572c4311Sfengbojiang     {"rpop",rpopCommand,2,"wF",0,NULL,1,1,1,0,0},
159*572c4311Sfengbojiang     {"lpop",lpopCommand,2,"wF",0,NULL,1,1,1,0,0},
160*572c4311Sfengbojiang     {"brpop",brpopCommand,-3,"ws",0,NULL,1,-2,1,0,0},
161*572c4311Sfengbojiang     {"brpoplpush",brpoplpushCommand,4,"wms",0,NULL,1,2,1,0,0},
162*572c4311Sfengbojiang     {"blpop",blpopCommand,-3,"ws",0,NULL,1,-2,1,0,0},
163*572c4311Sfengbojiang     {"llen",llenCommand,2,"rF",0,NULL,1,1,1,0,0},
164*572c4311Sfengbojiang     {"lindex",lindexCommand,3,"r",0,NULL,1,1,1,0,0},
165*572c4311Sfengbojiang     {"lset",lsetCommand,4,"wm",0,NULL,1,1,1,0,0},
166*572c4311Sfengbojiang     {"lrange",lrangeCommand,4,"r",0,NULL,1,1,1,0,0},
167*572c4311Sfengbojiang     {"ltrim",ltrimCommand,4,"w",0,NULL,1,1,1,0,0},
168*572c4311Sfengbojiang     {"lrem",lremCommand,4,"w",0,NULL,1,1,1,0,0},
169*572c4311Sfengbojiang     {"rpoplpush",rpoplpushCommand,3,"wm",0,NULL,1,2,1,0,0},
170*572c4311Sfengbojiang     {"sadd",saddCommand,-3,"wmF",0,NULL,1,1,1,0,0},
171*572c4311Sfengbojiang     {"srem",sremCommand,-3,"wF",0,NULL,1,1,1,0,0},
172*572c4311Sfengbojiang     {"smove",smoveCommand,4,"wF",0,NULL,1,2,1,0,0},
173*572c4311Sfengbojiang     {"sismember",sismemberCommand,3,"rF",0,NULL,1,1,1,0,0},
174*572c4311Sfengbojiang     {"scard",scardCommand,2,"rF",0,NULL,1,1,1,0,0},
175*572c4311Sfengbojiang     {"spop",spopCommand,-2,"wRF",0,NULL,1,1,1,0,0},
176*572c4311Sfengbojiang     {"srandmember",srandmemberCommand,-2,"rR",0,NULL,1,1,1,0,0},
177*572c4311Sfengbojiang     {"sinter",sinterCommand,-2,"rS",0,NULL,1,-1,1,0,0},
178*572c4311Sfengbojiang     {"sinterstore",sinterstoreCommand,-3,"wm",0,NULL,1,-1,1,0,0},
179*572c4311Sfengbojiang     {"sunion",sunionCommand,-2,"rS",0,NULL,1,-1,1,0,0},
180*572c4311Sfengbojiang     {"sunionstore",sunionstoreCommand,-3,"wm",0,NULL,1,-1,1,0,0},
181*572c4311Sfengbojiang     {"sdiff",sdiffCommand,-2,"rS",0,NULL,1,-1,1,0,0},
182*572c4311Sfengbojiang     {"sdiffstore",sdiffstoreCommand,-3,"wm",0,NULL,1,-1,1,0,0},
183*572c4311Sfengbojiang     {"smembers",sinterCommand,2,"rS",0,NULL,1,1,1,0,0},
184*572c4311Sfengbojiang     {"sscan",sscanCommand,-3,"rR",0,NULL,1,1,1,0,0},
185*572c4311Sfengbojiang     {"zadd",zaddCommand,-4,"wmF",0,NULL,1,1,1,0,0},
186*572c4311Sfengbojiang     {"zincrby",zincrbyCommand,4,"wmF",0,NULL,1,1,1,0,0},
187*572c4311Sfengbojiang     {"zrem",zremCommand,-3,"wF",0,NULL,1,1,1,0,0},
188*572c4311Sfengbojiang     {"zremrangebyscore",zremrangebyscoreCommand,4,"w",0,NULL,1,1,1,0,0},
189*572c4311Sfengbojiang     {"zremrangebyrank",zremrangebyrankCommand,4,"w",0,NULL,1,1,1,0,0},
190*572c4311Sfengbojiang     {"zremrangebylex",zremrangebylexCommand,4,"w",0,NULL,1,1,1,0,0},
191*572c4311Sfengbojiang     {"zunionstore",zunionstoreCommand,-4,"wm",0,zunionInterGetKeys,0,0,0,0,0},
192*572c4311Sfengbojiang     {"zinterstore",zinterstoreCommand,-4,"wm",0,zunionInterGetKeys,0,0,0,0,0},
193*572c4311Sfengbojiang     {"zrange",zrangeCommand,-4,"r",0,NULL,1,1,1,0,0},
194*572c4311Sfengbojiang     {"zrangebyscore",zrangebyscoreCommand,-4,"r",0,NULL,1,1,1,0,0},
195*572c4311Sfengbojiang     {"zrevrangebyscore",zrevrangebyscoreCommand,-4,"r",0,NULL,1,1,1,0,0},
196*572c4311Sfengbojiang     {"zrangebylex",zrangebylexCommand,-4,"r",0,NULL,1,1,1,0,0},
197*572c4311Sfengbojiang     {"zrevrangebylex",zrevrangebylexCommand,-4,"r",0,NULL,1,1,1,0,0},
198*572c4311Sfengbojiang     {"zcount",zcountCommand,4,"rF",0,NULL,1,1,1,0,0},
199*572c4311Sfengbojiang     {"zlexcount",zlexcountCommand,4,"rF",0,NULL,1,1,1,0,0},
200*572c4311Sfengbojiang     {"zrevrange",zrevrangeCommand,-4,"r",0,NULL,1,1,1,0,0},
201*572c4311Sfengbojiang     {"zcard",zcardCommand,2,"rF",0,NULL,1,1,1,0,0},
202*572c4311Sfengbojiang     {"zscore",zscoreCommand,3,"rF",0,NULL,1,1,1,0,0},
203*572c4311Sfengbojiang     {"zrank",zrankCommand,3,"rF",0,NULL,1,1,1,0,0},
204*572c4311Sfengbojiang     {"zrevrank",zrevrankCommand,3,"rF",0,NULL,1,1,1,0,0},
205*572c4311Sfengbojiang     {"zscan",zscanCommand,-3,"rR",0,NULL,1,1,1,0,0},
206*572c4311Sfengbojiang     {"zpopmin",zpopminCommand,-2,"wF",0,NULL,1,1,1,0,0},
207*572c4311Sfengbojiang     {"zpopmax",zpopmaxCommand,-2,"wF",0,NULL,1,1,1,0,0},
208*572c4311Sfengbojiang     {"bzpopmin",bzpopminCommand,-3,"wsF",0,NULL,1,-2,1,0,0},
209*572c4311Sfengbojiang     {"bzpopmax",bzpopmaxCommand,-3,"wsF",0,NULL,1,-2,1,0,0},
210*572c4311Sfengbojiang     {"hset",hsetCommand,-4,"wmF",0,NULL,1,1,1,0,0},
211*572c4311Sfengbojiang     {"hsetnx",hsetnxCommand,4,"wmF",0,NULL,1,1,1,0,0},
212*572c4311Sfengbojiang     {"hget",hgetCommand,3,"rF",0,NULL,1,1,1,0,0},
213*572c4311Sfengbojiang     {"hmset",hsetCommand,-4,"wmF",0,NULL,1,1,1,0,0},
214*572c4311Sfengbojiang     {"hmget",hmgetCommand,-3,"rF",0,NULL,1,1,1,0,0},
215*572c4311Sfengbojiang     {"hincrby",hincrbyCommand,4,"wmF",0,NULL,1,1,1,0,0},
216*572c4311Sfengbojiang     {"hincrbyfloat",hincrbyfloatCommand,4,"wmF",0,NULL,1,1,1,0,0},
217*572c4311Sfengbojiang     {"hdel",hdelCommand,-3,"wF",0,NULL,1,1,1,0,0},
218*572c4311Sfengbojiang     {"hlen",hlenCommand,2,"rF",0,NULL,1,1,1,0,0},
219*572c4311Sfengbojiang     {"hstrlen",hstrlenCommand,3,"rF",0,NULL,1,1,1,0,0},
220*572c4311Sfengbojiang     {"hkeys",hkeysCommand,2,"rS",0,NULL,1,1,1,0,0},
221*572c4311Sfengbojiang     {"hvals",hvalsCommand,2,"rS",0,NULL,1,1,1,0,0},
222*572c4311Sfengbojiang     {"hgetall",hgetallCommand,2,"rR",0,NULL,1,1,1,0,0},
223*572c4311Sfengbojiang     {"hexists",hexistsCommand,3,"rF",0,NULL,1,1,1,0,0},
224*572c4311Sfengbojiang     {"hscan",hscanCommand,-3,"rR",0,NULL,1,1,1,0,0},
225*572c4311Sfengbojiang     {"incrby",incrbyCommand,3,"wmF",0,NULL,1,1,1,0,0},
226*572c4311Sfengbojiang     {"decrby",decrbyCommand,3,"wmF",0,NULL,1,1,1,0,0},
227*572c4311Sfengbojiang     {"incrbyfloat",incrbyfloatCommand,3,"wmF",0,NULL,1,1,1,0,0},
228*572c4311Sfengbojiang     {"getset",getsetCommand,3,"wm",0,NULL,1,1,1,0,0},
229*572c4311Sfengbojiang     {"mset",msetCommand,-3,"wm",0,NULL,1,-1,2,0,0},
230*572c4311Sfengbojiang     {"msetnx",msetnxCommand,-3,"wm",0,NULL,1,-1,2,0,0},
231*572c4311Sfengbojiang     {"randomkey",randomkeyCommand,1,"rR",0,NULL,0,0,0,0,0},
232*572c4311Sfengbojiang     {"select",selectCommand,2,"lF",0,NULL,0,0,0,0,0},
233*572c4311Sfengbojiang     {"swapdb",swapdbCommand,3,"wF",0,NULL,0,0,0,0,0},
234*572c4311Sfengbojiang     {"move",moveCommand,3,"wF",0,NULL,1,1,1,0,0},
235*572c4311Sfengbojiang     {"rename",renameCommand,3,"w",0,NULL,1,2,1,0,0},
236*572c4311Sfengbojiang     {"renamenx",renamenxCommand,3,"wF",0,NULL,1,2,1,0,0},
237*572c4311Sfengbojiang     {"expire",expireCommand,3,"wF",0,NULL,1,1,1,0,0},
238*572c4311Sfengbojiang     {"expireat",expireatCommand,3,"wF",0,NULL,1,1,1,0,0},
239*572c4311Sfengbojiang     {"pexpire",pexpireCommand,3,"wF",0,NULL,1,1,1,0,0},
240*572c4311Sfengbojiang     {"pexpireat",pexpireatCommand,3,"wF",0,NULL,1,1,1,0,0},
241*572c4311Sfengbojiang     {"keys",keysCommand,2,"rS",0,NULL,0,0,0,0,0},
242*572c4311Sfengbojiang     {"scan",scanCommand,-2,"rR",0,NULL,0,0,0,0,0},
243*572c4311Sfengbojiang     {"dbsize",dbsizeCommand,1,"rF",0,NULL,0,0,0,0,0},
244*572c4311Sfengbojiang     {"auth",authCommand,2,"sltF",0,NULL,0,0,0,0,0},
245*572c4311Sfengbojiang     {"ping",pingCommand,-1,"tF",0,NULL,0,0,0,0,0},
246*572c4311Sfengbojiang     {"echo",echoCommand,2,"F",0,NULL,0,0,0,0,0},
247*572c4311Sfengbojiang     {"save",saveCommand,1,"as",0,NULL,0,0,0,0,0},
248*572c4311Sfengbojiang     {"bgsave",bgsaveCommand,-1,"as",0,NULL,0,0,0,0,0},
249*572c4311Sfengbojiang     {"bgrewriteaof",bgrewriteaofCommand,1,"as",0,NULL,0,0,0,0,0},
250*572c4311Sfengbojiang     {"shutdown",shutdownCommand,-1,"aslt",0,NULL,0,0,0,0,0},
251*572c4311Sfengbojiang     {"lastsave",lastsaveCommand,1,"RF",0,NULL,0,0,0,0,0},
252*572c4311Sfengbojiang     {"type",typeCommand,2,"rF",0,NULL,1,1,1,0,0},
253*572c4311Sfengbojiang     {"multi",multiCommand,1,"sF",0,NULL,0,0,0,0,0},
254*572c4311Sfengbojiang     {"exec",execCommand,1,"sM",0,NULL,0,0,0,0,0},
255*572c4311Sfengbojiang     {"discard",discardCommand,1,"sF",0,NULL,0,0,0,0,0},
256*572c4311Sfengbojiang     {"sync",syncCommand,1,"ars",0,NULL,0,0,0,0,0},
257*572c4311Sfengbojiang     {"psync",syncCommand,3,"ars",0,NULL,0,0,0,0,0},
258*572c4311Sfengbojiang     {"replconf",replconfCommand,-1,"aslt",0,NULL,0,0,0,0,0},
259*572c4311Sfengbojiang     {"flushdb",flushdbCommand,-1,"w",0,NULL,0,0,0,0,0},
260*572c4311Sfengbojiang     {"flushall",flushallCommand,-1,"w",0,NULL,0,0,0,0,0},
261*572c4311Sfengbojiang     {"sort",sortCommand,-2,"wm",0,sortGetKeys,1,1,1,0,0},
262*572c4311Sfengbojiang     {"info",infoCommand,-1,"ltR",0,NULL,0,0,0,0,0},
263*572c4311Sfengbojiang     {"monitor",monitorCommand,1,"as",0,NULL,0,0,0,0,0},
264*572c4311Sfengbojiang     {"ttl",ttlCommand,2,"rFR",0,NULL,1,1,1,0,0},
265*572c4311Sfengbojiang     {"touch",touchCommand,-2,"rF",0,NULL,1,1,1,0,0},
266*572c4311Sfengbojiang     {"pttl",pttlCommand,2,"rFR",0,NULL,1,1,1,0,0},
267*572c4311Sfengbojiang     {"persist",persistCommand,2,"wF",0,NULL,1,1,1,0,0},
268*572c4311Sfengbojiang     {"slaveof",replicaofCommand,3,"ast",0,NULL,0,0,0,0,0},
269*572c4311Sfengbojiang     {"replicaof",replicaofCommand,3,"ast",0,NULL,0,0,0,0,0},
270*572c4311Sfengbojiang     {"role",roleCommand,1,"lst",0,NULL,0,0,0,0,0},
271*572c4311Sfengbojiang     {"debug",debugCommand,-2,"as",0,NULL,0,0,0,0,0},
272*572c4311Sfengbojiang     {"config",configCommand,-2,"last",0,NULL,0,0,0,0,0},
273*572c4311Sfengbojiang     {"subscribe",subscribeCommand,-2,"pslt",0,NULL,0,0,0,0,0},
274*572c4311Sfengbojiang     {"unsubscribe",unsubscribeCommand,-1,"pslt",0,NULL,0,0,0,0,0},
275*572c4311Sfengbojiang     {"psubscribe",psubscribeCommand,-2,"pslt",0,NULL,0,0,0,0,0},
276*572c4311Sfengbojiang     {"punsubscribe",punsubscribeCommand,-1,"pslt",0,NULL,0,0,0,0,0},
277*572c4311Sfengbojiang     {"publish",publishCommand,3,"pltF",0,NULL,0,0,0,0,0},
278*572c4311Sfengbojiang     {"pubsub",pubsubCommand,-2,"pltR",0,NULL,0,0,0,0,0},
279*572c4311Sfengbojiang     {"watch",watchCommand,-2,"sF",0,NULL,1,-1,1,0,0},
280*572c4311Sfengbojiang     {"unwatch",unwatchCommand,1,"sF",0,NULL,0,0,0,0,0},
281*572c4311Sfengbojiang     {"cluster",clusterCommand,-2,"a",0,NULL,0,0,0,0,0},
282*572c4311Sfengbojiang     {"restore",restoreCommand,-4,"wm",0,NULL,1,1,1,0,0},
283*572c4311Sfengbojiang     {"restore-asking",restoreCommand,-4,"wmk",0,NULL,1,1,1,0,0},
284*572c4311Sfengbojiang     {"migrate",migrateCommand,-6,"wR",0,migrateGetKeys,0,0,0,0,0},
285*572c4311Sfengbojiang     {"asking",askingCommand,1,"F",0,NULL,0,0,0,0,0},
286*572c4311Sfengbojiang     {"readonly",readonlyCommand,1,"F",0,NULL,0,0,0,0,0},
287*572c4311Sfengbojiang     {"readwrite",readwriteCommand,1,"F",0,NULL,0,0,0,0,0},
288*572c4311Sfengbojiang     {"dump",dumpCommand,2,"rR",0,NULL,1,1,1,0,0},
289*572c4311Sfengbojiang     {"object",objectCommand,-2,"rR",0,NULL,2,2,1,0,0},
290*572c4311Sfengbojiang     {"memory",memoryCommand,-2,"rR",0,NULL,0,0,0,0,0},
291*572c4311Sfengbojiang     {"client",clientCommand,-2,"as",0,NULL,0,0,0,0,0},
292*572c4311Sfengbojiang     {"eval",evalCommand,-3,"s",0,evalGetKeys,0,0,0,0,0},
293*572c4311Sfengbojiang     {"evalsha",evalShaCommand,-3,"s",0,evalGetKeys,0,0,0,0,0},
294*572c4311Sfengbojiang     {"slowlog",slowlogCommand,-2,"aR",0,NULL,0,0,0,0,0},
295*572c4311Sfengbojiang     {"script",scriptCommand,-2,"s",0,NULL,0,0,0,0,0},
296*572c4311Sfengbojiang     {"time",timeCommand,1,"RF",0,NULL,0,0,0,0,0},
297*572c4311Sfengbojiang     {"bitop",bitopCommand,-4,"wm",0,NULL,2,-1,1,0,0},
298*572c4311Sfengbojiang     {"bitcount",bitcountCommand,-2,"r",0,NULL,1,1,1,0,0},
299*572c4311Sfengbojiang     {"bitpos",bitposCommand,-3,"r",0,NULL,1,1,1,0,0},
300*572c4311Sfengbojiang     {"wait",waitCommand,3,"s",0,NULL,0,0,0,0,0},
301*572c4311Sfengbojiang     {"command",commandCommand,0,"ltR",0,NULL,0,0,0,0,0},
302*572c4311Sfengbojiang     {"geoadd",geoaddCommand,-5,"wm",0,NULL,1,1,1,0,0},
303*572c4311Sfengbojiang     {"georadius",georadiusCommand,-6,"w",0,georadiusGetKeys,1,1,1,0,0},
304*572c4311Sfengbojiang     {"georadius_ro",georadiusroCommand,-6,"r",0,georadiusGetKeys,1,1,1,0,0},
305*572c4311Sfengbojiang     {"georadiusbymember",georadiusbymemberCommand,-5,"w",0,georadiusGetKeys,1,1,1,0,0},
306*572c4311Sfengbojiang     {"georadiusbymember_ro",georadiusbymemberroCommand,-5,"r",0,georadiusGetKeys,1,1,1,0,0},
307*572c4311Sfengbojiang     {"geohash",geohashCommand,-2,"r",0,NULL,1,1,1,0,0},
308*572c4311Sfengbojiang     {"geopos",geoposCommand,-2,"r",0,NULL,1,1,1,0,0},
309*572c4311Sfengbojiang     {"geodist",geodistCommand,-4,"r",0,NULL,1,1,1,0,0},
310*572c4311Sfengbojiang     {"pfselftest",pfselftestCommand,1,"a",0,NULL,0,0,0,0,0},
311*572c4311Sfengbojiang     {"pfadd",pfaddCommand,-2,"wmF",0,NULL,1,1,1,0,0},
312*572c4311Sfengbojiang     {"pfcount",pfcountCommand,-2,"r",0,NULL,1,-1,1,0,0},
313*572c4311Sfengbojiang     {"pfmerge",pfmergeCommand,-2,"wm",0,NULL,1,-1,1,0,0},
314*572c4311Sfengbojiang     {"pfdebug",pfdebugCommand,-3,"w",0,NULL,0,0,0,0,0},
315*572c4311Sfengbojiang     {"xadd",xaddCommand,-5,"wmFR",0,NULL,1,1,1,0,0},
316*572c4311Sfengbojiang     {"xrange",xrangeCommand,-4,"r",0,NULL,1,1,1,0,0},
317*572c4311Sfengbojiang     {"xrevrange",xrevrangeCommand,-4,"r",0,NULL,1,1,1,0,0},
318*572c4311Sfengbojiang     {"xlen",xlenCommand,2,"rF",0,NULL,1,1,1,0,0},
319*572c4311Sfengbojiang     {"xread",xreadCommand,-4,"rs",0,xreadGetKeys,1,1,1,0,0},
320*572c4311Sfengbojiang     {"xreadgroup",xreadCommand,-7,"ws",0,xreadGetKeys,1,1,1,0,0},
321*572c4311Sfengbojiang     {"xgroup",xgroupCommand,-2,"wm",0,NULL,2,2,1,0,0},
322*572c4311Sfengbojiang     {"xsetid",xsetidCommand,3,"wmF",0,NULL,1,1,1,0,0},
323*572c4311Sfengbojiang     {"xack",xackCommand,-4,"wF",0,NULL,1,1,1,0,0},
324*572c4311Sfengbojiang     {"xpending",xpendingCommand,-3,"rR",0,NULL,1,1,1,0,0},
325*572c4311Sfengbojiang     {"xclaim",xclaimCommand,-6,"wRF",0,NULL,1,1,1,0,0},
326*572c4311Sfengbojiang     {"xinfo",xinfoCommand,-2,"rR",0,NULL,2,2,1,0,0},
327*572c4311Sfengbojiang     {"xdel",xdelCommand,-3,"wF",0,NULL,1,1,1,0,0},
328*572c4311Sfengbojiang     {"xtrim",xtrimCommand,-2,"wFR",0,NULL,1,1,1,0,0},
329*572c4311Sfengbojiang     {"post",securityWarningCommand,-1,"lt",0,NULL,0,0,0,0,0},
330*572c4311Sfengbojiang     {"host:",securityWarningCommand,-1,"lt",0,NULL,0,0,0,0,0},
331*572c4311Sfengbojiang     {"latency",latencyCommand,-2,"aslt",0,NULL,0,0,0,0,0},
332*572c4311Sfengbojiang     {"lolwut",lolwutCommand,-1,"r",0,NULL,0,0,0,0,0}
333*572c4311Sfengbojiang };
334*572c4311Sfengbojiang 
335*572c4311Sfengbojiang /*============================ Utility functions ============================ */
336*572c4311Sfengbojiang 
337*572c4311Sfengbojiang /* We use a private localtime implementation which is fork-safe. The logging
338*572c4311Sfengbojiang  * function of Redis may be called from other threads. */
339*572c4311Sfengbojiang void nolocks_localtime(struct tm *tmp, time_t t, time_t tz, int dst);
340*572c4311Sfengbojiang 
341*572c4311Sfengbojiang /* Low level logging. To use only for very big messages, otherwise
342*572c4311Sfengbojiang  * serverLog() is to prefer. */
serverLogRaw(int level,const char * msg)343*572c4311Sfengbojiang void serverLogRaw(int level, const char *msg) {
344*572c4311Sfengbojiang     const int syslogLevelMap[] = { LOG_DEBUG, LOG_INFO, LOG_NOTICE, LOG_WARNING };
345*572c4311Sfengbojiang     const char *c = ".-*#";
346*572c4311Sfengbojiang     FILE *fp;
347*572c4311Sfengbojiang     char buf[64];
348*572c4311Sfengbojiang     int rawmode = (level & LL_RAW);
349*572c4311Sfengbojiang     int log_to_stdout = server.logfile[0] == '\0';
350*572c4311Sfengbojiang 
351*572c4311Sfengbojiang     level &= 0xff; /* clear flags */
352*572c4311Sfengbojiang     if (level < server.verbosity) return;
353*572c4311Sfengbojiang 
354*572c4311Sfengbojiang     fp = log_to_stdout ? stdout : fopen(server.logfile,"a");
355*572c4311Sfengbojiang     if (!fp) return;
356*572c4311Sfengbojiang 
357*572c4311Sfengbojiang     if (rawmode) {
358*572c4311Sfengbojiang         fprintf(fp,"%s",msg);
359*572c4311Sfengbojiang     } else {
360*572c4311Sfengbojiang         int off;
361*572c4311Sfengbojiang         struct timeval tv;
362*572c4311Sfengbojiang         int role_char;
363*572c4311Sfengbojiang         pid_t pid = getpid();
364*572c4311Sfengbojiang 
365*572c4311Sfengbojiang         gettimeofday(&tv,NULL);
366*572c4311Sfengbojiang         struct tm tm;
367*572c4311Sfengbojiang         nolocks_localtime(&tm,tv.tv_sec,server.timezone,server.daylight_active);
368*572c4311Sfengbojiang         off = strftime(buf,sizeof(buf),"%d %b %Y %H:%M:%S.",&tm);
369*572c4311Sfengbojiang         snprintf(buf+off,sizeof(buf)-off,"%03d",(int)tv.tv_usec/1000);
370*572c4311Sfengbojiang         if (server.sentinel_mode) {
371*572c4311Sfengbojiang             role_char = 'X'; /* Sentinel. */
372*572c4311Sfengbojiang         } else if (pid != server.pid) {
373*572c4311Sfengbojiang             role_char = 'C'; /* RDB / AOF writing child. */
374*572c4311Sfengbojiang         } else {
375*572c4311Sfengbojiang             role_char = (server.masterhost ? 'S':'M'); /* Slave or Master. */
376*572c4311Sfengbojiang         }
377*572c4311Sfengbojiang         fprintf(fp,"%d:%c %s %c %s\n",
378*572c4311Sfengbojiang             (int)getpid(),role_char, buf,c[level],msg);
379*572c4311Sfengbojiang     }
380*572c4311Sfengbojiang     fflush(fp);
381*572c4311Sfengbojiang 
382*572c4311Sfengbojiang     if (!log_to_stdout) fclose(fp);
383*572c4311Sfengbojiang     if (server.syslog_enabled) syslog(syslogLevelMap[level], "%s", msg);
384*572c4311Sfengbojiang }
385*572c4311Sfengbojiang 
386*572c4311Sfengbojiang /* Like serverLogRaw() but with printf-alike support. This is the function that
387*572c4311Sfengbojiang  * is used across the code. The raw version is only used in order to dump
388*572c4311Sfengbojiang  * the INFO output on crash. */
serverLog(int level,const char * fmt,...)389*572c4311Sfengbojiang void serverLog(int level, const char *fmt, ...) {
390*572c4311Sfengbojiang     va_list ap;
391*572c4311Sfengbojiang     char msg[LOG_MAX_LEN];
392*572c4311Sfengbojiang 
393*572c4311Sfengbojiang     if ((level&0xff) < server.verbosity) return;
394*572c4311Sfengbojiang 
395*572c4311Sfengbojiang     va_start(ap, fmt);
396*572c4311Sfengbojiang     vsnprintf(msg, sizeof(msg), fmt, ap);
397*572c4311Sfengbojiang     va_end(ap);
398*572c4311Sfengbojiang 
399*572c4311Sfengbojiang     serverLogRaw(level,msg);
400*572c4311Sfengbojiang }
401*572c4311Sfengbojiang 
402*572c4311Sfengbojiang /* Log a fixed message without printf-alike capabilities, in a way that is
403*572c4311Sfengbojiang  * safe to call from a signal handler.
404*572c4311Sfengbojiang  *
405*572c4311Sfengbojiang  * We actually use this only for signals that are not fatal from the point
406*572c4311Sfengbojiang  * of view of Redis. Signals that are going to kill the server anyway and
407*572c4311Sfengbojiang  * where we need printf-alike features are served by serverLog(). */
serverLogFromHandler(int level,const char * msg)408*572c4311Sfengbojiang void serverLogFromHandler(int level, const char *msg) {
409*572c4311Sfengbojiang     int fd;
410*572c4311Sfengbojiang     int log_to_stdout = server.logfile[0] == '\0';
411*572c4311Sfengbojiang     char buf[64];
412*572c4311Sfengbojiang 
413*572c4311Sfengbojiang     if ((level&0xff) < server.verbosity || (log_to_stdout && server.daemonize))
414*572c4311Sfengbojiang         return;
415*572c4311Sfengbojiang     fd = log_to_stdout ? STDOUT_FILENO :
416*572c4311Sfengbojiang                          open(server.logfile, O_APPEND|O_CREAT|O_WRONLY, 0644);
417*572c4311Sfengbojiang     if (fd == -1) return;
418*572c4311Sfengbojiang     ll2string(buf,sizeof(buf),getpid());
419*572c4311Sfengbojiang     if (write(fd,buf,strlen(buf)) == -1) goto err;
420*572c4311Sfengbojiang     if (write(fd,":signal-handler (",17) == -1) goto err;
421*572c4311Sfengbojiang     ll2string(buf,sizeof(buf),time(NULL));
422*572c4311Sfengbojiang     if (write(fd,buf,strlen(buf)) == -1) goto err;
423*572c4311Sfengbojiang     if (write(fd,") ",2) == -1) goto err;
424*572c4311Sfengbojiang     if (write(fd,msg,strlen(msg)) == -1) goto err;
425*572c4311Sfengbojiang     if (write(fd,"\n",1) == -1) goto err;
426*572c4311Sfengbojiang err:
427*572c4311Sfengbojiang     if (!log_to_stdout) close(fd);
428*572c4311Sfengbojiang }
429*572c4311Sfengbojiang 
430*572c4311Sfengbojiang /* Return the UNIX time in microseconds */
ustime(void)431*572c4311Sfengbojiang long long ustime(void) {
432*572c4311Sfengbojiang     struct timeval tv;
433*572c4311Sfengbojiang     long long ust;
434*572c4311Sfengbojiang 
435*572c4311Sfengbojiang     gettimeofday(&tv, NULL);
436*572c4311Sfengbojiang     ust = ((long long)tv.tv_sec)*1000000;
437*572c4311Sfengbojiang     ust += tv.tv_usec;
438*572c4311Sfengbojiang     return ust;
439*572c4311Sfengbojiang }
440*572c4311Sfengbojiang 
441*572c4311Sfengbojiang /* Return the UNIX time in milliseconds */
mstime(void)442*572c4311Sfengbojiang mstime_t mstime(void) {
443*572c4311Sfengbojiang     return ustime()/1000;
444*572c4311Sfengbojiang }
445*572c4311Sfengbojiang 
446*572c4311Sfengbojiang /* After an RDB dump or AOF rewrite we exit from children using _exit() instead of
447*572c4311Sfengbojiang  * exit(), because the latter may interact with the same file objects used by
448*572c4311Sfengbojiang  * the parent process. However if we are testing the coverage normal exit() is
449*572c4311Sfengbojiang  * used in order to obtain the right coverage information. */
exitFromChild(int retcode)450*572c4311Sfengbojiang void exitFromChild(int retcode) {
451*572c4311Sfengbojiang #ifdef COVERAGE_TEST
452*572c4311Sfengbojiang     exit(retcode);
453*572c4311Sfengbojiang #else
454*572c4311Sfengbojiang     _exit(retcode);
455*572c4311Sfengbojiang #endif
456*572c4311Sfengbojiang }
457*572c4311Sfengbojiang 
458*572c4311Sfengbojiang /*====================== Hash table type implementation  ==================== */
459*572c4311Sfengbojiang 
460*572c4311Sfengbojiang /* This is a hash table type that uses the SDS dynamic strings library as
461*572c4311Sfengbojiang  * keys and redis objects as values (objects can hold SDS strings,
462*572c4311Sfengbojiang  * lists, sets). */
463*572c4311Sfengbojiang 
dictVanillaFree(void * privdata,void * val)464*572c4311Sfengbojiang void dictVanillaFree(void *privdata, void *val)
465*572c4311Sfengbojiang {
466*572c4311Sfengbojiang     DICT_NOTUSED(privdata);
467*572c4311Sfengbojiang     zfree(val);
468*572c4311Sfengbojiang }
469*572c4311Sfengbojiang 
dictListDestructor(void * privdata,void * val)470*572c4311Sfengbojiang void dictListDestructor(void *privdata, void *val)
471*572c4311Sfengbojiang {
472*572c4311Sfengbojiang     DICT_NOTUSED(privdata);
473*572c4311Sfengbojiang     listRelease((list*)val);
474*572c4311Sfengbojiang }
475*572c4311Sfengbojiang 
dictSdsKeyCompare(void * privdata,const void * key1,const void * key2)476*572c4311Sfengbojiang int dictSdsKeyCompare(void *privdata, const void *key1,
477*572c4311Sfengbojiang         const void *key2)
478*572c4311Sfengbojiang {
479*572c4311Sfengbojiang     int l1,l2;
480*572c4311Sfengbojiang     DICT_NOTUSED(privdata);
481*572c4311Sfengbojiang 
482*572c4311Sfengbojiang     l1 = sdslen((sds)key1);
483*572c4311Sfengbojiang     l2 = sdslen((sds)key2);
484*572c4311Sfengbojiang     if (l1 != l2) return 0;
485*572c4311Sfengbojiang     return memcmp(key1, key2, l1) == 0;
486*572c4311Sfengbojiang }
487*572c4311Sfengbojiang 
488*572c4311Sfengbojiang /* A case insensitive version used for the command lookup table and other
489*572c4311Sfengbojiang  * places where case insensitive non binary-safe comparison is needed. */
dictSdsKeyCaseCompare(void * privdata,const void * key1,const void * key2)490*572c4311Sfengbojiang int dictSdsKeyCaseCompare(void *privdata, const void *key1,
491*572c4311Sfengbojiang         const void *key2)
492*572c4311Sfengbojiang {
493*572c4311Sfengbojiang     DICT_NOTUSED(privdata);
494*572c4311Sfengbojiang 
495*572c4311Sfengbojiang     return strcasecmp(key1, key2) == 0;
496*572c4311Sfengbojiang }
497*572c4311Sfengbojiang 
dictObjectDestructor(void * privdata,void * val)498*572c4311Sfengbojiang void dictObjectDestructor(void *privdata, void *val)
499*572c4311Sfengbojiang {
500*572c4311Sfengbojiang     DICT_NOTUSED(privdata);
501*572c4311Sfengbojiang 
502*572c4311Sfengbojiang     if (val == NULL) return; /* Lazy freeing will set value to NULL. */
503*572c4311Sfengbojiang     decrRefCount(val);
504*572c4311Sfengbojiang }
505*572c4311Sfengbojiang 
dictSdsDestructor(void * privdata,void * val)506*572c4311Sfengbojiang void dictSdsDestructor(void *privdata, void *val)
507*572c4311Sfengbojiang {
508*572c4311Sfengbojiang     DICT_NOTUSED(privdata);
509*572c4311Sfengbojiang 
510*572c4311Sfengbojiang     sdsfree(val);
511*572c4311Sfengbojiang }
512*572c4311Sfengbojiang 
dictObjKeyCompare(void * privdata,const void * key1,const void * key2)513*572c4311Sfengbojiang int dictObjKeyCompare(void *privdata, const void *key1,
514*572c4311Sfengbojiang         const void *key2)
515*572c4311Sfengbojiang {
516*572c4311Sfengbojiang     const robj *o1 = key1, *o2 = key2;
517*572c4311Sfengbojiang     return dictSdsKeyCompare(privdata,o1->ptr,o2->ptr);
518*572c4311Sfengbojiang }
519*572c4311Sfengbojiang 
dictObjHash(const void * key)520*572c4311Sfengbojiang uint64_t dictObjHash(const void *key) {
521*572c4311Sfengbojiang     const robj *o = key;
522*572c4311Sfengbojiang     return dictGenHashFunction(o->ptr, sdslen((sds)o->ptr));
523*572c4311Sfengbojiang }
524*572c4311Sfengbojiang 
dictSdsHash(const void * key)525*572c4311Sfengbojiang uint64_t dictSdsHash(const void *key) {
526*572c4311Sfengbojiang     return dictGenHashFunction((unsigned char*)key, sdslen((char*)key));
527*572c4311Sfengbojiang }
528*572c4311Sfengbojiang 
dictSdsCaseHash(const void * key)529*572c4311Sfengbojiang uint64_t dictSdsCaseHash(const void *key) {
530*572c4311Sfengbojiang     return dictGenCaseHashFunction((unsigned char*)key, sdslen((char*)key));
531*572c4311Sfengbojiang }
532*572c4311Sfengbojiang 
dictEncObjKeyCompare(void * privdata,const void * key1,const void * key2)533*572c4311Sfengbojiang int dictEncObjKeyCompare(void *privdata, const void *key1,
534*572c4311Sfengbojiang         const void *key2)
535*572c4311Sfengbojiang {
536*572c4311Sfengbojiang     robj *o1 = (robj*) key1, *o2 = (robj*) key2;
537*572c4311Sfengbojiang     int cmp;
538*572c4311Sfengbojiang 
539*572c4311Sfengbojiang     if (o1->encoding == OBJ_ENCODING_INT &&
540*572c4311Sfengbojiang         o2->encoding == OBJ_ENCODING_INT)
541*572c4311Sfengbojiang             return o1->ptr == o2->ptr;
542*572c4311Sfengbojiang 
543*572c4311Sfengbojiang     o1 = getDecodedObject(o1);
544*572c4311Sfengbojiang     o2 = getDecodedObject(o2);
545*572c4311Sfengbojiang     cmp = dictSdsKeyCompare(privdata,o1->ptr,o2->ptr);
546*572c4311Sfengbojiang     decrRefCount(o1);
547*572c4311Sfengbojiang     decrRefCount(o2);
548*572c4311Sfengbojiang     return cmp;
549*572c4311Sfengbojiang }
550*572c4311Sfengbojiang 
dictEncObjHash(const void * key)551*572c4311Sfengbojiang uint64_t dictEncObjHash(const void *key) {
552*572c4311Sfengbojiang     robj *o = (robj*) key;
553*572c4311Sfengbojiang 
554*572c4311Sfengbojiang     if (sdsEncodedObject(o)) {
555*572c4311Sfengbojiang         return dictGenHashFunction(o->ptr, sdslen((sds)o->ptr));
556*572c4311Sfengbojiang     } else {
557*572c4311Sfengbojiang         if (o->encoding == OBJ_ENCODING_INT) {
558*572c4311Sfengbojiang             char buf[32];
559*572c4311Sfengbojiang             int len;
560*572c4311Sfengbojiang 
561*572c4311Sfengbojiang             len = ll2string(buf,32,(long)o->ptr);
562*572c4311Sfengbojiang             return dictGenHashFunction((unsigned char*)buf, len);
563*572c4311Sfengbojiang         } else {
564*572c4311Sfengbojiang             uint64_t hash;
565*572c4311Sfengbojiang 
566*572c4311Sfengbojiang             o = getDecodedObject(o);
567*572c4311Sfengbojiang             hash = dictGenHashFunction(o->ptr, sdslen((sds)o->ptr));
568*572c4311Sfengbojiang             decrRefCount(o);
569*572c4311Sfengbojiang             return hash;
570*572c4311Sfengbojiang         }
571*572c4311Sfengbojiang     }
572*572c4311Sfengbojiang }
573*572c4311Sfengbojiang 
574*572c4311Sfengbojiang /* Generic hash table type where keys are Redis Objects, Values
575*572c4311Sfengbojiang  * dummy pointers. */
576*572c4311Sfengbojiang dictType objectKeyPointerValueDictType = {
577*572c4311Sfengbojiang     dictEncObjHash,            /* hash function */
578*572c4311Sfengbojiang     NULL,                      /* key dup */
579*572c4311Sfengbojiang     NULL,                      /* val dup */
580*572c4311Sfengbojiang     dictEncObjKeyCompare,      /* key compare */
581*572c4311Sfengbojiang     dictObjectDestructor,      /* key destructor */
582*572c4311Sfengbojiang     NULL                       /* val destructor */
583*572c4311Sfengbojiang };
584*572c4311Sfengbojiang 
585*572c4311Sfengbojiang /* Like objectKeyPointerValueDictType(), but values can be destroyed, if
586*572c4311Sfengbojiang  * not NULL, calling zfree(). */
587*572c4311Sfengbojiang dictType objectKeyHeapPointerValueDictType = {
588*572c4311Sfengbojiang     dictEncObjHash,            /* hash function */
589*572c4311Sfengbojiang     NULL,                      /* key dup */
590*572c4311Sfengbojiang     NULL,                      /* val dup */
591*572c4311Sfengbojiang     dictEncObjKeyCompare,      /* key compare */
592*572c4311Sfengbojiang     dictObjectDestructor,      /* key destructor */
593*572c4311Sfengbojiang     dictVanillaFree            /* val destructor */
594*572c4311Sfengbojiang };
595*572c4311Sfengbojiang 
596*572c4311Sfengbojiang /* Set dictionary type. Keys are SDS strings, values are ot used. */
597*572c4311Sfengbojiang dictType setDictType = {
598*572c4311Sfengbojiang     dictSdsHash,               /* hash function */
599*572c4311Sfengbojiang     NULL,                      /* key dup */
600*572c4311Sfengbojiang     NULL,                      /* val dup */
601*572c4311Sfengbojiang     dictSdsKeyCompare,         /* key compare */
602*572c4311Sfengbojiang     dictSdsDestructor,         /* key destructor */
603*572c4311Sfengbojiang     NULL                       /* val destructor */
604*572c4311Sfengbojiang };
605*572c4311Sfengbojiang 
606*572c4311Sfengbojiang /* Sorted sets hash (note: a skiplist is used in addition to the hash table) */
607*572c4311Sfengbojiang dictType zsetDictType = {
608*572c4311Sfengbojiang     dictSdsHash,               /* hash function */
609*572c4311Sfengbojiang     NULL,                      /* key dup */
610*572c4311Sfengbojiang     NULL,                      /* val dup */
611*572c4311Sfengbojiang     dictSdsKeyCompare,         /* key compare */
612*572c4311Sfengbojiang     NULL,                      /* Note: SDS string shared & freed by skiplist */
613*572c4311Sfengbojiang     NULL                       /* val destructor */
614*572c4311Sfengbojiang };
615*572c4311Sfengbojiang 
616*572c4311Sfengbojiang /* Db->dict, keys are sds strings, vals are Redis objects. */
617*572c4311Sfengbojiang dictType dbDictType = {
618*572c4311Sfengbojiang     dictSdsHash,                /* hash function */
619*572c4311Sfengbojiang     NULL,                       /* key dup */
620*572c4311Sfengbojiang     NULL,                       /* val dup */
621*572c4311Sfengbojiang     dictSdsKeyCompare,          /* key compare */
622*572c4311Sfengbojiang     dictSdsDestructor,          /* key destructor */
623*572c4311Sfengbojiang     dictObjectDestructor   /* val destructor */
624*572c4311Sfengbojiang };
625*572c4311Sfengbojiang 
626*572c4311Sfengbojiang /* server.lua_scripts sha (as sds string) -> scripts (as robj) cache. */
627*572c4311Sfengbojiang dictType shaScriptObjectDictType = {
628*572c4311Sfengbojiang     dictSdsCaseHash,            /* hash function */
629*572c4311Sfengbojiang     NULL,                       /* key dup */
630*572c4311Sfengbojiang     NULL,                       /* val dup */
631*572c4311Sfengbojiang     dictSdsKeyCaseCompare,      /* key compare */
632*572c4311Sfengbojiang     dictSdsDestructor,          /* key destructor */
633*572c4311Sfengbojiang     dictObjectDestructor        /* val destructor */
634*572c4311Sfengbojiang };
635*572c4311Sfengbojiang 
636*572c4311Sfengbojiang /* Db->expires */
637*572c4311Sfengbojiang dictType keyptrDictType = {
638*572c4311Sfengbojiang     dictSdsHash,                /* hash function */
639*572c4311Sfengbojiang     NULL,                       /* key dup */
640*572c4311Sfengbojiang     NULL,                       /* val dup */
641*572c4311Sfengbojiang     dictSdsKeyCompare,          /* key compare */
642*572c4311Sfengbojiang     NULL,                       /* key destructor */
643*572c4311Sfengbojiang     NULL                        /* val destructor */
644*572c4311Sfengbojiang };
645*572c4311Sfengbojiang 
646*572c4311Sfengbojiang /* Command table. sds string -> command struct pointer. */
647*572c4311Sfengbojiang dictType commandTableDictType = {
648*572c4311Sfengbojiang     dictSdsCaseHash,            /* hash function */
649*572c4311Sfengbojiang     NULL,                       /* key dup */
650*572c4311Sfengbojiang     NULL,                       /* val dup */
651*572c4311Sfengbojiang     dictSdsKeyCaseCompare,      /* key compare */
652*572c4311Sfengbojiang     dictSdsDestructor,          /* key destructor */
653*572c4311Sfengbojiang     NULL                        /* val destructor */
654*572c4311Sfengbojiang };
655*572c4311Sfengbojiang 
656*572c4311Sfengbojiang /* Hash type hash table (note that small hashes are represented with ziplists) */
657*572c4311Sfengbojiang dictType hashDictType = {
658*572c4311Sfengbojiang     dictSdsHash,                /* hash function */
659*572c4311Sfengbojiang     NULL,                       /* key dup */
660*572c4311Sfengbojiang     NULL,                       /* val dup */
661*572c4311Sfengbojiang     dictSdsKeyCompare,          /* key compare */
662*572c4311Sfengbojiang     dictSdsDestructor,          /* key destructor */
663*572c4311Sfengbojiang     dictSdsDestructor           /* val destructor */
664*572c4311Sfengbojiang };
665*572c4311Sfengbojiang 
666*572c4311Sfengbojiang /* Keylist hash table type has unencoded redis objects as keys and
667*572c4311Sfengbojiang  * lists as values. It's used for blocking operations (BLPOP) and to
668*572c4311Sfengbojiang  * map swapped keys to a list of clients waiting for this keys to be loaded. */
669*572c4311Sfengbojiang dictType keylistDictType = {
670*572c4311Sfengbojiang     dictObjHash,                /* hash function */
671*572c4311Sfengbojiang     NULL,                       /* key dup */
672*572c4311Sfengbojiang     NULL,                       /* val dup */
673*572c4311Sfengbojiang     dictObjKeyCompare,          /* key compare */
674*572c4311Sfengbojiang     dictObjectDestructor,       /* key destructor */
675*572c4311Sfengbojiang     dictListDestructor          /* val destructor */
676*572c4311Sfengbojiang };
677*572c4311Sfengbojiang 
678*572c4311Sfengbojiang /* Cluster nodes hash table, mapping nodes addresses 1.2.3.4:6379 to
679*572c4311Sfengbojiang  * clusterNode structures. */
680*572c4311Sfengbojiang dictType clusterNodesDictType = {
681*572c4311Sfengbojiang     dictSdsHash,                /* hash function */
682*572c4311Sfengbojiang     NULL,                       /* key dup */
683*572c4311Sfengbojiang     NULL,                       /* val dup */
684*572c4311Sfengbojiang     dictSdsKeyCompare,          /* key compare */
685*572c4311Sfengbojiang     dictSdsDestructor,          /* key destructor */
686*572c4311Sfengbojiang     NULL                        /* val destructor */
687*572c4311Sfengbojiang };
688*572c4311Sfengbojiang 
689*572c4311Sfengbojiang /* Cluster re-addition blacklist. This maps node IDs to the time
690*572c4311Sfengbojiang  * we can re-add this node. The goal is to avoid readding a removed
691*572c4311Sfengbojiang  * node for some time. */
692*572c4311Sfengbojiang dictType clusterNodesBlackListDictType = {
693*572c4311Sfengbojiang     dictSdsCaseHash,            /* hash function */
694*572c4311Sfengbojiang     NULL,                       /* key dup */
695*572c4311Sfengbojiang     NULL,                       /* val dup */
696*572c4311Sfengbojiang     dictSdsKeyCaseCompare,      /* key compare */
697*572c4311Sfengbojiang     dictSdsDestructor,          /* key destructor */
698*572c4311Sfengbojiang     NULL                        /* val destructor */
699*572c4311Sfengbojiang };
700*572c4311Sfengbojiang 
701*572c4311Sfengbojiang /* Cluster re-addition blacklist. This maps node IDs to the time
702*572c4311Sfengbojiang  * we can re-add this node. The goal is to avoid readding a removed
703*572c4311Sfengbojiang  * node for some time. */
704*572c4311Sfengbojiang dictType modulesDictType = {
705*572c4311Sfengbojiang     dictSdsCaseHash,            /* hash function */
706*572c4311Sfengbojiang     NULL,                       /* key dup */
707*572c4311Sfengbojiang     NULL,                       /* val dup */
708*572c4311Sfengbojiang     dictSdsKeyCaseCompare,      /* key compare */
709*572c4311Sfengbojiang     dictSdsDestructor,          /* key destructor */
710*572c4311Sfengbojiang     NULL                        /* val destructor */
711*572c4311Sfengbojiang };
712*572c4311Sfengbojiang 
713*572c4311Sfengbojiang /* Migrate cache dict type. */
714*572c4311Sfengbojiang dictType migrateCacheDictType = {
715*572c4311Sfengbojiang     dictSdsHash,                /* hash function */
716*572c4311Sfengbojiang     NULL,                       /* key dup */
717*572c4311Sfengbojiang     NULL,                       /* val dup */
718*572c4311Sfengbojiang     dictSdsKeyCompare,          /* key compare */
719*572c4311Sfengbojiang     dictSdsDestructor,          /* key destructor */
720*572c4311Sfengbojiang     NULL                        /* val destructor */
721*572c4311Sfengbojiang };
722*572c4311Sfengbojiang 
723*572c4311Sfengbojiang /* Replication cached script dict (server.repl_scriptcache_dict).
724*572c4311Sfengbojiang  * Keys are sds SHA1 strings, while values are not used at all in the current
725*572c4311Sfengbojiang  * implementation. */
726*572c4311Sfengbojiang dictType replScriptCacheDictType = {
727*572c4311Sfengbojiang     dictSdsCaseHash,            /* hash function */
728*572c4311Sfengbojiang     NULL,                       /* key dup */
729*572c4311Sfengbojiang     NULL,                       /* val dup */
730*572c4311Sfengbojiang     dictSdsKeyCaseCompare,      /* key compare */
731*572c4311Sfengbojiang     dictSdsDestructor,          /* key destructor */
732*572c4311Sfengbojiang     NULL                        /* val destructor */
733*572c4311Sfengbojiang };
734*572c4311Sfengbojiang 
htNeedsResize(dict * dict)735*572c4311Sfengbojiang int htNeedsResize(dict *dict) {
736*572c4311Sfengbojiang     long long size, used;
737*572c4311Sfengbojiang 
738*572c4311Sfengbojiang     size = dictSlots(dict);
739*572c4311Sfengbojiang     used = dictSize(dict);
740*572c4311Sfengbojiang     return (size > DICT_HT_INITIAL_SIZE &&
741*572c4311Sfengbojiang             (used*100/size < HASHTABLE_MIN_FILL));
742*572c4311Sfengbojiang }
743*572c4311Sfengbojiang 
744*572c4311Sfengbojiang /* If the percentage of used slots in the HT reaches HASHTABLE_MIN_FILL
745*572c4311Sfengbojiang  * we resize the hash table to save memory */
tryResizeHashTables(int dbid)746*572c4311Sfengbojiang void tryResizeHashTables(int dbid) {
747*572c4311Sfengbojiang     if (htNeedsResize(server.db[dbid].dict))
748*572c4311Sfengbojiang         dictResize(server.db[dbid].dict);
749*572c4311Sfengbojiang     if (htNeedsResize(server.db[dbid].expires))
750*572c4311Sfengbojiang         dictResize(server.db[dbid].expires);
751*572c4311Sfengbojiang }
752*572c4311Sfengbojiang 
753*572c4311Sfengbojiang /* Our hash table implementation performs rehashing incrementally while
754*572c4311Sfengbojiang  * we write/read from the hash table. Still if the server is idle, the hash
755*572c4311Sfengbojiang  * table will use two tables for a long time. So we try to use 1 millisecond
756*572c4311Sfengbojiang  * of CPU time at every call of this function to perform some rehahsing.
757*572c4311Sfengbojiang  *
758*572c4311Sfengbojiang  * The function returns 1 if some rehashing was performed, otherwise 0
759*572c4311Sfengbojiang  * is returned. */
incrementallyRehash(int dbid)760*572c4311Sfengbojiang int incrementallyRehash(int dbid) {
761*572c4311Sfengbojiang     /* Keys dictionary */
762*572c4311Sfengbojiang     if (dictIsRehashing(server.db[dbid].dict)) {
763*572c4311Sfengbojiang         dictRehashMilliseconds(server.db[dbid].dict,1);
764*572c4311Sfengbojiang         return 1; /* already used our millisecond for this loop... */
765*572c4311Sfengbojiang     }
766*572c4311Sfengbojiang     /* Expires */
767*572c4311Sfengbojiang     if (dictIsRehashing(server.db[dbid].expires)) {
768*572c4311Sfengbojiang         dictRehashMilliseconds(server.db[dbid].expires,1);
769*572c4311Sfengbojiang         return 1; /* already used our millisecond for this loop... */
770*572c4311Sfengbojiang     }
771*572c4311Sfengbojiang     return 0;
772*572c4311Sfengbojiang }
773*572c4311Sfengbojiang 
774*572c4311Sfengbojiang /* This function is called once a background process of some kind terminates,
775*572c4311Sfengbojiang  * as we want to avoid resizing the hash tables when there is a child in order
776*572c4311Sfengbojiang  * to play well with copy-on-write (otherwise when a resize happens lots of
777*572c4311Sfengbojiang  * memory pages are copied). The goal of this function is to update the ability
778*572c4311Sfengbojiang  * for dict.c to resize the hash tables accordingly to the fact we have o not
779*572c4311Sfengbojiang  * running childs. */
updateDictResizePolicy(void)780*572c4311Sfengbojiang void updateDictResizePolicy(void) {
781*572c4311Sfengbojiang     if (server.rdb_child_pid == -1 && server.aof_child_pid == -1)
782*572c4311Sfengbojiang         dictEnableResize();
783*572c4311Sfengbojiang     else
784*572c4311Sfengbojiang         dictDisableResize();
785*572c4311Sfengbojiang }
786*572c4311Sfengbojiang 
787*572c4311Sfengbojiang /* ======================= Cron: called every 100 ms ======================== */
788*572c4311Sfengbojiang 
789*572c4311Sfengbojiang /* Add a sample to the operations per second array of samples. */
trackInstantaneousMetric(int metric,long long current_reading)790*572c4311Sfengbojiang void trackInstantaneousMetric(int metric, long long current_reading) {
791*572c4311Sfengbojiang     long long t = mstime() - server.inst_metric[metric].last_sample_time;
792*572c4311Sfengbojiang     long long ops = current_reading -
793*572c4311Sfengbojiang                     server.inst_metric[metric].last_sample_count;
794*572c4311Sfengbojiang     long long ops_sec;
795*572c4311Sfengbojiang 
796*572c4311Sfengbojiang     ops_sec = t > 0 ? (ops*1000/t) : 0;
797*572c4311Sfengbojiang 
798*572c4311Sfengbojiang     server.inst_metric[metric].samples[server.inst_metric[metric].idx] =
799*572c4311Sfengbojiang         ops_sec;
800*572c4311Sfengbojiang     server.inst_metric[metric].idx++;
801*572c4311Sfengbojiang     server.inst_metric[metric].idx %= STATS_METRIC_SAMPLES;
802*572c4311Sfengbojiang     server.inst_metric[metric].last_sample_time = mstime();
803*572c4311Sfengbojiang     server.inst_metric[metric].last_sample_count = current_reading;
804*572c4311Sfengbojiang }
805*572c4311Sfengbojiang 
806*572c4311Sfengbojiang /* Return the mean of all the samples. */
getInstantaneousMetric(int metric)807*572c4311Sfengbojiang long long getInstantaneousMetric(int metric) {
808*572c4311Sfengbojiang     int j;
809*572c4311Sfengbojiang     long long sum = 0;
810*572c4311Sfengbojiang 
811*572c4311Sfengbojiang     for (j = 0; j < STATS_METRIC_SAMPLES; j++)
812*572c4311Sfengbojiang         sum += server.inst_metric[metric].samples[j];
813*572c4311Sfengbojiang     return sum / STATS_METRIC_SAMPLES;
814*572c4311Sfengbojiang }
815*572c4311Sfengbojiang 
816*572c4311Sfengbojiang /* Check for timeouts. Returns non-zero if the client was terminated.
817*572c4311Sfengbojiang  * The function gets the current time in milliseconds as argument since
818*572c4311Sfengbojiang  * it gets called multiple times in a loop, so calling gettimeofday() for
819*572c4311Sfengbojiang  * each iteration would be costly without any actual gain. */
clientsCronHandleTimeout(client * c,mstime_t now_ms)820*572c4311Sfengbojiang int clientsCronHandleTimeout(client *c, mstime_t now_ms) {
821*572c4311Sfengbojiang     time_t now = now_ms/1000;
822*572c4311Sfengbojiang 
823*572c4311Sfengbojiang     if (server.maxidletime &&
824*572c4311Sfengbojiang         !(c->flags & CLIENT_SLAVE) &&    /* no timeout for slaves */
825*572c4311Sfengbojiang         !(c->flags & CLIENT_MASTER) &&   /* no timeout for masters */
826*572c4311Sfengbojiang         !(c->flags & CLIENT_BLOCKED) &&  /* no timeout for BLPOP */
827*572c4311Sfengbojiang         !(c->flags & CLIENT_PUBSUB) &&   /* no timeout for Pub/Sub clients */
828*572c4311Sfengbojiang         (now - c->lastinteraction > server.maxidletime))
829*572c4311Sfengbojiang     {
830*572c4311Sfengbojiang         serverLog(LL_VERBOSE,"Closing idle client");
831*572c4311Sfengbojiang         freeClient(c);
832*572c4311Sfengbojiang         return 1;
833*572c4311Sfengbojiang     } else if (c->flags & CLIENT_BLOCKED) {
834*572c4311Sfengbojiang         /* Blocked OPS timeout is handled with milliseconds resolution.
835*572c4311Sfengbojiang          * However note that the actual resolution is limited by
836*572c4311Sfengbojiang          * server.hz. */
837*572c4311Sfengbojiang 
838*572c4311Sfengbojiang         if (c->bpop.timeout != 0 && c->bpop.timeout < now_ms) {
839*572c4311Sfengbojiang             /* Handle blocking operation specific timeout. */
840*572c4311Sfengbojiang             replyToBlockedClientTimedOut(c);
841*572c4311Sfengbojiang             unblockClient(c);
842*572c4311Sfengbojiang         } else if (server.cluster_enabled) {
843*572c4311Sfengbojiang             /* Cluster: handle unblock & redirect of clients blocked
844*572c4311Sfengbojiang              * into keys no longer served by this server. */
845*572c4311Sfengbojiang             if (clusterRedirectBlockedClientIfNeeded(c))
846*572c4311Sfengbojiang                 unblockClient(c);
847*572c4311Sfengbojiang         }
848*572c4311Sfengbojiang     }
849*572c4311Sfengbojiang     return 0;
850*572c4311Sfengbojiang }
851*572c4311Sfengbojiang 
852*572c4311Sfengbojiang /* The client query buffer is an sds.c string that can end with a lot of
853*572c4311Sfengbojiang  * free space not used, this function reclaims space if needed.
854*572c4311Sfengbojiang  *
855*572c4311Sfengbojiang  * The function always returns 0 as it never terminates the client. */
clientsCronResizeQueryBuffer(client * c)856*572c4311Sfengbojiang int clientsCronResizeQueryBuffer(client *c) {
857*572c4311Sfengbojiang     size_t querybuf_size = sdsAllocSize(c->querybuf);
858*572c4311Sfengbojiang     time_t idletime = server.unixtime - c->lastinteraction;
859*572c4311Sfengbojiang 
860*572c4311Sfengbojiang     /* There are two conditions to resize the query buffer:
861*572c4311Sfengbojiang      * 1) Query buffer is > BIG_ARG and too big for latest peak.
862*572c4311Sfengbojiang      * 2) Query buffer is > BIG_ARG and client is idle. */
863*572c4311Sfengbojiang     if (querybuf_size > PROTO_MBULK_BIG_ARG &&
864*572c4311Sfengbojiang          ((querybuf_size/(c->querybuf_peak+1)) > 2 ||
865*572c4311Sfengbojiang           idletime > 2))
866*572c4311Sfengbojiang     {
867*572c4311Sfengbojiang         /* Only resize the query buffer if it is actually wasting
868*572c4311Sfengbojiang          * at least a few kbytes. */
869*572c4311Sfengbojiang         if (sdsavail(c->querybuf) > 1024*4) {
870*572c4311Sfengbojiang             c->querybuf = sdsRemoveFreeSpace(c->querybuf);
871*572c4311Sfengbojiang         }
872*572c4311Sfengbojiang     }
873*572c4311Sfengbojiang     /* Reset the peak again to capture the peak memory usage in the next
874*572c4311Sfengbojiang      * cycle. */
875*572c4311Sfengbojiang     c->querybuf_peak = 0;
876*572c4311Sfengbojiang 
877*572c4311Sfengbojiang     /* Clients representing masters also use a "pending query buffer" that
878*572c4311Sfengbojiang      * is the yet not applied part of the stream we are reading. Such buffer
879*572c4311Sfengbojiang      * also needs resizing from time to time, otherwise after a very large
880*572c4311Sfengbojiang      * transfer (a huge value or a big MIGRATE operation) it will keep using
881*572c4311Sfengbojiang      * a lot of memory. */
882*572c4311Sfengbojiang     if (c->flags & CLIENT_MASTER) {
883*572c4311Sfengbojiang         /* There are two conditions to resize the pending query buffer:
884*572c4311Sfengbojiang          * 1) Pending Query buffer is > LIMIT_PENDING_QUERYBUF.
885*572c4311Sfengbojiang          * 2) Used length is smaller than pending_querybuf_size/2 */
886*572c4311Sfengbojiang         size_t pending_querybuf_size = sdsAllocSize(c->pending_querybuf);
887*572c4311Sfengbojiang         if(pending_querybuf_size > LIMIT_PENDING_QUERYBUF &&
888*572c4311Sfengbojiang            sdslen(c->pending_querybuf) < (pending_querybuf_size/2))
889*572c4311Sfengbojiang         {
890*572c4311Sfengbojiang             c->pending_querybuf = sdsRemoveFreeSpace(c->pending_querybuf);
891*572c4311Sfengbojiang         }
892*572c4311Sfengbojiang     }
893*572c4311Sfengbojiang     return 0;
894*572c4311Sfengbojiang }
895*572c4311Sfengbojiang 
896*572c4311Sfengbojiang /* This function is used in order to track clients using the biggest amount
897*572c4311Sfengbojiang  * of memory in the latest few seconds. This way we can provide such information
898*572c4311Sfengbojiang  * in the INFO output (clients section), without having to do an O(N) scan for
899*572c4311Sfengbojiang  * all the clients.
900*572c4311Sfengbojiang  *
901*572c4311Sfengbojiang  * This is how it works. We have an array of CLIENTS_PEAK_MEM_USAGE_SLOTS slots
902*572c4311Sfengbojiang  * where we track, for each, the biggest client output and input buffers we
903*572c4311Sfengbojiang  * saw in that slot. Every slot correspond to one of the latest seconds, since
904*572c4311Sfengbojiang  * the array is indexed by doing UNIXTIME % CLIENTS_PEAK_MEM_USAGE_SLOTS.
905*572c4311Sfengbojiang  *
906*572c4311Sfengbojiang  * When we want to know what was recently the peak memory usage, we just scan
907*572c4311Sfengbojiang  * such few slots searching for the maximum value. */
908*572c4311Sfengbojiang #define CLIENTS_PEAK_MEM_USAGE_SLOTS 8
909*572c4311Sfengbojiang size_t ClientsPeakMemInput[CLIENTS_PEAK_MEM_USAGE_SLOTS];
910*572c4311Sfengbojiang size_t ClientsPeakMemOutput[CLIENTS_PEAK_MEM_USAGE_SLOTS];
911*572c4311Sfengbojiang 
clientsCronTrackExpansiveClients(client * c)912*572c4311Sfengbojiang int clientsCronTrackExpansiveClients(client *c) {
913*572c4311Sfengbojiang     size_t in_usage = sdsAllocSize(c->querybuf);
914*572c4311Sfengbojiang     size_t out_usage = getClientOutputBufferMemoryUsage(c);
915*572c4311Sfengbojiang     int i = server.unixtime % CLIENTS_PEAK_MEM_USAGE_SLOTS;
916*572c4311Sfengbojiang     int zeroidx = (i+1) % CLIENTS_PEAK_MEM_USAGE_SLOTS;
917*572c4311Sfengbojiang 
918*572c4311Sfengbojiang     /* Always zero the next sample, so that when we switch to that second, we'll
919*572c4311Sfengbojiang      * only register samples that are greater in that second without considering
920*572c4311Sfengbojiang      * the history of such slot.
921*572c4311Sfengbojiang      *
922*572c4311Sfengbojiang      * Note: our index may jump to any random position if serverCron() is not
923*572c4311Sfengbojiang      * called for some reason with the normal frequency, for instance because
924*572c4311Sfengbojiang      * some slow command is called taking multiple seconds to execute. In that
925*572c4311Sfengbojiang      * case our array may end containing data which is potentially older
926*572c4311Sfengbojiang      * than CLIENTS_PEAK_MEM_USAGE_SLOTS seconds: however this is not a problem
927*572c4311Sfengbojiang      * since here we want just to track if "recently" there were very expansive
928*572c4311Sfengbojiang      * clients from the POV of memory usage. */
929*572c4311Sfengbojiang     ClientsPeakMemInput[zeroidx] = 0;
930*572c4311Sfengbojiang     ClientsPeakMemOutput[zeroidx] = 0;
931*572c4311Sfengbojiang 
932*572c4311Sfengbojiang     /* Track the biggest values observed so far in this slot. */
933*572c4311Sfengbojiang     if (in_usage > ClientsPeakMemInput[i]) ClientsPeakMemInput[i] = in_usage;
934*572c4311Sfengbojiang     if (out_usage > ClientsPeakMemOutput[i]) ClientsPeakMemOutput[i] = out_usage;
935*572c4311Sfengbojiang 
936*572c4311Sfengbojiang     return 0; /* This function never terminates the client. */
937*572c4311Sfengbojiang }
938*572c4311Sfengbojiang 
939*572c4311Sfengbojiang /* Return the max samples in the memory usage of clients tracked by
940*572c4311Sfengbojiang  * the function clientsCronTrackExpansiveClients(). */
getExpansiveClientsInfo(size_t * in_usage,size_t * out_usage)941*572c4311Sfengbojiang void getExpansiveClientsInfo(size_t *in_usage, size_t *out_usage) {
942*572c4311Sfengbojiang     size_t i = 0, o = 0;
943*572c4311Sfengbojiang     for (int j = 0; j < CLIENTS_PEAK_MEM_USAGE_SLOTS; j++) {
944*572c4311Sfengbojiang         if (ClientsPeakMemInput[j] > i) i = ClientsPeakMemInput[j];
945*572c4311Sfengbojiang         if (ClientsPeakMemOutput[j] > o) o = ClientsPeakMemOutput[j];
946*572c4311Sfengbojiang     }
947*572c4311Sfengbojiang     *in_usage = i;
948*572c4311Sfengbojiang     *out_usage = o;
949*572c4311Sfengbojiang }
950*572c4311Sfengbojiang 
951*572c4311Sfengbojiang /* This function is called by serverCron() and is used in order to perform
952*572c4311Sfengbojiang  * operations on clients that are important to perform constantly. For instance
953*572c4311Sfengbojiang  * we use this function in order to disconnect clients after a timeout, including
954*572c4311Sfengbojiang  * clients blocked in some blocking command with a non-zero timeout.
955*572c4311Sfengbojiang  *
956*572c4311Sfengbojiang  * The function makes some effort to process all the clients every second, even
957*572c4311Sfengbojiang  * if this cannot be strictly guaranteed, since serverCron() may be called with
958*572c4311Sfengbojiang  * an actual frequency lower than server.hz in case of latency events like slow
959*572c4311Sfengbojiang  * commands.
960*572c4311Sfengbojiang  *
961*572c4311Sfengbojiang  * It is very important for this function, and the functions it calls, to be
962*572c4311Sfengbojiang  * very fast: sometimes Redis has tens of hundreds of connected clients, and the
963*572c4311Sfengbojiang  * default server.hz value is 10, so sometimes here we need to process thousands
964*572c4311Sfengbojiang  * of clients per second, turning this function into a source of latency.
965*572c4311Sfengbojiang  */
966*572c4311Sfengbojiang #define CLIENTS_CRON_MIN_ITERATIONS 5
clientsCron(void)967*572c4311Sfengbojiang void clientsCron(void) {
968*572c4311Sfengbojiang     /* Try to process at least numclients/server.hz of clients
969*572c4311Sfengbojiang      * per call. Since normally (if there are no big latency events) this
970*572c4311Sfengbojiang      * function is called server.hz times per second, in the average case we
971*572c4311Sfengbojiang      * process all the clients in 1 second. */
972*572c4311Sfengbojiang     int numclients = listLength(server.clients);
973*572c4311Sfengbojiang     int iterations = numclients/server.hz;
974*572c4311Sfengbojiang     mstime_t now = mstime();
975*572c4311Sfengbojiang 
976*572c4311Sfengbojiang     /* Process at least a few clients while we are at it, even if we need
977*572c4311Sfengbojiang      * to process less than CLIENTS_CRON_MIN_ITERATIONS to meet our contract
978*572c4311Sfengbojiang      * of processing each client once per second. */
979*572c4311Sfengbojiang     if (iterations < CLIENTS_CRON_MIN_ITERATIONS)
980*572c4311Sfengbojiang         iterations = (numclients < CLIENTS_CRON_MIN_ITERATIONS) ?
981*572c4311Sfengbojiang                      numclients : CLIENTS_CRON_MIN_ITERATIONS;
982*572c4311Sfengbojiang 
983*572c4311Sfengbojiang     while(listLength(server.clients) && iterations--) {
984*572c4311Sfengbojiang         client *c;
985*572c4311Sfengbojiang         listNode *head;
986*572c4311Sfengbojiang 
987*572c4311Sfengbojiang         /* Rotate the list, take the current head, process.
988*572c4311Sfengbojiang          * This way if the client must be removed from the list it's the
989*572c4311Sfengbojiang          * first element and we don't incur into O(N) computation. */
990*572c4311Sfengbojiang         listRotate(server.clients);
991*572c4311Sfengbojiang         head = listFirst(server.clients);
992*572c4311Sfengbojiang         c = listNodeValue(head);
993*572c4311Sfengbojiang         /* The following functions do different service checks on the client.
994*572c4311Sfengbojiang          * The protocol is that they return non-zero if the client was
995*572c4311Sfengbojiang          * terminated. */
996*572c4311Sfengbojiang         if (clientsCronHandleTimeout(c,now)) continue;
997*572c4311Sfengbojiang         if (clientsCronResizeQueryBuffer(c)) continue;
998*572c4311Sfengbojiang         if (clientsCronTrackExpansiveClients(c)) continue;
999*572c4311Sfengbojiang     }
1000*572c4311Sfengbojiang }
1001*572c4311Sfengbojiang 
1002*572c4311Sfengbojiang /* This function handles 'background' operations we are required to do
1003*572c4311Sfengbojiang  * incrementally in Redis databases, such as active key expiring, resizing,
1004*572c4311Sfengbojiang  * rehashing. */
databasesCron(void)1005*572c4311Sfengbojiang void databasesCron(void) {
1006*572c4311Sfengbojiang     /* Expire keys by random sampling. Not required for slaves
1007*572c4311Sfengbojiang      * as master will synthesize DELs for us. */
1008*572c4311Sfengbojiang     if (server.active_expire_enabled) {
1009*572c4311Sfengbojiang         if (server.masterhost == NULL) {
1010*572c4311Sfengbojiang             activeExpireCycle(ACTIVE_EXPIRE_CYCLE_SLOW);
1011*572c4311Sfengbojiang         } else {
1012*572c4311Sfengbojiang             expireSlaveKeys();
1013*572c4311Sfengbojiang         }
1014*572c4311Sfengbojiang     }
1015*572c4311Sfengbojiang 
1016*572c4311Sfengbojiang     /* Defrag keys gradually. */
1017*572c4311Sfengbojiang     if (server.active_defrag_enabled)
1018*572c4311Sfengbojiang         activeDefragCycle();
1019*572c4311Sfengbojiang 
1020*572c4311Sfengbojiang     /* Perform hash tables rehashing if needed, but only if there are no
1021*572c4311Sfengbojiang      * other processes saving the DB on disk. Otherwise rehashing is bad
1022*572c4311Sfengbojiang      * as will cause a lot of copy-on-write of memory pages. */
1023*572c4311Sfengbojiang     if (server.rdb_child_pid == -1 && server.aof_child_pid == -1) {
1024*572c4311Sfengbojiang         /* We use global counters so if we stop the computation at a given
1025*572c4311Sfengbojiang          * DB we'll be able to start from the successive in the next
1026*572c4311Sfengbojiang          * cron loop iteration. */
1027*572c4311Sfengbojiang         static unsigned int resize_db = 0;
1028*572c4311Sfengbojiang         static unsigned int rehash_db = 0;
1029*572c4311Sfengbojiang         int dbs_per_call = CRON_DBS_PER_CALL;
1030*572c4311Sfengbojiang         int j;
1031*572c4311Sfengbojiang 
1032*572c4311Sfengbojiang         /* Don't test more DBs than we have. */
1033*572c4311Sfengbojiang         if (dbs_per_call > server.dbnum) dbs_per_call = server.dbnum;
1034*572c4311Sfengbojiang 
1035*572c4311Sfengbojiang         /* Resize */
1036*572c4311Sfengbojiang         for (j = 0; j < dbs_per_call; j++) {
1037*572c4311Sfengbojiang             tryResizeHashTables(resize_db % server.dbnum);
1038*572c4311Sfengbojiang             resize_db++;
1039*572c4311Sfengbojiang         }
1040*572c4311Sfengbojiang 
1041*572c4311Sfengbojiang         /* Rehash */
1042*572c4311Sfengbojiang         if (server.activerehashing) {
1043*572c4311Sfengbojiang             for (j = 0; j < dbs_per_call; j++) {
1044*572c4311Sfengbojiang                 int work_done = incrementallyRehash(rehash_db);
1045*572c4311Sfengbojiang                 if (work_done) {
1046*572c4311Sfengbojiang                     /* If the function did some work, stop here, we'll do
1047*572c4311Sfengbojiang                      * more at the next cron loop. */
1048*572c4311Sfengbojiang                     break;
1049*572c4311Sfengbojiang                 } else {
1050*572c4311Sfengbojiang                     /* If this db didn't need rehash, we'll try the next one. */
1051*572c4311Sfengbojiang                     rehash_db++;
1052*572c4311Sfengbojiang                     rehash_db %= server.dbnum;
1053*572c4311Sfengbojiang                 }
1054*572c4311Sfengbojiang             }
1055*572c4311Sfengbojiang         }
1056*572c4311Sfengbojiang     }
1057*572c4311Sfengbojiang }
1058*572c4311Sfengbojiang 
1059*572c4311Sfengbojiang /* We take a cached value of the unix time in the global state because with
1060*572c4311Sfengbojiang  * virtual memory and aging there is to store the current time in objects at
1061*572c4311Sfengbojiang  * every object access, and accuracy is not needed. To access a global var is
1062*572c4311Sfengbojiang  * a lot faster than calling time(NULL) */
updateCachedTime(void)1063*572c4311Sfengbojiang void updateCachedTime(void) {
1064*572c4311Sfengbojiang     time_t unixtime = time(NULL);
1065*572c4311Sfengbojiang     atomicSet(server.unixtime,unixtime);
1066*572c4311Sfengbojiang     server.mstime = mstime();
1067*572c4311Sfengbojiang 
1068*572c4311Sfengbojiang     /* To get information about daylight saving time, we need to call localtime_r
1069*572c4311Sfengbojiang      * and cache the result. However calling localtime_r in this context is safe
1070*572c4311Sfengbojiang      * since we will never fork() while here, in the main thread. The logging
1071*572c4311Sfengbojiang      * function will call a thread safe version of localtime that has no locks. */
1072*572c4311Sfengbojiang     struct tm tm;
1073*572c4311Sfengbojiang     localtime_r(&server.unixtime,&tm);
1074*572c4311Sfengbojiang     server.daylight_active = tm.tm_isdst;
1075*572c4311Sfengbojiang }
1076*572c4311Sfengbojiang 
1077*572c4311Sfengbojiang /* This is our timer interrupt, called server.hz times per second.
1078*572c4311Sfengbojiang  * Here is where we do a number of things that need to be done asynchronously.
1079*572c4311Sfengbojiang  * For instance:
1080*572c4311Sfengbojiang  *
1081*572c4311Sfengbojiang  * - Active expired keys collection (it is also performed in a lazy way on
1082*572c4311Sfengbojiang  *   lookup).
1083*572c4311Sfengbojiang  * - Software watchdog.
1084*572c4311Sfengbojiang  * - Update some statistic.
1085*572c4311Sfengbojiang  * - Incremental rehashing of the DBs hash tables.
1086*572c4311Sfengbojiang  * - Triggering BGSAVE / AOF rewrite, and handling of terminated children.
1087*572c4311Sfengbojiang  * - Clients timeout of different kinds.
1088*572c4311Sfengbojiang  * - Replication reconnection.
1089*572c4311Sfengbojiang  * - Many more...
1090*572c4311Sfengbojiang  *
1091*572c4311Sfengbojiang  * Everything directly called here will be called server.hz times per second,
1092*572c4311Sfengbojiang  * so in order to throttle execution of things we want to do less frequently
1093*572c4311Sfengbojiang  * a macro is used: run_with_period(milliseconds) { .... }
1094*572c4311Sfengbojiang  */
1095*572c4311Sfengbojiang 
serverCron(struct aeEventLoop * eventLoop,long long id,void * clientData)1096*572c4311Sfengbojiang int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
1097*572c4311Sfengbojiang     int j;
1098*572c4311Sfengbojiang     UNUSED(eventLoop);
1099*572c4311Sfengbojiang     UNUSED(id);
1100*572c4311Sfengbojiang     UNUSED(clientData);
1101*572c4311Sfengbojiang 
1102*572c4311Sfengbojiang     /* Software watchdog: deliver the SIGALRM that will reach the signal
1103*572c4311Sfengbojiang      * handler if we don't return here fast enough. */
1104*572c4311Sfengbojiang     if (server.watchdog_period) watchdogScheduleSignal(server.watchdog_period);
1105*572c4311Sfengbojiang 
1106*572c4311Sfengbojiang     /* Update the time cache. */
1107*572c4311Sfengbojiang     updateCachedTime();
1108*572c4311Sfengbojiang 
1109*572c4311Sfengbojiang     server.hz = server.config_hz;
1110*572c4311Sfengbojiang     /* Adapt the server.hz value to the number of configured clients. If we have
1111*572c4311Sfengbojiang      * many clients, we want to call serverCron() with an higher frequency. */
1112*572c4311Sfengbojiang     if (server.dynamic_hz) {
1113*572c4311Sfengbojiang         while (listLength(server.clients) / server.hz >
1114*572c4311Sfengbojiang                MAX_CLIENTS_PER_CLOCK_TICK)
1115*572c4311Sfengbojiang         {
1116*572c4311Sfengbojiang             server.hz *= 2;
1117*572c4311Sfengbojiang             if (server.hz > CONFIG_MAX_HZ) {
1118*572c4311Sfengbojiang                 server.hz = CONFIG_MAX_HZ;
1119*572c4311Sfengbojiang                 break;
1120*572c4311Sfengbojiang             }
1121*572c4311Sfengbojiang         }
1122*572c4311Sfengbojiang     }
1123*572c4311Sfengbojiang 
1124*572c4311Sfengbojiang     run_with_period(100) {
1125*572c4311Sfengbojiang         trackInstantaneousMetric(STATS_METRIC_COMMAND,server.stat_numcommands);
1126*572c4311Sfengbojiang         trackInstantaneousMetric(STATS_METRIC_NET_INPUT,
1127*572c4311Sfengbojiang                 server.stat_net_input_bytes);
1128*572c4311Sfengbojiang         trackInstantaneousMetric(STATS_METRIC_NET_OUTPUT,
1129*572c4311Sfengbojiang                 server.stat_net_output_bytes);
1130*572c4311Sfengbojiang     }
1131*572c4311Sfengbojiang 
1132*572c4311Sfengbojiang     /* We have just LRU_BITS bits per object for LRU information.
1133*572c4311Sfengbojiang      * So we use an (eventually wrapping) LRU clock.
1134*572c4311Sfengbojiang      *
1135*572c4311Sfengbojiang      * Note that even if the counter wraps it's not a big problem,
1136*572c4311Sfengbojiang      * everything will still work but some object will appear younger
1137*572c4311Sfengbojiang      * to Redis. However for this to happen a given object should never be
1138*572c4311Sfengbojiang      * touched for all the time needed to the counter to wrap, which is
1139*572c4311Sfengbojiang      * not likely.
1140*572c4311Sfengbojiang      *
1141*572c4311Sfengbojiang      * Note that you can change the resolution altering the
1142*572c4311Sfengbojiang      * LRU_CLOCK_RESOLUTION define. */
1143*572c4311Sfengbojiang     unsigned long lruclock = getLRUClock();
1144*572c4311Sfengbojiang     atomicSet(server.lruclock,lruclock);
1145*572c4311Sfengbojiang 
1146*572c4311Sfengbojiang     /* Record the max memory used since the server was started. */
1147*572c4311Sfengbojiang     if (zmalloc_used_memory() > server.stat_peak_memory)
1148*572c4311Sfengbojiang         server.stat_peak_memory = zmalloc_used_memory();
1149*572c4311Sfengbojiang 
1150*572c4311Sfengbojiang     run_with_period(100) {
1151*572c4311Sfengbojiang         /* Sample the RSS and other metrics here since this is a relatively slow call.
1152*572c4311Sfengbojiang          * We must sample the zmalloc_used at the same time we take the rss, otherwise
1153*572c4311Sfengbojiang          * the frag ratio calculate may be off (ratio of two samples at different times) */
1154*572c4311Sfengbojiang         server.cron_malloc_stats.process_rss = zmalloc_get_rss();
1155*572c4311Sfengbojiang         server.cron_malloc_stats.zmalloc_used = zmalloc_used_memory();
1156*572c4311Sfengbojiang         /* Sampling the allcator info can be slow too.
1157*572c4311Sfengbojiang          * The fragmentation ratio it'll show is potentically more accurate
1158*572c4311Sfengbojiang          * it excludes other RSS pages such as: shared libraries, LUA and other non-zmalloc
1159*572c4311Sfengbojiang          * allocations, and allocator reserved pages that can be pursed (all not actual frag) */
1160*572c4311Sfengbojiang         zmalloc_get_allocator_info(&server.cron_malloc_stats.allocator_allocated,
1161*572c4311Sfengbojiang                                    &server.cron_malloc_stats.allocator_active,
1162*572c4311Sfengbojiang                                    &server.cron_malloc_stats.allocator_resident);
1163*572c4311Sfengbojiang         /* in case the allocator isn't providing these stats, fake them so that
1164*572c4311Sfengbojiang          * fragmention info still shows some (inaccurate metrics) */
1165*572c4311Sfengbojiang         if (!server.cron_malloc_stats.allocator_resident) {
1166*572c4311Sfengbojiang             /* LUA memory isn't part of zmalloc_used, but it is part of the process RSS,
1167*572c4311Sfengbojiang              * so we must desuct it in order to be able to calculate correct
1168*572c4311Sfengbojiang              * "allocator fragmentation" ratio */
1169*572c4311Sfengbojiang             size_t lua_memory = lua_gc(server.lua,LUA_GCCOUNT,0)*1024LL;
1170*572c4311Sfengbojiang             server.cron_malloc_stats.allocator_resident = server.cron_malloc_stats.process_rss - lua_memory;
1171*572c4311Sfengbojiang         }
1172*572c4311Sfengbojiang         if (!server.cron_malloc_stats.allocator_active)
1173*572c4311Sfengbojiang             server.cron_malloc_stats.allocator_active = server.cron_malloc_stats.allocator_resident;
1174*572c4311Sfengbojiang         if (!server.cron_malloc_stats.allocator_allocated)
1175*572c4311Sfengbojiang             server.cron_malloc_stats.allocator_allocated = server.cron_malloc_stats.zmalloc_used;
1176*572c4311Sfengbojiang     }
1177*572c4311Sfengbojiang 
1178*572c4311Sfengbojiang     /* We received a SIGTERM, shutting down here in a safe way, as it is
1179*572c4311Sfengbojiang      * not ok doing so inside the signal handler. */
1180*572c4311Sfengbojiang     if (server.shutdown_asap) {
1181*572c4311Sfengbojiang         if (prepareForShutdown(SHUTDOWN_NOFLAGS) == C_OK) exit(0);
1182*572c4311Sfengbojiang         serverLog(LL_WARNING,"SIGTERM received but errors trying to shut down the server, check the logs for more information");
1183*572c4311Sfengbojiang         server.shutdown_asap = 0;
1184*572c4311Sfengbojiang     }
1185*572c4311Sfengbojiang 
1186*572c4311Sfengbojiang     /* Show some info about non-empty databases */
1187*572c4311Sfengbojiang     run_with_period(5000) {
1188*572c4311Sfengbojiang         for (j = 0; j < server.dbnum; j++) {
1189*572c4311Sfengbojiang             long long size, used, vkeys;
1190*572c4311Sfengbojiang 
1191*572c4311Sfengbojiang             size = dictSlots(server.db[j].dict);
1192*572c4311Sfengbojiang             used = dictSize(server.db[j].dict);
1193*572c4311Sfengbojiang             vkeys = dictSize(server.db[j].expires);
1194*572c4311Sfengbojiang             if (used || vkeys) {
1195*572c4311Sfengbojiang                 serverLog(LL_VERBOSE,"DB %d: %lld keys (%lld volatile) in %lld slots HT.",j,used,vkeys,size);
1196*572c4311Sfengbojiang                 /* dictPrintStats(server.dict); */
1197*572c4311Sfengbojiang             }
1198*572c4311Sfengbojiang         }
1199*572c4311Sfengbojiang     }
1200*572c4311Sfengbojiang 
1201*572c4311Sfengbojiang     /* Show information about connected clients */
1202*572c4311Sfengbojiang     if (!server.sentinel_mode) {
1203*572c4311Sfengbojiang         run_with_period(5000) {
1204*572c4311Sfengbojiang             serverLog(LL_VERBOSE,
1205*572c4311Sfengbojiang                 "%lu clients connected (%lu replicas), %zu bytes in use",
1206*572c4311Sfengbojiang                 listLength(server.clients)-listLength(server.slaves),
1207*572c4311Sfengbojiang                 listLength(server.slaves),
1208*572c4311Sfengbojiang                 zmalloc_used_memory());
1209*572c4311Sfengbojiang         }
1210*572c4311Sfengbojiang     }
1211*572c4311Sfengbojiang 
1212*572c4311Sfengbojiang     /* We need to do a few operations on clients asynchronously. */
1213*572c4311Sfengbojiang     clientsCron();
1214*572c4311Sfengbojiang 
1215*572c4311Sfengbojiang     /* Handle background operations on Redis databases. */
1216*572c4311Sfengbojiang     databasesCron();
1217*572c4311Sfengbojiang 
1218*572c4311Sfengbojiang     /* Start a scheduled AOF rewrite if this was requested by the user while
1219*572c4311Sfengbojiang      * a BGSAVE was in progress. */
1220*572c4311Sfengbojiang     if (server.rdb_child_pid == -1 && server.aof_child_pid == -1 &&
1221*572c4311Sfengbojiang         server.aof_rewrite_scheduled)
1222*572c4311Sfengbojiang     {
1223*572c4311Sfengbojiang         rewriteAppendOnlyFileBackground();
1224*572c4311Sfengbojiang     }
1225*572c4311Sfengbojiang 
1226*572c4311Sfengbojiang     /* Check if a background saving or AOF rewrite in progress terminated. */
1227*572c4311Sfengbojiang     if (server.rdb_child_pid != -1 || server.aof_child_pid != -1 ||
1228*572c4311Sfengbojiang         ldbPendingChildren())
1229*572c4311Sfengbojiang     {
1230*572c4311Sfengbojiang         int statloc;
1231*572c4311Sfengbojiang         pid_t pid;
1232*572c4311Sfengbojiang 
1233*572c4311Sfengbojiang         if ((pid = wait3(&statloc,WNOHANG,NULL)) != 0) {
1234*572c4311Sfengbojiang             int exitcode = WEXITSTATUS(statloc);
1235*572c4311Sfengbojiang             int bysignal = 0;
1236*572c4311Sfengbojiang 
1237*572c4311Sfengbojiang             if (WIFSIGNALED(statloc)) bysignal = WTERMSIG(statloc);
1238*572c4311Sfengbojiang 
1239*572c4311Sfengbojiang             if (pid == -1) {
1240*572c4311Sfengbojiang                 serverLog(LL_WARNING,"wait3() returned an error: %s. "
1241*572c4311Sfengbojiang                     "rdb_child_pid = %d, aof_child_pid = %d",
1242*572c4311Sfengbojiang                     strerror(errno),
1243*572c4311Sfengbojiang                     (int) server.rdb_child_pid,
1244*572c4311Sfengbojiang                     (int) server.aof_child_pid);
1245*572c4311Sfengbojiang             } else if (pid == server.rdb_child_pid) {
1246*572c4311Sfengbojiang                 backgroundSaveDoneHandler(exitcode,bysignal);
1247*572c4311Sfengbojiang                 if (!bysignal && exitcode == 0) receiveChildInfo();
1248*572c4311Sfengbojiang             } else if (pid == server.aof_child_pid) {
1249*572c4311Sfengbojiang                 backgroundRewriteDoneHandler(exitcode,bysignal);
1250*572c4311Sfengbojiang                 if (!bysignal && exitcode == 0) receiveChildInfo();
1251*572c4311Sfengbojiang             } else {
1252*572c4311Sfengbojiang                 if (!ldbRemoveChild(pid)) {
1253*572c4311Sfengbojiang                     serverLog(LL_WARNING,
1254*572c4311Sfengbojiang                         "Warning, detected child with unmatched pid: %ld",
1255*572c4311Sfengbojiang                         (long)pid);
1256*572c4311Sfengbojiang                 }
1257*572c4311Sfengbojiang             }
1258*572c4311Sfengbojiang             updateDictResizePolicy();
1259*572c4311Sfengbojiang             closeChildInfoPipe();
1260*572c4311Sfengbojiang         }
1261*572c4311Sfengbojiang     } else {
1262*572c4311Sfengbojiang         /* If there is not a background saving/rewrite in progress check if
1263*572c4311Sfengbojiang          * we have to save/rewrite now. */
1264*572c4311Sfengbojiang         for (j = 0; j < server.saveparamslen; j++) {
1265*572c4311Sfengbojiang             struct saveparam *sp = server.saveparams+j;
1266*572c4311Sfengbojiang 
1267*572c4311Sfengbojiang             /* Save if we reached the given amount of changes,
1268*572c4311Sfengbojiang              * the given amount of seconds, and if the latest bgsave was
1269*572c4311Sfengbojiang              * successful or if, in case of an error, at least
1270*572c4311Sfengbojiang              * CONFIG_BGSAVE_RETRY_DELAY seconds already elapsed. */
1271*572c4311Sfengbojiang             if (server.dirty >= sp->changes &&
1272*572c4311Sfengbojiang                 server.unixtime-server.lastsave > sp->seconds &&
1273*572c4311Sfengbojiang                 (server.unixtime-server.lastbgsave_try >
1274*572c4311Sfengbojiang                  CONFIG_BGSAVE_RETRY_DELAY ||
1275*572c4311Sfengbojiang                  server.lastbgsave_status == C_OK))
1276*572c4311Sfengbojiang             {
1277*572c4311Sfengbojiang                 serverLog(LL_NOTICE,"%d changes in %d seconds. Saving...",
1278*572c4311Sfengbojiang                     sp->changes, (int)sp->seconds);
1279*572c4311Sfengbojiang                 rdbSaveInfo rsi, *rsiptr;
1280*572c4311Sfengbojiang                 rsiptr = rdbPopulateSaveInfo(&rsi);
1281*572c4311Sfengbojiang                 rdbSaveBackground(server.rdb_filename,rsiptr);
1282*572c4311Sfengbojiang                 break;
1283*572c4311Sfengbojiang             }
1284*572c4311Sfengbojiang         }
1285*572c4311Sfengbojiang 
1286*572c4311Sfengbojiang         /* Trigger an AOF rewrite if needed. */
1287*572c4311Sfengbojiang         if (server.aof_state == AOF_ON &&
1288*572c4311Sfengbojiang             server.rdb_child_pid == -1 &&
1289*572c4311Sfengbojiang             server.aof_child_pid == -1 &&
1290*572c4311Sfengbojiang             server.aof_rewrite_perc &&
1291*572c4311Sfengbojiang             server.aof_current_size > server.aof_rewrite_min_size)
1292*572c4311Sfengbojiang         {
1293*572c4311Sfengbojiang             long long base = server.aof_rewrite_base_size ?
1294*572c4311Sfengbojiang                 server.aof_rewrite_base_size : 1;
1295*572c4311Sfengbojiang             long long growth = (server.aof_current_size*100/base) - 100;
1296*572c4311Sfengbojiang             if (growth >= server.aof_rewrite_perc) {
1297*572c4311Sfengbojiang                 serverLog(LL_NOTICE,"Starting automatic rewriting of AOF on %lld%% growth",growth);
1298*572c4311Sfengbojiang                 rewriteAppendOnlyFileBackground();
1299*572c4311Sfengbojiang             }
1300*572c4311Sfengbojiang         }
1301*572c4311Sfengbojiang     }
1302*572c4311Sfengbojiang 
1303*572c4311Sfengbojiang 
1304*572c4311Sfengbojiang     /* AOF postponed flush: Try at every cron cycle if the slow fsync
1305*572c4311Sfengbojiang      * completed. */
1306*572c4311Sfengbojiang     if (server.aof_flush_postponed_start) flushAppendOnlyFile(0);
1307*572c4311Sfengbojiang 
1308*572c4311Sfengbojiang     /* AOF write errors: in this case we have a buffer to flush as well and
1309*572c4311Sfengbojiang      * clear the AOF error in case of success to make the DB writable again,
1310*572c4311Sfengbojiang      * however to try every second is enough in case of 'hz' is set to
1311*572c4311Sfengbojiang      * an higher frequency. */
1312*572c4311Sfengbojiang     run_with_period(1000) {
1313*572c4311Sfengbojiang         if (server.aof_last_write_status == C_ERR)
1314*572c4311Sfengbojiang             flushAppendOnlyFile(0);
1315*572c4311Sfengbojiang     }
1316*572c4311Sfengbojiang 
1317*572c4311Sfengbojiang     /* Close clients that need to be closed asynchronous */
1318*572c4311Sfengbojiang     freeClientsInAsyncFreeQueue();
1319*572c4311Sfengbojiang 
1320*572c4311Sfengbojiang     /* Clear the paused clients flag if needed. */
1321*572c4311Sfengbojiang     clientsArePaused(); /* Don't check return value, just use the side effect.*/
1322*572c4311Sfengbojiang 
1323*572c4311Sfengbojiang     /* Replication cron function -- used to reconnect to master,
1324*572c4311Sfengbojiang      * detect transfer failures, start background RDB transfers and so forth. */
1325*572c4311Sfengbojiang     run_with_period(1000) replicationCron();
1326*572c4311Sfengbojiang 
1327*572c4311Sfengbojiang     /* Run the Redis Cluster cron. */
1328*572c4311Sfengbojiang     run_with_period(100) {
1329*572c4311Sfengbojiang         if (server.cluster_enabled) clusterCron();
1330*572c4311Sfengbojiang     }
1331*572c4311Sfengbojiang 
1332*572c4311Sfengbojiang     /* Run the Sentinel timer if we are in sentinel mode. */
1333*572c4311Sfengbojiang     if (server.sentinel_mode) sentinelTimer();
1334*572c4311Sfengbojiang 
1335*572c4311Sfengbojiang     /* Cleanup expired MIGRATE cached sockets. */
1336*572c4311Sfengbojiang     run_with_period(1000) {
1337*572c4311Sfengbojiang         migrateCloseTimedoutSockets();
1338*572c4311Sfengbojiang     }
1339*572c4311Sfengbojiang 
1340*572c4311Sfengbojiang     /* Start a scheduled BGSAVE if the corresponding flag is set. This is
1341*572c4311Sfengbojiang      * useful when we are forced to postpone a BGSAVE because an AOF
1342*572c4311Sfengbojiang      * rewrite is in progress.
1343*572c4311Sfengbojiang      *
1344*572c4311Sfengbojiang      * Note: this code must be after the replicationCron() call above so
1345*572c4311Sfengbojiang      * make sure when refactoring this file to keep this order. This is useful
1346*572c4311Sfengbojiang      * because we want to give priority to RDB savings for replication. */
1347*572c4311Sfengbojiang     if (server.rdb_child_pid == -1 && server.aof_child_pid == -1 &&
1348*572c4311Sfengbojiang         server.rdb_bgsave_scheduled &&
1349*572c4311Sfengbojiang         (server.unixtime-server.lastbgsave_try > CONFIG_BGSAVE_RETRY_DELAY ||
1350*572c4311Sfengbojiang          server.lastbgsave_status == C_OK))
1351*572c4311Sfengbojiang     {
1352*572c4311Sfengbojiang         rdbSaveInfo rsi, *rsiptr;
1353*572c4311Sfengbojiang         rsiptr = rdbPopulateSaveInfo(&rsi);
1354*572c4311Sfengbojiang         if (rdbSaveBackground(server.rdb_filename,rsiptr) == C_OK)
1355*572c4311Sfengbojiang             server.rdb_bgsave_scheduled = 0;
1356*572c4311Sfengbojiang     }
1357*572c4311Sfengbojiang 
1358*572c4311Sfengbojiang     server.cronloops++;
1359*572c4311Sfengbojiang     return 1000/server.hz;
1360*572c4311Sfengbojiang }
1361*572c4311Sfengbojiang 
1362*572c4311Sfengbojiang /* This function gets called every time Redis is entering the
1363*572c4311Sfengbojiang  * main loop of the event driven library, that is, before to sleep
1364*572c4311Sfengbojiang  * for ready file descriptors. */
beforeSleep(struct aeEventLoop * eventLoop)1365*572c4311Sfengbojiang void beforeSleep(struct aeEventLoop *eventLoop) {
1366*572c4311Sfengbojiang     UNUSED(eventLoop);
1367*572c4311Sfengbojiang 
1368*572c4311Sfengbojiang     /* Call the Redis Cluster before sleep function. Note that this function
1369*572c4311Sfengbojiang      * may change the state of Redis Cluster (from ok to fail or vice versa),
1370*572c4311Sfengbojiang      * so it's a good idea to call it before serving the unblocked clients
1371*572c4311Sfengbojiang      * later in this function. */
1372*572c4311Sfengbojiang     if (server.cluster_enabled) clusterBeforeSleep();
1373*572c4311Sfengbojiang 
1374*572c4311Sfengbojiang     /* Run a fast expire cycle (the called function will return
1375*572c4311Sfengbojiang      * ASAP if a fast cycle is not needed). */
1376*572c4311Sfengbojiang     if (server.active_expire_enabled && server.masterhost == NULL)
1377*572c4311Sfengbojiang         activeExpireCycle(ACTIVE_EXPIRE_CYCLE_FAST);
1378*572c4311Sfengbojiang 
1379*572c4311Sfengbojiang     /* Send all the slaves an ACK request if at least one client blocked
1380*572c4311Sfengbojiang      * during the previous event loop iteration. */
1381*572c4311Sfengbojiang     if (server.get_ack_from_slaves) {
1382*572c4311Sfengbojiang         robj *argv[3];
1383*572c4311Sfengbojiang 
1384*572c4311Sfengbojiang         argv[0] = createStringObject("REPLCONF",8);
1385*572c4311Sfengbojiang         argv[1] = createStringObject("GETACK",6);
1386*572c4311Sfengbojiang         argv[2] = createStringObject("*",1); /* Not used argument. */
1387*572c4311Sfengbojiang         replicationFeedSlaves(server.slaves, server.slaveseldb, argv, 3);
1388*572c4311Sfengbojiang         decrRefCount(argv[0]);
1389*572c4311Sfengbojiang         decrRefCount(argv[1]);
1390*572c4311Sfengbojiang         decrRefCount(argv[2]);
1391*572c4311Sfengbojiang         server.get_ack_from_slaves = 0;
1392*572c4311Sfengbojiang     }
1393*572c4311Sfengbojiang 
1394*572c4311Sfengbojiang     /* Unblock all the clients blocked for synchronous replication
1395*572c4311Sfengbojiang      * in WAIT. */
1396*572c4311Sfengbojiang     if (listLength(server.clients_waiting_acks))
1397*572c4311Sfengbojiang         processClientsWaitingReplicas();
1398*572c4311Sfengbojiang 
1399*572c4311Sfengbojiang     /* Check if there are clients unblocked by modules that implement
1400*572c4311Sfengbojiang      * blocking commands. */
1401*572c4311Sfengbojiang     moduleHandleBlockedClients();
1402*572c4311Sfengbojiang 
1403*572c4311Sfengbojiang     /* Try to process pending commands for clients that were just unblocked. */
1404*572c4311Sfengbojiang     if (listLength(server.unblocked_clients))
1405*572c4311Sfengbojiang         processUnblockedClients();
1406*572c4311Sfengbojiang 
1407*572c4311Sfengbojiang     /* Write the AOF buffer on disk */
1408*572c4311Sfengbojiang     flushAppendOnlyFile(0);
1409*572c4311Sfengbojiang 
1410*572c4311Sfengbojiang     /* Handle writes with pending output buffers. */
1411*572c4311Sfengbojiang     handleClientsWithPendingWrites();
1412*572c4311Sfengbojiang 
1413*572c4311Sfengbojiang     /* Before we are going to sleep, let the threads access the dataset by
1414*572c4311Sfengbojiang      * releasing the GIL. Redis main thread will not touch anything at this
1415*572c4311Sfengbojiang      * time. */
1416*572c4311Sfengbojiang     if (moduleCount()) moduleReleaseGIL();
1417*572c4311Sfengbojiang }
1418*572c4311Sfengbojiang 
1419*572c4311Sfengbojiang /* This function is called immadiately after the event loop multiplexing
1420*572c4311Sfengbojiang  * API returned, and the control is going to soon return to Redis by invoking
1421*572c4311Sfengbojiang  * the different events callbacks. */
afterSleep(struct aeEventLoop * eventLoop)1422*572c4311Sfengbojiang void afterSleep(struct aeEventLoop *eventLoop) {
1423*572c4311Sfengbojiang     UNUSED(eventLoop);
1424*572c4311Sfengbojiang     if (moduleCount()) moduleAcquireGIL();
1425*572c4311Sfengbojiang }
1426*572c4311Sfengbojiang 
1427*572c4311Sfengbojiang /* =========================== Server initialization ======================== */
1428*572c4311Sfengbojiang 
createSharedObjects(void)1429*572c4311Sfengbojiang void createSharedObjects(void) {
1430*572c4311Sfengbojiang     int j;
1431*572c4311Sfengbojiang 
1432*572c4311Sfengbojiang     shared.crlf = createObject(OBJ_STRING,sdsnew("\r\n"));
1433*572c4311Sfengbojiang     shared.ok = createObject(OBJ_STRING,sdsnew("+OK\r\n"));
1434*572c4311Sfengbojiang     shared.err = createObject(OBJ_STRING,sdsnew("-ERR\r\n"));
1435*572c4311Sfengbojiang     shared.emptybulk = createObject(OBJ_STRING,sdsnew("$0\r\n\r\n"));
1436*572c4311Sfengbojiang     shared.czero = createObject(OBJ_STRING,sdsnew(":0\r\n"));
1437*572c4311Sfengbojiang     shared.cone = createObject(OBJ_STRING,sdsnew(":1\r\n"));
1438*572c4311Sfengbojiang     shared.cnegone = createObject(OBJ_STRING,sdsnew(":-1\r\n"));
1439*572c4311Sfengbojiang     shared.nullbulk = createObject(OBJ_STRING,sdsnew("$-1\r\n"));
1440*572c4311Sfengbojiang     shared.nullmultibulk = createObject(OBJ_STRING,sdsnew("*-1\r\n"));
1441*572c4311Sfengbojiang     shared.emptymultibulk = createObject(OBJ_STRING,sdsnew("*0\r\n"));
1442*572c4311Sfengbojiang     shared.pong = createObject(OBJ_STRING,sdsnew("+PONG\r\n"));
1443*572c4311Sfengbojiang     shared.queued = createObject(OBJ_STRING,sdsnew("+QUEUED\r\n"));
1444*572c4311Sfengbojiang     shared.emptyscan = createObject(OBJ_STRING,sdsnew("*2\r\n$1\r\n0\r\n*0\r\n"));
1445*572c4311Sfengbojiang     shared.wrongtypeerr = createObject(OBJ_STRING,sdsnew(
1446*572c4311Sfengbojiang         "-WRONGTYPE Operation against a key holding the wrong kind of value\r\n"));
1447*572c4311Sfengbojiang     shared.nokeyerr = createObject(OBJ_STRING,sdsnew(
1448*572c4311Sfengbojiang         "-ERR no such key\r\n"));
1449*572c4311Sfengbojiang     shared.syntaxerr = createObject(OBJ_STRING,sdsnew(
1450*572c4311Sfengbojiang         "-ERR syntax error\r\n"));
1451*572c4311Sfengbojiang     shared.sameobjecterr = createObject(OBJ_STRING,sdsnew(
1452*572c4311Sfengbojiang         "-ERR source and destination objects are the same\r\n"));
1453*572c4311Sfengbojiang     shared.outofrangeerr = createObject(OBJ_STRING,sdsnew(
1454*572c4311Sfengbojiang         "-ERR index out of range\r\n"));
1455*572c4311Sfengbojiang     shared.noscripterr = createObject(OBJ_STRING,sdsnew(
1456*572c4311Sfengbojiang         "-NOSCRIPT No matching script. Please use EVAL.\r\n"));
1457*572c4311Sfengbojiang     shared.loadingerr = createObject(OBJ_STRING,sdsnew(
1458*572c4311Sfengbojiang         "-LOADING Redis is loading the dataset in memory\r\n"));
1459*572c4311Sfengbojiang     shared.slowscripterr = createObject(OBJ_STRING,sdsnew(
1460*572c4311Sfengbojiang         "-BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.\r\n"));
1461*572c4311Sfengbojiang     shared.masterdownerr = createObject(OBJ_STRING,sdsnew(
1462*572c4311Sfengbojiang         "-MASTERDOWN Link with MASTER is down and replica-serve-stale-data is set to 'no'.\r\n"));
1463*572c4311Sfengbojiang     shared.bgsaveerr = createObject(OBJ_STRING,sdsnew(
1464*572c4311Sfengbojiang         "-MISCONF Redis is configured to save RDB snapshots, but it is currently not able to persist on disk. Commands that may modify the data set are disabled, because this instance is configured to report errors during writes if RDB snapshotting fails (stop-writes-on-bgsave-error option). Please check the Redis logs for details about the RDB error.\r\n"));
1465*572c4311Sfengbojiang     shared.roslaveerr = createObject(OBJ_STRING,sdsnew(
1466*572c4311Sfengbojiang         "-READONLY You can't write against a read only replica.\r\n"));
1467*572c4311Sfengbojiang     shared.noautherr = createObject(OBJ_STRING,sdsnew(
1468*572c4311Sfengbojiang         "-NOAUTH Authentication required.\r\n"));
1469*572c4311Sfengbojiang     shared.oomerr = createObject(OBJ_STRING,sdsnew(
1470*572c4311Sfengbojiang         "-OOM command not allowed when used memory > 'maxmemory'.\r\n"));
1471*572c4311Sfengbojiang     shared.execaborterr = createObject(OBJ_STRING,sdsnew(
1472*572c4311Sfengbojiang         "-EXECABORT Transaction discarded because of previous errors.\r\n"));
1473*572c4311Sfengbojiang     shared.noreplicaserr = createObject(OBJ_STRING,sdsnew(
1474*572c4311Sfengbojiang         "-NOREPLICAS Not enough good replicas to write.\r\n"));
1475*572c4311Sfengbojiang     shared.busykeyerr = createObject(OBJ_STRING,sdsnew(
1476*572c4311Sfengbojiang         "-BUSYKEY Target key name already exists.\r\n"));
1477*572c4311Sfengbojiang     shared.space = createObject(OBJ_STRING,sdsnew(" "));
1478*572c4311Sfengbojiang     shared.colon = createObject(OBJ_STRING,sdsnew(":"));
1479*572c4311Sfengbojiang     shared.plus = createObject(OBJ_STRING,sdsnew("+"));
1480*572c4311Sfengbojiang 
1481*572c4311Sfengbojiang     for (j = 0; j < PROTO_SHARED_SELECT_CMDS; j++) {
1482*572c4311Sfengbojiang         char dictid_str[64];
1483*572c4311Sfengbojiang         int dictid_len;
1484*572c4311Sfengbojiang 
1485*572c4311Sfengbojiang         dictid_len = ll2string(dictid_str,sizeof(dictid_str),j);
1486*572c4311Sfengbojiang         shared.select[j] = createObject(OBJ_STRING,
1487*572c4311Sfengbojiang             sdscatprintf(sdsempty(),
1488*572c4311Sfengbojiang                 "*2\r\n$6\r\nSELECT\r\n$%d\r\n%s\r\n",
1489*572c4311Sfengbojiang                 dictid_len, dictid_str));
1490*572c4311Sfengbojiang     }
1491*572c4311Sfengbojiang     shared.messagebulk = createStringObject("$7\r\nmessage\r\n",13);
1492*572c4311Sfengbojiang     shared.pmessagebulk = createStringObject("$8\r\npmessage\r\n",14);
1493*572c4311Sfengbojiang     shared.subscribebulk = createStringObject("$9\r\nsubscribe\r\n",15);
1494*572c4311Sfengbojiang     shared.unsubscribebulk = createStringObject("$11\r\nunsubscribe\r\n",18);
1495*572c4311Sfengbojiang     shared.psubscribebulk = createStringObject("$10\r\npsubscribe\r\n",17);
1496*572c4311Sfengbojiang     shared.punsubscribebulk = createStringObject("$12\r\npunsubscribe\r\n",19);
1497*572c4311Sfengbojiang     shared.del = createStringObject("DEL",3);
1498*572c4311Sfengbojiang     shared.unlink = createStringObject("UNLINK",6);
1499*572c4311Sfengbojiang     shared.rpop = createStringObject("RPOP",4);
1500*572c4311Sfengbojiang     shared.lpop = createStringObject("LPOP",4);
1501*572c4311Sfengbojiang     shared.lpush = createStringObject("LPUSH",5);
1502*572c4311Sfengbojiang     shared.rpoplpush = createStringObject("RPOPLPUSH",9);
1503*572c4311Sfengbojiang     shared.zpopmin = createStringObject("ZPOPMIN",7);
1504*572c4311Sfengbojiang     shared.zpopmax = createStringObject("ZPOPMAX",7);
1505*572c4311Sfengbojiang     for (j = 0; j < OBJ_SHARED_INTEGERS; j++) {
1506*572c4311Sfengbojiang         shared.integers[j] =
1507*572c4311Sfengbojiang             makeObjectShared(createObject(OBJ_STRING,(void*)(long)j));
1508*572c4311Sfengbojiang         shared.integers[j]->encoding = OBJ_ENCODING_INT;
1509*572c4311Sfengbojiang     }
1510*572c4311Sfengbojiang     for (j = 0; j < OBJ_SHARED_BULKHDR_LEN; j++) {
1511*572c4311Sfengbojiang         shared.mbulkhdr[j] = createObject(OBJ_STRING,
1512*572c4311Sfengbojiang             sdscatprintf(sdsempty(),"*%d\r\n",j));
1513*572c4311Sfengbojiang         shared.bulkhdr[j] = createObject(OBJ_STRING,
1514*572c4311Sfengbojiang             sdscatprintf(sdsempty(),"$%d\r\n",j));
1515*572c4311Sfengbojiang     }
1516*572c4311Sfengbojiang     /* The following two shared objects, minstring and maxstrings, are not
1517*572c4311Sfengbojiang      * actually used for their value but as a special object meaning
1518*572c4311Sfengbojiang      * respectively the minimum possible string and the maximum possible
1519*572c4311Sfengbojiang      * string in string comparisons for the ZRANGEBYLEX command. */
1520*572c4311Sfengbojiang     shared.minstring = sdsnew("minstring");
1521*572c4311Sfengbojiang     shared.maxstring = sdsnew("maxstring");
1522*572c4311Sfengbojiang }
1523*572c4311Sfengbojiang 
initServerConfig(void)1524*572c4311Sfengbojiang void initServerConfig(void) {
1525*572c4311Sfengbojiang     int j;
1526*572c4311Sfengbojiang 
1527*572c4311Sfengbojiang     pthread_mutex_init(&server.next_client_id_mutex,NULL);
1528*572c4311Sfengbojiang     pthread_mutex_init(&server.lruclock_mutex,NULL);
1529*572c4311Sfengbojiang     pthread_mutex_init(&server.unixtime_mutex,NULL);
1530*572c4311Sfengbojiang 
1531*572c4311Sfengbojiang     updateCachedTime();
1532*572c4311Sfengbojiang     getRandomHexChars(server.runid,CONFIG_RUN_ID_SIZE);
1533*572c4311Sfengbojiang     server.runid[CONFIG_RUN_ID_SIZE] = '\0';
1534*572c4311Sfengbojiang     changeReplicationId();
1535*572c4311Sfengbojiang     clearReplicationId2();
1536*572c4311Sfengbojiang     server.timezone = getTimeZone(); /* Initialized by tzset(). */
1537*572c4311Sfengbojiang     server.configfile = NULL;
1538*572c4311Sfengbojiang     server.executable = NULL;
1539*572c4311Sfengbojiang     server.hz = server.config_hz = CONFIG_DEFAULT_HZ;
1540*572c4311Sfengbojiang     server.dynamic_hz = CONFIG_DEFAULT_DYNAMIC_HZ;
1541*572c4311Sfengbojiang     server.arch_bits = (sizeof(long) == 8) ? 64 : 32;
1542*572c4311Sfengbojiang     server.port = CONFIG_DEFAULT_SERVER_PORT;
1543*572c4311Sfengbojiang     server.tcp_backlog = CONFIG_DEFAULT_TCP_BACKLOG;
1544*572c4311Sfengbojiang     server.bindaddr_count = 0;
1545*572c4311Sfengbojiang     server.unixsocket = NULL;
1546*572c4311Sfengbojiang     server.unixsocketperm = CONFIG_DEFAULT_UNIX_SOCKET_PERM;
1547*572c4311Sfengbojiang     server.ipfd_count = 0;
1548*572c4311Sfengbojiang     server.sofd = -1;
1549*572c4311Sfengbojiang     server.protected_mode = CONFIG_DEFAULT_PROTECTED_MODE;
1550*572c4311Sfengbojiang     server.dbnum = CONFIG_DEFAULT_DBNUM;
1551*572c4311Sfengbojiang     server.verbosity = CONFIG_DEFAULT_VERBOSITY;
1552*572c4311Sfengbojiang     server.maxidletime = CONFIG_DEFAULT_CLIENT_TIMEOUT;
1553*572c4311Sfengbojiang     server.tcpkeepalive = CONFIG_DEFAULT_TCP_KEEPALIVE;
1554*572c4311Sfengbojiang     server.active_expire_enabled = 1;
1555*572c4311Sfengbojiang     server.active_defrag_enabled = CONFIG_DEFAULT_ACTIVE_DEFRAG;
1556*572c4311Sfengbojiang     server.active_defrag_ignore_bytes = CONFIG_DEFAULT_DEFRAG_IGNORE_BYTES;
1557*572c4311Sfengbojiang     server.active_defrag_threshold_lower = CONFIG_DEFAULT_DEFRAG_THRESHOLD_LOWER;
1558*572c4311Sfengbojiang     server.active_defrag_threshold_upper = CONFIG_DEFAULT_DEFRAG_THRESHOLD_UPPER;
1559*572c4311Sfengbojiang     server.active_defrag_cycle_min = CONFIG_DEFAULT_DEFRAG_CYCLE_MIN;
1560*572c4311Sfengbojiang     server.active_defrag_cycle_max = CONFIG_DEFAULT_DEFRAG_CYCLE_MAX;
1561*572c4311Sfengbojiang     server.active_defrag_max_scan_fields = CONFIG_DEFAULT_DEFRAG_MAX_SCAN_FIELDS;
1562*572c4311Sfengbojiang     server.proto_max_bulk_len = CONFIG_DEFAULT_PROTO_MAX_BULK_LEN;
1563*572c4311Sfengbojiang     server.client_max_querybuf_len = PROTO_MAX_QUERYBUF_LEN;
1564*572c4311Sfengbojiang     server.saveparams = NULL;
1565*572c4311Sfengbojiang     server.loading = 0;
1566*572c4311Sfengbojiang     server.logfile = zstrdup(CONFIG_DEFAULT_LOGFILE);
1567*572c4311Sfengbojiang     server.syslog_enabled = CONFIG_DEFAULT_SYSLOG_ENABLED;
1568*572c4311Sfengbojiang     server.syslog_ident = zstrdup(CONFIG_DEFAULT_SYSLOG_IDENT);
1569*572c4311Sfengbojiang     server.syslog_facility = LOG_LOCAL0;
1570*572c4311Sfengbojiang     server.daemonize = CONFIG_DEFAULT_DAEMONIZE;
1571*572c4311Sfengbojiang     server.supervised = 0;
1572*572c4311Sfengbojiang     server.supervised_mode = SUPERVISED_NONE;
1573*572c4311Sfengbojiang     server.aof_state = AOF_OFF;
1574*572c4311Sfengbojiang     server.aof_fsync = CONFIG_DEFAULT_AOF_FSYNC;
1575*572c4311Sfengbojiang     server.aof_no_fsync_on_rewrite = CONFIG_DEFAULT_AOF_NO_FSYNC_ON_REWRITE;
1576*572c4311Sfengbojiang     server.aof_rewrite_perc = AOF_REWRITE_PERC;
1577*572c4311Sfengbojiang     server.aof_rewrite_min_size = AOF_REWRITE_MIN_SIZE;
1578*572c4311Sfengbojiang     server.aof_rewrite_base_size = 0;
1579*572c4311Sfengbojiang     server.aof_rewrite_scheduled = 0;
1580*572c4311Sfengbojiang     server.aof_last_fsync = time(NULL);
1581*572c4311Sfengbojiang     server.aof_rewrite_time_last = -1;
1582*572c4311Sfengbojiang     server.aof_rewrite_time_start = -1;
1583*572c4311Sfengbojiang     server.aof_lastbgrewrite_status = C_OK;
1584*572c4311Sfengbojiang     server.aof_delayed_fsync = 0;
1585*572c4311Sfengbojiang     server.aof_fd = -1;
1586*572c4311Sfengbojiang     server.aof_selected_db = -1; /* Make sure the first time will not match */
1587*572c4311Sfengbojiang     server.aof_flush_postponed_start = 0;
1588*572c4311Sfengbojiang     server.aof_rewrite_incremental_fsync = CONFIG_DEFAULT_AOF_REWRITE_INCREMENTAL_FSYNC;
1589*572c4311Sfengbojiang     server.rdb_save_incremental_fsync = CONFIG_DEFAULT_RDB_SAVE_INCREMENTAL_FSYNC;
1590*572c4311Sfengbojiang     server.aof_load_truncated = CONFIG_DEFAULT_AOF_LOAD_TRUNCATED;
1591*572c4311Sfengbojiang     server.aof_use_rdb_preamble = CONFIG_DEFAULT_AOF_USE_RDB_PREAMBLE;
1592*572c4311Sfengbojiang     server.pidfile = NULL;
1593*572c4311Sfengbojiang     server.rdb_filename = zstrdup(CONFIG_DEFAULT_RDB_FILENAME);
1594*572c4311Sfengbojiang     server.aof_filename = zstrdup(CONFIG_DEFAULT_AOF_FILENAME);
1595*572c4311Sfengbojiang     server.requirepass = NULL;
1596*572c4311Sfengbojiang     server.rdb_compression = CONFIG_DEFAULT_RDB_COMPRESSION;
1597*572c4311Sfengbojiang     server.rdb_checksum = CONFIG_DEFAULT_RDB_CHECKSUM;
1598*572c4311Sfengbojiang     server.stop_writes_on_bgsave_err = CONFIG_DEFAULT_STOP_WRITES_ON_BGSAVE_ERROR;
1599*572c4311Sfengbojiang     server.activerehashing = CONFIG_DEFAULT_ACTIVE_REHASHING;
1600*572c4311Sfengbojiang     server.active_defrag_running = 0;
1601*572c4311Sfengbojiang     server.notify_keyspace_events = 0;
1602*572c4311Sfengbojiang     server.maxclients = CONFIG_DEFAULT_MAX_CLIENTS;
1603*572c4311Sfengbojiang     server.blocked_clients = 0;
1604*572c4311Sfengbojiang     memset(server.blocked_clients_by_type,0,
1605*572c4311Sfengbojiang            sizeof(server.blocked_clients_by_type));
1606*572c4311Sfengbojiang     server.maxmemory = CONFIG_DEFAULT_MAXMEMORY;
1607*572c4311Sfengbojiang     server.maxmemory_policy = CONFIG_DEFAULT_MAXMEMORY_POLICY;
1608*572c4311Sfengbojiang     server.maxmemory_samples = CONFIG_DEFAULT_MAXMEMORY_SAMPLES;
1609*572c4311Sfengbojiang     server.lfu_log_factor = CONFIG_DEFAULT_LFU_LOG_FACTOR;
1610*572c4311Sfengbojiang     server.lfu_decay_time = CONFIG_DEFAULT_LFU_DECAY_TIME;
1611*572c4311Sfengbojiang     server.hash_max_ziplist_entries = OBJ_HASH_MAX_ZIPLIST_ENTRIES;
1612*572c4311Sfengbojiang     server.hash_max_ziplist_value = OBJ_HASH_MAX_ZIPLIST_VALUE;
1613*572c4311Sfengbojiang     server.list_max_ziplist_size = OBJ_LIST_MAX_ZIPLIST_SIZE;
1614*572c4311Sfengbojiang     server.list_compress_depth = OBJ_LIST_COMPRESS_DEPTH;
1615*572c4311Sfengbojiang     server.set_max_intset_entries = OBJ_SET_MAX_INTSET_ENTRIES;
1616*572c4311Sfengbojiang     server.zset_max_ziplist_entries = OBJ_ZSET_MAX_ZIPLIST_ENTRIES;
1617*572c4311Sfengbojiang     server.zset_max_ziplist_value = OBJ_ZSET_MAX_ZIPLIST_VALUE;
1618*572c4311Sfengbojiang     server.hll_sparse_max_bytes = CONFIG_DEFAULT_HLL_SPARSE_MAX_BYTES;
1619*572c4311Sfengbojiang     server.stream_node_max_bytes = OBJ_STREAM_NODE_MAX_BYTES;
1620*572c4311Sfengbojiang     server.stream_node_max_entries = OBJ_STREAM_NODE_MAX_ENTRIES;
1621*572c4311Sfengbojiang     server.shutdown_asap = 0;
1622*572c4311Sfengbojiang     server.cluster_enabled = 0;
1623*572c4311Sfengbojiang     server.cluster_node_timeout = CLUSTER_DEFAULT_NODE_TIMEOUT;
1624*572c4311Sfengbojiang     server.cluster_migration_barrier = CLUSTER_DEFAULT_MIGRATION_BARRIER;
1625*572c4311Sfengbojiang     server.cluster_slave_validity_factor = CLUSTER_DEFAULT_SLAVE_VALIDITY;
1626*572c4311Sfengbojiang     server.cluster_require_full_coverage = CLUSTER_DEFAULT_REQUIRE_FULL_COVERAGE;
1627*572c4311Sfengbojiang     server.cluster_slave_no_failover = CLUSTER_DEFAULT_SLAVE_NO_FAILOVER;
1628*572c4311Sfengbojiang     server.cluster_configfile = zstrdup(CONFIG_DEFAULT_CLUSTER_CONFIG_FILE);
1629*572c4311Sfengbojiang     server.cluster_announce_ip = CONFIG_DEFAULT_CLUSTER_ANNOUNCE_IP;
1630*572c4311Sfengbojiang     server.cluster_announce_port = CONFIG_DEFAULT_CLUSTER_ANNOUNCE_PORT;
1631*572c4311Sfengbojiang     server.cluster_announce_bus_port = CONFIG_DEFAULT_CLUSTER_ANNOUNCE_BUS_PORT;
1632*572c4311Sfengbojiang     server.cluster_module_flags = CLUSTER_MODULE_FLAG_NONE;
1633*572c4311Sfengbojiang     server.migrate_cached_sockets = dictCreate(&migrateCacheDictType,NULL);
1634*572c4311Sfengbojiang     server.next_client_id = 1; /* Client IDs, start from 1 .*/
1635*572c4311Sfengbojiang     server.loading_process_events_interval_bytes = (1024*1024*2);
1636*572c4311Sfengbojiang     server.lazyfree_lazy_eviction = CONFIG_DEFAULT_LAZYFREE_LAZY_EVICTION;
1637*572c4311Sfengbojiang     server.lazyfree_lazy_expire = CONFIG_DEFAULT_LAZYFREE_LAZY_EXPIRE;
1638*572c4311Sfengbojiang     server.lazyfree_lazy_server_del = CONFIG_DEFAULT_LAZYFREE_LAZY_SERVER_DEL;
1639*572c4311Sfengbojiang     server.always_show_logo = CONFIG_DEFAULT_ALWAYS_SHOW_LOGO;
1640*572c4311Sfengbojiang     server.lua_time_limit = LUA_SCRIPT_TIME_LIMIT;
1641*572c4311Sfengbojiang 
1642*572c4311Sfengbojiang     unsigned int lruclock = getLRUClock();
1643*572c4311Sfengbojiang     atomicSet(server.lruclock,lruclock);
1644*572c4311Sfengbojiang     resetServerSaveParams();
1645*572c4311Sfengbojiang 
1646*572c4311Sfengbojiang     appendServerSaveParams(60*60,1);  /* save after 1 hour and 1 change */
1647*572c4311Sfengbojiang     appendServerSaveParams(300,100);  /* save after 5 minutes and 100 changes */
1648*572c4311Sfengbojiang     appendServerSaveParams(60,10000); /* save after 1 minute and 10000 changes */
1649*572c4311Sfengbojiang 
1650*572c4311Sfengbojiang     /* Replication related */
1651*572c4311Sfengbojiang     server.masterauth = NULL;
1652*572c4311Sfengbojiang     server.masterhost = NULL;
1653*572c4311Sfengbojiang     server.masterport = 6379;
1654*572c4311Sfengbojiang     server.master = NULL;
1655*572c4311Sfengbojiang     server.cached_master = NULL;
1656*572c4311Sfengbojiang     server.master_initial_offset = -1;
1657*572c4311Sfengbojiang     server.repl_state = REPL_STATE_NONE;
1658*572c4311Sfengbojiang     server.repl_syncio_timeout = CONFIG_REPL_SYNCIO_TIMEOUT;
1659*572c4311Sfengbojiang     server.repl_serve_stale_data = CONFIG_DEFAULT_SLAVE_SERVE_STALE_DATA;
1660*572c4311Sfengbojiang     server.repl_slave_ro = CONFIG_DEFAULT_SLAVE_READ_ONLY;
1661*572c4311Sfengbojiang     server.repl_slave_ignore_maxmemory = CONFIG_DEFAULT_SLAVE_IGNORE_MAXMEMORY;
1662*572c4311Sfengbojiang     server.repl_slave_lazy_flush = CONFIG_DEFAULT_SLAVE_LAZY_FLUSH;
1663*572c4311Sfengbojiang     server.repl_down_since = 0; /* Never connected, repl is down since EVER. */
1664*572c4311Sfengbojiang     server.repl_disable_tcp_nodelay = CONFIG_DEFAULT_REPL_DISABLE_TCP_NODELAY;
1665*572c4311Sfengbojiang     server.repl_diskless_sync = CONFIG_DEFAULT_REPL_DISKLESS_SYNC;
1666*572c4311Sfengbojiang     server.repl_diskless_sync_delay = CONFIG_DEFAULT_REPL_DISKLESS_SYNC_DELAY;
1667*572c4311Sfengbojiang     server.repl_ping_slave_period = CONFIG_DEFAULT_REPL_PING_SLAVE_PERIOD;
1668*572c4311Sfengbojiang     server.repl_timeout = CONFIG_DEFAULT_REPL_TIMEOUT;
1669*572c4311Sfengbojiang     server.repl_min_slaves_to_write = CONFIG_DEFAULT_MIN_SLAVES_TO_WRITE;
1670*572c4311Sfengbojiang     server.repl_min_slaves_max_lag = CONFIG_DEFAULT_MIN_SLAVES_MAX_LAG;
1671*572c4311Sfengbojiang     server.slave_priority = CONFIG_DEFAULT_SLAVE_PRIORITY;
1672*572c4311Sfengbojiang     server.slave_announce_ip = CONFIG_DEFAULT_SLAVE_ANNOUNCE_IP;
1673*572c4311Sfengbojiang     server.slave_announce_port = CONFIG_DEFAULT_SLAVE_ANNOUNCE_PORT;
1674*572c4311Sfengbojiang     server.master_repl_offset = 0;
1675*572c4311Sfengbojiang 
1676*572c4311Sfengbojiang     /* Replication partial resync backlog */
1677*572c4311Sfengbojiang     server.repl_backlog = NULL;
1678*572c4311Sfengbojiang     server.repl_backlog_size = CONFIG_DEFAULT_REPL_BACKLOG_SIZE;
1679*572c4311Sfengbojiang     server.repl_backlog_histlen = 0;
1680*572c4311Sfengbojiang     server.repl_backlog_idx = 0;
1681*572c4311Sfengbojiang     server.repl_backlog_off = 0;
1682*572c4311Sfengbojiang     server.repl_backlog_time_limit = CONFIG_DEFAULT_REPL_BACKLOG_TIME_LIMIT;
1683*572c4311Sfengbojiang     server.repl_no_slaves_since = time(NULL);
1684*572c4311Sfengbojiang 
1685*572c4311Sfengbojiang     /* Client output buffer limits */
1686*572c4311Sfengbojiang     for (j = 0; j < CLIENT_TYPE_OBUF_COUNT; j++)
1687*572c4311Sfengbojiang         server.client_obuf_limits[j] = clientBufferLimitsDefaults[j];
1688*572c4311Sfengbojiang 
1689*572c4311Sfengbojiang     /* Double constants initialization */
1690*572c4311Sfengbojiang     R_Zero = 0.0;
1691*572c4311Sfengbojiang     R_PosInf = 1.0/R_Zero;
1692*572c4311Sfengbojiang     R_NegInf = -1.0/R_Zero;
1693*572c4311Sfengbojiang     R_Nan = R_Zero/R_Zero;
1694*572c4311Sfengbojiang 
1695*572c4311Sfengbojiang     /* Command table -- we initiialize it here as it is part of the
1696*572c4311Sfengbojiang      * initial configuration, since command names may be changed via
1697*572c4311Sfengbojiang      * redis.conf using the rename-command directive. */
1698*572c4311Sfengbojiang     server.commands = dictCreate(&commandTableDictType,NULL);
1699*572c4311Sfengbojiang     server.orig_commands = dictCreate(&commandTableDictType,NULL);
1700*572c4311Sfengbojiang     populateCommandTable();
1701*572c4311Sfengbojiang     server.delCommand = lookupCommandByCString("del");
1702*572c4311Sfengbojiang     server.multiCommand = lookupCommandByCString("multi");
1703*572c4311Sfengbojiang     server.lpushCommand = lookupCommandByCString("lpush");
1704*572c4311Sfengbojiang     server.lpopCommand = lookupCommandByCString("lpop");
1705*572c4311Sfengbojiang     server.rpopCommand = lookupCommandByCString("rpop");
1706*572c4311Sfengbojiang     server.zpopminCommand = lookupCommandByCString("zpopmin");
1707*572c4311Sfengbojiang     server.zpopmaxCommand = lookupCommandByCString("zpopmax");
1708*572c4311Sfengbojiang     server.sremCommand = lookupCommandByCString("srem");
1709*572c4311Sfengbojiang     server.execCommand = lookupCommandByCString("exec");
1710*572c4311Sfengbojiang     server.expireCommand = lookupCommandByCString("expire");
1711*572c4311Sfengbojiang     server.pexpireCommand = lookupCommandByCString("pexpire");
1712*572c4311Sfengbojiang     server.xclaimCommand = lookupCommandByCString("xclaim");
1713*572c4311Sfengbojiang     server.xgroupCommand = lookupCommandByCString("xgroup");
1714*572c4311Sfengbojiang 
1715*572c4311Sfengbojiang     /* Slow log */
1716*572c4311Sfengbojiang     server.slowlog_log_slower_than = CONFIG_DEFAULT_SLOWLOG_LOG_SLOWER_THAN;
1717*572c4311Sfengbojiang     server.slowlog_max_len = CONFIG_DEFAULT_SLOWLOG_MAX_LEN;
1718*572c4311Sfengbojiang 
1719*572c4311Sfengbojiang     /* Latency monitor */
1720*572c4311Sfengbojiang     server.latency_monitor_threshold = CONFIG_DEFAULT_LATENCY_MONITOR_THRESHOLD;
1721*572c4311Sfengbojiang 
1722*572c4311Sfengbojiang     /* Debugging */
1723*572c4311Sfengbojiang     server.assert_failed = "<no assertion failed>";
1724*572c4311Sfengbojiang     server.assert_file = "<no file>";
1725*572c4311Sfengbojiang     server.assert_line = 0;
1726*572c4311Sfengbojiang     server.bug_report_start = 0;
1727*572c4311Sfengbojiang     server.watchdog_period = 0;
1728*572c4311Sfengbojiang 
1729*572c4311Sfengbojiang     /* By default we want scripts to be always replicated by effects
1730*572c4311Sfengbojiang      * (single commands executed by the script), and not by sending the
1731*572c4311Sfengbojiang      * script to the slave / AOF. This is the new way starting from
1732*572c4311Sfengbojiang      * Redis 5. However it is possible to revert it via redis.conf. */
1733*572c4311Sfengbojiang     server.lua_always_replicate_commands = 1;
1734*572c4311Sfengbojiang }
1735*572c4311Sfengbojiang 
1736*572c4311Sfengbojiang extern char **environ;
1737*572c4311Sfengbojiang 
1738*572c4311Sfengbojiang /* Restart the server, executing the same executable that started this
1739*572c4311Sfengbojiang  * instance, with the same arguments and configuration file.
1740*572c4311Sfengbojiang  *
1741*572c4311Sfengbojiang  * The function is designed to directly call execve() so that the new
1742*572c4311Sfengbojiang  * server instance will retain the PID of the previous one.
1743*572c4311Sfengbojiang  *
1744*572c4311Sfengbojiang  * The list of flags, that may be bitwise ORed together, alter the
1745*572c4311Sfengbojiang  * behavior of this function:
1746*572c4311Sfengbojiang  *
1747*572c4311Sfengbojiang  * RESTART_SERVER_NONE              No flags.
1748*572c4311Sfengbojiang  * RESTART_SERVER_GRACEFULLY        Do a proper shutdown before restarting.
1749*572c4311Sfengbojiang  * RESTART_SERVER_CONFIG_REWRITE    Rewrite the config file before restarting.
1750*572c4311Sfengbojiang  *
1751*572c4311Sfengbojiang  * On success the function does not return, because the process turns into
1752*572c4311Sfengbojiang  * a different process. On error C_ERR is returned. */
restartServer(int flags,mstime_t delay)1753*572c4311Sfengbojiang int restartServer(int flags, mstime_t delay) {
1754*572c4311Sfengbojiang     int j;
1755*572c4311Sfengbojiang 
1756*572c4311Sfengbojiang     /* Check if we still have accesses to the executable that started this
1757*572c4311Sfengbojiang      * server instance. */
1758*572c4311Sfengbojiang     if (access(server.executable,X_OK) == -1) {
1759*572c4311Sfengbojiang         serverLog(LL_WARNING,"Can't restart: this process has no "
1760*572c4311Sfengbojiang                              "permissions to execute %s", server.executable);
1761*572c4311Sfengbojiang         return C_ERR;
1762*572c4311Sfengbojiang     }
1763*572c4311Sfengbojiang 
1764*572c4311Sfengbojiang     /* Config rewriting. */
1765*572c4311Sfengbojiang     if (flags & RESTART_SERVER_CONFIG_REWRITE &&
1766*572c4311Sfengbojiang         server.configfile &&
1767*572c4311Sfengbojiang         rewriteConfig(server.configfile) == -1)
1768*572c4311Sfengbojiang     {
1769*572c4311Sfengbojiang         serverLog(LL_WARNING,"Can't restart: configuration rewrite process "
1770*572c4311Sfengbojiang                              "failed");
1771*572c4311Sfengbojiang         return C_ERR;
1772*572c4311Sfengbojiang     }
1773*572c4311Sfengbojiang 
1774*572c4311Sfengbojiang     /* Perform a proper shutdown. */
1775*572c4311Sfengbojiang     if (flags & RESTART_SERVER_GRACEFULLY &&
1776*572c4311Sfengbojiang         prepareForShutdown(SHUTDOWN_NOFLAGS) != C_OK)
1777*572c4311Sfengbojiang     {
1778*572c4311Sfengbojiang         serverLog(LL_WARNING,"Can't restart: error preparing for shutdown");
1779*572c4311Sfengbojiang         return C_ERR;
1780*572c4311Sfengbojiang     }
1781*572c4311Sfengbojiang 
1782*572c4311Sfengbojiang     /* Close all file descriptors, with the exception of stdin, stdout, strerr
1783*572c4311Sfengbojiang      * which are useful if we restart a Redis server which is not daemonized. */
1784*572c4311Sfengbojiang     for (j = 3; j < (int)server.maxclients + 1024; j++) {
1785*572c4311Sfengbojiang         /* Test the descriptor validity before closing it, otherwise
1786*572c4311Sfengbojiang          * Valgrind issues a warning on close(). */
1787*572c4311Sfengbojiang         if (fcntl(j,F_GETFD) != -1) close(j);
1788*572c4311Sfengbojiang     }
1789*572c4311Sfengbojiang 
1790*572c4311Sfengbojiang     /* Execute the server with the original command line. */
1791*572c4311Sfengbojiang     if (delay) usleep(delay*1000);
1792*572c4311Sfengbojiang     zfree(server.exec_argv[0]);
1793*572c4311Sfengbojiang     server.exec_argv[0] = zstrdup(server.executable);
1794*572c4311Sfengbojiang     execve(server.executable,server.exec_argv,environ);
1795*572c4311Sfengbojiang 
1796*572c4311Sfengbojiang     /* If an error occurred here, there is nothing we can do, but exit. */
1797*572c4311Sfengbojiang     _exit(1);
1798*572c4311Sfengbojiang 
1799*572c4311Sfengbojiang     return C_ERR; /* Never reached. */
1800*572c4311Sfengbojiang }
1801*572c4311Sfengbojiang 
1802*572c4311Sfengbojiang /* This function will try to raise the max number of open files accordingly to
1803*572c4311Sfengbojiang  * the configured max number of clients. It also reserves a number of file
1804*572c4311Sfengbojiang  * descriptors (CONFIG_MIN_RESERVED_FDS) for extra operations of
1805*572c4311Sfengbojiang  * persistence, listening sockets, log files and so forth.
1806*572c4311Sfengbojiang  *
1807*572c4311Sfengbojiang  * If it will not be possible to set the limit accordingly to the configured
1808*572c4311Sfengbojiang  * max number of clients, the function will do the reverse setting
1809*572c4311Sfengbojiang  * server.maxclients to the value that we can actually handle. */
adjustOpenFilesLimit(void)1810*572c4311Sfengbojiang void adjustOpenFilesLimit(void) {
1811*572c4311Sfengbojiang     rlim_t maxfiles = server.maxclients+CONFIG_MIN_RESERVED_FDS;
1812*572c4311Sfengbojiang     struct rlimit limit;
1813*572c4311Sfengbojiang 
1814*572c4311Sfengbojiang     if (getrlimit(RLIMIT_NOFILE,&limit) == -1) {
1815*572c4311Sfengbojiang         serverLog(LL_WARNING,"Unable to obtain the current NOFILE limit (%s), assuming 1024 and setting the max clients configuration accordingly.",
1816*572c4311Sfengbojiang             strerror(errno));
1817*572c4311Sfengbojiang         server.maxclients = 1024-CONFIG_MIN_RESERVED_FDS;
1818*572c4311Sfengbojiang     } else {
1819*572c4311Sfengbojiang         rlim_t oldlimit = limit.rlim_cur;
1820*572c4311Sfengbojiang 
1821*572c4311Sfengbojiang         /* Set the max number of files if the current limit is not enough
1822*572c4311Sfengbojiang          * for our needs. */
1823*572c4311Sfengbojiang         if (oldlimit < maxfiles) {
1824*572c4311Sfengbojiang             rlim_t bestlimit;
1825*572c4311Sfengbojiang             int setrlimit_error = 0;
1826*572c4311Sfengbojiang 
1827*572c4311Sfengbojiang             /* Try to set the file limit to match 'maxfiles' or at least
1828*572c4311Sfengbojiang              * to the higher value supported less than maxfiles. */
1829*572c4311Sfengbojiang             bestlimit = maxfiles;
1830*572c4311Sfengbojiang             while(bestlimit > oldlimit) {
1831*572c4311Sfengbojiang                 rlim_t decr_step = 16;
1832*572c4311Sfengbojiang 
1833*572c4311Sfengbojiang                 limit.rlim_cur = bestlimit;
1834*572c4311Sfengbojiang                 limit.rlim_max = bestlimit;
1835*572c4311Sfengbojiang                 if (setrlimit(RLIMIT_NOFILE,&limit) != -1) break;
1836*572c4311Sfengbojiang                 setrlimit_error = errno;
1837*572c4311Sfengbojiang 
1838*572c4311Sfengbojiang                 /* We failed to set file limit to 'bestlimit'. Try with a
1839*572c4311Sfengbojiang                  * smaller limit decrementing by a few FDs per iteration. */
1840*572c4311Sfengbojiang                 if (bestlimit < decr_step) break;
1841*572c4311Sfengbojiang                 bestlimit -= decr_step;
1842*572c4311Sfengbojiang             }
1843*572c4311Sfengbojiang 
1844*572c4311Sfengbojiang             /* Assume that the limit we get initially is still valid if
1845*572c4311Sfengbojiang              * our last try was even lower. */
1846*572c4311Sfengbojiang             if (bestlimit < oldlimit) bestlimit = oldlimit;
1847*572c4311Sfengbojiang 
1848*572c4311Sfengbojiang             if (bestlimit < maxfiles) {
1849*572c4311Sfengbojiang                 unsigned int old_maxclients = server.maxclients;
1850*572c4311Sfengbojiang                 server.maxclients = bestlimit-CONFIG_MIN_RESERVED_FDS;
1851*572c4311Sfengbojiang                 /* maxclients is unsigned so may overflow: in order
1852*572c4311Sfengbojiang                  * to check if maxclients is now logically less than 1
1853*572c4311Sfengbojiang                  * we test indirectly via bestlimit. */
1854*572c4311Sfengbojiang                 if (bestlimit <= CONFIG_MIN_RESERVED_FDS) {
1855*572c4311Sfengbojiang                     serverLog(LL_WARNING,"Your current 'ulimit -n' "
1856*572c4311Sfengbojiang                         "of %llu is not enough for the server to start. "
1857*572c4311Sfengbojiang                         "Please increase your open file limit to at least "
1858*572c4311Sfengbojiang                         "%llu. Exiting.",
1859*572c4311Sfengbojiang                         (unsigned long long) oldlimit,
1860*572c4311Sfengbojiang                         (unsigned long long) maxfiles);
1861*572c4311Sfengbojiang                     exit(1);
1862*572c4311Sfengbojiang                 }
1863*572c4311Sfengbojiang                 serverLog(LL_WARNING,"You requested maxclients of %d "
1864*572c4311Sfengbojiang                     "requiring at least %llu max file descriptors.",
1865*572c4311Sfengbojiang                     old_maxclients,
1866*572c4311Sfengbojiang                     (unsigned long long) maxfiles);
1867*572c4311Sfengbojiang                 serverLog(LL_WARNING,"Server can't set maximum open files "
1868*572c4311Sfengbojiang                     "to %llu because of OS error: %s.",
1869*572c4311Sfengbojiang                     (unsigned long long) maxfiles, strerror(setrlimit_error));
1870*572c4311Sfengbojiang                 serverLog(LL_WARNING,"Current maximum open files is %llu. "
1871*572c4311Sfengbojiang                     "maxclients has been reduced to %d to compensate for "
1872*572c4311Sfengbojiang                     "low ulimit. "
1873*572c4311Sfengbojiang                     "If you need higher maxclients increase 'ulimit -n'.",
1874*572c4311Sfengbojiang                     (unsigned long long) bestlimit, server.maxclients);
1875*572c4311Sfengbojiang             } else {
1876*572c4311Sfengbojiang                 serverLog(LL_NOTICE,"Increased maximum number of open files "
1877*572c4311Sfengbojiang                     "to %llu (it was originally set to %llu).",
1878*572c4311Sfengbojiang                     (unsigned long long) maxfiles,
1879*572c4311Sfengbojiang                     (unsigned long long) oldlimit);
1880*572c4311Sfengbojiang             }
1881*572c4311Sfengbojiang         }
1882*572c4311Sfengbojiang     }
1883*572c4311Sfengbojiang }
1884*572c4311Sfengbojiang 
1885*572c4311Sfengbojiang /* Check that server.tcp_backlog can be actually enforced in Linux according
1886*572c4311Sfengbojiang  * to the value of /proc/sys/net/core/somaxconn, or warn about it. */
checkTcpBacklogSettings(void)1887*572c4311Sfengbojiang void checkTcpBacklogSettings(void) {
1888*572c4311Sfengbojiang #ifdef HAVE_PROC_SOMAXCONN
1889*572c4311Sfengbojiang     FILE *fp = fopen("/proc/sys/net/core/somaxconn","r");
1890*572c4311Sfengbojiang     char buf[1024];
1891*572c4311Sfengbojiang     if (!fp) return;
1892*572c4311Sfengbojiang     if (fgets(buf,sizeof(buf),fp) != NULL) {
1893*572c4311Sfengbojiang         int somaxconn = atoi(buf);
1894*572c4311Sfengbojiang         if (somaxconn > 0 && somaxconn < server.tcp_backlog) {
1895*572c4311Sfengbojiang             serverLog(LL_WARNING,"WARNING: The TCP backlog setting of %d cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of %d.", server.tcp_backlog, somaxconn);
1896*572c4311Sfengbojiang         }
1897*572c4311Sfengbojiang     }
1898*572c4311Sfengbojiang     fclose(fp);
1899*572c4311Sfengbojiang #endif
1900*572c4311Sfengbojiang }
1901*572c4311Sfengbojiang 
1902*572c4311Sfengbojiang /* Initialize a set of file descriptors to listen to the specified 'port'
1903*572c4311Sfengbojiang  * binding the addresses specified in the Redis server configuration.
1904*572c4311Sfengbojiang  *
1905*572c4311Sfengbojiang  * The listening file descriptors are stored in the integer array 'fds'
1906*572c4311Sfengbojiang  * and their number is set in '*count'.
1907*572c4311Sfengbojiang  *
1908*572c4311Sfengbojiang  * The addresses to bind are specified in the global server.bindaddr array
1909*572c4311Sfengbojiang  * and their number is server.bindaddr_count. If the server configuration
1910*572c4311Sfengbojiang  * contains no specific addresses to bind, this function will try to
1911*572c4311Sfengbojiang  * bind * (all addresses) for both the IPv4 and IPv6 protocols.
1912*572c4311Sfengbojiang  *
1913*572c4311Sfengbojiang  * On success the function returns C_OK.
1914*572c4311Sfengbojiang  *
1915*572c4311Sfengbojiang  * On error the function returns C_ERR. For the function to be on
1916*572c4311Sfengbojiang  * error, at least one of the server.bindaddr addresses was
1917*572c4311Sfengbojiang  * impossible to bind, or no bind addresses were specified in the server
1918*572c4311Sfengbojiang  * configuration but the function is not able to bind * for at least
1919*572c4311Sfengbojiang  * one of the IPv4 or IPv6 protocols. */
listenToPort(int port,int * fds,int * count)1920*572c4311Sfengbojiang int listenToPort(int port, int *fds, int *count) {
1921*572c4311Sfengbojiang     int j;
1922*572c4311Sfengbojiang 
1923*572c4311Sfengbojiang     /* Force binding of 0.0.0.0 if no bind address is specified, always
1924*572c4311Sfengbojiang      * entering the loop if j == 0. */
1925*572c4311Sfengbojiang     if (server.bindaddr_count == 0) server.bindaddr[0] = NULL;
1926*572c4311Sfengbojiang     for (j = 0; j < server.bindaddr_count || j == 0; j++) {
1927*572c4311Sfengbojiang         if (server.bindaddr[j] == NULL) {
1928*572c4311Sfengbojiang             int unsupported = 0;
1929*572c4311Sfengbojiang             /* Bind * for both IPv6 and IPv4, we enter here only if
1930*572c4311Sfengbojiang              * server.bindaddr_count == 0. */
1931*572c4311Sfengbojiang             fds[*count] = anetTcp6Server(server.neterr,port,NULL,
1932*572c4311Sfengbojiang                 server.tcp_backlog);
1933*572c4311Sfengbojiang             if (fds[*count] != ANET_ERR) {
1934*572c4311Sfengbojiang                 anetNonBlock(NULL,fds[*count]);
1935*572c4311Sfengbojiang                 (*count)++;
1936*572c4311Sfengbojiang             } else if (errno == EAFNOSUPPORT) {
1937*572c4311Sfengbojiang                 unsupported++;
1938*572c4311Sfengbojiang                 serverLog(LL_WARNING,"Not listening to IPv6: unsupproted");
1939*572c4311Sfengbojiang             }
1940*572c4311Sfengbojiang 
1941*572c4311Sfengbojiang             if (*count == 1 || unsupported) {
1942*572c4311Sfengbojiang                 /* Bind the IPv4 address as well. */
1943*572c4311Sfengbojiang                 fds[*count] = anetTcpServer(server.neterr,port,NULL,
1944*572c4311Sfengbojiang                     server.tcp_backlog);
1945*572c4311Sfengbojiang                 if (fds[*count] != ANET_ERR) {
1946*572c4311Sfengbojiang                     anetNonBlock(NULL,fds[*count]);
1947*572c4311Sfengbojiang                     (*count)++;
1948*572c4311Sfengbojiang                 } else if (errno == EAFNOSUPPORT) {
1949*572c4311Sfengbojiang                     unsupported++;
1950*572c4311Sfengbojiang                     serverLog(LL_WARNING,"Not listening to IPv4: unsupproted");
1951*572c4311Sfengbojiang                 }
1952*572c4311Sfengbojiang             }
1953*572c4311Sfengbojiang             /* Exit the loop if we were able to bind * on IPv4 and IPv6,
1954*572c4311Sfengbojiang              * otherwise fds[*count] will be ANET_ERR and we'll print an
1955*572c4311Sfengbojiang              * error and return to the caller with an error. */
1956*572c4311Sfengbojiang             if (*count + unsupported == 2) break;
1957*572c4311Sfengbojiang         } else if (strchr(server.bindaddr[j],':')) {
1958*572c4311Sfengbojiang             /* Bind IPv6 address. */
1959*572c4311Sfengbojiang             fds[*count] = anetTcp6Server(server.neterr,port,server.bindaddr[j],
1960*572c4311Sfengbojiang                 server.tcp_backlog);
1961*572c4311Sfengbojiang         } else {
1962*572c4311Sfengbojiang             /* Bind IPv4 address. */
1963*572c4311Sfengbojiang             fds[*count] = anetTcpServer(server.neterr,port,server.bindaddr[j],
1964*572c4311Sfengbojiang                 server.tcp_backlog);
1965*572c4311Sfengbojiang         }
1966*572c4311Sfengbojiang         if (fds[*count] == ANET_ERR) {
1967*572c4311Sfengbojiang             serverLog(LL_WARNING,
1968*572c4311Sfengbojiang                 "Could not create server TCP listening socket %s:%d: %s",
1969*572c4311Sfengbojiang                 server.bindaddr[j] ? server.bindaddr[j] : "*",
1970*572c4311Sfengbojiang                 port, server.neterr);
1971*572c4311Sfengbojiang                 if (errno == ENOPROTOOPT     || errno == EPROTONOSUPPORT ||
1972*572c4311Sfengbojiang                     errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
1973*572c4311Sfengbojiang                     errno == EAFNOSUPPORT    || errno == EADDRNOTAVAIL)
1974*572c4311Sfengbojiang                     continue;
1975*572c4311Sfengbojiang             return C_ERR;
1976*572c4311Sfengbojiang         }
1977*572c4311Sfengbojiang         anetNonBlock(NULL,fds[*count]);
1978*572c4311Sfengbojiang         (*count)++;
1979*572c4311Sfengbojiang     }
1980*572c4311Sfengbojiang     return C_OK;
1981*572c4311Sfengbojiang }
1982*572c4311Sfengbojiang 
1983*572c4311Sfengbojiang /* Resets the stats that we expose via INFO or other means that we want
1984*572c4311Sfengbojiang  * to reset via CONFIG RESETSTAT. The function is also used in order to
1985*572c4311Sfengbojiang  * initialize these fields in initServer() at server startup. */
resetServerStats(void)1986*572c4311Sfengbojiang void resetServerStats(void) {
1987*572c4311Sfengbojiang     int j;
1988*572c4311Sfengbojiang 
1989*572c4311Sfengbojiang     server.stat_numcommands = 0;
1990*572c4311Sfengbojiang     server.stat_numconnections = 0;
1991*572c4311Sfengbojiang     server.stat_expiredkeys = 0;
1992*572c4311Sfengbojiang     server.stat_expired_stale_perc = 0;
1993*572c4311Sfengbojiang     server.stat_expired_time_cap_reached_count = 0;
1994*572c4311Sfengbojiang     server.stat_evictedkeys = 0;
1995*572c4311Sfengbojiang     server.stat_keyspace_misses = 0;
1996*572c4311Sfengbojiang     server.stat_keyspace_hits = 0;
1997*572c4311Sfengbojiang     server.stat_active_defrag_hits = 0;
1998*572c4311Sfengbojiang     server.stat_active_defrag_misses = 0;
1999*572c4311Sfengbojiang     server.stat_active_defrag_key_hits = 0;
2000*572c4311Sfengbojiang     server.stat_active_defrag_key_misses = 0;
2001*572c4311Sfengbojiang     server.stat_active_defrag_scanned = 0;
2002*572c4311Sfengbojiang     server.stat_fork_time = 0;
2003*572c4311Sfengbojiang     server.stat_fork_rate = 0;
2004*572c4311Sfengbojiang     server.stat_rejected_conn = 0;
2005*572c4311Sfengbojiang     server.stat_sync_full = 0;
2006*572c4311Sfengbojiang     server.stat_sync_partial_ok = 0;
2007*572c4311Sfengbojiang     server.stat_sync_partial_err = 0;
2008*572c4311Sfengbojiang     for (j = 0; j < STATS_METRIC_COUNT; j++) {
2009*572c4311Sfengbojiang         server.inst_metric[j].idx = 0;
2010*572c4311Sfengbojiang         server.inst_metric[j].last_sample_time = mstime();
2011*572c4311Sfengbojiang         server.inst_metric[j].last_sample_count = 0;
2012*572c4311Sfengbojiang         memset(server.inst_metric[j].samples,0,
2013*572c4311Sfengbojiang             sizeof(server.inst_metric[j].samples));
2014*572c4311Sfengbojiang     }
2015*572c4311Sfengbojiang     server.stat_net_input_bytes = 0;
2016*572c4311Sfengbojiang     server.stat_net_output_bytes = 0;
2017*572c4311Sfengbojiang     server.aof_delayed_fsync = 0;
2018*572c4311Sfengbojiang }
2019*572c4311Sfengbojiang 
initServer(void)2020*572c4311Sfengbojiang void initServer(void) {
2021*572c4311Sfengbojiang     int j;
2022*572c4311Sfengbojiang 
2023*572c4311Sfengbojiang     signal(SIGHUP, SIG_IGN);
2024*572c4311Sfengbojiang     signal(SIGPIPE, SIG_IGN);
2025*572c4311Sfengbojiang     setupSignalHandlers();
2026*572c4311Sfengbojiang 
2027*572c4311Sfengbojiang     if (server.syslog_enabled) {
2028*572c4311Sfengbojiang         openlog(server.syslog_ident, LOG_PID | LOG_NDELAY | LOG_NOWAIT,
2029*572c4311Sfengbojiang             server.syslog_facility);
2030*572c4311Sfengbojiang     }
2031*572c4311Sfengbojiang 
2032*572c4311Sfengbojiang     server.hz = server.config_hz;
2033*572c4311Sfengbojiang     server.pid = getpid();
2034*572c4311Sfengbojiang     server.current_client = NULL;
2035*572c4311Sfengbojiang     server.clients = listCreate();
2036*572c4311Sfengbojiang     server.clients_index = raxNew();
2037*572c4311Sfengbojiang     server.clients_to_close = listCreate();
2038*572c4311Sfengbojiang     server.slaves = listCreate();
2039*572c4311Sfengbojiang     server.monitors = listCreate();
2040*572c4311Sfengbojiang     server.clients_pending_write = listCreate();
2041*572c4311Sfengbojiang     server.slaveseldb = -1; /* Force to emit the first SELECT command. */
2042*572c4311Sfengbojiang     server.unblocked_clients = listCreate();
2043*572c4311Sfengbojiang     server.ready_keys = listCreate();
2044*572c4311Sfengbojiang     server.clients_waiting_acks = listCreate();
2045*572c4311Sfengbojiang     server.get_ack_from_slaves = 0;
2046*572c4311Sfengbojiang     server.clients_paused = 0;
2047*572c4311Sfengbojiang     server.system_memory_size = zmalloc_get_memory_size();
2048*572c4311Sfengbojiang 
2049*572c4311Sfengbojiang     createSharedObjects();
2050*572c4311Sfengbojiang     adjustOpenFilesLimit();
2051*572c4311Sfengbojiang     server.el = aeCreateEventLoop(server.maxclients+CONFIG_FDSET_INCR);
2052*572c4311Sfengbojiang     if (server.el == NULL) {
2053*572c4311Sfengbojiang         serverLog(LL_WARNING,
2054*572c4311Sfengbojiang             "Failed creating the event loop. Error message: '%s'",
2055*572c4311Sfengbojiang             strerror(errno));
2056*572c4311Sfengbojiang         exit(1);
2057*572c4311Sfengbojiang     }
2058*572c4311Sfengbojiang     server.db = zmalloc(sizeof(redisDb)*server.dbnum);
2059*572c4311Sfengbojiang 
2060*572c4311Sfengbojiang     /* Open the TCP listening socket for the user commands. */
2061*572c4311Sfengbojiang     if (server.port != 0 &&
2062*572c4311Sfengbojiang         listenToPort(server.port,server.ipfd,&server.ipfd_count) == C_ERR)
2063*572c4311Sfengbojiang         exit(1);
2064*572c4311Sfengbojiang 
2065*572c4311Sfengbojiang     /* Open the listening Unix domain socket. */
2066*572c4311Sfengbojiang     if (server.unixsocket != NULL) {
2067*572c4311Sfengbojiang         unlink(server.unixsocket); /* don't care if this fails */
2068*572c4311Sfengbojiang         server.sofd = anetUnixServer(server.neterr,server.unixsocket,
2069*572c4311Sfengbojiang             server.unixsocketperm, server.tcp_backlog);
2070*572c4311Sfengbojiang         if (server.sofd == ANET_ERR) {
2071*572c4311Sfengbojiang             serverLog(LL_WARNING, "Opening Unix socket: %s", server.neterr);
2072*572c4311Sfengbojiang             exit(1);
2073*572c4311Sfengbojiang         }
2074*572c4311Sfengbojiang         anetNonBlock(NULL,server.sofd);
2075*572c4311Sfengbojiang     }
2076*572c4311Sfengbojiang 
2077*572c4311Sfengbojiang     /* Abort if there are no listening sockets at all. */
2078*572c4311Sfengbojiang     if (server.ipfd_count == 0 && server.sofd < 0) {
2079*572c4311Sfengbojiang         serverLog(LL_WARNING, "Configured to not listen anywhere, exiting.");
2080*572c4311Sfengbojiang         exit(1);
2081*572c4311Sfengbojiang     }
2082*572c4311Sfengbojiang 
2083*572c4311Sfengbojiang     /* Create the Redis databases, and initialize other internal state. */
2084*572c4311Sfengbojiang     for (j = 0; j < server.dbnum; j++) {
2085*572c4311Sfengbojiang         server.db[j].dict = dictCreate(&dbDictType,NULL);
2086*572c4311Sfengbojiang         server.db[j].expires = dictCreate(&keyptrDictType,NULL);
2087*572c4311Sfengbojiang         server.db[j].blocking_keys = dictCreate(&keylistDictType,NULL);
2088*572c4311Sfengbojiang         server.db[j].ready_keys = dictCreate(&objectKeyPointerValueDictType,NULL);
2089*572c4311Sfengbojiang         server.db[j].watched_keys = dictCreate(&keylistDictType,NULL);
2090*572c4311Sfengbojiang         server.db[j].id = j;
2091*572c4311Sfengbojiang         server.db[j].avg_ttl = 0;
2092*572c4311Sfengbojiang         server.db[j].defrag_later = listCreate();
2093*572c4311Sfengbojiang     }
2094*572c4311Sfengbojiang     evictionPoolAlloc(); /* Initialize the LRU keys pool. */
2095*572c4311Sfengbojiang     server.pubsub_channels = dictCreate(&keylistDictType,NULL);
2096*572c4311Sfengbojiang     server.pubsub_patterns = listCreate();
2097*572c4311Sfengbojiang     listSetFreeMethod(server.pubsub_patterns,freePubsubPattern);
2098*572c4311Sfengbojiang     listSetMatchMethod(server.pubsub_patterns,listMatchPubsubPattern);
2099*572c4311Sfengbojiang     server.cronloops = 0;
2100*572c4311Sfengbojiang     server.rdb_child_pid = -1;
2101*572c4311Sfengbojiang     server.aof_child_pid = -1;
2102*572c4311Sfengbojiang     server.rdb_child_type = RDB_CHILD_TYPE_NONE;
2103*572c4311Sfengbojiang     server.rdb_bgsave_scheduled = 0;
2104*572c4311Sfengbojiang     server.child_info_pipe[0] = -1;
2105*572c4311Sfengbojiang     server.child_info_pipe[1] = -1;
2106*572c4311Sfengbojiang     server.child_info_data.magic = 0;
2107*572c4311Sfengbojiang     aofRewriteBufferReset();
2108*572c4311Sfengbojiang     server.aof_buf = sdsempty();
2109*572c4311Sfengbojiang     server.lastsave = time(NULL); /* At startup we consider the DB saved. */
2110*572c4311Sfengbojiang     server.lastbgsave_try = 0;    /* At startup we never tried to BGSAVE. */
2111*572c4311Sfengbojiang     server.rdb_save_time_last = -1;
2112*572c4311Sfengbojiang     server.rdb_save_time_start = -1;
2113*572c4311Sfengbojiang     server.dirty = 0;
2114*572c4311Sfengbojiang     resetServerStats();
2115*572c4311Sfengbojiang     /* A few stats we don't want to reset: server startup time, and peak mem. */
2116*572c4311Sfengbojiang     server.stat_starttime = time(NULL);
2117*572c4311Sfengbojiang     server.stat_peak_memory = 0;
2118*572c4311Sfengbojiang     server.stat_rdb_cow_bytes = 0;
2119*572c4311Sfengbojiang     server.stat_aof_cow_bytes = 0;
2120*572c4311Sfengbojiang     server.cron_malloc_stats.zmalloc_used = 0;
2121*572c4311Sfengbojiang     server.cron_malloc_stats.process_rss = 0;
2122*572c4311Sfengbojiang     server.cron_malloc_stats.allocator_allocated = 0;
2123*572c4311Sfengbojiang     server.cron_malloc_stats.allocator_active = 0;
2124*572c4311Sfengbojiang     server.cron_malloc_stats.allocator_resident = 0;
2125*572c4311Sfengbojiang     server.lastbgsave_status = C_OK;
2126*572c4311Sfengbojiang     server.aof_last_write_status = C_OK;
2127*572c4311Sfengbojiang     server.aof_last_write_errno = 0;
2128*572c4311Sfengbojiang     server.repl_good_slaves_count = 0;
2129*572c4311Sfengbojiang 
2130*572c4311Sfengbojiang     /* Create the timer callback, this is our way to process many background
2131*572c4311Sfengbojiang      * operations incrementally, like clients timeout, eviction of unaccessed
2132*572c4311Sfengbojiang      * expired keys and so forth. */
2133*572c4311Sfengbojiang     if (aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL) == AE_ERR) {
2134*572c4311Sfengbojiang         serverPanic("Can't create event loop timers.");
2135*572c4311Sfengbojiang         exit(1);
2136*572c4311Sfengbojiang     }
2137*572c4311Sfengbojiang 
2138*572c4311Sfengbojiang     /* Create an event handler for accepting new connections in TCP and Unix
2139*572c4311Sfengbojiang      * domain sockets. */
2140*572c4311Sfengbojiang     for (j = 0; j < server.ipfd_count; j++) {
2141*572c4311Sfengbojiang         if (aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE,
2142*572c4311Sfengbojiang             acceptTcpHandler,NULL) == AE_ERR)
2143*572c4311Sfengbojiang             {
2144*572c4311Sfengbojiang                 serverPanic(
2145*572c4311Sfengbojiang                     "Unrecoverable error creating server.ipfd file event.");
2146*572c4311Sfengbojiang             }
2147*572c4311Sfengbojiang     }
2148*572c4311Sfengbojiang     if (server.sofd > 0 && aeCreateFileEvent(server.el,server.sofd,AE_READABLE,
2149*572c4311Sfengbojiang         acceptUnixHandler,NULL) == AE_ERR) serverPanic("Unrecoverable error creating server.sofd file event.");
2150*572c4311Sfengbojiang 
2151*572c4311Sfengbojiang #ifndef HAVE_FF_KQUEUE
2152*572c4311Sfengbojiang     /* Register a readable event for the pipe used to awake the event loop
2153*572c4311Sfengbojiang      * when a blocked client in a module needs attention. */
2154*572c4311Sfengbojiang     if (aeCreateFileEvent(server.el, server.module_blocked_pipe[0], AE_READABLE,
2155*572c4311Sfengbojiang         moduleBlockedClientPipeReadable,NULL) == AE_ERR) {
2156*572c4311Sfengbojiang             serverPanic(
2157*572c4311Sfengbojiang                 "Error registering the readable event for the module "
2158*572c4311Sfengbojiang                 "blocked clients subsystem.");
2159*572c4311Sfengbojiang     }
2160*572c4311Sfengbojiang #endif
2161*572c4311Sfengbojiang 
2162*572c4311Sfengbojiang     /* Open the AOF file if needed. */
2163*572c4311Sfengbojiang     if (server.aof_state == AOF_ON) {
2164*572c4311Sfengbojiang         server.aof_fd = open(server.aof_filename,
2165*572c4311Sfengbojiang                                O_WRONLY|O_APPEND|O_CREAT,0644);
2166*572c4311Sfengbojiang         if (server.aof_fd == -1) {
2167*572c4311Sfengbojiang             serverLog(LL_WARNING, "Can't open the append-only file: %s",
2168*572c4311Sfengbojiang                 strerror(errno));
2169*572c4311Sfengbojiang             exit(1);
2170*572c4311Sfengbojiang         }
2171*572c4311Sfengbojiang     }
2172*572c4311Sfengbojiang 
2173*572c4311Sfengbojiang     /* 32 bit instances are limited to 4GB of address space, so if there is
2174*572c4311Sfengbojiang      * no explicit limit in the user provided configuration we set a limit
2175*572c4311Sfengbojiang      * at 3 GB using maxmemory with 'noeviction' policy'. This avoids
2176*572c4311Sfengbojiang      * useless crashes of the Redis instance for out of memory. */
2177*572c4311Sfengbojiang     if (server.arch_bits == 32 && server.maxmemory == 0) {
2178*572c4311Sfengbojiang         serverLog(LL_WARNING,"Warning: 32 bit instance detected but no memory limit set. Setting 3 GB maxmemory limit with 'noeviction' policy now.");
2179*572c4311Sfengbojiang         server.maxmemory = 3072LL*(1024*1024); /* 3 GB */
2180*572c4311Sfengbojiang         server.maxmemory_policy = MAXMEMORY_NO_EVICTION;
2181*572c4311Sfengbojiang     }
2182*572c4311Sfengbojiang 
2183*572c4311Sfengbojiang     if (server.cluster_enabled) clusterInit();
2184*572c4311Sfengbojiang     replicationScriptCacheInit();
2185*572c4311Sfengbojiang     scriptingInit(1);
2186*572c4311Sfengbojiang     slowlogInit();
2187*572c4311Sfengbojiang     latencyMonitorInit();
2188*572c4311Sfengbojiang     bioInit();
2189*572c4311Sfengbojiang     server.initial_memory_usage = zmalloc_used_memory();
2190*572c4311Sfengbojiang }
2191*572c4311Sfengbojiang 
2192*572c4311Sfengbojiang /* Populates the Redis Command Table starting from the hard coded list
2193*572c4311Sfengbojiang  * we have on top of redis.c file. */
populateCommandTable(void)2194*572c4311Sfengbojiang void populateCommandTable(void) {
2195*572c4311Sfengbojiang     int j;
2196*572c4311Sfengbojiang     int numcommands = sizeof(redisCommandTable)/sizeof(struct redisCommand);
2197*572c4311Sfengbojiang 
2198*572c4311Sfengbojiang     for (j = 0; j < numcommands; j++) {
2199*572c4311Sfengbojiang         struct redisCommand *c = redisCommandTable+j;
2200*572c4311Sfengbojiang         char *f = c->sflags;
2201*572c4311Sfengbojiang         int retval1, retval2;
2202*572c4311Sfengbojiang 
2203*572c4311Sfengbojiang         while(*f != '\0') {
2204*572c4311Sfengbojiang             switch(*f) {
2205*572c4311Sfengbojiang             case 'w': c->flags |= CMD_WRITE; break;
2206*572c4311Sfengbojiang             case 'r': c->flags |= CMD_READONLY; break;
2207*572c4311Sfengbojiang             case 'm': c->flags |= CMD_DENYOOM; break;
2208*572c4311Sfengbojiang             case 'a': c->flags |= CMD_ADMIN; break;
2209*572c4311Sfengbojiang             case 'p': c->flags |= CMD_PUBSUB; break;
2210*572c4311Sfengbojiang             case 's': c->flags |= CMD_NOSCRIPT; break;
2211*572c4311Sfengbojiang             case 'R': c->flags |= CMD_RANDOM; break;
2212*572c4311Sfengbojiang             case 'S': c->flags |= CMD_SORT_FOR_SCRIPT; break;
2213*572c4311Sfengbojiang             case 'l': c->flags |= CMD_LOADING; break;
2214*572c4311Sfengbojiang             case 't': c->flags |= CMD_STALE; break;
2215*572c4311Sfengbojiang             case 'M': c->flags |= CMD_SKIP_MONITOR; break;
2216*572c4311Sfengbojiang             case 'k': c->flags |= CMD_ASKING; break;
2217*572c4311Sfengbojiang             case 'F': c->flags |= CMD_FAST; break;
2218*572c4311Sfengbojiang             default: serverPanic("Unsupported command flag"); break;
2219*572c4311Sfengbojiang             }
2220*572c4311Sfengbojiang             f++;
2221*572c4311Sfengbojiang         }
2222*572c4311Sfengbojiang 
2223*572c4311Sfengbojiang         retval1 = dictAdd(server.commands, sdsnew(c->name), c);
2224*572c4311Sfengbojiang         /* Populate an additional dictionary that will be unaffected
2225*572c4311Sfengbojiang          * by rename-command statements in redis.conf. */
2226*572c4311Sfengbojiang         retval2 = dictAdd(server.orig_commands, sdsnew(c->name), c);
2227*572c4311Sfengbojiang         serverAssert(retval1 == DICT_OK && retval2 == DICT_OK);
2228*572c4311Sfengbojiang     }
2229*572c4311Sfengbojiang }
2230*572c4311Sfengbojiang 
resetCommandTableStats(void)2231*572c4311Sfengbojiang void resetCommandTableStats(void) {
2232*572c4311Sfengbojiang     struct redisCommand *c;
2233*572c4311Sfengbojiang     dictEntry *de;
2234*572c4311Sfengbojiang     dictIterator *di;
2235*572c4311Sfengbojiang 
2236*572c4311Sfengbojiang     di = dictGetSafeIterator(server.commands);
2237*572c4311Sfengbojiang     while((de = dictNext(di)) != NULL) {
2238*572c4311Sfengbojiang         c = (struct redisCommand *) dictGetVal(de);
2239*572c4311Sfengbojiang         c->microseconds = 0;
2240*572c4311Sfengbojiang         c->calls = 0;
2241*572c4311Sfengbojiang     }
2242*572c4311Sfengbojiang     dictReleaseIterator(di);
2243*572c4311Sfengbojiang 
2244*572c4311Sfengbojiang }
2245*572c4311Sfengbojiang 
2246*572c4311Sfengbojiang /* ========================== Redis OP Array API ============================ */
2247*572c4311Sfengbojiang 
redisOpArrayInit(redisOpArray * oa)2248*572c4311Sfengbojiang void redisOpArrayInit(redisOpArray *oa) {
2249*572c4311Sfengbojiang     oa->ops = NULL;
2250*572c4311Sfengbojiang     oa->numops = 0;
2251*572c4311Sfengbojiang }
2252*572c4311Sfengbojiang 
redisOpArrayAppend(redisOpArray * oa,struct redisCommand * cmd,int dbid,robj ** argv,int argc,int target)2253*572c4311Sfengbojiang int redisOpArrayAppend(redisOpArray *oa, struct redisCommand *cmd, int dbid,
2254*572c4311Sfengbojiang                        robj **argv, int argc, int target)
2255*572c4311Sfengbojiang {
2256*572c4311Sfengbojiang     redisOp *op;
2257*572c4311Sfengbojiang 
2258*572c4311Sfengbojiang     oa->ops = zrealloc(oa->ops,sizeof(redisOp)*(oa->numops+1));
2259*572c4311Sfengbojiang     op = oa->ops+oa->numops;
2260*572c4311Sfengbojiang     op->cmd = cmd;
2261*572c4311Sfengbojiang     op->dbid = dbid;
2262*572c4311Sfengbojiang     op->argv = argv;
2263*572c4311Sfengbojiang     op->argc = argc;
2264*572c4311Sfengbojiang     op->target = target;
2265*572c4311Sfengbojiang     oa->numops++;
2266*572c4311Sfengbojiang     return oa->numops;
2267*572c4311Sfengbojiang }
2268*572c4311Sfengbojiang 
redisOpArrayFree(redisOpArray * oa)2269*572c4311Sfengbojiang void redisOpArrayFree(redisOpArray *oa) {
2270*572c4311Sfengbojiang     while(oa->numops) {
2271*572c4311Sfengbojiang         int j;
2272*572c4311Sfengbojiang         redisOp *op;
2273*572c4311Sfengbojiang 
2274*572c4311Sfengbojiang         oa->numops--;
2275*572c4311Sfengbojiang         op = oa->ops+oa->numops;
2276*572c4311Sfengbojiang         for (j = 0; j < op->argc; j++)
2277*572c4311Sfengbojiang             decrRefCount(op->argv[j]);
2278*572c4311Sfengbojiang         zfree(op->argv);
2279*572c4311Sfengbojiang     }
2280*572c4311Sfengbojiang     zfree(oa->ops);
2281*572c4311Sfengbojiang }
2282*572c4311Sfengbojiang 
2283*572c4311Sfengbojiang /* ====================== Commands lookup and execution ===================== */
2284*572c4311Sfengbojiang 
lookupCommand(sds name)2285*572c4311Sfengbojiang struct redisCommand *lookupCommand(sds name) {
2286*572c4311Sfengbojiang     return dictFetchValue(server.commands, name);
2287*572c4311Sfengbojiang }
2288*572c4311Sfengbojiang 
lookupCommandByCString(char * s)2289*572c4311Sfengbojiang struct redisCommand *lookupCommandByCString(char *s) {
2290*572c4311Sfengbojiang     struct redisCommand *cmd;
2291*572c4311Sfengbojiang     sds name = sdsnew(s);
2292*572c4311Sfengbojiang 
2293*572c4311Sfengbojiang     cmd = dictFetchValue(server.commands, name);
2294*572c4311Sfengbojiang     sdsfree(name);
2295*572c4311Sfengbojiang     return cmd;
2296*572c4311Sfengbojiang }
2297*572c4311Sfengbojiang 
2298*572c4311Sfengbojiang /* Lookup the command in the current table, if not found also check in
2299*572c4311Sfengbojiang  * the original table containing the original command names unaffected by
2300*572c4311Sfengbojiang  * redis.conf rename-command statement.
2301*572c4311Sfengbojiang  *
2302*572c4311Sfengbojiang  * This is used by functions rewriting the argument vector such as
2303*572c4311Sfengbojiang  * rewriteClientCommandVector() in order to set client->cmd pointer
2304*572c4311Sfengbojiang  * correctly even if the command was renamed. */
lookupCommandOrOriginal(sds name)2305*572c4311Sfengbojiang struct redisCommand *lookupCommandOrOriginal(sds name) {
2306*572c4311Sfengbojiang     struct redisCommand *cmd = dictFetchValue(server.commands, name);
2307*572c4311Sfengbojiang 
2308*572c4311Sfengbojiang     if (!cmd) cmd = dictFetchValue(server.orig_commands,name);
2309*572c4311Sfengbojiang     return cmd;
2310*572c4311Sfengbojiang }
2311*572c4311Sfengbojiang 
2312*572c4311Sfengbojiang /* Propagate the specified command (in the context of the specified database id)
2313*572c4311Sfengbojiang  * to AOF and Slaves.
2314*572c4311Sfengbojiang  *
2315*572c4311Sfengbojiang  * flags are an xor between:
2316*572c4311Sfengbojiang  * + PROPAGATE_NONE (no propagation of command at all)
2317*572c4311Sfengbojiang  * + PROPAGATE_AOF (propagate into the AOF file if is enabled)
2318*572c4311Sfengbojiang  * + PROPAGATE_REPL (propagate into the replication link)
2319*572c4311Sfengbojiang  *
2320*572c4311Sfengbojiang  * This should not be used inside commands implementation. Use instead
2321*572c4311Sfengbojiang  * alsoPropagate(), preventCommandPropagation(), forceCommandPropagation().
2322*572c4311Sfengbojiang  */
propagate(struct redisCommand * cmd,int dbid,robj ** argv,int argc,int flags)2323*572c4311Sfengbojiang void propagate(struct redisCommand *cmd, int dbid, robj **argv, int argc,
2324*572c4311Sfengbojiang                int flags)
2325*572c4311Sfengbojiang {
2326*572c4311Sfengbojiang     if (server.aof_state != AOF_OFF && flags & PROPAGATE_AOF)
2327*572c4311Sfengbojiang         feedAppendOnlyFile(cmd,dbid,argv,argc);
2328*572c4311Sfengbojiang     if (flags & PROPAGATE_REPL)
2329*572c4311Sfengbojiang         replicationFeedSlaves(server.slaves,dbid,argv,argc);
2330*572c4311Sfengbojiang }
2331*572c4311Sfengbojiang 
2332*572c4311Sfengbojiang /* Used inside commands to schedule the propagation of additional commands
2333*572c4311Sfengbojiang  * after the current command is propagated to AOF / Replication.
2334*572c4311Sfengbojiang  *
2335*572c4311Sfengbojiang  * 'cmd' must be a pointer to the Redis command to replicate, dbid is the
2336*572c4311Sfengbojiang  * database ID the command should be propagated into.
2337*572c4311Sfengbojiang  * Arguments of the command to propagte are passed as an array of redis
2338*572c4311Sfengbojiang  * objects pointers of len 'argc', using the 'argv' vector.
2339*572c4311Sfengbojiang  *
2340*572c4311Sfengbojiang  * The function does not take a reference to the passed 'argv' vector,
2341*572c4311Sfengbojiang  * so it is up to the caller to release the passed argv (but it is usually
2342*572c4311Sfengbojiang  * stack allocated).  The function autoamtically increments ref count of
2343*572c4311Sfengbojiang  * passed objects, so the caller does not need to. */
alsoPropagate(struct redisCommand * cmd,int dbid,robj ** argv,int argc,int target)2344*572c4311Sfengbojiang void alsoPropagate(struct redisCommand *cmd, int dbid, robj **argv, int argc,
2345*572c4311Sfengbojiang                    int target)
2346*572c4311Sfengbojiang {
2347*572c4311Sfengbojiang     robj **argvcopy;
2348*572c4311Sfengbojiang     int j;
2349*572c4311Sfengbojiang 
2350*572c4311Sfengbojiang     if (server.loading) return; /* No propagation during loading. */
2351*572c4311Sfengbojiang 
2352*572c4311Sfengbojiang     argvcopy = zmalloc(sizeof(robj*)*argc);
2353*572c4311Sfengbojiang     for (j = 0; j < argc; j++) {
2354*572c4311Sfengbojiang         argvcopy[j] = argv[j];
2355*572c4311Sfengbojiang         incrRefCount(argv[j]);
2356*572c4311Sfengbojiang     }
2357*572c4311Sfengbojiang     redisOpArrayAppend(&server.also_propagate,cmd,dbid,argvcopy,argc,target);
2358*572c4311Sfengbojiang }
2359*572c4311Sfengbojiang 
2360*572c4311Sfengbojiang /* It is possible to call the function forceCommandPropagation() inside a
2361*572c4311Sfengbojiang  * Redis command implementation in order to to force the propagation of a
2362*572c4311Sfengbojiang  * specific command execution into AOF / Replication. */
forceCommandPropagation(client * c,int flags)2363*572c4311Sfengbojiang void forceCommandPropagation(client *c, int flags) {
2364*572c4311Sfengbojiang     if (flags & PROPAGATE_REPL) c->flags |= CLIENT_FORCE_REPL;
2365*572c4311Sfengbojiang     if (flags & PROPAGATE_AOF) c->flags |= CLIENT_FORCE_AOF;
2366*572c4311Sfengbojiang }
2367*572c4311Sfengbojiang 
2368*572c4311Sfengbojiang /* Avoid that the executed command is propagated at all. This way we
2369*572c4311Sfengbojiang  * are free to just propagate what we want using the alsoPropagate()
2370*572c4311Sfengbojiang  * API. */
preventCommandPropagation(client * c)2371*572c4311Sfengbojiang void preventCommandPropagation(client *c) {
2372*572c4311Sfengbojiang     c->flags |= CLIENT_PREVENT_PROP;
2373*572c4311Sfengbojiang }
2374*572c4311Sfengbojiang 
2375*572c4311Sfengbojiang /* AOF specific version of preventCommandPropagation(). */
preventCommandAOF(client * c)2376*572c4311Sfengbojiang void preventCommandAOF(client *c) {
2377*572c4311Sfengbojiang     c->flags |= CLIENT_PREVENT_AOF_PROP;
2378*572c4311Sfengbojiang }
2379*572c4311Sfengbojiang 
2380*572c4311Sfengbojiang /* Replication specific version of preventCommandPropagation(). */
preventCommandReplication(client * c)2381*572c4311Sfengbojiang void preventCommandReplication(client *c) {
2382*572c4311Sfengbojiang     c->flags |= CLIENT_PREVENT_REPL_PROP;
2383*572c4311Sfengbojiang }
2384*572c4311Sfengbojiang 
2385*572c4311Sfengbojiang /* Call() is the core of Redis execution of a command.
2386*572c4311Sfengbojiang  *
2387*572c4311Sfengbojiang  * The following flags can be passed:
2388*572c4311Sfengbojiang  * CMD_CALL_NONE        No flags.
2389*572c4311Sfengbojiang  * CMD_CALL_SLOWLOG     Check command speed and log in the slow log if needed.
2390*572c4311Sfengbojiang  * CMD_CALL_STATS       Populate command stats.
2391*572c4311Sfengbojiang  * CMD_CALL_PROPAGATE_AOF   Append command to AOF if it modified the dataset
2392*572c4311Sfengbojiang  *                          or if the client flags are forcing propagation.
2393*572c4311Sfengbojiang  * CMD_CALL_PROPAGATE_REPL  Send command to salves if it modified the dataset
2394*572c4311Sfengbojiang  *                          or if the client flags are forcing propagation.
2395*572c4311Sfengbojiang  * CMD_CALL_PROPAGATE   Alias for PROPAGATE_AOF|PROPAGATE_REPL.
2396*572c4311Sfengbojiang  * CMD_CALL_FULL        Alias for SLOWLOG|STATS|PROPAGATE.
2397*572c4311Sfengbojiang  *
2398*572c4311Sfengbojiang  * The exact propagation behavior depends on the client flags.
2399*572c4311Sfengbojiang  * Specifically:
2400*572c4311Sfengbojiang  *
2401*572c4311Sfengbojiang  * 1. If the client flags CLIENT_FORCE_AOF or CLIENT_FORCE_REPL are set
2402*572c4311Sfengbojiang  *    and assuming the corresponding CMD_CALL_PROPAGATE_AOF/REPL is set
2403*572c4311Sfengbojiang  *    in the call flags, then the command is propagated even if the
2404*572c4311Sfengbojiang  *    dataset was not affected by the command.
2405*572c4311Sfengbojiang  * 2. If the client flags CLIENT_PREVENT_REPL_PROP or CLIENT_PREVENT_AOF_PROP
2406*572c4311Sfengbojiang  *    are set, the propagation into AOF or to slaves is not performed even
2407*572c4311Sfengbojiang  *    if the command modified the dataset.
2408*572c4311Sfengbojiang  *
2409*572c4311Sfengbojiang  * Note that regardless of the client flags, if CMD_CALL_PROPAGATE_AOF
2410*572c4311Sfengbojiang  * or CMD_CALL_PROPAGATE_REPL are not set, then respectively AOF or
2411*572c4311Sfengbojiang  * slaves propagation will never occur.
2412*572c4311Sfengbojiang  *
2413*572c4311Sfengbojiang  * Client flags are modified by the implementation of a given command
2414*572c4311Sfengbojiang  * using the following API:
2415*572c4311Sfengbojiang  *
2416*572c4311Sfengbojiang  * forceCommandPropagation(client *c, int flags);
2417*572c4311Sfengbojiang  * preventCommandPropagation(client *c);
2418*572c4311Sfengbojiang  * preventCommandAOF(client *c);
2419*572c4311Sfengbojiang  * preventCommandReplication(client *c);
2420*572c4311Sfengbojiang  *
2421*572c4311Sfengbojiang  */
call(client * c,int flags)2422*572c4311Sfengbojiang void call(client *c, int flags) {
2423*572c4311Sfengbojiang     long long dirty, start, duration;
2424*572c4311Sfengbojiang     int client_old_flags = c->flags;
2425*572c4311Sfengbojiang     struct redisCommand *real_cmd = c->cmd;
2426*572c4311Sfengbojiang 
2427*572c4311Sfengbojiang     /* Sent the command to clients in MONITOR mode, only if the commands are
2428*572c4311Sfengbojiang      * not generated from reading an AOF. */
2429*572c4311Sfengbojiang     if (listLength(server.monitors) &&
2430*572c4311Sfengbojiang         !server.loading &&
2431*572c4311Sfengbojiang         !(c->cmd->flags & (CMD_SKIP_MONITOR|CMD_ADMIN)))
2432*572c4311Sfengbojiang     {
2433*572c4311Sfengbojiang         replicationFeedMonitors(c,server.monitors,c->db->id,c->argv,c->argc);
2434*572c4311Sfengbojiang     }
2435*572c4311Sfengbojiang 
2436*572c4311Sfengbojiang     /* Initialization: clear the flags that must be set by the command on
2437*572c4311Sfengbojiang      * demand, and initialize the array for additional commands propagation. */
2438*572c4311Sfengbojiang     c->flags &= ~(CLIENT_FORCE_AOF|CLIENT_FORCE_REPL|CLIENT_PREVENT_PROP);
2439*572c4311Sfengbojiang     redisOpArray prev_also_propagate = server.also_propagate;
2440*572c4311Sfengbojiang     redisOpArrayInit(&server.also_propagate);
2441*572c4311Sfengbojiang 
2442*572c4311Sfengbojiang     /* Call the command. */
2443*572c4311Sfengbojiang     dirty = server.dirty;
2444*572c4311Sfengbojiang     start = ustime();
2445*572c4311Sfengbojiang     c->cmd->proc(c);
2446*572c4311Sfengbojiang     duration = ustime()-start;
2447*572c4311Sfengbojiang     dirty = server.dirty-dirty;
2448*572c4311Sfengbojiang     if (dirty < 0) dirty = 0;
2449*572c4311Sfengbojiang 
2450*572c4311Sfengbojiang     /* When EVAL is called loading the AOF we don't want commands called
2451*572c4311Sfengbojiang      * from Lua to go into the slowlog or to populate statistics. */
2452*572c4311Sfengbojiang     if (server.loading && c->flags & CLIENT_LUA)
2453*572c4311Sfengbojiang         flags &= ~(CMD_CALL_SLOWLOG | CMD_CALL_STATS);
2454*572c4311Sfengbojiang 
2455*572c4311Sfengbojiang     /* If the caller is Lua, we want to force the EVAL caller to propagate
2456*572c4311Sfengbojiang      * the script if the command flag or client flag are forcing the
2457*572c4311Sfengbojiang      * propagation. */
2458*572c4311Sfengbojiang     if (c->flags & CLIENT_LUA && server.lua_caller) {
2459*572c4311Sfengbojiang         if (c->flags & CLIENT_FORCE_REPL)
2460*572c4311Sfengbojiang             server.lua_caller->flags |= CLIENT_FORCE_REPL;
2461*572c4311Sfengbojiang         if (c->flags & CLIENT_FORCE_AOF)
2462*572c4311Sfengbojiang             server.lua_caller->flags |= CLIENT_FORCE_AOF;
2463*572c4311Sfengbojiang     }
2464*572c4311Sfengbojiang 
2465*572c4311Sfengbojiang     /* Log the command into the Slow log if needed, and populate the
2466*572c4311Sfengbojiang      * per-command statistics that we show in INFO commandstats. */
2467*572c4311Sfengbojiang     if (flags & CMD_CALL_SLOWLOG && c->cmd->proc != execCommand) {
2468*572c4311Sfengbojiang         char *latency_event = (c->cmd->flags & CMD_FAST) ?
2469*572c4311Sfengbojiang                               "fast-command" : "command";
2470*572c4311Sfengbojiang         latencyAddSampleIfNeeded(latency_event,duration/1000);
2471*572c4311Sfengbojiang         slowlogPushEntryIfNeeded(c,c->argv,c->argc,duration);
2472*572c4311Sfengbojiang     }
2473*572c4311Sfengbojiang     if (flags & CMD_CALL_STATS) {
2474*572c4311Sfengbojiang         /* use the real command that was executed (cmd and lastamc) may be
2475*572c4311Sfengbojiang          * different, in case of MULTI-EXEC or re-written commands such as
2476*572c4311Sfengbojiang          * EXPIRE, GEOADD, etc. */
2477*572c4311Sfengbojiang         real_cmd->microseconds += duration;
2478*572c4311Sfengbojiang         real_cmd->calls++;
2479*572c4311Sfengbojiang     }
2480*572c4311Sfengbojiang 
2481*572c4311Sfengbojiang     /* Propagate the command into the AOF and replication link */
2482*572c4311Sfengbojiang     if (flags & CMD_CALL_PROPAGATE &&
2483*572c4311Sfengbojiang         (c->flags & CLIENT_PREVENT_PROP) != CLIENT_PREVENT_PROP)
2484*572c4311Sfengbojiang     {
2485*572c4311Sfengbojiang         int propagate_flags = PROPAGATE_NONE;
2486*572c4311Sfengbojiang 
2487*572c4311Sfengbojiang         /* Check if the command operated changes in the data set. If so
2488*572c4311Sfengbojiang          * set for replication / AOF propagation. */
2489*572c4311Sfengbojiang         if (dirty) propagate_flags |= (PROPAGATE_AOF|PROPAGATE_REPL);
2490*572c4311Sfengbojiang 
2491*572c4311Sfengbojiang         /* If the client forced AOF / replication of the command, set
2492*572c4311Sfengbojiang          * the flags regardless of the command effects on the data set. */
2493*572c4311Sfengbojiang         if (c->flags & CLIENT_FORCE_REPL) propagate_flags |= PROPAGATE_REPL;
2494*572c4311Sfengbojiang         if (c->flags & CLIENT_FORCE_AOF) propagate_flags |= PROPAGATE_AOF;
2495*572c4311Sfengbojiang 
2496*572c4311Sfengbojiang         /* However prevent AOF / replication propagation if the command
2497*572c4311Sfengbojiang          * implementations called preventCommandPropagation() or similar,
2498*572c4311Sfengbojiang          * or if we don't have the call() flags to do so. */
2499*572c4311Sfengbojiang         if (c->flags & CLIENT_PREVENT_REPL_PROP ||
2500*572c4311Sfengbojiang             !(flags & CMD_CALL_PROPAGATE_REPL))
2501*572c4311Sfengbojiang                 propagate_flags &= ~PROPAGATE_REPL;
2502*572c4311Sfengbojiang         if (c->flags & CLIENT_PREVENT_AOF_PROP ||
2503*572c4311Sfengbojiang             !(flags & CMD_CALL_PROPAGATE_AOF))
2504*572c4311Sfengbojiang                 propagate_flags &= ~PROPAGATE_AOF;
2505*572c4311Sfengbojiang 
2506*572c4311Sfengbojiang         /* Call propagate() only if at least one of AOF / replication
2507*572c4311Sfengbojiang          * propagation is needed. Note that modules commands handle replication
2508*572c4311Sfengbojiang          * in an explicit way, so we never replicate them automatically. */
2509*572c4311Sfengbojiang         if (propagate_flags != PROPAGATE_NONE && !(c->cmd->flags & CMD_MODULE))
2510*572c4311Sfengbojiang             propagate(c->cmd,c->db->id,c->argv,c->argc,propagate_flags);
2511*572c4311Sfengbojiang     }
2512*572c4311Sfengbojiang 
2513*572c4311Sfengbojiang     /* Restore the old replication flags, since call() can be executed
2514*572c4311Sfengbojiang      * recursively. */
2515*572c4311Sfengbojiang     c->flags &= ~(CLIENT_FORCE_AOF|CLIENT_FORCE_REPL|CLIENT_PREVENT_PROP);
2516*572c4311Sfengbojiang     c->flags |= client_old_flags &
2517*572c4311Sfengbojiang         (CLIENT_FORCE_AOF|CLIENT_FORCE_REPL|CLIENT_PREVENT_PROP);
2518*572c4311Sfengbojiang 
2519*572c4311Sfengbojiang     /* Handle the alsoPropagate() API to handle commands that want to propagate
2520*572c4311Sfengbojiang      * multiple separated commands. Note that alsoPropagate() is not affected
2521*572c4311Sfengbojiang      * by CLIENT_PREVENT_PROP flag. */
2522*572c4311Sfengbojiang     if (server.also_propagate.numops) {
2523*572c4311Sfengbojiang         int j;
2524*572c4311Sfengbojiang         redisOp *rop;
2525*572c4311Sfengbojiang 
2526*572c4311Sfengbojiang         if (flags & CMD_CALL_PROPAGATE) {
2527*572c4311Sfengbojiang             for (j = 0; j < server.also_propagate.numops; j++) {
2528*572c4311Sfengbojiang                 rop = &server.also_propagate.ops[j];
2529*572c4311Sfengbojiang                 int target = rop->target;
2530*572c4311Sfengbojiang                 /* Whatever the command wish is, we honor the call() flags. */
2531*572c4311Sfengbojiang                 if (!(flags&CMD_CALL_PROPAGATE_AOF)) target &= ~PROPAGATE_AOF;
2532*572c4311Sfengbojiang                 if (!(flags&CMD_CALL_PROPAGATE_REPL)) target &= ~PROPAGATE_REPL;
2533*572c4311Sfengbojiang                 if (target)
2534*572c4311Sfengbojiang                     propagate(rop->cmd,rop->dbid,rop->argv,rop->argc,target);
2535*572c4311Sfengbojiang             }
2536*572c4311Sfengbojiang         }
2537*572c4311Sfengbojiang         redisOpArrayFree(&server.also_propagate);
2538*572c4311Sfengbojiang     }
2539*572c4311Sfengbojiang     server.also_propagate = prev_also_propagate;
2540*572c4311Sfengbojiang     server.stat_numcommands++;
2541*572c4311Sfengbojiang }
2542*572c4311Sfengbojiang 
2543*572c4311Sfengbojiang /* If this function gets called we already read a whole
2544*572c4311Sfengbojiang  * command, arguments are in the client argv/argc fields.
2545*572c4311Sfengbojiang  * processCommand() execute the command or prepare the
2546*572c4311Sfengbojiang  * server for a bulk read from the client.
2547*572c4311Sfengbojiang  *
2548*572c4311Sfengbojiang  * If C_OK is returned the client is still alive and valid and
2549*572c4311Sfengbojiang  * other operations can be performed by the caller. Otherwise
2550*572c4311Sfengbojiang  * if C_ERR is returned the client was destroyed (i.e. after QUIT). */
processCommand(client * c)2551*572c4311Sfengbojiang int processCommand(client *c) {
2552*572c4311Sfengbojiang     moduleCallCommandFilters(c);
2553*572c4311Sfengbojiang 
2554*572c4311Sfengbojiang     /* The QUIT command is handled separately. Normal command procs will
2555*572c4311Sfengbojiang      * go through checking for replication and QUIT will cause trouble
2556*572c4311Sfengbojiang      * when FORCE_REPLICATION is enabled and would be implemented in
2557*572c4311Sfengbojiang      * a regular command proc. */
2558*572c4311Sfengbojiang     if (!strcasecmp(c->argv[0]->ptr,"quit")) {
2559*572c4311Sfengbojiang         addReply(c,shared.ok);
2560*572c4311Sfengbojiang         c->flags |= CLIENT_CLOSE_AFTER_REPLY;
2561*572c4311Sfengbojiang         return C_ERR;
2562*572c4311Sfengbojiang     }
2563*572c4311Sfengbojiang 
2564*572c4311Sfengbojiang     /* Now lookup the command and check ASAP about trivial error conditions
2565*572c4311Sfengbojiang      * such as wrong arity, bad command name and so forth. */
2566*572c4311Sfengbojiang     c->cmd = c->lastcmd = lookupCommand(c->argv[0]->ptr);
2567*572c4311Sfengbojiang     if (!c->cmd) {
2568*572c4311Sfengbojiang         flagTransaction(c);
2569*572c4311Sfengbojiang         sds args = sdsempty();
2570*572c4311Sfengbojiang         int i;
2571*572c4311Sfengbojiang         for (i=1; i < c->argc && sdslen(args) < 128; i++)
2572*572c4311Sfengbojiang             args = sdscatprintf(args, "`%.*s`, ", 128-(int)sdslen(args), (char*)c->argv[i]->ptr);
2573*572c4311Sfengbojiang         addReplyErrorFormat(c,"unknown command `%s`, with args beginning with: %s",
2574*572c4311Sfengbojiang             (char*)c->argv[0]->ptr, args);
2575*572c4311Sfengbojiang         sdsfree(args);
2576*572c4311Sfengbojiang         return C_OK;
2577*572c4311Sfengbojiang     } else if ((c->cmd->arity > 0 && c->cmd->arity != c->argc) ||
2578*572c4311Sfengbojiang                (c->argc < -c->cmd->arity)) {
2579*572c4311Sfengbojiang         flagTransaction(c);
2580*572c4311Sfengbojiang         addReplyErrorFormat(c,"wrong number of arguments for '%s' command",
2581*572c4311Sfengbojiang             c->cmd->name);
2582*572c4311Sfengbojiang         return C_OK;
2583*572c4311Sfengbojiang     }
2584*572c4311Sfengbojiang 
2585*572c4311Sfengbojiang     /* Check if the user is authenticated */
2586*572c4311Sfengbojiang     if (server.requirepass && !c->authenticated && c->cmd->proc != authCommand)
2587*572c4311Sfengbojiang     {
2588*572c4311Sfengbojiang         flagTransaction(c);
2589*572c4311Sfengbojiang         addReply(c,shared.noautherr);
2590*572c4311Sfengbojiang         return C_OK;
2591*572c4311Sfengbojiang     }
2592*572c4311Sfengbojiang 
2593*572c4311Sfengbojiang     /* If cluster is enabled perform the cluster redirection here.
2594*572c4311Sfengbojiang      * However we don't perform the redirection if:
2595*572c4311Sfengbojiang      * 1) The sender of this command is our master.
2596*572c4311Sfengbojiang      * 2) The command has no key arguments. */
2597*572c4311Sfengbojiang     if (server.cluster_enabled &&
2598*572c4311Sfengbojiang         !(c->flags & CLIENT_MASTER) &&
2599*572c4311Sfengbojiang         !(c->flags & CLIENT_LUA &&
2600*572c4311Sfengbojiang           server.lua_caller->flags & CLIENT_MASTER) &&
2601*572c4311Sfengbojiang         !(c->cmd->getkeys_proc == NULL && c->cmd->firstkey == 0 &&
2602*572c4311Sfengbojiang           c->cmd->proc != execCommand))
2603*572c4311Sfengbojiang     {
2604*572c4311Sfengbojiang         int hashslot;
2605*572c4311Sfengbojiang         int error_code;
2606*572c4311Sfengbojiang         clusterNode *n = getNodeByQuery(c,c->cmd,c->argv,c->argc,
2607*572c4311Sfengbojiang                                         &hashslot,&error_code);
2608*572c4311Sfengbojiang         if (n == NULL || n != server.cluster->myself) {
2609*572c4311Sfengbojiang             if (c->cmd->proc == execCommand) {
2610*572c4311Sfengbojiang                 discardTransaction(c);
2611*572c4311Sfengbojiang             } else {
2612*572c4311Sfengbojiang                 flagTransaction(c);
2613*572c4311Sfengbojiang             }
2614*572c4311Sfengbojiang             clusterRedirectClient(c,n,hashslot,error_code);
2615*572c4311Sfengbojiang             return C_OK;
2616*572c4311Sfengbojiang         }
2617*572c4311Sfengbojiang     }
2618*572c4311Sfengbojiang 
2619*572c4311Sfengbojiang     /* Handle the maxmemory directive.
2620*572c4311Sfengbojiang      *
2621*572c4311Sfengbojiang      * Note that we do not want to reclaim memory if we are here re-entering
2622*572c4311Sfengbojiang      * the event loop since there is a busy Lua script running in timeout
2623*572c4311Sfengbojiang      * condition, to avoid mixing the propagation of scripts with the
2624*572c4311Sfengbojiang      * propagation of DELs due to eviction. */
2625*572c4311Sfengbojiang     if (server.maxmemory && !server.lua_timedout) {
2626*572c4311Sfengbojiang         int out_of_memory = freeMemoryIfNeededAndSafe() == C_ERR;
2627*572c4311Sfengbojiang         /* freeMemoryIfNeeded may flush slave output buffers. This may result
2628*572c4311Sfengbojiang          * into a slave, that may be the active client, to be freed. */
2629*572c4311Sfengbojiang         if (server.current_client == NULL) return C_ERR;
2630*572c4311Sfengbojiang 
2631*572c4311Sfengbojiang         /* It was impossible to free enough memory, and the command the client
2632*572c4311Sfengbojiang          * is trying to execute is denied during OOM conditions or the client
2633*572c4311Sfengbojiang          * is in MULTI/EXEC context? Error. */
2634*572c4311Sfengbojiang         if (out_of_memory &&
2635*572c4311Sfengbojiang             (c->cmd->flags & CMD_DENYOOM ||
2636*572c4311Sfengbojiang              (c->flags & CLIENT_MULTI && c->cmd->proc != execCommand))) {
2637*572c4311Sfengbojiang             flagTransaction(c);
2638*572c4311Sfengbojiang             addReply(c, shared.oomerr);
2639*572c4311Sfengbojiang             return C_OK;
2640*572c4311Sfengbojiang         }
2641*572c4311Sfengbojiang     }
2642*572c4311Sfengbojiang 
2643*572c4311Sfengbojiang     /* Don't accept write commands if there are problems persisting on disk
2644*572c4311Sfengbojiang      * and if this is a master instance. */
2645*572c4311Sfengbojiang     int deny_write_type = writeCommandsDeniedByDiskError();
2646*572c4311Sfengbojiang     if (deny_write_type != DISK_ERROR_TYPE_NONE &&
2647*572c4311Sfengbojiang         server.masterhost == NULL &&
2648*572c4311Sfengbojiang         (c->cmd->flags & CMD_WRITE ||
2649*572c4311Sfengbojiang          c->cmd->proc == pingCommand))
2650*572c4311Sfengbojiang     {
2651*572c4311Sfengbojiang         flagTransaction(c);
2652*572c4311Sfengbojiang         if (deny_write_type == DISK_ERROR_TYPE_RDB)
2653*572c4311Sfengbojiang             addReply(c, shared.bgsaveerr);
2654*572c4311Sfengbojiang         else
2655*572c4311Sfengbojiang             addReplySds(c,
2656*572c4311Sfengbojiang                 sdscatprintf(sdsempty(),
2657*572c4311Sfengbojiang                 "-MISCONF Errors writing to the AOF file: %s\r\n",
2658*572c4311Sfengbojiang                 strerror(server.aof_last_write_errno)));
2659*572c4311Sfengbojiang         return C_OK;
2660*572c4311Sfengbojiang     }
2661*572c4311Sfengbojiang 
2662*572c4311Sfengbojiang     /* Don't accept write commands if there are not enough good slaves and
2663*572c4311Sfengbojiang      * user configured the min-slaves-to-write option. */
2664*572c4311Sfengbojiang     if (server.masterhost == NULL &&
2665*572c4311Sfengbojiang         server.repl_min_slaves_to_write &&
2666*572c4311Sfengbojiang         server.repl_min_slaves_max_lag &&
2667*572c4311Sfengbojiang         c->cmd->flags & CMD_WRITE &&
2668*572c4311Sfengbojiang         server.repl_good_slaves_count < server.repl_min_slaves_to_write)
2669*572c4311Sfengbojiang     {
2670*572c4311Sfengbojiang         flagTransaction(c);
2671*572c4311Sfengbojiang         addReply(c, shared.noreplicaserr);
2672*572c4311Sfengbojiang         return C_OK;
2673*572c4311Sfengbojiang     }
2674*572c4311Sfengbojiang 
2675*572c4311Sfengbojiang     /* Don't accept write commands if this is a read only slave. But
2676*572c4311Sfengbojiang      * accept write commands if this is our master. */
2677*572c4311Sfengbojiang     if (server.masterhost && server.repl_slave_ro &&
2678*572c4311Sfengbojiang         !(c->flags & CLIENT_MASTER) &&
2679*572c4311Sfengbojiang         c->cmd->flags & CMD_WRITE)
2680*572c4311Sfengbojiang     {
2681*572c4311Sfengbojiang         addReply(c, shared.roslaveerr);
2682*572c4311Sfengbojiang         return C_OK;
2683*572c4311Sfengbojiang     }
2684*572c4311Sfengbojiang 
2685*572c4311Sfengbojiang     /* Only allow SUBSCRIBE and UNSUBSCRIBE in the context of Pub/Sub */
2686*572c4311Sfengbojiang     if (c->flags & CLIENT_PUBSUB &&
2687*572c4311Sfengbojiang         c->cmd->proc != pingCommand &&
2688*572c4311Sfengbojiang         c->cmd->proc != subscribeCommand &&
2689*572c4311Sfengbojiang         c->cmd->proc != unsubscribeCommand &&
2690*572c4311Sfengbojiang         c->cmd->proc != psubscribeCommand &&
2691*572c4311Sfengbojiang         c->cmd->proc != punsubscribeCommand) {
2692*572c4311Sfengbojiang         addReplyError(c,"only (P)SUBSCRIBE / (P)UNSUBSCRIBE / PING / QUIT allowed in this context");
2693*572c4311Sfengbojiang         return C_OK;
2694*572c4311Sfengbojiang     }
2695*572c4311Sfengbojiang 
2696*572c4311Sfengbojiang     /* Only allow commands with flag "t", such as INFO, SLAVEOF and so on,
2697*572c4311Sfengbojiang      * when slave-serve-stale-data is no and we are a slave with a broken
2698*572c4311Sfengbojiang      * link with master. */
2699*572c4311Sfengbojiang     if (server.masterhost && server.repl_state != REPL_STATE_CONNECTED &&
2700*572c4311Sfengbojiang         server.repl_serve_stale_data == 0 &&
2701*572c4311Sfengbojiang         !(c->cmd->flags & CMD_STALE))
2702*572c4311Sfengbojiang     {
2703*572c4311Sfengbojiang         flagTransaction(c);
2704*572c4311Sfengbojiang         addReply(c, shared.masterdownerr);
2705*572c4311Sfengbojiang         return C_OK;
2706*572c4311Sfengbojiang     }
2707*572c4311Sfengbojiang 
2708*572c4311Sfengbojiang     /* Loading DB? Return an error if the command has not the
2709*572c4311Sfengbojiang      * CMD_LOADING flag. */
2710*572c4311Sfengbojiang     if (server.loading && !(c->cmd->flags & CMD_LOADING)) {
2711*572c4311Sfengbojiang         addReply(c, shared.loadingerr);
2712*572c4311Sfengbojiang         return C_OK;
2713*572c4311Sfengbojiang     }
2714*572c4311Sfengbojiang 
2715*572c4311Sfengbojiang     /* Lua script too slow? Only allow a limited number of commands. */
2716*572c4311Sfengbojiang     if (server.lua_timedout &&
2717*572c4311Sfengbojiang           c->cmd->proc != authCommand &&
2718*572c4311Sfengbojiang           c->cmd->proc != replconfCommand &&
2719*572c4311Sfengbojiang         !(c->cmd->proc == shutdownCommand &&
2720*572c4311Sfengbojiang           c->argc == 2 &&
2721*572c4311Sfengbojiang           tolower(((char*)c->argv[1]->ptr)[0]) == 'n') &&
2722*572c4311Sfengbojiang         !(c->cmd->proc == scriptCommand &&
2723*572c4311Sfengbojiang           c->argc == 2 &&
2724*572c4311Sfengbojiang           tolower(((char*)c->argv[1]->ptr)[0]) == 'k'))
2725*572c4311Sfengbojiang     {
2726*572c4311Sfengbojiang         flagTransaction(c);
2727*572c4311Sfengbojiang         addReply(c, shared.slowscripterr);
2728*572c4311Sfengbojiang         return C_OK;
2729*572c4311Sfengbojiang     }
2730*572c4311Sfengbojiang 
2731*572c4311Sfengbojiang     /* Exec the command */
2732*572c4311Sfengbojiang     if (c->flags & CLIENT_MULTI &&
2733*572c4311Sfengbojiang         c->cmd->proc != execCommand && c->cmd->proc != discardCommand &&
2734*572c4311Sfengbojiang         c->cmd->proc != multiCommand && c->cmd->proc != watchCommand)
2735*572c4311Sfengbojiang     {
2736*572c4311Sfengbojiang         queueMultiCommand(c);
2737*572c4311Sfengbojiang         addReply(c,shared.queued);
2738*572c4311Sfengbojiang     } else {
2739*572c4311Sfengbojiang         call(c,CMD_CALL_FULL);
2740*572c4311Sfengbojiang         c->woff = server.master_repl_offset;
2741*572c4311Sfengbojiang         if (listLength(server.ready_keys))
2742*572c4311Sfengbojiang             handleClientsBlockedOnKeys();
2743*572c4311Sfengbojiang     }
2744*572c4311Sfengbojiang     return C_OK;
2745*572c4311Sfengbojiang }
2746*572c4311Sfengbojiang 
2747*572c4311Sfengbojiang /*================================== Shutdown =============================== */
2748*572c4311Sfengbojiang 
2749*572c4311Sfengbojiang /* Close listening sockets. Also unlink the unix domain socket if
2750*572c4311Sfengbojiang  * unlink_unix_socket is non-zero. */
closeListeningSockets(int unlink_unix_socket)2751*572c4311Sfengbojiang void closeListeningSockets(int unlink_unix_socket) {
2752*572c4311Sfengbojiang     int j;
2753*572c4311Sfengbojiang 
2754*572c4311Sfengbojiang     for (j = 0; j < server.ipfd_count; j++) close(server.ipfd[j]);
2755*572c4311Sfengbojiang     if (server.sofd != -1) close(server.sofd);
2756*572c4311Sfengbojiang     if (server.cluster_enabled)
2757*572c4311Sfengbojiang         for (j = 0; j < server.cfd_count; j++) close(server.cfd[j]);
2758*572c4311Sfengbojiang     if (unlink_unix_socket && server.unixsocket) {
2759*572c4311Sfengbojiang         serverLog(LL_NOTICE,"Removing the unix socket file.");
2760*572c4311Sfengbojiang         unlink(server.unixsocket); /* don't care if this fails */
2761*572c4311Sfengbojiang     }
2762*572c4311Sfengbojiang }
2763*572c4311Sfengbojiang 
2764*572c4311Sfengbojiang /* Reset cpu affinity as soon as new process fork().
2765*572c4311Sfengbojiang   * For new process will use same cpu core with redis server. */
resetCpuAffinity(const char * name)2766*572c4311Sfengbojiang void resetCpuAffinity(const char* name)
2767*572c4311Sfengbojiang {
2768*572c4311Sfengbojiang     int j = 0, s = 0;
2769*572c4311Sfengbojiang     cpu_set_t cpuset_frm, cpuset_to;
2770*572c4311Sfengbojiang     pthread_t thread;
2771*572c4311Sfengbojiang #ifdef HAVE_FF_KQUEUE
2772*572c4311Sfengbojiang     thread = pthread_self();
2773*572c4311Sfengbojiang     CPU_ZERO(&cpuset_frm);
2774*572c4311Sfengbojiang     CPU_ZERO(&cpuset_to);
2775*572c4311Sfengbojiang 
2776*572c4311Sfengbojiang     pthread_getaffinity_np(thread, sizeof(cpu_set_t), &cpuset_frm);
2777*572c4311Sfengbojiang     for (j = 0; j < CPU_SETSIZE; j++)
2778*572c4311Sfengbojiang     {
2779*572c4311Sfengbojiang         if ( CPU_ISSET(j, &cpuset_frm) )
2780*572c4311Sfengbojiang             continue;
2781*572c4311Sfengbojiang         CPU_SET(j, &cpuset_to);
2782*572c4311Sfengbojiang     }
2783*572c4311Sfengbojiang     s = pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset_to);
2784*572c4311Sfengbojiang     if (s != 0)
2785*572c4311Sfengbojiang         serverLog(LL_WARNING,"set cpu affinity, failed.");
2786*572c4311Sfengbojiang     if (name!=NULL)
2787*572c4311Sfengbojiang     {
2788*572c4311Sfengbojiang     	pthread_setname_np(thread, name);
2789*572c4311Sfengbojiang     }
2790*572c4311Sfengbojiang #endif
2791*572c4311Sfengbojiang     return;
2792*572c4311Sfengbojiang }
2793*572c4311Sfengbojiang 
prepareForShutdown(int flags)2794*572c4311Sfengbojiang int prepareForShutdown(int flags) {
2795*572c4311Sfengbojiang     int save = flags & SHUTDOWN_SAVE;
2796*572c4311Sfengbojiang     int nosave = flags & SHUTDOWN_NOSAVE;
2797*572c4311Sfengbojiang 
2798*572c4311Sfengbojiang     serverLog(LL_WARNING,"User requested shutdown...");
2799*572c4311Sfengbojiang 
2800*572c4311Sfengbojiang     /* Kill all the Lua debugger forked sessions. */
2801*572c4311Sfengbojiang     ldbKillForkedSessions();
2802*572c4311Sfengbojiang 
2803*572c4311Sfengbojiang     /* Kill the saving child if there is a background saving in progress.
2804*572c4311Sfengbojiang        We want to avoid race conditions, for instance our saving child may
2805*572c4311Sfengbojiang        overwrite the synchronous saving did by SHUTDOWN. */
2806*572c4311Sfengbojiang     if (server.rdb_child_pid != -1) {
2807*572c4311Sfengbojiang         serverLog(LL_WARNING,"There is a child saving an .rdb. Killing it!");
2808*572c4311Sfengbojiang         kill(server.rdb_child_pid,SIGUSR1);
2809*572c4311Sfengbojiang         rdbRemoveTempFile(server.rdb_child_pid);
2810*572c4311Sfengbojiang     }
2811*572c4311Sfengbojiang 
2812*572c4311Sfengbojiang     if (server.aof_state != AOF_OFF) {
2813*572c4311Sfengbojiang         /* Kill the AOF saving child as the AOF we already have may be longer
2814*572c4311Sfengbojiang          * but contains the full dataset anyway. */
2815*572c4311Sfengbojiang         if (server.aof_child_pid != -1) {
2816*572c4311Sfengbojiang             /* If we have AOF enabled but haven't written the AOF yet, don't
2817*572c4311Sfengbojiang              * shutdown or else the dataset will be lost. */
2818*572c4311Sfengbojiang             if (server.aof_state == AOF_WAIT_REWRITE) {
2819*572c4311Sfengbojiang                 serverLog(LL_WARNING, "Writing initial AOF, can't exit.");
2820*572c4311Sfengbojiang                 return C_ERR;
2821*572c4311Sfengbojiang             }
2822*572c4311Sfengbojiang             serverLog(LL_WARNING,
2823*572c4311Sfengbojiang                 "There is a child rewriting the AOF. Killing it!");
2824*572c4311Sfengbojiang             kill(server.aof_child_pid,SIGUSR1);
2825*572c4311Sfengbojiang         }
2826*572c4311Sfengbojiang         /* Append only file: flush buffers and fsync() the AOF at exit */
2827*572c4311Sfengbojiang         serverLog(LL_NOTICE,"Calling fsync() on the AOF file.");
2828*572c4311Sfengbojiang         flushAppendOnlyFile(1);
2829*572c4311Sfengbojiang         redis_fsync(server.aof_fd);
2830*572c4311Sfengbojiang     }
2831*572c4311Sfengbojiang 
2832*572c4311Sfengbojiang     /* Create a new RDB file before exiting. */
2833*572c4311Sfengbojiang     if ((server.saveparamslen > 0 && !nosave) || save) {
2834*572c4311Sfengbojiang         serverLog(LL_NOTICE,"Saving the final RDB snapshot before exiting.");
2835*572c4311Sfengbojiang         /* Snapshotting. Perform a SYNC SAVE and exit */
2836*572c4311Sfengbojiang         rdbSaveInfo rsi, *rsiptr;
2837*572c4311Sfengbojiang         rsiptr = rdbPopulateSaveInfo(&rsi);
2838*572c4311Sfengbojiang         if (rdbSave(server.rdb_filename,rsiptr) != C_OK) {
2839*572c4311Sfengbojiang             /* Ooops.. error saving! The best we can do is to continue
2840*572c4311Sfengbojiang              * operating. Note that if there was a background saving process,
2841*572c4311Sfengbojiang              * in the next cron() Redis will be notified that the background
2842*572c4311Sfengbojiang              * saving aborted, handling special stuff like slaves pending for
2843*572c4311Sfengbojiang              * synchronization... */
2844*572c4311Sfengbojiang             serverLog(LL_WARNING,"Error trying to save the DB, can't exit.");
2845*572c4311Sfengbojiang             return C_ERR;
2846*572c4311Sfengbojiang         }
2847*572c4311Sfengbojiang     }
2848*572c4311Sfengbojiang 
2849*572c4311Sfengbojiang     /* Remove the pid file if possible and needed. */
2850*572c4311Sfengbojiang     if (server.daemonize || server.pidfile) {
2851*572c4311Sfengbojiang         serverLog(LL_NOTICE,"Removing the pid file.");
2852*572c4311Sfengbojiang         unlink(server.pidfile);
2853*572c4311Sfengbojiang     }
2854*572c4311Sfengbojiang 
2855*572c4311Sfengbojiang     /* Best effort flush of slave output buffers, so that we hopefully
2856*572c4311Sfengbojiang      * send them pending writes. */
2857*572c4311Sfengbojiang     flushSlavesOutputBuffers();
2858*572c4311Sfengbojiang 
2859*572c4311Sfengbojiang     /* Close the listening sockets. Apparently this allows faster restarts. */
2860*572c4311Sfengbojiang     closeListeningSockets(1);
2861*572c4311Sfengbojiang     serverLog(LL_WARNING,"%s is now ready to exit, bye bye...",
2862*572c4311Sfengbojiang         server.sentinel_mode ? "Sentinel" : "Redis");
2863*572c4311Sfengbojiang     return C_OK;
2864*572c4311Sfengbojiang }
2865*572c4311Sfengbojiang 
2866*572c4311Sfengbojiang /*================================== Commands =============================== */
2867*572c4311Sfengbojiang 
2868*572c4311Sfengbojiang /* Sometimes Redis cannot accept write commands because there is a perstence
2869*572c4311Sfengbojiang  * error with the RDB or AOF file, and Redis is configured in order to stop
2870*572c4311Sfengbojiang  * accepting writes in such situation. This function returns if such a
2871*572c4311Sfengbojiang  * condition is active, and the type of the condition.
2872*572c4311Sfengbojiang  *
2873*572c4311Sfengbojiang  * Function return values:
2874*572c4311Sfengbojiang  *
2875*572c4311Sfengbojiang  * DISK_ERROR_TYPE_NONE:    No problems, we can accept writes.
2876*572c4311Sfengbojiang  * DISK_ERROR_TYPE_AOF:     Don't accept writes: AOF errors.
2877*572c4311Sfengbojiang  * DISK_ERROR_TYPE_RDB:     Don't accept writes: RDB errors.
2878*572c4311Sfengbojiang  */
writeCommandsDeniedByDiskError(void)2879*572c4311Sfengbojiang int writeCommandsDeniedByDiskError(void) {
2880*572c4311Sfengbojiang     if (server.stop_writes_on_bgsave_err &&
2881*572c4311Sfengbojiang         server.saveparamslen > 0 &&
2882*572c4311Sfengbojiang         server.lastbgsave_status == C_ERR)
2883*572c4311Sfengbojiang     {
2884*572c4311Sfengbojiang         return DISK_ERROR_TYPE_RDB;
2885*572c4311Sfengbojiang     } else if (server.aof_state != AOF_OFF &&
2886*572c4311Sfengbojiang                server.aof_last_write_status == C_ERR)
2887*572c4311Sfengbojiang     {
2888*572c4311Sfengbojiang         return DISK_ERROR_TYPE_AOF;
2889*572c4311Sfengbojiang     } else {
2890*572c4311Sfengbojiang         return DISK_ERROR_TYPE_NONE;
2891*572c4311Sfengbojiang     }
2892*572c4311Sfengbojiang }
2893*572c4311Sfengbojiang 
2894*572c4311Sfengbojiang /* Return zero if strings are the same, non-zero if they are not.
2895*572c4311Sfengbojiang  * The comparison is performed in a way that prevents an attacker to obtain
2896*572c4311Sfengbojiang  * information about the nature of the strings just monitoring the execution
2897*572c4311Sfengbojiang  * time of the function.
2898*572c4311Sfengbojiang  *
2899*572c4311Sfengbojiang  * Note that limiting the comparison length to strings up to 512 bytes we
2900*572c4311Sfengbojiang  * can avoid leaking any information about the password length and any
2901*572c4311Sfengbojiang  * possible branch misprediction related leak.
2902*572c4311Sfengbojiang  */
time_independent_strcmp(char * a,char * b)2903*572c4311Sfengbojiang int time_independent_strcmp(char *a, char *b) {
2904*572c4311Sfengbojiang     char bufa[CONFIG_AUTHPASS_MAX_LEN], bufb[CONFIG_AUTHPASS_MAX_LEN];
2905*572c4311Sfengbojiang     /* The above two strlen perform len(a) + len(b) operations where either
2906*572c4311Sfengbojiang      * a or b are fixed (our password) length, and the difference is only
2907*572c4311Sfengbojiang      * relative to the length of the user provided string, so no information
2908*572c4311Sfengbojiang      * leak is possible in the following two lines of code. */
2909*572c4311Sfengbojiang     unsigned int alen = strlen(a);
2910*572c4311Sfengbojiang     unsigned int blen = strlen(b);
2911*572c4311Sfengbojiang     unsigned int j;
2912*572c4311Sfengbojiang     int diff = 0;
2913*572c4311Sfengbojiang 
2914*572c4311Sfengbojiang     /* We can't compare strings longer than our static buffers.
2915*572c4311Sfengbojiang      * Note that this will never pass the first test in practical circumstances
2916*572c4311Sfengbojiang      * so there is no info leak. */
2917*572c4311Sfengbojiang     if (alen > sizeof(bufa) || blen > sizeof(bufb)) return 1;
2918*572c4311Sfengbojiang 
2919*572c4311Sfengbojiang     memset(bufa,0,sizeof(bufa));        /* Constant time. */
2920*572c4311Sfengbojiang     memset(bufb,0,sizeof(bufb));        /* Constant time. */
2921*572c4311Sfengbojiang     /* Again the time of the following two copies is proportional to
2922*572c4311Sfengbojiang      * len(a) + len(b) so no info is leaked. */
2923*572c4311Sfengbojiang     memcpy(bufa,a,alen);
2924*572c4311Sfengbojiang     memcpy(bufb,b,blen);
2925*572c4311Sfengbojiang 
2926*572c4311Sfengbojiang     /* Always compare all the chars in the two buffers without
2927*572c4311Sfengbojiang      * conditional expressions. */
2928*572c4311Sfengbojiang     for (j = 0; j < sizeof(bufa); j++) {
2929*572c4311Sfengbojiang         diff |= (bufa[j] ^ bufb[j]);
2930*572c4311Sfengbojiang     }
2931*572c4311Sfengbojiang     /* Length must be equal as well. */
2932*572c4311Sfengbojiang     diff |= alen ^ blen;
2933*572c4311Sfengbojiang     return diff; /* If zero strings are the same. */
2934*572c4311Sfengbojiang }
2935*572c4311Sfengbojiang 
authCommand(client * c)2936*572c4311Sfengbojiang void authCommand(client *c) {
2937*572c4311Sfengbojiang     if (!server.requirepass) {
2938*572c4311Sfengbojiang         addReplyError(c,"Client sent AUTH, but no password is set");
2939*572c4311Sfengbojiang     } else if (!time_independent_strcmp(c->argv[1]->ptr, server.requirepass)) {
2940*572c4311Sfengbojiang       c->authenticated = 1;
2941*572c4311Sfengbojiang       addReply(c,shared.ok);
2942*572c4311Sfengbojiang     } else {
2943*572c4311Sfengbojiang       c->authenticated = 0;
2944*572c4311Sfengbojiang       addReplyError(c,"invalid password");
2945*572c4311Sfengbojiang     }
2946*572c4311Sfengbojiang }
2947*572c4311Sfengbojiang 
2948*572c4311Sfengbojiang /* The PING command. It works in a different way if the client is in
2949*572c4311Sfengbojiang  * in Pub/Sub mode. */
pingCommand(client * c)2950*572c4311Sfengbojiang void pingCommand(client *c) {
2951*572c4311Sfengbojiang     /* The command takes zero or one arguments. */
2952*572c4311Sfengbojiang     if (c->argc > 2) {
2953*572c4311Sfengbojiang         addReplyErrorFormat(c,"wrong number of arguments for '%s' command",
2954*572c4311Sfengbojiang             c->cmd->name);
2955*572c4311Sfengbojiang         return;
2956*572c4311Sfengbojiang     }
2957*572c4311Sfengbojiang 
2958*572c4311Sfengbojiang     if (c->flags & CLIENT_PUBSUB) {
2959*572c4311Sfengbojiang         addReply(c,shared.mbulkhdr[2]);
2960*572c4311Sfengbojiang         addReplyBulkCBuffer(c,"pong",4);
2961*572c4311Sfengbojiang         if (c->argc == 1)
2962*572c4311Sfengbojiang             addReplyBulkCBuffer(c,"",0);
2963*572c4311Sfengbojiang         else
2964*572c4311Sfengbojiang             addReplyBulk(c,c->argv[1]);
2965*572c4311Sfengbojiang     } else {
2966*572c4311Sfengbojiang         if (c->argc == 1)
2967*572c4311Sfengbojiang             addReply(c,shared.pong);
2968*572c4311Sfengbojiang         else
2969*572c4311Sfengbojiang             addReplyBulk(c,c->argv[1]);
2970*572c4311Sfengbojiang     }
2971*572c4311Sfengbojiang }
2972*572c4311Sfengbojiang 
echoCommand(client * c)2973*572c4311Sfengbojiang void echoCommand(client *c) {
2974*572c4311Sfengbojiang     addReplyBulk(c,c->argv[1]);
2975*572c4311Sfengbojiang }
2976*572c4311Sfengbojiang 
timeCommand(client * c)2977*572c4311Sfengbojiang void timeCommand(client *c) {
2978*572c4311Sfengbojiang     struct timeval tv;
2979*572c4311Sfengbojiang 
2980*572c4311Sfengbojiang     /* gettimeofday() can only fail if &tv is a bad address so we
2981*572c4311Sfengbojiang      * don't check for errors. */
2982*572c4311Sfengbojiang     gettimeofday(&tv,NULL);
2983*572c4311Sfengbojiang     addReplyMultiBulkLen(c,2);
2984*572c4311Sfengbojiang     addReplyBulkLongLong(c,tv.tv_sec);
2985*572c4311Sfengbojiang     addReplyBulkLongLong(c,tv.tv_usec);
2986*572c4311Sfengbojiang }
2987*572c4311Sfengbojiang 
2988*572c4311Sfengbojiang /* Helper function for addReplyCommand() to output flags. */
addReplyCommandFlag(client * c,struct redisCommand * cmd,int f,char * reply)2989*572c4311Sfengbojiang int addReplyCommandFlag(client *c, struct redisCommand *cmd, int f, char *reply) {
2990*572c4311Sfengbojiang     if (cmd->flags & f) {
2991*572c4311Sfengbojiang         addReplyStatus(c, reply);
2992*572c4311Sfengbojiang         return 1;
2993*572c4311Sfengbojiang     }
2994*572c4311Sfengbojiang     return 0;
2995*572c4311Sfengbojiang }
2996*572c4311Sfengbojiang 
2997*572c4311Sfengbojiang /* Output the representation of a Redis command. Used by the COMMAND command. */
addReplyCommand(client * c,struct redisCommand * cmd)2998*572c4311Sfengbojiang void addReplyCommand(client *c, struct redisCommand *cmd) {
2999*572c4311Sfengbojiang     if (!cmd) {
3000*572c4311Sfengbojiang         addReply(c, shared.nullbulk);
3001*572c4311Sfengbojiang     } else {
3002*572c4311Sfengbojiang         /* We are adding: command name, arg count, flags, first, last, offset */
3003*572c4311Sfengbojiang         addReplyMultiBulkLen(c, 6);
3004*572c4311Sfengbojiang         addReplyBulkCString(c, cmd->name);
3005*572c4311Sfengbojiang         addReplyLongLong(c, cmd->arity);
3006*572c4311Sfengbojiang 
3007*572c4311Sfengbojiang         int flagcount = 0;
3008*572c4311Sfengbojiang         void *flaglen = addDeferredMultiBulkLength(c);
3009*572c4311Sfengbojiang         flagcount += addReplyCommandFlag(c,cmd,CMD_WRITE, "write");
3010*572c4311Sfengbojiang         flagcount += addReplyCommandFlag(c,cmd,CMD_READONLY, "readonly");
3011*572c4311Sfengbojiang         flagcount += addReplyCommandFlag(c,cmd,CMD_DENYOOM, "denyoom");
3012*572c4311Sfengbojiang         flagcount += addReplyCommandFlag(c,cmd,CMD_ADMIN, "admin");
3013*572c4311Sfengbojiang         flagcount += addReplyCommandFlag(c,cmd,CMD_PUBSUB, "pubsub");
3014*572c4311Sfengbojiang         flagcount += addReplyCommandFlag(c,cmd,CMD_NOSCRIPT, "noscript");
3015*572c4311Sfengbojiang         flagcount += addReplyCommandFlag(c,cmd,CMD_RANDOM, "random");
3016*572c4311Sfengbojiang         flagcount += addReplyCommandFlag(c,cmd,CMD_SORT_FOR_SCRIPT,"sort_for_script");
3017*572c4311Sfengbojiang         flagcount += addReplyCommandFlag(c,cmd,CMD_LOADING, "loading");
3018*572c4311Sfengbojiang         flagcount += addReplyCommandFlag(c,cmd,CMD_STALE, "stale");
3019*572c4311Sfengbojiang         flagcount += addReplyCommandFlag(c,cmd,CMD_SKIP_MONITOR, "skip_monitor");
3020*572c4311Sfengbojiang         flagcount += addReplyCommandFlag(c,cmd,CMD_ASKING, "asking");
3021*572c4311Sfengbojiang         flagcount += addReplyCommandFlag(c,cmd,CMD_FAST, "fast");
3022*572c4311Sfengbojiang         if ((cmd->getkeys_proc && !(cmd->flags & CMD_MODULE)) ||
3023*572c4311Sfengbojiang             cmd->flags & CMD_MODULE_GETKEYS)
3024*572c4311Sfengbojiang         {
3025*572c4311Sfengbojiang             addReplyStatus(c, "movablekeys");
3026*572c4311Sfengbojiang             flagcount += 1;
3027*572c4311Sfengbojiang         }
3028*572c4311Sfengbojiang         setDeferredMultiBulkLength(c, flaglen, flagcount);
3029*572c4311Sfengbojiang 
3030*572c4311Sfengbojiang         addReplyLongLong(c, cmd->firstkey);
3031*572c4311Sfengbojiang         addReplyLongLong(c, cmd->lastkey);
3032*572c4311Sfengbojiang         addReplyLongLong(c, cmd->keystep);
3033*572c4311Sfengbojiang     }
3034*572c4311Sfengbojiang }
3035*572c4311Sfengbojiang 
3036*572c4311Sfengbojiang /* COMMAND <subcommand> <args> */
commandCommand(client * c)3037*572c4311Sfengbojiang void commandCommand(client *c) {
3038*572c4311Sfengbojiang     dictIterator *di;
3039*572c4311Sfengbojiang     dictEntry *de;
3040*572c4311Sfengbojiang 
3041*572c4311Sfengbojiang     if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"help")) {
3042*572c4311Sfengbojiang         const char *help[] = {
3043*572c4311Sfengbojiang "(no subcommand) -- Return details about all Redis commands.",
3044*572c4311Sfengbojiang "COUNT -- Return the total number of commands in this Redis server.",
3045*572c4311Sfengbojiang "GETKEYS <full-command> -- Return the keys from a full Redis command.",
3046*572c4311Sfengbojiang "INFO [command-name ...] -- Return details about multiple Redis commands.",
3047*572c4311Sfengbojiang NULL
3048*572c4311Sfengbojiang         };
3049*572c4311Sfengbojiang         addReplyHelp(c, help);
3050*572c4311Sfengbojiang     } else if (c->argc == 1) {
3051*572c4311Sfengbojiang         addReplyMultiBulkLen(c, dictSize(server.commands));
3052*572c4311Sfengbojiang         di = dictGetIterator(server.commands);
3053*572c4311Sfengbojiang         while ((de = dictNext(di)) != NULL) {
3054*572c4311Sfengbojiang             addReplyCommand(c, dictGetVal(de));
3055*572c4311Sfengbojiang         }
3056*572c4311Sfengbojiang         dictReleaseIterator(di);
3057*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr, "info")) {
3058*572c4311Sfengbojiang         int i;
3059*572c4311Sfengbojiang         addReplyMultiBulkLen(c, c->argc-2);
3060*572c4311Sfengbojiang         for (i = 2; i < c->argc; i++) {
3061*572c4311Sfengbojiang             addReplyCommand(c, dictFetchValue(server.commands, c->argv[i]->ptr));
3062*572c4311Sfengbojiang         }
3063*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr, "count") && c->argc == 2) {
3064*572c4311Sfengbojiang         addReplyLongLong(c, dictSize(server.commands));
3065*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr,"getkeys") && c->argc >= 3) {
3066*572c4311Sfengbojiang         struct redisCommand *cmd = lookupCommand(c->argv[2]->ptr);
3067*572c4311Sfengbojiang         int *keys, numkeys, j;
3068*572c4311Sfengbojiang 
3069*572c4311Sfengbojiang         if (!cmd) {
3070*572c4311Sfengbojiang             addReplyError(c,"Invalid command specified");
3071*572c4311Sfengbojiang             return;
3072*572c4311Sfengbojiang         } else if (cmd->getkeys_proc == NULL && cmd->firstkey == 0) {
3073*572c4311Sfengbojiang             addReplyError(c,"The command has no key arguments");
3074*572c4311Sfengbojiang             return;
3075*572c4311Sfengbojiang         } else if ((cmd->arity > 0 && cmd->arity != c->argc-2) ||
3076*572c4311Sfengbojiang                    ((c->argc-2) < -cmd->arity))
3077*572c4311Sfengbojiang         {
3078*572c4311Sfengbojiang             addReplyError(c,"Invalid number of arguments specified for command");
3079*572c4311Sfengbojiang             return;
3080*572c4311Sfengbojiang         }
3081*572c4311Sfengbojiang 
3082*572c4311Sfengbojiang         keys = getKeysFromCommand(cmd,c->argv+2,c->argc-2,&numkeys);
3083*572c4311Sfengbojiang         if (!keys) {
3084*572c4311Sfengbojiang             addReplyError(c,"Invalid arguments specified for command");
3085*572c4311Sfengbojiang         } else {
3086*572c4311Sfengbojiang             addReplyMultiBulkLen(c,numkeys);
3087*572c4311Sfengbojiang             for (j = 0; j < numkeys; j++) addReplyBulk(c,c->argv[keys[j]+2]);
3088*572c4311Sfengbojiang             getKeysFreeResult(keys);
3089*572c4311Sfengbojiang         }
3090*572c4311Sfengbojiang     } else {
3091*572c4311Sfengbojiang         addReplySubcommandSyntaxError(c);
3092*572c4311Sfengbojiang     }
3093*572c4311Sfengbojiang }
3094*572c4311Sfengbojiang 
3095*572c4311Sfengbojiang /* Convert an amount of bytes into a human readable string in the form
3096*572c4311Sfengbojiang  * of 100B, 2G, 100M, 4K, and so forth. */
bytesToHuman(char * s,unsigned long long n)3097*572c4311Sfengbojiang void bytesToHuman(char *s, unsigned long long n) {
3098*572c4311Sfengbojiang     double d;
3099*572c4311Sfengbojiang 
3100*572c4311Sfengbojiang     if (n < 1024) {
3101*572c4311Sfengbojiang         /* Bytes */
3102*572c4311Sfengbojiang         sprintf(s,"%lluB",n);
3103*572c4311Sfengbojiang     } else if (n < (1024*1024)) {
3104*572c4311Sfengbojiang         d = (double)n/(1024);
3105*572c4311Sfengbojiang         sprintf(s,"%.2fK",d);
3106*572c4311Sfengbojiang     } else if (n < (1024LL*1024*1024)) {
3107*572c4311Sfengbojiang         d = (double)n/(1024*1024);
3108*572c4311Sfengbojiang         sprintf(s,"%.2fM",d);
3109*572c4311Sfengbojiang     } else if (n < (1024LL*1024*1024*1024)) {
3110*572c4311Sfengbojiang         d = (double)n/(1024LL*1024*1024);
3111*572c4311Sfengbojiang         sprintf(s,"%.2fG",d);
3112*572c4311Sfengbojiang     } else if (n < (1024LL*1024*1024*1024*1024)) {
3113*572c4311Sfengbojiang         d = (double)n/(1024LL*1024*1024*1024);
3114*572c4311Sfengbojiang         sprintf(s,"%.2fT",d);
3115*572c4311Sfengbojiang     } else if (n < (1024LL*1024*1024*1024*1024*1024)) {
3116*572c4311Sfengbojiang         d = (double)n/(1024LL*1024*1024*1024*1024);
3117*572c4311Sfengbojiang         sprintf(s,"%.2fP",d);
3118*572c4311Sfengbojiang     } else {
3119*572c4311Sfengbojiang         /* Let's hope we never need this */
3120*572c4311Sfengbojiang         sprintf(s,"%lluB",n);
3121*572c4311Sfengbojiang     }
3122*572c4311Sfengbojiang }
3123*572c4311Sfengbojiang 
3124*572c4311Sfengbojiang /* Create the string returned by the INFO command. This is decoupled
3125*572c4311Sfengbojiang  * by the INFO command itself as we need to report the same information
3126*572c4311Sfengbojiang  * on memory corruption problems. */
genRedisInfoString(char * section)3127*572c4311Sfengbojiang sds genRedisInfoString(char *section) {
3128*572c4311Sfengbojiang     sds info = sdsempty();
3129*572c4311Sfengbojiang     time_t uptime = server.unixtime-server.stat_starttime;
3130*572c4311Sfengbojiang     int j;
3131*572c4311Sfengbojiang     struct rusage self_ru, c_ru;
3132*572c4311Sfengbojiang     int allsections = 0, defsections = 0;
3133*572c4311Sfengbojiang     int sections = 0;
3134*572c4311Sfengbojiang 
3135*572c4311Sfengbojiang     if (section == NULL) section = "default";
3136*572c4311Sfengbojiang     allsections = strcasecmp(section,"all") == 0;
3137*572c4311Sfengbojiang     defsections = strcasecmp(section,"default") == 0;
3138*572c4311Sfengbojiang 
3139*572c4311Sfengbojiang     getrusage(RUSAGE_SELF, &self_ru);
3140*572c4311Sfengbojiang     getrusage(RUSAGE_CHILDREN, &c_ru);
3141*572c4311Sfengbojiang 
3142*572c4311Sfengbojiang     /* Server */
3143*572c4311Sfengbojiang     if (allsections || defsections || !strcasecmp(section,"server")) {
3144*572c4311Sfengbojiang         static int call_uname = 1;
3145*572c4311Sfengbojiang         static struct utsname name;
3146*572c4311Sfengbojiang         char *mode;
3147*572c4311Sfengbojiang 
3148*572c4311Sfengbojiang         if (server.cluster_enabled) mode = "cluster";
3149*572c4311Sfengbojiang         else if (server.sentinel_mode) mode = "sentinel";
3150*572c4311Sfengbojiang         else mode = "standalone";
3151*572c4311Sfengbojiang 
3152*572c4311Sfengbojiang         if (sections++) info = sdscat(info,"\r\n");
3153*572c4311Sfengbojiang 
3154*572c4311Sfengbojiang         if (call_uname) {
3155*572c4311Sfengbojiang             /* Uname can be slow and is always the same output. Cache it. */
3156*572c4311Sfengbojiang             uname(&name);
3157*572c4311Sfengbojiang             call_uname = 0;
3158*572c4311Sfengbojiang         }
3159*572c4311Sfengbojiang 
3160*572c4311Sfengbojiang         unsigned int lruclock;
3161*572c4311Sfengbojiang         atomicGet(server.lruclock,lruclock);
3162*572c4311Sfengbojiang         info = sdscatprintf(info,
3163*572c4311Sfengbojiang             "# Server\r\n"
3164*572c4311Sfengbojiang             "redis_version:%s\r\n"
3165*572c4311Sfengbojiang             "redis_git_sha1:%s\r\n"
3166*572c4311Sfengbojiang             "redis_git_dirty:%d\r\n"
3167*572c4311Sfengbojiang             "redis_build_id:%llx\r\n"
3168*572c4311Sfengbojiang             "redis_mode:%s\r\n"
3169*572c4311Sfengbojiang             "os:%s %s %s\r\n"
3170*572c4311Sfengbojiang             "arch_bits:%d\r\n"
3171*572c4311Sfengbojiang             "multiplexing_api:%s\r\n"
3172*572c4311Sfengbojiang             "atomicvar_api:%s\r\n"
3173*572c4311Sfengbojiang             "gcc_version:%d.%d.%d\r\n"
3174*572c4311Sfengbojiang             "process_id:%ld\r\n"
3175*572c4311Sfengbojiang             "run_id:%s\r\n"
3176*572c4311Sfengbojiang             "tcp_port:%d\r\n"
3177*572c4311Sfengbojiang             "uptime_in_seconds:%jd\r\n"
3178*572c4311Sfengbojiang             "uptime_in_days:%jd\r\n"
3179*572c4311Sfengbojiang             "hz:%d\r\n"
3180*572c4311Sfengbojiang             "configured_hz:%d\r\n"
3181*572c4311Sfengbojiang             "lru_clock:%ld\r\n"
3182*572c4311Sfengbojiang             "executable:%s\r\n"
3183*572c4311Sfengbojiang             "config_file:%s\r\n",
3184*572c4311Sfengbojiang             REDIS_VERSION,
3185*572c4311Sfengbojiang             redisGitSHA1(),
3186*572c4311Sfengbojiang             strtol(redisGitDirty(),NULL,10) > 0,
3187*572c4311Sfengbojiang             (unsigned long long) redisBuildId(),
3188*572c4311Sfengbojiang             mode,
3189*572c4311Sfengbojiang             name.sysname, name.release, name.machine,
3190*572c4311Sfengbojiang             server.arch_bits,
3191*572c4311Sfengbojiang             aeGetApiName(),
3192*572c4311Sfengbojiang             REDIS_ATOMIC_API,
3193*572c4311Sfengbojiang #ifdef __GNUC__
3194*572c4311Sfengbojiang             __GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__,
3195*572c4311Sfengbojiang #else
3196*572c4311Sfengbojiang             0,0,0,
3197*572c4311Sfengbojiang #endif
3198*572c4311Sfengbojiang             (long) getpid(),
3199*572c4311Sfengbojiang             server.runid,
3200*572c4311Sfengbojiang             server.port,
3201*572c4311Sfengbojiang             (intmax_t)uptime,
3202*572c4311Sfengbojiang             (intmax_t)(uptime/(3600*24)),
3203*572c4311Sfengbojiang             server.hz,
3204*572c4311Sfengbojiang             server.config_hz,
3205*572c4311Sfengbojiang             (unsigned long) lruclock,
3206*572c4311Sfengbojiang             server.executable ? server.executable : "",
3207*572c4311Sfengbojiang             server.configfile ? server.configfile : "");
3208*572c4311Sfengbojiang     }
3209*572c4311Sfengbojiang 
3210*572c4311Sfengbojiang     /* Clients */
3211*572c4311Sfengbojiang     if (allsections || defsections || !strcasecmp(section,"clients")) {
3212*572c4311Sfengbojiang         size_t maxin, maxout;
3213*572c4311Sfengbojiang         getExpansiveClientsInfo(&maxin,&maxout);
3214*572c4311Sfengbojiang         if (sections++) info = sdscat(info,"\r\n");
3215*572c4311Sfengbojiang         info = sdscatprintf(info,
3216*572c4311Sfengbojiang             "# Clients\r\n"
3217*572c4311Sfengbojiang             "connected_clients:%lu\r\n"
3218*572c4311Sfengbojiang             "client_recent_max_input_buffer:%zu\r\n"
3219*572c4311Sfengbojiang             "client_recent_max_output_buffer:%zu\r\n"
3220*572c4311Sfengbojiang             "blocked_clients:%d\r\n",
3221*572c4311Sfengbojiang             listLength(server.clients)-listLength(server.slaves),
3222*572c4311Sfengbojiang             maxin, maxout,
3223*572c4311Sfengbojiang             server.blocked_clients);
3224*572c4311Sfengbojiang     }
3225*572c4311Sfengbojiang 
3226*572c4311Sfengbojiang     /* Memory */
3227*572c4311Sfengbojiang     if (allsections || defsections || !strcasecmp(section,"memory")) {
3228*572c4311Sfengbojiang         char hmem[64];
3229*572c4311Sfengbojiang         char peak_hmem[64];
3230*572c4311Sfengbojiang         char total_system_hmem[64];
3231*572c4311Sfengbojiang         char used_memory_lua_hmem[64];
3232*572c4311Sfengbojiang         char used_memory_scripts_hmem[64];
3233*572c4311Sfengbojiang         char used_memory_rss_hmem[64];
3234*572c4311Sfengbojiang         char maxmemory_hmem[64];
3235*572c4311Sfengbojiang         size_t zmalloc_used = zmalloc_used_memory();
3236*572c4311Sfengbojiang         size_t total_system_mem = server.system_memory_size;
3237*572c4311Sfengbojiang         const char *evict_policy = evictPolicyToString();
3238*572c4311Sfengbojiang         long long memory_lua = (long long)lua_gc(server.lua,LUA_GCCOUNT,0)*1024;
3239*572c4311Sfengbojiang         struct redisMemOverhead *mh = getMemoryOverheadData();
3240*572c4311Sfengbojiang 
3241*572c4311Sfengbojiang         /* Peak memory is updated from time to time by serverCron() so it
3242*572c4311Sfengbojiang          * may happen that the instantaneous value is slightly bigger than
3243*572c4311Sfengbojiang          * the peak value. This may confuse users, so we update the peak
3244*572c4311Sfengbojiang          * if found smaller than the current memory usage. */
3245*572c4311Sfengbojiang         if (zmalloc_used > server.stat_peak_memory)
3246*572c4311Sfengbojiang             server.stat_peak_memory = zmalloc_used;
3247*572c4311Sfengbojiang 
3248*572c4311Sfengbojiang         bytesToHuman(hmem,zmalloc_used);
3249*572c4311Sfengbojiang         bytesToHuman(peak_hmem,server.stat_peak_memory);
3250*572c4311Sfengbojiang         bytesToHuman(total_system_hmem,total_system_mem);
3251*572c4311Sfengbojiang         bytesToHuman(used_memory_lua_hmem,memory_lua);
3252*572c4311Sfengbojiang         bytesToHuman(used_memory_scripts_hmem,mh->lua_caches);
3253*572c4311Sfengbojiang         bytesToHuman(used_memory_rss_hmem,server.cron_malloc_stats.process_rss);
3254*572c4311Sfengbojiang         bytesToHuman(maxmemory_hmem,server.maxmemory);
3255*572c4311Sfengbojiang 
3256*572c4311Sfengbojiang         if (sections++) info = sdscat(info,"\r\n");
3257*572c4311Sfengbojiang         info = sdscatprintf(info,
3258*572c4311Sfengbojiang             "# Memory\r\n"
3259*572c4311Sfengbojiang             "used_memory:%zu\r\n"
3260*572c4311Sfengbojiang             "used_memory_human:%s\r\n"
3261*572c4311Sfengbojiang             "used_memory_rss:%zu\r\n"
3262*572c4311Sfengbojiang             "used_memory_rss_human:%s\r\n"
3263*572c4311Sfengbojiang             "used_memory_peak:%zu\r\n"
3264*572c4311Sfengbojiang             "used_memory_peak_human:%s\r\n"
3265*572c4311Sfengbojiang             "used_memory_peak_perc:%.2f%%\r\n"
3266*572c4311Sfengbojiang             "used_memory_overhead:%zu\r\n"
3267*572c4311Sfengbojiang             "used_memory_startup:%zu\r\n"
3268*572c4311Sfengbojiang             "used_memory_dataset:%zu\r\n"
3269*572c4311Sfengbojiang             "used_memory_dataset_perc:%.2f%%\r\n"
3270*572c4311Sfengbojiang             "allocator_allocated:%zu\r\n"
3271*572c4311Sfengbojiang             "allocator_active:%zu\r\n"
3272*572c4311Sfengbojiang             "allocator_resident:%zu\r\n"
3273*572c4311Sfengbojiang             "total_system_memory:%lu\r\n"
3274*572c4311Sfengbojiang             "total_system_memory_human:%s\r\n"
3275*572c4311Sfengbojiang             "used_memory_lua:%lld\r\n"
3276*572c4311Sfengbojiang             "used_memory_lua_human:%s\r\n"
3277*572c4311Sfengbojiang             "used_memory_scripts:%lld\r\n"
3278*572c4311Sfengbojiang             "used_memory_scripts_human:%s\r\n"
3279*572c4311Sfengbojiang             "number_of_cached_scripts:%lu\r\n"
3280*572c4311Sfengbojiang             "maxmemory:%lld\r\n"
3281*572c4311Sfengbojiang             "maxmemory_human:%s\r\n"
3282*572c4311Sfengbojiang             "maxmemory_policy:%s\r\n"
3283*572c4311Sfengbojiang             "allocator_frag_ratio:%.2f\r\n"
3284*572c4311Sfengbojiang             "allocator_frag_bytes:%zu\r\n"
3285*572c4311Sfengbojiang             "allocator_rss_ratio:%.2f\r\n"
3286*572c4311Sfengbojiang             "allocator_rss_bytes:%zd\r\n"
3287*572c4311Sfengbojiang             "rss_overhead_ratio:%.2f\r\n"
3288*572c4311Sfengbojiang             "rss_overhead_bytes:%zd\r\n"
3289*572c4311Sfengbojiang             "mem_fragmentation_ratio:%.2f\r\n"
3290*572c4311Sfengbojiang             "mem_fragmentation_bytes:%zd\r\n"
3291*572c4311Sfengbojiang             "mem_not_counted_for_evict:%zu\r\n"
3292*572c4311Sfengbojiang             "mem_replication_backlog:%zu\r\n"
3293*572c4311Sfengbojiang             "mem_clients_slaves:%zu\r\n"
3294*572c4311Sfengbojiang             "mem_clients_normal:%zu\r\n"
3295*572c4311Sfengbojiang             "mem_aof_buffer:%zu\r\n"
3296*572c4311Sfengbojiang             "mem_allocator:%s\r\n"
3297*572c4311Sfengbojiang             "active_defrag_running:%d\r\n"
3298*572c4311Sfengbojiang             "lazyfree_pending_objects:%zu\r\n",
3299*572c4311Sfengbojiang             zmalloc_used,
3300*572c4311Sfengbojiang             hmem,
3301*572c4311Sfengbojiang             server.cron_malloc_stats.process_rss,
3302*572c4311Sfengbojiang             used_memory_rss_hmem,
3303*572c4311Sfengbojiang             server.stat_peak_memory,
3304*572c4311Sfengbojiang             peak_hmem,
3305*572c4311Sfengbojiang             mh->peak_perc,
3306*572c4311Sfengbojiang             mh->overhead_total,
3307*572c4311Sfengbojiang             mh->startup_allocated,
3308*572c4311Sfengbojiang             mh->dataset,
3309*572c4311Sfengbojiang             mh->dataset_perc,
3310*572c4311Sfengbojiang             server.cron_malloc_stats.allocator_allocated,
3311*572c4311Sfengbojiang             server.cron_malloc_stats.allocator_active,
3312*572c4311Sfengbojiang             server.cron_malloc_stats.allocator_resident,
3313*572c4311Sfengbojiang             (unsigned long)total_system_mem,
3314*572c4311Sfengbojiang             total_system_hmem,
3315*572c4311Sfengbojiang             memory_lua,
3316*572c4311Sfengbojiang             used_memory_lua_hmem,
3317*572c4311Sfengbojiang             (long long) mh->lua_caches,
3318*572c4311Sfengbojiang             used_memory_scripts_hmem,
3319*572c4311Sfengbojiang             dictSize(server.lua_scripts),
3320*572c4311Sfengbojiang             server.maxmemory,
3321*572c4311Sfengbojiang             maxmemory_hmem,
3322*572c4311Sfengbojiang             evict_policy,
3323*572c4311Sfengbojiang             mh->allocator_frag,
3324*572c4311Sfengbojiang             mh->allocator_frag_bytes,
3325*572c4311Sfengbojiang             mh->allocator_rss,
3326*572c4311Sfengbojiang             mh->allocator_rss_bytes,
3327*572c4311Sfengbojiang             mh->rss_extra,
3328*572c4311Sfengbojiang             mh->rss_extra_bytes,
3329*572c4311Sfengbojiang             mh->total_frag, /* this is the total RSS overhead, including fragmentation, */
3330*572c4311Sfengbojiang             mh->total_frag_bytes, /* named so for backwards compatibility */
3331*572c4311Sfengbojiang             freeMemoryGetNotCountedMemory(),
3332*572c4311Sfengbojiang             mh->repl_backlog,
3333*572c4311Sfengbojiang             mh->clients_slaves,
3334*572c4311Sfengbojiang             mh->clients_normal,
3335*572c4311Sfengbojiang             mh->aof_buffer,
3336*572c4311Sfengbojiang             ZMALLOC_LIB,
3337*572c4311Sfengbojiang             server.active_defrag_running,
3338*572c4311Sfengbojiang             lazyfreeGetPendingObjectsCount()
3339*572c4311Sfengbojiang         );
3340*572c4311Sfengbojiang         freeMemoryOverheadData(mh);
3341*572c4311Sfengbojiang     }
3342*572c4311Sfengbojiang 
3343*572c4311Sfengbojiang     /* Persistence */
3344*572c4311Sfengbojiang     if (allsections || defsections || !strcasecmp(section,"persistence")) {
3345*572c4311Sfengbojiang         if (sections++) info = sdscat(info,"\r\n");
3346*572c4311Sfengbojiang         info = sdscatprintf(info,
3347*572c4311Sfengbojiang             "# Persistence\r\n"
3348*572c4311Sfengbojiang             "loading:%d\r\n"
3349*572c4311Sfengbojiang             "rdb_changes_since_last_save:%lld\r\n"
3350*572c4311Sfengbojiang             "rdb_bgsave_in_progress:%d\r\n"
3351*572c4311Sfengbojiang             "rdb_last_save_time:%jd\r\n"
3352*572c4311Sfengbojiang             "rdb_last_bgsave_status:%s\r\n"
3353*572c4311Sfengbojiang             "rdb_last_bgsave_time_sec:%jd\r\n"
3354*572c4311Sfengbojiang             "rdb_current_bgsave_time_sec:%jd\r\n"
3355*572c4311Sfengbojiang             "rdb_last_cow_size:%zu\r\n"
3356*572c4311Sfengbojiang             "aof_enabled:%d\r\n"
3357*572c4311Sfengbojiang             "aof_rewrite_in_progress:%d\r\n"
3358*572c4311Sfengbojiang             "aof_rewrite_scheduled:%d\r\n"
3359*572c4311Sfengbojiang             "aof_last_rewrite_time_sec:%jd\r\n"
3360*572c4311Sfengbojiang             "aof_current_rewrite_time_sec:%jd\r\n"
3361*572c4311Sfengbojiang             "aof_last_bgrewrite_status:%s\r\n"
3362*572c4311Sfengbojiang             "aof_last_write_status:%s\r\n"
3363*572c4311Sfengbojiang             "aof_last_cow_size:%zu\r\n",
3364*572c4311Sfengbojiang             server.loading,
3365*572c4311Sfengbojiang             server.dirty,
3366*572c4311Sfengbojiang             server.rdb_child_pid != -1,
3367*572c4311Sfengbojiang             (intmax_t)server.lastsave,
3368*572c4311Sfengbojiang             (server.lastbgsave_status == C_OK) ? "ok" : "err",
3369*572c4311Sfengbojiang             (intmax_t)server.rdb_save_time_last,
3370*572c4311Sfengbojiang             (intmax_t)((server.rdb_child_pid == -1) ?
3371*572c4311Sfengbojiang                 -1 : time(NULL)-server.rdb_save_time_start),
3372*572c4311Sfengbojiang             server.stat_rdb_cow_bytes,
3373*572c4311Sfengbojiang             server.aof_state != AOF_OFF,
3374*572c4311Sfengbojiang             server.aof_child_pid != -1,
3375*572c4311Sfengbojiang             server.aof_rewrite_scheduled,
3376*572c4311Sfengbojiang             (intmax_t)server.aof_rewrite_time_last,
3377*572c4311Sfengbojiang             (intmax_t)((server.aof_child_pid == -1) ?
3378*572c4311Sfengbojiang                 -1 : time(NULL)-server.aof_rewrite_time_start),
3379*572c4311Sfengbojiang             (server.aof_lastbgrewrite_status == C_OK) ? "ok" : "err",
3380*572c4311Sfengbojiang             (server.aof_last_write_status == C_OK) ? "ok" : "err",
3381*572c4311Sfengbojiang             server.stat_aof_cow_bytes);
3382*572c4311Sfengbojiang 
3383*572c4311Sfengbojiang         if (server.aof_state != AOF_OFF) {
3384*572c4311Sfengbojiang             info = sdscatprintf(info,
3385*572c4311Sfengbojiang                 "aof_current_size:%lld\r\n"
3386*572c4311Sfengbojiang                 "aof_base_size:%lld\r\n"
3387*572c4311Sfengbojiang                 "aof_pending_rewrite:%d\r\n"
3388*572c4311Sfengbojiang                 "aof_buffer_length:%zu\r\n"
3389*572c4311Sfengbojiang                 "aof_rewrite_buffer_length:%lu\r\n"
3390*572c4311Sfengbojiang                 "aof_pending_bio_fsync:%llu\r\n"
3391*572c4311Sfengbojiang                 "aof_delayed_fsync:%lu\r\n",
3392*572c4311Sfengbojiang                 (long long) server.aof_current_size,
3393*572c4311Sfengbojiang                 (long long) server.aof_rewrite_base_size,
3394*572c4311Sfengbojiang                 server.aof_rewrite_scheduled,
3395*572c4311Sfengbojiang                 sdslen(server.aof_buf),
3396*572c4311Sfengbojiang                 aofRewriteBufferSize(),
3397*572c4311Sfengbojiang                 bioPendingJobsOfType(BIO_AOF_FSYNC),
3398*572c4311Sfengbojiang                 server.aof_delayed_fsync);
3399*572c4311Sfengbojiang         }
3400*572c4311Sfengbojiang 
3401*572c4311Sfengbojiang         if (server.loading) {
3402*572c4311Sfengbojiang             double perc;
3403*572c4311Sfengbojiang             time_t eta, elapsed;
3404*572c4311Sfengbojiang             off_t remaining_bytes = server.loading_total_bytes-
3405*572c4311Sfengbojiang                                     server.loading_loaded_bytes;
3406*572c4311Sfengbojiang 
3407*572c4311Sfengbojiang             perc = ((double)server.loading_loaded_bytes /
3408*572c4311Sfengbojiang                    (server.loading_total_bytes+1)) * 100;
3409*572c4311Sfengbojiang 
3410*572c4311Sfengbojiang             elapsed = time(NULL)-server.loading_start_time;
3411*572c4311Sfengbojiang             if (elapsed == 0) {
3412*572c4311Sfengbojiang                 eta = 1; /* A fake 1 second figure if we don't have
3413*572c4311Sfengbojiang                             enough info */
3414*572c4311Sfengbojiang             } else {
3415*572c4311Sfengbojiang                 eta = (elapsed*remaining_bytes)/(server.loading_loaded_bytes+1);
3416*572c4311Sfengbojiang             }
3417*572c4311Sfengbojiang 
3418*572c4311Sfengbojiang             info = sdscatprintf(info,
3419*572c4311Sfengbojiang                 "loading_start_time:%jd\r\n"
3420*572c4311Sfengbojiang                 "loading_total_bytes:%llu\r\n"
3421*572c4311Sfengbojiang                 "loading_loaded_bytes:%llu\r\n"
3422*572c4311Sfengbojiang                 "loading_loaded_perc:%.2f\r\n"
3423*572c4311Sfengbojiang                 "loading_eta_seconds:%jd\r\n",
3424*572c4311Sfengbojiang                 (intmax_t) server.loading_start_time,
3425*572c4311Sfengbojiang                 (unsigned long long) server.loading_total_bytes,
3426*572c4311Sfengbojiang                 (unsigned long long) server.loading_loaded_bytes,
3427*572c4311Sfengbojiang                 perc,
3428*572c4311Sfengbojiang                 (intmax_t)eta
3429*572c4311Sfengbojiang             );
3430*572c4311Sfengbojiang         }
3431*572c4311Sfengbojiang     }
3432*572c4311Sfengbojiang 
3433*572c4311Sfengbojiang     /* Stats */
3434*572c4311Sfengbojiang     if (allsections || defsections || !strcasecmp(section,"stats")) {
3435*572c4311Sfengbojiang         if (sections++) info = sdscat(info,"\r\n");
3436*572c4311Sfengbojiang         info = sdscatprintf(info,
3437*572c4311Sfengbojiang             "# Stats\r\n"
3438*572c4311Sfengbojiang             "total_connections_received:%lld\r\n"
3439*572c4311Sfengbojiang             "total_commands_processed:%lld\r\n"
3440*572c4311Sfengbojiang             "instantaneous_ops_per_sec:%lld\r\n"
3441*572c4311Sfengbojiang             "total_net_input_bytes:%lld\r\n"
3442*572c4311Sfengbojiang             "total_net_output_bytes:%lld\r\n"
3443*572c4311Sfengbojiang             "instantaneous_input_kbps:%.2f\r\n"
3444*572c4311Sfengbojiang             "instantaneous_output_kbps:%.2f\r\n"
3445*572c4311Sfengbojiang             "rejected_connections:%lld\r\n"
3446*572c4311Sfengbojiang             "sync_full:%lld\r\n"
3447*572c4311Sfengbojiang             "sync_partial_ok:%lld\r\n"
3448*572c4311Sfengbojiang             "sync_partial_err:%lld\r\n"
3449*572c4311Sfengbojiang             "expired_keys:%lld\r\n"
3450*572c4311Sfengbojiang             "expired_stale_perc:%.2f\r\n"
3451*572c4311Sfengbojiang             "expired_time_cap_reached_count:%lld\r\n"
3452*572c4311Sfengbojiang             "evicted_keys:%lld\r\n"
3453*572c4311Sfengbojiang             "keyspace_hits:%lld\r\n"
3454*572c4311Sfengbojiang             "keyspace_misses:%lld\r\n"
3455*572c4311Sfengbojiang             "pubsub_channels:%ld\r\n"
3456*572c4311Sfengbojiang             "pubsub_patterns:%lu\r\n"
3457*572c4311Sfengbojiang             "latest_fork_usec:%lld\r\n"
3458*572c4311Sfengbojiang             "migrate_cached_sockets:%ld\r\n"
3459*572c4311Sfengbojiang             "slave_expires_tracked_keys:%zu\r\n"
3460*572c4311Sfengbojiang             "active_defrag_hits:%lld\r\n"
3461*572c4311Sfengbojiang             "active_defrag_misses:%lld\r\n"
3462*572c4311Sfengbojiang             "active_defrag_key_hits:%lld\r\n"
3463*572c4311Sfengbojiang             "active_defrag_key_misses:%lld\r\n",
3464*572c4311Sfengbojiang             server.stat_numconnections,
3465*572c4311Sfengbojiang             server.stat_numcommands,
3466*572c4311Sfengbojiang             getInstantaneousMetric(STATS_METRIC_COMMAND),
3467*572c4311Sfengbojiang             server.stat_net_input_bytes,
3468*572c4311Sfengbojiang             server.stat_net_output_bytes,
3469*572c4311Sfengbojiang             (float)getInstantaneousMetric(STATS_METRIC_NET_INPUT)/1024,
3470*572c4311Sfengbojiang             (float)getInstantaneousMetric(STATS_METRIC_NET_OUTPUT)/1024,
3471*572c4311Sfengbojiang             server.stat_rejected_conn,
3472*572c4311Sfengbojiang             server.stat_sync_full,
3473*572c4311Sfengbojiang             server.stat_sync_partial_ok,
3474*572c4311Sfengbojiang             server.stat_sync_partial_err,
3475*572c4311Sfengbojiang             server.stat_expiredkeys,
3476*572c4311Sfengbojiang             server.stat_expired_stale_perc*100,
3477*572c4311Sfengbojiang             server.stat_expired_time_cap_reached_count,
3478*572c4311Sfengbojiang             server.stat_evictedkeys,
3479*572c4311Sfengbojiang             server.stat_keyspace_hits,
3480*572c4311Sfengbojiang             server.stat_keyspace_misses,
3481*572c4311Sfengbojiang             dictSize(server.pubsub_channels),
3482*572c4311Sfengbojiang             listLength(server.pubsub_patterns),
3483*572c4311Sfengbojiang             server.stat_fork_time,
3484*572c4311Sfengbojiang             dictSize(server.migrate_cached_sockets),
3485*572c4311Sfengbojiang             getSlaveKeyWithExpireCount(),
3486*572c4311Sfengbojiang             server.stat_active_defrag_hits,
3487*572c4311Sfengbojiang             server.stat_active_defrag_misses,
3488*572c4311Sfengbojiang             server.stat_active_defrag_key_hits,
3489*572c4311Sfengbojiang             server.stat_active_defrag_key_misses);
3490*572c4311Sfengbojiang     }
3491*572c4311Sfengbojiang 
3492*572c4311Sfengbojiang     /* Replication */
3493*572c4311Sfengbojiang     if (allsections || defsections || !strcasecmp(section,"replication")) {
3494*572c4311Sfengbojiang         if (sections++) info = sdscat(info,"\r\n");
3495*572c4311Sfengbojiang         info = sdscatprintf(info,
3496*572c4311Sfengbojiang             "# Replication\r\n"
3497*572c4311Sfengbojiang             "role:%s\r\n",
3498*572c4311Sfengbojiang             server.masterhost == NULL ? "master" : "slave");
3499*572c4311Sfengbojiang         if (server.masterhost) {
3500*572c4311Sfengbojiang             long long slave_repl_offset = 1;
3501*572c4311Sfengbojiang 
3502*572c4311Sfengbojiang             if (server.master)
3503*572c4311Sfengbojiang                 slave_repl_offset = server.master->reploff;
3504*572c4311Sfengbojiang             else if (server.cached_master)
3505*572c4311Sfengbojiang                 slave_repl_offset = server.cached_master->reploff;
3506*572c4311Sfengbojiang 
3507*572c4311Sfengbojiang             info = sdscatprintf(info,
3508*572c4311Sfengbojiang                 "master_host:%s\r\n"
3509*572c4311Sfengbojiang                 "master_port:%d\r\n"
3510*572c4311Sfengbojiang                 "master_link_status:%s\r\n"
3511*572c4311Sfengbojiang                 "master_last_io_seconds_ago:%d\r\n"
3512*572c4311Sfengbojiang                 "master_sync_in_progress:%d\r\n"
3513*572c4311Sfengbojiang                 "slave_repl_offset:%lld\r\n"
3514*572c4311Sfengbojiang                 ,server.masterhost,
3515*572c4311Sfengbojiang                 server.masterport,
3516*572c4311Sfengbojiang                 (server.repl_state == REPL_STATE_CONNECTED) ?
3517*572c4311Sfengbojiang                     "up" : "down",
3518*572c4311Sfengbojiang                 server.master ?
3519*572c4311Sfengbojiang                 ((int)(server.unixtime-server.master->lastinteraction)) : -1,
3520*572c4311Sfengbojiang                 server.repl_state == REPL_STATE_TRANSFER,
3521*572c4311Sfengbojiang                 slave_repl_offset
3522*572c4311Sfengbojiang             );
3523*572c4311Sfengbojiang 
3524*572c4311Sfengbojiang             if (server.repl_state == REPL_STATE_TRANSFER) {
3525*572c4311Sfengbojiang                 info = sdscatprintf(info,
3526*572c4311Sfengbojiang                     "master_sync_left_bytes:%lld\r\n"
3527*572c4311Sfengbojiang                     "master_sync_last_io_seconds_ago:%d\r\n"
3528*572c4311Sfengbojiang                     , (long long)
3529*572c4311Sfengbojiang                         (server.repl_transfer_size - server.repl_transfer_read),
3530*572c4311Sfengbojiang                     (int)(server.unixtime-server.repl_transfer_lastio)
3531*572c4311Sfengbojiang                 );
3532*572c4311Sfengbojiang             }
3533*572c4311Sfengbojiang 
3534*572c4311Sfengbojiang             if (server.repl_state != REPL_STATE_CONNECTED) {
3535*572c4311Sfengbojiang                 info = sdscatprintf(info,
3536*572c4311Sfengbojiang                     "master_link_down_since_seconds:%jd\r\n",
3537*572c4311Sfengbojiang                     (intmax_t)server.unixtime-server.repl_down_since);
3538*572c4311Sfengbojiang             }
3539*572c4311Sfengbojiang             info = sdscatprintf(info,
3540*572c4311Sfengbojiang                 "slave_priority:%d\r\n"
3541*572c4311Sfengbojiang                 "slave_read_only:%d\r\n",
3542*572c4311Sfengbojiang                 server.slave_priority,
3543*572c4311Sfengbojiang                 server.repl_slave_ro);
3544*572c4311Sfengbojiang         }
3545*572c4311Sfengbojiang 
3546*572c4311Sfengbojiang         info = sdscatprintf(info,
3547*572c4311Sfengbojiang             "connected_slaves:%lu\r\n",
3548*572c4311Sfengbojiang             listLength(server.slaves));
3549*572c4311Sfengbojiang 
3550*572c4311Sfengbojiang         /* If min-slaves-to-write is active, write the number of slaves
3551*572c4311Sfengbojiang          * currently considered 'good'. */
3552*572c4311Sfengbojiang         if (server.repl_min_slaves_to_write &&
3553*572c4311Sfengbojiang             server.repl_min_slaves_max_lag) {
3554*572c4311Sfengbojiang             info = sdscatprintf(info,
3555*572c4311Sfengbojiang                 "min_slaves_good_slaves:%d\r\n",
3556*572c4311Sfengbojiang                 server.repl_good_slaves_count);
3557*572c4311Sfengbojiang         }
3558*572c4311Sfengbojiang 
3559*572c4311Sfengbojiang         if (listLength(server.slaves)) {
3560*572c4311Sfengbojiang             int slaveid = 0;
3561*572c4311Sfengbojiang             listNode *ln;
3562*572c4311Sfengbojiang             listIter li;
3563*572c4311Sfengbojiang 
3564*572c4311Sfengbojiang             listRewind(server.slaves,&li);
3565*572c4311Sfengbojiang             while((ln = listNext(&li))) {
3566*572c4311Sfengbojiang                 client *slave = listNodeValue(ln);
3567*572c4311Sfengbojiang                 char *state = NULL;
3568*572c4311Sfengbojiang                 char ip[NET_IP_STR_LEN], *slaveip = slave->slave_ip;
3569*572c4311Sfengbojiang                 int port;
3570*572c4311Sfengbojiang                 long lag = 0;
3571*572c4311Sfengbojiang 
3572*572c4311Sfengbojiang                 if (slaveip[0] == '\0') {
3573*572c4311Sfengbojiang                     if (anetPeerToString(slave->fd,ip,sizeof(ip),&port) == -1)
3574*572c4311Sfengbojiang                         continue;
3575*572c4311Sfengbojiang                     slaveip = ip;
3576*572c4311Sfengbojiang                 }
3577*572c4311Sfengbojiang                 switch(slave->replstate) {
3578*572c4311Sfengbojiang                 case SLAVE_STATE_WAIT_BGSAVE_START:
3579*572c4311Sfengbojiang                 case SLAVE_STATE_WAIT_BGSAVE_END:
3580*572c4311Sfengbojiang                     state = "wait_bgsave";
3581*572c4311Sfengbojiang                     break;
3582*572c4311Sfengbojiang                 case SLAVE_STATE_SEND_BULK:
3583*572c4311Sfengbojiang                     state = "send_bulk";
3584*572c4311Sfengbojiang                     break;
3585*572c4311Sfengbojiang                 case SLAVE_STATE_ONLINE:
3586*572c4311Sfengbojiang                     state = "online";
3587*572c4311Sfengbojiang                     break;
3588*572c4311Sfengbojiang                 }
3589*572c4311Sfengbojiang                 if (state == NULL) continue;
3590*572c4311Sfengbojiang                 if (slave->replstate == SLAVE_STATE_ONLINE)
3591*572c4311Sfengbojiang                     lag = time(NULL) - slave->repl_ack_time;
3592*572c4311Sfengbojiang 
3593*572c4311Sfengbojiang                 info = sdscatprintf(info,
3594*572c4311Sfengbojiang                     "slave%d:ip=%s,port=%d,state=%s,"
3595*572c4311Sfengbojiang                     "offset=%lld,lag=%ld\r\n",
3596*572c4311Sfengbojiang                     slaveid,slaveip,slave->slave_listening_port,state,
3597*572c4311Sfengbojiang                     slave->repl_ack_off, lag);
3598*572c4311Sfengbojiang                 slaveid++;
3599*572c4311Sfengbojiang             }
3600*572c4311Sfengbojiang         }
3601*572c4311Sfengbojiang         info = sdscatprintf(info,
3602*572c4311Sfengbojiang             "master_replid:%s\r\n"
3603*572c4311Sfengbojiang             "master_replid2:%s\r\n"
3604*572c4311Sfengbojiang             "master_repl_offset:%lld\r\n"
3605*572c4311Sfengbojiang             "second_repl_offset:%lld\r\n"
3606*572c4311Sfengbojiang             "repl_backlog_active:%d\r\n"
3607*572c4311Sfengbojiang             "repl_backlog_size:%lld\r\n"
3608*572c4311Sfengbojiang             "repl_backlog_first_byte_offset:%lld\r\n"
3609*572c4311Sfengbojiang             "repl_backlog_histlen:%lld\r\n",
3610*572c4311Sfengbojiang             server.replid,
3611*572c4311Sfengbojiang             server.replid2,
3612*572c4311Sfengbojiang             server.master_repl_offset,
3613*572c4311Sfengbojiang             server.second_replid_offset,
3614*572c4311Sfengbojiang             server.repl_backlog != NULL,
3615*572c4311Sfengbojiang             server.repl_backlog_size,
3616*572c4311Sfengbojiang             server.repl_backlog_off,
3617*572c4311Sfengbojiang             server.repl_backlog_histlen);
3618*572c4311Sfengbojiang     }
3619*572c4311Sfengbojiang 
3620*572c4311Sfengbojiang     /* CPU */
3621*572c4311Sfengbojiang     if (allsections || defsections || !strcasecmp(section,"cpu")) {
3622*572c4311Sfengbojiang         if (sections++) info = sdscat(info,"\r\n");
3623*572c4311Sfengbojiang         info = sdscatprintf(info,
3624*572c4311Sfengbojiang         "# CPU\r\n"
3625*572c4311Sfengbojiang         "used_cpu_sys:%ld.%06ld\r\n"
3626*572c4311Sfengbojiang         "used_cpu_user:%ld.%06ld\r\n"
3627*572c4311Sfengbojiang         "used_cpu_sys_children:%ld.%06ld\r\n"
3628*572c4311Sfengbojiang         "used_cpu_user_children:%ld.%06ld\r\n",
3629*572c4311Sfengbojiang         (long)self_ru.ru_stime.tv_sec, (long)self_ru.ru_stime.tv_usec,
3630*572c4311Sfengbojiang         (long)self_ru.ru_utime.tv_sec, (long)self_ru.ru_utime.tv_usec,
3631*572c4311Sfengbojiang         (long)c_ru.ru_stime.tv_sec, (long)c_ru.ru_stime.tv_usec,
3632*572c4311Sfengbojiang         (long)c_ru.ru_utime.tv_sec, (long)c_ru.ru_utime.tv_usec);
3633*572c4311Sfengbojiang     }
3634*572c4311Sfengbojiang 
3635*572c4311Sfengbojiang     /* Command statistics */
3636*572c4311Sfengbojiang     if (allsections || !strcasecmp(section,"commandstats")) {
3637*572c4311Sfengbojiang         if (sections++) info = sdscat(info,"\r\n");
3638*572c4311Sfengbojiang         info = sdscatprintf(info, "# Commandstats\r\n");
3639*572c4311Sfengbojiang 
3640*572c4311Sfengbojiang         struct redisCommand *c;
3641*572c4311Sfengbojiang         dictEntry *de;
3642*572c4311Sfengbojiang         dictIterator *di;
3643*572c4311Sfengbojiang         di = dictGetSafeIterator(server.commands);
3644*572c4311Sfengbojiang         while((de = dictNext(di)) != NULL) {
3645*572c4311Sfengbojiang             c = (struct redisCommand *) dictGetVal(de);
3646*572c4311Sfengbojiang             if (!c->calls) continue;
3647*572c4311Sfengbojiang             info = sdscatprintf(info,
3648*572c4311Sfengbojiang                 "cmdstat_%s:calls=%lld,usec=%lld,usec_per_call=%.2f\r\n",
3649*572c4311Sfengbojiang                 c->name, c->calls, c->microseconds,
3650*572c4311Sfengbojiang                 (c->calls == 0) ? 0 : ((float)c->microseconds/c->calls));
3651*572c4311Sfengbojiang         }
3652*572c4311Sfengbojiang         dictReleaseIterator(di);
3653*572c4311Sfengbojiang     }
3654*572c4311Sfengbojiang 
3655*572c4311Sfengbojiang     /* Cluster */
3656*572c4311Sfengbojiang     if (allsections || defsections || !strcasecmp(section,"cluster")) {
3657*572c4311Sfengbojiang         if (sections++) info = sdscat(info,"\r\n");
3658*572c4311Sfengbojiang         info = sdscatprintf(info,
3659*572c4311Sfengbojiang         "# Cluster\r\n"
3660*572c4311Sfengbojiang         "cluster_enabled:%d\r\n",
3661*572c4311Sfengbojiang         server.cluster_enabled);
3662*572c4311Sfengbojiang     }
3663*572c4311Sfengbojiang 
3664*572c4311Sfengbojiang     /* Key space */
3665*572c4311Sfengbojiang     if (allsections || defsections || !strcasecmp(section,"keyspace")) {
3666*572c4311Sfengbojiang         if (sections++) info = sdscat(info,"\r\n");
3667*572c4311Sfengbojiang         info = sdscatprintf(info, "# Keyspace\r\n");
3668*572c4311Sfengbojiang         for (j = 0; j < server.dbnum; j++) {
3669*572c4311Sfengbojiang             long long keys, vkeys;
3670*572c4311Sfengbojiang 
3671*572c4311Sfengbojiang             keys = dictSize(server.db[j].dict);
3672*572c4311Sfengbojiang             vkeys = dictSize(server.db[j].expires);
3673*572c4311Sfengbojiang             if (keys || vkeys) {
3674*572c4311Sfengbojiang                 info = sdscatprintf(info,
3675*572c4311Sfengbojiang                     "db%d:keys=%lld,expires=%lld,avg_ttl=%lld\r\n",
3676*572c4311Sfengbojiang                     j, keys, vkeys, server.db[j].avg_ttl);
3677*572c4311Sfengbojiang             }
3678*572c4311Sfengbojiang         }
3679*572c4311Sfengbojiang     }
3680*572c4311Sfengbojiang     return info;
3681*572c4311Sfengbojiang }
3682*572c4311Sfengbojiang 
infoCommand(client * c)3683*572c4311Sfengbojiang void infoCommand(client *c) {
3684*572c4311Sfengbojiang     char *section = c->argc == 2 ? c->argv[1]->ptr : "default";
3685*572c4311Sfengbojiang 
3686*572c4311Sfengbojiang     if (c->argc > 2) {
3687*572c4311Sfengbojiang         addReply(c,shared.syntaxerr);
3688*572c4311Sfengbojiang         return;
3689*572c4311Sfengbojiang     }
3690*572c4311Sfengbojiang     addReplyBulkSds(c, genRedisInfoString(section));
3691*572c4311Sfengbojiang }
3692*572c4311Sfengbojiang 
monitorCommand(client * c)3693*572c4311Sfengbojiang void monitorCommand(client *c) {
3694*572c4311Sfengbojiang     /* ignore MONITOR if already slave or in monitor mode */
3695*572c4311Sfengbojiang     if (c->flags & CLIENT_SLAVE) return;
3696*572c4311Sfengbojiang 
3697*572c4311Sfengbojiang     c->flags |= (CLIENT_SLAVE|CLIENT_MONITOR);
3698*572c4311Sfengbojiang     listAddNodeTail(server.monitors,c);
3699*572c4311Sfengbojiang     addReply(c,shared.ok);
3700*572c4311Sfengbojiang }
3701*572c4311Sfengbojiang 
3702*572c4311Sfengbojiang /* =================================== Main! ================================ */
3703*572c4311Sfengbojiang 
3704*572c4311Sfengbojiang #ifdef __linux__
linuxOvercommitMemoryValue(void)3705*572c4311Sfengbojiang int linuxOvercommitMemoryValue(void) {
3706*572c4311Sfengbojiang     FILE *fp = fopen("/proc/sys/vm/overcommit_memory","r");
3707*572c4311Sfengbojiang     char buf[64];
3708*572c4311Sfengbojiang 
3709*572c4311Sfengbojiang     if (!fp) return -1;
3710*572c4311Sfengbojiang     if (fgets(buf,64,fp) == NULL) {
3711*572c4311Sfengbojiang         fclose(fp);
3712*572c4311Sfengbojiang         return -1;
3713*572c4311Sfengbojiang     }
3714*572c4311Sfengbojiang     fclose(fp);
3715*572c4311Sfengbojiang 
3716*572c4311Sfengbojiang     return atoi(buf);
3717*572c4311Sfengbojiang }
3718*572c4311Sfengbojiang 
linuxMemoryWarnings(void)3719*572c4311Sfengbojiang void linuxMemoryWarnings(void) {
3720*572c4311Sfengbojiang     if (linuxOvercommitMemoryValue() == 0) {
3721*572c4311Sfengbojiang         serverLog(LL_WARNING,"WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.");
3722*572c4311Sfengbojiang     }
3723*572c4311Sfengbojiang     if (THPIsEnabled()) {
3724*572c4311Sfengbojiang         serverLog(LL_WARNING,"WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.");
3725*572c4311Sfengbojiang     }
3726*572c4311Sfengbojiang }
3727*572c4311Sfengbojiang #endif /* __linux__ */
3728*572c4311Sfengbojiang 
createPidFile(void)3729*572c4311Sfengbojiang void createPidFile(void) {
3730*572c4311Sfengbojiang     /* If pidfile requested, but no pidfile defined, use
3731*572c4311Sfengbojiang      * default pidfile path */
3732*572c4311Sfengbojiang     if (!server.pidfile) server.pidfile = zstrdup(CONFIG_DEFAULT_PID_FILE);
3733*572c4311Sfengbojiang 
3734*572c4311Sfengbojiang     /* Try to write the pid file in a best-effort way. */
3735*572c4311Sfengbojiang     FILE *fp = fopen(server.pidfile,"w");
3736*572c4311Sfengbojiang     if (fp) {
3737*572c4311Sfengbojiang         fprintf(fp,"%d\n",(int)getpid());
3738*572c4311Sfengbojiang         fclose(fp);
3739*572c4311Sfengbojiang     }
3740*572c4311Sfengbojiang }
3741*572c4311Sfengbojiang 
daemonize(void)3742*572c4311Sfengbojiang void daemonize(void) {
3743*572c4311Sfengbojiang     int fd;
3744*572c4311Sfengbojiang 
3745*572c4311Sfengbojiang     if (fork() != 0) exit(0); /* parent exits */
3746*572c4311Sfengbojiang     setsid(); /* create a new session */
3747*572c4311Sfengbojiang 
3748*572c4311Sfengbojiang     /* Every output goes to /dev/null. If Redis is daemonized but
3749*572c4311Sfengbojiang      * the 'logfile' is set to 'stdout' in the configuration file
3750*572c4311Sfengbojiang      * it will not log at all. */
3751*572c4311Sfengbojiang     if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
3752*572c4311Sfengbojiang         dup2(fd, STDIN_FILENO);
3753*572c4311Sfengbojiang         dup2(fd, STDOUT_FILENO);
3754*572c4311Sfengbojiang         dup2(fd, STDERR_FILENO);
3755*572c4311Sfengbojiang         if (fd > STDERR_FILENO) close(fd);
3756*572c4311Sfengbojiang     }
3757*572c4311Sfengbojiang }
3758*572c4311Sfengbojiang 
version(void)3759*572c4311Sfengbojiang void version(void) {
3760*572c4311Sfengbojiang     printf("Redis server v=%s sha=%s:%d malloc=%s bits=%d build=%llx\n",
3761*572c4311Sfengbojiang         REDIS_VERSION,
3762*572c4311Sfengbojiang         redisGitSHA1(),
3763*572c4311Sfengbojiang         atoi(redisGitDirty()) > 0,
3764*572c4311Sfengbojiang         ZMALLOC_LIB,
3765*572c4311Sfengbojiang         sizeof(long) == 4 ? 32 : 64,
3766*572c4311Sfengbojiang         (unsigned long long) redisBuildId());
3767*572c4311Sfengbojiang     exit(0);
3768*572c4311Sfengbojiang }
3769*572c4311Sfengbojiang 
usage(void)3770*572c4311Sfengbojiang void usage(void) {
3771*572c4311Sfengbojiang     fprintf(stderr,"Usage: ./redis-server [/path/to/redis.conf] [options]\n");
3772*572c4311Sfengbojiang     fprintf(stderr,"       ./redis-server - (read config from stdin)\n");
3773*572c4311Sfengbojiang     fprintf(stderr,"       ./redis-server -v or --version\n");
3774*572c4311Sfengbojiang     fprintf(stderr,"       ./redis-server -h or --help\n");
3775*572c4311Sfengbojiang     fprintf(stderr,"       ./redis-server --test-memory <megabytes>\n\n");
3776*572c4311Sfengbojiang     fprintf(stderr,"Examples:\n");
3777*572c4311Sfengbojiang     fprintf(stderr,"       ./redis-server (run the server with default conf)\n");
3778*572c4311Sfengbojiang     fprintf(stderr,"       ./redis-server /etc/redis/6379.conf\n");
3779*572c4311Sfengbojiang     fprintf(stderr,"       ./redis-server --port 7777\n");
3780*572c4311Sfengbojiang     fprintf(stderr,"       ./redis-server --port 7777 --replicaof 127.0.0.1 8888\n");
3781*572c4311Sfengbojiang     fprintf(stderr,"       ./redis-server /etc/myredis.conf --loglevel verbose\n\n");
3782*572c4311Sfengbojiang     fprintf(stderr,"Sentinel mode:\n");
3783*572c4311Sfengbojiang     fprintf(stderr,"       ./redis-server /etc/sentinel.conf --sentinel\n");
3784*572c4311Sfengbojiang     exit(1);
3785*572c4311Sfengbojiang }
3786*572c4311Sfengbojiang 
redisAsciiArt(void)3787*572c4311Sfengbojiang void redisAsciiArt(void) {
3788*572c4311Sfengbojiang #include "asciilogo.h"
3789*572c4311Sfengbojiang     char *buf = zmalloc(1024*16);
3790*572c4311Sfengbojiang     char *mode;
3791*572c4311Sfengbojiang 
3792*572c4311Sfengbojiang     if (server.cluster_enabled) mode = "cluster";
3793*572c4311Sfengbojiang     else if (server.sentinel_mode) mode = "sentinel";
3794*572c4311Sfengbojiang     else mode = "standalone";
3795*572c4311Sfengbojiang 
3796*572c4311Sfengbojiang     /* Show the ASCII logo if: log file is stdout AND stdout is a
3797*572c4311Sfengbojiang      * tty AND syslog logging is disabled. Also show logo if the user
3798*572c4311Sfengbojiang      * forced us to do so via redis.conf. */
3799*572c4311Sfengbojiang     int show_logo = ((!server.syslog_enabled &&
3800*572c4311Sfengbojiang                       server.logfile[0] == '\0' &&
3801*572c4311Sfengbojiang                       isatty(fileno(stdout))) ||
3802*572c4311Sfengbojiang                      server.always_show_logo);
3803*572c4311Sfengbojiang 
3804*572c4311Sfengbojiang     if (!show_logo) {
3805*572c4311Sfengbojiang         serverLog(LL_NOTICE,
3806*572c4311Sfengbojiang             "Running mode=%s, port=%d.",
3807*572c4311Sfengbojiang             mode, server.port
3808*572c4311Sfengbojiang         );
3809*572c4311Sfengbojiang     } else {
3810*572c4311Sfengbojiang         snprintf(buf,1024*16,ascii_logo,
3811*572c4311Sfengbojiang             REDIS_VERSION,
3812*572c4311Sfengbojiang             redisGitSHA1(),
3813*572c4311Sfengbojiang             strtol(redisGitDirty(),NULL,10) > 0,
3814*572c4311Sfengbojiang             (sizeof(long) == 8) ? "64" : "32",
3815*572c4311Sfengbojiang             mode, server.port,
3816*572c4311Sfengbojiang             (long) getpid()
3817*572c4311Sfengbojiang         );
3818*572c4311Sfengbojiang         serverLogRaw(LL_NOTICE|LL_RAW,buf);
3819*572c4311Sfengbojiang     }
3820*572c4311Sfengbojiang     zfree(buf);
3821*572c4311Sfengbojiang }
3822*572c4311Sfengbojiang 
sigShutdownHandler(int sig)3823*572c4311Sfengbojiang static void sigShutdownHandler(int sig) {
3824*572c4311Sfengbojiang     char *msg;
3825*572c4311Sfengbojiang 
3826*572c4311Sfengbojiang     switch (sig) {
3827*572c4311Sfengbojiang     case SIGINT:
3828*572c4311Sfengbojiang         msg = "Received SIGINT scheduling shutdown...";
3829*572c4311Sfengbojiang         break;
3830*572c4311Sfengbojiang     case SIGTERM:
3831*572c4311Sfengbojiang         msg = "Received SIGTERM scheduling shutdown...";
3832*572c4311Sfengbojiang         break;
3833*572c4311Sfengbojiang     default:
3834*572c4311Sfengbojiang         msg = "Received shutdown signal, scheduling shutdown...";
3835*572c4311Sfengbojiang     };
3836*572c4311Sfengbojiang 
3837*572c4311Sfengbojiang     /* SIGINT is often delivered via Ctrl+C in an interactive session.
3838*572c4311Sfengbojiang      * If we receive the signal the second time, we interpret this as
3839*572c4311Sfengbojiang      * the user really wanting to quit ASAP without waiting to persist
3840*572c4311Sfengbojiang      * on disk. */
3841*572c4311Sfengbojiang     if (server.shutdown_asap && sig == SIGINT) {
3842*572c4311Sfengbojiang         serverLogFromHandler(LL_WARNING, "You insist... exiting now.");
3843*572c4311Sfengbojiang         rdbRemoveTempFile(getpid());
3844*572c4311Sfengbojiang         exit(1); /* Exit with an error since this was not a clean shutdown. */
3845*572c4311Sfengbojiang     } else if (server.loading) {
3846*572c4311Sfengbojiang         serverLogFromHandler(LL_WARNING, "Received shutdown signal during loading, exiting now.");
3847*572c4311Sfengbojiang         exit(0);
3848*572c4311Sfengbojiang     }
3849*572c4311Sfengbojiang 
3850*572c4311Sfengbojiang     serverLogFromHandler(LL_WARNING, msg);
3851*572c4311Sfengbojiang     server.shutdown_asap = 1;
3852*572c4311Sfengbojiang }
3853*572c4311Sfengbojiang 
setupSignalHandlers(void)3854*572c4311Sfengbojiang void setupSignalHandlers(void) {
3855*572c4311Sfengbojiang     struct sigaction act;
3856*572c4311Sfengbojiang 
3857*572c4311Sfengbojiang     /* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction is used.
3858*572c4311Sfengbojiang      * Otherwise, sa_handler is used. */
3859*572c4311Sfengbojiang     sigemptyset(&act.sa_mask);
3860*572c4311Sfengbojiang     act.sa_flags = 0;
3861*572c4311Sfengbojiang     act.sa_handler = sigShutdownHandler;
3862*572c4311Sfengbojiang     sigaction(SIGTERM, &act, NULL);
3863*572c4311Sfengbojiang     sigaction(SIGINT, &act, NULL);
3864*572c4311Sfengbojiang 
3865*572c4311Sfengbojiang #ifdef HAVE_BACKTRACE
3866*572c4311Sfengbojiang     sigemptyset(&act.sa_mask);
3867*572c4311Sfengbojiang     act.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
3868*572c4311Sfengbojiang     act.sa_sigaction = sigsegvHandler;
3869*572c4311Sfengbojiang     sigaction(SIGSEGV, &act, NULL);
3870*572c4311Sfengbojiang     sigaction(SIGBUS, &act, NULL);
3871*572c4311Sfengbojiang     sigaction(SIGFPE, &act, NULL);
3872*572c4311Sfengbojiang     sigaction(SIGILL, &act, NULL);
3873*572c4311Sfengbojiang #endif
3874*572c4311Sfengbojiang     return;
3875*572c4311Sfengbojiang }
3876*572c4311Sfengbojiang 
3877*572c4311Sfengbojiang void memtest(size_t megabytes, int passes);
3878*572c4311Sfengbojiang 
3879*572c4311Sfengbojiang /* Returns 1 if there is --sentinel among the arguments or if
3880*572c4311Sfengbojiang  * argv[0] contains "redis-sentinel". */
checkForSentinelMode(int argc,char ** argv)3881*572c4311Sfengbojiang int checkForSentinelMode(int argc, char **argv) {
3882*572c4311Sfengbojiang     int j;
3883*572c4311Sfengbojiang 
3884*572c4311Sfengbojiang     if (strstr(argv[0],"redis-sentinel") != NULL) return 1;
3885*572c4311Sfengbojiang     for (j = 1; j < argc; j++)
3886*572c4311Sfengbojiang         if (!strcmp(argv[j],"--sentinel")) return 1;
3887*572c4311Sfengbojiang     return 0;
3888*572c4311Sfengbojiang }
3889*572c4311Sfengbojiang 
3890*572c4311Sfengbojiang /* Function called at startup to load RDB or AOF file in memory. */
loadDataFromDisk(void)3891*572c4311Sfengbojiang void loadDataFromDisk(void) {
3892*572c4311Sfengbojiang     long long start = ustime();
3893*572c4311Sfengbojiang     if (server.aof_state == AOF_ON) {
3894*572c4311Sfengbojiang         if (loadAppendOnlyFile(server.aof_filename) == C_OK)
3895*572c4311Sfengbojiang             serverLog(LL_NOTICE,"DB loaded from append only file: %.3f seconds",(float)(ustime()-start)/1000000);
3896*572c4311Sfengbojiang     } else {
3897*572c4311Sfengbojiang         rdbSaveInfo rsi = RDB_SAVE_INFO_INIT;
3898*572c4311Sfengbojiang         if (rdbLoad(server.rdb_filename,&rsi) == C_OK) {
3899*572c4311Sfengbojiang             serverLog(LL_NOTICE,"DB loaded from disk: %.3f seconds",
3900*572c4311Sfengbojiang                 (float)(ustime()-start)/1000000);
3901*572c4311Sfengbojiang 
3902*572c4311Sfengbojiang             /* Restore the replication ID / offset from the RDB file. */
3903*572c4311Sfengbojiang             if ((server.masterhost || (server.cluster_enabled && nodeIsSlave(server.cluster->myself)))&&
3904*572c4311Sfengbojiang                 rsi.repl_id_is_set &&
3905*572c4311Sfengbojiang                 rsi.repl_offset != -1 &&
3906*572c4311Sfengbojiang                 /* Note that older implementations may save a repl_stream_db
3907*572c4311Sfengbojiang                  * of -1 inside the RDB file in a wrong way, see more information
3908*572c4311Sfengbojiang                  * in function rdbPopulateSaveInfo. */
3909*572c4311Sfengbojiang                 rsi.repl_stream_db != -1)
3910*572c4311Sfengbojiang             {
3911*572c4311Sfengbojiang                 memcpy(server.replid,rsi.repl_id,sizeof(server.replid));
3912*572c4311Sfengbojiang                 server.master_repl_offset = rsi.repl_offset;
3913*572c4311Sfengbojiang                 /* If we are a slave, create a cached master from this
3914*572c4311Sfengbojiang                  * information, in order to allow partial resynchronizations
3915*572c4311Sfengbojiang                  * with masters. */
3916*572c4311Sfengbojiang                 replicationCacheMasterUsingMyself();
3917*572c4311Sfengbojiang                 selectDb(server.cached_master,rsi.repl_stream_db);
3918*572c4311Sfengbojiang             }
3919*572c4311Sfengbojiang         } else if (errno != ENOENT) {
3920*572c4311Sfengbojiang             serverLog(LL_WARNING,"Fatal error loading the DB: %s. Exiting.",strerror(errno));
3921*572c4311Sfengbojiang             exit(1);
3922*572c4311Sfengbojiang         }
3923*572c4311Sfengbojiang     }
3924*572c4311Sfengbojiang }
3925*572c4311Sfengbojiang 
redisOutOfMemoryHandler(size_t allocation_size)3926*572c4311Sfengbojiang void redisOutOfMemoryHandler(size_t allocation_size) {
3927*572c4311Sfengbojiang     serverLog(LL_WARNING,"Out Of Memory allocating %zu bytes!",
3928*572c4311Sfengbojiang         allocation_size);
3929*572c4311Sfengbojiang     serverPanic("Redis aborting for OUT OF MEMORY");
3930*572c4311Sfengbojiang }
3931*572c4311Sfengbojiang 
redisSetProcTitle(char * title)3932*572c4311Sfengbojiang void redisSetProcTitle(char *title) {
3933*572c4311Sfengbojiang #ifdef USE_SETPROCTITLE
3934*572c4311Sfengbojiang     char *server_mode = "";
3935*572c4311Sfengbojiang     if (server.cluster_enabled) server_mode = " [cluster]";
3936*572c4311Sfengbojiang     else if (server.sentinel_mode) server_mode = " [sentinel]";
3937*572c4311Sfengbojiang 
3938*572c4311Sfengbojiang     setproctitle("%s %s:%d%s",
3939*572c4311Sfengbojiang         title,
3940*572c4311Sfengbojiang         server.bindaddr_count ? server.bindaddr[0] : "*",
3941*572c4311Sfengbojiang         server.port,
3942*572c4311Sfengbojiang         server_mode);
3943*572c4311Sfengbojiang #else
3944*572c4311Sfengbojiang     UNUSED(title);
3945*572c4311Sfengbojiang #endif
3946*572c4311Sfengbojiang }
3947*572c4311Sfengbojiang 
3948*572c4311Sfengbojiang /*
3949*572c4311Sfengbojiang  * Check whether systemd or upstart have been used to start redis.
3950*572c4311Sfengbojiang  */
3951*572c4311Sfengbojiang 
redisSupervisedUpstart(void)3952*572c4311Sfengbojiang int redisSupervisedUpstart(void) {
3953*572c4311Sfengbojiang     const char *upstart_job = getenv("UPSTART_JOB");
3954*572c4311Sfengbojiang 
3955*572c4311Sfengbojiang     if (!upstart_job) {
3956*572c4311Sfengbojiang         serverLog(LL_WARNING,
3957*572c4311Sfengbojiang                 "upstart supervision requested, but UPSTART_JOB not found");
3958*572c4311Sfengbojiang         return 0;
3959*572c4311Sfengbojiang     }
3960*572c4311Sfengbojiang 
3961*572c4311Sfengbojiang     serverLog(LL_NOTICE, "supervised by upstart, will stop to signal readiness");
3962*572c4311Sfengbojiang     raise(SIGSTOP);
3963*572c4311Sfengbojiang     unsetenv("UPSTART_JOB");
3964*572c4311Sfengbojiang     return 1;
3965*572c4311Sfengbojiang }
3966*572c4311Sfengbojiang 
redisSupervisedSystemd(void)3967*572c4311Sfengbojiang int redisSupervisedSystemd(void) {
3968*572c4311Sfengbojiang     const char *notify_socket = getenv("NOTIFY_SOCKET");
3969*572c4311Sfengbojiang     int fd = 1;
3970*572c4311Sfengbojiang     struct sockaddr_un su;
3971*572c4311Sfengbojiang     struct iovec iov;
3972*572c4311Sfengbojiang     struct msghdr hdr;
3973*572c4311Sfengbojiang     int sendto_flags = 0;
3974*572c4311Sfengbojiang 
3975*572c4311Sfengbojiang     if (!notify_socket) {
3976*572c4311Sfengbojiang         serverLog(LL_WARNING,
3977*572c4311Sfengbojiang                 "systemd supervision requested, but NOTIFY_SOCKET not found");
3978*572c4311Sfengbojiang         return 0;
3979*572c4311Sfengbojiang     }
3980*572c4311Sfengbojiang 
3981*572c4311Sfengbojiang     if ((strchr("@/", notify_socket[0])) == NULL || strlen(notify_socket) < 2) {
3982*572c4311Sfengbojiang         return 0;
3983*572c4311Sfengbojiang     }
3984*572c4311Sfengbojiang 
3985*572c4311Sfengbojiang     serverLog(LL_NOTICE, "supervised by systemd, will signal readiness");
3986*572c4311Sfengbojiang     if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) {
3987*572c4311Sfengbojiang         serverLog(LL_WARNING,
3988*572c4311Sfengbojiang                 "Can't connect to systemd socket %s", notify_socket);
3989*572c4311Sfengbojiang         return 0;
3990*572c4311Sfengbojiang     }
3991*572c4311Sfengbojiang 
3992*572c4311Sfengbojiang     memset(&su, 0, sizeof(su));
3993*572c4311Sfengbojiang     su.sun_family = AF_UNIX;
3994*572c4311Sfengbojiang     strncpy (su.sun_path, notify_socket, sizeof(su.sun_path) -1);
3995*572c4311Sfengbojiang     su.sun_path[sizeof(su.sun_path) - 1] = '\0';
3996*572c4311Sfengbojiang 
3997*572c4311Sfengbojiang     if (notify_socket[0] == '@')
3998*572c4311Sfengbojiang         su.sun_path[0] = '\0';
3999*572c4311Sfengbojiang 
4000*572c4311Sfengbojiang     memset(&iov, 0, sizeof(iov));
4001*572c4311Sfengbojiang     iov.iov_base = "READY=1";
4002*572c4311Sfengbojiang     iov.iov_len = strlen("READY=1");
4003*572c4311Sfengbojiang 
4004*572c4311Sfengbojiang     memset(&hdr, 0, sizeof(hdr));
4005*572c4311Sfengbojiang     hdr.msg_name = &su;
4006*572c4311Sfengbojiang     hdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) +
4007*572c4311Sfengbojiang         strlen(notify_socket);
4008*572c4311Sfengbojiang     hdr.msg_iov = &iov;
4009*572c4311Sfengbojiang     hdr.msg_iovlen = 1;
4010*572c4311Sfengbojiang 
4011*572c4311Sfengbojiang     unsetenv("NOTIFY_SOCKET");
4012*572c4311Sfengbojiang #ifdef HAVE_MSG_NOSIGNAL
4013*572c4311Sfengbojiang     sendto_flags |= MSG_NOSIGNAL;
4014*572c4311Sfengbojiang #endif
4015*572c4311Sfengbojiang     if (sendmsg(fd, &hdr, sendto_flags) < 0) {
4016*572c4311Sfengbojiang         serverLog(LL_WARNING, "Can't send notification to systemd");
4017*572c4311Sfengbojiang         close(fd);
4018*572c4311Sfengbojiang         return 0;
4019*572c4311Sfengbojiang     }
4020*572c4311Sfengbojiang     close(fd);
4021*572c4311Sfengbojiang     return 1;
4022*572c4311Sfengbojiang }
4023*572c4311Sfengbojiang 
redisIsSupervised(int mode)4024*572c4311Sfengbojiang int redisIsSupervised(int mode) {
4025*572c4311Sfengbojiang     if (mode == SUPERVISED_AUTODETECT) {
4026*572c4311Sfengbojiang         const char *upstart_job = getenv("UPSTART_JOB");
4027*572c4311Sfengbojiang         const char *notify_socket = getenv("NOTIFY_SOCKET");
4028*572c4311Sfengbojiang 
4029*572c4311Sfengbojiang         if (upstart_job) {
4030*572c4311Sfengbojiang             redisSupervisedUpstart();
4031*572c4311Sfengbojiang         } else if (notify_socket) {
4032*572c4311Sfengbojiang             redisSupervisedSystemd();
4033*572c4311Sfengbojiang         }
4034*572c4311Sfengbojiang     } else if (mode == SUPERVISED_UPSTART) {
4035*572c4311Sfengbojiang         return redisSupervisedUpstart();
4036*572c4311Sfengbojiang     } else if (mode == SUPERVISED_SYSTEMD) {
4037*572c4311Sfengbojiang         return redisSupervisedSystemd();
4038*572c4311Sfengbojiang     }
4039*572c4311Sfengbojiang 
4040*572c4311Sfengbojiang     return 0;
4041*572c4311Sfengbojiang }
4042*572c4311Sfengbojiang 
loop(void * arg)4043*572c4311Sfengbojiang static int loop(void *arg) {
4044*572c4311Sfengbojiang     aeMain((aeEventLoop *)arg);
4045*572c4311Sfengbojiang     return 0;
4046*572c4311Sfengbojiang }
4047*572c4311Sfengbojiang 
main(int argc,char ** argv)4048*572c4311Sfengbojiang int main(int argc, char **argv) {
4049*572c4311Sfengbojiang     struct timeval tv;
4050*572c4311Sfengbojiang     int j;
4051*572c4311Sfengbojiang 
4052*572c4311Sfengbojiang #ifdef HAVE_FF_KQUEUE
4053*572c4311Sfengbojiang     int rc = ff_init(argc, argv);
4054*572c4311Sfengbojiang     assert(0 == rc);
4055*572c4311Sfengbojiang     ff_mod_init();
4056*572c4311Sfengbojiang     int new_argc = argc - 4;
4057*572c4311Sfengbojiang     if (new_argc <= 0) {
4058*572c4311Sfengbojiang         new_argc = 1;
4059*572c4311Sfengbojiang     }
4060*572c4311Sfengbojiang 
4061*572c4311Sfengbojiang     char **new_argv = zmalloc(sizeof(char *) * new_argc);
4062*572c4311Sfengbojiang     new_argv[0] = argv[0];
4063*572c4311Sfengbojiang     int i;
4064*572c4311Sfengbojiang     for (i = 1; i < new_argc; i++) {
4065*572c4311Sfengbojiang         new_argv[i] = argv[i + 4];
4066*572c4311Sfengbojiang     }
4067*572c4311Sfengbojiang     argv = new_argv;
4068*572c4311Sfengbojiang     argc = new_argc;
4069*572c4311Sfengbojiang #endif
4070*572c4311Sfengbojiang 
4071*572c4311Sfengbojiang 
4072*572c4311Sfengbojiang #ifdef REDIS_TEST
4073*572c4311Sfengbojiang     if (argc == 3 && !strcasecmp(argv[1], "test")) {
4074*572c4311Sfengbojiang         if (!strcasecmp(argv[2], "ziplist")) {
4075*572c4311Sfengbojiang             return ziplistTest(argc, argv);
4076*572c4311Sfengbojiang         } else if (!strcasecmp(argv[2], "quicklist")) {
4077*572c4311Sfengbojiang             quicklistTest(argc, argv);
4078*572c4311Sfengbojiang         } else if (!strcasecmp(argv[2], "intset")) {
4079*572c4311Sfengbojiang             return intsetTest(argc, argv);
4080*572c4311Sfengbojiang         } else if (!strcasecmp(argv[2], "zipmap")) {
4081*572c4311Sfengbojiang             return zipmapTest(argc, argv);
4082*572c4311Sfengbojiang         } else if (!strcasecmp(argv[2], "sha1test")) {
4083*572c4311Sfengbojiang             return sha1Test(argc, argv);
4084*572c4311Sfengbojiang         } else if (!strcasecmp(argv[2], "util")) {
4085*572c4311Sfengbojiang             return utilTest(argc, argv);
4086*572c4311Sfengbojiang         } else if (!strcasecmp(argv[2], "endianconv")) {
4087*572c4311Sfengbojiang             return endianconvTest(argc, argv);
4088*572c4311Sfengbojiang         } else if (!strcasecmp(argv[2], "crc64")) {
4089*572c4311Sfengbojiang             return crc64Test(argc, argv);
4090*572c4311Sfengbojiang         } else if (!strcasecmp(argv[2], "zmalloc")) {
4091*572c4311Sfengbojiang             return zmalloc_test(argc, argv);
4092*572c4311Sfengbojiang         }
4093*572c4311Sfengbojiang 
4094*572c4311Sfengbojiang         return -1; /* test not found */
4095*572c4311Sfengbojiang     }
4096*572c4311Sfengbojiang #endif
4097*572c4311Sfengbojiang 
4098*572c4311Sfengbojiang     /* We need to initialize our libraries, and the server configuration. */
4099*572c4311Sfengbojiang #ifdef INIT_SETPROCTITLE_REPLACEMENT
4100*572c4311Sfengbojiang     spt_init(argc, argv);
4101*572c4311Sfengbojiang #endif
4102*572c4311Sfengbojiang     setlocale(LC_COLLATE,"");
4103*572c4311Sfengbojiang     tzset(); /* Populates 'timezone' global. */
4104*572c4311Sfengbojiang     zmalloc_set_oom_handler(redisOutOfMemoryHandler);
4105*572c4311Sfengbojiang     srand(time(NULL)^getpid());
4106*572c4311Sfengbojiang     gettimeofday(&tv,NULL);
4107*572c4311Sfengbojiang 
4108*572c4311Sfengbojiang     char hashseed[16];
4109*572c4311Sfengbojiang     getRandomHexChars(hashseed,sizeof(hashseed));
4110*572c4311Sfengbojiang     dictSetHashFunctionSeed((uint8_t*)hashseed);
4111*572c4311Sfengbojiang     server.sentinel_mode = checkForSentinelMode(argc,argv);
4112*572c4311Sfengbojiang     initServerConfig();
4113*572c4311Sfengbojiang     moduleInitModulesSystem();
4114*572c4311Sfengbojiang 
4115*572c4311Sfengbojiang     /* Store the executable path and arguments in a safe place in order
4116*572c4311Sfengbojiang      * to be able to restart the server later. */
4117*572c4311Sfengbojiang     server.executable = getAbsolutePath(argv[0]);
4118*572c4311Sfengbojiang     server.exec_argv = zmalloc(sizeof(char*)*(argc+1));
4119*572c4311Sfengbojiang     server.exec_argv[argc] = NULL;
4120*572c4311Sfengbojiang     for (j = 0; j < argc; j++) server.exec_argv[j] = zstrdup(argv[j]);
4121*572c4311Sfengbojiang 
4122*572c4311Sfengbojiang     /* We need to init sentinel right now as parsing the configuration file
4123*572c4311Sfengbojiang      * in sentinel mode will have the effect of populating the sentinel
4124*572c4311Sfengbojiang      * data structures with master nodes to monitor. */
4125*572c4311Sfengbojiang     if (server.sentinel_mode) {
4126*572c4311Sfengbojiang         initSentinelConfig();
4127*572c4311Sfengbojiang         initSentinel();
4128*572c4311Sfengbojiang     }
4129*572c4311Sfengbojiang 
4130*572c4311Sfengbojiang     /* Check if we need to start in redis-check-rdb/aof mode. We just execute
4131*572c4311Sfengbojiang      * the program main. However the program is part of the Redis executable
4132*572c4311Sfengbojiang      * so that we can easily execute an RDB check on loading errors. */
4133*572c4311Sfengbojiang     if (strstr(argv[0],"redis-check-rdb") != NULL)
4134*572c4311Sfengbojiang         redis_check_rdb_main(argc,argv,NULL);
4135*572c4311Sfengbojiang     else if (strstr(argv[0],"redis-check-aof") != NULL)
4136*572c4311Sfengbojiang         redis_check_aof_main(argc,argv);
4137*572c4311Sfengbojiang 
4138*572c4311Sfengbojiang     if (argc >= 2) {
4139*572c4311Sfengbojiang         j = 1; /* First option to parse in argv[] */
4140*572c4311Sfengbojiang         sds options = sdsempty();
4141*572c4311Sfengbojiang         char *configfile = NULL;
4142*572c4311Sfengbojiang 
4143*572c4311Sfengbojiang         /* Handle special options --help and --version */
4144*572c4311Sfengbojiang         if (strcmp(argv[1], "-v") == 0 ||
4145*572c4311Sfengbojiang             strcmp(argv[1], "--version") == 0) version();
4146*572c4311Sfengbojiang         if (strcmp(argv[1], "--help") == 0 ||
4147*572c4311Sfengbojiang             strcmp(argv[1], "-h") == 0) usage();
4148*572c4311Sfengbojiang         if (strcmp(argv[1], "--test-memory") == 0) {
4149*572c4311Sfengbojiang             if (argc == 3) {
4150*572c4311Sfengbojiang                 memtest(atoi(argv[2]),50);
4151*572c4311Sfengbojiang                 exit(0);
4152*572c4311Sfengbojiang             } else {
4153*572c4311Sfengbojiang                 fprintf(stderr,"Please specify the amount of memory to test in megabytes.\n");
4154*572c4311Sfengbojiang                 fprintf(stderr,"Example: ./redis-server --test-memory 4096\n\n");
4155*572c4311Sfengbojiang                 exit(1);
4156*572c4311Sfengbojiang             }
4157*572c4311Sfengbojiang         }
4158*572c4311Sfengbojiang 
4159*572c4311Sfengbojiang         /* First argument is the config file name? */
4160*572c4311Sfengbojiang         if (argv[j][0] != '-' || argv[j][1] != '-') {
4161*572c4311Sfengbojiang             configfile = argv[j];
4162*572c4311Sfengbojiang             server.configfile = getAbsolutePath(configfile);
4163*572c4311Sfengbojiang             /* Replace the config file in server.exec_argv with
4164*572c4311Sfengbojiang              * its absolute path. */
4165*572c4311Sfengbojiang             zfree(server.exec_argv[j]);
4166*572c4311Sfengbojiang             server.exec_argv[j] = zstrdup(server.configfile);
4167*572c4311Sfengbojiang             j++;
4168*572c4311Sfengbojiang         }
4169*572c4311Sfengbojiang 
4170*572c4311Sfengbojiang         /* All the other options are parsed and conceptually appended to the
4171*572c4311Sfengbojiang          * configuration file. For instance --port 6380 will generate the
4172*572c4311Sfengbojiang          * string "port 6380\n" to be parsed after the actual file name
4173*572c4311Sfengbojiang          * is parsed, if any. */
4174*572c4311Sfengbojiang         while(j != argc) {
4175*572c4311Sfengbojiang             if (argv[j][0] == '-' && argv[j][1] == '-') {
4176*572c4311Sfengbojiang                 /* Option name */
4177*572c4311Sfengbojiang                 if (!strcmp(argv[j], "--check-rdb")) {
4178*572c4311Sfengbojiang                     /* Argument has no options, need to skip for parsing. */
4179*572c4311Sfengbojiang                     j++;
4180*572c4311Sfengbojiang                     continue;
4181*572c4311Sfengbojiang                 }
4182*572c4311Sfengbojiang                 if (sdslen(options)) options = sdscat(options,"\n");
4183*572c4311Sfengbojiang                 options = sdscat(options,argv[j]+2);
4184*572c4311Sfengbojiang                 options = sdscat(options," ");
4185*572c4311Sfengbojiang             } else {
4186*572c4311Sfengbojiang                 /* Option argument */
4187*572c4311Sfengbojiang                 options = sdscatrepr(options,argv[j],strlen(argv[j]));
4188*572c4311Sfengbojiang                 options = sdscat(options," ");
4189*572c4311Sfengbojiang             }
4190*572c4311Sfengbojiang             j++;
4191*572c4311Sfengbojiang         }
4192*572c4311Sfengbojiang         if (server.sentinel_mode && configfile && *configfile == '-') {
4193*572c4311Sfengbojiang             serverLog(LL_WARNING,
4194*572c4311Sfengbojiang                 "Sentinel config from STDIN not allowed.");
4195*572c4311Sfengbojiang             serverLog(LL_WARNING,
4196*572c4311Sfengbojiang                 "Sentinel needs config file on disk to save state.  Exiting...");
4197*572c4311Sfengbojiang             exit(1);
4198*572c4311Sfengbojiang         }
4199*572c4311Sfengbojiang         resetServerSaveParams();
4200*572c4311Sfengbojiang         loadServerConfig(configfile,options);
4201*572c4311Sfengbojiang         sdsfree(options);
4202*572c4311Sfengbojiang     }
4203*572c4311Sfengbojiang 
4204*572c4311Sfengbojiang     serverLog(LL_WARNING, "oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo");
4205*572c4311Sfengbojiang     serverLog(LL_WARNING,
4206*572c4311Sfengbojiang         "Redis version=%s, bits=%d, commit=%s, modified=%d, pid=%d, just started",
4207*572c4311Sfengbojiang             REDIS_VERSION,
4208*572c4311Sfengbojiang             (sizeof(long) == 8) ? 64 : 32,
4209*572c4311Sfengbojiang             redisGitSHA1(),
4210*572c4311Sfengbojiang             strtol(redisGitDirty(),NULL,10) > 0,
4211*572c4311Sfengbojiang             (int)getpid());
4212*572c4311Sfengbojiang 
4213*572c4311Sfengbojiang     if (argc == 1) {
4214*572c4311Sfengbojiang         serverLog(LL_WARNING, "Warning: no config file specified, using the default config. In order to specify a config file use %s /path/to/%s.conf", argv[0], server.sentinel_mode ? "sentinel" : "redis");
4215*572c4311Sfengbojiang     } else {
4216*572c4311Sfengbojiang         serverLog(LL_WARNING, "Configuration loaded");
4217*572c4311Sfengbojiang     }
4218*572c4311Sfengbojiang 
4219*572c4311Sfengbojiang     server.supervised = redisIsSupervised(server.supervised_mode);
4220*572c4311Sfengbojiang     int background = server.daemonize && !server.supervised;
4221*572c4311Sfengbojiang     if (background) daemonize();
4222*572c4311Sfengbojiang 
4223*572c4311Sfengbojiang     initServer();
4224*572c4311Sfengbojiang     if (background || server.pidfile) createPidFile();
4225*572c4311Sfengbojiang     redisSetProcTitle(argv[0]);
4226*572c4311Sfengbojiang     redisAsciiArt();
4227*572c4311Sfengbojiang     checkTcpBacklogSettings();
4228*572c4311Sfengbojiang 
4229*572c4311Sfengbojiang     if (!server.sentinel_mode) {
4230*572c4311Sfengbojiang         /* Things not needed when running in Sentinel mode. */
4231*572c4311Sfengbojiang         serverLog(LL_WARNING,"Server initialized");
4232*572c4311Sfengbojiang     #ifdef __linux__
4233*572c4311Sfengbojiang         linuxMemoryWarnings();
4234*572c4311Sfengbojiang     #endif
4235*572c4311Sfengbojiang         moduleLoadFromQueue();
4236*572c4311Sfengbojiang         loadDataFromDisk();
4237*572c4311Sfengbojiang         if (server.cluster_enabled) {
4238*572c4311Sfengbojiang             if (verifyClusterConfigWithData() == C_ERR) {
4239*572c4311Sfengbojiang                 serverLog(LL_WARNING,
4240*572c4311Sfengbojiang                     "You can't have keys in a DB different than DB 0 when in "
4241*572c4311Sfengbojiang                     "Cluster mode. Exiting.");
4242*572c4311Sfengbojiang                 exit(1);
4243*572c4311Sfengbojiang             }
4244*572c4311Sfengbojiang         }
4245*572c4311Sfengbojiang         if (server.ipfd_count > 0)
4246*572c4311Sfengbojiang             serverLog(LL_NOTICE,"Ready to accept connections");
4247*572c4311Sfengbojiang         if (server.sofd > 0)
4248*572c4311Sfengbojiang             serverLog(LL_NOTICE,"The server is now ready to accept connections at %s", server.unixsocket);
4249*572c4311Sfengbojiang     } else {
4250*572c4311Sfengbojiang         sentinelIsRunning();
4251*572c4311Sfengbojiang     }
4252*572c4311Sfengbojiang 
4253*572c4311Sfengbojiang     /* Warning the user about suspicious maxmemory setting. */
4254*572c4311Sfengbojiang     if (server.maxmemory > 0 && server.maxmemory < 1024*1024) {
4255*572c4311Sfengbojiang         serverLog(LL_WARNING,"WARNING: You specified a maxmemory value that is less than 1MB (current value is %llu bytes). Are you sure this is what you really want?", server.maxmemory);
4256*572c4311Sfengbojiang     }
4257*572c4311Sfengbojiang 
4258*572c4311Sfengbojiang     aeSetBeforeSleepProc(server.el,beforeSleep);
4259*572c4311Sfengbojiang     aeSetAfterSleepProc(server.el,afterSleep);
4260*572c4311Sfengbojiang     ff_run(loop, server.el);
4261*572c4311Sfengbojiang     aeDeleteEventLoop(server.el);
4262*572c4311Sfengbojiang #ifdef HAVE_FF_KQUEUE
4263*572c4311Sfengbojiang     zfree(new_argv);
4264*572c4311Sfengbojiang #endif
4265*572c4311Sfengbojiang     return 0;
4266*572c4311Sfengbojiang }
4267*572c4311Sfengbojiang 
4268*572c4311Sfengbojiang /* The End */
4269