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