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