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