GithubHelp home page GithubHelp logo

huangz1990 / redis-3.0-annotated Goto Github PK

View Code? Open in Web Editor NEW
9.9K 585.0 4.2K 5.8 MB

带有详细注释的 Redis 3.0 代码(annotated Redis 3.0 source code)。

License: BSD 3-Clause "New" or "Revised" License

Makefile 0.28% Shell 0.42% C 84.28% Ruby 1.94% Tcl 13.05% Smarty 0.04%

redis-3.0-annotated's Introduction

Redis 3.0 源码注释

本项目是注释版的 Redis 3.0 源码, 原始代码来自: https://github.com/antirez/redis

这份注释是我在创作新版《Redis 设计与实现》期间, 为了了解 Redis 的内部实现而制作的, 所有在书中有介绍的内容, 在源码中都进行了相应的注释。

在注释的过程中, 除了少量空格和空行方面的调整外, 没有对原始代码进行任何其他改动, 最大程度地保证了代码的“原汁原味”。

希望这份注释源码能给大家学习和了解 Redis 带来一点帮助。

另外, 新版《Redis 设计与实现》正在各大网店发售中, 希望大家可以多多支持这本书。

Have fun!

黄健宏(huangz)
2014 年 6 月 28 日

附录:各个源码文件的作用简介

文件 作用
adlist.cadlist.h 双端链表数据结构的实现。
ae.cae.hae_epoll.cae_evport.cae_kqueue.cae_select.c 事件处理器,以及各个具体实现。
anet.canet.h Redis 的异步网络框架,内容主要为对 socket 库的包装。
aof.c AOF 功能的实现。
asciilogo.h 保存了 Redis 的 ASCII LOGO 。
bio.cbio.h Redis 的后台 I/O 程序,用于将 I/O 操作放到子线程里面执行, 减少 I/O 操作对主线程的阻塞。
bitops.c 二进制位操作命令的实现文件。
blocked.c 用于实现 BLPOP 命令和 WAIT 命令的阻塞效果。
cluster.ccluster.h Redis 的集群实现。
config.cconfig.h Redis 的配置管理实现,负责读取并分析配置文件, 然后根据这些配置修改 Redis 服务器的各个选项。
crc16.ccrc64.ccrc64.h 计算 CRC 校验和。
db.c 数据库实现。
debug.c 调试实现。
dict.cdict.h 字典数据结构的实现。
endianconv.cendianconv.h 二进制的大端、小端转换函数。
fmacros.h 一些移植性方面的宏。
help.h utils/generate-command-help.rb 程序自动生成的命令帮助信息。
hyperloglog.c HyperLogLog 数据结构的实现。
intset.cintset.h 整数集合数据结构的实现,用于优化 SET 类型。
lzf_c.clzf_d.clzf.hlzfP.h Redis 对字符串和 RDB 文件进行压缩时使用的 LZF 压缩算法的实现。
MakefileMakefile.dep 构建文件。
memtest.c 内存测试。
mkreleasehdr.sh 用于生成释出信息的脚本。
multi.c Redis 的事务实现。
networking.c Redis 的客户端网络操作库, 用于实现命令请求接收、发送命令回复等工作, 文件中的函数大多为 write 、 read 、 close 等函数的包装, 以及各种协议的分析和构建函数。
notify.c Redis 的数据库通知实现。
object.c Redis 的对象系统实现。
pqsort.cpqsort.h 快速排序(QuickSort)算法的实现。
pubsub.c 发布与订阅功能的实现。
rand.crand.h 伪随机数生成器。
rdb.crdb.h RDB 持久化功能的实现。
redisassert.h Redis 自建的断言系统。
redis-benchmark.c Redis 的性能测试程序。
redis.c 负责服务器的启动、维护和关闭等事项。
redis-check-aof.credis-check-dump.c RDB 文件和 AOF 文件的合法性检查程序。
redis-cli.c Redis 客户端的实现。
redis.h Redis 的主要头文件,记录了 Redis 中的大部分数据结构, 包括服务器状态和客户端状态。
redis-trib.rb Redis 集群的管理程序。
release.crelease.h 记录和生成 Redis 的释出版本信息。
replication.c 复制功能的实现。
rio.crio.h Redis 对文件 I/O 函数的包装, 在普通 I/O 函数的基础上增加了显式缓存、以及计算校验和等功能。
scripting.c 脚本功能的实现。
sds.csds.h SDS 数据结构的实现,SDS 为 Redis 的默认字符串表示。
sentinel.c Redis Sentinel 的实现。
setproctitle.c 进程环境设置函数。
sha1.csha1.h SHA1 校验和计算函数。
slowlog.cslowlog.h 慢查询功能的实现。
solarisfixes.h 针对 Solaris 系统的补丁。
sort.c SORT 命令的实现。
syncio.c 同步 I/O 操作。
testhelp.h 测试辅助宏。
t_hash.ct_list.ct_set.ct_string.ct_zset.c 定义了 Redis 的各种数据类型,以及这些数据类型的命令。
util.cutil.h 各种辅助函数。
valgrind.sup valgrind 的suppression文件。
version.h 记录了 Redis 的版本号。
ziplist.cziplist.h ZIPLIST 数据结构的实现,用于优化 LIST 类型。
zipmap.czipmap.h ZIPMAP 数据结构的实现,在 Redis 2.6 以前用与优化 HASH 类型, Redis 2.6 开始已经废弃。
zmalloc.czmalloc.h 内存管理程序。

