美文网首页
redis t_string t_list

redis t_string t_list

作者: lmem | 来源:发表于2017-06-11 18:25 被阅读29次

t_string


t_string 字符串,不涉及具体的转换,注意这里有个过期时间

/* The setGenericCommand() function implements the SET operation with different
 * options and variants. This function is called in order to implement the
 * following commands: SET, SETEX, PSETEX, SETNX.
 *
 * 'flags' changes the behavior of the command (NX or XX, see belove).
 *
 * 'expire' represents an expire to set in form of a Redis object as passed
 * by the user. It is interpreted according to the specified 'unit'.
 *
 * 'ok_reply' and 'abort_reply' is what the function will reply to the client
 * if the operation is performed, or when it is not because of NX or
 * XX flags.
 *
 * If ok_reply is NULL "+OK" is used.
 * If abort_reply is NULL, "$-1" is used. */

#define OBJ_SET_NO_FLAGS 0
#define OBJ_SET_NX (1<<0)     /* Set if key not exists. */
#define OBJ_SET_XX (1<<1)     /* Set if key exists. */
#define OBJ_SET_EX (1<<2)     /* Set if time in seconds is given */
#define OBJ_SET_PX (1<<3)     /* Set if time in ms in given */

void setGenericCommand(client *c, int flags, robj *key, robj *val, robj *expire, int unit, robj *ok_reply, robj *abort_reply) {
    long long milliseconds = 0; /* initialized to avoid any harmness warning */

    if (expire) {
        //如果有过期时间则需要验证是否合法
        if (getLongLongFromObjectOrReply(c, expire, &milliseconds, NULL) != C_OK)
            return;
        if (milliseconds <= 0) {
            addReplyErrorFormat(c,"invalid expire time in %s",c->cmd->name);
            return;
        }
        if (unit == UNIT_SECONDS) milliseconds *= 1000;
    }
    //Set if key not exists.
    if ((flags & OBJ_SET_NX && lookupKeyWrite(c->db,key) != NULL) ||
        (flags & OBJ_SET_XX && lookupKeyWrite(c->db,key) == NULL))
    {
        addReply(c, abort_reply ? abort_reply : shared.nullbulk);
        return;
    }
    setKey(c->db,key,val);
    server.dirty++;
    if (expire) setExpire(c->db,key,mstime()+milliseconds);
    notifyKeyspaceEvent(NOTIFY_STRING,"set",key,c->db->id);
    if (expire) notifyKeyspaceEvent(NOTIFY_GENERIC,
        "expire",key,c->db->id);
    addReply(c, ok_reply ? ok_reply : shared.ok);
}

t_list


双向链表在插入节点上复杂度很低,但它的内存开销很大,每个节点的地址不连续,容易产生内存碎片。
ziplist是存储在一段连续的内存上,存储效率高,但是它不利于修改操作,插入和删除数都很麻烦,复杂度高,而且其需要频繁的申请释放内存,特别是ziplist中数据较多的情况下,搬移内存数据太费时!
Redis综合了双向链表和ziplist的优点,设计了quicklist这个数据结构,使它作为list键的底层实现。接下来,就要考虑每一个ziplist中存放的元素个数。

  • 如果每一个ziplist中的元素个数过少,内存碎片就会增多。可以按照极端情况双向链表来考虑。
  • 如果每一个ziplist中的元素个数过多,那么ziplist分配大块连续内存空间的难度就增大,同样会影响效率。

具体可见quiklist

