redisObject

1
2
3
4
5
6
7
8
9
10
11
typedef struct redisObject {
unsigned type:4; // 类型,4位
unsigned encoding:4; // 编码
// 上次访问时间
// #define LRU_BITS 24
unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
* LFU data (least significant 8 bits frequency
* and most significant 16 bits access time). */
int refcount; // 引用次数
void *ptr; // 底层地址
} robj;
  • type类型

    1
    2
    3
    4
    5
    6
    7
    #define OBJ_STRING 0    /* String object. */
    #define OBJ_LIST 1 /* List object. */
    #define OBJ_SET 2 /* Set object. */
    #define OBJ_ZSET 3 /* Sorted set object. */
    #define OBJ_HASH 4 /* Hash object. */
    #define OBJ_MODULE 5 /* Module object. */,Redis module 直接管理的
    #define OBJ_STREAM 6 /* Stream object. */
  • encoding编码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #define OBJ_ENCODING_RAW 0     /* Raw representation */
    #define OBJ_ENCODING_INT 1 /* Encoded as integer */
    #define OBJ_ENCODING_HT 2 /* Encoded as hash table */
    #define OBJ_ENCODING_ZIPMAP 3 /* Encoded as zipmap */ 主要在rdb里面使用
    #define OBJ_ENCODING_LINKEDLIST 4 /* No longer used: old list encoding. */
    #define OBJ_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
    #define OBJ_ENCODING_INTSET 6 /* Encoded as intset */
    #define OBJ_ENCODING_SKIPLIST 7 /* Encoded as skiplist */
    #define OBJ_ENCODING_EMBSTR 8 /* Embedded sds string encoding */
    #define OBJ_ENCODING_QUICKLIST 9 /* Encoded as linked list of ziplists */
    #define OBJ_ENCODING_STREAM 10 /* Encoded as a radix tree of listpacks */

t_string

  1. 有三种编码方式,OBJ_ENCODING_INT,OBJ_ENCODING_EMBSTR,OBJ_ENCODING_RAW
  2. OBJ_ENCODING_EMBSTR_SIZE_LIMIT = 44,也就是小于等于44子长用embstr编码,大于就用raw.因为redisObject大小 = (4+4+24)/8+4+8 = 16,sdshdr8除去buf外的大小是3(len,alloc,flag),预留1byte的’\0’,供20byte.redis的内存分配方法按2^n分配,所以最接近的是64,剩下44byte.
  3. tryObjectEncoding
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79

    /* 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);
    // 20减去4个长度剩下16,2^64~=1.84E19(所以超过20位,减去符号19位,超过了int64表示的极限)
    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. */
    // 如果设置了最大使用内存,说明要进行回收,不能有共享变量(要LRU)
    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;
    }
    }

    /* 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. */
    // 如果小于等于44,改用EMBSTR
    // 说明默认是RAW编码
    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;
    }

t_list

  1. 编码方式有OBJ_ENCODING_QUICKLIST(OBJ_ENCODING_LINKEDLIST被弃用)(,OBJ_ENCODING_ZIPLIST在list里没用了)
  2. quicklist
  • 将linkedlist和ziplist混合起来使用,每个节点是一个ziplist
  • list-max-ziplist-size设置ziplist的大小,正数表示长度,负数表示 -n = 2^(n+1)kb

t_hash

  1. 编码方式有OBJ_ENCODING_ZIPLIST,OBJ_ENCODING_HT
  2. 如果长度大于server.hash_max_ziplist_entries,转换成OBJ_ENCODING_HT
  3. 如果键值的长度大于 server.hash_max_ziplist_value,转换成OBJ_ENCODING_HT

t_set

  1. 编码方式有OBJ_ENCODING_HT,OBJ_ENCODING_INTSET
  2. 如果长度大于server.set_max_intset_entries,或者有非整数,转换成OBJ_ENCODING_HT

t_zset

  1. 编码方式有OBJ_ENCODING_ZIPLIST,OBJ_ENCODING_SKIPLIST
  2. 如果长度大于server.zset_max_ziplist_entries,或者有非整数,转换成OBJ_ENCODING_SKIPLIST
  3. 如果值的长度大于 server.zset_max_ziplist_value,转换成OBJ_ENCODING_SKIPLIST