redis-3.0-annotated's People

Contributors

alexmchale avatar antirez avatar anydot avatar badboy avatar bpot avatar catwell avatar charsyam avatar d0k avatar dieken avatar djanowski avatar erikdubbelboer avatar florean avatar geoffgarside avatar hampus avatar huangzworks avatar janoberst avatar jbergstroem avatar jokea avatar jzawodn avatar kaoshijuan avatar lucsky avatar melo avatar mrb avatar pietern avatar saj avatar soveran avatar stamhe avatar tmm1 avatar xuewuhen avatar yamt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

redis-3.0-annotated's Issues

zskiplistNode level为何什么是个数组

zskiplistNode level为何什么是个数组,生成 zskiplistNode 的时候, 为其随机分配一个 1 到32 之间的值作为 level 数组的大小,那如何为其赋值呢?

关于客户端源码hiredis读取服务端响应问题

读取服务端响应没有对tcp数据流进行粘包和拆包,这个应该有问题吧

调用read返回的nread长度不一定等于一条完整消息的长度吧,有可能会小于。
int redisBufferRead(redisContext c) {
char buf[1024
16];
int nread;

/* Return early when the context has seen an error. */
if (c->err)
    return REDIS_ERR;

nread = read(c->fd,buf,sizeof(buf));
if (nread == -1) {
    if (errno == EAGAIN && !(c->flags & REDIS_BLOCK)) {
        /* Try again later */
    } else {
        __redisSetError(c,REDIS_ERR_IO,NULL);
        return REDIS_ERR;
    }
} else if (nread == 0) {
    __redisSetError(c,REDIS_ERR_EOF,"Server closed the connection");
    return REDIS_ERR;
} else {
    if (redisReaderFeed(c->reader,buf,nread) != REDIS_OK) {
        __redisSetError(c,c->reader->err,c->reader->errstr);
        return REDIS_ERR;
    }
}
return REDIS_OK;

}

clusterSendPing当中的疑问

这里的while循环当中gossipcount的范围是[0,3),不应该是发送3个节点信息么?
另外,gossip = &(hdr->data.ping.gossip[gossipcount]);这个操作会不会污染后面的内存呢?毕竟gossip的数组大小是1.


