Implements TTL and PTTL */
| 804 | |
| 805 | /* Implements TTL and PTTL */ |
| 806 | void ttlGenericCommand(client *c, int output_ms) { |
| 807 | long long expire = INVALID_EXPIRE, ttl = -1; |
| 808 | |
| 809 | /* If the key does not exist at all, return -2 */ |
| 810 | if (lookupKeyReadWithFlags(c->db,c->argv[1],LOOKUP_NOTOUCH) == nullptr) { |
| 811 | addReplyLongLong(c,-2); |
| 812 | return; |
| 813 | } |
| 814 | |
| 815 | /* The key exists. Return -1 if it has no expire, or the actual |
| 816 | * TTL value otherwise. */ |
| 817 | expireEntry *pexpire = c->db->getExpire(c->argv[1]); |
| 818 | |
| 819 | if (c->argc == 2) { |
| 820 | // primary expire |
| 821 | if (pexpire != nullptr) |
| 822 | pexpire->FGetPrimaryExpire(&expire); |
| 823 | } else if (c->argc == 3) { |
| 824 | // We want a subkey expire |
| 825 | if (pexpire && pexpire->FFat()) { |
| 826 | for (auto itr : *pexpire) { |
| 827 | if (itr.subkey() == nullptr) |
| 828 | continue; |
| 829 | if (sdscmp((sds)itr.subkey(), szFromObj(c->argv[2])) == 0) { |
| 830 | expire = itr.when(); |
| 831 | break; |
| 832 | } |
| 833 | } |
| 834 | } |
| 835 | } else { |
| 836 | addReplyError(c, "Invalid arguments"); |
| 837 | return; |
| 838 | } |
| 839 | |
| 840 | |
| 841 | if (expire != INVALID_EXPIRE) { |
| 842 | ttl = expire-mstime(); |
| 843 | if (ttl < 0) ttl = 0; |
| 844 | } |
| 845 | if (ttl == -1) { |
| 846 | addReplyLongLong(c,-1); |
| 847 | } else { |
| 848 | addReplyLongLong(c,output_ms ? ttl : ((ttl+500)/1000)); |
| 849 | } |
| 850 | } |
| 851 | |
| 852 | /* TTL key */ |
| 853 | void ttlCommand(client *c) { |
no test coverage detected