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
&&
35 pthread_equal(pthread_self(),server
.mainthread
)) {
36 incrRefCount(shared
.integers
[value
]);
37 o
= shared
.integers
[value
];
39 if (value
>= LONG_MIN
&& value
<= LONG_MAX
) {
40 o
= createObject(REDIS_STRING
, NULL
);
41 o
->encoding
= REDIS_ENCODING_INT
;
42 o
->ptr
= (void*)((long)value
);
44 o
= createObject(REDIS_STRING
,sdsfromlonglong(value
));
50 robj
*dupStringObject(robj
*o
) {
51 redisAssert(o
->encoding
== REDIS_ENCODING_RAW
);
52 return createStringObject(o
->ptr
,sdslen(o
->ptr
));
55 robj
*createListObject(void) {
56 list
*l
= listCreate();
57 robj
*o
= createObject(REDIS_LIST
,l
);
58 listSetFreeMethod(l
,decrRefCount
);
59 o
->encoding
= REDIS_ENCODING_LINKEDLIST
;
63 robj
*createZiplistObject(void) {
64 unsigned char *zl
= ziplistNew();
65 robj
*o
= createObject(REDIS_LIST
,zl
);
66 o
->encoding
= REDIS_ENCODING_ZIPLIST
;
70 robj
*createSetObject(void) {
71 dict
*d
= dictCreate(&setDictType
,NULL
);
72 robj
*o
= createObject(REDIS_SET
,d
);
73 o
->encoding
= REDIS_ENCODING_HT
;
77 robj
*createIntsetObject(void) {
78 intset
*is
= intsetNew();
79 robj
*o
= createObject(REDIS_SET
,is
);
80 o
->encoding
= REDIS_ENCODING_INTSET
;
84 robj
*createHashObject(void) {
85 /* All the Hashes start as zipmaps. Will be automatically converted
86 * into hash tables if there are enough elements or big elements
88 unsigned char *zm
= zipmapNew();
89 robj
*o
= createObject(REDIS_HASH
,zm
);
90 o
->encoding
= REDIS_ENCODING_ZIPMAP
;
94 robj
*createZsetObject(void) {
95 zset
*zs
= zmalloc(sizeof(*zs
));
96 zs
->dict
= dictCreate(&zsetDictType
,NULL
);
97 zs
->zsl
= zslCreate();
98 return createObject(REDIS_ZSET
,zs
);
101 robj
*createZsetZiplistObject(void) {
102 unsigned char *zl
= ziplistNew();
103 robj
*o
= createObject(REDIS_ZSET
,zl
);
104 o
->encoding
= REDIS_ENCODING_ZIPLIST
;
108 void freeStringObject(robj
*o
) {
109 if (o
->encoding
== REDIS_ENCODING_RAW
) {
114 void freeListObject(robj
*o
) {
115 switch (o
->encoding
) {
116 case REDIS_ENCODING_LINKEDLIST
:
117 listRelease((list
*) o
->ptr
);
119 case REDIS_ENCODING_ZIPLIST
:
123 redisPanic("Unknown list encoding type");
127 void freeSetObject(robj
*o
) {
128 switch (o
->encoding
) {
129 case REDIS_ENCODING_HT
:
130 dictRelease((dict
*) o
->ptr
);
132 case REDIS_ENCODING_INTSET
:
136 redisPanic("Unknown set encoding type");
140 void freeZsetObject(robj
*o
) {
142 switch (o
->encoding
) {
143 case REDIS_ENCODING_RAW
:
145 dictRelease(zs
->dict
);
149 case REDIS_ENCODING_ZIPLIST
:
153 redisPanic("Unknown sorted set encoding");
157 void freeHashObject(robj
*o
) {
158 switch (o
->encoding
) {
159 case REDIS_ENCODING_HT
:
160 dictRelease((dict
*) o
->ptr
);
162 case REDIS_ENCODING_ZIPMAP
:
166 redisPanic("Unknown hash encoding type");
171 void incrRefCount(robj
*o
) {
175 void decrRefCount(void *obj
) {
178 if (o
->refcount
<= 0) redisPanic("decrRefCount against refcount <= 0");
179 if (--(o
->refcount
) == 0) {
181 case REDIS_STRING
: freeStringObject(o
); break;
182 case REDIS_LIST
: freeListObject(o
); break;
183 case REDIS_SET
: freeSetObject(o
); break;
184 case REDIS_ZSET
: freeZsetObject(o
); break;
185 case REDIS_HASH
: freeHashObject(o
); break;
186 default: redisPanic("Unknown object type"); break;
188 o
->ptr
= NULL
; /* defensive programming. We'll see NULL in traces. */
193 int checkType(redisClient
*c
, robj
*o
, int type
) {
194 if (o
->type
!= type
) {
195 addReply(c
,shared
.wrongtypeerr
);
201 /* Try to encode a string object in order to save space */
202 robj
*tryObjectEncoding(robj
*o
) {
206 if (o
->encoding
!= REDIS_ENCODING_RAW
)
207 return o
; /* Already encoded */
209 /* It's not safe to encode shared objects: shared objects can be shared
210 * everywhere in the "object space" of Redis. Encoded objects can only
211 * appear as "values" (and not, for instance, as keys) */
212 if (o
->refcount
> 1) return o
;
214 /* Currently we try to encode only strings */
215 redisAssert(o
->type
== REDIS_STRING
);
217 /* Check if we can represent this string as a long integer */
218 if (isStringRepresentableAsLong(s
,&value
) == REDIS_ERR
) return o
;
220 /* Ok, this object can be encoded...
222 * Can I use a shared object? Only if the object is inside a given
223 * range and if the back end in use is in-memory. For disk store every
224 * object in memory used as value should be independent.
226 * Note that we also avoid using shared integers when maxmemory is used
227 * because every object needs to have a private LRU field for the LRU
228 * algorithm to work well. */
229 if (!server
.ds_enabled
&&
230 server
.maxmemory
== 0 && value
>= 0 && value
< REDIS_SHARED_INTEGERS
&&
231 pthread_equal(pthread_self(),server
.mainthread
))
234 incrRefCount(shared
.integers
[value
]);
235 return shared
.integers
[value
];
237 o
->encoding
= REDIS_ENCODING_INT
;
239 o
->ptr
= (void*) value
;
244 /* Get a decoded version of an encoded object (returned as a new object).
245 * If the object is already raw-encoded just increment the ref count. */
246 robj
*getDecodedObject(robj
*o
) {
249 if (o
->encoding
== REDIS_ENCODING_RAW
) {
253 if (o
->type
== REDIS_STRING
&& o
->encoding
== REDIS_ENCODING_INT
) {
256 ll2string(buf
,32,(long)o
->ptr
);
257 dec
= createStringObject(buf
,strlen(buf
));
260 redisPanic("Unknown encoding type");
264 /* Compare two string objects via strcmp() or alike.
265 * Note that the objects may be integer-encoded. In such a case we
266 * use ll2string() to get a string representation of the numbers on the stack
267 * and compare the strings, it's much faster than calling getDecodedObject().
269 * Important note: if objects are not integer encoded, but binary-safe strings,
270 * sdscmp() from sds.c will apply memcmp() so this function ca be considered
272 int compareStringObjects(robj
*a
, robj
*b
) {
273 redisAssert(a
->type
== REDIS_STRING
&& b
->type
== REDIS_STRING
);
274 char bufa
[128], bufb
[128], *astr
, *bstr
;
277 if (a
== b
) return 0;
278 if (a
->encoding
!= REDIS_ENCODING_RAW
) {
279 ll2string(bufa
,sizeof(bufa
),(long) a
->ptr
);
285 if (b
->encoding
!= REDIS_ENCODING_RAW
) {
286 ll2string(bufb
,sizeof(bufb
),(long) b
->ptr
);
292 return bothsds
? sdscmp(astr
,bstr
) : strcmp(astr
,bstr
);
295 /* Equal string objects return 1 if the two objects are the same from the
296 * point of view of a string comparison, otherwise 0 is returned. Note that
297 * this function is faster then checking for (compareStringObject(a,b) == 0)
298 * because it can perform some more optimization. */
299 int equalStringObjects(robj
*a
, robj
*b
) {
300 if (a
->encoding
!= REDIS_ENCODING_RAW
&& b
->encoding
!= REDIS_ENCODING_RAW
){
301 return a
->ptr
== b
->ptr
;
303 return compareStringObjects(a
,b
) == 0;
307 size_t stringObjectLen(robj
*o
) {
308 redisAssert(o
->type
== REDIS_STRING
);
309 if (o
->encoding
== REDIS_ENCODING_RAW
) {
310 return sdslen(o
->ptr
);
314 return ll2string(buf
,32,(long)o
->ptr
);
318 int getDoubleFromObject(robj
*o
, double *target
) {
325 redisAssert(o
->type
== REDIS_STRING
);
326 if (o
->encoding
== REDIS_ENCODING_RAW
) {
327 value
= strtod(o
->ptr
, &eptr
);
328 if (eptr
[0] != '\0' || isnan(value
)) return REDIS_ERR
;
329 } else if (o
->encoding
== REDIS_ENCODING_INT
) {
330 value
= (long)o
->ptr
;
332 redisPanic("Unknown string encoding");
340 int getDoubleFromObjectOrReply(redisClient
*c
, robj
*o
, double *target
, const char *msg
) {
342 if (getDoubleFromObject(o
, &value
) != REDIS_OK
) {
344 addReplyError(c
,(char*)msg
);
346 addReplyError(c
,"value is not a double");
355 int getLongLongFromObject(robj
*o
, long long *target
) {
362 redisAssert(o
->type
== REDIS_STRING
);
363 if (o
->encoding
== REDIS_ENCODING_RAW
) {
364 value
= strtoll(o
->ptr
, &eptr
, 10);
365 if (eptr
[0] != '\0') return REDIS_ERR
;
366 if (errno
== ERANGE
&& (value
== LLONG_MIN
|| value
== LLONG_MAX
))
368 } else if (o
->encoding
== REDIS_ENCODING_INT
) {
369 value
= (long)o
->ptr
;
371 redisPanic("Unknown string encoding");
375 if (target
) *target
= value
;
379 int getLongLongFromObjectOrReply(redisClient
*c
, robj
*o
, long long *target
, const char *msg
) {
381 if (getLongLongFromObject(o
, &value
) != REDIS_OK
) {
383 addReplyError(c
,(char*)msg
);
385 addReplyError(c
,"value is not an integer or out of range");
394 int getLongFromObjectOrReply(redisClient
*c
, robj
*o
, long *target
, const char *msg
) {
397 if (getLongLongFromObjectOrReply(c
, o
, &value
, msg
) != REDIS_OK
) return REDIS_ERR
;
398 if (value
< LONG_MIN
|| value
> LONG_MAX
) {
400 addReplyError(c
,(char*)msg
);
402 addReplyError(c
,"value is out of range");
411 char *strEncoding(int encoding
) {
413 case REDIS_ENCODING_RAW
: return "raw";
414 case REDIS_ENCODING_INT
: return "int";
415 case REDIS_ENCODING_HT
: return "hashtable";
416 case REDIS_ENCODING_ZIPMAP
: return "zipmap";
417 case REDIS_ENCODING_LINKEDLIST
: return "linkedlist";
418 case REDIS_ENCODING_ZIPLIST
: return "ziplist";
419 case REDIS_ENCODING_INTSET
: return "intset";
420 default: return "unknown";
424 /* Given an object returns the min number of seconds the object was never
425 * requested, using an approximated LRU algorithm. */
426 unsigned long estimateObjectIdleTime(robj
*o
) {
427 if (server
.lruclock
>= o
->lru
) {
428 return (server
.lruclock
- o
->lru
) * REDIS_LRU_CLOCK_RESOLUTION
;
430 return ((REDIS_LRU_CLOCK_MAX
- o
->lru
) + server
.lruclock
) *
431 REDIS_LRU_CLOCK_RESOLUTION
;