// 向指定节点发送一个 PING 或者 PONG 信息
void clusterSendPing(clusterLink link, int type) {
unsigned char buf[sizeof(clusterMsg)];
clusterMsg hdr = (clusterMsg) buf;
int gossipcount = 0, totlen;
/
freshnodes is the number of nodes we can still use to populate the
* gossip section of the ping packet. Basically we start with the nodes
* we have in memory minus two (ourself and the node we are sending the
* message to). Every time we add a node we decrement the counter, so when
* it will drop to <= zero we know there is no more gossip info we can
* send. */
// freshnodes 是用于发送 gossip 信息的计数器
// 每次发送一条信息时,程序将 freshnodes 的值减一
// 当 freshnodes 的数值小于等于 0 时,程序停止发送 gossip 信息
// freshnodes 的数量是节点目前的 nodes 表中的节点数量减去 2
// 这里的 2 指两个节点,一个是 myself 节点(也即是发送信息的这个节点)
// 另一个是接受 gossip 信息的节点
int freshnodes = dictSize(server.cluster->nodes)-2;

// 如果发送的信息是 PING ,那么更新最后一次发送 PING 命令的时间戳
if (link->node && type == CLUSTERMSG_TYPE_PING)
    link->node->ping_sent = mstime();

// 设置信息
clusterBuildMessageHdr(hdr,type);
    
/* Populate the gossip fields */
// 每个节点有 freshnodes 次发送 gossip 信息的机会
// 每次向目标节点发送 2 个被选中节点的 gossip 信息(gossipcount 计数)
while(freshnodes > 0 && gossipcount < 3) {

    // 从 nodes 字典中随机选出一个节点(被选中节点)
    struct dictEntry *de = dictGetRandomKey(server.cluster->nodes);
    clusterNode *this = dictGetVal(de);

    clusterMsgDataGossip *gossip;
    int j;

    /* In the gossip section don't include:
     * 以下节点不能作为被选中节点:
     * 1) Myself.
     *    节点本身。
     * 2) Nodes in HANDSHAKE state.
     *    处于 HANDSHAKE 状态的节点。
     * 3) Nodes with the NOADDR flag set.
     *    带有 NOADDR 标识的节点
     * 4) Disconnected nodes if they don't have configured slots.
     *    因为不处理任何槽而被断开连接的节点 
     */
    if (this == server.cluster->myself ||
        this->flags & (REDIS_NODE_HANDSHAKE|REDIS_NODE_NOADDR) ||
        (this->link == NULL && this->numslots == 0))
    {
            freshnodes--; /* otherwise we may loop forever. */
            continue;
    }

    /* Check if we already added this node */
    // 检查被选中节点是否已经在 hdr->data.ping.gossip 数组里面
    // 如果是的话说明这个节点之前已经被选中了
    // 不要再选中它(否则就会出现重复)
    for (j = 0; j < gossipcount; j++) {
        if (memcmp(hdr->data.ping.gossip[j].nodename,this->name,
                REDIS_CLUSTER_NAMELEN) == 0) break;
    }
    if (j != gossipcount) continue;

    /* Add it */

    // 这个被选中节点有效,计数器减一
    freshnodes--;

    // 指向 gossip 信息结构
    gossip = &(hdr->data.ping.gossip[gossipcount]);

    // 将被选中节点的名字记录到 gossip 信息
    memcpy(gossip->nodename,this->name,REDIS_CLUSTER_NAMELEN);
    // 将被选中节点的 PING 命令发送时间戳记录到 gossip 信息
    gossip->ping_sent = htonl(this->ping_sent);
    // 将被选中节点的 PING 命令回复的时间戳记录到 gossip 信息
    gossip->pong_received = htonl(this->pong_received);
    // 将被选中节点的 IP 记录到 gossip 信息
    memcpy(gossip->ip,this->ip,sizeof(this->ip));
    // 将被选中节点的端口号记录到 gossip 信息
    gossip->port = htons(this->port);
    // 将被选中节点的标识值记录到 gossip 信息
    gossip->flags = htons(this->flags);

    // 这个被选中节点有效,计数器增一
    gossipcount++;
}

// 计算信息长度
totlen = sizeof(clusterMsg)-sizeof(union clusterMsgData);
totlen += (sizeof(clusterMsgDataGossip)*gossipcount);
// 将被选中节点的数量(gossip 信息中包含了多少个节点的信息)
// 记录在 count 属性里面
hdr->count = htons(gossipcount);
// 将信息的长度记录到信息里面
hdr->totlen = htonl(totlen);

// 发送信息
clusterSendMessage(link,buf,totlen);

}

t_list.c/pushGenericCommand 函数中的waiting什么作用?

如题,代码里的waiting一直都是0啊?