void listTypePush(robj *subject, robj *value, int where) /* 在头部或尾部插入value元素 */  
robj *listTypePop(robj *subject, int where)  /* 在列表的头部或尾弹出元素 */  
unsigned long listTypeLength(robj *subject) /* 列表的长度 */  
listTypeIterator *listTypeInitIterator(robj *subject, long index, unsigned char direction) /* 返回列表迭代器,方向有头尾之分 */  
void listTypeReleaseIterator(listTypeIterator *li) /* 释放列表迭代器 */  
int listTypeNext(listTypeIterator *li, listTypeEntry *entry) /* 根据列表迭代器,获取下一个元素 */  
robj *listTypeGet(listTypeEntry *entry) /* 获取listType元素,有ziplist和linkedlist */  
void listTypeInsert(listTypeEntry *entry, robj *value, int where) /* listType了类型插入元素操作 */  
int listTypeEqual(listTypeEntry *entry, robj *o) /* 判断2个元素是否相等 */  
void listTypeDelete(listTypeEntry *entry) /* listType类型删除元素 */  
void listTypeConvert(robj *subject, int enc) /* listType类型的转换操作,这里指的是往linkedList上转 */  
      
/* List的相关命令 */  
void pushGenericCommand(redisClient *c, int where) /* 插入操作命令的原始操作 */  
void lpushCommand(redisClient *c) /* 左边插入元素命令 */  
void rpushCommand(redisClient *c) /* 右边插入元素命令 */  
void pushxGenericCommand(redisClient *c, robj *refval, robj *val, int where) /* 有返回状态的插入操作命令,假设首先都是能够实现插入命令的 */  
void lpushxCommand(redisClient *c) /* 左边插入元素有返回消息的命令 */  
void rpushxCommand(redisClient *c) /* 右边插入元素有返回消息的命令 */  
void linsertCommand(redisClient *c) /* 列表指定位置插入元素操作命令 */  
void llenCommand(redisClient *c) /* 列表返回长度命令 */  
void lindexCommand(redisClient *c) /* 获取index位置的上的元素 */  
void lsetCommand(redisClient *c) /* listType类型设置value命令 */  
void popGenericCommand(redisClient *c, int where) /* 实现弹出操作的原始命令 */  
void lpopCommand(redisClient *c) /* 左边弹出元素命令 */  
void rpopCommand(redisClient *c) /* 右边弹出操作命令 */  
void lrangeCommand(redisClient *c) /* 移动listType位置操作 */  
void ltrimCommand(redisClient *c) /* listType实现截取操作,把多余范围的元素删除 */  
void lremCommand(redisClient *c) /* 移除在listType中出现的与指定的元素相等的元素 */  
void rpoplpushHandlePush(redisClient *c, robj *dstkey, robj *dstobj, robj *value) /* 元素从一个obj右边弹出,在从左侧推入另一个obj列表操作 */  
void rpoplpushCommand(redisClient *c) /* 右边弹出,左边推入元素的命令 */  
void blockForKeys(redisClient *c, robj **keys, int numkeys, time_t timeout, robj *target) >/* 设置客户端为阻塞模式,并设置超时时间,当请求特定的key元素时 */  
void unblockClientWaitingData(redisClient *c) /* 客户端解锁操作 */  
void signalListAsReady(redisDb *db, robj *key) /* 将key存入server中,后续可以用于客户端的存取 */  
int serveClientBlockedOnList(redisClient *receiver, robj *key, robj *dstkey, redisDb *db, robj *value, int where) /* 根据server,Client的key,value情况,判断server此时能否服务于Client,否则Client将被阻塞 */  
void handleClientsBlockedOnLists(void) /* 服务端解除阻塞住的Client */  
int getTimeoutFromObjectOrReply(redisClient *c, robj *object, time_t *timeout) /* 获取超时时间 */   
void blockingPopGenericCommand(redisClient *c, int where) /* 阻塞弹出命令的原始操作 */  
void blpopCommand(redisClient *c) /* 左边弹出数据的阻塞式命令 */  
void brpopCommand(redisClient *c) /* 右边弹出数据的阻塞式命令 */  
void brpoplpushCommand(redisClient *c) /* 弹出推入阻塞式命令 */  

相关文章

网友评论

      本文标题:redis t_string t_list

      本文链接:https://www.haomeiwen.com/subject/gujhqxtx.html