]> git.saurik.com Git - redis.git/blame - src/object.c
DEBUG should not be flagged as w otherwise we can not call DEBUG DIGEST and other...
[redis.git] / src / object.c
CommitLineData
e2641e09 1#include "redis.h"
673e1fb7 2#include <math.h>
d93f9a86 3#include <ctype.h>
e2641e09 4
5robj *createObject(int type, void *ptr) {
a9b18e54 6 robj *o = zmalloc(sizeof(*o));
e2641e09 7 o->type = type;
8 o->encoding = REDIS_ENCODING_RAW;
9 o->ptr = ptr;
10 o->refcount = 1;
a9b18e54 11
ef59a8bc 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.
15 *
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. */
e2641e09 24 return o;
25}
26
27robj *createStringObject(char *ptr, size_t len) {
28 return createObject(REDIS_STRING,sdsnewlen(ptr,len));
29}
30
31robj *createStringObjectFromLongLong(long long value) {
32 robj *o;
c9d0c362 33 if (value >= 0 && value < REDIS_SHARED_INTEGERS) {
e2641e09 34 incrRefCount(shared.integers[value]);
35 o = shared.integers[value];
36 } else {
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);
41 } else {
42 o = createObject(REDIS_STRING,sdsfromlonglong(value));
43 }
44 }
45 return o;
46}
47
5574b53e 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 */
50robj *createStringObjectFromLongDouble(long double value) {
51 char buf[256];
52 int len;
53
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),"%.17Lg", value);
60 return createStringObject(buf,len);
61}
62
e2641e09 63robj *dupStringObject(robj *o) {
eab0e26e 64 redisAssertWithInfo(NULL,o,o->encoding == REDIS_ENCODING_RAW);
e2641e09 65 return createStringObject(o->ptr,sdslen(o->ptr));
66}
67
68robj *createListObject(void) {
69 list *l = listCreate();
70 robj *o = createObject(REDIS_LIST,l);
71 listSetFreeMethod(l,decrRefCount);
72 o->encoding = REDIS_ENCODING_LINKEDLIST;
73 return o;
74}
75
76robj *createZiplistObject(void) {
77 unsigned char *zl = ziplistNew();
78 robj *o = createObject(REDIS_LIST,zl);
79 o->encoding = REDIS_ENCODING_ZIPLIST;
80 return o;
81}
82
83robj *createSetObject(void) {
84 dict *d = dictCreate(&setDictType,NULL);
96ffb2fe
PN
85 robj *o = createObject(REDIS_SET,d);
86 o->encoding = REDIS_ENCODING_HT;
87 return o;
88}
89
90robj *createIntsetObject(void) {
91 intset *is = intsetNew();
92 robj *o = createObject(REDIS_SET,is);
93 o->encoding = REDIS_ENCODING_INTSET;
94 return o;
e2641e09 95}
96
97robj *createHashObject(void) {
ebd85e9a
PN
98 unsigned char *zl = ziplistNew();
99 robj *o = createObject(REDIS_HASH, zl);
100 o->encoding = REDIS_ENCODING_ZIPLIST;
e2641e09 101 return o;
102}
103
104robj *createZsetObject(void) {
105 zset *zs = zmalloc(sizeof(*zs));
0b7f6d09 106 robj *o;
e2641e09 107
108 zs->dict = dictCreate(&zsetDictType,NULL);
109 zs->zsl = zslCreate();
0b7f6d09 110 o = createObject(REDIS_ZSET,zs);
111 o->encoding = REDIS_ENCODING_SKIPLIST;
112 return o;
e2641e09 113}
114
9e7cee0e
PN
115robj *createZsetZiplistObject(void) {
116 unsigned char *zl = ziplistNew();
117 robj *o = createObject(REDIS_ZSET,zl);
118 o->encoding = REDIS_ENCODING_ZIPLIST;
119 return o;
120}
121
e2641e09 122void freeStringObject(robj *o) {
123 if (o->encoding == REDIS_ENCODING_RAW) {
124 sdsfree(o->ptr);
125 }
126}
127
128void freeListObject(robj *o) {
129 switch (o->encoding) {
130 case REDIS_ENCODING_LINKEDLIST:
131 listRelease((list*) o->ptr);
132 break;
133 case REDIS_ENCODING_ZIPLIST:
134 zfree(o->ptr);
135 break;
136 default:
137 redisPanic("Unknown list encoding type");
138 }
139}
140
141void freeSetObject(robj *o) {
96ffb2fe
PN
142 switch (o->encoding) {
143 case REDIS_ENCODING_HT:
144 dictRelease((dict*) o->ptr);
145 break;
146 case REDIS_ENCODING_INTSET:
147 zfree(o->ptr);
148 break;
149 default:
150 redisPanic("Unknown set encoding type");
151 }
e2641e09 152}
153
154void freeZsetObject(robj *o) {
0f23eb3b
PN
155 zset *zs;
156 switch (o->encoding) {
100ed062 157 case REDIS_ENCODING_SKIPLIST:
0f23eb3b
PN
158 zs = o->ptr;
159 dictRelease(zs->dict);
160 zslFree(zs->zsl);
161 zfree(zs);
162 break;
163 case REDIS_ENCODING_ZIPLIST:
164 zfree(o->ptr);
165 break;
166 default:
167 redisPanic("Unknown sorted set encoding");
168 }
e2641e09 169}
170
171void freeHashObject(robj *o) {
172 switch (o->encoding) {
173 case REDIS_ENCODING_HT:
174 dictRelease((dict*) o->ptr);
175 break;
ebd85e9a 176 case REDIS_ENCODING_ZIPLIST:
e2641e09 177 zfree(o->ptr);
178 break;
179 default:
180 redisPanic("Unknown hash encoding type");
181 break;
182 }
183}
184
185void incrRefCount(robj *o) {
186 o->refcount++;
187}
188
189void decrRefCount(void *obj) {
190 robj *o = obj;
191
e2641e09 192 if (o->refcount <= 0) redisPanic("decrRefCount against refcount <= 0");
936c4ab6 193 if (o->refcount == 1) {
e2641e09 194 switch(o->type) {
195 case REDIS_STRING: freeStringObject(o); break;
196 case REDIS_LIST: freeListObject(o); break;
197 case REDIS_SET: freeSetObject(o); break;
198 case REDIS_ZSET: freeZsetObject(o); break;
199 case REDIS_HASH: freeHashObject(o); break;
200 default: redisPanic("Unknown object type"); break;
201 }
a9b18e54 202 zfree(o);
936c4ab6 203 } else {
204 o->refcount--;
e2641e09 205 }
206}
207
4dd444bb 208/* This function set the ref count to zero without freeing the object.
209 * It is useful in order to pass a new object to functions incrementing
210 * the ref count of the received object. Example:
211 *
212 * functionThatWillIncrementRefCount(resetRefCount(CreateObject(...)));
213 *
214 * Otherwise you need to resort to the less elegant pattern:
215 *
216 * *obj = createObject(...);
217 * functionThatWillIncrementRefCount(obj);
218 * decrRefCount(obj);
219 */
220robj *resetRefCount(robj *obj) {
221 obj->refcount = 0;
222 return obj;
223}
224
e2641e09 225int checkType(redisClient *c, robj *o, int type) {
226 if (o->type != type) {
227 addReply(c,shared.wrongtypeerr);
228 return 1;
229 }
230 return 0;
231}
232
5d081931 233int isObjectRepresentableAsLongLong(robj *o, long long *llval) {
eab0e26e 234 redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
5d081931
PN
235 if (o->encoding == REDIS_ENCODING_INT) {
236 if (llval) *llval = (long) o->ptr;
237 return REDIS_OK;
238 } else {
239 return string2ll(o->ptr,sdslen(o->ptr),llval) ? REDIS_OK : REDIS_ERR;
240 }
241}
242
e2641e09 243/* Try to encode a string object in order to save space */
244robj *tryObjectEncoding(robj *o) {
245 long value;
246 sds s = o->ptr;
247
248 if (o->encoding != REDIS_ENCODING_RAW)
249 return o; /* Already encoded */
250
251 /* It's not safe to encode shared objects: shared objects can be shared
252 * everywhere in the "object space" of Redis. Encoded objects can only
253 * appear as "values" (and not, for instance, as keys) */
254 if (o->refcount > 1) return o;
255
256 /* Currently we try to encode only strings */
eab0e26e 257 redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
e2641e09 258
259 /* Check if we can represent this string as a long integer */
5d081931 260 if (!string2l(s,sdslen(s),&value)) return o;
e2641e09 261
0e5441d8 262 /* Ok, this object can be encoded...
263 *
264 * Can I use a shared object? Only if the object is inside a given
cea8c5cd 265 * range and if the back end in use is in-memory. For disk store every
266 * object in memory used as value should be independent.
13a49af4 267 *
268 * Note that we also avoid using shared integers when maxmemory is used
cea8c5cd 269 * because every object needs to have a private LRU field for the LRU
13a49af4 270 * algorithm to work well. */
c9d0c362 271 if (server.maxmemory == 0 && value >= 0 && value < REDIS_SHARED_INTEGERS) {
e2641e09 272 decrRefCount(o);
273 incrRefCount(shared.integers[value]);
274 return shared.integers[value];
275 } else {
276 o->encoding = REDIS_ENCODING_INT;
277 sdsfree(o->ptr);
278 o->ptr = (void*) value;
279 return o;
280 }
281}
282
283/* Get a decoded version of an encoded object (returned as a new object).
284 * If the object is already raw-encoded just increment the ref count. */
285robj *getDecodedObject(robj *o) {
286 robj *dec;
287
288 if (o->encoding == REDIS_ENCODING_RAW) {
289 incrRefCount(o);
290 return o;
291 }
292 if (o->type == REDIS_STRING && o->encoding == REDIS_ENCODING_INT) {
293 char buf[32];
294
295 ll2string(buf,32,(long)o->ptr);
296 dec = createStringObject(buf,strlen(buf));
297 return dec;
298 } else {
299 redisPanic("Unknown encoding type");
300 }
301}
302
303/* Compare two string objects via strcmp() or alike.
304 * Note that the objects may be integer-encoded. In such a case we
305 * use ll2string() to get a string representation of the numbers on the stack
306 * and compare the strings, it's much faster than calling getDecodedObject().
307 *
308 * Important note: if objects are not integer encoded, but binary-safe strings,
309 * sdscmp() from sds.c will apply memcmp() so this function ca be considered
310 * binary safe. */
311int compareStringObjects(robj *a, robj *b) {
eab0e26e 312 redisAssertWithInfo(NULL,a,a->type == REDIS_STRING && b->type == REDIS_STRING);
e2641e09 313 char bufa[128], bufb[128], *astr, *bstr;
314 int bothsds = 1;
315
316 if (a == b) return 0;
317 if (a->encoding != REDIS_ENCODING_RAW) {
318 ll2string(bufa,sizeof(bufa),(long) a->ptr);
319 astr = bufa;
320 bothsds = 0;
321 } else {
322 astr = a->ptr;
323 }
324 if (b->encoding != REDIS_ENCODING_RAW) {
325 ll2string(bufb,sizeof(bufb),(long) b->ptr);
326 bstr = bufb;
327 bothsds = 0;
328 } else {
329 bstr = b->ptr;
330 }
331 return bothsds ? sdscmp(astr,bstr) : strcmp(astr,bstr);
332}
333
334/* Equal string objects return 1 if the two objects are the same from the
335 * point of view of a string comparison, otherwise 0 is returned. Note that
336 * this function is faster then checking for (compareStringObject(a,b) == 0)
337 * because it can perform some more optimization. */
338int equalStringObjects(robj *a, robj *b) {
339 if (a->encoding != REDIS_ENCODING_RAW && b->encoding != REDIS_ENCODING_RAW){
340 return a->ptr == b->ptr;
341 } else {
342 return compareStringObjects(a,b) == 0;
343 }
344}
345
346size_t stringObjectLen(robj *o) {
eab0e26e 347 redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
e2641e09 348 if (o->encoding == REDIS_ENCODING_RAW) {
349 return sdslen(o->ptr);
350 } else {
351 char buf[32];
352
353 return ll2string(buf,32,(long)o->ptr);
354 }
355}
356
357int getDoubleFromObject(robj *o, double *target) {
358 double value;
359 char *eptr;
360
361 if (o == NULL) {
362 value = 0;
363 } else {
eab0e26e 364 redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
e2641e09 365 if (o->encoding == REDIS_ENCODING_RAW) {
5574b53e 366 errno = 0;
e2641e09 367 value = strtod(o->ptr, &eptr);
d93f9a86 368 if (isspace(((char*)o->ptr)[0]) || eptr[0] != '\0' ||
369 errno == ERANGE || isnan(value))
5574b53e 370 return REDIS_ERR;
e2641e09 371 } else if (o->encoding == REDIS_ENCODING_INT) {
372 value = (long)o->ptr;
373 } else {
374 redisPanic("Unknown string encoding");
375 }
376 }
e2641e09 377 *target = value;
378 return REDIS_OK;
379}
380
381int getDoubleFromObjectOrReply(redisClient *c, robj *o, double *target, const char *msg) {
382 double value;
383 if (getDoubleFromObject(o, &value) != REDIS_OK) {
384 if (msg != NULL) {
3ab20376 385 addReplyError(c,(char*)msg);
e2641e09 386 } else {
5574b53e 387 addReplyError(c,"value is not a valid float");
388 }
389 return REDIS_ERR;
390 }
5574b53e 391 *target = value;
392 return REDIS_OK;
393}
394
395int getLongDoubleFromObject(robj *o, long double *target) {
396 long double value;
397 char *eptr;
398
399 if (o == NULL) {
400 value = 0;
401 } else {
402 redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
403 if (o->encoding == REDIS_ENCODING_RAW) {
404 errno = 0;
405 value = strtold(o->ptr, &eptr);
d93f9a86 406 if (isspace(((char*)o->ptr)[0]) || eptr[0] != '\0' ||
407 errno == ERANGE || isnan(value))
5574b53e 408 return REDIS_ERR;
409 } else if (o->encoding == REDIS_ENCODING_INT) {
410 value = (long)o->ptr;
411 } else {
412 redisPanic("Unknown string encoding");
413 }
414 }
415 *target = value;
416 return REDIS_OK;
417}
418
419int getLongDoubleFromObjectOrReply(redisClient *c, robj *o, long double *target, const char *msg) {
420 long double value;
421 if (getLongDoubleFromObject(o, &value) != REDIS_OK) {
422 if (msg != NULL) {
423 addReplyError(c,(char*)msg);
424 } else {
425 addReplyError(c,"value is not a valid float");
e2641e09 426 }
427 return REDIS_ERR;
428 }
e2641e09 429 *target = value;
430 return REDIS_OK;
431}
432
433int getLongLongFromObject(robj *o, long long *target) {
434 long long value;
435 char *eptr;
436
437 if (o == NULL) {
438 value = 0;
439 } else {
eab0e26e 440 redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
e2641e09 441 if (o->encoding == REDIS_ENCODING_RAW) {
d93f9a86 442 errno = 0;
e2641e09 443 value = strtoll(o->ptr, &eptr, 10);
d93f9a86 444 if (isspace(((char*)o->ptr)[0]) || eptr[0] != '\0' ||
445 errno == ERANGE)
c91abdcd 446 return REDIS_ERR;
e2641e09 447 } else if (o->encoding == REDIS_ENCODING_INT) {
448 value = (long)o->ptr;
449 } else {
450 redisPanic("Unknown string encoding");
451 }
452 }
96ffb2fe 453 if (target) *target = value;
e2641e09 454 return REDIS_OK;
455}
456
457int getLongLongFromObjectOrReply(redisClient *c, robj *o, long long *target, const char *msg) {
458 long long value;
459 if (getLongLongFromObject(o, &value) != REDIS_OK) {
460 if (msg != NULL) {
3ab20376 461 addReplyError(c,(char*)msg);
e2641e09 462 } else {
3ab20376 463 addReplyError(c,"value is not an integer or out of range");
e2641e09 464 }
465 return REDIS_ERR;
466 }
e2641e09 467 *target = value;
468 return REDIS_OK;
469}
470
471int getLongFromObjectOrReply(redisClient *c, robj *o, long *target, const char *msg) {
472 long long value;
473
474 if (getLongLongFromObjectOrReply(c, o, &value, msg) != REDIS_OK) return REDIS_ERR;
475 if (value < LONG_MIN || value > LONG_MAX) {
476 if (msg != NULL) {
3ab20376 477 addReplyError(c,(char*)msg);
e2641e09 478 } else {
3ab20376 479 addReplyError(c,"value is out of range");
e2641e09 480 }
481 return REDIS_ERR;
482 }
e2641e09 483 *target = value;
484 return REDIS_OK;
485}
486
487char *strEncoding(int encoding) {
488 switch(encoding) {
489 case REDIS_ENCODING_RAW: return "raw";
490 case REDIS_ENCODING_INT: return "int";
491 case REDIS_ENCODING_HT: return "hashtable";
e2641e09 492 case REDIS_ENCODING_LINKEDLIST: return "linkedlist";
493 case REDIS_ENCODING_ZIPLIST: return "ziplist";
96ffb2fe 494 case REDIS_ENCODING_INTSET: return "intset";
0b7f6d09 495 case REDIS_ENCODING_SKIPLIST: return "skiplist";
e2641e09 496 default: return "unknown";
497 }
498}
ef59a8bc 499
500/* Given an object returns the min number of seconds the object was never
501 * requested, using an approximated LRU algorithm. */
502unsigned long estimateObjectIdleTime(robj *o) {
503 if (server.lruclock >= o->lru) {
165346ca 504 return (server.lruclock - o->lru) * REDIS_LRU_CLOCK_RESOLUTION;
ef59a8bc 505 } else {
165346ca 506 return ((REDIS_LRU_CLOCK_MAX - o->lru) + server.lruclock) *
507 REDIS_LRU_CLOCK_RESOLUTION;
ef59a8bc 508 }
509}
ece74202 510
511/* This is an helper function for the DEBUG command. We need to lookup keys
512 * without any modification of LRU or other parameters. */
513robj *objectCommandLookup(redisClient *c, robj *key) {
514 dictEntry *de;
515
516 if ((de = dictFind(c->db->dict,key->ptr)) == NULL) return NULL;
c0ba9ebe 517 return (robj*) dictGetVal(de);
ece74202 518}
519
520robj *objectCommandLookupOrReply(redisClient *c, robj *key, robj *reply) {
521 robj *o = objectCommandLookup(c,key);
522
523 if (!o) addReply(c, reply);
524 return o;
525}
526
527/* Object command allows to inspect the internals of an Redis Object.
528 * Usage: OBJECT <verb> ... arguments ... */
529void objectCommand(redisClient *c) {
530 robj *o;
531
532 if (!strcasecmp(c->argv[1]->ptr,"refcount") && c->argc == 3) {
533 if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk))
534 == NULL) return;
535 addReplyLongLong(c,o->refcount);
536 } else if (!strcasecmp(c->argv[1]->ptr,"encoding") && c->argc == 3) {
537 if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk))
538 == NULL) return;
539 addReplyBulkCString(c,strEncoding(o->encoding));
540 } else if (!strcasecmp(c->argv[1]->ptr,"idletime") && c->argc == 3) {
541 if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk))
542 == NULL) return;
543 addReplyLongLong(c,estimateObjectIdleTime(o));
544 } else {
545 addReplyError(c,"Syntax error. Try OBJECT (refcount|encoding|idletime)");
546 }
547}
548