void pushGenericCommand(redisClient *c, int where) {

    int j, waiting = 0, pushed = 0;

    // 取出列表对象
    robj *lobj = lookupKeyWrite(c->db,c->argv[1]);

    // 如果列表对象不存在,那么可能有客户端在等待这个键的出现
    int may_have_waiting_clients = (lobj == NULL);

    if (lobj && lobj->type != REDIS_LIST) {
        addReply(c,shared.wrongtypeerr);
        return;
    }

    // 将列表状态设置为就绪
    if (may_have_waiting_clients) signalListAsReady(c,c->argv[1]);

    // 遍历所有输入值,并将它们添加到列表中
    for (j = 2; j < c->argc; j++) {

        // 编码值
        c->argv[j] = tryObjectEncoding(c->argv[j]);

        // 如果列表对象不存在,那么创建一个,并关联到数据库
        if (!lobj) {
            lobj = createZiplistObject();
            dbAdd(c->db,c->argv[1],lobj);
        }

        // 将值推入到列表
        listTypePush(lobj,c->argv[j],where);

        pushed++;
    }

    // 返回添加的节点数量
    addReplyLongLong(c, waiting + (lobj ? listTypeLength(lobj) : 0));

    // 如果至少有一个元素被成功推入,那么执行以下代码
    if (pushed) {
        char *event = (where == REDIS_HEAD) ? "lpush" : "rpush";

        // 发送键修改信号
        signalModifiedKey(c->db,c->argv[1]);

        // 发送事件通知
        notifyKeyspaceEvent(REDIS_NOTIFY_LIST,event,c->argv[1],c->db->id);
    }

    server.dirty += pushed;
}

关于hashFunction的一点疑问

我在实现redis中的dict的时候在写hashFunction的时候有点疑惑,在dictType中的hashFunction指针是在哪里被实现的呢?找了半天没找到,求指教

向大家请教一下跳跃表插入节点函数中的两句代码的含义?

大家好,我最近在阅读 Redis 3.0的代码,提交ID是48e24d54。

在跳跃表的插入函数zskiplistNode *zslInsert(zskiplist *zsl, double score, robj *obj)中,关于计算节点中level的span,有这样两句代码,代码链接:

    x = zslCreateNode(level,score,obj);
    for (i = 0; i < level; i++) {
        x->level[i].forward = update[i]->level[i].forward;
        update[i]->level[i].forward = x;

        /* update span covered by update[i] as x is inserted here */
        //TODO: 这两句这个跨度是如何计算的,真的没太看懂
        x->level[i].span = update[i]->level[i].span - (rank[0] - rank[i]);
        update[i]->level[i].span = (rank[0] - rank[i]) + 1;
    }

关于计算span的后两句,我真的没看太懂,我知道update数组记录的是每一层中,插入新节点前的一个节点,rank数组记录的是头结点到update中记录的节点的 span 值的和,请问那个rank[0] - rank[i]是什么意思啊,真的没太懂,还请各位书友不吝赐教。

p & 3 含义是什么

while((unsigned long)p & 3 && count)
在 redis bitcount实现中 说不足32 bit的直接使用这个这个循环进行计算。但是 不理解 p&3 什么含义。
似乎跟32bit 没什么关系

关于dictRehash的疑问

while(de) {
uint64_t h;
nextde = de->next;
/* Get the index in the new hash table */
h = dictHashKey(d, de->key) & d->ht[1].sizemask;
de->next = d->ht[1].table[h];
d->ht[1].table[h] = de;
d->ht[0].used--;
d->ht[1].used++;
de = nextde;
}
以上代码是int dictRehash(dict *d, int n)中的部分实现,对于d->ht[0].used--有疑问,由于我们使用链接法解决冲突,所以de节点后面链接的所有节点理论上并没有记录在d->ht[0].used中,所以这里不是很明白,希望大神能帮我解惑。

源码中关于复杂度的错误

我在看redis中的跳跃表的实现,觉得注释中对于复杂度的记录是有问题的。

` *

  • T = O(N)
    */
    int zslRandomLevel(void) {
    int level = 1;

    while ((random() & 0xFFFF) < (ZSKIPLIST_P * 0xFFFF))
    level += 1;

    return (level < ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
    }`
    这里的复杂度是O(N),但是应该是O(ZSKIPLIST_MAXLEVEL)。由于在算法中复杂度计算的时候会忽略常数,因此这个函数的复杂度其实是O(1),当然需要假设random的复杂度是O(1).

还有跳跃表的插入和删除在代码中都是O(Nlog(N)),而查找的复杂度是O(log(N))。但是跳跃表的插入和查找的复杂度其实是一样的,都是最好O(log(N)),最坏O(N)。这点维基也有写,希望您能改下。

当时看到这个地方的时候确实很让人迷惑。

redis.h 中 zskiplistNode 结构体中的 level 是如何定义的

大家好,我最近在阅读 Redis 的3.0的源码,提交ID是48e24d54b736b162617112ce27ec724b9290592e

我在阅读 redis.h 中跳跃表节点的定义的时候,遇到了点疑惑,特来和大家请教一下,还望各位不吝赐教。

