This is the generic command implementation for EXPIRE, PEXPIRE, EXPIREAT * and PEXPIREAT. Because the command second argument may be relative or absolute * the "basetime" argument is used to signal what the base time is (either 0 * for *AT variants of the command, or the current time for relative expires). * * unit is either UNIT_SECONDS or UNIT_MILLISECONDS, and is only used for * the argv[
| 488 | * unit is either UNIT_SECONDS or UNIT_MILLISECONDS, and is only used for |
| 489 | * the argv[2] parameter. The basetime is always specified in milliseconds. */ |
| 490 | void expireGenericCommand(client *c, long long basetime, int unit) { |
| 491 | robj *key = c->argv[1], *param = c->argv[2]; |
| 492 | long long when; /* unix time in milliseconds when the key will expire. */ |
| 493 | |
| 494 | if (getLongLongFromObjectOrReply(c, param, &when, NULL) != C_OK) |
| 495 | return; |
| 496 | int negative_when = when < 0; |
| 497 | if (unit == UNIT_SECONDS) when *= 1000; |
| 498 | when += basetime; |
| 499 | if (((when < 0) && !negative_when) || ((when-basetime > 0) && negative_when)) { |
| 500 | /* EXPIRE allows negative numbers, but we can at least detect an |
| 501 | * overflow by either unit conversion or basetime addition. */ |
| 502 | addReplyErrorFormat(c, "invalid expire time in %s", c->cmd->name); |
| 503 | return; |
| 504 | } |
| 505 | /* No key, return zero. */ |
| 506 | if (lookupKeyWrite(c->db,key) == NULL) { |
| 507 | addReply(c,shared.czero); |
| 508 | return; |
| 509 | } |
| 510 | |
| 511 | if (checkAlreadyExpired(when)) { |
| 512 | robj *aux; |
| 513 | |
| 514 | int deleted = server.lazyfree_lazy_expire ? dbAsyncDelete(c->db,key) : |
| 515 | dbSyncDelete(c->db,key); |
| 516 | serverAssertWithInfo(c,key,deleted); |
| 517 | server.dirty++; |
| 518 | |
| 519 | /* Replicate/AOF this as an explicit DEL or UNLINK. */ |
| 520 | aux = server.lazyfree_lazy_expire ? shared.unlink : shared.del; |
| 521 | rewriteClientCommandVector(c,2,aux,key); |
| 522 | signalModifiedKey(c,c->db,key); |
| 523 | notifyKeyspaceEvent(NOTIFY_GENERIC,"del",key,c->db->id); |
| 524 | addReply(c, shared.cone); |
| 525 | return; |
| 526 | } else { |
| 527 | setExpire(c,c->db,key,when); |
| 528 | addReply(c,shared.cone); |
| 529 | signalModifiedKey(c,c->db,key); |
| 530 | notifyKeyspaceEvent(NOTIFY_GENERIC,"expire",key,c->db->id); |
| 531 | server.dirty++; |
| 532 | return; |
| 533 | } |
| 534 | } |
| 535 | |
| 536 | /* EXPIRE key seconds */ |
| 537 | void expireCommand(client *c) { |
no test coverage detected