mirror of
https://github.com/fluencelabs/redis
synced 2025-03-21 01:50:50 +00:00
update list iteration semantic to work as expected (i.e. "while(lNext(..))")
This commit is contained in:
parent
6a8e35ad92
commit
be02a7c0d6
130
redis.c
130
redis.c
@ -4806,7 +4806,7 @@ static robj *lPop(robj *subject, int where) {
|
|||||||
value = createStringObjectFromLongLong(vval);
|
value = createStringObjectFromLongLong(vval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
subject->ptr = ziplistDelete(subject->ptr,&p,ZIPLIST_TAIL);
|
subject->ptr = ziplistDelete(subject->ptr,&p);
|
||||||
} else if (subject->encoding == REDIS_ENCODING_LIST) {
|
} else if (subject->encoding == REDIS_ENCODING_LIST) {
|
||||||
list *list = subject->ptr;
|
list *list = subject->ptr;
|
||||||
listNode *ln;
|
listNode *ln;
|
||||||
@ -4840,15 +4840,24 @@ static unsigned long lLength(robj *subject) {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
robj *subject;
|
robj *subject;
|
||||||
unsigned char encoding;
|
unsigned char encoding;
|
||||||
|
unsigned char direction; /* Iteration direction */
|
||||||
unsigned char *zi;
|
unsigned char *zi;
|
||||||
listNode *ln;
|
listNode *ln;
|
||||||
} lIterator;
|
} lIterator;
|
||||||
|
|
||||||
|
/* Structure for an entry while iterating over a list. */
|
||||||
|
typedef struct {
|
||||||
|
lIterator *li;
|
||||||
|
unsigned char *zi; /* Entry in ziplist */
|
||||||
|
listNode *ln; /* Entry in linked list */
|
||||||
|
} lEntry;
|
||||||
|
|
||||||
/* Initialize an iterator at the specified index. */
|
/* Initialize an iterator at the specified index. */
|
||||||
static lIterator *lInitIterator(robj *subject, int index) {
|
static lIterator *lInitIterator(robj *subject, int index, unsigned char direction) {
|
||||||
lIterator *li = zmalloc(sizeof(lIterator));
|
lIterator *li = zmalloc(sizeof(lIterator));
|
||||||
li->subject = subject;
|
li->subject = subject;
|
||||||
li->encoding = subject->encoding;
|
li->encoding = subject->encoding;
|
||||||
|
li->direction = direction;
|
||||||
if (li->encoding == REDIS_ENCODING_ZIPLIST) {
|
if (li->encoding == REDIS_ENCODING_ZIPLIST) {
|
||||||
li->zi = ziplistIndex(subject->ptr,index);
|
li->zi = ziplistIndex(subject->ptr,index);
|
||||||
} else if (li->encoding == REDIS_ENCODING_LIST) {
|
} else if (li->encoding == REDIS_ENCODING_LIST) {
|
||||||
@ -4864,26 +4873,45 @@ static void lReleaseIterator(lIterator *li) {
|
|||||||
zfree(li);
|
zfree(li);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Whether the entry pointed at is a valid entry. */
|
/* Stores pointer to current the entry in the provided entry structure
|
||||||
static int lIsEntry(lIterator *li) {
|
* and advances the position of the iterator. Returns 1 when the current
|
||||||
|
* entry is in fact an entry, 0 otherwise. */
|
||||||
|
static int lNext(lIterator *li, lEntry *entry) {
|
||||||
|
entry->li = li;
|
||||||
if (li->encoding == REDIS_ENCODING_ZIPLIST) {
|
if (li->encoding == REDIS_ENCODING_ZIPLIST) {
|
||||||
return li->zi != NULL;
|
entry->zi = li->zi;
|
||||||
|
if (entry->zi != NULL) {
|
||||||
|
if (li->direction == REDIS_TAIL)
|
||||||
|
li->zi = ziplistNext(li->subject->ptr,li->zi);
|
||||||
|
else
|
||||||
|
li->zi = ziplistPrev(li->subject->ptr,li->zi);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
} else if (li->encoding == REDIS_ENCODING_LIST) {
|
} else if (li->encoding == REDIS_ENCODING_LIST) {
|
||||||
return li->ln != NULL;
|
entry->ln = li->ln;
|
||||||
|
if (entry->ln != NULL) {
|
||||||
|
if (li->direction == REDIS_TAIL)
|
||||||
|
li->ln = li->ln->next;
|
||||||
|
else
|
||||||
|
li->ln = li->ln->prev;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
redisPanic("Unknown list encoding");
|
redisPanic("Unknown list encoding");
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return entry or NULL at the current position of the iterator. */
|
/* Return entry or NULL at the current position of the iterator. */
|
||||||
static robj *lGet(lIterator *li) {
|
static robj *lGet(lEntry *entry) {
|
||||||
|
lIterator *li = entry->li;
|
||||||
robj *value = NULL;
|
robj *value = NULL;
|
||||||
if (li->encoding == REDIS_ENCODING_ZIPLIST) {
|
if (li->encoding == REDIS_ENCODING_ZIPLIST) {
|
||||||
char *v;
|
char *v;
|
||||||
unsigned int vlen;
|
unsigned int vlen;
|
||||||
long long vval;
|
long long vval;
|
||||||
redisAssert(li->zi != NULL);
|
redisAssert(entry->zi != NULL);
|
||||||
if (ziplistGet(li->zi,&v,&vlen,&vval)) {
|
if (ziplistGet(entry->zi,&v,&vlen,&vval)) {
|
||||||
if (v) {
|
if (v) {
|
||||||
value = createStringObject(v,vlen);
|
value = createStringObject(v,vlen);
|
||||||
} else {
|
} else {
|
||||||
@ -4891,8 +4919,8 @@ static robj *lGet(lIterator *li) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (li->encoding == REDIS_ENCODING_LIST) {
|
} else if (li->encoding == REDIS_ENCODING_LIST) {
|
||||||
redisAssert(li->ln != NULL);
|
redisAssert(entry->ln != NULL);
|
||||||
value = listNodeValue(li->ln);
|
value = listNodeValue(entry->ln);
|
||||||
incrRefCount(value);
|
incrRefCount(value);
|
||||||
} else {
|
} else {
|
||||||
redisPanic("Unknown list encoding");
|
redisPanic("Unknown list encoding");
|
||||||
@ -4900,50 +4928,39 @@ static robj *lGet(lIterator *li) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Delete the element pointed to. */
|
|
||||||
static void lDelete(lIterator *li, int direction) {
|
|
||||||
if (li->encoding == REDIS_ENCODING_ZIPLIST) {
|
|
||||||
direction = (direction == REDIS_HEAD) ? ZIPLIST_HEAD : ZIPLIST_TAIL;
|
|
||||||
li->subject->ptr = ziplistDelete(li->subject->ptr,&li->zi,direction);
|
|
||||||
} else if (li->encoding == REDIS_ENCODING_LIST) {
|
|
||||||
listNode *next;
|
|
||||||
if (direction == REDIS_HEAD)
|
|
||||||
next = li->ln->prev;
|
|
||||||
else
|
|
||||||
next = li->ln->next;
|
|
||||||
listDelNode(li->subject->ptr,li->ln);
|
|
||||||
li->ln = next;
|
|
||||||
} else {
|
|
||||||
redisPanic("Unknown list encoding");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Compare the given object with the entry at the current position. */
|
/* Compare the given object with the entry at the current position. */
|
||||||
static int lEqualTo(lIterator *li, robj *o) {
|
static int lEqual(lEntry *entry, robj *o) {
|
||||||
|
lIterator *li = entry->li;
|
||||||
if (li->encoding == REDIS_ENCODING_ZIPLIST) {
|
if (li->encoding == REDIS_ENCODING_ZIPLIST) {
|
||||||
redisAssert(o->encoding == REDIS_ENCODING_RAW);
|
redisAssert(o->encoding == REDIS_ENCODING_RAW);
|
||||||
return ziplistCompare(li->zi,o->ptr,sdslen(o->ptr));
|
return ziplistCompare(entry->zi,o->ptr,sdslen(o->ptr));
|
||||||
} else if (li->encoding == REDIS_ENCODING_LIST) {
|
} else if (li->encoding == REDIS_ENCODING_LIST) {
|
||||||
return equalStringObjects(o,listNodeValue(li->ln));
|
return equalStringObjects(o,listNodeValue(entry->ln));
|
||||||
} else {
|
} else {
|
||||||
redisPanic("Unknown list encoding");
|
redisPanic("Unknown list encoding");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move to the next or previous entry in the list. */
|
/* Delete the element pointed to. */
|
||||||
static void lMove(lIterator *li, int where) {
|
static void lDelete(lEntry *entry) {
|
||||||
|
lIterator *li = entry->li;
|
||||||
if (li->encoding == REDIS_ENCODING_ZIPLIST) {
|
if (li->encoding == REDIS_ENCODING_ZIPLIST) {
|
||||||
redisAssert(li->zi != NULL);
|
unsigned char *p = entry->zi;
|
||||||
if (where == REDIS_HEAD)
|
li->subject->ptr = ziplistDelete(li->subject->ptr,&p);
|
||||||
li->zi = ziplistPrev(li->zi);
|
|
||||||
|
/* Update position of the iterator depending on the direction */
|
||||||
|
if (li->direction == REDIS_TAIL)
|
||||||
|
li->zi = p;
|
||||||
else
|
else
|
||||||
li->zi = ziplistNext(li->zi);
|
li->zi = ziplistPrev(li->subject->ptr,p);
|
||||||
} else if (li->encoding == REDIS_ENCODING_LIST) {
|
} else if (entry->li->encoding == REDIS_ENCODING_LIST) {
|
||||||
redisAssert(li->ln != NULL);
|
listNode *next;
|
||||||
if (where == REDIS_HEAD)
|
if (li->direction == REDIS_TAIL)
|
||||||
li->ln = li->ln->prev;
|
next = entry->ln->next;
|
||||||
else
|
else
|
||||||
li->ln = li->ln->next;
|
next = entry->ln->prev;
|
||||||
|
listDelNode(li->subject->ptr,entry->ln);
|
||||||
|
li->ln = next;
|
||||||
} else {
|
} else {
|
||||||
redisPanic("Unknown list encoding");
|
redisPanic("Unknown list encoding");
|
||||||
}
|
}
|
||||||
@ -5037,7 +5054,7 @@ static void lsetCommand(redisClient *c) {
|
|||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
addReply(c,shared.outofrangeerr);
|
addReply(c,shared.outofrangeerr);
|
||||||
} else {
|
} else {
|
||||||
o->ptr = ziplistDelete(o->ptr,&p,ZIPLIST_TAIL);
|
o->ptr = ziplistDelete(o->ptr,&p);
|
||||||
value = getDecodedObject(value);
|
value = getDecodedObject(value);
|
||||||
o->ptr = ziplistInsert(o->ptr,p,value->ptr,sdslen(value->ptr));
|
o->ptr = ziplistInsert(o->ptr,p,value->ptr,sdslen(value->ptr));
|
||||||
decrRefCount(value);
|
decrRefCount(value);
|
||||||
@ -5089,6 +5106,7 @@ static void lrangeCommand(redisClient *c) {
|
|||||||
int end = atoi(c->argv[3]->ptr);
|
int end = atoi(c->argv[3]->ptr);
|
||||||
int llen;
|
int llen;
|
||||||
int rangelen, j;
|
int rangelen, j;
|
||||||
|
lEntry entry;
|
||||||
|
|
||||||
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptymultibulk)) == NULL
|
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptymultibulk)) == NULL
|
||||||
|| checkType(c,o,REDIS_LIST)) return;
|
|| checkType(c,o,REDIS_LIST)) return;
|
||||||
@ -5111,12 +5129,12 @@ static void lrangeCommand(redisClient *c) {
|
|||||||
|
|
||||||
/* Return the result in form of a multi-bulk reply */
|
/* Return the result in form of a multi-bulk reply */
|
||||||
addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",rangelen));
|
addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",rangelen));
|
||||||
lIterator *li = lInitIterator(o,start);
|
lIterator *li = lInitIterator(o,start,REDIS_TAIL);
|
||||||
for (j = 0; j < rangelen; j++) {
|
for (j = 0; j < rangelen; j++) {
|
||||||
value = lGet(li);
|
redisAssert(lNext(li,&entry));
|
||||||
redisAssert(value != NULL);
|
value = lGet(&entry);
|
||||||
addReplyBulk(c,value);
|
addReplyBulk(c,value);
|
||||||
lMove(li,REDIS_TAIL);
|
decrRefCount(value);
|
||||||
}
|
}
|
||||||
lReleaseIterator(li);
|
lReleaseIterator(li);
|
||||||
}
|
}
|
||||||
@ -5177,7 +5195,7 @@ static void lremCommand(redisClient *c) {
|
|||||||
robj *subject, *obj = c->argv[3];
|
robj *subject, *obj = c->argv[3];
|
||||||
int toremove = atoi(c->argv[2]->ptr);
|
int toremove = atoi(c->argv[2]->ptr);
|
||||||
int removed = 0;
|
int removed = 0;
|
||||||
int direction;
|
lEntry entry;
|
||||||
|
|
||||||
subject = lookupKeyWriteOrReply(c,c->argv[1],shared.czero);
|
subject = lookupKeyWriteOrReply(c,c->argv[1],shared.czero);
|
||||||
if (subject == NULL || checkType(c,subject,REDIS_LIST)) return;
|
if (subject == NULL || checkType(c,subject,REDIS_LIST)) return;
|
||||||
@ -5189,21 +5207,17 @@ static void lremCommand(redisClient *c) {
|
|||||||
lIterator *li;
|
lIterator *li;
|
||||||
if (toremove < 0) {
|
if (toremove < 0) {
|
||||||
toremove = -toremove;
|
toremove = -toremove;
|
||||||
direction = REDIS_HEAD;
|
li = lInitIterator(subject,-1,REDIS_HEAD);
|
||||||
li = lInitIterator(subject,-1);
|
|
||||||
} else {
|
} else {
|
||||||
direction = REDIS_TAIL;
|
li = lInitIterator(subject,0,REDIS_TAIL);
|
||||||
li = lInitIterator(subject,0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (lIsEntry(li)) {
|
while (lNext(li,&entry)) {
|
||||||
if (lEqualTo(li,obj)) {
|
if (lEqual(&entry,obj)) {
|
||||||
lDelete(li,direction);
|
lDelete(&entry);
|
||||||
server.dirty++;
|
server.dirty++;
|
||||||
removed++;
|
removed++;
|
||||||
if (toremove && removed == toremove) break;
|
if (toremove && removed == toremove) break;
|
||||||
} else {
|
|
||||||
lMove(li,direction);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lReleaseIterator(li);
|
lReleaseIterator(li);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user