mirror of
https://github.com/fluencelabs/redis
synced 2025-03-31 14:51:04 +00:00
Lazyfree: Sorted sets convereted to plain SDS. (several commits squashed)
This commit is contained in:
parent
86d48efbfd
commit
a7c5be18a8
@ -826,7 +826,7 @@ int rewriteSetObject(rio *r, robj *key, robj *o) {
|
|||||||
dictEntry *de;
|
dictEntry *de;
|
||||||
|
|
||||||
while((de = dictNext(di)) != NULL) {
|
while((de = dictNext(di)) != NULL) {
|
||||||
robj *eleobj = dictGetKey(de);
|
sds ele = dictGetKey(de);
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
int cmd_items = (items > AOF_REWRITE_ITEMS_PER_CMD) ?
|
int cmd_items = (items > AOF_REWRITE_ITEMS_PER_CMD) ?
|
||||||
AOF_REWRITE_ITEMS_PER_CMD : items;
|
AOF_REWRITE_ITEMS_PER_CMD : items;
|
||||||
@ -835,7 +835,7 @@ int rewriteSetObject(rio *r, robj *key, robj *o) {
|
|||||||
if (rioWriteBulkString(r,"SADD",4) == 0) return 0;
|
if (rioWriteBulkString(r,"SADD",4) == 0) return 0;
|
||||||
if (rioWriteBulkObject(r,key) == 0) return 0;
|
if (rioWriteBulkObject(r,key) == 0) return 0;
|
||||||
}
|
}
|
||||||
if (rioWriteBulkObject(r,eleobj) == 0) return 0;
|
if (rioWriteBulkString(r,ele,sdslen(ele)) == 0) return 0;
|
||||||
if (++count == AOF_REWRITE_ITEMS_PER_CMD) count = 0;
|
if (++count == AOF_REWRITE_ITEMS_PER_CMD) count = 0;
|
||||||
items--;
|
items--;
|
||||||
}
|
}
|
||||||
@ -892,7 +892,7 @@ int rewriteSortedSetObject(rio *r, robj *key, robj *o) {
|
|||||||
dictEntry *de;
|
dictEntry *de;
|
||||||
|
|
||||||
while((de = dictNext(di)) != NULL) {
|
while((de = dictNext(di)) != NULL) {
|
||||||
robj *eleobj = dictGetKey(de);
|
sds ele = dictGetKey(de);
|
||||||
double *score = dictGetVal(de);
|
double *score = dictGetVal(de);
|
||||||
|
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
@ -904,7 +904,7 @@ int rewriteSortedSetObject(rio *r, robj *key, robj *o) {
|
|||||||
if (rioWriteBulkObject(r,key) == 0) return 0;
|
if (rioWriteBulkObject(r,key) == 0) return 0;
|
||||||
}
|
}
|
||||||
if (rioWriteBulkDouble(r,*score) == 0) return 0;
|
if (rioWriteBulkDouble(r,*score) == 0) return 0;
|
||||||
if (rioWriteBulkObject(r,eleobj) == 0) return 0;
|
if (rioWriteBulkString(r,ele,sdslen(ele)) == 0) return 0;
|
||||||
if (++count == AOF_REWRITE_ITEMS_PER_CMD) count = 0;
|
if (++count == AOF_REWRITE_ITEMS_PER_CMD) count = 0;
|
||||||
items--;
|
items--;
|
||||||
}
|
}
|
||||||
|
@ -4087,7 +4087,10 @@ void clusterCommand(client *c) {
|
|||||||
keys = zmalloc(sizeof(robj*)*maxkeys);
|
keys = zmalloc(sizeof(robj*)*maxkeys);
|
||||||
numkeys = getKeysInSlot(slot, keys, maxkeys);
|
numkeys = getKeysInSlot(slot, keys, maxkeys);
|
||||||
addReplyMultiBulkLen(c,numkeys);
|
addReplyMultiBulkLen(c,numkeys);
|
||||||
for (j = 0; j < numkeys; j++) addReplyBulk(c,keys[j]);
|
for (j = 0; j < numkeys; j++) {
|
||||||
|
addReplyBulk(c,keys[j]);
|
||||||
|
decrRefCount(keys[j]);
|
||||||
|
}
|
||||||
zfree(keys);
|
zfree(keys);
|
||||||
} else if (!strcasecmp(c->argv[1]->ptr,"forget") && c->argc == 3) {
|
} else if (!strcasecmp(c->argv[1]->ptr,"forget") && c->argc == 3) {
|
||||||
/* CLUSTER FORGET <NODE ID> */
|
/* CLUSTER FORGET <NODE ID> */
|
||||||
|
24
src/db.c
24
src/db.c
@ -423,8 +423,8 @@ void scanCallback(void *privdata, const dictEntry *de) {
|
|||||||
val = dictGetVal(de);
|
val = dictGetVal(de);
|
||||||
incrRefCount(val);
|
incrRefCount(val);
|
||||||
} else if (o->type == OBJ_ZSET) {
|
} else if (o->type == OBJ_ZSET) {
|
||||||
key = dictGetKey(de);
|
sds keysds = dictGetKey(de);
|
||||||
incrRefCount(key);
|
key = createStringObject(keysds,sdslen(keysds));
|
||||||
val = createStringObjectFromLongDouble(*(double*)dictGetVal(de),0);
|
val = createStringObjectFromLongDouble(*(double*)dictGetVal(de),0);
|
||||||
} else {
|
} else {
|
||||||
serverPanic("Type not handled in SCAN callback.");
|
serverPanic("Type not handled in SCAN callback.");
|
||||||
@ -1181,14 +1181,13 @@ int *sortGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys)
|
|||||||
void slotToKeyAdd(robj *key) {
|
void slotToKeyAdd(robj *key) {
|
||||||
unsigned int hashslot = keyHashSlot(key->ptr,sdslen(key->ptr));
|
unsigned int hashslot = keyHashSlot(key->ptr,sdslen(key->ptr));
|
||||||
|
|
||||||
zslInsert(server.cluster->slots_to_keys,hashslot,key);
|
sds sdskey = sdsdup(key->ptr);
|
||||||
incrRefCount(key);
|
zslInsert(server.cluster->slots_to_keys,hashslot,sdskey);
|
||||||
}
|
}
|
||||||
|
|
||||||
void slotToKeyDel(robj *key) {
|
void slotToKeyDel(robj *key) {
|
||||||
unsigned int hashslot = keyHashSlot(key->ptr,sdslen(key->ptr));
|
unsigned int hashslot = keyHashSlot(key->ptr,sdslen(key->ptr));
|
||||||
|
zslDelete(server.cluster->slots_to_keys,hashslot,key->ptr,NULL);
|
||||||
zslDelete(server.cluster->slots_to_keys,hashslot,key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void slotToKeyFlush(void) {
|
void slotToKeyFlush(void) {
|
||||||
@ -1196,6 +1195,9 @@ void slotToKeyFlush(void) {
|
|||||||
server.cluster->slots_to_keys = zslCreate();
|
server.cluster->slots_to_keys = zslCreate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Pupulate the specified array of objects with keys in the specified slot.
|
||||||
|
* New objects are returned to represent keys, it's up to the caller to
|
||||||
|
* decrement the reference count to release the keys names. */
|
||||||
unsigned int getKeysInSlot(unsigned int hashslot, robj **keys, unsigned int count) {
|
unsigned int getKeysInSlot(unsigned int hashslot, robj **keys, unsigned int count) {
|
||||||
zskiplistNode *n;
|
zskiplistNode *n;
|
||||||
zrangespec range;
|
zrangespec range;
|
||||||
@ -1206,7 +1208,7 @@ unsigned int getKeysInSlot(unsigned int hashslot, robj **keys, unsigned int coun
|
|||||||
|
|
||||||
n = zslFirstInRange(server.cluster->slots_to_keys, &range);
|
n = zslFirstInRange(server.cluster->slots_to_keys, &range);
|
||||||
while(n && n->score == hashslot && count--) {
|
while(n && n->score == hashslot && count--) {
|
||||||
keys[j++] = n->obj;
|
keys[j++] = createStringObject(n->ele,sdslen(n->ele));
|
||||||
n = n->level[0].forward;
|
n = n->level[0].forward;
|
||||||
}
|
}
|
||||||
return j;
|
return j;
|
||||||
@ -1224,9 +1226,9 @@ unsigned int delKeysInSlot(unsigned int hashslot) {
|
|||||||
|
|
||||||
n = zslFirstInRange(server.cluster->slots_to_keys, &range);
|
n = zslFirstInRange(server.cluster->slots_to_keys, &range);
|
||||||
while(n && n->score == hashslot) {
|
while(n && n->score == hashslot) {
|
||||||
robj *key = n->obj;
|
sds sdskey = n->ele;
|
||||||
|
robj *key = createStringObject(sdskey,sdslen(sdskey));
|
||||||
n = n->level[0].forward; /* Go to the next item before freeing it. */
|
n = n->level[0].forward; /* Go to the next item before freeing it. */
|
||||||
incrRefCount(key); /* Protect the object while freeing it. */
|
|
||||||
dbDelete(&server.db[0],key);
|
dbDelete(&server.db[0],key);
|
||||||
decrRefCount(key);
|
decrRefCount(key);
|
||||||
j++;
|
j++;
|
||||||
@ -1248,7 +1250,7 @@ unsigned int countKeysInSlot(unsigned int hashslot) {
|
|||||||
|
|
||||||
/* Use rank of first element, if any, to determine preliminary count */
|
/* Use rank of first element, if any, to determine preliminary count */
|
||||||
if (zn != NULL) {
|
if (zn != NULL) {
|
||||||
rank = zslGetRank(zsl, zn->score, zn->obj);
|
rank = zslGetRank(zsl, zn->score, zn->ele);
|
||||||
count = (zsl->length - (rank - 1));
|
count = (zsl->length - (rank - 1));
|
||||||
|
|
||||||
/* Find last element in range */
|
/* Find last element in range */
|
||||||
@ -1256,7 +1258,7 @@ unsigned int countKeysInSlot(unsigned int hashslot) {
|
|||||||
|
|
||||||
/* Use rank of last element, if any, to determine the actual count */
|
/* Use rank of last element, if any, to determine the actual count */
|
||||||
if (zn != NULL) {
|
if (zn != NULL) {
|
||||||
rank = zslGetRank(zsl, zn->score, zn->obj);
|
rank = zslGetRank(zsl, zn->score, zn->ele);
|
||||||
count -= (zsl->length - rank);
|
count -= (zsl->length - rank);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,12 +163,9 @@ void computeDatasetDigest(unsigned char *final) {
|
|||||||
listTypeReleaseIterator(li);
|
listTypeReleaseIterator(li);
|
||||||
} else if (o->type == OBJ_SET) {
|
} else if (o->type == OBJ_SET) {
|
||||||
setTypeIterator *si = setTypeInitIterator(o);
|
setTypeIterator *si = setTypeInitIterator(o);
|
||||||
robj *ele;
|
|
||||||
sds sdsele;
|
sds sdsele;
|
||||||
while((sdsele = setTypeNextObject(si)) != NULL) {
|
while((sdsele = setTypeNextObject(si)) != NULL) {
|
||||||
ele = createObject(OBJ_STRING,sdsele);
|
xorDigest(digest,sdsele,sdslen(sdsele));
|
||||||
xorObjectDigest(digest,ele);
|
|
||||||
decrRefCount(ele);
|
|
||||||
}
|
}
|
||||||
setTypeReleaseIterator(si);
|
setTypeReleaseIterator(si);
|
||||||
} else if (o->type == OBJ_ZSET) {
|
} else if (o->type == OBJ_ZSET) {
|
||||||
@ -210,12 +207,12 @@ void computeDatasetDigest(unsigned char *final) {
|
|||||||
dictEntry *de;
|
dictEntry *de;
|
||||||
|
|
||||||
while((de = dictNext(di)) != NULL) {
|
while((de = dictNext(di)) != NULL) {
|
||||||
robj *eleobj = dictGetKey(de);
|
sds sdsele = dictGetKey(de);
|
||||||
double *score = dictGetVal(de);
|
double *score = dictGetVal(de);
|
||||||
|
|
||||||
snprintf(buf,sizeof(buf),"%.17g",*score);
|
snprintf(buf,sizeof(buf),"%.17g",*score);
|
||||||
memset(eledigest,0,20);
|
memset(eledigest,0,20);
|
||||||
mixObjectDigest(eledigest,eleobj);
|
mixDigest(eledigest,sdsele,sdslen(sdsele));
|
||||||
mixDigest(eledigest,buf,strlen(buf));
|
mixDigest(eledigest,buf,strlen(buf));
|
||||||
xorDigest(digest,eledigest,20);
|
xorDigest(digest,eledigest,20);
|
||||||
}
|
}
|
||||||
|
20
src/geo.c
20
src/geo.c
@ -112,7 +112,7 @@ int extractLongLatOrReply(client *c, robj **argv,
|
|||||||
int longLatFromMember(robj *zobj, robj *member, double *xy) {
|
int longLatFromMember(robj *zobj, robj *member, double *xy) {
|
||||||
double score = 0;
|
double score = 0;
|
||||||
|
|
||||||
if (zsetScore(zobj, member, &score) == C_ERR) return C_ERR;
|
if (zsetScore(zobj, member->ptr, &score) == C_ERR) return C_ERR;
|
||||||
if (!decodeGeohash(score, xy)) return C_ERR;
|
if (!decodeGeohash(score, xy)) return C_ERR;
|
||||||
return C_OK;
|
return C_OK;
|
||||||
}
|
}
|
||||||
@ -261,16 +261,14 @@ int geoGetPointsInRange(robj *zobj, double min, double max, double lon, double l
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (ln) {
|
while (ln) {
|
||||||
robj *o = ln->obj;
|
sds ele = ln->ele;
|
||||||
/* Abort when the node is no longer in range. */
|
/* Abort when the node is no longer in range. */
|
||||||
if (!zslValueLteMax(ln->score, &range))
|
if (!zslValueLteMax(ln->score, &range))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
member = (o->encoding == OBJ_ENCODING_INT) ?
|
ele = sdsdup(ele);
|
||||||
sdsfromlonglong((long)o->ptr) :
|
if (geoAppendIfWithinRadius(ga,lon,lat,radius,ln->score,ele)
|
||||||
sdsdup(o->ptr);
|
== C_ERR) sdsfree(ele);
|
||||||
if (geoAppendIfWithinRadius(ga,lon,lat,radius,ln->score,member)
|
|
||||||
== C_ERR) sdsfree(member);
|
|
||||||
ln = ln->level[0].forward;
|
ln = ln->level[0].forward;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -606,7 +604,7 @@ void geohashCommand(client *c) {
|
|||||||
addReplyMultiBulkLen(c,c->argc-2);
|
addReplyMultiBulkLen(c,c->argc-2);
|
||||||
for (j = 2; j < c->argc; j++) {
|
for (j = 2; j < c->argc; j++) {
|
||||||
double score;
|
double score;
|
||||||
if (zsetScore(zobj, c->argv[j], &score) == C_ERR) {
|
if (zsetScore(zobj, c->argv[j]->ptr, &score) == C_ERR) {
|
||||||
addReply(c,shared.nullbulk);
|
addReply(c,shared.nullbulk);
|
||||||
} else {
|
} else {
|
||||||
/* The internal format we use for geocoding is a bit different
|
/* The internal format we use for geocoding is a bit different
|
||||||
@ -660,7 +658,7 @@ void geoposCommand(client *c) {
|
|||||||
addReplyMultiBulkLen(c,c->argc-2);
|
addReplyMultiBulkLen(c,c->argc-2);
|
||||||
for (j = 2; j < c->argc; j++) {
|
for (j = 2; j < c->argc; j++) {
|
||||||
double score;
|
double score;
|
||||||
if (zsetScore(zobj, c->argv[j], &score) == C_ERR) {
|
if (zsetScore(zobj, c->argv[j]->ptr, &score) == C_ERR) {
|
||||||
addReply(c,shared.nullmultibulk);
|
addReply(c,shared.nullmultibulk);
|
||||||
} else {
|
} else {
|
||||||
/* Decode... */
|
/* Decode... */
|
||||||
@ -700,8 +698,8 @@ void geodistCommand(client *c) {
|
|||||||
|
|
||||||
/* Get the scores. We need both otherwise NULL is returned. */
|
/* Get the scores. We need both otherwise NULL is returned. */
|
||||||
double score1, score2, xyxy[4];
|
double score1, score2, xyxy[4];
|
||||||
if (zsetScore(zobj, c->argv[2], &score1) == C_ERR ||
|
if (zsetScore(zobj, c->argv[2]->ptr, &score1) == C_ERR ||
|
||||||
zsetScore(zobj, c->argv[3], &score2) == C_ERR)
|
zsetScore(zobj, c->argv[3]->ptr, &score2) == C_ERR)
|
||||||
{
|
{
|
||||||
addReply(c,shared.nullbulk);
|
addReply(c,shared.nullbulk);
|
||||||
return;
|
return;
|
||||||
|
27
src/rdb.c
27
src/rdb.c
@ -622,10 +622,11 @@ ssize_t rdbSaveObject(rio *rdb, robj *o) {
|
|||||||
nwritten += n;
|
nwritten += n;
|
||||||
|
|
||||||
while((de = dictNext(di)) != NULL) {
|
while((de = dictNext(di)) != NULL) {
|
||||||
robj *eleobj = dictGetKey(de);
|
sds ele = dictGetKey(de);
|
||||||
double *score = dictGetVal(de);
|
double *score = dictGetVal(de);
|
||||||
|
|
||||||
if ((n = rdbSaveStringObject(rdb,eleobj)) == -1) return -1;
|
if ((n = rdbSaveRawString(rdb,(unsigned char*)ele,sdslen(ele)))
|
||||||
|
== -1) return -1;
|
||||||
nwritten += n;
|
nwritten += n;
|
||||||
if ((n = rdbSaveDoubleValue(rdb,*score)) == -1) return -1;
|
if ((n = rdbSaveDoubleValue(rdb,*score)) == -1) return -1;
|
||||||
nwritten += n;
|
nwritten += n;
|
||||||
@ -992,7 +993,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (o->encoding == OBJ_ENCODING_INTSET) {
|
if (o->encoding == OBJ_ENCODING_INTSET) {
|
||||||
/* Fetch integer value from element */
|
/* Fetch integer value from element. */
|
||||||
if (isSdsRepresentableAsLongLong(sdsele,&llval) == C_OK) {
|
if (isSdsRepresentableAsLongLong(sdsele,&llval) == C_OK) {
|
||||||
o->ptr = intsetAdd(o->ptr,llval,NULL);
|
o->ptr = intsetAdd(o->ptr,llval,NULL);
|
||||||
} else {
|
} else {
|
||||||
@ -1002,7 +1003,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* This will also be called when the set was just converted
|
/* This will also be called when the set was just converted
|
||||||
* to a regular hash table encoded set */
|
* to a regular hash table encoded set. */
|
||||||
if (o->encoding == OBJ_ENCODING_HT) {
|
if (o->encoding == OBJ_ENCODING_HT) {
|
||||||
dictAdd((dict*)o->ptr,sdsele,NULL);
|
dictAdd((dict*)o->ptr,sdsele,NULL);
|
||||||
} else {
|
} else {
|
||||||
@ -1010,7 +1011,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (rdbtype == RDB_TYPE_ZSET) {
|
} else if (rdbtype == RDB_TYPE_ZSET) {
|
||||||
/* Read list/set value */
|
/* Read list/set value. */
|
||||||
size_t zsetlen;
|
size_t zsetlen;
|
||||||
size_t maxelelen = 0;
|
size_t maxelelen = 0;
|
||||||
zset *zs;
|
zset *zs;
|
||||||
@ -1019,23 +1020,21 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
|
|||||||
o = createZsetObject();
|
o = createZsetObject();
|
||||||
zs = o->ptr;
|
zs = o->ptr;
|
||||||
|
|
||||||
/* Load every single element of the list/set */
|
/* Load every single element of the sorted set. */
|
||||||
while(zsetlen--) {
|
while(zsetlen--) {
|
||||||
robj *ele;
|
sds sdsele;
|
||||||
double score;
|
double score;
|
||||||
zskiplistNode *znode;
|
zskiplistNode *znode;
|
||||||
|
|
||||||
if ((ele = rdbLoadEncodedStringObject(rdb)) == NULL) return NULL;
|
if ((sdsele = rdbGenericLoadStringObject(rdb,RDB_LOAD_SDS)) == NULL)
|
||||||
ele = tryObjectEncoding(ele);
|
return NULL;
|
||||||
if (rdbLoadDoubleValue(rdb,&score) == -1) return NULL;
|
if (rdbLoadDoubleValue(rdb,&score) == -1) return NULL;
|
||||||
|
|
||||||
/* Don't care about integer-encoded strings. */
|
/* Don't care about integer-encoded strings. */
|
||||||
if (sdsEncodedObject(ele) && sdslen(ele->ptr) > maxelelen)
|
if (sdslen(sdsele) > maxelelen) maxelelen = sdslen(sdsele);
|
||||||
maxelelen = sdslen(ele->ptr);
|
|
||||||
|
|
||||||
znode = zslInsert(zs->zsl,score,ele);
|
znode = zslInsert(zs->zsl,score,sdsele);
|
||||||
dictAdd(zs->dict,ele,&znode->score);
|
dictAdd(zs->dict,sdsele,&znode->score);
|
||||||
incrRefCount(ele); /* added to skiplist */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert *after* loading, since sorted sets are not stored ordered. */
|
/* Convert *after* loading, since sorted sets are not stored ordered. */
|
||||||
|
10
src/server.c
10
src/server.c
@ -554,11 +554,11 @@ dictType setDictType = {
|
|||||||
|
|
||||||
/* Sorted sets hash (note: a skiplist is used in addition to the hash table) */
|
/* Sorted sets hash (note: a skiplist is used in addition to the hash table) */
|
||||||
dictType zsetDictType = {
|
dictType zsetDictType = {
|
||||||
dictEncObjHash, /* hash function */
|
dictSdsHash, /* hash function */
|
||||||
NULL, /* key dup */
|
NULL, /* key dup */
|
||||||
NULL, /* val dup */
|
NULL, /* val dup */
|
||||||
dictEncObjKeyCompare, /* key compare */
|
dictSdsKeyCompare, /* key compare */
|
||||||
dictObjectDestructor, /* key destructor */
|
NULL, /* Note: SDS string shared & freed by skiplist */
|
||||||
NULL /* val destructor */
|
NULL /* val destructor */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1428,8 +1428,8 @@ void createSharedObjects(void) {
|
|||||||
* actually used for their value but as a special object meaning
|
* actually used for their value but as a special object meaning
|
||||||
* respectively the minimum possible string and the maximum possible
|
* respectively the minimum possible string and the maximum possible
|
||||||
* string in string comparisons for the ZRANGEBYLEX command. */
|
* string in string comparisons for the ZRANGEBYLEX command. */
|
||||||
shared.minstring = createStringObject("minstring",9);
|
shared.minstring = sdsnew("minstring");
|
||||||
shared.maxstring = createStringObject("maxstring",9);
|
shared.maxstring = sdsnew("maxstring");
|
||||||
}
|
}
|
||||||
|
|
||||||
void initServerConfig(void) {
|
void initServerConfig(void) {
|
||||||
|
17
src/server.h
17
src/server.h
@ -612,16 +612,17 @@ struct sharedObjectsStruct {
|
|||||||
*masterdownerr, *roslaveerr, *execaborterr, *noautherr, *noreplicaserr,
|
*masterdownerr, *roslaveerr, *execaborterr, *noautherr, *noreplicaserr,
|
||||||
*busykeyerr, *oomerr, *plus, *messagebulk, *pmessagebulk, *subscribebulk,
|
*busykeyerr, *oomerr, *plus, *messagebulk, *pmessagebulk, *subscribebulk,
|
||||||
*unsubscribebulk, *psubscribebulk, *punsubscribebulk, *del, *rpop, *lpop,
|
*unsubscribebulk, *psubscribebulk, *punsubscribebulk, *del, *rpop, *lpop,
|
||||||
*lpush, *emptyscan, *minstring, *maxstring,
|
*lpush, *emptyscan,
|
||||||
*select[PROTO_SHARED_SELECT_CMDS],
|
*select[PROTO_SHARED_SELECT_CMDS],
|
||||||
*integers[OBJ_SHARED_INTEGERS],
|
*integers[OBJ_SHARED_INTEGERS],
|
||||||
*mbulkhdr[OBJ_SHARED_BULKHDR_LEN], /* "*<value>\r\n" */
|
*mbulkhdr[OBJ_SHARED_BULKHDR_LEN], /* "*<value>\r\n" */
|
||||||
*bulkhdr[OBJ_SHARED_BULKHDR_LEN]; /* "$<value>\r\n" */
|
*bulkhdr[OBJ_SHARED_BULKHDR_LEN]; /* "$<value>\r\n" */
|
||||||
|
sds minstring, maxstring;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ZSETs use a specialized version of Skiplists */
|
/* ZSETs use a specialized version of Skiplists */
|
||||||
typedef struct zskiplistNode {
|
typedef struct zskiplistNode {
|
||||||
robj *obj;
|
sds ele;
|
||||||
double score;
|
double score;
|
||||||
struct zskiplistNode *backward;
|
struct zskiplistNode *backward;
|
||||||
struct zskiplistLevel {
|
struct zskiplistLevel {
|
||||||
@ -1261,15 +1262,15 @@ typedef struct {
|
|||||||
|
|
||||||
/* Struct to hold an inclusive/exclusive range spec by lexicographic comparison. */
|
/* Struct to hold an inclusive/exclusive range spec by lexicographic comparison. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
robj *min, *max; /* May be set to shared.(minstring|maxstring) */
|
sds min, max; /* May be set to shared.(minstring|maxstring) */
|
||||||
int minex, maxex; /* are min or max exclusive? */
|
int minex, maxex; /* are min or max exclusive? */
|
||||||
} zlexrangespec;
|
} zlexrangespec;
|
||||||
|
|
||||||
zskiplist *zslCreate(void);
|
zskiplist *zslCreate(void);
|
||||||
void zslFree(zskiplist *zsl);
|
void zslFree(zskiplist *zsl);
|
||||||
zskiplistNode *zslInsert(zskiplist *zsl, double score, robj *obj);
|
zskiplistNode *zslInsert(zskiplist *zsl, double score, sds ele);
|
||||||
unsigned char *zzlInsert(unsigned char *zl, robj *ele, double score);
|
unsigned char *zzlInsert(unsigned char *zl, sds ele, double score);
|
||||||
int zslDelete(zskiplist *zsl, double score, robj *obj);
|
int zslDelete(zskiplist *zsl, double score, sds ele, zskiplistNode **node);
|
||||||
zskiplistNode *zslFirstInRange(zskiplist *zsl, zrangespec *range);
|
zskiplistNode *zslFirstInRange(zskiplist *zsl, zrangespec *range);
|
||||||
zskiplistNode *zslLastInRange(zskiplist *zsl, zrangespec *range);
|
zskiplistNode *zslLastInRange(zskiplist *zsl, zrangespec *range);
|
||||||
double zzlGetScore(unsigned char *sptr);
|
double zzlGetScore(unsigned char *sptr);
|
||||||
@ -1277,8 +1278,8 @@ void zzlNext(unsigned char *zl, unsigned char **eptr, unsigned char **sptr);
|
|||||||
void zzlPrev(unsigned char *zl, unsigned char **eptr, unsigned char **sptr);
|
void zzlPrev(unsigned char *zl, unsigned char **eptr, unsigned char **sptr);
|
||||||
unsigned int zsetLength(robj *zobj);
|
unsigned int zsetLength(robj *zobj);
|
||||||
void zsetConvert(robj *zobj, int encoding);
|
void zsetConvert(robj *zobj, int encoding);
|
||||||
int zsetScore(robj *zobj, robj *member, double *score);
|
int zsetScore(robj *zobj, sds member, double *score);
|
||||||
unsigned long zslGetRank(zskiplist *zsl, double score, robj *o);
|
unsigned long zslGetRank(zskiplist *zsl, double score, sds o);
|
||||||
|
|
||||||
/* Core functions */
|
/* Core functions */
|
||||||
int freeMemoryIfNeeded(void);
|
int freeMemoryIfNeeded(void);
|
||||||
|
10
src/sort.c
10
src/sort.c
@ -399,7 +399,7 @@ void sortCommand(client *c) {
|
|||||||
zset *zs = sortval->ptr;
|
zset *zs = sortval->ptr;
|
||||||
zskiplist *zsl = zs->zsl;
|
zskiplist *zsl = zs->zsl;
|
||||||
zskiplistNode *ln;
|
zskiplistNode *ln;
|
||||||
robj *ele;
|
sds sdsele;
|
||||||
int rangelen = vectorlen;
|
int rangelen = vectorlen;
|
||||||
|
|
||||||
/* Check if starting point is trivial, before doing log(N) lookup. */
|
/* Check if starting point is trivial, before doing log(N) lookup. */
|
||||||
@ -417,8 +417,8 @@ void sortCommand(client *c) {
|
|||||||
|
|
||||||
while(rangelen--) {
|
while(rangelen--) {
|
||||||
serverAssertWithInfo(c,sortval,ln != NULL);
|
serverAssertWithInfo(c,sortval,ln != NULL);
|
||||||
ele = ln->obj;
|
sdsele = ln->ele;
|
||||||
vector[j].obj = ele;
|
vector[j].obj = createStringObject(sdsele,sdslen(sdsele));
|
||||||
vector[j].u.score = 0;
|
vector[j].u.score = 0;
|
||||||
vector[j].u.cmpobj = NULL;
|
vector[j].u.cmpobj = NULL;
|
||||||
j++;
|
j++;
|
||||||
@ -431,9 +431,11 @@ void sortCommand(client *c) {
|
|||||||
dict *set = ((zset*)sortval->ptr)->dict;
|
dict *set = ((zset*)sortval->ptr)->dict;
|
||||||
dictIterator *di;
|
dictIterator *di;
|
||||||
dictEntry *setele;
|
dictEntry *setele;
|
||||||
|
sds sdsele;
|
||||||
di = dictGetIterator(set);
|
di = dictGetIterator(set);
|
||||||
while((setele = dictNext(di)) != NULL) {
|
while((setele = dictNext(di)) != NULL) {
|
||||||
vector[j].obj = dictGetKey(setele);
|
sdsele = dictGetKey(setele);
|
||||||
|
vector[j].obj = createStringObject(sdsele,sdslen(sdsele));
|
||||||
vector[j].u.score = 0;
|
vector[j].u.score = 0;
|
||||||
vector[j].u.cmpobj = NULL;
|
vector[j].u.cmpobj = NULL;
|
||||||
j++;
|
j++;
|
||||||
|
442
src/t_zset.c
442
src/t_zset.c
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user