跳跃表节点的定义如下:

/* ZSETs use a specialized version of Skiplists */
typedef struct zskiplistNode {
    robj *obj;
    double score;
    struct zskiplistNode *backward;
    // 跳跃表节点的层
    struct zskiplistLevel {
        // 前进指针
        struct zskiplistNode *forward;
        // 跨度
        unsigned int span;
    } level[];
} zskiplistNode;

我的问题如下:

  1. 请问一下这个结构体在内存中是如何组织的,如果我通过 malloc(sizeof(zskiplistNode)) 申请了一片跳跃表节点内存,申请的内存空间中应该没有为level申请的内存吧?

  2. level 的结构体数组的定义方式和指针有什么不同,为什么我将结构体数组替换成指针之后,运行 Redis 的测试会报错。

修改的代码如下:

/* ZSETs use a specialized version of Skiplists */
typedef struct zskiplistNode {
    robj *obj;
    double score;
    struct zskiplistNode *backward;
    struct zskiplistLevel {
        struct zskiplistNode *forward;
        unsigned int span;
    } *level;
} zskiplistNode;

错误如下:

=== REDIS BUG REPORT START: Cut & paste starting from here ===
11954:M 15 Mar 22:44:15.832 #     Redis 3.0.7 crashed by signal: 11
11954:M 15 Mar 22:44:15.832 #     SIGSEGV caused by address: 0x0
11954:M 15 Mar 22:44:15.832 #     Failed assertion: <no assertion failed> (<no file>:0)
11954:M 15 Mar 22:44:15.832 # --- STACK TRACE
0   redis-server                        0x000000010893c007 logStackTrace + 103
1   redis-server                        0x0000000108924750 zslCreate + 80
2   libsystem_platform.dylib            0x00007fff4fcecf5a _sigtramp + 26
3   ???                                 0x0000000110307292 0x0 + 4566577810
4   redis-server                        0x0000000108911969 createZsetObject + 41
5   redis-server                        0x0000000108928d7a zunionInterGenericCommand + 906
6   redis-server                        0x0000000108900682 call + 194
7   redis-server                        0x0000000108900e69 processCommand + 1305
8   redis-server                        0x000000010890f036 processInputBuffer + 182
9   redis-server                        0x000000010890c6e3 readQueryFromClient + 419
10  redis-server                        0x00000001088f98c3 aeProcessEvents + 643
11  redis-server                        0x00000001088f9bab aeMain + 43
12  redis-server                        0x0000000108903d74 main + 1092
13  libdyld.dylib                       0x00007fff4fa6b115 start + 1
14  ???                                 0x0000000000000002 0x0 + 2
11954:M 15 Mar 22:44:15.833 # --- INFO OUTPUT
11954:M 15 Mar 22:44:15.833 # # Server
redis_version:3.0.7
redis_git_sha1:0473b287
redis_git_dirty:1
redis_build_id:f557074db7ddeb0c
redis_mode:standalone
os:Darwin 17.4.0 x86_64
arch_bits:64
multiplexing_api:kqueue
gcc_version:4.2.1
process_id:11954
run_id:e6c591f7ad8ce94881fa71da41e7a0516c42fce2
tcp_port:21342
uptime_in_seconds:0
uptime_in_days:0
hz:10
lru_clock:11175615
config_file:/Users/michaeltsui/Github/redis/./tests/tmp/redis.conf.11937.2

# Clients
connected_clients:1
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0

# Memory
used_memory:1009616
used_memory_human:985.95K
used_memory_rss:2174976
used_memory_peak:1009616
used_memory_peak_human:985.95K
used_memory_lua:36864
mem_fragmentation_ratio:2.15
mem_allocator:libc

# Persistence
loading:0
rdb_changes_since_last_save:309
rdb_bgsave_in_progress:0
rdb_last_save_time:1521125055
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:-1
rdb_current_bgsave_time_sec:-1
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok

# Stats
total_connections_received:2
total_commands_processed:470
instantaneous_ops_per_sec:127
total_net_input_bytes:19991
total_net_output_bytes:4743
instantaneous_input_kbps:5.37
instantaneous_output_kbps:1.37
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:0
evicted_keys:0
keyspace_hits:150
keyspace_misses:4
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:0
migrate_cached_sockets:0

# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

