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[
| 737 | * unit is either UNIT_SECONDS or UNIT_MILLISECONDS, and is only used for |
| 738 | * the argv[2] parameter. The basetime is always specified in milliseconds. */ |
| 739 | void expireGenericCommand(client *c, long long basetime, int unit) { |
| 740 | robj *key = c->argv[1], *param = c->argv[2]; |
| 741 | long long when; /* unix time in milliseconds when the key will expire. */ |
| 742 | |
| 743 | if (getLongLongFromObjectOrReply(c, param, &when, NULL) != C_OK) |
| 744 | return; |
| 745 | int negative_when = when < 0; |
| 746 | if (unit == UNIT_SECONDS) when *= 1000; |
| 747 | when += basetime; |
| 748 | if (((when < 0) && !negative_when) || ((when-basetime > 0) && negative_when)) { |
| 749 | /* EXPIRE allows negative numbers, but we can at least detect an |
| 750 | * overflow by either unit conversion or basetime addition. */ |
| 751 | addReplyErrorFormat(c, "invalid expire time in %s", c->cmd->name); |
| 752 | return; |
| 753 | } |
| 754 | /* No key, return zero. */ |
| 755 | if (lookupKeyWrite(c->db,key) == NULL) { |
| 756 | addReply(c,shared.czero); |
| 757 | return; |
| 758 | } |
| 759 | |
| 760 | if (checkAlreadyExpired(when)) { |
| 761 | robj *aux; |
| 762 | |
| 763 | int deleted = g_pserver->lazyfree_lazy_expire ? dbAsyncDelete(c->db,key) : |
| 764 | dbSyncDelete(c->db,key); |
| 765 | serverAssertWithInfo(c,key,deleted); |
| 766 | g_pserver->dirty++; |
| 767 | |
| 768 | /* Replicate/AOF this as an explicit DEL or UNLINK. */ |
| 769 | aux = g_pserver->lazyfree_lazy_expire ? shared.unlink : shared.del; |
| 770 | rewriteClientCommandVector(c,2,aux,key); |
| 771 | signalModifiedKey(c,c->db,key); |
| 772 | notifyKeyspaceEvent(NOTIFY_GENERIC,"del",key,c->db->id); |
| 773 | addReply(c, shared.cone); |
| 774 | return; |
| 775 | } else { |
| 776 | setExpire(c,c->db,key,nullptr,when); |
| 777 | addReply(c,shared.cone); |
| 778 | signalModifiedKey(c,c->db,key); |
| 779 | notifyKeyspaceEvent(NOTIFY_GENERIC,"expire",key,c->db->id); |
| 780 | g_pserver->dirty++; |
| 781 | return; |
| 782 | } |
| 783 | } |
| 784 | |
| 785 | /* EXPIRE key seconds */ |
| 786 | void expireCommand(client *c) { |
no test coverage detected