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
)
15 pthread_mutex_unlock(&server
.obj_freelist_mutex
);
16 o
= zmalloc(sizeof(*o
));
19 o
->encoding
= REDIS_ENCODING_RAW
;
22 if (server
.vm_enabled
) {
23 /* Note that this code may run in the context of an I/O thread
24 * and accessing server.lruclock in theory is an error
25 * (no locks). But in practice this is safe, and even if we read
26 * garbage Redis will not fail. */
27 o
->lru
= server
.lruclock
;
28 o
->storage
= REDIS_VM_MEMORY
;
33 robj
*createStringObject(char *ptr
, size_t len
) {
34 return createObject(REDIS_STRING
,sdsnewlen(ptr
,len
));
37 robj
*createStringObjectFromLongLong(long long value
) {
39 if (value
>= 0 && value
< REDIS_SHARED_INTEGERS
) {
40 incrRefCount(shared
.integers
[value
]);
41 o
= shared
.integers
[value
];
43 if (value
>= LONG_MIN
&& value
<= LONG_MAX
) {
44 o
= createObject(REDIS_STRING
, NULL
);
45 o
->encoding
= REDIS_ENCODING_INT
;
46 o
->ptr
= (void*)((long)value
);
48 o
= createObject(REDIS_STRING
,sdsfromlonglong(value
));
54 robj
*dupStringObject(robj
*o
) {
55 redisAssert(o
->encoding
== REDIS_ENCODING_RAW
);
56 return createStringObject(o
->ptr
,sdslen(o
->ptr
));
59 robj
*createListObject(void) {
60 list
*l
= listCreate();
61 robj
*o
= createObject(REDIS_LIST
,l
);
62 listSetFreeMethod(l
,decrRefCount
);
63 o
->encoding
= REDIS_ENCODING_LINKEDLIST
;
67 robj
*createZiplistObject(void) {
68 unsigned char *zl
= ziplistNew();
69 robj
*o
= createObject(REDIS_LIST
,zl
);
70 o
->encoding
= REDIS_ENCODING_ZIPLIST
;
74 robj
*createSetObject(void) {
75 dict
*d
= dictCreate(&setDictType
,NULL
);
76 robj
*o
= createObject(REDIS_SET
,d
);
77 o
->encoding
= REDIS_ENCODING_HT
;
81 robj
*createIntsetObject(void) {
82 intset
*is
= intsetNew();
83 robj
*o
= createObject(REDIS_SET
,is
);
84 o
->encoding
= REDIS_ENCODING_INTSET
;
88 robj
*createHashObject(void) {
89 /* All the Hashes start as zipmaps. Will be automatically converted
90 * into hash tables if there are enough elements or big elements
92 unsigned char *zm
= zipmapNew();
93 robj
*o
= createObject(REDIS_HASH
,zm
);
94 o
->encoding
= REDIS_ENCODING_ZIPMAP
;
98 robj
*createZsetObject(void) {
99 zset
*zs
= zmalloc(sizeof(*zs
));
101 zs
->dict
= dictCreate(&zsetDictType
,NULL
);
102 zs
->zsl
= zslCreate();
103 return createObject(REDIS_ZSET
,zs
);
106 void freeStringObject(robj
*o
) {
107 if (o
->encoding
== REDIS_ENCODING_RAW
) {
112 void freeListObject(robj
*o
) {
113 switch (o
->encoding
) {
114 case REDIS_ENCODING_LINKEDLIST
:
115 listRelease((list
*) o
->ptr
);
117 case REDIS_ENCODING_ZIPLIST
:
121 redisPanic("Unknown list encoding type");
125 void freeSetObject(robj
*o
) {
126 switch (o
->encoding
) {
127 case REDIS_ENCODING_HT
:
128 dictRelease((dict
*) o
->ptr
);
130 case REDIS_ENCODING_INTSET
:
134 redisPanic("Unknown set encoding type");
138 void freeZsetObject(robj
*o
) {
141 dictRelease(zs
->dict
);
146 void freeHashObject(robj
*o
) {
147 switch (o
->encoding
) {
148 case REDIS_ENCODING_HT
:
149 dictRelease((dict
*) o
->ptr
);
151 case REDIS_ENCODING_ZIPMAP
:
155 redisPanic("Unknown hash encoding type");
160 void incrRefCount(robj
*o
) {
164 void decrRefCount(void *obj
) {
167 /* Object is a swapped out value, or in the process of being loaded. */
168 if (server
.vm_enabled
&&
169 (o
->storage
== REDIS_VM_SWAPPED
|| o
->storage
== REDIS_VM_LOADING
))
172 if (o
->storage
== REDIS_VM_LOADING
) vmCancelThreadedIOJob(o
);
173 vmMarkPagesFree(vp
->page
,vp
->usedpages
);
174 server
.vm_stats_swapped_objects
--;
179 if (o
->refcount
<= 0) redisPanic("decrRefCount against refcount <= 0");
180 /* Object is in memory, or in the process of being swapped out.
182 * If the object is being swapped out, abort the operation on
183 * decrRefCount even if the refcount does not drop to 0: the object
184 * is referenced at least two times, as value of the key AND as
185 * job->val in the iojob. So if we don't invalidate the iojob, when it is
186 * done but the relevant key was removed in the meantime, the
187 * complete jobs handler will not find the key about the job and the
188 * assert will fail. */
189 if (server
.vm_enabled
&& o
->storage
== REDIS_VM_SWAPPING
)
190 vmCancelThreadedIOJob(o
);
191 if (--(o
->refcount
) == 0) {
193 case REDIS_STRING
: freeStringObject(o
); break;
194 case REDIS_LIST
: freeListObject(o
); break;
195 case REDIS_SET
: freeSetObject(o
); break;
196 case REDIS_ZSET
: freeZsetObject(o
); break;
197 case REDIS_HASH
: freeHashObject(o
); break;
198 default: redisPanic("Unknown object type"); break;
200 if (server
.vm_enabled
) pthread_mutex_lock(&server
.obj_freelist_mutex
);
201 if (listLength(server
.objfreelist
) > REDIS_OBJFREELIST_MAX
||
202 !listAddNodeHead(server
.objfreelist
,o
))
204 if (server
.vm_enabled
) pthread_mutex_unlock(&server
.obj_freelist_mutex
);
208 int checkType(redisClient
*c
, robj
*o
, int type
) {
209 if (o
->type
!= type
) {
210 addReply(c
,shared
.wrongtypeerr
);
216 /* Try to encode a string object in order to save space */
217 robj
*tryObjectEncoding(robj
*o
) {
221 if (o
->encoding
!= REDIS_ENCODING_RAW
)
222 return o
; /* Already encoded */
224 /* It's not safe to encode shared objects: shared objects can be shared
225 * everywhere in the "object space" of Redis. Encoded objects can only
226 * appear as "values" (and not, for instance, as keys) */
227 if (o
->refcount
> 1) return o
;
229 /* Currently we try to encode only strings */
230 redisAssert(o
->type
== REDIS_STRING
);
232 /* Check if we can represent this string as a long integer */
233 if (isStringRepresentableAsLong(s
,&value
) == REDIS_ERR
) return o
;
235 /* Ok, this object can be encoded */
236 if (value
>= 0 && value
< REDIS_SHARED_INTEGERS
) {
238 incrRefCount(shared
.integers
[value
]);
239 return shared
.integers
[value
];
241 o
->encoding
= REDIS_ENCODING_INT
;
243 o
->ptr
= (void*) value
;
248 /* Get a decoded version of an encoded object (returned as a new object).
249 * If the object is already raw-encoded just increment the ref count. */
250 robj
*getDecodedObject(robj
*o
) {
253 if (o
->encoding
== REDIS_ENCODING_RAW
) {
257 if (o
->type
== REDIS_STRING
&& o
->encoding
== REDIS_ENCODING_INT
) {
260 ll2string(buf
,32,(long)o
->ptr
);
261 dec
= createStringObject(buf
,strlen(buf
));
264 redisPanic("Unknown encoding type");
268 /* Compare two string objects via strcmp() or alike.
269 * Note that the objects may be integer-encoded. In such a case we
270 * use ll2string() to get a string representation of the numbers on the stack
271 * and compare the strings, it's much faster than calling getDecodedObject().
273 * Important note: if objects are not integer encoded, but binary-safe strings,
274 * sdscmp() from sds.c will apply memcmp() so this function ca be considered
276 int compareStringObjects(robj
*a
, robj
*b
) {
277 redisAssert(a
->type
== REDIS_STRING
&& b
->type
== REDIS_STRING
);
278 char bufa
[128], bufb
[128], *astr
, *bstr
;
281 if (a
== b
) return 0;
282 if (a
->encoding
!= REDIS_ENCODING_RAW
) {
283 ll2string(bufa
,sizeof(bufa
),(long) a
->ptr
);
289 if (b
->encoding
!= REDIS_ENCODING_RAW
) {
290 ll2string(bufb
,sizeof(bufb
),(long) b
->ptr
);
296 return bothsds
? sdscmp(astr
,bstr
) : strcmp(astr
,bstr
);
299 /* Equal string objects return 1 if the two objects are the same from the
300 * point of view of a string comparison, otherwise 0 is returned. Note that
301 * this function is faster then checking for (compareStringObject(a,b) == 0)
302 * because it can perform some more optimization. */
303 int equalStringObjects(robj
*a
, robj
*b
) {
304 if (a
->encoding
!= REDIS_ENCODING_RAW
&& b
->encoding
!= REDIS_ENCODING_RAW
){
305 return a
->ptr
== b
->ptr
;
307 return compareStringObjects(a
,b
) == 0;
311 size_t stringObjectLen(robj
*o
) {
312 redisAssert(o
->type
== REDIS_STRING
);
313 if (o
->encoding
== REDIS_ENCODING_RAW
) {
314 return sdslen(o
->ptr
);
318 return ll2string(buf
,32,(long)o
->ptr
);
322 int getDoubleFromObject(robj
*o
, double *target
) {
329 redisAssert(o
->type
== REDIS_STRING
);
330 if (o
->encoding
== REDIS_ENCODING_RAW
) {
331 value
= strtod(o
->ptr
, &eptr
);
332 if (eptr
[0] != '\0') return REDIS_ERR
;
333 } else if (o
->encoding
== REDIS_ENCODING_INT
) {
334 value
= (long)o
->ptr
;
336 redisPanic("Unknown string encoding");
344 int getDoubleFromObjectOrReply(redisClient
*c
, robj
*o
, double *target
, const char *msg
) {
346 if (getDoubleFromObject(o
, &value
) != REDIS_OK
) {
348 addReplySds(c
, sdscatprintf(sdsempty(), "-ERR %s\r\n", msg
));
350 addReplySds(c
, sdsnew("-ERR value is not a double\r\n"));
359 int getLongLongFromObject(robj
*o
, long long *target
) {
366 redisAssert(o
->type
== REDIS_STRING
);
367 if (o
->encoding
== REDIS_ENCODING_RAW
) {
368 value
= strtoll(o
->ptr
, &eptr
, 10);
369 if (eptr
[0] != '\0') return REDIS_ERR
;
370 } else if (o
->encoding
== REDIS_ENCODING_INT
) {
371 value
= (long)o
->ptr
;
373 redisPanic("Unknown string encoding");
377 if (target
) *target
= value
;
381 int getLongLongFromObjectOrReply(redisClient
*c
, robj
*o
, long long *target
, const char *msg
) {
383 if (getLongLongFromObject(o
, &value
) != REDIS_OK
) {
385 addReplySds(c
, sdscatprintf(sdsempty(), "-ERR %s\r\n", msg
));
387 addReplySds(c
, sdsnew("-ERR value is not an integer\r\n"));
396 int getLongFromObjectOrReply(redisClient
*c
, robj
*o
, long *target
, const char *msg
) {
399 if (getLongLongFromObjectOrReply(c
, o
, &value
, msg
) != REDIS_OK
) return REDIS_ERR
;
400 if (value
< LONG_MIN
|| value
> LONG_MAX
) {
402 addReplySds(c
, sdscatprintf(sdsempty(), "-ERR %s\r\n", msg
));
404 addReplySds(c
, sdsnew("-ERR value is out of range\r\n"));
413 char *strEncoding(int encoding
) {
415 case REDIS_ENCODING_RAW
: return "raw";
416 case REDIS_ENCODING_INT
: return "int";
417 case REDIS_ENCODING_HT
: return "hashtable";
418 case REDIS_ENCODING_ZIPMAP
: return "zipmap";
419 case REDIS_ENCODING_LINKEDLIST
: return "linkedlist";
420 case REDIS_ENCODING_ZIPLIST
: return "ziplist";
421 case REDIS_ENCODING_INTSET
: return "intset";
422 default: return "unknown";