Lookup a key for read operations, or return NULL if the key is not found * in the specified DB. * * As a side effect of calling this function: * 1. A key gets expired if it reached it's TTL. * 2. The key last access time is updated. * 3. The global keys hits/misses stats are updated (reported in INFO). * 4. If keyspace notifications are enabled, a "keymiss" notification is fired. * * This
| 104 | * correctly report a key is expired on slaves even if the master is lagging |
| 105 | * expiring our key via DELs in the replication link. */ |
| 106 | robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) { |
| 107 | robj *val; |
| 108 | |
| 109 | if (expireIfNeeded(db,key) == 1) { |
| 110 | /* If we are in the context of a master, expireIfNeeded() returns 1 |
| 111 | * when the key is no longer valid, so we can return NULL ASAP. */ |
| 112 | if (server.masterhost == NULL) |
| 113 | goto keymiss; |
| 114 | |
| 115 | /* However if we are in the context of a slave, expireIfNeeded() will |
| 116 | * not really try to expire the key, it only returns information |
| 117 | * about the "logical" status of the key: key expiring is up to the |
| 118 | * master in order to have a consistent view of master's data set. |
| 119 | * |
| 120 | * However, if the command caller is not the master, and as additional |
| 121 | * safety measure, the command invoked is a read-only command, we can |
| 122 | * safely return NULL here, and provide a more consistent behavior |
| 123 | * to clients accessing expired values in a read-only fashion, that |
| 124 | * will say the key as non existing. |
| 125 | * |
| 126 | * Notably this covers GETs when slaves are used to scale reads. */ |
| 127 | if (server.current_client && |
| 128 | server.current_client != server.master && |
| 129 | server.current_client->cmd && |
| 130 | server.current_client->cmd->flags & CMD_READONLY) |
| 131 | { |
| 132 | goto keymiss; |
| 133 | } |
| 134 | } |
| 135 | val = lookupKey(db,key,flags); |
| 136 | if (val == NULL) |
| 137 | goto keymiss; |
| 138 | server.stat_keyspace_hits++; |
| 139 | return val; |
| 140 | |
| 141 | keymiss: |
| 142 | if (!(flags & LOOKUP_NONOTIFY)) { |
| 143 | notifyKeyspaceEvent(NOTIFY_KEY_MISS, "keymiss", key, db->id); |
| 144 | } |
| 145 | server.stat_keyspace_misses++; |
| 146 | return NULL; |
| 147 | } |
| 148 | |
| 149 | /* Like lookupKeyReadWithFlags(), but does not use any flag, which is the |
| 150 | * common case. */ |
no test coverage detected