# CPU
used_cpu_sys:0.03
used_cpu_user:0.02
used_cpu_sys_children:0.00
used_cpu_user_children:0.00

# Commandstats
cmdstat_del:calls=51,usec=473,usec_per_call=9.27
cmdstat_exists:calls=25,usec=102,usec_per_call=4.08
cmdstat_zadd:calls=187,usec=2483,usec_per_call=13.28
cmdstat_zincrby:calls=8,usec=199,usec_per_call=24.88
cmdstat_zrem:calls=10,usec=118,usec_per_call=11.80
cmdstat_zremrangebyscore:calls=16,usec=191,usec_per_call=11.94
cmdstat_zremrangebyrank:calls=6,usec=58,usec_per_call=9.67
cmdstat_zrange:calls=39,usec=284,usec_per_call=7.28
cmdstat_zrangebyscore:calls=29,usec=319,usec_per_call=11.00
cmdstat_zrevrangebyscore:calls=18,usec=242,usec_per_call=13.44
cmdstat_zrangebylex:calls=21,usec=266,usec_per_call=12.67
cmdstat_zrevrangebylex:calls=10,usec=179,usec_per_call=17.90
cmdstat_zcount:calls=2,usec=14,usec_per_call=7.00
cmdstat_zlexcount:calls=2,usec=27,usec_per_call=13.50
cmdstat_zrevrange:calls=15,usec=89,usec_per_call=5.93
cmdstat_zcard:calls=5,usec=45,usec_per_call=9.00
cmdstat_zscore:calls=10,usec=105,usec_per_call=10.50
cmdstat_zrank:calls=6,usec=39,usec_per_call=6.50
cmdstat_zrevrank:calls=4,usec=20,usec_per_call=5.00
cmdstat_select:calls=1,usec=10,usec_per_call=10.00
cmdstat_ping:calls=1,usec=13,usec_per_call=13.00
cmdstat_type:calls=1,usec=5,usec_per_call=5.00
cmdstat_debug:calls=1,usec=31,usec_per_call=31.00
cmdstat_config:calls=2,usec=27,usec_per_call=13.50

# Cluster
cluster_enabled:0

# Keyspace
db9:keys=2,expires=0,avg_ttl=0
hash_init_value: 1521039639

11954:M 15 Mar 22:44:15.833 # --- CLIENT LIST OUTPUT
11954:M 15 Mar 22:44:15.833 # id=3 addr=127.0.0.1:50777 fd=10 name= age=0 idle=0 flags=N db=9 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=zunionstore

11954:M 15 Mar 22:44:15.833 # --- CURRENT CLIENT INFO
11954:M 15 Mar 22:44:15.833 # client: id=3 addr=127.0.0.1:50777 fd=10 name= age=0 idle=0 flags=N db=9 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=zunionstore
11954:M 15 Mar 22:44:15.833 # argv[0]: 'zunionstore'
11954:M 15 Mar 22:44:15.833 # argv[1]: 'dst_key'
11954:M 15 Mar 22:44:15.833 # argv[2]: '1'
11954:M 15 Mar 22:44:15.833 # argv[3]: 'zseta'
11954:M 15 Mar 22:44:15.833 # --- REGISTERS
11954:M 15 Mar 22:44:15.833 #
RAX:00007f8d49e18b40 RBX:00007f8d49e18990
RCX:0000000000000000 RDX:0000000000000000
RDI:00000001089ed000 RSI:0000000000000000
RBP:00007ffee7307190 RSP:00007ffee7307180
R8 :9e3779b97f4a7c55 R9 :0000000000000022
R10:0000000600000000 R11:00007f8d49e00000
R12:0000000000000001 R13:00007f8d4a800000
R14:0000000000000004 R15:0000000000000001
RIP:0000000108924750 EFL:0000000000010246
CS :000000000000002b FS:0000000000000000  GS:0000000000000000
11954:M 15 Mar 22:44:15.833 # (00007ffee730718f) -> 00000001089f0a00
11954:M 15 Mar 22:44:15.833 # (00007ffee730718e) -> 0000000000001e00
11954:M 15 Mar 22:44:15.833 # (00007ffee730718d) -> 000000000000000a
11954:M 15 Mar 22:44:15.833 # (00007ffee730718c) -> 00000000089fd000
11954:M 15 Mar 22:44:15.833 # (00007ffee730718b) -> 00007fff4fc13403
11954:M 15 Mar 22:44:15.833 # (00007ffee730718a) -> 00007f8d49e18880
11954:M 15 Mar 22:44:15.833 # (00007ffee7307189) -> 00007f8d49e1ffff
11954:M 15 Mar 22:44:15.833 # (00007ffee7307188) -> fd00000070001003
11954:M 15 Mar 22:44:15.833 # (00007ffee7307187) -> 0000000108928d7a
11954:M 15 Mar 22:44:15.833 # (00007ffee7307186) -> 00007ffee73072b0
11954:M 15 Mar 22:44:15.833 # (00007ffee7307185) -> 0000000000000004
11954:M 15 Mar 22:44:15.833 # (00007ffee7307184) -> 0000000000000000
11954:M 15 Mar 22:44:15.833 # (00007ffee7307183) -> 0000000108911969
11954:M 15 Mar 22:44:15.833 # (00007ffee7307182) -> 00007ffee73071b0
11954:M 15 Mar 22:44:15.833 # (00007ffee7307181) -> 00007f8d49e186b0
11954:M 15 Mar 22:44:15.834 # (00007ffee7307180) -> 00007f8d49e18930
11954:M 15 Mar 22:44:15.834 #
=== REDIS BUG REPORT END. Make sure to include from START to END. ===

       Please report the crash by opening an issue on github:

           http://github.com/antirez/redis/issues

  Suspect RAM error? Use redis-server --test-memory to verify it.



