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