4 robj 
*createObject(int type
, void *ptr
) { 
   7     if (server
.vm_enabled
) pthread_mutex_lock(&server
.obj_freelist_mutex
); 
   8     if (listLength(server
.objfreelist
)) { 
   9         listNode 
*head 
= listFirst(server
.objfreelist
); 
  10         o 
= listNodeValue(head
); 
  11         listDelNode(server
.objfreelist
,head
); 
  12         if (server
.vm_enabled
) pthread_mutex_unlock(&server
.obj_freelist_mutex
); 
  14         if (server
.vm_enabled
) pthread_mutex_unlock(&server
.obj_freelist_mutex
); 
  15         o 
= zmalloc(sizeof(*o
)); 
  18     o
->encoding 
= REDIS_ENCODING_RAW
; 
  21     if (server
.vm_enabled
) { 
  22         /* Note that this code may run in the context of an I/O thread 
  23          * and accessing server.lruclock in theory is an error 
  24          * (no locks). But in practice this is safe, and even if we read 
  25          * garbage Redis will not fail. */ 
  26         o
->lru 
= server
.lruclock
; 
  27         o
->storage 
= REDIS_VM_MEMORY
; 
  32 robj 
*createStringObject(char *ptr
, size_t len
) { 
  33     return createObject(REDIS_STRING
,sdsnewlen(ptr
,len
)); 
  36 robj 
*createStringObjectFromLongLong(long long value
) { 
  38     if (value 
>= 0 && value 
< REDIS_SHARED_INTEGERS
) { 
  39         incrRefCount(shared
.integers
[value
]); 
  40         o 
= shared
.integers
[value
]; 
  42         if (value 
>= LONG_MIN 
&& value 
<= LONG_MAX
) { 
  43             o 
= createObject(REDIS_STRING
, NULL
); 
  44             o
->encoding 
= REDIS_ENCODING_INT
; 
  45             o
->ptr 
= (void*)((long)value
); 
  47             o 
= createObject(REDIS_STRING
,sdsfromlonglong(value
)); 
  53 robj 
*dupStringObject(robj 
*o
) { 
  54     redisAssert(o
->encoding 
== REDIS_ENCODING_RAW
); 
  55     return createStringObject(o
->ptr
,sdslen(o
->ptr
)); 
  58 robj 
*createListObject(void) { 
  59     list 
*l 
= listCreate(); 
  60     robj 
*o 
= createObject(REDIS_LIST
,l
); 
  61     listSetFreeMethod(l
,decrRefCount
); 
  62     o
->encoding 
= REDIS_ENCODING_LINKEDLIST
; 
  66 robj 
*createZiplistObject(void) { 
  67     unsigned char *zl 
= ziplistNew(); 
  68     robj 
*o 
= createObject(REDIS_LIST
,zl
); 
  69     o
->encoding 
= REDIS_ENCODING_ZIPLIST
; 
  73 robj 
*createSetObject(void) { 
  74     dict 
*d 
= dictCreate(&setDictType
,NULL
); 
  75     return createObject(REDIS_SET
,d
); 
  78 robj 
*createHashObject(void) { 
  79     /* All the Hashes start as zipmaps. Will be automatically converted 
  80      * into hash tables if there are enough elements or big elements 
  82     unsigned char *zm 
= zipmapNew(); 
  83     robj 
*o 
= createObject(REDIS_HASH
,zm
); 
  84     o
->encoding 
= REDIS_ENCODING_ZIPMAP
; 
  88 robj 
*createZsetObject(void) { 
  89     zset 
*zs 
= zmalloc(sizeof(*zs
)); 
  91     zs
->dict 
= dictCreate(&zsetDictType
,NULL
); 
  92     zs
->zsl 
= zslCreate(); 
  93     return createObject(REDIS_ZSET
,zs
); 
  96 void freeStringObject(robj 
*o
) { 
  97     if (o
->encoding 
== REDIS_ENCODING_RAW
) { 
 102 void freeListObject(robj 
*o
) { 
 103     switch (o
->encoding
) { 
 104     case REDIS_ENCODING_LINKEDLIST
: 
 105         listRelease((list
*) o
->ptr
); 
 107     case REDIS_ENCODING_ZIPLIST
: 
 111         redisPanic("Unknown list encoding type"); 
 115 void freeSetObject(robj 
*o
) { 
 116     dictRelease((dict
*) o
->ptr
); 
 119 void freeZsetObject(robj 
*o
) { 
 122     dictRelease(zs
->dict
); 
 127 void freeHashObject(robj 
*o
) { 
 128     switch (o
->encoding
) { 
 129     case REDIS_ENCODING_HT
: 
 130         dictRelease((dict
*) o
->ptr
); 
 132     case REDIS_ENCODING_ZIPMAP
: 
 136         redisPanic("Unknown hash encoding type"); 
 141 void incrRefCount(robj 
*o
) { 
 145 void decrRefCount(void *obj
) { 
 148     /* Object is a swapped out value, or in the process of being loaded. */ 
 149     if (server
.vm_enabled 
&& 
 150         (o
->storage 
== REDIS_VM_SWAPPED 
|| o
->storage 
== REDIS_VM_LOADING
)) 
 153         if (o
->storage 
== REDIS_VM_LOADING
) vmCancelThreadedIOJob(o
); 
 154         vmMarkPagesFree(vp
->page
,vp
->usedpages
); 
 155         server
.vm_stats_swapped_objects
--; 
 160     if (o
->refcount 
<= 0) redisPanic("decrRefCount against refcount <= 0"); 
 161     /* Object is in memory, or in the process of being swapped out. 
 163      * If the object is being swapped out, abort the operation on 
 164      * decrRefCount even if the refcount does not drop to 0: the object 
 165      * is referenced at least two times, as value of the key AND as 
 166      * job->val in the iojob. So if we don't invalidate the iojob, when it is 
 167      * done but the relevant key was removed in the meantime, the 
 168      * complete jobs handler will not find the key about the job and the 
 169      * assert will fail. */ 
 170     if (server
.vm_enabled 
&& o
->storage 
== REDIS_VM_SWAPPING
) 
 171         vmCancelThreadedIOJob(o
); 
 172     if (--(o
->refcount
) == 0) { 
 174         case REDIS_STRING
: freeStringObject(o
); break; 
 175         case REDIS_LIST
: freeListObject(o
); break; 
 176         case REDIS_SET
: freeSetObject(o
); break; 
 177         case REDIS_ZSET
: freeZsetObject(o
); break; 
 178         case REDIS_HASH
: freeHashObject(o
); break; 
 179         default: redisPanic("Unknown object type"); break; 
 181         if (server
.vm_enabled
) pthread_mutex_lock(&server
.obj_freelist_mutex
); 
 182         if (listLength(server
.objfreelist
) > REDIS_OBJFREELIST_MAX 
|| 
 183             !listAddNodeHead(server
.objfreelist
,o
)) 
 185         if (server
.vm_enabled
) pthread_mutex_unlock(&server
.obj_freelist_mutex
); 
 189 int checkType(redisClient 
*c
, robj 
*o
, int type
) { 
 190     if (o
->type 
!= type
) { 
 191         addReply(c
,shared
.wrongtypeerr
); 
 197 /* Try to encode a string object in order to save space */ 
 198 robj 
*tryObjectEncoding(robj 
*o
) { 
 202     if (o
->encoding 
!= REDIS_ENCODING_RAW
) 
 203         return o
; /* Already encoded */ 
 205     /* It's not safe to encode shared objects: shared objects can be shared 
 206      * everywhere in the "object space" of Redis. Encoded objects can only 
 207      * appear as "values" (and not, for instance, as keys) */ 
 208      if (o
->refcount 
> 1) return o
; 
 210     /* Currently we try to encode only strings */ 
 211     redisAssert(o
->type 
== REDIS_STRING
); 
 213     /* Check if we can represent this string as a long integer */ 
 214     if (isStringRepresentableAsLong(s
,&value
) == REDIS_ERR
) return o
; 
 216     /* Ok, this object can be encoded... 
 218      * Can I use a shared object? Only if the object is inside a given 
 219      * range and if this is the main thread, since when VM is enabled we 
 220      * have the constraint that I/O thread should only handle non-shared 
 221      * objects, in order to avoid race conditions (we don't have per-object 
 223     if (value 
>= 0 && value 
< REDIS_SHARED_INTEGERS 
&& 
 224         pthread_equal(pthread_self(),server
.mainthread
)) { 
 226         incrRefCount(shared
.integers
[value
]); 
 227         return shared
.integers
[value
]; 
 229         o
->encoding 
= REDIS_ENCODING_INT
; 
 231         o
->ptr 
= (void*) value
; 
 236 /* Get a decoded version of an encoded object (returned as a new object). 
 237  * If the object is already raw-encoded just increment the ref count. */ 
 238 robj 
*getDecodedObject(robj 
*o
) { 
 241     if (o
->encoding 
== REDIS_ENCODING_RAW
) { 
 245     if (o
->type 
== REDIS_STRING 
&& o
->encoding 
== REDIS_ENCODING_INT
) { 
 248         ll2string(buf
,32,(long)o
->ptr
); 
 249         dec 
= createStringObject(buf
,strlen(buf
)); 
 252         redisPanic("Unknown encoding type"); 
 256 /* Compare two string objects via strcmp() or alike. 
 257  * Note that the objects may be integer-encoded. In such a case we 
 258  * use ll2string() to get a string representation of the numbers on the stack 
 259  * and compare the strings, it's much faster than calling getDecodedObject(). 
 261  * Important note: if objects are not integer encoded, but binary-safe strings, 
 262  * sdscmp() from sds.c will apply memcmp() so this function ca be considered 
 264 int compareStringObjects(robj 
*a
, robj 
*b
) { 
 265     redisAssert(a
->type 
== REDIS_STRING 
&& b
->type 
== REDIS_STRING
); 
 266     char bufa
[128], bufb
[128], *astr
, *bstr
; 
 269     if (a 
== b
) return 0; 
 270     if (a
->encoding 
!= REDIS_ENCODING_RAW
) { 
 271         ll2string(bufa
,sizeof(bufa
),(long) a
->ptr
); 
 277     if (b
->encoding 
!= REDIS_ENCODING_RAW
) { 
 278         ll2string(bufb
,sizeof(bufb
),(long) b
->ptr
); 
 284     return bothsds 
? sdscmp(astr
,bstr
) : strcmp(astr
,bstr
); 
 287 /* Equal string objects return 1 if the two objects are the same from the 
 288  * point of view of a string comparison, otherwise 0 is returned. Note that 
 289  * this function is faster then checking for (compareStringObject(a,b) == 0) 
 290  * because it can perform some more optimization. */ 
 291 int equalStringObjects(robj 
*a
, robj 
*b
) { 
 292     if (a
->encoding 
!= REDIS_ENCODING_RAW 
&& b
->encoding 
!= REDIS_ENCODING_RAW
){ 
 293         return a
->ptr 
== b
->ptr
; 
 295         return compareStringObjects(a
,b
) == 0; 
 299 size_t stringObjectLen(robj 
*o
) { 
 300     redisAssert(o
->type 
== REDIS_STRING
); 
 301     if (o
->encoding 
== REDIS_ENCODING_RAW
) { 
 302         return sdslen(o
->ptr
); 
 306         return ll2string(buf
,32,(long)o
->ptr
); 
 310 int getDoubleFromObject(robj 
*o
, double *target
) { 
 317         redisAssert(o
->type 
== REDIS_STRING
); 
 318         if (o
->encoding 
== REDIS_ENCODING_RAW
) { 
 319             value 
= strtod(o
->ptr
, &eptr
); 
 320             if (eptr
[0] != '\0') return REDIS_ERR
; 
 321         } else if (o
->encoding 
== REDIS_ENCODING_INT
) { 
 322             value 
= (long)o
->ptr
; 
 324             redisPanic("Unknown string encoding"); 
 332 int getDoubleFromObjectOrReply(redisClient 
*c
, robj 
*o
, double *target
, const char *msg
) { 
 334     if (getDoubleFromObject(o
, &value
) != REDIS_OK
) { 
 336             addReplySds(c
, sdscatprintf(sdsempty(), "-ERR %s\r\n", msg
)); 
 338             addReplySds(c
, sdsnew("-ERR value is not a double\r\n")); 
 347 int getLongLongFromObject(robj 
*o
, long long *target
) { 
 354         redisAssert(o
->type 
== REDIS_STRING
); 
 355         if (o
->encoding 
== REDIS_ENCODING_RAW
) { 
 356             value 
= strtoll(o
->ptr
, &eptr
, 10); 
 357             if (eptr
[0] != '\0') return REDIS_ERR
; 
 358         } else if (o
->encoding 
== REDIS_ENCODING_INT
) { 
 359             value 
= (long)o
->ptr
; 
 361             redisPanic("Unknown string encoding"); 
 369 int getLongLongFromObjectOrReply(redisClient 
*c
, robj 
*o
, long long *target
, const char *msg
) { 
 371     if (getLongLongFromObject(o
, &value
) != REDIS_OK
) { 
 373             addReplySds(c
, sdscatprintf(sdsempty(), "-ERR %s\r\n", msg
)); 
 375             addReplySds(c
, sdsnew("-ERR value is not an integer\r\n")); 
 384 int getLongFromObjectOrReply(redisClient 
*c
, robj 
*o
, long *target
, const char *msg
) { 
 387     if (getLongLongFromObjectOrReply(c
, o
, &value
, msg
) != REDIS_OK
) return REDIS_ERR
; 
 388     if (value 
< LONG_MIN 
|| value 
> LONG_MAX
) { 
 390             addReplySds(c
, sdscatprintf(sdsempty(), "-ERR %s\r\n", msg
)); 
 392             addReplySds(c
, sdsnew("-ERR value is out of range\r\n")); 
 401 char *strEncoding(int encoding
) { 
 403     case REDIS_ENCODING_RAW
: return "raw"; 
 404     case REDIS_ENCODING_INT
: return "int"; 
 405     case REDIS_ENCODING_HT
: return "hashtable"; 
 406     case REDIS_ENCODING_ZIPMAP
: return "zipmap"; 
 407     case REDIS_ENCODING_LINKEDLIST
: return "linkedlist"; 
 408     case REDIS_ENCODING_ZIPLIST
: return "ziplist"; 
 409     default: return "unknown";