1 /* Redis Object implementation.
3 * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * * Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * * Neither the name of Redis nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without
16 * specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
35 robj
*createObject(int type
, void *ptr
) {
36 robj
*o
= zmalloc(sizeof(*o
));
38 o
->encoding
= REDIS_ENCODING_RAW
;
42 /* Set the LRU to the current lruclock (minutes resolution). */
43 o
->lru
= server
.lruclock
;
47 robj
*createStringObject(char *ptr
, size_t len
) {
48 return createObject(REDIS_STRING
,sdsnewlen(ptr
,len
));
51 robj
*createStringObjectFromLongLong(long long value
) {
53 if (value
>= 0 && value
< REDIS_SHARED_INTEGERS
) {
54 incrRefCount(shared
.integers
[value
]);
55 o
= shared
.integers
[value
];
57 if (value
>= LONG_MIN
&& value
<= LONG_MAX
) {
58 o
= createObject(REDIS_STRING
, NULL
);
59 o
->encoding
= REDIS_ENCODING_INT
;
60 o
->ptr
= (void*)((long)value
);
62 o
= createObject(REDIS_STRING
,sdsfromlonglong(value
));
68 /* Note: this function is defined into object.c since here it is where it
69 * belongs but it is actually designed to be used just for INCRBYFLOAT */
70 robj
*createStringObjectFromLongDouble(long double value
) {
74 /* We use 17 digits precision since with 128 bit floats that precision
75 * after rouding is able to represent most small decimal numbers in a way
76 * that is "non surprising" for the user (that is, most small decimal
77 * numbers will be represented in a way that when converted back into
78 * a string are exactly the same as what the user typed.) */
79 len
= snprintf(buf
,sizeof(buf
),"%.17Lf", value
);
80 /* Now remove trailing zeroes after the '.' */
81 if (strchr(buf
,'.') != NULL
) {
89 return createStringObject(buf
,len
);
92 robj
*dupStringObject(robj
*o
) {
93 redisAssertWithInfo(NULL
,o
,o
->encoding
== REDIS_ENCODING_RAW
);
94 return createStringObject(o
->ptr
,sdslen(o
->ptr
));
97 robj
*createListObject(void) {
98 list
*l
= listCreate();
99 robj
*o
= createObject(REDIS_LIST
,l
);
100 listSetFreeMethod(l
,decrRefCount
);
101 o
->encoding
= REDIS_ENCODING_LINKEDLIST
;
105 robj
*createZiplistObject(void) {
106 unsigned char *zl
= ziplistNew();
107 robj
*o
= createObject(REDIS_LIST
,zl
);
108 o
->encoding
= REDIS_ENCODING_ZIPLIST
;
112 robj
*createSetObject(void) {
113 dict
*d
= dictCreate(&setDictType
,NULL
);
114 robj
*o
= createObject(REDIS_SET
,d
);
115 o
->encoding
= REDIS_ENCODING_HT
;
119 robj
*createIntsetObject(void) {
120 intset
*is
= intsetNew();
121 robj
*o
= createObject(REDIS_SET
,is
);
122 o
->encoding
= REDIS_ENCODING_INTSET
;
126 robj
*createHashObject(void) {
127 unsigned char *zl
= ziplistNew();
128 robj
*o
= createObject(REDIS_HASH
, zl
);
129 o
->encoding
= REDIS_ENCODING_ZIPLIST
;
133 robj
*createZsetObject(void) {
134 zset
*zs
= zmalloc(sizeof(*zs
));
137 zs
->dict
= dictCreate(&zsetDictType
,NULL
);
138 zs
->zsl
= zslCreate();
139 o
= createObject(REDIS_ZSET
,zs
);
140 o
->encoding
= REDIS_ENCODING_SKIPLIST
;
144 robj
*createZsetZiplistObject(void) {
145 unsigned char *zl
= ziplistNew();
146 robj
*o
= createObject(REDIS_ZSET
,zl
);
147 o
->encoding
= REDIS_ENCODING_ZIPLIST
;
151 void freeStringObject(robj
*o
) {
152 if (o
->encoding
== REDIS_ENCODING_RAW
) {
157 void freeListObject(robj
*o
) {
158 switch (o
->encoding
) {
159 case REDIS_ENCODING_LINKEDLIST
:
160 listRelease((list
*) o
->ptr
);
162 case REDIS_ENCODING_ZIPLIST
:
166 redisPanic("Unknown list encoding type");
170 void freeSetObject(robj
*o
) {
171 switch (o
->encoding
) {
172 case REDIS_ENCODING_HT
:
173 dictRelease((dict
*) o
->ptr
);
175 case REDIS_ENCODING_INTSET
:
179 redisPanic("Unknown set encoding type");
183 void freeZsetObject(robj
*o
) {
185 switch (o
->encoding
) {
186 case REDIS_ENCODING_SKIPLIST
:
188 dictRelease(zs
->dict
);
192 case REDIS_ENCODING_ZIPLIST
:
196 redisPanic("Unknown sorted set encoding");
200 void freeHashObject(robj
*o
) {
201 switch (o
->encoding
) {
202 case REDIS_ENCODING_HT
:
203 dictRelease((dict
*) o
->ptr
);
205 case REDIS_ENCODING_ZIPLIST
:
209 redisPanic("Unknown hash encoding type");
214 void incrRefCount(robj
*o
) {
218 void decrRefCount(void *obj
) {
221 if (o
->refcount
<= 0) redisPanic("decrRefCount against refcount <= 0");
222 if (o
->refcount
== 1) {
224 case REDIS_STRING
: freeStringObject(o
); break;
225 case REDIS_LIST
: freeListObject(o
); break;
226 case REDIS_SET
: freeSetObject(o
); break;
227 case REDIS_ZSET
: freeZsetObject(o
); break;
228 case REDIS_HASH
: freeHashObject(o
); break;
229 default: redisPanic("Unknown object type"); break;
237 /* This function set the ref count to zero without freeing the object.
238 * It is useful in order to pass a new object to functions incrementing
239 * the ref count of the received object. Example:
241 * functionThatWillIncrementRefCount(resetRefCount(CreateObject(...)));
243 * Otherwise you need to resort to the less elegant pattern:
245 * *obj = createObject(...);
246 * functionThatWillIncrementRefCount(obj);
249 robj
*resetRefCount(robj
*obj
) {
254 int checkType(redisClient
*c
, robj
*o
, int type
) {
255 if (o
->type
!= type
) {
256 addReply(c
,shared
.wrongtypeerr
);
262 int isObjectRepresentableAsLongLong(robj
*o
, long long *llval
) {
263 redisAssertWithInfo(NULL
,o
,o
->type
== REDIS_STRING
);
264 if (o
->encoding
== REDIS_ENCODING_INT
) {
265 if (llval
) *llval
= (long) o
->ptr
;
268 return string2ll(o
->ptr
,sdslen(o
->ptr
),llval
) ? REDIS_OK
: REDIS_ERR
;
272 /* Try to encode a string object in order to save space */
273 robj
*tryObjectEncoding(robj
*o
) {
277 if (o
->encoding
!= REDIS_ENCODING_RAW
)
278 return o
; /* Already encoded */
280 /* It's not safe to encode shared objects: shared objects can be shared
281 * everywhere in the "object space" of Redis. Encoded objects can only
282 * appear as "values" (and not, for instance, as keys) */
283 if (o
->refcount
> 1) return o
;
285 /* Currently we try to encode only strings */
286 redisAssertWithInfo(NULL
,o
,o
->type
== REDIS_STRING
);
288 /* Check if we can represent this string as a long integer */
289 if (!string2l(s
,sdslen(s
),&value
)) return o
;
291 /* Ok, this object can be encoded...
293 * Can I use a shared object? Only if the object is inside a given range
295 * Note that we also avoid using shared integers when maxmemory is used
296 * because every object needs to have a private LRU field for the LRU
297 * algorithm to work well. */
298 if (server
.maxmemory
== 0 && value
>= 0 && value
< REDIS_SHARED_INTEGERS
) {
300 incrRefCount(shared
.integers
[value
]);
301 return shared
.integers
[value
];
303 o
->encoding
= REDIS_ENCODING_INT
;
305 o
->ptr
= (void*) value
;
310 /* Get a decoded version of an encoded object (returned as a new object).
311 * If the object is already raw-encoded just increment the ref count. */
312 robj
*getDecodedObject(robj
*o
) {
315 if (o
->encoding
== REDIS_ENCODING_RAW
) {
319 if (o
->type
== REDIS_STRING
&& o
->encoding
== REDIS_ENCODING_INT
) {
322 ll2string(buf
,32,(long)o
->ptr
);
323 dec
= createStringObject(buf
,strlen(buf
));
326 redisPanic("Unknown encoding type");
330 /* Compare two string objects via strcmp() or alike.
331 * Note that the objects may be integer-encoded. In such a case we
332 * use ll2string() to get a string representation of the numbers on the stack
333 * and compare the strings, it's much faster than calling getDecodedObject().
335 * Important note: if objects are not integer encoded, but binary-safe strings,
336 * sdscmp() from sds.c will apply memcmp() so this function ca be considered
338 int compareStringObjects(robj
*a
, robj
*b
) {
339 redisAssertWithInfo(NULL
,a
,a
->type
== REDIS_STRING
&& b
->type
== REDIS_STRING
);
340 char bufa
[128], bufb
[128], *astr
, *bstr
;
343 if (a
== b
) return 0;
344 if (a
->encoding
!= REDIS_ENCODING_RAW
) {
345 ll2string(bufa
,sizeof(bufa
),(long) a
->ptr
);
351 if (b
->encoding
!= REDIS_ENCODING_RAW
) {
352 ll2string(bufb
,sizeof(bufb
),(long) b
->ptr
);
358 return bothsds
? sdscmp(astr
,bstr
) : strcmp(astr
,bstr
);
361 /* Equal string objects return 1 if the two objects are the same from the
362 * point of view of a string comparison, otherwise 0 is returned. Note that
363 * this function is faster then checking for (compareStringObject(a,b) == 0)
364 * because it can perform some more optimization. */
365 int equalStringObjects(robj
*a
, robj
*b
) {
366 if (a
->encoding
!= REDIS_ENCODING_RAW
&& b
->encoding
!= REDIS_ENCODING_RAW
){
367 return a
->ptr
== b
->ptr
;
369 return compareStringObjects(a
,b
) == 0;
373 size_t stringObjectLen(robj
*o
) {
374 redisAssertWithInfo(NULL
,o
,o
->type
== REDIS_STRING
);
375 if (o
->encoding
== REDIS_ENCODING_RAW
) {
376 return sdslen(o
->ptr
);
380 return ll2string(buf
,32,(long)o
->ptr
);
384 int getDoubleFromObject(robj
*o
, double *target
) {
391 redisAssertWithInfo(NULL
,o
,o
->type
== REDIS_STRING
);
392 if (o
->encoding
== REDIS_ENCODING_RAW
) {
394 value
= strtod(o
->ptr
, &eptr
);
395 if (isspace(((char*)o
->ptr
)[0]) || eptr
[0] != '\0' ||
396 errno
== ERANGE
|| isnan(value
))
398 } else if (o
->encoding
== REDIS_ENCODING_INT
) {
399 value
= (long)o
->ptr
;
401 redisPanic("Unknown string encoding");
408 int getDoubleFromObjectOrReply(redisClient
*c
, robj
*o
, double *target
, const char *msg
) {
410 if (getDoubleFromObject(o
, &value
) != REDIS_OK
) {
412 addReplyError(c
,(char*)msg
);
414 addReplyError(c
,"value is not a valid float");
422 int getLongDoubleFromObject(robj
*o
, long double *target
) {
429 redisAssertWithInfo(NULL
,o
,o
->type
== REDIS_STRING
);
430 if (o
->encoding
== REDIS_ENCODING_RAW
) {
432 value
= strtold(o
->ptr
, &eptr
);
433 if (isspace(((char*)o
->ptr
)[0]) || eptr
[0] != '\0' ||
434 errno
== ERANGE
|| isnan(value
))
436 } else if (o
->encoding
== REDIS_ENCODING_INT
) {
437 value
= (long)o
->ptr
;
439 redisPanic("Unknown string encoding");
446 int getLongDoubleFromObjectOrReply(redisClient
*c
, robj
*o
, long double *target
, const char *msg
) {
448 if (getLongDoubleFromObject(o
, &value
) != REDIS_OK
) {
450 addReplyError(c
,(char*)msg
);
452 addReplyError(c
,"value is not a valid float");
460 int getLongLongFromObject(robj
*o
, long long *target
) {
467 redisAssertWithInfo(NULL
,o
,o
->type
== REDIS_STRING
);
468 if (o
->encoding
== REDIS_ENCODING_RAW
) {
470 value
= strtoll(o
->ptr
, &eptr
, 10);
471 if (isspace(((char*)o
->ptr
)[0]) || eptr
[0] != '\0' ||
474 } else if (o
->encoding
== REDIS_ENCODING_INT
) {
475 value
= (long)o
->ptr
;
477 redisPanic("Unknown string encoding");
480 if (target
) *target
= value
;
484 int getLongLongFromObjectOrReply(redisClient
*c
, robj
*o
, long long *target
, const char *msg
) {
486 if (getLongLongFromObject(o
, &value
) != REDIS_OK
) {
488 addReplyError(c
,(char*)msg
);
490 addReplyError(c
,"value is not an integer or out of range");
498 int getLongFromObjectOrReply(redisClient
*c
, robj
*o
, long *target
, const char *msg
) {
501 if (getLongLongFromObjectOrReply(c
, o
, &value
, msg
) != REDIS_OK
) return REDIS_ERR
;
502 if (value
< LONG_MIN
|| value
> LONG_MAX
) {
504 addReplyError(c
,(char*)msg
);
506 addReplyError(c
,"value is out of range");
514 char *strEncoding(int encoding
) {
516 case REDIS_ENCODING_RAW
: return "raw";
517 case REDIS_ENCODING_INT
: return "int";
518 case REDIS_ENCODING_HT
: return "hashtable";
519 case REDIS_ENCODING_LINKEDLIST
: return "linkedlist";
520 case REDIS_ENCODING_ZIPLIST
: return "ziplist";
521 case REDIS_ENCODING_INTSET
: return "intset";
522 case REDIS_ENCODING_SKIPLIST
: return "skiplist";
523 default: return "unknown";
527 /* Given an object returns the min number of seconds the object was never
528 * requested, using an approximated LRU algorithm. */
529 unsigned long estimateObjectIdleTime(robj
*o
) {
530 if (server
.lruclock
>= o
->lru
) {
531 return (server
.lruclock
- o
->lru
) * REDIS_LRU_CLOCK_RESOLUTION
;
533 return ((REDIS_LRU_CLOCK_MAX
- o
->lru
) + server
.lruclock
) *
534 REDIS_LRU_CLOCK_RESOLUTION
;
538 /* This is an helper function for the DEBUG command. We need to lookup keys
539 * without any modification of LRU or other parameters. */
540 robj
*objectCommandLookup(redisClient
*c
, robj
*key
) {
543 if ((de
= dictFind(c
->db
->dict
,key
->ptr
)) == NULL
) return NULL
;
544 return (robj
*) dictGetVal(de
);
547 robj
*objectCommandLookupOrReply(redisClient
*c
, robj
*key
, robj
*reply
) {
548 robj
*o
= objectCommandLookup(c
,key
);
550 if (!o
) addReply(c
, reply
);
554 /* Object command allows to inspect the internals of an Redis Object.
555 * Usage: OBJECT <verb> ... arguments ... */
556 void objectCommand(redisClient
*c
) {
559 if (!strcasecmp(c
->argv
[1]->ptr
,"refcount") && c
->argc
== 3) {
560 if ((o
= objectCommandLookupOrReply(c
,c
->argv
[2],shared
.nullbulk
))
562 addReplyLongLong(c
,o
->refcount
);
563 } else if (!strcasecmp(c
->argv
[1]->ptr
,"encoding") && c
->argc
== 3) {
564 if ((o
= objectCommandLookupOrReply(c
,c
->argv
[2],shared
.nullbulk
))
566 addReplyBulkCString(c
,strEncoding(o
->encoding
));
567 } else if (!strcasecmp(c
->argv
[1]->ptr
,"idletime") && c
->argc
== 3) {
568 if ((o
= objectCommandLookupOrReply(c
,c
->argv
[2],shared
.nullbulk
))
570 addReplyLongLong(c
,estimateObjectIdleTime(o
));
572 addReplyError(c
,"Syntax error. Try OBJECT (refcount|encoding|idletime)");