1 #include "redis.h" 2 3 #include <signal.h> 4 5 void SlotToKeyAdd(robj *key); 6 void SlotToKeyDel(robj *key); 7 8 /*----------------------------------------------------------------------------- 9 * C-level DB API 10 *----------------------------------------------------------------------------*/ 11 12 /* Important notes on lookup and disk store. 13 * 14 * When disk store is enabled on lookup we can have different cases. 15 * 16 * a) The key is in memory: 17 * - If the key is not in IO_SAVEINPROG state we can access it. 18 * As if it's just IO_SAVE this means we have the key in the IO queue 19 * but can't be accessed by the IO thread (it requires to be 20 * translated into an IO Job by the cache cron function.) 21 * - If the key is in IO_SAVEINPROG we can't touch the key and have 22 * to blocking wait completion of operations. 23 * b) The key is not in memory: 24 * - If it's marked as non existing on disk as well (negative cache) 25 * we don't need to perform the disk access. 26 * - if the key MAY EXIST, but is not in memory, and it is marked as IO_SAVE 27 * then the key can only be a deleted one. As IO_SAVE keys are never 28 * evicted (dirty state), so the only possibility is that key was deleted. 29 * - if the key MAY EXIST we need to blocking load it. 30 * We check that the key is not in IO_SAVEINPROG state before accessing 31 * the disk object. If it is in this state, we wait. 32 */ 33 34 robj *lookupKey(redisDb *db, robj *key) { 35 dictEntry *de = dictFind(db->dict,key->ptr); 36 if (de) { 37 robj *val = dictGetEntryVal(de); 38 39 /* Update the access time for the aging algorithm. 40 * Don't do it if we have a saving child, as this will trigger 41 * a copy on write madness. */ 42 if (server.bgsavechildpid == -1 && server.bgrewritechildpid == -1) 43 val->lru = server.lruclock; 44 server.stat_keyspace_hits++; 45 return val; 46 } else { 47 server.stat_keyspace_misses++; 48 return NULL; 49 } 50 } 51 52 robj *lookupKeyRead(redisDb *db, robj *key) { 53 expireIfNeeded(db,key); 54 return lookupKey(db,key); 55 } 56 57 robj *lookupKeyWrite(redisDb *db, robj *key) { 58 expireIfNeeded(db,key); 59 return lookupKey(db,key); 60 } 61 62 robj *lookupKeyReadOrReply(redisClient *c, robj *key, robj *reply) { 63 robj *o = lookupKeyRead(c->db, key); 64 if (!o) addReply(c,reply); 65 return o; 66 } 67 68 robj *lookupKeyWriteOrReply(redisClient *c, robj *key, robj *reply) { 69 robj *o = lookupKeyWrite(c->db, key); 70 if (!o) addReply(c,reply); 71 return o; 72 } 73 74 /* Add the key to the DB. It's up to the caller to increment the reference 75 * counte of the value if needed. 76 * 77 * The program is aborted if the key already exists. */ 78 void dbAdd(redisDb *db, robj *key, robj *val) { 79 sds copy = sdsdup(key->ptr); 80 int retval = dictAdd(db->dict, copy, val); 81 82 redisAssert(retval == REDIS_OK); 83 if (server.cluster_enabled) SlotToKeyAdd(key); 84 } 85 86 /* Overwrite an existing key with a new value. Incrementing the reference 87 * count of the new value is up to the caller. 88 * This function does not modify the expire time of the existing key. 89 * 90 * The program is aborted if the key was not already present. */ 91 void dbOverwrite(redisDb *db, robj *key, robj *val) { 92 struct dictEntry *de = dictFind(db->dict,key->ptr); 93 94 redisAssert(de != NULL); 95 dictReplace(db->dict, key->ptr, val); 96 } 97 98 /* High level Set operation. This function can be used in order to set 99 * a key, whatever it was existing or not, to a new object. 100 * 101 * 1) The ref count of the value object is incremented. 102 * 2) clients WATCHing for the destination key notified. 103 * 3) The expire time of the key is reset (the key is made persistent). */ 104 void setKey(redisDb *db, robj *key, robj *val) { 105 if (lookupKeyWrite(db,key) == NULL) { 106 dbAdd(db,key,val); 107 } else { 108 dbOverwrite(db,key,val); 109 } 110 incrRefCount(val); 111 removeExpire(db,key); 112 touchWatchedKey(db,key); 113 } 114 115 int dbExists(redisDb *db, robj *key) { 116 return dictFind(db->dict,key->ptr) != NULL; 117 } 118 119 /* Return a random key, in form of a Redis object. 120 * If there are no keys, NULL is returned. 121 * 122 * The function makes sure to return keys not already expired. */ 123 robj *dbRandomKey(redisDb *db) { 124 struct dictEntry *de; 125 126 while(1) { 127 sds key; 128 robj *keyobj; 129 130 de = dictGetRandomKey(db->dict); 131 if (de == NULL) return NULL; 132 133 key = dictGetEntryKey(de); 134 keyobj = createStringObject(key,sdslen(key)); 135 if (dictFind(db->expires,key)) { 136 if (expireIfNeeded(db,keyobj)) { 137 decrRefCount(keyobj); 138 continue; /* search for another key. This expired. */ 139 } 140 } 141 return keyobj; 142 } 143 } 144 145 /* Delete a key, value, and associated expiration entry if any, from the DB */ 146 int dbDelete(redisDb *db, robj *key) { 147 /* Deleting an entry from the expires dict will not free the sds of 148 * the key, because it is shared with the main dictionary. */ 149 if (dictSize(db->expires) > 0) dictDelete(db->expires,key->ptr); 150 if (dictDelete(db->dict,key->ptr) == DICT_OK) { 151 if (server.cluster_enabled) SlotToKeyDel(key); 152 return 1; 153 } else { 154 return 0; 155 } 156 } 157 158 /* Empty the whole database. 159 * If diskstore is enabled this function will just flush the in-memory cache. */ 160 long long emptyDb() { 161 int j; 162 long long removed = 0; 163 164 for (j = 0; j < server.dbnum; j++) { 165 removed += dictSize(server.db[j].dict); 166 dictEmpty(server.db[j].dict); 167 dictEmpty(server.db[j].expires); 168 } 169 return removed; 170 } 171 172 int selectDb(redisClient *c, int id) { 173 if (id < 0 || id >= server.dbnum) 174 return REDIS_ERR; 175 c->db = &server.db[id]; 176 return REDIS_OK; 177 } 178 179 /*----------------------------------------------------------------------------- 180 * Hooks for key space changes. 181 * 182 * Every time a key in the database is modified the function 183 * signalModifiedKey() is called. 184 * 185 * Every time a DB is flushed the function signalFlushDb() is called. 186 *----------------------------------------------------------------------------*/ 187 188 void signalModifiedKey(redisDb *db, robj *key) { 189 touchWatchedKey(db,key); 190 } 191 192 void signalFlushedDb(int dbid) { 193 touchWatchedKeysOnFlush(dbid); 194 } 195 196 /*----------------------------------------------------------------------------- 197 * Type agnostic commands operating on the key space 198 *----------------------------------------------------------------------------*/ 199 200 void flushdbCommand(redisClient *c) { 201 server.dirty += dictSize(c->db->dict); 202 signalFlushedDb(c->db->id); 203 dictEmpty(c->db->dict); 204 dictEmpty(c->db->expires); 205 addReply(c,shared.ok); 206 } 207 208 void flushallCommand(redisClient *c) { 209 signalFlushedDb(-1); 210 server.dirty += emptyDb(); 211 addReply(c,shared.ok); 212 if (server.bgsavechildpid != -1) { 213 kill(server.bgsavechildpid,SIGKILL); 214 rdbRemoveTempFile(server.bgsavechildpid); 215 } 216 rdbSave(server.dbfilename); 217 server.dirty++; 218 } 219 220 void delCommand(redisClient *c) { 221 int deleted = 0, j; 222 223 for (j = 1; j < c->argc; j++) { 224 if (dbDelete(c->db,c->argv[j])) { 225 signalModifiedKey(c->db,c->argv[j]); 226 server.dirty++; 227 deleted++; 228 } 229 } 230 addReplyLongLong(c,deleted); 231 } 232 233 void existsCommand(redisClient *c) { 234 expireIfNeeded(c->db,c->argv[1]); 235 if (dbExists(c->db,c->argv[1])) { 236 addReply(c, shared.cone); 237 } else { 238 addReply(c, shared.czero); 239 } 240 } 241 242 void selectCommand(redisClient *c) { 243 int id = atoi(c->argv[1]->ptr); 244 245 if (server.cluster_enabled && id != 0) { 246 addReplyError(c,"SELECT is not allowed in cluster mode"); 247 return; 248 } 249 if (selectDb(c,id) == REDIS_ERR) { 250 addReplyError(c,"invalid DB index"); 251 } else { 252 addReply(c,shared.ok); 253 } 254 } 255 256 void randomkeyCommand(redisClient *c) { 257 robj *key; 258 259 if ((key = dbRandomKey(c->db)) == NULL) { 260 addReply(c,shared.nullbulk); 261 return; 262 } 263 264 addReplyBulk(c,key); 265 decrRefCount(key); 266 } 267 268 void keysCommand(redisClient *c) { 269 dictIterator *di; 270 dictEntry *de; 271 sds pattern = c->argv[1]->ptr; 272 int plen = sdslen(pattern), allkeys; 273 unsigned long numkeys = 0; 274 void *replylen = addDeferredMultiBulkLength(c); 275 276 di = dictGetIterator(c->db->dict); 277 allkeys = (pattern[0] == '*' && pattern[1] == '\0'); 278 while((de = dictNext(di)) != NULL) { 279 sds key = dictGetEntryKey(de); 280 robj *keyobj; 281 282 if (allkeys || stringmatchlen(pattern,plen,key,sdslen(key),0)) { 283 keyobj = createStringObject(key,sdslen(key)); 284 if (expireIfNeeded(c->db,keyobj) == 0) { 285 addReplyBulk(c,keyobj); 286 numkeys++; 287 } 288 decrRefCount(keyobj); 289 } 290 } 291 dictReleaseIterator(di); 292 setDeferredMultiBulkLength(c,replylen,numkeys); 293 } 294 295 void dbsizeCommand(redisClient *c) { 296 addReplyLongLong(c,dictSize(c->db->dict)); 297 } 298 299 void lastsaveCommand(redisClient *c) { 300 addReplyLongLong(c,server.lastsave); 301 } 302 303 void typeCommand(redisClient *c) { 304 robj *o; 305 char *type; 306 307 o = lookupKeyRead(c->db,c->argv[1]); 308 if (o == NULL) { 309 type = "none"; 310 } else { 311 switch(o->type) { 312 case REDIS_STRING: type = "string"; break; 313 case REDIS_LIST: type = "list"; break; 314 case REDIS_SET: type = "set"; break; 315 case REDIS_ZSET: type = "zset"; break; 316 case REDIS_HASH: type = "hash"; break; 317 default: type = "unknown"; break; 318 } 319 } 320 addReplyStatus(c,type); 321 } 322 323 void shutdownCommand(redisClient *c) { 324 if (prepareForShutdown() == REDIS_OK) 325 exit(0); 326 addReplyError(c,"Errors trying to SHUTDOWN. Check logs."); 327 } 328 329 void renameGenericCommand(redisClient *c, int nx) { 330 robj *o; 331 332 /* To use the same key as src and dst is probably an error */ 333 if (sdscmp(c->argv[1]->ptr,c->argv[2]->ptr) == 0) { 334 addReply(c,shared.sameobjecterr); 335 return; 336 } 337 338 if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.nokeyerr)) == NULL) 339 return; 340 341 incrRefCount(o); 342 if (lookupKeyWrite(c->db,c->argv[2]) != NULL) { 343 if (nx) { 344 decrRefCount(o); 345 addReply(c,shared.czero); 346 return; 347 } 348 dbOverwrite(c->db,c->argv[2],o); 349 } else { 350 dbAdd(c->db,c->argv[2],o); 351 } 352 dbDelete(c->db,c->argv[1]); 353 signalModifiedKey(c->db,c->argv[1]); 354 signalModifiedKey(c->db,c->argv[2]); 355 server.dirty++; 356 addReply(c,nx ? shared.cone : shared.ok); 357 } 358 359 void renameCommand(redisClient *c) { 360 renameGenericCommand(c,0); 361 } 362 363 void renamenxCommand(redisClient *c) { 364 renameGenericCommand(c,1); 365 } 366 367 void moveCommand(redisClient *c) { 368 robj *o; 369 redisDb *src, *dst; 370 int srcid; 371 372 if (server.cluster_enabled) { 373 addReplyError(c,"MOVE is not allowed in cluster mode"); 374 return; 375 } 376 377 /* Obtain source and target DB pointers */ 378 src = c->db; 379 srcid = c->db->id; 380 if (selectDb(c,atoi(c->argv[2]->ptr)) == REDIS_ERR) { 381 addReply(c,shared.outofrangeerr); 382 return; 383 } 384 dst = c->db; 385 selectDb(c,srcid); /* Back to the source DB */ 386 387 /* If the user is moving using as target the same 388 * DB as the source DB it is probably an error. */ 389 if (src == dst) { 390 addReply(c,shared.sameobjecterr); 391 return; 392 } 393 394 /* Check if the element exists and get a reference */ 395 o = lookupKeyWrite(c->db,c->argv[1]); 396 if (!o) { 397 addReply(c,shared.czero); 398 return; 399 } 400 401 /* Return zero if the key already exists in the target DB */ 402 if (lookupKeyWrite(dst,c->argv[1]) != NULL) { 403 addReply(c,shared.czero); 404 return; 405 } 406 dbAdd(dst,c->argv[1],o); 407 incrRefCount(o); 408 409 /* OK! key moved, free the entry in the source DB */ 410 dbDelete(src,c->argv[1]); 411 server.dirty++; 412 addReply(c,shared.cone); 413 } 414 415 /*----------------------------------------------------------------------------- 416 * Expires API 417 *----------------------------------------------------------------------------*/ 418 419 int removeExpire(redisDb *db, robj *key) { 420 /* An expire may only be removed if there is a corresponding entry in the 421 * main dict. Otherwise, the key will never be freed. */ 422 redisAssert(dictFind(db->dict,key->ptr) != NULL); 423 return dictDelete(db->expires,key->ptr) == DICT_OK; 424 } 425 426 void setExpire(redisDb *db, robj *key, time_t when) { 427 dictEntry *de; 428 429 /* Reuse the sds from the main dict in the expire dict */ 430 de = dictFind(db->dict,key->ptr); 431 redisAssert(de != NULL); 432 dictReplace(db->expires,dictGetEntryKey(de),(void*)when); 433 } 434 435 /* Return the expire time of the specified key, or -1 if no expire 436 * is associated with this key (i.e. the key is non volatile) */ 437 time_t getExpire(redisDb *db, robj *key) { 438 dictEntry *de; 439 440 /* No expire? return ASAP */ 441 if (dictSize(db->expires) == 0 || 442 (de = dictFind(db->expires,key->ptr)) == NULL) return -1; 443 444 /* The entry was found in the expire dict, this means it should also 445 * be present in the main dict (safety check). */ 446 redisAssert(dictFind(db->dict,key->ptr) != NULL); 447 return (time_t) dictGetEntryVal(de); 448 } 449 450 /* Propagate expires into slaves and the AOF file. 451 * When a key expires in the master, a DEL operation for this key is sent 452 * to all the slaves and the AOF file if enabled. 453 * 454 * This way the key expiry is centralized in one place, and since both 455 * AOF and the master->slave link guarantee operation ordering, everything 456 * will be consistent even if we allow write operations against expiring 457 * keys. */ 458 void propagateExpire(redisDb *db, robj *key) { 459 robj *argv[2]; 460 461 argv[0] = createStringObject("DEL",3); 462 argv[1] = key; 463 incrRefCount(key); 464 465 if (server.appendonly) 466 feedAppendOnlyFile(server.delCommand,db->id,argv,2); 467 if (listLength(server.slaves)) 468 replicationFeedSlaves(server.slaves,db->id,argv,2); 469 470 decrRefCount(argv[0]); 471 decrRefCount(argv[1]); 472 } 473 474 int expireIfNeeded(redisDb *db, robj *key) { 475 time_t when = getExpire(db,key); 476 477 if (when < 0) return 0; /* No expire for this key */ 478 479 /* If we are running in the context of a slave, return ASAP: 480 * the slave key expiration is controlled by the master that will 481 * send us synthesized DEL operations for expired keys. 482 * 483 * Still we try to return the right information to the caller, 484 * that is, 0 if we think the key should be still valid, 1 if 485 * we think the key is expired at this time. */ 486 if (server.masterhost != NULL) { 487 return time(NULL) > when; 488 } 489 490 /* Return when this key has not expired */ 491 if (time(NULL) <= when) return 0; 492 493 /* Delete the key */ 494 server.stat_expiredkeys++; 495 propagateExpire(db,key); 496 return dbDelete(db,key); 497 } 498 499 /*----------------------------------------------------------------------------- 500 * Expires Commands 501 *----------------------------------------------------------------------------*/ 502 503 void expireGenericCommand(redisClient *c, robj *key, robj *param, long offset) { 504 dictEntry *de; 505 long seconds; 506 507 if (getLongFromObjectOrReply(c, param, &seconds, NULL) != REDIS_OK) return; 508 509 seconds -= offset; 510 511 de = dictFind(c->db->dict,key->ptr); 512 if (de == NULL) { 513 addReply(c,shared.czero); 514 return; 515 } 516 if (seconds <= 0) { 517 if (dbDelete(c->db,key)) server.dirty++; 518 addReply(c, shared.cone); 519 signalModifiedKey(c->db,key); 520 return; 521 } else { 522 time_t when = time(NULL)+seconds; 523 setExpire(c->db,key,when); 524 addReply(c,shared.cone); 525 signalModifiedKey(c->db,key); 526 server.dirty++; 527 return; 528 } 529 } 530 531 void expireCommand(redisClient *c) { 532 expireGenericCommand(c,c->argv[1],c->argv[2],0); 533 } 534 535 void expireatCommand(redisClient *c) { 536 expireGenericCommand(c,c->argv[1],c->argv[2],time(NULL)); 537 } 538 539 void ttlCommand(redisClient *c) { 540 time_t expire, ttl = -1; 541 542 expire = getExpire(c->db,c->argv[1]); 543 if (expire != -1) { 544 ttl = (expire-time(NULL)); 545 if (ttl < 0) ttl = -1; 546 } 547 addReplyLongLong(c,(long long)ttl); 548 } 549 550 void persistCommand(redisClient *c) { 551 dictEntry *de; 552 553 de = dictFind(c->db->dict,c->argv[1]->ptr); 554 if (de == NULL) { 555 addReply(c,shared.czero); 556 } else { 557 if (removeExpire(c->db,c->argv[1])) { 558 addReply(c,shared.cone); 559 server.dirty++; 560 } else { 561 addReply(c,shared.czero); 562 } 563 } 564 } 565 566 /* ----------------------------------------------------------------------------- 567 * API to get key arguments from commands 568 * ---------------------------------------------------------------------------*/ 569 570 int *getKeysUsingCommandTable(struct redisCommand *cmd,robj **argv, int argc, int *numkeys) { 571 int j, i = 0, last, *keys; 572 REDIS_NOTUSED(argv); 573 574 if (cmd->firstkey == 0) { 575 *numkeys = 0; 576 return NULL; 577 } 578 last = cmd->lastkey; 579 if (last < 0) last = argc+last; 580 keys = zmalloc(sizeof(int)*((last - cmd->firstkey)+1)); 581 for (j = cmd->firstkey; j <= last; j += cmd->keystep) { 582 redisAssert(j < argc); 583 keys[i++] = j; 584 } 585 *numkeys = i; 586 return keys; 587 } 588 589 int *getKeysFromCommand(struct redisCommand *cmd,robj **argv, int argc, int *numkeys, int flags) { 590 if (cmd->getkeys_proc) { 591 return cmd->getkeys_proc(cmd,argv,argc,numkeys,flags); 592 } else { 593 return getKeysUsingCommandTable(cmd,argv,argc,numkeys); 594 } 595 } 596 597 void getKeysFreeResult(int *result) { 598 zfree(result); 599 } 600 601 int *noPreloadGetKeys(struct redisCommand *cmd,robj **argv, int argc, int *numkeys, int flags) { 602 if (flags & REDIS_GETKEYS_PRELOAD) { 603 *numkeys = 0; 604 return NULL; 605 } else { 606 return getKeysUsingCommandTable(cmd,argv,argc,numkeys); 607 } 608 } 609 610 int *renameGetKeys(struct redisCommand *cmd,robj **argv, int argc, int *numkeys, int flags) { 611 if (flags & REDIS_GETKEYS_PRELOAD) { 612 int *keys = zmalloc(sizeof(int)); 613 *numkeys = 1; 614 keys[0] = 1; 615 return keys; 616 } else { 617 return getKeysUsingCommandTable(cmd,argv,argc,numkeys); 618 } 619 } 620 621 int *zunionInterGetKeys(struct redisCommand *cmd,robj **argv, int argc, int *numkeys, int flags) { 622 int i, num, *keys; 623 REDIS_NOTUSED(cmd); 624 REDIS_NOTUSED(flags); 625 626 num = atoi(argv[2]->ptr); 627 /* Sanity check. Don't return any key if the command is going to 628 * reply with syntax error. */ 629 if (num > (argc-3)) { 630 *numkeys = 0; 631 return NULL; 632 } 633 keys = zmalloc(sizeof(int)*num); 634 for (i = 0; i < num; i++) keys[i] = 3+i; 635 *numkeys = num; 636 return keys; 637 } 638 639 /* Slot to Key API. This is used by Redis Cluster in order to obtain in 640 * a fast way a key that belongs to a specified hash slot. This is useful 641 * while rehashing the cluster. */ 642 void SlotToKeyAdd(robj *key) { 643 unsigned int hashslot = keyHashSlot(key->ptr,sdslen(key->ptr)); 644 645 zslInsert(server.cluster.slots_to_keys,hashslot,key); 646 incrRefCount(key); 647 } 648 649 void SlotToKeyDel(robj *key) { 650 unsigned int hashslot = keyHashSlot(key->ptr,sdslen(key->ptr)); 651 652 zslDelete(server.cluster.slots_to_keys,hashslot,key); 653 } 654 655 unsigned int GetKeysInSlot(unsigned int hashslot, robj **keys, unsigned int count) { 656 zskiplistNode *n; 657 zrangespec range; 658 int j = 0; 659 660 range.min = range.max = hashslot; 661 range.minex = range.maxex = 0; 662 663 n = zslFirstInRange(server.cluster.slots_to_keys, range); 664 while(n && n->score == hashslot && count--) { 665 keys[j++] = n->obj; 666 n = n->level[0].forward; 667 } 668 return j; 669 } 670