5 robj
*createObject(int type
, void *ptr
) {
6 robj
*o
= zmalloc(sizeof(*o
));
8 o
->encoding
= REDIS_ENCODING_RAW
;
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.
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 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. */
27 robj
*createStringObject(char *ptr
, size_t len
) {
28 return createObject(REDIS_STRING
,sdsnewlen(ptr
,len
));
31 robj
*createStringObjectFromLongLong(long long value
) {
33 if (value
>= 0 && value
< REDIS_SHARED_INTEGERS
) {
34 incrRefCount(shared
.integers
[value
]);
35 o
= shared
.integers
[value
];
37 if (value
>= LONG_MIN
&& value
<= LONG_MAX
) {
38 o
= createObject(REDIS_STRING
, NULL
);
39 o
->encoding
= REDIS_ENCODING_INT
;
40 o
->ptr
= (void*)((long)value
);
42 o
= createObject(REDIS_STRING
,sdsfromlonglong(value
));
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 robj
*createStringObjectFromLongDouble(long double value
) {
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 len
= snprintf(buf
,sizeof(buf
),"%.17Lf", value
);
60 /* Now remove trailing zeroes after the '.' */
61 if ((p
= strchr(buf
,'.')) != NULL
) {
69 return createStringObject(buf
,len
);
72 robj
*dupStringObject(robj
*o
) {
73 redisAssertWithInfo(NULL
,o
,o
->encoding
== REDIS_ENCODING_RAW
);
74 return createStringObject(o
->ptr
,sdslen(o
->ptr
));
77 robj
*createListObject(void) {
78 list
*l
= listCreate();
79 robj
*o
= createObject(REDIS_LIST
,l
);
80 listSetFreeMethod(l
,decrRefCount
);
81 o
->encoding
= REDIS_ENCODING_LINKEDLIST
;
85 robj
*createZiplistObject(void) {
86 unsigned char *zl
= ziplistNew();
87 robj
*o
= createObject(REDIS_LIST
,zl
);
88 o
->encoding
= REDIS_ENCODING_ZIPLIST
;
92 robj
*createSetObject(void) {
93 dict
*d
= dictCreate(&setDictType
,NULL
);
94 robj
*o
= createObject(REDIS_SET
,d
);
95 o
->encoding
= REDIS_ENCODING_HT
;
99 robj
*createIntsetObject(void) {
100 intset
*is
= intsetNew();
101 robj
*o
= createObject(REDIS_SET
,is
);
102 o
->encoding
= REDIS_ENCODING_INTSET
;
106 robj
*createHashObject(void) {
107 unsigned char *zl
= ziplistNew();
108 robj
*o
= createObject(REDIS_HASH
, zl
);
109 o
->encoding
= REDIS_ENCODING_ZIPLIST
;
113 robj
*createZsetObject(void) {
114 zset
*zs
= zmalloc(sizeof(*zs
));
117 zs
->dict
= dictCreate(&zsetDictType
,NULL
);
118 zs
->zsl
= zslCreate();
119 o
= createObject(REDIS_ZSET
,zs
);
120 o
->encoding
= REDIS_ENCODING_SKIPLIST
;
124 robj
*createZsetZiplistObject(void) {
125 unsigned char *zl
= ziplistNew();
126 robj
*o
= createObject(REDIS_ZSET
,zl
);
127 o
->encoding
= REDIS_ENCODING_ZIPLIST
;
131 void freeStringObject(robj
*o
) {
132 if (o
->encoding
== REDIS_ENCODING_RAW
) {
137 void freeListObject(robj
*o
) {
138 switch (o
->encoding
) {
139 case REDIS_ENCODING_LINKEDLIST
:
140 listRelease((list
*) o
->ptr
);
142 case REDIS_ENCODING_ZIPLIST
:
146 redisPanic("Unknown list encoding type");
150 void freeSetObject(robj
*o
) {
151 switch (o
->encoding
) {
152 case REDIS_ENCODING_HT
:
153 dictRelease((dict
*) o
->ptr
);
155 case REDIS_ENCODING_INTSET
:
159 redisPanic("Unknown set encoding type");
163 void freeZsetObject(robj
*o
) {
165 switch (o
->encoding
) {
166 case REDIS_ENCODING_SKIPLIST
:
168 dictRelease(zs
->dict
);
172 case REDIS_ENCODING_ZIPLIST
:
176 redisPanic("Unknown sorted set encoding");
180 void freeHashObject(robj
*o
) {
181 switch (o
->encoding
) {
182 case REDIS_ENCODING_HT
:
183 dictRelease((dict
*) o
->ptr
);
185 case REDIS_ENCODING_ZIPLIST
:
189 redisPanic("Unknown hash encoding type");
194 void incrRefCount(robj
*o
) {
198 void decrRefCount(void *obj
) {
201 if (o
->refcount
<= 0) redisPanic("decrRefCount against refcount <= 0");
202 if (o
->refcount
== 1) {
204 case REDIS_STRING
: freeStringObject(o
); break;
205 case REDIS_LIST
: freeListObject(o
); break;
206 case REDIS_SET
: freeSetObject(o
); break;
207 case REDIS_ZSET
: freeZsetObject(o
); break;
208 case REDIS_HASH
: freeHashObject(o
); break;
209 default: redisPanic("Unknown object type"); break;
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:
221 * functionThatWillIncrementRefCount(resetRefCount(CreateObject(...)));
223 * Otherwise you need to resort to the less elegant pattern:
225 * *obj = createObject(...);
226 * functionThatWillIncrementRefCount(obj);
229 robj
*resetRefCount(robj
*obj
) {
234 int checkType(redisClient
*c
, robj
*o
, int type
) {
235 if (o
->type
!= type
) {
236 addReply(c
,shared
.wrongtypeerr
);
242 int isObjectRepresentableAsLongLong(robj
*o
, long long *llval
) {
243 redisAssertWithInfo(NULL
,o
,o
->type
== REDIS_STRING
);
244 if (o
->encoding
== REDIS_ENCODING_INT
) {
245 if (llval
) *llval
= (long) o
->ptr
;
248 return string2ll(o
->ptr
,sdslen(o
->ptr
),llval
) ? REDIS_OK
: REDIS_ERR
;
252 /* Try to encode a string object in order to save space */
253 robj
*tryObjectEncoding(robj
*o
) {
257 if (o
->encoding
!= REDIS_ENCODING_RAW
)
258 return o
; /* Already encoded */
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 if (o
->refcount
> 1) return o
;
265 /* Currently we try to encode only strings */
266 redisAssertWithInfo(NULL
,o
,o
->type
== REDIS_STRING
);
268 /* Check if we can represent this string as a long integer */
269 if (!string2l(s
,sdslen(s
),&value
)) return o
;
271 /* Ok, this object can be encoded...
273 * Can I use a shared object? Only if the object is inside a given
274 * range and if the back end in use is in-memory. For disk store every
275 * object in memory used as value should be independent.
277 * Note that we also avoid using shared integers when maxmemory is used
278 * because every object needs to have a private LRU field for the LRU
279 * algorithm to work well. */
280 if (server
.maxmemory
== 0 && value
>= 0 && value
< REDIS_SHARED_INTEGERS
) {
282 incrRefCount(shared
.integers
[value
]);
283 return shared
.integers
[value
];
285 o
->encoding
= REDIS_ENCODING_INT
;
287 o
->ptr
= (void*) value
;
292 /* Get a decoded version of an encoded object (returned as a new object).
293 * If the object is already raw-encoded just increment the ref count. */
294 robj
*getDecodedObject(robj
*o
) {
297 if (o
->encoding
== REDIS_ENCODING_RAW
) {
301 if (o
->type
== REDIS_STRING
&& o
->encoding
== REDIS_ENCODING_INT
) {
304 ll2string(buf
,32,(long)o
->ptr
);
305 dec
= createStringObject(buf
,strlen(buf
));
308 redisPanic("Unknown encoding type");
312 /* Compare two string objects via strcmp() or alike.
313 * Note that the objects may be integer-encoded. In such a case we
314 * use ll2string() to get a string representation of the numbers on the stack
315 * and compare the strings, it's much faster than calling getDecodedObject().
317 * Important note: if objects are not integer encoded, but binary-safe strings,
318 * sdscmp() from sds.c will apply memcmp() so this function ca be considered
320 int compareStringObjects(robj
*a
, robj
*b
) {
321 redisAssertWithInfo(NULL
,a
,a
->type
== REDIS_STRING
&& b
->type
== REDIS_STRING
);
322 char bufa
[128], bufb
[128], *astr
, *bstr
;
325 if (a
== b
) return 0;
326 if (a
->encoding
!= REDIS_ENCODING_RAW
) {
327 ll2string(bufa
,sizeof(bufa
),(long) a
->ptr
);
333 if (b
->encoding
!= REDIS_ENCODING_RAW
) {
334 ll2string(bufb
,sizeof(bufb
),(long) b
->ptr
);
340 return bothsds
? sdscmp(astr
,bstr
) : strcmp(astr
,bstr
);
343 /* Equal string objects return 1 if the two objects are the same from the
344 * point of view of a string comparison, otherwise 0 is returned. Note that
345 * this function is faster then checking for (compareStringObject(a,b) == 0)
346 * because it can perform some more optimization. */
347 int equalStringObjects(robj
*a
, robj
*b
) {
348 if (a
->encoding
!= REDIS_ENCODING_RAW
&& b
->encoding
!= REDIS_ENCODING_RAW
){
349 return a
->ptr
== b
->ptr
;
351 return compareStringObjects(a
,b
) == 0;
355 size_t stringObjectLen(robj
*o
) {
356 redisAssertWithInfo(NULL
,o
,o
->type
== REDIS_STRING
);
357 if (o
->encoding
== REDIS_ENCODING_RAW
) {
358 return sdslen(o
->ptr
);
362 return ll2string(buf
,32,(long)o
->ptr
);
366 int getDoubleFromObject(robj
*o
, double *target
) {
373 redisAssertWithInfo(NULL
,o
,o
->type
== REDIS_STRING
);
374 if (o
->encoding
== REDIS_ENCODING_RAW
) {
376 value
= strtod(o
->ptr
, &eptr
);
377 if (isspace(((char*)o
->ptr
)[0]) || eptr
[0] != '\0' ||
378 errno
== ERANGE
|| isnan(value
))
380 } else if (o
->encoding
== REDIS_ENCODING_INT
) {
381 value
= (long)o
->ptr
;
383 redisPanic("Unknown string encoding");
390 int getDoubleFromObjectOrReply(redisClient
*c
, robj
*o
, double *target
, const char *msg
) {
392 if (getDoubleFromObject(o
, &value
) != REDIS_OK
) {
394 addReplyError(c
,(char*)msg
);
396 addReplyError(c
,"value is not a valid float");
404 int getLongDoubleFromObject(robj
*o
, long double *target
) {
411 redisAssertWithInfo(NULL
,o
,o
->type
== REDIS_STRING
);
412 if (o
->encoding
== REDIS_ENCODING_RAW
) {
414 value
= strtold(o
->ptr
, &eptr
);
415 if (isspace(((char*)o
->ptr
)[0]) || eptr
[0] != '\0' ||
416 errno
== ERANGE
|| isnan(value
))
418 } else if (o
->encoding
== REDIS_ENCODING_INT
) {
419 value
= (long)o
->ptr
;
421 redisPanic("Unknown string encoding");
428 int getLongDoubleFromObjectOrReply(redisClient
*c
, robj
*o
, long double *target
, const char *msg
) {
430 if (getLongDoubleFromObject(o
, &value
) != REDIS_OK
) {
432 addReplyError(c
,(char*)msg
);
434 addReplyError(c
,"value is not a valid float");
442 int getLongLongFromObject(robj
*o
, long long *target
) {
449 redisAssertWithInfo(NULL
,o
,o
->type
== REDIS_STRING
);
450 if (o
->encoding
== REDIS_ENCODING_RAW
) {
452 value
= strtoll(o
->ptr
, &eptr
, 10);
453 if (isspace(((char*)o
->ptr
)[0]) || eptr
[0] != '\0' ||
456 } else if (o
->encoding
== REDIS_ENCODING_INT
) {
457 value
= (long)o
->ptr
;
459 redisPanic("Unknown string encoding");
462 if (target
) *target
= value
;
466 int getLongLongFromObjectOrReply(redisClient
*c
, robj
*o
, long long *target
, const char *msg
) {
468 if (getLongLongFromObject(o
, &value
) != REDIS_OK
) {
470 addReplyError(c
,(char*)msg
);
472 addReplyError(c
,"value is not an integer or out of range");
480 int getLongFromObjectOrReply(redisClient
*c
, robj
*o
, long *target
, const char *msg
) {
483 if (getLongLongFromObjectOrReply(c
, o
, &value
, msg
) != REDIS_OK
) return REDIS_ERR
;
484 if (value
< LONG_MIN
|| value
> LONG_MAX
) {
486 addReplyError(c
,(char*)msg
);
488 addReplyError(c
,"value is out of range");
496 char *strEncoding(int encoding
) {
498 case REDIS_ENCODING_RAW
: return "raw";
499 case REDIS_ENCODING_INT
: return "int";
500 case REDIS_ENCODING_HT
: return "hashtable";
501 case REDIS_ENCODING_LINKEDLIST
: return "linkedlist";
502 case REDIS_ENCODING_ZIPLIST
: return "ziplist";
503 case REDIS_ENCODING_INTSET
: return "intset";
504 case REDIS_ENCODING_SKIPLIST
: return "skiplist";
505 default: return "unknown";
509 /* Given an object returns the min number of seconds the object was never
510 * requested, using an approximated LRU algorithm. */
511 unsigned long estimateObjectIdleTime(robj
*o
) {
512 if (server
.lruclock
>= o
->lru
) {
513 return (server
.lruclock
- o
->lru
) * REDIS_LRU_CLOCK_RESOLUTION
;
515 return ((REDIS_LRU_CLOCK_MAX
- o
->lru
) + server
.lruclock
) *
516 REDIS_LRU_CLOCK_RESOLUTION
;
520 /* This is an helper function for the DEBUG command. We need to lookup keys
521 * without any modification of LRU or other parameters. */
522 robj
*objectCommandLookup(redisClient
*c
, robj
*key
) {
525 if ((de
= dictFind(c
->db
->dict
,key
->ptr
)) == NULL
) return NULL
;
526 return (robj
*) dictGetVal(de
);
529 robj
*objectCommandLookupOrReply(redisClient
*c
, robj
*key
, robj
*reply
) {
530 robj
*o
= objectCommandLookup(c
,key
);
532 if (!o
) addReply(c
, reply
);
536 /* Object command allows to inspect the internals of an Redis Object.
537 * Usage: OBJECT <verb> ... arguments ... */
538 void objectCommand(redisClient
*c
) {
541 if (!strcasecmp(c
->argv
[1]->ptr
,"refcount") && c
->argc
== 3) {
542 if ((o
= objectCommandLookupOrReply(c
,c
->argv
[2],shared
.nullbulk
))
544 addReplyLongLong(c
,o
->refcount
);
545 } else if (!strcasecmp(c
->argv
[1]->ptr
,"encoding") && c
->argc
== 3) {
546 if ((o
= objectCommandLookupOrReply(c
,c
->argv
[2],shared
.nullbulk
))
548 addReplyBulkCString(c
,strEncoding(o
->encoding
));
549 } else if (!strcasecmp(c
->argv
[1]->ptr
,"idletime") && c
->argc
== 3) {
550 if ((o
= objectCommandLookupOrReply(c
,c
->argv
[2],shared
.nullbulk
))
552 addReplyLongLong(c
,estimateObjectIdleTime(o
));
554 addReplyError(c
,"Syntax error. Try OBJECT (refcount|encoding|idletime)");