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