这里主要就是对象的转换,没啥具体复杂的逻辑。
在看源码时,我们需要掌握这些转换到底做了什么事情,而不需要去看每个转化的细化步骤。
- /* Create a string object with EMBSTR encoding if it is smaller than
- * OBJ_ENCODING_EMBSTR_SIZE_LIMIT, otherwise the RAW encoding is
- * used.
- *
- * The current limit of 44 is chosen so that the biggest string object
- * we allocate as EMBSTR will still fit into the 64 byte arena of jemalloc. */
- #define OBJ_ENCODING_EMBSTR_SIZE_LIMIT 44
- robj *createStringObject(const char *ptr, size_t len) {
- if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT)
- return createEmbeddedStringObject(ptr,len);
- else
- return createRawStringObject(ptr,len);
- }
-
- /* Same as CreateRawStringObject, can return NULL if allocation fails */
- robj *tryCreateRawStringObject(const char *ptr, size_t len) {
- sds str = sdstrynewlen(ptr,len);
- if (!str) return NULL;
- return createObject(OBJ_STRING, str);
- }
-
- /* Same as createStringObject, can return NULL if allocation fails */
- robj *tryCreateStringObject(const char *ptr, size_t len) {
- if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT)
- return createEmbeddedStringObject(ptr,len);
- else
- return tryCreateRawStringObject(ptr,len);
- }
-
- /* Create a string object from a long long value. When possible returns a
- * shared integer object, or at least an integer encoded one.
- *
- * If valueobj is non zero, the function avoids returning a shared
- * integer, because the object is going to be used as value in the Redis key
- * space (for instance when the INCR command is used), so we want LFU/LRU
- * values specific for each key. */
- robj *createStringObjectFromLongLongWithOptions(long long value, int valueobj) {
- robj *o;
-
- if (server.maxmemory == 0 ||
- !(server.maxmemory_policy & MAXMEMORY_FLAG_NO_SHARED_INTEGERS))
- {
- /* If the maxmemory policy permits, we can still return shared integers
- * even if valueobj is true. */
- valueobj = 0;
- }
-
- if (value >= 0 && value < OBJ_SHARED_INTEGERS && valueobj == 0) {
- incrRefCount(shared.integers[value]);
- o = shared.integers[value];
- } else {
- if (value >= LONG_MIN && value <= LONG_MAX) {
- o = createObject(OBJ_STRING, NULL);
- o->encoding = OBJ_ENCODING_INT;
- o->ptr = (void*)((long)value);
- } else {
- o = createObject(OBJ_STRING,sdsfromlonglong(value));
- }
- }
- return o;
- }
-
- /* Wrapper for createStringObjectFromLongLongWithOptions() always demanding
- * to create a shared object if possible. */
- robj *createStringObjectFromLongLong(long long value) {
- return createStringObjectFromLongLongWithOptions(value,0);
- }
-
- /* Wrapper for createStringObjectFromLongLongWithOptions() avoiding a shared
- * object when LFU/LRU info are needed, that is, when the object is used
- * as a value in the key space, and Redis is configured to evict based on
- * LFU/LRU. */
- robj *createStringObjectFromLongLongForValue(long long value) {
- return createStringObjectFromLongLongWithOptions(value,1);
- }
-
- /* Create a string object from a long double. If humanfriendly is non-zero
- * it does not use exponential format and trims trailing zeroes at the end,
- * however this results in loss of precision. Otherwise exp format is used
- * and the output of snprintf() is not modified.
- *
- * The 'humanfriendly' option is used for INCRBYFLOAT and HINCRBYFLOAT. */
- robj *createStringObjectFromLongDouble(long double value, int humanfriendly) {
- char buf[MAX_LONG_DOUBLE_CHARS];
- int len = ld2string(buf,sizeof(buf),value,humanfriendly? LD_STR_HUMAN: LD_STR_AUTO);
- return createStringObject(buf,len);
- }
-
- /* Duplicate a string object, with the guarantee that the returned object
- * has the same encoding as the original one.
- *
- * This function also guarantees that duplicating a small integer object
- * (or a string object that contains a representation of a small integer)
- * will always result in a fresh object that is unshared (refcount == 1).
- *
- * The resulting object always has refcount set to 1. */
- robj *dupStringObject(const robj *o) {
- robj *d;
-
- serverAssert(o->type == OBJ_STRING);
-
- switch(o->encoding) {
- case OBJ_ENCODING_RAW:
- return createRawStringObject(o->ptr,sdslen(o->ptr));
- case OBJ_ENCODING_EMBSTR:
- return createEmbeddedStringObject(o->ptr,sdslen(o->ptr));
- case OBJ_ENCODING_INT:
- d = createObject(OBJ_STRING, NULL);
- d->encoding = OBJ_ENCODING_INT;
- d->ptr = o->ptr;
- return d;
- default:
- serverPanic("Wrong encoding.");
- break;
- }
- }
-
- robj *createQuicklistObject(void) {
- quicklist *l = quicklistCreate();
- robj *o = createObject(OBJ_LIST,l);
- o->encoding = OBJ_ENCODING_QUICKLIST;
- return o;
- }
-
- robj *createZiplistObject(void) {
- unsigned char *zl = ziplistNew();
- robj *o = createObject(OBJ_LIST,zl);
- o->encoding = OBJ_ENCODING_ZIPLIST;
- return o;
- }
-
- robj *createSetObject(void) {
- dict *d = dictCreate(&setDictType,NULL);
- robj *o = createObject(OBJ_SET,d);
- o->encoding = OBJ_ENCODING_HT;
- return o;
- }
-
- robj *createIntsetObject(void) {
- intset *is = intsetNew();
- robj *o = createObject(OBJ_SET,is);
- o->encoding = OBJ_ENCODING_INTSET;
- return o;
- }
-
- robj *createHashObject(void) {
- unsigned char *zl = ziplistNew();
- robj *o = createObject(OBJ_HASH, zl);
- o->encoding = OBJ_ENCODING_ZIPLIST;
- return o;
- }
-
- robj *createZsetObject(void) {
- zset *zs = zmalloc(sizeof(*zs));
- robj *o;
-
- zs->dict = dictCreate(&zsetDictType,NULL);
- zs->zsl = zslCreate();
- o = createObject(OBJ_ZSET,zs);
- o->encoding = OBJ_ENCODING_SKIPLIST;
- return o;
- }
-
- robj *createZsetZiplistObject(void) {
- unsigned char *zl = ziplistNew();
- robj *o = createObject(OBJ_ZSET,zl);
- o->encoding = OBJ_ENCODING_ZIPLIST;
- return o;
- }
-
- robj *createStreamObject(void) {
- stream *s = streamNew();
- robj *o = createObject(OBJ_STREAM,s);
- o->encoding = OBJ_ENCODING_STREAM;
- return o;
- }
-
- robj *createModuleObject(moduleType *mt, void *value) {
- moduleValue *mv = zmalloc(sizeof(*mv));
- mv->type = mt;
- mv->value = value;
- return createObject(OBJ_MODULE,mv);
- }
-
- void freeStringObject(robj *o) {
- if (o->encoding == OBJ_ENCODING_RAW) {
- sdsfree(o->ptr);
- }
- }
-
- void freeListObject(robj *o) {
- if (o->encoding == OBJ_ENCODING_QUICKLIST) {
- quicklistRelease(o->ptr);
- } else {
- serverPanic("Unknown list encoding type");
- }
- }
-
- void freeSetObject(robj *o) {
- switch (o->encoding) {
- case OBJ_ENCODING_HT:
- dictRelease((dict*) o->ptr);
- break;
- case OBJ_ENCODING_INTSET:
- zfree(o->ptr);
- break;
- default:
- serverPanic("Unknown set encoding type");
- }
- }
-
- void freeZsetObject(robj *o) {
- zset *zs;
- switch (o->encoding) {
- case OBJ_ENCODING_SKIPLIST:
- zs = o->ptr;
- dictRelease(zs->dict);
- zslFree(zs->zsl);
- zfree(zs);
- break;
- case OBJ_ENCODING_ZIPLIST:
- zfree(o->ptr);
- break;
- default:
- serverPanic("Unknown sorted set encoding");
- }
- }
-
- void freeHashObject(robj *o) {
- switch (o->encoding) {
- case OBJ_ENCODING_HT:
- dictRelease((dict*) o->ptr);
- break;
- case OBJ_ENCODING_ZIPLIST:
- zfree(o->ptr);
- break;
- default:
- serverPanic("Unknown hash encoding type");
- break;
- }
- }
-
- void freeModuleObject(robj *o) {
- moduleValue *mv = o->ptr;
- mv->type->free(mv->value);
- zfree(mv);
- }
-
- void freeStreamObject(robj *o) {
- freeStream(o->ptr);
- }
-
- void incrRefCount(robj *o) {
- if (o->refcount < OBJ_FIRST_SPECIAL_REFCOUNT) {
- o->refcount++;
- } else {
- if (o->refcount == OBJ_SHARED_REFCOUNT) {
- /* Nothing to do: this refcount is immutable. */
- } else if (o->refcount == OBJ_STATIC_REFCOUNT) {
- serverPanic("You tried to retain an object allocated in the stack");
- }
- }
- }
-
- void decrRefCount(robj *o) {
- if (o->refcount == 1) {
- switch(o->type) {
- case OBJ_STRING: freeStringObject(o); break;
- case OBJ_LIST: freeListObject(o); break;
- case OBJ_SET: freeSetObject(o); break;
- case OBJ_ZSET: freeZsetObject(o); break;
- case OBJ_HASH: freeHashObject(o); break;
- case OBJ_MODULE: freeModuleObject(o); break;
- case OBJ_STREAM: freeStreamObject(o); break;
- default: serverPanic("Unknown object type"); break;
- }
- zfree(o);
- } else {
- if (o->refcount <= 0) serverPanic("decrRefCount against refcount <= 0");
- if (o->refcount != OBJ_SHARED_REFCOUNT) o->refcount--;
- }
- }
-
- /* This variant of decrRefCount() gets its argument as void, and is useful
- * as free method in data structures that expect a 'void free_object(void*)'
- * prototype for the free method. */
- void decrRefCountVoid(void *o) {
- decrRefCount(o);
- }
-
- int checkType(client *c, robj *o, int type) {
- /* A NULL is considered an empty key */
- if (o && o->type != type) {
- addReplyErrorObject(c,shared.wrongtypeerr);
- return 1;
- }
- return 0;
- }
-
- int isSdsRepresentableAsLongLong(sds s, long long *llval) {
- return string2ll(s,sdslen(s),llval) ? C_OK : C_ERR;
- }
-
- int isObjectRepresentableAsLongLong(robj *o, long long *llval) {
- serverAssertWithInfo(NULL,o,o->type == OBJ_STRING);
- if (o->encoding == OBJ_ENCODING_INT) {
- if (llval) *llval = (long) o->ptr;
- return C_OK;
- } else {
- return isSdsRepresentableAsLongLong(o->ptr,llval);
- }
- }
-
- /* Optimize the SDS string inside the string object to require little space,
- * in case there is more than 10% of free space at the end of the SDS
- * string. This happens because SDS strings tend to overallocate to avoid
- * wasting too much time in allocations when appending to the string. */
- void trimStringObjectIfNeeded(robj *o) {
- if (o->encoding == OBJ_ENCODING_RAW &&
- sdsavail(o->ptr) > sdslen(o->ptr)/10)
- {
- o->ptr = sdsRemoveFreeSpace(o->ptr);
- }
- }
-
- /* Try to encode a string object in order to save space */
- robj *tryObjectEncoding(robj *o) {
- long value;
- sds s = o->ptr;
- size_t len;
-
- /* Make sure this is a string object, the only type we encode
- * in this function. Other types use encoded memory efficient
- * representations but are handled by the commands implementing
- * the type. */
- serverAssertWithInfo(NULL,o,o->type == OBJ_STRING);
-
- /* We try some specialized encoding only for objects that are
- * RAW or EMBSTR encoded, in other words objects that are still
- * in represented by an actually array of chars. */
- if (!sdsEncodedObject(o)) return o;
-
- /* It's not safe to encode shared objects: shared objects can be shared
- * everywhere in the "object space" of Redis and may end in places where
- * they are not handled. We handle them only as values in the keyspace. */
- if (o->refcount > 1) return o;
-
- /* Check if we can represent this string as a long integer.
- * Note that we are sure that a string larger than 20 chars is not
- * representable as a 32 nor 64 bit integer. */
- len = sdslen(s);
- if (len <= 20 && string2l(s,len,&value)) {
- /* This object is encodable as a long. Try to use a shared object.
- * Note that we avoid using shared integers when maxmemory is used
- * because every object needs to have a private LRU field for the LRU
- * algorithm to work well. */
- if ((server.maxmemory == 0 ||
- !(server.maxmemory_policy & MAXMEMORY_FLAG_NO_SHARED_INTEGERS)) &&
- value >= 0 &&
- value < OBJ_SHARED_INTEGERS)
- {
- decrRefCount(o);
- incrRefCount(shared.integers[value]);
- return shared.integers[value];
- } else {
- if (o->encoding == OBJ_ENCODING_RAW) {
- sdsfree(o->ptr);
- o->encoding = OBJ_ENCODING_INT;
- o->ptr = (void*) value;
- return o;
- } else if (o->encoding == OBJ_ENCODING_EMBSTR) {
- decrRefCount(o);
- return createStringObjectFromLongLongForValue(value);
- }
- }
- }
-
- /* If the string is small and is still RAW encoded,
- * try the EMBSTR encoding which is more efficient.
- * In this representation the object and the SDS string are allocated
- * in the same chunk of memory to save space and cache misses. */
- if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT) {
- robj *emb;
-
- if (o->encoding == OBJ_ENCODING_EMBSTR) return o;
- emb = createEmbeddedStringObject(s,sdslen(s));
- decrRefCount(o);
- return emb;
- }
-
- /* We can't encode the object...
- *
- * Do the last try, and at least optimize the SDS string inside
- * the string object to require little space, in case there
- * is more than 10% of free space at the end of the SDS string.
- *
- * We do that only for relatively large strings as this branch
- * is only entered if the length of the string is greater than
- * OBJ_ENCODING_EMBSTR_SIZE_LIMIT. */
- trimStringObjectIfNeeded(o);
-
- /* Return the original object. */
- return o;
- }