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