4 robj
*createObject(int type
, void *ptr
) {
5 robj
*o
= zmalloc(sizeof(*o
));
7 o
->encoding
= REDIS_ENCODING_RAW
;
11 /* Set the LRU to the current lruclock (minutes resolution).
12 * We do this regardless of the fact VM is active as LRU is also
13 * used for the maxmemory directive when Redis is used as cache.
15 * Note that this code may run in the context of an I/O thread
16 * and accessing server.lruclock in theory is an error
17 * (no locks). But in practice this is safe, and even if we read
18 * garbage Redis will not fail. */
19 o
->lru
= server
.lruclock
;
20 /* The following is only needed if VM is active, but since the conditional
21 * is probably more costly than initializing the field it's better to
22 * have every field properly initialized anyway. */
26 robj
*createStringObject(char *ptr
, size_t len
) {
27 return createObject(REDIS_STRING
,sdsnewlen(ptr
,len
));
30 robj
*createStringObjectFromLongLong(long long value
) {
32 if (value
>= 0 && value
< REDIS_SHARED_INTEGERS
) {
33 incrRefCount(shared
.integers
[value
]);
34 o
= shared
.integers
[value
];
36 if (value
>= LONG_MIN
&& value
<= LONG_MAX
) {
37 o
= createObject(REDIS_STRING
, NULL
);
38 o
->encoding
= REDIS_ENCODING_INT
;
39 o
->ptr
= (void*)((long)value
);
41 o
= createObject(REDIS_STRING
,sdsfromlonglong(value
));
47 robj
*dupStringObject(robj
*o
) {
48 redisAssert(o
->encoding
== REDIS_ENCODING_RAW
);
49 return createStringObject(o
->ptr
,sdslen(o
->ptr
));
52 robj
*createListObject(void) {
53 list
*l
= listCreate();
54 robj
*o
= createObject(REDIS_LIST
,l
);
55 listSetFreeMethod(l
,decrRefCount
);
56 o
->encoding
= REDIS_ENCODING_LINKEDLIST
;
60 robj
*createZiplistObject(void) {
61 unsigned char *zl
= ziplistNew();
62 robj
*o
= createObject(REDIS_LIST
,zl
);
63 o
->encoding
= REDIS_ENCODING_ZIPLIST
;
67 robj
*createSetObject(void) {
68 dict
*d
= dictCreate(&setDictType
,NULL
);
69 robj
*o
= createObject(REDIS_SET
,d
);
70 o
->encoding
= REDIS_ENCODING_HT
;
74 robj
*createIntsetObject(void) {
75 intset
*is
= intsetNew();
76 robj
*o
= createObject(REDIS_SET
,is
);
77 o
->encoding
= REDIS_ENCODING_INTSET
;
81 robj
*createHashObject(void) {
82 /* All the Hashes start as zipmaps. Will be automatically converted
83 * into hash tables if there are enough elements or big elements
85 unsigned char *zm
= zipmapNew();
86 robj
*o
= createObject(REDIS_HASH
,zm
);
87 o
->encoding
= REDIS_ENCODING_ZIPMAP
;
91 robj
*createZsetObject(void) {
92 zset
*zs
= zmalloc(sizeof(*zs
));
95 zs
->dict
= dictCreate(&zsetDictType
,NULL
);
96 zs
->zsl
= zslCreate();
97 o
= createObject(REDIS_ZSET
,zs
);
98 o
->encoding
= REDIS_ENCODING_SKIPLIST
;
102 robj
*createZsetZiplistObject(void) {
103 unsigned char *zl
= ziplistNew();
104 robj
*o
= createObject(REDIS_ZSET
,zl
);
105 o
->encoding
= REDIS_ENCODING_ZIPLIST
;
109 void freeStringObject(robj
*o
) {
110 if (o
->encoding
== REDIS_ENCODING_RAW
) {
115 void freeListObject(robj
*o
) {
116 switch (o
->encoding
) {
117 case REDIS_ENCODING_LINKEDLIST
:
118 listRelease((list
*) o
->ptr
);
120 case REDIS_ENCODING_ZIPLIST
:
124 redisPanic("Unknown list encoding type");
128 void freeSetObject(robj
*o
) {
129 switch (o
->encoding
) {
130 case REDIS_ENCODING_HT
:
131 dictRelease((dict
*) o
->ptr
);
133 case REDIS_ENCODING_INTSET
:
137 redisPanic("Unknown set encoding type");
141 void freeZsetObject(robj
*o
) {
143 switch (o
->encoding
) {
144 case REDIS_ENCODING_SKIPLIST
:
146 dictRelease(zs
->dict
);
150 case REDIS_ENCODING_ZIPLIST
:
154 redisPanic("Unknown sorted set encoding");
158 void freeHashObject(robj
*o
) {
159 switch (o
->encoding
) {
160 case REDIS_ENCODING_HT
:
161 dictRelease((dict
*) o
->ptr
);
163 case REDIS_ENCODING_ZIPMAP
:
167 redisPanic("Unknown hash encoding type");
172 void incrRefCount(robj
*o
) {
176 void decrRefCount(void *obj
) {
179 if (o
->refcount
<= 0) redisPanic("decrRefCount against refcount <= 0");
180 if (o
->refcount
== 1) {
182 case REDIS_STRING
: freeStringObject(o
); break;
183 case REDIS_LIST
: freeListObject(o
); break;
184 case REDIS_SET
: freeSetObject(o
); break;
185 case REDIS_ZSET
: freeZsetObject(o
); break;
186 case REDIS_HASH
: freeHashObject(o
); break;
187 default: redisPanic("Unknown object type"); break;
195 int checkType(redisClient
*c
, robj
*o
, int type
) {
196 if (o
->type
!= type
) {
197 addReply(c
,shared
.wrongtypeerr
);
203 int isObjectRepresentableAsLongLong(robj
*o
, long long *llval
) {
204 redisAssert(o
->type
== REDIS_STRING
);
205 if (o
->encoding
== REDIS_ENCODING_INT
) {
206 if (llval
) *llval
= (long) o
->ptr
;
209 return string2ll(o
->ptr
,sdslen(o
->ptr
),llval
) ? REDIS_OK
: REDIS_ERR
;
213 /* Try to encode a string object in order to save space */
214 robj
*tryObjectEncoding(robj
*o
) {
218 if (o
->encoding
!= REDIS_ENCODING_RAW
)
219 return o
; /* Already encoded */
221 /* It's not safe to encode shared objects: shared objects can be shared
222 * everywhere in the "object space" of Redis. Encoded objects can only
223 * appear as "values" (and not, for instance, as keys) */
224 if (o
->refcount
> 1) return o
;
226 /* Currently we try to encode only strings */
227 redisAssert(o
->type
== REDIS_STRING
);
229 /* Check if we can represent this string as a long integer */
230 if (!string2l(s
,sdslen(s
),&value
)) return o
;
232 /* Ok, this object can be encoded...
234 * Can I use a shared object? Only if the object is inside a given
235 * range and if the back end in use is in-memory. For disk store every
236 * object in memory used as value should be independent.
238 * Note that we also avoid using shared integers when maxmemory is used
239 * because every object needs to have a private LRU field for the LRU
240 * algorithm to work well. */
241 if (server
.maxmemory
== 0 && value
>= 0 && value
< REDIS_SHARED_INTEGERS
) {
243 incrRefCount(shared
.integers
[value
]);
244 return shared
.integers
[value
];
246 o
->encoding
= REDIS_ENCODING_INT
;
248 o
->ptr
= (void*) value
;
253 /* Get a decoded version of an encoded object (returned as a new object).
254 * If the object is already raw-encoded just increment the ref count. */
255 robj
*getDecodedObject(robj
*o
) {
258 if (o
->encoding
== REDIS_ENCODING_RAW
) {
262 if (o
->type
== REDIS_STRING
&& o
->encoding
== REDIS_ENCODING_INT
) {
265 ll2string(buf
,32,(long)o
->ptr
);
266 dec
= createStringObject(buf
,strlen(buf
));
269 redisPanic("Unknown encoding type");
273 /* Compare two string objects via strcmp() or alike.
274 * Note that the objects may be integer-encoded. In such a case we
275 * use ll2string() to get a string representation of the numbers on the stack
276 * and compare the strings, it's much faster than calling getDecodedObject().
278 * Important note: if objects are not integer encoded, but binary-safe strings,
279 * sdscmp() from sds.c will apply memcmp() so this function ca be considered
281 int compareStringObjects(robj
*a
, robj
*b
) {
282 redisAssert(a
->type
== REDIS_STRING
&& b
->type
== REDIS_STRING
);
283 char bufa
[128], bufb
[128], *astr
, *bstr
;
286 if (a
== b
) return 0;
287 if (a
->encoding
!= REDIS_ENCODING_RAW
) {
288 ll2string(bufa
,sizeof(bufa
),(long) a
->ptr
);
294 if (b
->encoding
!= REDIS_ENCODING_RAW
) {
295 ll2string(bufb
,sizeof(bufb
),(long) b
->ptr
);
301 return bothsds
? sdscmp(astr
,bstr
) : strcmp(astr
,bstr
);
304 /* Equal string objects return 1 if the two objects are the same from the
305 * point of view of a string comparison, otherwise 0 is returned. Note that
306 * this function is faster then checking for (compareStringObject(a,b) == 0)
307 * because it can perform some more optimization. */
308 int equalStringObjects(robj
*a
, robj
*b
) {
309 if (a
->encoding
!= REDIS_ENCODING_RAW
&& b
->encoding
!= REDIS_ENCODING_RAW
){
310 return a
->ptr
== b
->ptr
;
312 return compareStringObjects(a
,b
) == 0;
316 size_t stringObjectLen(robj
*o
) {
317 redisAssert(o
->type
== REDIS_STRING
);
318 if (o
->encoding
== REDIS_ENCODING_RAW
) {
319 return sdslen(o
->ptr
);
323 return ll2string(buf
,32,(long)o
->ptr
);
327 int getDoubleFromObject(robj
*o
, double *target
) {
334 redisAssert(o
->type
== REDIS_STRING
);
335 if (o
->encoding
== REDIS_ENCODING_RAW
) {
336 value
= strtod(o
->ptr
, &eptr
);
337 if (eptr
[0] != '\0' || isnan(value
)) return REDIS_ERR
;
338 } else if (o
->encoding
== REDIS_ENCODING_INT
) {
339 value
= (long)o
->ptr
;
341 redisPanic("Unknown string encoding");
349 int getDoubleFromObjectOrReply(redisClient
*c
, robj
*o
, double *target
, const char *msg
) {
351 if (getDoubleFromObject(o
, &value
) != REDIS_OK
) {
353 addReplyError(c
,(char*)msg
);
355 addReplyError(c
,"value is not a double");
364 int getLongLongFromObject(robj
*o
, long long *target
) {
371 redisAssert(o
->type
== REDIS_STRING
);
372 if (o
->encoding
== REDIS_ENCODING_RAW
) {
373 value
= strtoll(o
->ptr
, &eptr
, 10);
374 if (eptr
[0] != '\0') return REDIS_ERR
;
375 if (errno
== ERANGE
&& (value
== LLONG_MIN
|| value
== LLONG_MAX
))
377 } else if (o
->encoding
== REDIS_ENCODING_INT
) {
378 value
= (long)o
->ptr
;
380 redisPanic("Unknown string encoding");
384 if (target
) *target
= value
;
388 int getLongLongFromObjectOrReply(redisClient
*c
, robj
*o
, long long *target
, const char *msg
) {
390 if (getLongLongFromObject(o
, &value
) != REDIS_OK
) {
392 addReplyError(c
,(char*)msg
);
394 addReplyError(c
,"value is not an integer or out of range");
403 int getLongFromObjectOrReply(redisClient
*c
, robj
*o
, long *target
, const char *msg
) {
406 if (getLongLongFromObjectOrReply(c
, o
, &value
, msg
) != REDIS_OK
) return REDIS_ERR
;
407 if (value
< LONG_MIN
|| value
> LONG_MAX
) {
409 addReplyError(c
,(char*)msg
);
411 addReplyError(c
,"value is out of range");
420 char *strEncoding(int encoding
) {
422 case REDIS_ENCODING_RAW
: return "raw";
423 case REDIS_ENCODING_INT
: return "int";
424 case REDIS_ENCODING_HT
: return "hashtable";
425 case REDIS_ENCODING_ZIPMAP
: return "zipmap";
426 case REDIS_ENCODING_LINKEDLIST
: return "linkedlist";
427 case REDIS_ENCODING_ZIPLIST
: return "ziplist";
428 case REDIS_ENCODING_INTSET
: return "intset";
429 case REDIS_ENCODING_SKIPLIST
: return "skiplist";
430 default: return "unknown";
434 /* Given an object returns the min number of seconds the object was never
435 * requested, using an approximated LRU algorithm. */
436 unsigned long estimateObjectIdleTime(robj
*o
) {
437 if (server
.lruclock
>= o
->lru
) {
438 return (server
.lruclock
- o
->lru
) * REDIS_LRU_CLOCK_RESOLUTION
;
440 return ((REDIS_LRU_CLOCK_MAX
- o
->lru
) + server
.lruclock
) *
441 REDIS_LRU_CLOCK_RESOLUTION
;
445 /* This is an helper function for the DEBUG command. We need to lookup keys
446 * without any modification of LRU or other parameters. */
447 robj
*objectCommandLookup(redisClient
*c
, robj
*key
) {
450 if ((de
= dictFind(c
->db
->dict
,key
->ptr
)) == NULL
) return NULL
;
451 return (robj
*) dictGetEntryVal(de
);
454 robj
*objectCommandLookupOrReply(redisClient
*c
, robj
*key
, robj
*reply
) {
455 robj
*o
= objectCommandLookup(c
,key
);
457 if (!o
) addReply(c
, reply
);
461 /* Object command allows to inspect the internals of an Redis Object.
462 * Usage: OBJECT <verb> ... arguments ... */
463 void objectCommand(redisClient
*c
) {
466 if (!strcasecmp(c
->argv
[1]->ptr
,"refcount") && c
->argc
== 3) {
467 if ((o
= objectCommandLookupOrReply(c
,c
->argv
[2],shared
.nullbulk
))
469 addReplyLongLong(c
,o
->refcount
);
470 } else if (!strcasecmp(c
->argv
[1]->ptr
,"encoding") && c
->argc
== 3) {
471 if ((o
= objectCommandLookupOrReply(c
,c
->argv
[2],shared
.nullbulk
))
473 addReplyBulkCString(c
,strEncoding(o
->encoding
));
474 } else if (!strcasecmp(c
->argv
[1]->ptr
,"idletime") && c
->argc
== 3) {
475 if ((o
= objectCommandLookupOrReply(c
,c
->argv
[2],shared
.nullbulk
))
477 addReplyLongLong(c
,estimateObjectIdleTime(o
));
479 addReplyError(c
,"Syntax error. Try OBJECT (refcount|encoding|idletime)");