5 robj
*createObject(int type
, void *ptr
) {
8 if (server
.vm_enabled
) pthread_mutex_lock(&server
.obj_freelist_mutex
);
9 if (listLength(server
.objfreelist
)) {
10 listNode
*head
= listFirst(server
.objfreelist
);
11 o
= listNodeValue(head
);
12 listDelNode(server
.objfreelist
,head
);
13 if (server
.vm_enabled
) pthread_mutex_unlock(&server
.obj_freelist_mutex
);
15 if (server
.vm_enabled
) pthread_mutex_unlock(&server
.obj_freelist_mutex
);
16 o
= zmalloc(sizeof(*o
));
19 o
->encoding
= REDIS_ENCODING_RAW
;
22 /* Set the LRU to the current lruclock (minutes resolution).
23 * We do this regardless of the fact VM is active as LRU is also
24 * used for the maxmemory directive when Redis is used as cache.
26 * Note that this code may run in the context of an I/O thread
27 * and accessing server.lruclock in theory is an error
28 * (no locks). But in practice this is safe, and even if we read
29 * garbage Redis will not fail. */
30 o
->lru
= server
.lruclock
;
31 /* The following is only needed if VM is active, but since the conditional
32 * is probably more costly than initializing the field it's better to
33 * have every field properly initialized anyway. */
34 o
->storage
= REDIS_VM_MEMORY
;
38 robj
*createStringObject(char *ptr
, size_t len
) {
39 return createObject(REDIS_STRING
,sdsnewlen(ptr
,len
));
42 robj
*createStringObjectFromLongLong(long long value
) {
44 if (value
>= 0 && value
< REDIS_SHARED_INTEGERS
&&
45 pthread_equal(pthread_self(),server
.mainthread
)) {
46 incrRefCount(shared
.integers
[value
]);
47 o
= shared
.integers
[value
];
49 if (value
>= LONG_MIN
&& value
<= LONG_MAX
) {
50 o
= createObject(REDIS_STRING
, NULL
);
51 o
->encoding
= REDIS_ENCODING_INT
;
52 o
->ptr
= (void*)((long)value
);
54 o
= createObject(REDIS_STRING
,sdsfromlonglong(value
));
60 robj
*dupStringObject(robj
*o
) {
61 redisAssert(o
->encoding
== REDIS_ENCODING_RAW
);
62 return createStringObject(o
->ptr
,sdslen(o
->ptr
));
65 robj
*createListObject(void) {
66 list
*l
= listCreate();
67 robj
*o
= createObject(REDIS_LIST
,l
);
68 listSetFreeMethod(l
,decrRefCount
);
69 o
->encoding
= REDIS_ENCODING_LINKEDLIST
;
73 robj
*createZiplistObject(void) {
74 unsigned char *zl
= ziplistNew();
75 robj
*o
= createObject(REDIS_LIST
,zl
);
76 o
->encoding
= REDIS_ENCODING_ZIPLIST
;
80 robj
*createSetObject(void) {
81 dict
*d
= dictCreate(&setDictType
,NULL
);
82 robj
*o
= createObject(REDIS_SET
,d
);
83 o
->encoding
= REDIS_ENCODING_HT
;
87 robj
*createIntsetObject(void) {
88 intset
*is
= intsetNew();
89 robj
*o
= createObject(REDIS_SET
,is
);
90 o
->encoding
= REDIS_ENCODING_INTSET
;
94 robj
*createHashObject(void) {
95 /* All the Hashes start as zipmaps. Will be automatically converted
96 * into hash tables if there are enough elements or big elements
98 unsigned char *zm
= zipmapNew();
99 robj
*o
= createObject(REDIS_HASH
,zm
);
100 o
->encoding
= REDIS_ENCODING_ZIPMAP
;
104 robj
*createZsetObject(void) {
105 zset
*zs
= zmalloc(sizeof(*zs
));
107 zs
->dict
= dictCreate(&zsetDictType
,NULL
);
108 zs
->zsl
= zslCreate();
109 return createObject(REDIS_ZSET
,zs
);
112 void freeStringObject(robj
*o
) {
113 if (o
->encoding
== REDIS_ENCODING_RAW
) {
118 void freeListObject(robj
*o
) {
119 switch (o
->encoding
) {
120 case REDIS_ENCODING_LINKEDLIST
:
121 listRelease((list
*) o
->ptr
);
123 case REDIS_ENCODING_ZIPLIST
:
127 redisPanic("Unknown list encoding type");
131 void freeSetObject(robj
*o
) {
132 switch (o
->encoding
) {
133 case REDIS_ENCODING_HT
:
134 dictRelease((dict
*) o
->ptr
);
136 case REDIS_ENCODING_INTSET
:
140 redisPanic("Unknown set encoding type");
144 void freeZsetObject(robj
*o
) {
147 dictRelease(zs
->dict
);
152 void freeHashObject(robj
*o
) {
153 switch (o
->encoding
) {
154 case REDIS_ENCODING_HT
:
155 dictRelease((dict
*) o
->ptr
);
157 case REDIS_ENCODING_ZIPMAP
:
161 redisPanic("Unknown hash encoding type");
166 void incrRefCount(robj
*o
) {
170 void decrRefCount(void *obj
) {
173 /* Object is a swapped out value, or in the process of being loaded. */
174 if (server
.vm_enabled
&&
175 (o
->storage
== REDIS_VM_SWAPPED
|| o
->storage
== REDIS_VM_LOADING
))
178 if (o
->storage
== REDIS_VM_LOADING
) vmCancelThreadedIOJob(o
);
179 vmMarkPagesFree(vp
->page
,vp
->usedpages
);
180 server
.vm_stats_swapped_objects
--;
185 if (o
->refcount
<= 0) redisPanic("decrRefCount against refcount <= 0");
186 /* Object is in memory, or in the process of being swapped out.
188 * If the object is being swapped out, abort the operation on
189 * decrRefCount even if the refcount does not drop to 0: the object
190 * is referenced at least two times, as value of the key AND as
191 * job->val in the iojob. So if we don't invalidate the iojob, when it is
192 * done but the relevant key was removed in the meantime, the
193 * complete jobs handler will not find the key about the job and the
194 * assert will fail. */
195 if (server
.vm_enabled
&& o
->storage
== REDIS_VM_SWAPPING
)
196 vmCancelThreadedIOJob(o
);
197 if (--(o
->refcount
) == 0) {
199 case REDIS_STRING
: freeStringObject(o
); break;
200 case REDIS_LIST
: freeListObject(o
); break;
201 case REDIS_SET
: freeSetObject(o
); break;
202 case REDIS_ZSET
: freeZsetObject(o
); break;
203 case REDIS_HASH
: freeHashObject(o
); break;
204 default: redisPanic("Unknown object type"); break;
206 o
->ptr
= NULL
; /* defensive programming. We'll see NULL in traces. */
207 if (server
.vm_enabled
) pthread_mutex_lock(&server
.obj_freelist_mutex
);
208 if (listLength(server
.objfreelist
) > REDIS_OBJFREELIST_MAX
||
209 !listAddNodeHead(server
.objfreelist
,o
))
211 if (server
.vm_enabled
) pthread_mutex_unlock(&server
.obj_freelist_mutex
);
215 int checkType(redisClient
*c
, robj
*o
, int type
) {
216 if (o
->type
!= type
) {
217 addReply(c
,shared
.wrongtypeerr
);
223 /* Try to encode a string object in order to save space */
224 robj
*tryObjectEncoding(robj
*o
) {
228 if (o
->encoding
!= REDIS_ENCODING_RAW
)
229 return o
; /* Already encoded */
231 /* It's not safe to encode shared objects: shared objects can be shared
232 * everywhere in the "object space" of Redis. Encoded objects can only
233 * appear as "values" (and not, for instance, as keys) */
234 if (o
->refcount
> 1) return o
;
236 /* Currently we try to encode only strings */
237 redisAssert(o
->type
== REDIS_STRING
);
239 /* Check if we can represent this string as a long integer */
240 if (isStringRepresentableAsLong(s
,&value
) == REDIS_ERR
) return o
;
242 /* Ok, this object can be encoded...
244 * Can I use a shared object? Only if the object is inside a given
245 * range and if this is the main thread, since when VM is enabled we
246 * have the constraint that I/O thread should only handle non-shared
247 * objects, in order to avoid race conditions (we don't have per-object
249 if (value
>= 0 && value
< REDIS_SHARED_INTEGERS
&&
250 pthread_equal(pthread_self(),server
.mainthread
)) {
252 incrRefCount(shared
.integers
[value
]);
253 return shared
.integers
[value
];
255 o
->encoding
= REDIS_ENCODING_INT
;
257 o
->ptr
= (void*) value
;
262 /* Get a decoded version of an encoded object (returned as a new object).
263 * If the object is already raw-encoded just increment the ref count. */
264 robj
*getDecodedObject(robj
*o
) {
267 if (o
->encoding
== REDIS_ENCODING_RAW
) {
271 if (o
->type
== REDIS_STRING
&& o
->encoding
== REDIS_ENCODING_INT
) {
274 ll2string(buf
,32,(long)o
->ptr
);
275 dec
= createStringObject(buf
,strlen(buf
));
278 redisPanic("Unknown encoding type");
282 /* Compare two string objects via strcmp() or alike.
283 * Note that the objects may be integer-encoded. In such a case we
284 * use ll2string() to get a string representation of the numbers on the stack
285 * and compare the strings, it's much faster than calling getDecodedObject().
287 * Important note: if objects are not integer encoded, but binary-safe strings,
288 * sdscmp() from sds.c will apply memcmp() so this function ca be considered
290 int compareStringObjects(robj
*a
, robj
*b
) {
291 redisAssert(a
->type
== REDIS_STRING
&& b
->type
== REDIS_STRING
);
292 char bufa
[128], bufb
[128], *astr
, *bstr
;
295 if (a
== b
) return 0;
296 if (a
->encoding
!= REDIS_ENCODING_RAW
) {
297 ll2string(bufa
,sizeof(bufa
),(long) a
->ptr
);
303 if (b
->encoding
!= REDIS_ENCODING_RAW
) {
304 ll2string(bufb
,sizeof(bufb
),(long) b
->ptr
);
310 return bothsds
? sdscmp(astr
,bstr
) : strcmp(astr
,bstr
);
313 /* Equal string objects return 1 if the two objects are the same from the
314 * point of view of a string comparison, otherwise 0 is returned. Note that
315 * this function is faster then checking for (compareStringObject(a,b) == 0)
316 * because it can perform some more optimization. */
317 int equalStringObjects(robj
*a
, robj
*b
) {
318 if (a
->encoding
!= REDIS_ENCODING_RAW
&& b
->encoding
!= REDIS_ENCODING_RAW
){
319 return a
->ptr
== b
->ptr
;
321 return compareStringObjects(a
,b
) == 0;
325 size_t stringObjectLen(robj
*o
) {
326 redisAssert(o
->type
== REDIS_STRING
);
327 if (o
->encoding
== REDIS_ENCODING_RAW
) {
328 return sdslen(o
->ptr
);
332 return ll2string(buf
,32,(long)o
->ptr
);
336 int getDoubleFromObject(robj
*o
, double *target
) {
343 redisAssert(o
->type
== REDIS_STRING
);
344 if (o
->encoding
== REDIS_ENCODING_RAW
) {
345 value
= strtod(o
->ptr
, &eptr
);
346 if (eptr
[0] != '\0' || isnan(value
)) return REDIS_ERR
;
347 } else if (o
->encoding
== REDIS_ENCODING_INT
) {
348 value
= (long)o
->ptr
;
350 redisPanic("Unknown string encoding");
358 int getDoubleFromObjectOrReply(redisClient
*c
, robj
*o
, double *target
, const char *msg
) {
360 if (getDoubleFromObject(o
, &value
) != REDIS_OK
) {
362 addReplyError(c
,(char*)msg
);
364 addReplyError(c
,"value is not a double");
373 int getLongLongFromObject(robj
*o
, long long *target
) {
380 redisAssert(o
->type
== REDIS_STRING
);
381 if (o
->encoding
== REDIS_ENCODING_RAW
) {
382 value
= strtoll(o
->ptr
, &eptr
, 10);
383 if (eptr
[0] != '\0') return REDIS_ERR
;
384 if (errno
== ERANGE
&& (value
== LLONG_MIN
|| value
== LLONG_MAX
))
386 } else if (o
->encoding
== REDIS_ENCODING_INT
) {
387 value
= (long)o
->ptr
;
389 redisPanic("Unknown string encoding");
393 if (target
) *target
= value
;
397 int getLongLongFromObjectOrReply(redisClient
*c
, robj
*o
, long long *target
, const char *msg
) {
399 if (getLongLongFromObject(o
, &value
) != REDIS_OK
) {
401 addReplyError(c
,(char*)msg
);
403 addReplyError(c
,"value is not an integer or out of range");
412 int getLongFromObjectOrReply(redisClient
*c
, robj
*o
, long *target
, const char *msg
) {
415 if (getLongLongFromObjectOrReply(c
, o
, &value
, msg
) != REDIS_OK
) return REDIS_ERR
;
416 if (value
< LONG_MIN
|| value
> LONG_MAX
) {
418 addReplyError(c
,(char*)msg
);
420 addReplyError(c
,"value is out of range");
429 char *strEncoding(int encoding
) {
431 case REDIS_ENCODING_RAW
: return "raw";
432 case REDIS_ENCODING_INT
: return "int";
433 case REDIS_ENCODING_HT
: return "hashtable";
434 case REDIS_ENCODING_ZIPMAP
: return "zipmap";
435 case REDIS_ENCODING_LINKEDLIST
: return "linkedlist";
436 case REDIS_ENCODING_ZIPLIST
: return "ziplist";
437 case REDIS_ENCODING_INTSET
: return "intset";
438 default: return "unknown";
442 /* Given an object returns the min number of seconds the object was never
443 * requested, using an approximated LRU algorithm. */
444 unsigned long estimateObjectIdleTime(robj
*o
) {
445 if (server
.lruclock
>= o
->lru
) {
446 return (server
.lruclock
- o
->lru
) * REDIS_LRU_CLOCK_RESOLUTION
;
448 return ((REDIS_LRU_CLOCK_MAX
- o
->lru
) + server
.lruclock
) *
449 REDIS_LRU_CLOCK_RESOLUTION
;