LCOV - code coverage report
Current view: directory - redis/src - object.c (source / functions) Found Hit Coverage
Test: redis.info Lines: 290 270 93.1 %
Date: 2012-04-04 Functions: 39 39 100.0 %
Colors: not hit hit

       1                 : #include "redis.h"
       2                 : #include <math.h>
       3                 : #include <ctype.h>
       4                 : 
       5        11598102 : robj *createObject(int type, void *ptr) {
       6        11598102 :     robj *o = zmalloc(sizeof(*o));
       7        11598102 :     o->type = type;
       8        11598102 :     o->encoding = REDIS_ENCODING_RAW;
       9        11598102 :     o->ptr = ptr;
      10        11598102 :     o->refcount = 1;
      11                 : 
      12                 :     /* Set the LRU to the current lruclock (minutes resolution).
      13                 :      * We do this regardless of the fact VM is active as LRU is also
      14                 :      * used for the maxmemory directive when Redis is used as cache.
      15                 :      *
      16                 :      * Note that this code may run in the context of an I/O thread
      17                 :      * and accessing server.lruclock in theory is an error
      18                 :      * (no locks). But in practice this is safe, and even if we read
      19                 :      * garbage Redis will not fail. */
      20        11598102 :     o->lru = server.lruclock;
      21                 :     /* The following is only needed if VM is active, but since the conditional
      22                 :      * is probably more costly than initializing the field it's better to
      23                 :      * have every field properly initialized anyway. */
      24        11598102 :     return o;
      25                 : }
      26                 : 
      27         8250188 : robj *createStringObject(char *ptr, size_t len) {
      28         8250188 :     return createObject(REDIS_STRING,sdsnewlen(ptr,len));
      29                 : }
      30                 : 
      31          176565 : robj *createStringObjectFromLongLong(long long value) {
      32                 :     robj *o;
      33          176565 :     if (value >= 0 && value < REDIS_SHARED_INTEGERS) {
      34           60257 :         incrRefCount(shared.integers[value]);
      35           60257 :         o = shared.integers[value];
      36                 :     } else {
      37                 :         if (value >= LONG_MIN && value <= LONG_MAX) {
      38          116308 :             o = createObject(REDIS_STRING, NULL);
      39          116308 :             o->encoding = REDIS_ENCODING_INT;
      40          116308 :             o->ptr = (void*)((long)value);
      41                 :         } else {
      42                 :             o = createObject(REDIS_STRING,sdsfromlonglong(value));
      43                 :         }
      44                 :     }
      45          176565 :     return o;
      46                 : }
      47                 : 
      48                 : /* Note: this function is defined into object.c since here it is where it
      49                 :  * belongs but it is actually designed to be used just for INCRBYFLOAT */
      50              17 : robj *createStringObjectFromLongDouble(long double value) {
      51                 :     char buf[256];
      52                 :     int len;
      53                 : 
      54                 :     /* We use 17 digits precision since with 128 bit floats that precision
      55                 :      * after rouding is able to represent most small decimal numbers in a way
      56                 :      * that is "non surprising" for the user (that is, most small decimal
      57                 :      * numbers will be represented in a way that when converted back into
      58                 :      * a string are exactly the same as what the user typed.) */
      59              34 :     len = snprintf(buf,sizeof(buf),"%.17Lf", value);
      60                 :     /* Now remove trailing zeroes after the '.' */
      61              17 :     if (strchr(buf,'.') != NULL) {
      62              17 :         char *p = buf+len-1;
      63             314 :         while(*p == '0') {
      64             280 :             p--;
      65             280 :             len--;
      66                 :         }
      67              17 :         if (*p == '.') len--;
      68                 :     }
      69              17 :     return createStringObject(buf,len);
      70                 : }
      71                 : 
      72            2592 : robj *dupStringObject(robj *o) {
      73            2592 :     redisAssertWithInfo(NULL,o,o->encoding == REDIS_ENCODING_RAW);
      74            5184 :     return createStringObject(o->ptr,sdslen(o->ptr));
      75                 : }
      76                 : 
      77               4 : robj *createListObject(void) {
      78               4 :     list *l = listCreate();
      79               4 :     robj *o = createObject(REDIS_LIST,l);
      80               4 :     listSetFreeMethod(l,decrRefCount);
      81               4 :     o->encoding = REDIS_ENCODING_LINKEDLIST;
      82               4 :     return o;
      83                 : }
      84                 : 
      85           15250 : robj *createZiplistObject(void) {
      86           15250 :     unsigned char *zl = ziplistNew();
      87           15250 :     robj *o = createObject(REDIS_LIST,zl);
      88           15250 :     o->encoding = REDIS_ENCODING_ZIPLIST;
      89           15250 :     return o;
      90                 : }
      91                 : 
      92            3607 : robj *createSetObject(void) {
      93            3607 :     dict *d = dictCreate(&setDictType,NULL);
      94            3607 :     robj *o = createObject(REDIS_SET,d);
      95            3607 :     o->encoding = REDIS_ENCODING_HT;
      96            3607 :     return o;
      97                 : }
      98                 : 
      99           17208 : robj *createIntsetObject(void) {
     100           17208 :     intset *is = intsetNew();
     101           17208 :     robj *o = createObject(REDIS_SET,is);
     102           17208 :     o->encoding = REDIS_ENCODING_INTSET;
     103           17208 :     return o;
     104                 : }
     105                 : 
     106           25060 : robj *createHashObject(void) {
     107           25060 :     unsigned char *zl = ziplistNew();
     108           25060 :     robj *o = createObject(REDIS_HASH, zl);
     109           25060 :     o->encoding = REDIS_ENCODING_ZIPLIST;
     110           25060 :     return o;
     111                 : }
     112                 : 
     113            7540 : robj *createZsetObject(void) {
     114            7540 :     zset *zs = zmalloc(sizeof(*zs));
     115                 :     robj *o;
     116                 : 
     117            7540 :     zs->dict = dictCreate(&zsetDictType,NULL);
     118            7540 :     zs->zsl = zslCreate();
     119            7540 :     o = createObject(REDIS_ZSET,zs);
     120            7540 :     o->encoding = REDIS_ENCODING_SKIPLIST;
     121            7540 :     return o;
     122                 : }
     123                 : 
     124           12010 : robj *createZsetZiplistObject(void) {
     125           12010 :     unsigned char *zl = ziplistNew();
     126           12010 :     robj *o = createObject(REDIS_ZSET,zl);
     127           12010 :     o->encoding = REDIS_ENCODING_ZIPLIST;
     128           12010 :     return o;
     129                 : }
     130                 : 
     131         9283494 : void freeStringObject(robj *o) {
     132         9283494 :     if (o->encoding == REDIS_ENCODING_RAW) {
     133         9054980 :         sdsfree(o->ptr);
     134                 :     }
     135         9283494 : }
     136                 : 
     137            9689 : void freeListObject(robj *o) {
     138            9689 :     switch (o->encoding) {
     139                 :     case REDIS_ENCODING_LINKEDLIST:
     140            1852 :         listRelease((list*) o->ptr);
     141            1852 :         break;
     142                 :     case REDIS_ENCODING_ZIPLIST:
     143            7837 :         zfree(o->ptr);
     144            7837 :         break;
     145                 :     default:
     146               0 :         redisPanic("Unknown list encoding type");
     147                 :     }
     148            9689 : }
     149                 : 
     150            7539 : void freeSetObject(robj *o) {
     151            7539 :     switch (o->encoding) {
     152                 :     case REDIS_ENCODING_HT:
     153            1473 :         dictRelease((dict*) o->ptr);
     154            1473 :         break;
     155                 :     case REDIS_ENCODING_INTSET:
     156            6066 :         zfree(o->ptr);
     157            6066 :         break;
     158                 :     default:
     159               0 :         redisPanic("Unknown set encoding type");
     160                 :     }
     161            7539 : }
     162                 : 
     163            7456 : void freeZsetObject(robj *o) {
     164                 :     zset *zs;
     165            7456 :     switch (o->encoding) {
     166                 :     case REDIS_ENCODING_SKIPLIST:
     167            2895 :         zs = o->ptr;
     168            2895 :         dictRelease(zs->dict);
     169            2895 :         zslFree(zs->zsl);
     170            2895 :         zfree(zs);
     171            2895 :         break;
     172                 :     case REDIS_ENCODING_ZIPLIST:
     173            4561 :         zfree(o->ptr);
     174            4561 :         break;
     175                 :     default:
     176               0 :         redisPanic("Unknown sorted set encoding");
     177                 :     }
     178            7456 : }
     179                 : 
     180           17970 : void freeHashObject(robj *o) {
     181           17970 :     switch (o->encoding) {
     182                 :     case REDIS_ENCODING_HT:
     183               4 :         dictRelease((dict*) o->ptr);
     184               4 :         break;
     185                 :     case REDIS_ENCODING_ZIPLIST:
     186           17966 :         zfree(o->ptr);
     187           17966 :         break;
     188                 :     default:
     189               0 :         redisPanic("Unknown hash encoding type");
     190                 :         break;
     191                 :     }
     192           17970 : }
     193                 : 
     194         1229370 : void incrRefCount(robj *o) {
     195         4954568 :     o->refcount++;
     196         1229370 : }
     197                 : 
     198        14263814 : void decrRefCount(void *obj) {
     199        14263814 :     robj *o = obj;
     200                 : 
     201        14263814 :     if (o->refcount <= 0) redisPanic("decrRefCount against refcount <= 0");
     202        14263814 :     if (o->refcount == 1) {
     203         9326148 :         switch(o->type) {
     204         9283494 :         case REDIS_STRING: freeStringObject(o); break;
     205            9689 :         case REDIS_LIST: freeListObject(o); break;
     206            7539 :         case REDIS_SET: freeSetObject(o); break;
     207            7456 :         case REDIS_ZSET: freeZsetObject(o); break;
     208           17970 :         case REDIS_HASH: freeHashObject(o); break;
     209               0 :         default: redisPanic("Unknown object type"); break;
     210                 :         }
     211         9326148 :         zfree(o);
     212                 :     } else {
     213         4937666 :         o->refcount--;
     214                 :     }
     215        14263814 : }
     216                 : 
     217                 : /* This function set the ref count to zero without freeing the object.
     218                 :  * It is useful in order to pass a new object to functions incrementing
     219                 :  * the ref count of the received object. Example:
     220                 :  *
     221                 :  *    functionThatWillIncrementRefCount(resetRefCount(CreateObject(...)));
     222                 :  *
     223                 :  * Otherwise you need to resort to the less elegant pattern:
     224                 :  *
     225                 :  *    *obj = createObject(...);
     226                 :  *    functionThatWillIncrementRefCount(obj);
     227                 :  *    decrRefCount(obj);
     228                 :  */
     229              23 : robj *resetRefCount(robj *obj) {
     230              23 :     obj->refcount = 0;
     231              23 :     return obj;
     232                 : }
     233                 : 
     234          176272 : int checkType(redisClient *c, robj *o, int type) {
     235          176272 :     if (o->type != type) {
     236              18 :         addReply(c,shared.wrongtypeerr);
     237              18 :         return 1;
     238                 :     }
     239          176254 :     return 0;
     240                 : }
     241                 : 
     242           54746 : int isObjectRepresentableAsLongLong(robj *o, long long *llval) {
     243           54746 :     redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
     244           54746 :     if (o->encoding == REDIS_ENCODING_INT) {
     245           33512 :         if (llval) *llval = (long) o->ptr;
     246           33512 :         return REDIS_OK;
     247                 :     } else {
     248           42468 :         return string2ll(o->ptr,sdslen(o->ptr),llval) ? REDIS_OK : REDIS_ERR;
     249                 :     }
     250                 : }
     251                 : 
     252                 : /* Try to encode a string object in order to save space */
     253         2073561 : robj *tryObjectEncoding(robj *o) {
     254                 :     long value;
     255         2073561 :     sds s = o->ptr;
     256                 : 
     257         2073561 :     if (o->encoding != REDIS_ENCODING_RAW)
     258            5786 :         return o; /* Already encoded */
     259                 : 
     260                 :     /* It's not safe to encode shared objects: shared objects can be shared
     261                 :      * everywhere in the "object space" of Redis. Encoded objects can only
     262                 :      * appear as "values" (and not, for instance, as keys) */
     263         2067775 :      if (o->refcount > 1) return o;
     264                 : 
     265                 :     /* Currently we try to encode only strings */
     266         2067775 :     redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
     267                 : 
     268                 :     /* Check if we can represent this string as a long integer */
     269         2067775 :     if (!string2l(s,sdslen(s),&value)) return o;
     270                 : 
     271                 :     /* Ok, this object can be encoded...
     272                 :      *
     273                 :      * Can I use a shared object? Only if the object is inside a given range
     274                 :      *
     275                 :      * Note that we also avoid using shared integers when maxmemory is used
     276                 :      * because every object needs to have a private LRU field for the LRU
     277                 :      * algorithm to work well. */
     278          209995 :     if (server.maxmemory == 0 && value >= 0 && value < REDIS_SHARED_INTEGERS) {
     279           87100 :         decrRefCount(o);
     280           87100 :         incrRefCount(shared.integers[value]);
     281           87100 :         return shared.integers[value];
     282                 :     } else {
     283          122895 :         o->encoding = REDIS_ENCODING_INT;
     284          122895 :         sdsfree(o->ptr);
     285          122895 :         o->ptr = (void*) value;
     286          122895 :         return o;
     287                 :     }
     288                 : }
     289                 : 
     290                 : /* Get a decoded version of an encoded object (returned as a new object).
     291                 :  * If the object is already raw-encoded just increment the ref count. */
     292         3947271 : robj *getDecodedObject(robj *o) {
     293                 :     robj *dec;
     294                 : 
     295         3947271 :     if (o->encoding == REDIS_ENCODING_RAW) {
     296                 :         incrRefCount(o);
     297         3577841 :         return o;
     298                 :     }
     299          369430 :     if (o->type == REDIS_STRING && o->encoding == REDIS_ENCODING_INT) {
     300                 :         char buf[32];
     301                 : 
     302          369430 :         ll2string(buf,32,(long)o->ptr);
     303          369430 :         dec = createStringObject(buf,strlen(buf));
     304          369430 :         return dec;
     305                 :     } else {
     306               0 :         redisPanic("Unknown encoding type");
     307                 :     }
     308                 : }
     309                 : 
     310                 : /* Compare two string objects via strcmp() or alike.
     311                 :  * Note that the objects may be integer-encoded. In such a case we
     312                 :  * use ll2string() to get a string representation of the numbers on the stack
     313                 :  * and compare the strings, it's much faster than calling getDecodedObject().
     314                 :  *
     315                 :  * Important note: if objects are not integer encoded, but binary-safe strings,
     316                 :  * sdscmp() from sds.c will apply memcmp() so this function ca be considered
     317                 :  * binary safe. */
     318            9378 : int compareStringObjects(robj *a, robj *b) {
     319            9378 :     redisAssertWithInfo(NULL,a,a->type == REDIS_STRING && b->type == REDIS_STRING);
     320                 :     char bufa[128], bufb[128], *astr, *bstr;
     321            9378 :     int bothsds = 1;
     322                 : 
     323            9378 :     if (a == b) return 0;
     324            4356 :     if (a->encoding != REDIS_ENCODING_RAW) {
     325            1372 :         ll2string(bufa,sizeof(bufa),(long) a->ptr);
     326            1372 :         astr = bufa;
     327            1372 :         bothsds = 0;
     328                 :     } else {
     329            2984 :         astr = a->ptr;
     330                 :     }
     331            4356 :     if (b->encoding != REDIS_ENCODING_RAW) {
     332             643 :         ll2string(bufb,sizeof(bufb),(long) b->ptr);
     333             643 :         bstr = bufb;
     334             643 :         bothsds = 0;
     335                 :     } else {
     336            3713 :         bstr = b->ptr;
     337                 :     }
     338            4356 :     return bothsds ? sdscmp(astr,bstr) : strcmp(astr,bstr);
     339                 : }
     340                 : 
     341                 : /* Equal string objects return 1 if the two objects are the same from the
     342                 :  * point of view of a string comparison, otherwise 0 is returned. Note that
     343                 :  * this function is faster then checking for (compareStringObject(a,b) == 0)
     344                 :  * because it can perform some more optimization. */
     345           14217 : int equalStringObjects(robj *a, robj *b) {
     346           14217 :     if (a->encoding != REDIS_ENCODING_RAW && b->encoding != REDIS_ENCODING_RAW){
     347           12253 :         return a->ptr == b->ptr;
     348                 :     } else {
     349            1964 :         return compareStringObjects(a,b) == 0;
     350                 :     }
     351                 : }
     352                 : 
     353            3016 : size_t stringObjectLen(robj *o) {
     354            3016 :     redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
     355            3016 :     if (o->encoding == REDIS_ENCODING_RAW) {
     356            6012 :         return sdslen(o->ptr);
     357                 :     } else {
     358                 :         char buf[32];
     359                 : 
     360              10 :         return ll2string(buf,32,(long)o->ptr);
     361                 :     }
     362                 : }
     363                 : 
     364           27231 : int getDoubleFromObject(robj *o, double *target) {
     365                 :     double value;
     366                 :     char *eptr;
     367                 : 
     368           27231 :     if (o == NULL) {
     369               0 :         value = 0;
     370                 :     } else {
     371           27231 :         redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
     372           27231 :         if (o->encoding == REDIS_ENCODING_RAW) {
     373           27231 :             errno = 0;
     374           27231 :             value = strtod(o->ptr, &eptr);
     375           81689 :             if (isspace(((char*)o->ptr)[0]) || eptr[0] != '\0' ||
     376           54458 :                 errno == ERANGE || isnan(value))
     377              10 :                 return REDIS_ERR;
     378               0 :         } else if (o->encoding == REDIS_ENCODING_INT) {
     379               0 :             value = (long)o->ptr;
     380                 :         } else {
     381               0 :             redisPanic("Unknown string encoding");
     382                 :         }
     383                 :     }
     384           27221 :     *target = value;
     385           27221 :     return REDIS_OK;
     386                 : }
     387                 : 
     388           27231 : int getDoubleFromObjectOrReply(redisClient *c, robj *o, double *target, const char *msg) {
     389                 :     double value;
     390           27231 :     if (getDoubleFromObject(o, &value) != REDIS_OK) {
     391              10 :         if (msg != NULL) {
     392               4 :             addReplyError(c,(char*)msg);
     393                 :         } else {
     394               6 :             addReplyError(c,"value is not a valid float");
     395                 :         }
     396              10 :         return REDIS_ERR;
     397                 :     }
     398           27221 :     *target = value;
     399           27221 :     return REDIS_OK;
     400                 : }
     401                 : 
     402              44 : int getLongDoubleFromObject(robj *o, long double *target) {
     403                 :     long double value;
     404                 :     char *eptr;
     405                 : 
     406              44 :     if (o == NULL) {
     407               1 :         value = 0;
     408                 :     } else {
     409              43 :         redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
     410              43 :         if (o->encoding == REDIS_ENCODING_RAW) {
     411              33 :             errno = 0;
     412              33 :             value = strtold(o->ptr, &eptr);
     413              85 :             if (isspace(((char*)o->ptr)[0]) || eptr[0] != '\0' ||
     414              52 :                 errno == ERANGE || isnan(value))
     415               7 :                 return REDIS_ERR;
     416              10 :         } else if (o->encoding == REDIS_ENCODING_INT) {
     417              10 :             value = (long)o->ptr;
     418                 :         } else {
     419               0 :             redisPanic("Unknown string encoding");
     420                 :         }
     421                 :     }
     422              37 :     *target = value;
     423              37 :     return REDIS_OK;
     424                 : }
     425                 : 
     426              44 : int getLongDoubleFromObjectOrReply(redisClient *c, robj *o, long double *target, const char *msg) {
     427                 :     long double value;
     428              44 :     if (getLongDoubleFromObject(o, &value) != REDIS_OK) {
     429               7 :         if (msg != NULL) {
     430               4 :             addReplyError(c,(char*)msg);
     431                 :         } else {
     432               3 :             addReplyError(c,"value is not a valid float");
     433                 :         }
     434               7 :         return REDIS_ERR;
     435                 :     }
     436              37 :     *target = value;
     437              37 :     return REDIS_OK;
     438                 : }
     439                 : 
     440          100701 : int getLongLongFromObject(robj *o, long long *target) {
     441                 :     long long value;
     442                 :     char *eptr;
     443                 : 
     444          100701 :     if (o == NULL) {
     445               3 :         value = 0;
     446                 :     } else {
     447          100698 :         redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
     448          100698 :         if (o->encoding == REDIS_ENCODING_RAW) {
     449          100678 :             errno = 0;
     450          100678 :             value = strtoll(o->ptr, &eptr, 10);
     451          201346 :             if (isspace(((char*)o->ptr)[0]) || eptr[0] != '\0' ||
     452          100668 :                 errno == ERANGE)
     453              10 :                 return REDIS_ERR;
     454              20 :         } else if (o->encoding == REDIS_ENCODING_INT) {
     455              20 :             value = (long)o->ptr;
     456                 :         } else {
     457               0 :             redisPanic("Unknown string encoding");
     458                 :         }
     459                 :     }
     460          100691 :     if (target) *target = value;
     461          100691 :     return REDIS_OK;
     462                 : }
     463                 : 
     464          100676 : int getLongLongFromObjectOrReply(redisClient *c, robj *o, long long *target, const char *msg) {
     465                 :     long long value;
     466          100676 :     if (getLongLongFromObject(o, &value) != REDIS_OK) {
     467              10 :         if (msg != NULL) {
     468               6 :             addReplyError(c,(char*)msg);
     469                 :         } else {
     470               4 :             addReplyError(c,"value is not an integer or out of range");
     471                 :         }
     472              10 :         return REDIS_ERR;
     473                 :     }
     474          100666 :     *target = value;
     475          100666 :     return REDIS_OK;
     476                 : }
     477                 : 
     478           78733 : int getLongFromObjectOrReply(redisClient *c, robj *o, long *target, const char *msg) {
     479                 :     long long value;
     480                 : 
     481           78733 :     if (getLongLongFromObjectOrReply(c, o, &value, msg) != REDIS_OK) return REDIS_ERR;
     482                 :     if (value < LONG_MIN || value > LONG_MAX) {
     483                 :         if (msg != NULL) {
     484                 :             addReplyError(c,(char*)msg);
     485                 :         } else {
     486                 :             addReplyError(c,"value is out of range");
     487                 :         }
     488                 :         return REDIS_ERR;
     489                 :     }
     490           78731 :     *target = value;
     491           78731 :     return REDIS_OK;
     492                 : }
     493                 : 
     494            3414 : char *strEncoding(int encoding) {
     495            3414 :     switch(encoding) {
     496               3 :     case REDIS_ENCODING_RAW: return "raw";
     497               7 :     case REDIS_ENCODING_INT: return "int";
     498              37 :     case REDIS_ENCODING_HT: return "hashtable";
     499              56 :     case REDIS_ENCODING_LINKEDLIST: return "linkedlist";
     500            1662 :     case REDIS_ENCODING_ZIPLIST: return "ziplist";
     501              27 :     case REDIS_ENCODING_INTSET: return "intset";
     502            1622 :     case REDIS_ENCODING_SKIPLIST: return "skiplist";
     503               0 :     default: return "unknown";
     504                 :     }
     505                 : }
     506                 : 
     507                 : /* Given an object returns the min number of seconds the object was never
     508                 :  * requested, using an approximated LRU algorithm. */
     509           10765 : unsigned long estimateObjectIdleTime(robj *o) {
     510           10765 :     if (server.lruclock >= o->lru) {
     511           10765 :         return (server.lruclock - o->lru) * REDIS_LRU_CLOCK_RESOLUTION;
     512                 :     } else {
     513               0 :         return ((REDIS_LRU_CLOCK_MAX - o->lru) + server.lruclock) *
     514                 :                     REDIS_LRU_CLOCK_RESOLUTION;
     515                 :     }
     516                 : }
     517                 : 
     518                 : /* This is an helper function for the DEBUG command. We need to lookup keys
     519                 :  * without any modification of LRU or other parameters. */
     520              14 : robj *objectCommandLookup(redisClient *c, robj *key) {
     521                 :     dictEntry *de;
     522                 : 
     523              14 :     if ((de = dictFind(c->db->dict,key->ptr)) == NULL) return NULL;
     524              14 :     return (robj*) dictGetVal(de);
     525                 : }
     526                 : 
     527              14 : robj *objectCommandLookupOrReply(redisClient *c, robj *key, robj *reply) {
     528              14 :     robj *o = objectCommandLookup(c,key);
     529                 : 
     530              14 :     if (!o) addReply(c, reply);
     531              14 :     return o;
     532                 : }
     533                 : 
     534                 : /* Object command allows to inspect the internals of an Redis Object.
     535                 :  * Usage: OBJECT <verb> ... arguments ... */
     536              14 : void objectCommand(redisClient *c) {
     537                 :     robj *o;
     538                 : 
     539              14 :     if (!strcasecmp(c->argv[1]->ptr,"refcount") && c->argc == 3) {
     540               0 :         if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk))
     541                 :                 == NULL) return;
     542               0 :         addReplyLongLong(c,o->refcount);
     543              28 :     } else if (!strcasecmp(c->argv[1]->ptr,"encoding") && c->argc == 3) {
     544              14 :         if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk))
     545                 :                 == NULL) return;
     546              14 :         addReplyBulkCString(c,strEncoding(o->encoding));
     547               0 :     } else if (!strcasecmp(c->argv[1]->ptr,"idletime") && c->argc == 3) {
     548               0 :         if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk))
     549                 :                 == NULL) return;
     550               0 :         addReplyLongLong(c,estimateObjectIdleTime(o));
     551                 :     } else {
     552               0 :         addReplyError(c,"Syntax error. Try OBJECT (refcount|encoding|idletime)");
     553                 :     }
     554                 : }
     555                 : 

Generated by: LCOV version 1.7