Return a random key, in form of a Redis object. * If there are no keys, NULL is returned. * * The function makes sure to return keys not already expired. */
| 277 | * |
| 278 | * The function makes sure to return keys not already expired. */ |
| 279 | robj *dbRandomKey(redisDb *db) { |
| 280 | dictEntry *de; |
| 281 | int maxtries = 100; |
| 282 | int allvolatile = dictSize(db->dict) == dictSize(db->expires); |
| 283 | |
| 284 | while(1) { |
| 285 | sds key; |
| 286 | robj *keyobj; |
| 287 | |
| 288 | de = dictGetFairRandomKey(db->dict); |
| 289 | if (de == NULL) return NULL; |
| 290 | |
| 291 | key = dictGetKey(de); |
| 292 | keyobj = createStringObject(key,sdslen(key)); |
| 293 | if (dictFind(db->expires,key)) { |
| 294 | if (allvolatile && server.masterhost && --maxtries == 0) { |
| 295 | /* If the DB is composed only of keys with an expire set, |
| 296 | * it could happen that all the keys are already logically |
| 297 | * expired in the slave, so the function cannot stop because |
| 298 | * expireIfNeeded() is false, nor it can stop because |
| 299 | * dictGetRandomKey() returns NULL (there are keys to return). |
| 300 | * To prevent the infinite loop we do some tries, but if there |
| 301 | * are the conditions for an infinite loop, eventually we |
| 302 | * return a key name that may be already expired. */ |
| 303 | return keyobj; |
| 304 | } |
| 305 | if (expireIfNeeded(db,keyobj)) { |
| 306 | decrRefCount(keyobj); |
| 307 | continue; /* search for another key. This expired. */ |
| 308 | } |
| 309 | } |
| 310 | return keyobj; |
| 311 | } |
| 312 | } |
| 313 | |
| 314 | /* Delete a key, value, and associated expiration entry if any, from the DB */ |
| 315 | int dbSyncDelete(redisDb *db, robj *key) { |
no test coverage detected