redis源码笔记-config
redis配置文件的头文件,有一些和平台有关的配置,在这里边进行设置。
config.h
1 #ifndef __CONFIG_H 2 #define __CONFIG_H 3 4 #ifdef __APPLE__ 5 #include <AvailabilityMacros.h> 6 #endif 7 8 /* Define redis_fstat to fstat or fstat64() */ 9 #if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6) 10 #define redis_fstat fstat64 11 #define redis_stat stat64 12 #else 13 #define redis_fstat fstat 14 #define redis_stat stat 15 #endif 16 17 /* Test for proc filesystem */ 18 //proc filesystem是进程文件系统的意思,包含一个伪文件系统(启动时动态生成的文件系统),用于通过内核访问进程信息。这个文件系统通常挂载在/proc目录下,/proc不是真正的文件系统,仅占用内存空间 19 //redis在获取rss信息(zmalloc.c的zmalloc_get_rss函数)时,需要判断是否有proc filesystem。rss是Resident Set Size的缩写,表示进程占用被hold在内存的那一部分。 20 #ifdef __linux__ 21 #define HAVE_PROCFS 1 22 #endif 23 24 /* Test for task_info() */ 25 #if defined(__APPLE__) 26 #define HAVE_TASKINFO 1 27 #endif 28 29 //backtrace是指“A backtrace is a list of the function calls that are currently active in a thread. The usual way to inspect a backtrace of a program is to use an external debugger such as gdb. However, sometimes it is useful to obtain a backtrace programmatically from within a program, e.g., for the purposes of logging or diagnostics.”或者说,我们通常说的栈祯。在debug.c和redis.c中均有应用,具体到相关调用处再说明。 30 /* Test for backtrace() */ 31 #if defined(__APPLE__) || defined(__linux__) || defined(__sun) 32 #define HAVE_BACKTRACE 1 33 #endif 34 35 //linux下使用epoll构建事件框架 36 /* Test for polling API */ 37 #ifdef __linux__ 38 #define HAVE_EPOLL 1 39 #endif 40 41 #if (defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined (__NetBSD__) 42 #define HAVE_KQUEUE 1 43 #endif 44 45 //linux下使用fdatasync来flush硬盘。apue上讲过,fsync和fdatasync的区别是,fsync同时刷新文件的元数据(精确描述大家自己翻书吧)。redis使用fsync是为了将内存中的业务数据保存下来,具体rdb文件的元数据是否得到及时更新,并不是很重要,因此,如果在fdatasync可用的时候,使用更快的就是一个更明智的选择。 46 /* Define aof_fsync to fdatasync() in Linux and fsync() for all the rest */ 47 #ifdef __linux__ 48 #define aof_fsync fdatasync 49 #else 50 #define aof_fsync fsync 51 #endif 52 53 #endif
config.c 读取配置文件,以及和配置文件有关的client命令的执行函数,可谓又臭又长,看看就好。
1 #include "redis.h" 2 3 /*----------------------------------------------------------------------------- 4 * Config file parsing 5 *----------------------------------------------------------------------------*/ 6 7 int yesnotoi(char *s) { 8 if (!strcasecmp(s,"yes")) return 1; 9 else if (!strcasecmp(s,"no")) return 0; 10 else return -1; 11 } 12 13 void appendServerSaveParams(time_t seconds, int changes) { 14 server.saveparams = zrealloc(server.saveparams,sizeof(struct saveparam)*(server.saveparamslen+1)); 15 server.saveparams[server.saveparamslen].seconds = seconds; 16 server.saveparams[server.saveparamslen].changes = changes; 17 server.saveparamslen++; 18 } 19 20 void resetServerSaveParams() { 21 zfree(server.saveparams); 22 server.saveparams = NULL; 23 server.saveparamslen = 0; 24 } 25 26 /* I agree, this is a very rudimental way to load a configuration... 27 will improve later if the config gets more complex */ 28 void loadServerConfig(char *filename) { 29 FILE *fp; 30 char buf[REDIS_CONFIGLINE_MAX+1], *err = NULL; 31 int linenum = 0; 32 sds line = NULL; 33 int really_use_vm = 0; 34 35 if (filename[0] == '-' && filename[1] == '\0') 36 fp = stdin; 37 else { 38 if ((fp = fopen(filename,"r")) == NULL) { 39 redisLog(REDIS_WARNING, "Fatal error, can't open config file '%s'", filename); 40 exit(1); 41 } 42 } 43 44 while(fgets(buf,REDIS_CONFIGLINE_MAX+1,fp) != NULL) { 45 sds *argv; 46 int argc, j; 47 48 linenum++; 49 line = sdsnew(buf); 50 line = sdstrim(line," \t\r\n"); 51 52 /* Skip comments and blank lines*/ 53 if (line[0] == '#' || line[0] == '\0') { 54 sdsfree(line); 55 continue; 56 } 57 58 /* Split into arguments */ 59 argv = sdssplitargs(line,&argc); 60 sdstolower(argv[0]); 61 62 /* Execute config directives */ 63 if (!strcasecmp(argv[0],"timeout") && argc == 2) { 64 server.maxidletime = atoi(argv[1]); 65 if (server.maxidletime < 0) { 66 err = "Invalid timeout value"; goto loaderr; 67 } 68 } else if (!strcasecmp(argv[0],"port") && argc == 2) { 69 server.port = atoi(argv[1]); 70 if (server.port < 0 || server.port > 65535) { 71 err = "Invalid port"; goto loaderr; 72 } 73 } else if (!strcasecmp(argv[0],"bind") && argc == 2) { 74 server.bindaddr = zstrdup(argv[1]); 75 } else if (!strcasecmp(argv[0],"unixsocket") && argc == 2) { 76 server.unixsocket = zstrdup(argv[1]); 77 } else if (!strcasecmp(argv[0],"unixsocketperm") && argc == 2) { 78 errno = 0; 79 server.unixsocketperm = (mode_t)strtol(argv[1], NULL, 8); 80 if (errno || server.unixsocketperm > 0777) { 81 err = "Invalid socket file permissions"; goto loaderr; 82 } 83 } else if (!strcasecmp(argv[0],"save") && argc == 3) { 84 int seconds = atoi(argv[1]); 85 int changes = atoi(argv[2]); 86 if (seconds < 1 || changes < 0) { 87 err = "Invalid save parameters"; goto loaderr; 88 } 89 appendServerSaveParams(seconds,changes); 90 } else if (!strcasecmp(argv[0],"dir") && argc == 2) { 91 if (chdir(argv[1]) == -1) { 92 redisLog(REDIS_WARNING,"Can't chdir to '%s': %s", 93 argv[1], strerror(errno)); 94 exit(1); 95 } 96 } else if (!strcasecmp(argv[0],"loglevel") && argc == 2) { 97 if (!strcasecmp(argv[1],"debug")) server.verbosity = REDIS_DEBUG; 98 else if (!strcasecmp(argv[1],"verbose")) server.verbosity = REDIS_VERBOSE; 99 else if (!strcasecmp(argv[1],"notice")) server.verbosity = REDIS_NOTICE; 100 else if (!strcasecmp(argv[1],"warning")) server.verbosity = REDIS_WARNING; 101 else { 102 err = "Invalid log level. Must be one of debug, notice, warning"; 103 goto loaderr; 104 } 105 } else if (!strcasecmp(argv[0],"logfile") && argc == 2) { 106 FILE *logfp; 107 108 server.logfile = zstrdup(argv[1]); 109 if (!strcasecmp(server.logfile,"stdout")) { 110 zfree(server.logfile); 111 server.logfile = NULL; 112 } 113 if (server.logfile) { 114 /* Test if we are able to open the file. The server will not 115 * be able to abort just for this problem later... */ 116 logfp = fopen(server.logfile,"a"); 117 if (logfp == NULL) { 118 err = sdscatprintf(sdsempty(), 119 "Can't open the log file: %s", strerror(errno)); 120 goto loaderr; 121 } 122 fclose(logfp); 123 } 124 } else if (!strcasecmp(argv[0],"syslog-enabled") && argc == 2) { 125 if ((server.syslog_enabled = yesnotoi(argv[1])) == -1) { 126 err = "argument must be 'yes' or 'no'"; goto loaderr; 127 } 128 } else if (!strcasecmp(argv[0],"syslog-ident") && argc == 2) { 129 if (server.syslog_ident) zfree(server.syslog_ident); 130 server.syslog_ident = zstrdup(argv[1]); 131 } else if (!strcasecmp(argv[0],"syslog-facility") && argc == 2) { 132 struct { 133 const char *name; 134 const int value; 135 } validSyslogFacilities[] = { 136 {"user", LOG_USER}, 137 {"local0", LOG_LOCAL0}, 138 {"local1", LOG_LOCAL1}, 139 {"local2", LOG_LOCAL2}, 140 {"local3", LOG_LOCAL3}, 141 {"local4", LOG_LOCAL4}, 142 {"local5", LOG_LOCAL5}, 143 {"local6", LOG_LOCAL6}, 144 {"local7", LOG_LOCAL7}, 145 {NULL, 0} 146 }; 147 int i; 148 149 for (i = 0; validSyslogFacilities[i].name; i++) { 150 if (!strcasecmp(validSyslogFacilities[i].name, argv[1])) { 151 server.syslog_facility = validSyslogFacilities[i].value; 152 break; 153 } 154 } 155 156 if (!validSyslogFacilities[i].name) { 157 err = "Invalid log facility. Must be one of USER or between LOCAL0-LOCAL7"; 158 goto loaderr; 159 } 160 } else if (!strcasecmp(argv[0],"databases") && argc == 2) { 161 server.dbnum = atoi(argv[1]); 162 if (server.dbnum < 1) { 163 err = "Invalid number of databases"; goto loaderr; 164 } 165 } else if (!strcasecmp(argv[0],"include") && argc == 2) { 166 loadServerConfig(argv[1]); 167 } else if (!strcasecmp(argv[0],"maxclients") && argc == 2) { 168 server.maxclients = atoi(argv[1]); 169 } else if (!strcasecmp(argv[0],"maxmemory") && argc == 2) { 170 server.maxmemory = memtoll(argv[1],NULL); 171 } else if (!strcasecmp(argv[0],"maxmemory-policy") && argc == 2) { 172 if (!strcasecmp(argv[1],"volatile-lru")) { 173 server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_LRU; 174 } else if (!strcasecmp(argv[1],"volatile-random")) { 175 server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_RANDOM; 176 } else if (!strcasecmp(argv[1],"volatile-ttl")) { 177 server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_TTL; 178 } else if (!strcasecmp(argv[1],"allkeys-lru")) { 179 server.maxmemory_policy = REDIS_MAXMEMORY_ALLKEYS_LRU; 180 } else if (!strcasecmp(argv[1],"allkeys-random")) { 181 server.maxmemory_policy = REDIS_MAXMEMORY_ALLKEYS_RANDOM; 182 } else if (!strcasecmp(argv[1],"noeviction")) { 183 server.maxmemory_policy = REDIS_MAXMEMORY_NO_EVICTION; 184 } else { 185 err = "Invalid maxmemory policy"; 186 goto loaderr; 187 } 188 } else if (!strcasecmp(argv[0],"maxmemory-samples") && argc == 2) { 189 server.maxmemory_samples = atoi(argv[1]); 190 if (server.maxmemory_samples <= 0) { 191 err = "maxmemory-samples must be 1 or greater"; 192 goto loaderr; 193 } 194 } else if (!strcasecmp(argv[0],"slaveof") && argc == 3) { 195 server.masterhost = sdsnew(argv[1]); 196 server.masterport = atoi(argv[2]); 197 server.replstate = REDIS_REPL_CONNECT; 198 } else if (!strcasecmp(argv[0],"repl-ping-slave-period") && argc == 2) { 199 server.repl_ping_slave_period = atoi(argv[1]); 200 if (server.repl_ping_slave_period <= 0) { 201 err = "repl-ping-slave-period must be 1 or greater"; 202 goto loaderr; 203 } 204 } else if (!strcasecmp(argv[0],"repl-timeout") && argc == 2) { 205 server.repl_timeout = atoi(argv[1]); 206 if (server.repl_timeout <= 0) { 207 err = "repl-timeout must be 1 or greater"; 208 goto loaderr; 209 } 210 } else if (!strcasecmp(argv[0],"masterauth") && argc == 2) { 211 server.masterauth = zstrdup(argv[1]); 212 } else if (!strcasecmp(argv[0],"slave-serve-stale-data") && argc == 2) { 213 if ((server.repl_serve_stale_data = yesnotoi(argv[1])) == -1) { 214 err = "argument must be 'yes' or 'no'"; goto loaderr; 215 } 216 } else if (!strcasecmp(argv[0],"glueoutputbuf")) { 217 redisLog(REDIS_WARNING, "Deprecated configuration directive: \"%s\"", argv[0]); 218 } else if (!strcasecmp(argv[0],"rdbcompression") && argc == 2) { 219 if ((server.rdbcompression = yesnotoi(argv[1])) == -1) { 220 err = "argument must be 'yes' or 'no'"; goto loaderr; 221 } 222 } else if (!strcasecmp(argv[0],"activerehashing") && argc == 2) { 223 if ((server.activerehashing = yesnotoi(argv[1])) == -1) { 224 err = "argument must be 'yes' or 'no'"; goto loaderr; 225 } 226 } else if (!strcasecmp(argv[0],"daemonize") && argc == 2) { 227 if ((server.daemonize = yesnotoi(argv[1])) == -1) { 228 err = "argument must be 'yes' or 'no'"; goto loaderr; 229 } 230 } else if (!strcasecmp(argv[0],"appendonly") && argc == 2) { 231 if ((server.appendonly = yesnotoi(argv[1])) == -1) { 232 err = "argument must be 'yes' or 'no'"; goto loaderr; 233 } 234 } else if (!strcasecmp(argv[0],"appendfilename") && argc == 2) { 235 zfree(server.appendfilename); 236 server.appendfilename = zstrdup(argv[1]); 237 } else if (!strcasecmp(argv[0],"no-appendfsync-on-rewrite") 238 && argc == 2) { 239 if ((server.no_appendfsync_on_rewrite= yesnotoi(argv[1])) == -1) { 240 err = "argument must be 'yes' or 'no'"; goto loaderr; 241 } 242 } else if (!strcasecmp(argv[0],"appendfsync") && argc == 2) { 243 if (!strcasecmp(argv[1],"no")) { 244 server.appendfsync = APPENDFSYNC_NO; 245 } else if (!strcasecmp(argv[1],"always")) { 246 server.appendfsync = APPENDFSYNC_ALWAYS; 247 } else if (!strcasecmp(argv[1],"everysec")) { 248 server.appendfsync = APPENDFSYNC_EVERYSEC; 249 } else { 250 err = "argument must be 'no', 'always' or 'everysec'"; 251 goto loaderr; 252 } 253 } else if (!strcasecmp(argv[0],"auto-aof-rewrite-percentage") && 254 argc == 2) 255 { 256 server.auto_aofrewrite_perc = atoi(argv[1]); 257 if (server.auto_aofrewrite_perc < 0) { 258 err = "Invalid negative percentage for AOF auto rewrite"; 259 goto loaderr; 260 } 261 } else if (!strcasecmp(argv[0],"auto-aof-rewrite-min-size") && 262 argc == 2) 263 { 264 server.auto_aofrewrite_min_size = memtoll(argv[1],NULL); 265 } else if (!strcasecmp(argv[0],"requirepass") && argc == 2) { 266 server.requirepass = zstrdup(argv[1]); 267 } else if (!strcasecmp(argv[0],"pidfile") && argc == 2) { 268 zfree(server.pidfile); 269 server.pidfile = zstrdup(argv[1]); 270 } else if (!strcasecmp(argv[0],"dbfilename") && argc == 2) { 271 zfree(server.dbfilename); 272 server.dbfilename = zstrdup(argv[1]); 273 } else if (!strcasecmp(argv[0],"vm-enabled") && argc == 2) { 274 if ((server.vm_enabled = yesnotoi(argv[1])) == -1) { 275 err = "argument must be 'yes' or 'no'"; goto loaderr; 276 } 277 } else if (!strcasecmp(argv[0],"really-use-vm") && argc == 2) { 278 if ((really_use_vm = yesnotoi(argv[1])) == -1) { 279 err = "argument must be 'yes' or 'no'"; goto loaderr; 280 } 281 } else if (!strcasecmp(argv[0],"vm-swap-file") && argc == 2) { 282 zfree(server.vm_swap_file); 283 server.vm_swap_file = zstrdup(argv[1]); 284 } else if (!strcasecmp(argv[0],"vm-max-memory") && argc == 2) { 285 server.vm_max_memory = memtoll(argv[1],NULL); 286 } else if (!strcasecmp(argv[0],"vm-page-size") && argc == 2) { 287 server.vm_page_size = memtoll(argv[1], NULL); 288 } else if (!strcasecmp(argv[0],"vm-pages") && argc == 2) { 289 server.vm_pages = memtoll(argv[1], NULL); 290 } else if (!strcasecmp(argv[0],"vm-max-threads") && argc == 2) { 291 server.vm_max_threads = strtoll(argv[1], NULL, 10); 292 } else if (!strcasecmp(argv[0],"hash-max-zipmap-entries") && argc == 2) { 293 server.hash_max_zipmap_entries = memtoll(argv[1], NULL); 294 } else if (!strcasecmp(argv[0],"hash-max-zipmap-value") && argc == 2) { 295 server.hash_max_zipmap_value = memtoll(argv[1], NULL); 296 } else if (!strcasecmp(argv[0],"list-max-ziplist-entries") && argc == 2){ 297 server.list_max_ziplist_entries = memtoll(argv[1], NULL); 298 } else if (!strcasecmp(argv[0],"list-max-ziplist-value") && argc == 2) { 299 server.list_max_ziplist_value = memtoll(argv[1], NULL); 300 } else if (!strcasecmp(argv[0],"set-max-intset-entries") && argc == 2) { 301 server.set_max_intset_entries = memtoll(argv[1], NULL); 302 } else if (!strcasecmp(argv[0],"zset-max-ziplist-entries") && argc == 2) { 303 server.zset_max_ziplist_entries = memtoll(argv[1], NULL); 304 } else if (!strcasecmp(argv[0],"zset-max-ziplist-value") && argc == 2) { 305 server.zset_max_ziplist_value = memtoll(argv[1], NULL); 306 } else if (!strcasecmp(argv[0],"rename-command") && argc == 3) { 307 struct redisCommand *cmd = lookupCommand(argv[1]); 308 int retval; 309 310 if (!cmd) { 311 err = "No such command in rename-command"; 312 goto loaderr; 313 } 314 315 /* If the target command name is the emtpy string we just 316 * remove it from the command table. */ 317 retval = dictDelete(server.commands, argv[1]); 318 redisAssert(retval == DICT_OK); 319 320 /* Otherwise we re-add the command under a different name. */ 321 if (sdslen(argv[2]) != 0) { 322 sds copy = sdsdup(argv[2]); 323 324 retval = dictAdd(server.commands, copy, cmd); 325 if (retval != DICT_OK) { 326 sdsfree(copy); 327 err = "Target command name already exists"; goto loaderr; 328 } 329 } 330 } else if (!strcasecmp(argv[0],"slowlog-log-slower-than") && 331 argc == 2) 332 { 333 server.slowlog_log_slower_than = strtoll(argv[1],NULL,10); 334 } else if (!strcasecmp(argv[0],"slowlog-max-len") && argc == 2) { 335 server.slowlog_max_len = strtoll(argv[1],NULL,10); 336 } else { 337 err = "Bad directive or wrong number of arguments"; goto loaderr; 338 } 339 for (j = 0; j < argc; j++) 340 sdsfree(argv[j]); 341 zfree(argv); 342 sdsfree(line); 343 } 344 if (fp != stdin) fclose(fp); 345 if (server.vm_enabled && !really_use_vm) goto vm_warning; 346 return; 347 348 loaderr: 349 fprintf(stderr, "\n*** FATAL CONFIG FILE ERROR ***\n"); 350 fprintf(stderr, "Reading the configuration file, at line %d\n", linenum); 351 fprintf(stderr, ">>> '%s'\n", line); 352 fprintf(stderr, "%s\n", err); 353 exit(1); 354 355 vm_warning: 356 fprintf(stderr, "\nARE YOU SURE YOU WANT TO USE VM?\n\n"); 357 fprintf(stderr, "Redis Virtual Memory is going to be deprecated soon,\n"); 358 fprintf(stderr, "we think you should NOT use it, but use Redis only if\n"); 359 fprintf(stderr, "your data is suitable for an in-memory database.\n"); 360 fprintf(stderr, "If you *really* want VM add this in the config file:\n"); 361 fprintf(stderr, "\n really-use-vm yes\n\n"); 362 exit(1); 363 } 364 365 /*----------------------------------------------------------------------------- 366 * CONFIG command for remote configuration 367 *----------------------------------------------------------------------------*/ 368 369 void configSetCommand(redisClient *c) { 370 robj *o; 371 long long ll; 372 redisAssert(c->argv[2]->encoding == REDIS_ENCODING_RAW); 373 redisAssert(c->argv[3]->encoding == REDIS_ENCODING_RAW); 374 o = c->argv[3]; 375 376 if (!strcasecmp(c->argv[2]->ptr,"dbfilename")) { 377 zfree(server.dbfilename); 378 server.dbfilename = zstrdup(o->ptr); 379 } else if (!strcasecmp(c->argv[2]->ptr,"requirepass")) { 380 zfree(server.requirepass); 381 server.requirepass = ((char*)o->ptr)[0] ? zstrdup(o->ptr) : NULL; 382 } else if (!strcasecmp(c->argv[2]->ptr,"masterauth")) { 383 zfree(server.masterauth); 384 server.masterauth = zstrdup(o->ptr); 385 } else if (!strcasecmp(c->argv[2]->ptr,"maxmemory")) { 386 if (getLongLongFromObject(o,&ll) == REDIS_ERR || 387 ll < 0) goto badfmt; 388 server.maxmemory = ll; 389 if (server.maxmemory) freeMemoryIfNeeded(); 390 } else if (!strcasecmp(c->argv[2]->ptr,"maxmemory-policy")) { 391 if (!strcasecmp(o->ptr,"volatile-lru")) { 392 server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_LRU; 393 } else if (!strcasecmp(o->ptr,"volatile-random")) { 394 server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_RANDOM; 395 } else if (!strcasecmp(o->ptr,"volatile-ttl")) { 396 server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_TTL; 397 } else if (!strcasecmp(o->ptr,"allkeys-lru")) { 398 server.maxmemory_policy = REDIS_MAXMEMORY_ALLKEYS_LRU; 399 } else if (!strcasecmp(o->ptr,"allkeys-random")) { 400 server.maxmemory_policy = REDIS_MAXMEMORY_ALLKEYS_RANDOM; 401 } else if (!strcasecmp(o->ptr,"noeviction")) { 402 server.maxmemory_policy = REDIS_MAXMEMORY_NO_EVICTION; 403 } else { 404 goto badfmt; 405 } 406 } else if (!strcasecmp(c->argv[2]->ptr,"maxmemory-samples")) { 407 if (getLongLongFromObject(o,&ll) == REDIS_ERR || 408 ll <= 0) goto badfmt; 409 server.maxmemory_samples = ll; 410 } else if (!strcasecmp(c->argv[2]->ptr,"timeout")) { 411 if (getLongLongFromObject(o,&ll) == REDIS_ERR || 412 ll < 0 || ll > LONG_MAX) goto badfmt; 413 server.maxidletime = ll; 414 } else if (!strcasecmp(c->argv[2]->ptr,"appendfsync")) { 415 if (!strcasecmp(o->ptr,"no")) { 416 server.appendfsync = APPENDFSYNC_NO; 417 } else if (!strcasecmp(o->ptr,"everysec")) { 418 server.appendfsync = APPENDFSYNC_EVERYSEC; 419 } else if (!strcasecmp(o->ptr,"always")) { 420 server.appendfsync = APPENDFSYNC_ALWAYS; 421 } else { 422 goto badfmt; 423 } 424 } else if (!strcasecmp(c->argv[2]->ptr,"no-appendfsync-on-rewrite")) { 425 int yn = yesnotoi(o->ptr); 426 427 if (yn == -1) goto badfmt; 428 server.no_appendfsync_on_rewrite = yn; 429 } else if (!strcasecmp(c->argv[2]->ptr,"appendonly")) { 430 int old = server.appendonly; 431 int new = yesnotoi(o->ptr); 432 433 if (new == -1) goto badfmt; 434 if (old != new) { 435 if (new == 0) { 436 stopAppendOnly(); 437 } else { 438 if (startAppendOnly() == REDIS_ERR) { 439 addReplyError(c, 440 "Unable to turn on AOF. Check server logs."); 441 return; 442 } 443 } 444 } 445 } else if (!strcasecmp(c->argv[2]->ptr,"auto-aof-rewrite-percentage")) { 446 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt; 447 server.auto_aofrewrite_perc = ll; 448 } else if (!strcasecmp(c->argv[2]->ptr,"auto-aof-rewrite-min-size")) { 449 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt; 450 server.auto_aofrewrite_min_size = ll; 451 } else if (!strcasecmp(c->argv[2]->ptr,"save")) { 452 int vlen, j; 453 sds *v = sdssplitlen(o->ptr,sdslen(o->ptr)," ",1,&vlen); 454 455 /* Perform sanity check before setting the new config: 456 * - Even number of args 457 * - Seconds >= 1, changes >= 0 */ 458 if (vlen & 1) { 459 sdsfreesplitres(v,vlen); 460 goto badfmt; 461 } 462 for (j = 0; j < vlen; j++) { 463 char *eptr; 464 long val; 465 466 val = strtoll(v[j], &eptr, 10); 467 if (eptr[0] != '\0' || 468 ((j & 1) == 0 && val < 1) || 469 ((j & 1) == 1 && val < 0)) { 470 sdsfreesplitres(v,vlen); 471 goto badfmt; 472 } 473 } 474 /* Finally set the new config */ 475 resetServerSaveParams(); 476 for (j = 0; j < vlen; j += 2) { 477 time_t seconds; 478 int changes; 479 480 seconds = strtoll(v[j],NULL,10); 481 changes = strtoll(v[j+1],NULL,10); 482 appendServerSaveParams(seconds, changes); 483 } 484 sdsfreesplitres(v,vlen); 485 } else if (!strcasecmp(c->argv[2]->ptr,"slave-serve-stale-data")) { 486 int yn = yesnotoi(o->ptr); 487 488 if (yn == -1) goto badfmt; 489 server.repl_serve_stale_data = yn; 490 } else if (!strcasecmp(c->argv[2]->ptr,"dir")) { 491 if (chdir((char*)o->ptr) == -1) { 492 addReplyErrorFormat(c,"Changing directory: %s", strerror(errno)); 493 return; 494 } 495 } else if (!strcasecmp(c->argv[2]->ptr,"hash-max-zipmap-entries")) { 496 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt; 497 server.hash_max_zipmap_entries = ll; 498 } else if (!strcasecmp(c->argv[2]->ptr,"hash-max-zipmap-value")) { 499 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt; 500 server.hash_max_zipmap_value = ll; 501 } else if (!strcasecmp(c->argv[2]->ptr,"list-max-ziplist-entries")) { 502 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt; 503 server.list_max_ziplist_entries = ll; 504 } else if (!strcasecmp(c->argv[2]->ptr,"list-max-ziplist-value")) { 505 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt; 506 server.list_max_ziplist_value = ll; 507 } else if (!strcasecmp(c->argv[2]->ptr,"set-max-intset-entries")) { 508 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt; 509 server.set_max_intset_entries = ll; 510 } else if (!strcasecmp(c->argv[2]->ptr,"zset-max-ziplist-entries")) { 511 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt; 512 server.zset_max_ziplist_entries = ll; 513 } else if (!strcasecmp(c->argv[2]->ptr,"zset-max-ziplist-value")) { 514 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt; 515 server.zset_max_ziplist_value = ll; 516 } else if (!strcasecmp(c->argv[2]->ptr,"slowlog-log-slower-than")) { 517 if (getLongLongFromObject(o,&ll) == REDIS_ERR) goto badfmt; 518 server.slowlog_log_slower_than = ll; 519 } else if (!strcasecmp(c->argv[2]->ptr,"slowlog-max-len")) { 520 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt; 521 server.slowlog_max_len = (unsigned)ll; 522 } else if (!strcasecmp(c->argv[2]->ptr,"loglevel")) { 523 if (!strcasecmp(o->ptr,"warning")) { 524 server.verbosity = REDIS_WARNING; 525 } else if (!strcasecmp(o->ptr,"notice")) { 526 server.verbosity = REDIS_NOTICE; 527 } else if (!strcasecmp(o->ptr,"verbose")) { 528 server.verbosity = REDIS_VERBOSE; 529 } else if (!strcasecmp(o->ptr,"debug")) { 530 server.verbosity = REDIS_DEBUG; 531 } else { 532 goto badfmt; 533 } 534 } else { 535 addReplyErrorFormat(c,"Unsupported CONFIG parameter: %s", 536 (char*)c->argv[2]->ptr); 537 return; 538 } 539 addReply(c,shared.ok); 540 return; 541 542 badfmt: /* Bad format errors */ 543 addReplyErrorFormat(c,"Invalid argument '%s' for CONFIG SET '%s'", 544 (char*)o->ptr, 545 (char*)c->argv[2]->ptr); 546 } 547 548 void configGetCommand(redisClient *c) { 549 robj *o = c->argv[2]; 550 void *replylen = addDeferredMultiBulkLength(c); 551 char *pattern = o->ptr; 552 char buf[128]; 553 int matches = 0; 554 redisAssert(o->encoding == REDIS_ENCODING_RAW); 555 556 if (stringmatch(pattern,"dir",0)) { 557 char buf[1024]; 558 559 if (getcwd(buf,sizeof(buf)) == NULL) 560 buf[0] = '\0'; 561 562 addReplyBulkCString(c,"dir"); 563 addReplyBulkCString(c,buf); 564 matches++; 565 } 566 if (stringmatch(pattern,"dbfilename",0)) { 567 addReplyBulkCString(c,"dbfilename"); 568 addReplyBulkCString(c,server.dbfilename); 569 matches++; 570 } 571 if (stringmatch(pattern,"requirepass",0)) { 572 addReplyBulkCString(c,"requirepass"); 573 addReplyBulkCString(c,server.requirepass); 574 matches++; 575 } 576 if (stringmatch(pattern,"masterauth",0)) { 577 addReplyBulkCString(c,"masterauth"); 578 addReplyBulkCString(c,server.masterauth); 579 matches++; 580 } 581 if (stringmatch(pattern,"maxmemory",0)) { 582 ll2string(buf,sizeof(buf),server.maxmemory); 583 addReplyBulkCString(c,"maxmemory"); 584 addReplyBulkCString(c,buf); 585 matches++; 586 } 587 if (stringmatch(pattern,"maxmemory-policy",0)) { 588 char *s; 589 590 switch(server.maxmemory_policy) { 591 case REDIS_MAXMEMORY_VOLATILE_LRU: s = "volatile-lru"; break; 592 case REDIS_MAXMEMORY_VOLATILE_TTL: s = "volatile-ttl"; break; 593 case REDIS_MAXMEMORY_VOLATILE_RANDOM: s = "volatile-random"; break; 594 case REDIS_MAXMEMORY_ALLKEYS_LRU: s = "allkeys-lru"; break; 595 case REDIS_MAXMEMORY_ALLKEYS_RANDOM: s = "allkeys-random"; break; 596 case REDIS_MAXMEMORY_NO_EVICTION: s = "noeviction"; break; 597 default: s = "unknown"; break; /* too harmless to panic */ 598 } 599 addReplyBulkCString(c,"maxmemory-policy"); 600 addReplyBulkCString(c,s); 601 matches++; 602 } 603 if (stringmatch(pattern,"maxmemory-samples",0)) { 604 ll2string(buf,sizeof(buf),server.maxmemory_samples); 605 addReplyBulkCString(c,"maxmemory-samples"); 606 addReplyBulkCString(c,buf); 607 matches++; 608 } 609 if (stringmatch(pattern,"timeout",0)) { 610 ll2string(buf,sizeof(buf),server.maxidletime); 611 addReplyBulkCString(c,"timeout"); 612 addReplyBulkCString(c,buf); 613 matches++; 614 } 615 if (stringmatch(pattern,"appendonly",0)) { 616 addReplyBulkCString(c,"appendonly"); 617 addReplyBulkCString(c,server.appendonly ? "yes" : "no"); 618 matches++; 619 } 620 if (stringmatch(pattern,"no-appendfsync-on-rewrite",0)) { 621 addReplyBulkCString(c,"no-appendfsync-on-rewrite"); 622 addReplyBulkCString(c,server.no_appendfsync_on_rewrite ? "yes" : "no"); 623 matches++; 624 } 625 if (stringmatch(pattern,"appendfsync",0)) { 626 char *policy; 627 628 switch(server.appendfsync) { 629 case APPENDFSYNC_NO: policy = "no"; break; 630 case APPENDFSYNC_EVERYSEC: policy = "everysec"; break; 631 case APPENDFSYNC_ALWAYS: policy = "always"; break; 632 default: policy = "unknown"; break; /* too harmless to panic */ 633 } 634 addReplyBulkCString(c,"appendfsync"); 635 addReplyBulkCString(c,policy); 636 matches++; 637 } 638 if (stringmatch(pattern,"save",0)) { 639 sds buf = sdsempty(); 640 int j; 641 642 for (j = 0; j < server.saveparamslen; j++) { 643 buf = sdscatprintf(buf,"%ld %d", 644 server.saveparams[j].seconds, 645 server.saveparams[j].changes); 646 if (j != server.saveparamslen-1) 647 buf = sdscatlen(buf," ",1); 648 } 649 addReplyBulkCString(c,"save"); 650 addReplyBulkCString(c,buf); 651 sdsfree(buf); 652 matches++; 653 } 654 if (stringmatch(pattern,"auto-aof-rewrite-percentage",0)) { 655 addReplyBulkCString(c,"auto-aof-rewrite-percentage"); 656 addReplyBulkLongLong(c,server.auto_aofrewrite_perc); 657 matches++; 658 } 659 if (stringmatch(pattern,"auto-aof-rewrite-min-size",0)) { 660 addReplyBulkCString(c,"auto-aof-rewrite-min-size"); 661 addReplyBulkLongLong(c,server.auto_aofrewrite_min_size); 662 matches++; 663 } 664 if (stringmatch(pattern,"slave-serve-stale-data",0)) { 665 addReplyBulkCString(c,"slave-serve-stale-data"); 666 addReplyBulkCString(c,server.repl_serve_stale_data ? "yes" : "no"); 667 matches++; 668 } 669 if (stringmatch(pattern,"hash-max-zipmap-entries",0)) { 670 addReplyBulkCString(c,"hash-max-zipmap-entries"); 671 addReplyBulkLongLong(c,server.hash_max_zipmap_entries); 672 matches++; 673 } 674 if (stringmatch(pattern,"hash-max-zipmap-value",0)) { 675 addReplyBulkCString(c,"hash-max-zipmap-value"); 676 addReplyBulkLongLong(c,server.hash_max_zipmap_value); 677 matches++; 678 } 679 if (stringmatch(pattern,"list-max-ziplist-entries",0)) { 680 addReplyBulkCString(c,"list-max-ziplist-entries"); 681 addReplyBulkLongLong(c,server.list_max_ziplist_entries); 682 matches++; 683 } 684 if (stringmatch(pattern,"list-max-ziplist-value",0)) { 685 addReplyBulkCString(c,"list-max-ziplist-value"); 686 addReplyBulkLongLong(c,server.list_max_ziplist_value); 687 matches++; 688 } 689 if (stringmatch(pattern,"set-max-intset-entries",0)) { 690 addReplyBulkCString(c,"set-max-intset-entries"); 691 addReplyBulkLongLong(c,server.set_max_intset_entries); 692 matches++; 693 } 694 if (stringmatch(pattern,"zset-max-ziplist-entries",0)) { 695 addReplyBulkCString(c,"zset-max-ziplist-entries"); 696 addReplyBulkLongLong(c,server.zset_max_ziplist_entries); 697 matches++; 698 } 699 if (stringmatch(pattern,"zset-max-ziplist-value",0)) { 700 addReplyBulkCString(c,"zset-max-ziplist-value"); 701 addReplyBulkLongLong(c,server.zset_max_ziplist_value); 702 matches++; 703 } 704 if (stringmatch(pattern,"slowlog-log-slower-than",0)) { 705 addReplyBulkCString(c,"slowlog-log-slower-than"); 706 addReplyBulkLongLong(c,server.slowlog_log_slower_than); 707 matches++; 708 } 709 if (stringmatch(pattern,"slowlog-max-len",0)) { 710 addReplyBulkCString(c,"slowlog-max-len"); 711 addReplyBulkLongLong(c,server.slowlog_max_len); 712 matches++; 713 } 714 if (stringmatch(pattern,"loglevel",0)) { 715 char *s; 716 717 switch(server.verbosity) { 718 case REDIS_WARNING: s = "warning"; break; 719 case REDIS_VERBOSE: s = "verbose"; break; 720 case REDIS_NOTICE: s = "notice"; break; 721 case REDIS_DEBUG: s = "debug"; break; 722 default: s = "unknown"; break; /* too harmless to panic */ 723 } 724 addReplyBulkCString(c,"loglevel"); 725 addReplyBulkCString(c,s); 726 matches++; 727 } 728 setDeferredMultiBulkLength(c,replylen,matches*2); 729 } 730 731 void configCommand(redisClient *c) { 732 if (!strcasecmp(c->argv[1]->ptr,"set")) { 733 if (c->argc != 4) goto badarity; 734 configSetCommand(c); 735 } else if (!strcasecmp(c->argv[1]->ptr,"get")) { 736 if (c->argc != 3) goto badarity; 737 configGetCommand(c); 738 } else if (!strcasecmp(c->argv[1]->ptr,"resetstat")) { 739 if (c->argc != 2) goto badarity; 740 server.stat_keyspace_hits = 0; 741 server.stat_keyspace_misses = 0; 742 server.stat_numcommands = 0; 743 server.stat_numconnections = 0; 744 server.stat_expiredkeys = 0; 745 addReply(c,shared.ok); 746 } else { 747 addReplyError(c, 748 "CONFIG subcommand must be one of GET, SET, RESETSTAT"); 749 } 750 return; 751 752 badarity: 753 addReplyErrorFormat(c,"Wrong number of arguments for CONFIG %s", 754 (char*) c->argv[1]->ptr); 755 }