1 #include "redis.h" 2 #include <pthread.h> 3 #include <math.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 !server.ds_enabled && 35 pthread_equal(pthread_self(),server.mainthread)) { 36 incrRefCount(shared.integers[value]); 37 o = shared.integers[value]; 38 } else { 39 if (value >= LONG_MIN && value <= LONG_MAX) { 40 o = createObject(REDIS_STRING, NULL); 41 o->encoding = REDIS_ENCODING_INT; 42 o->ptr = (void*)((long)value); 43 } else { 44 o = createObject(REDIS_STRING,sdsfromlonglong(value)); 45 } 46 } 47 return o; 48 } 49 50 robj *dupStringObject(robj *o) { 51 redisAssert(o->encoding == REDIS_ENCODING_RAW); 52 return createStringObject(o->ptr,sdslen(o->ptr)); 53 } 54 55 robj *createListObject(void) { 56 list *l = listCreate(); 57 robj *o = createObject(REDIS_LIST,l); 58 listSetFreeMethod(l,decrRefCount); 59 o->encoding = REDIS_ENCODING_LINKEDLIST; 60 return o; 61 } 62 63 robj *createZiplistObject(void) { 64 unsigned char *zl = ziplistNew(); 65 robj *o = createObject(REDIS_LIST,zl); 66 o->encoding = REDIS_ENCODING_ZIPLIST; 67 return o; 68 } 69 70 robj *createSetObject(void) { 71 dict *d = dictCreate(&setDictType,NULL); 72 robj *o = createObject(REDIS_SET,d); 73 o->encoding = REDIS_ENCODING_HT; 74 return o; 75 } 76 77 robj *createIntsetObject(void) { 78 intset *is = intsetNew(); 79 robj *o = createObject(REDIS_SET,is); 80 o->encoding = REDIS_ENCODING_INTSET; 81 return o; 82 } 83 84 robj *createHashObject(void) { 85 /* All the Hashes start as zipmaps. Will be automatically converted 86 * into hash tables if there are enough elements or big elements 87 * inside. */ 88 unsigned char *zm = zipmapNew(); 89 robj *o = createObject(REDIS_HASH,zm); 90 o->encoding = REDIS_ENCODING_ZIPMAP; 91 return o; 92 } 93 94 robj *createZsetObject(void) { 95 zset *zs = zmalloc(sizeof(*zs)); 96 97 zs->dict = dictCreate(&zsetDictType,NULL); 98 zs->zsl = zslCreate(); 99 return createObject(REDIS_ZSET,zs); 100 } 101 102 void freeStringObject(robj *o) { 103 if (o->encoding == REDIS_ENCODING_RAW) { 104 sdsfree(o->ptr); 105 } 106 } 107 108 void freeListObject(robj *o) { 109 switch (o->encoding) { 110 case REDIS_ENCODING_LINKEDLIST: 111 listRelease((list*) o->ptr); 112 break; 113 case REDIS_ENCODING_ZIPLIST: 114 zfree(o->ptr); 115 break; 116 default: 117 redisPanic("Unknown list encoding type"); 118 } 119 } 120 121 void freeSetObject(robj *o) { 122 switch (o->encoding) { 123 case REDIS_ENCODING_HT: 124 dictRelease((dict*) o->ptr); 125 break; 126 case REDIS_ENCODING_INTSET: 127 zfree(o->ptr); 128 break; 129 default: 130 redisPanic("Unknown set encoding type"); 131 } 132 } 133 134 void freeZsetObject(robj *o) { 135 zset *zs = o->ptr; 136 137 dictRelease(zs->dict); 138 zslFree(zs->zsl); 139 zfree(zs); 140 } 141 142 void freeHashObject(robj *o) { 143 switch (o->encoding) { 144 case REDIS_ENCODING_HT: 145 dictRelease((dict*) o->ptr); 146 break; 147 case REDIS_ENCODING_ZIPMAP: 148 zfree(o->ptr); 149 break; 150 default: 151 redisPanic("Unknown hash encoding type"); 152 break; 153 } 154 } 155 156 void incrRefCount(robj *o) { 157 o->refcount++; 158 } 159 160 void decrRefCount(void *obj) { 161 robj *o = obj; 162 163 if (o->refcount <= 0) redisPanic("decrRefCount against refcount <= 0"); 164 if (--(o->refcount) == 0) { 165 switch(o->type) { 166 case REDIS_STRING: freeStringObject(o); break; 167 case REDIS_LIST: freeListObject(o); break; 168 case REDIS_SET: freeSetObject(o); break; 169 case REDIS_ZSET: freeZsetObject(o); break; 170 case REDIS_HASH: freeHashObject(o); break; 171 default: redisPanic("Unknown object type"); break; 172 } 173 o->ptr = NULL; /* defensive programming. We'll see NULL in traces. */ 174 zfree(o); 175 } 176 } 177 178 int checkType(redisClient *c, robj *o, int type) { 179 if (o->type != type) { 180 addReply(c,shared.wrongtypeerr); 181 return 1; 182 } 183 return 0; 184 } 185 186 /* Try to encode a string object in order to save space */ 187 robj *tryObjectEncoding(robj *o) { 188 long value; 189 sds s = o->ptr; 190 191 if (o->encoding != REDIS_ENCODING_RAW) 192 return o; /* Already encoded */ 193 194 /* It's not safe to encode shared objects: shared objects can be shared 195 * everywhere in the "object space" of Redis. Encoded objects can only 196 * appear as "values" (and not, for instance, as keys) */ 197 if (o->refcount > 1) return o; 198 199 /* Currently we try to encode only strings */ 200 redisAssert(o->type == REDIS_STRING); 201 202 /* Check if we can represent this string as a long integer */ 203 if (isStringRepresentableAsLong(s,&value) == REDIS_ERR) return o; 204 205 /* Ok, this object can be encoded... 206 * 207 * Can I use a shared object? Only if the object is inside a given 208 * range and if the back end in use is in-memory. For disk store every 209 * object in memory used as value should be independent. 210 * 211 * Note that we also avoid using shared integers when maxmemory is used 212 * because every object needs to have a private LRU field for the LRU 213 * algorithm to work well. */ 214 if (!server.ds_enabled && 215 server.maxmemory == 0 && value >= 0 && value < REDIS_SHARED_INTEGERS && 216 pthread_equal(pthread_self(),server.mainthread)) 217 { 218 decrRefCount(o); 219 incrRefCount(shared.integers[value]); 220 return shared.integers[value]; 221 } else { 222 o->encoding = REDIS_ENCODING_INT; 223 sdsfree(o->ptr); 224 o->ptr = (void*) value; 225 return o; 226 } 227 } 228 229 /* Get a decoded version of an encoded object (returned as a new object). 230 * If the object is already raw-encoded just increment the ref count. */ 231 robj *getDecodedObject(robj *o) { 232 robj *dec; 233 234 if (o->encoding == REDIS_ENCODING_RAW) { 235 incrRefCount(o); 236 return o; 237 } 238 if (o->type == REDIS_STRING && o->encoding == REDIS_ENCODING_INT) { 239 char buf[32]; 240 241 ll2string(buf,32,(long)o->ptr); 242 dec = createStringObject(buf,strlen(buf)); 243 return dec; 244 } else { 245 redisPanic("Unknown encoding type"); 246 } 247 } 248 249 /* Compare two string objects via strcmp() or alike. 250 * Note that the objects may be integer-encoded. In such a case we 251 * use ll2string() to get a string representation of the numbers on the stack 252 * and compare the strings, it's much faster than calling getDecodedObject(). 253 * 254 * Important note: if objects are not integer encoded, but binary-safe strings, 255 * sdscmp() from sds.c will apply memcmp() so this function ca be considered 256 * binary safe. */ 257 int compareStringObjects(robj *a, robj *b) { 258 redisAssert(a->type == REDIS_STRING && b->type == REDIS_STRING); 259 char bufa[128], bufb[128], *astr, *bstr; 260 int bothsds = 1; 261 262 if (a == b) return 0; 263 if (a->encoding != REDIS_ENCODING_RAW) { 264 ll2string(bufa,sizeof(bufa),(long) a->ptr); 265 astr = bufa; 266 bothsds = 0; 267 } else { 268 astr = a->ptr; 269 } 270 if (b->encoding != REDIS_ENCODING_RAW) { 271 ll2string(bufb,sizeof(bufb),(long) b->ptr); 272 bstr = bufb; 273 bothsds = 0; 274 } else { 275 bstr = b->ptr; 276 } 277 return bothsds ? sdscmp(astr,bstr) : strcmp(astr,bstr); 278 } 279 280 /* Equal string objects return 1 if the two objects are the same from the 281 * point of view of a string comparison, otherwise 0 is returned. Note that 282 * this function is faster then checking for (compareStringObject(a,b) == 0) 283 * because it can perform some more optimization. */ 284 int equalStringObjects(robj *a, robj *b) { 285 if (a->encoding != REDIS_ENCODING_RAW && b->encoding != REDIS_ENCODING_RAW){ 286 return a->ptr == b->ptr; 287 } else { 288 return compareStringObjects(a,b) == 0; 289 } 290 } 291 292 size_t stringObjectLen(robj *o) { 293 redisAssert(o->type == REDIS_STRING); 294 if (o->encoding == REDIS_ENCODING_RAW) { 295 return sdslen(o->ptr); 296 } else { 297 char buf[32]; 298 299 return ll2string(buf,32,(long)o->ptr); 300 } 301 } 302 303 int getDoubleFromObject(robj *o, double *target) { 304 double value; 305 char *eptr; 306 307 if (o == NULL) { 308 value = 0; 309 } else { 310 redisAssert(o->type == REDIS_STRING); 311 if (o->encoding == REDIS_ENCODING_RAW) { 312 value = strtod(o->ptr, &eptr); 313 if (eptr[0] != '\0' || isnan(value)) return REDIS_ERR; 314 } else if (o->encoding == REDIS_ENCODING_INT) { 315 value = (long)o->ptr; 316 } else { 317 redisPanic("Unknown string encoding"); 318 } 319 } 320 321 *target = value; 322 return REDIS_OK; 323 } 324 325 int getDoubleFromObjectOrReply(redisClient *c, robj *o, double *target, const char *msg) { 326 double value; 327 if (getDoubleFromObject(o, &value) != REDIS_OK) { 328 if (msg != NULL) { 329 addReplyError(c,(char*)msg); 330 } else { 331 addReplyError(c,"value is not a double"); 332 } 333 return REDIS_ERR; 334 } 335 336 *target = value; 337 return REDIS_OK; 338 } 339 340 int getLongLongFromObject(robj *o, long long *target) { 341 long long value; 342 char *eptr; 343 344 if (o == NULL) { 345 value = 0; 346 } else { 347 redisAssert(o->type == REDIS_STRING); 348 if (o->encoding == REDIS_ENCODING_RAW) { 349 value = strtoll(o->ptr, &eptr, 10); 350 if (eptr[0] != '\0') return REDIS_ERR; 351 if (errno == ERANGE && (value == LLONG_MIN || value == LLONG_MAX)) 352 return REDIS_ERR; 353 } else if (o->encoding == REDIS_ENCODING_INT) { 354 value = (long)o->ptr; 355 } else { 356 redisPanic("Unknown string encoding"); 357 } 358 } 359 360 if (target) *target = value; 361 return REDIS_OK; 362 } 363 364 int getLongLongFromObjectOrReply(redisClient *c, robj *o, long long *target, const char *msg) { 365 long long value; 366 if (getLongLongFromObject(o, &value) != REDIS_OK) { 367 if (msg != NULL) { 368 addReplyError(c,(char*)msg); 369 } else { 370 addReplyError(c,"value is not an integer or out of range"); 371 } 372 return REDIS_ERR; 373 } 374 375 *target = value; 376 return REDIS_OK; 377 } 378 379 int getLongFromObjectOrReply(redisClient *c, robj *o, long *target, const char *msg) { 380 long long value; 381 382 if (getLongLongFromObjectOrReply(c, o, &value, msg) != REDIS_OK) return REDIS_ERR; 383 if (value < LONG_MIN || value > LONG_MAX) { 384 if (msg != NULL) { 385 addReplyError(c,(char*)msg); 386 } else { 387 addReplyError(c,"value is out of range"); 388 } 389 return REDIS_ERR; 390 } 391 392 *target = value; 393 return REDIS_OK; 394 } 395 396 char *strEncoding(int encoding) { 397 switch(encoding) { 398 case REDIS_ENCODING_RAW: return "raw"; 399 case REDIS_ENCODING_INT: return "int"; 400 case REDIS_ENCODING_HT: return "hashtable"; 401 case REDIS_ENCODING_ZIPMAP: return "zipmap"; 402 case REDIS_ENCODING_LINKEDLIST: return "linkedlist"; 403 case REDIS_ENCODING_ZIPLIST: return "ziplist"; 404 case REDIS_ENCODING_INTSET: return "intset"; 405 default: return "unknown"; 406 } 407 } 408 409 /* Given an object returns the min number of seconds the object was never 410 * requested, using an approximated LRU algorithm. */ 411 unsigned long estimateObjectIdleTime(robj *o) { 412 if (server.lruclock >= o->lru) { 413 return (server.lruclock - o->lru) * REDIS_LRU_CLOCK_RESOLUTION; 414 } else { 415 return ((REDIS_LRU_CLOCK_MAX - o->lru) + server.lruclock) * 416 REDIS_LRU_CLOCK_RESOLUTION; 417 } 418 } 419