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