zset 怎么get_Redis之ZSet命令

本文介绍了Redis中的有序集合ZSet的存储结构和转换规则,并详细解析了`ZADD`和`ZCOUNT`命令的内部实现。`ZADD`用于向有序集合中添加元素,支持分数累加;`ZCOUNT`则统计分数在特定范围内的元素数量。文章还提及了ZSet在ziplist和skiplist两种存储结构间的转换条件。
摘要由CSDN通过智能技术生成

0.前言

Redis有序集合ZSet可以按分数进行排序, 存储结构可能使用ziplist,skiplist和hash表, zset_max_ziplist_entries和zset_max_ziplist_value两个字段控制zset采用何种存储方式, zset_max_ziplist_entries表示ziplist中存储score和member占用的内存空间超过该值, 则存储结构会转变为skiplist和hash表; zset_max_ziplist_value表示ziplist中存储的member值占用的内存空间超过该值, 则存储结构会转变为skiplist和hash表. 存储使用ziplist时, ziplist存储格式为[member, score, member, score....], 以score值升序进行排序.存储使用skiplist时, 需要hash表配合使用, hash表存储以member为key, score为值, 加快member检索score速度; skiplist存储score和member, 并以score值进行升序排序.

1.目录

2.ZADD命令

添加元素到有序集合中, 命令格式 : ZADD key score member [[score member] [score member] ...], 入口函数zaddCommand

void zaddCommand(redisClient *c) {

zaddGenericCommand(c,0);

}

/*函数向有序集合中添加一个元素, 在incr值设置时, 同时可以实现对score值进行累加操作*/

void zaddGenericCommand(redisClient *c, int incr) {

static char *nanerr = "resulting score is not a number (NaN)";

robj *key = c->argv[1];

robj *ele;

robj *zobj;

robj *curobj;

double score = 0, *scores = NULL, curscore = 0.0;

int j, elements = (c->argc-2)/2;

int added = 0, updated = 0;

if (c->argc % 2) {

addReply(c,shared.syntaxerr);

return;

}

/* 获取scores值, score必须为数字, 否则直接返回错误*/

scores = zmalloc(sizeof(double)*elements);

for (j = 0; j < elements; j++) {

if (getDoubleFromObjectOrReply(c,c->argv[2+j*2],&scores[j],NULL)

!= REDIS_OK) goto cleanup;

}

/* 如果有序集合不存在, 直接进行创建 */

zobj = lookupKeyWrite(c->db,key);

if (zobj == NULL) {

/*对限制条件进行判断,选择存储结构*/

if (server.zset_max_ziplist_entries == 0 ||

server.zset_max_ziplist_value < sdslen(c->argv[3]->ptr))

{

/*创建有序集合, 存储结构式skiplist*/

zobj = createZsetObject();

} else {

/*创建有序集合, 存储结构式ziplist*/

zobj = createZsetZiplistObject();

}

dbAdd(c->db,key,zobj);

} else {

if (zobj->type != REDIS_ZSET) {

addReply(c,shared.wrongtypeerr);

goto cleanup;

}

}

for (j = 0; j < elements; j++) {

score = scores[j];

if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {

unsigned char *eptr;

/* 在skiplist中进行查找, 找到则删除原来的, 插入新的, 否则直接进行插入操作*/

ele = c->argv[3+j*2];

if ((eptr = zzlFind(zobj->ptr,ele,&curscore)) != NULL) {

/*incr值设置, 则需要进行累加*/

if (incr) {

score += curscore;

if (isnan(score)) {

addReplyError(c,nanerr);

goto cleanup;

}

}

/* 如果member和score都没有变化, 则不进行任何操作*/

if (score != curscore) {

zobj->ptr = zzlDelete(zobj->ptr,eptr);

zobj->ptr = zzlInsert(zobj->ptr,ele,score);

server.dirty++;

updated++;

}

} else {

/* 同样插入元素时进行检测ziplist转skiplist的阀值*/

zobj->ptr = zzlInsert(zobj->ptr,ele,score);

if (zzlLength(zobj->ptr) > server.zset_max_ziplist_entries)

zsetConvert(zobj,REDIS_ENCODING_SKIPLIST);

if (sdslen(ele->ptr) > server.zset_max_ziplist_value)

zsetConvert(zobj,REDIS_ENCODING_SKIPLIST);

server.dirty++;

added++;

}

} else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {

zset *zs = zobj->ptr;

zskiplistNode *znode;

dictEntry *de;

/*存储结构为skiplist时, 首先从hash表中通过member查找到score, 同样找到删除原来的, 找不到则直接插入*/

ele = c->argv[3+j*2] = tryObjectEncoding(c->argv[3+j*2]);

de = dictFind(zs->dict,ele);

if (de != NULL) {

curobj = dictGetKey(de);

curscore = *(double*)dictGetVal(de);

if (incr) {

score += curscore;

if (isnan(score)) {

addReplyError(c,nanerr);

goto cleanup;

}

}

/* member和score完全一样, 则不进行任何操作*/

if (score != curscore) {

redisAssert

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值