[exception]: Executing test client: I/O error reading reply.
I/O error reading reply
    while executing
"[srv $level "client"] {*}$args"
    (procedure "r" line 7)
    invoked from within
"r zunionstore dst_key 1 zseta"
    ("uplevel" body line 3)
    invoked from within
"uplevel 1 $code"
    (procedure "test" line 29)
    invoked from within
"test "ZUNIONSTORE against non-existing key doesn't set destination - $encoding" {
            r del zseta
            assert_equal 0 [r zunionstore ds..."
    (procedure "basics" line 521)
    invoked from within
"basics ziplist"
    ("uplevel" body line 647)
    invoked from within
"uplevel 1 $code "
    (procedure "start_server" line 3)
    invoked from within
"start_server {tags {"zset"}} {
    proc create_zset {key items} {
        r del $key
        foreach {score entry} $items {
            r zadd $key $s..."
    (file "tests/unit/type/zset.tcl" line 1)
    invoked from within
"source $path"
    (procedure "execute_tests" line 4)
    invoked from within
"execute_tests $data"
    (procedure "test_client_main" line 10)
    invoked from within
"test_client_main $::test_server_port "
Killing still running Redis server 11947
Killing still running Redis server 11948
Killing still running Redis server 11949
Killing still running Redis server 11951
Killing still running Redis server 11953
Killing still running Redis server 11952
Killing still running Redis server 11964
Killing still running Redis server 11960
Killing still running Redis server 11962
Killing still running Redis server 11961
Killing still running Redis server 11954
Killing still running Redis server 11971
Killing still running Redis server 11972
Killing still running Redis server 11973
Killing still running Redis server 11980
Killing still running Redis server 12042
Killing still running Redis server 12066
make[1]: *** [test] Error 1
make: *** [test] Error 2
make test  11.26s user 3.92s system 100% cpu 15.150 total

sdscatvprintf 时间复杂度问题

源码中对 sdscatvprintf 这个函数的时间复杂度分析

/* Try with buffers two times bigger every time we fail to
     * fit the string in the current buffer size. */
    while(1) {
        buf[buflen-2] = '\0';
        va_copy(cpy,ap);
        // T = O(N)
        vsnprintf(buf, buflen, fmt, cpy);
        if (buf[buflen-2] != '\0') {
            if (buf != staticbuf) zfree(buf);
            buflen *= 2;
            buf = zmalloc(buflen);
            if (buf == NULL) return NULL;
            continue;
        }
        break;
    }

buf 每次是两倍的长度增长, 时间复杂度应该是 n*logn
n 代表 fmt 字符串的长度

为什么redis哨兵每次要建立2个socket连接?

分别用于命令发送和订阅功能, 为什么不能通过共享同一个sockect连接实现?
书上说 为了不丢失__sentinel__:hello频道的任何信息,必须建立订阅连接接收, 没有理解丢不丢消息和几个连接有什么关系, 如果客户端下线或断网,建立几个都没用啊

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.