| 73 | #define OBJ_PERSIST (1<<8) /* Set if we need to remove the ttl */ |
| 74 | |
| 75 | void setGenericCommand(client *c, int flags, robj *key, robj *val, robj *expire, int unit, robj *ok_reply, robj *abort_reply) { |
| 76 | long long milliseconds = 0, when = 0; /* initialized to avoid any harmness warning */ |
| 77 | |
| 78 | if (expire) { |
| 79 | if (getLongLongFromObjectOrReply(c, expire, &milliseconds, NULL) != C_OK) |
| 80 | return; |
| 81 | if (milliseconds <= 0 || (unit == UNIT_SECONDS && milliseconds > LLONG_MAX / 1000)) { |
| 82 | /* Negative value provided or multiplication is gonna overflow. */ |
| 83 | addReplyErrorFormat(c, "invalid expire time in %s", c->cmd->name); |
| 84 | return; |
| 85 | } |
| 86 | if (unit == UNIT_SECONDS) milliseconds *= 1000; |
| 87 | when = milliseconds; |
| 88 | if ((flags & OBJ_PX) || (flags & OBJ_EX)) |
| 89 | when += mstime(); |
| 90 | if (when <= 0) { |
| 91 | /* Overflow detected. */ |
| 92 | addReplyErrorFormat(c, "invalid expire time in %s", c->cmd->name); |
| 93 | return; |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | if ((flags & OBJ_SET_NX && lookupKeyWrite(c->db,key) != NULL) || |
| 98 | (flags & OBJ_SET_XX && lookupKeyWrite(c->db,key) == NULL)) |
| 99 | { |
| 100 | addReply(c, abort_reply ? abort_reply : shared.null[c->resp]); |
| 101 | return; |
| 102 | } |
| 103 | |
| 104 | if (flags & OBJ_SET_GET) { |
| 105 | if (getGenericCommand(c) == C_ERR) return; |
| 106 | } |
| 107 | |
| 108 | genericSetKey(c,c->db,key, val,flags & OBJ_KEEPTTL,1); |
| 109 | server.dirty++; |
| 110 | notifyKeyspaceEvent(NOTIFY_STRING,"set",key,c->db->id); |
| 111 | if (expire) { |
| 112 | setExpire(c,c->db,key,when); |
| 113 | notifyKeyspaceEvent(NOTIFY_GENERIC,"expire",key,c->db->id); |
| 114 | |
| 115 | /* Propagate as SET Key Value PXAT millisecond-timestamp if there is EXAT/PXAT or |
| 116 | * propagate as SET Key Value PX millisecond if there is EX/PX flag. |
| 117 | * |
| 118 | * Additionally when we propagate the SET with PX (relative millisecond) we translate |
| 119 | * it again to SET with PXAT for the AOF. |
| 120 | * |
| 121 | * Additional care is required while modifying the argument order. AOF relies on the |
| 122 | * exp argument being at index 3. (see feedAppendOnlyFile) |
| 123 | * */ |
| 124 | robj *exp = (flags & OBJ_PXAT) || (flags & OBJ_EXAT) ? shared.pxat : shared.px; |
| 125 | robj *millisecondObj = createStringObjectFromLongLong(milliseconds); |
| 126 | rewriteClientCommandVector(c,5,shared.set,key,val,exp,millisecondObj); |
| 127 | decrRefCount(millisecondObj); |
| 128 | } |
| 129 | if (!(flags & OBJ_SET_GET)) { |
| 130 | addReply(c, ok_reply ? ok_reply : shared.ok); |
| 131 | } |
| 132 |
no test coverage detected