Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
dedff272
Commit
dedff272
authored
Jun 11, 2010
by
Robey Pointer
Committed by
Pieter Noordhuis
Jun 11, 2010
Browse files
squashed merge from robey/twitter3: LINSERT BEFORE|AFTER, LPUSHX, RPUSHX
parent
306974f5
Changes
5
Hide whitespace changes
Inline
Side-by-side
adlist.c
View file @
dedff272
...
...
@@ -123,6 +123,35 @@ list *listAddNodeTail(list *list, void *value)
return
list
;
}
list
*
listInsertNode
(
list
*
list
,
listNode
*
old_node
,
void
*
value
,
int
after
)
{
listNode
*
node
;
if
((
node
=
zmalloc
(
sizeof
(
*
node
)))
==
NULL
)
return
NULL
;
node
->
value
=
value
;
if
(
after
)
{
node
->
prev
=
old_node
;
node
->
next
=
old_node
->
next
;
if
(
list
->
tail
==
old_node
)
{
list
->
tail
=
node
;
}
}
else
{
node
->
next
=
old_node
;
node
->
prev
=
old_node
->
prev
;
if
(
list
->
head
==
old_node
)
{
list
->
head
=
node
;
}
}
if
(
node
->
prev
!=
NULL
)
{
node
->
prev
->
next
=
node
;
}
if
(
node
->
next
!=
NULL
)
{
node
->
next
->
prev
=
node
;
}
list
->
len
++
;
return
list
;
}
/* Remove the specified node from the specified list.
* It's up to the caller to free the private value of the node.
*
...
...
@@ -183,9 +212,9 @@ void listRewindTail(list *list, listIter *li) {
* or NULL if there are no more elements, so the classical usage patter
* is:
*
* iter = listGetIt
arot
r(list,<direction>);
* while ((node = listNext
Iterator
(iter)) != NULL) {
*
D
oSomethingWith(listNodeValue(node));
* iter = listGetIt
erato
r(list,<direction>);
* while ((node = listNext(iter)) != NULL) {
*
d
oSomethingWith(listNodeValue(node));
* }
*
* */
...
...
adlist.h
View file @
dedff272
...
...
@@ -74,6 +74,7 @@ list *listCreate(void);
void
listRelease
(
list
*
list
);
list
*
listAddNodeHead
(
list
*
list
,
void
*
value
);
list
*
listAddNodeTail
(
list
*
list
,
void
*
value
);
list
*
listInsertNode
(
list
*
list
,
listNode
*
old_node
,
void
*
value
,
int
after
);
void
listDelNode
(
list
*
list
,
listNode
*
node
);
listIter
*
listGetIterator
(
list
*
list
,
int
direction
);
listNode
*
listNext
(
listIter
*
iter
);
...
...
redis.c
View file @
dedff272
...
...
@@ -261,7 +261,7 @@ typedef struct redisObject {
unsigned
lru
:
22
;
/* lru time (relative to server.lruclock) */
int
refcount
;
void
*
ptr
;
/* VM fields
, this
are only allocated if VM is active, otherwise the
/* VM fields are only allocated if VM is active, otherwise the
* object allocation function will just allocate
* sizeof(redisObjct) minus sizeof(redisObjectVM), so using
* Redis without VM active will not have any overhead. */
...
...
@@ -692,6 +692,9 @@ static void renameCommand(redisClient *c);
static
void
renamenxCommand
(
redisClient
*
c
);
static
void
lpushCommand
(
redisClient
*
c
);
static
void
rpushCommand
(
redisClient
*
c
);
static
void
lpushxCommand
(
redisClient
*
c
);
static
void
rpushxCommand
(
redisClient
*
c
);
static
void
linsertCommand
(
redisClient
*
c
);
static
void
lpopCommand
(
redisClient
*
c
);
static
void
rpopCommand
(
redisClient
*
c
);
static
void
llenCommand
(
redisClient
*
c
);
...
...
@@ -792,6 +795,9 @@ static struct redisCommand readonlyCommandTable[] = {
{
"mget"
,
mgetCommand
,
-
2
,
REDIS_CMD_INLINE
,
NULL
,
1
,
-
1
,
1
},
{
"rpush"
,
rpushCommand
,
3
,
REDIS_CMD_BULK
|
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"lpush"
,
lpushCommand
,
3
,
REDIS_CMD_BULK
|
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"rpushx"
,
rpushxCommand
,
3
,
REDIS_CMD_BULK
|
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"lpushx"
,
lpushxCommand
,
3
,
REDIS_CMD_BULK
|
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"linsert"
,
linsertCommand
,
5
,
REDIS_CMD_BULK
|
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"rpop"
,
rpopCommand
,
2
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"lpop"
,
lpopCommand
,
2
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"brpop"
,
brpopCommand
,
-
3
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
...
...
@@ -5174,6 +5180,82 @@ static void rpushCommand(redisClient *c) {
pushGenericCommand
(
c
,
REDIS_TAIL
);
}
static
void
listTypeInsert
(
robj
*
subject
,
listTypeEntry
*
old_entry
,
robj
*
new_obj
,
int
where
)
{
listTypeTryConversion
(
subject
,
new_obj
);
if
(
subject
->
encoding
==
REDIS_ENCODING_ZIPLIST
)
{
if
(
where
==
REDIS_HEAD
)
{
unsigned
char
*
next
=
ziplistNext
(
subject
->
ptr
,
old_entry
->
zi
);
if
(
next
==
NULL
)
{
listTypePush
(
subject
,
new_obj
,
REDIS_TAIL
);
}
else
{
subject
->
ptr
=
ziplistInsert
(
subject
->
ptr
,
next
,
new_obj
->
ptr
,
sdslen
(
new_obj
->
ptr
));
}
}
else
{
subject
->
ptr
=
ziplistInsert
(
subject
->
ptr
,
old_entry
->
zi
,
new_obj
->
ptr
,
sdslen
(
new_obj
->
ptr
));
}
}
else
if
(
subject
->
encoding
==
REDIS_ENCODING_LIST
)
{
if
(
where
==
REDIS_HEAD
)
{
listInsertNode
(
subject
->
ptr
,
old_entry
->
ln
,
new_obj
,
1
);
}
else
{
listInsertNode
(
subject
->
ptr
,
old_entry
->
ln
,
new_obj
,
0
);
}
incrRefCount
(
new_obj
);
}
else
{
redisPanic
(
"Unknown list encoding"
);
}
}
static
void
pushxGenericCommand
(
redisClient
*
c
,
int
where
,
robj
*
old_obj
,
robj
*
new_obj
)
{
robj
*
subject
;
listTypeIterator
*
iter
;
listTypeEntry
entry
;
if
((
subject
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
czero
))
==
NULL
||
checkType
(
c
,
subject
,
REDIS_LIST
))
return
;
if
(
handleClientsWaitingListPush
(
c
,
c
->
argv
[
1
],
new_obj
))
{
addReply
(
c
,
shared
.
cone
);
return
;
}
if
(
old_obj
!=
NULL
)
{
if
(
where
==
REDIS_HEAD
)
{
iter
=
listTypeInitIterator
(
subject
,
0
,
REDIS_TAIL
);
}
else
{
iter
=
listTypeInitIterator
(
subject
,
-
1
,
REDIS_HEAD
);
}
while
(
listTypeNext
(
iter
,
&
entry
))
{
if
(
listTypeEqual
(
&
entry
,
old_obj
))
{
listTypeInsert
(
subject
,
&
entry
,
new_obj
,
where
);
break
;
}
}
listTypeReleaseIterator
(
iter
);
}
else
{
listTypePush
(
subject
,
new_obj
,
where
);
}
server
.
dirty
++
;
addReplyUlong
(
c
,
listTypeLength
(
subject
));
}
static
void
lpushxCommand
(
redisClient
*
c
)
{
pushxGenericCommand
(
c
,
REDIS_HEAD
,
NULL
,
c
->
argv
[
2
]);
}
static
void
rpushxCommand
(
redisClient
*
c
)
{
pushxGenericCommand
(
c
,
REDIS_TAIL
,
NULL
,
c
->
argv
[
2
]);
}
static
void
linsertCommand
(
redisClient
*
c
)
{
if
(
strcasecmp
(
c
->
argv
[
2
]
->
ptr
,
"after"
)
==
0
)
{
pushxGenericCommand
(
c
,
REDIS_HEAD
,
c
->
argv
[
3
],
c
->
argv
[
4
]);
}
else
if
(
strcasecmp
(
c
->
argv
[
2
]
->
ptr
,
"before"
)
==
0
)
{
pushxGenericCommand
(
c
,
REDIS_TAIL
,
c
->
argv
[
3
],
c
->
argv
[
4
]);
}
else
{
addReply
(
c
,
shared
.
syntaxerr
);
}
}
static
void
llenCommand
(
redisClient
*
c
)
{
robj
*
o
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
czero
);
if
(
o
==
NULL
||
checkType
(
c
,
o
,
REDIS_LIST
))
return
;
...
...
tests/support/redis.tcl
View file @
dedff272
...
...
@@ -40,7 +40,7 @@ array set ::redis::multibulkarg {}
# Flag commands requiring last argument as a bulk write operation
foreach redis_bulk_cmd
{
set setnx rpush lpush lset lrem sadd srem sismember echo getset smove zadd zrem zscore zincrby append zrank zrevrank hget hdel hexists setex
set setnx rpush lpush
rpushx lpushx linsert
lset lrem sadd srem sismember echo getset smove zadd zrem zscore zincrby append zrank zrevrank hget hdel hexists setex
}
{
set ::redis::bulkarg
(
$redis
_bulk_cmd
)
{}
}
...
...
tests/unit/type/list.tcl
View file @
dedff272
...
...
@@ -52,6 +52,54 @@ start_server {
assert_equal $large_value
[
r lindex mylist2 2
]
}
test
{
LPUSHX, RPUSHX, LPUSHXAFTER, RPUSHXAFTER - ziplist
}
{
r del xlist
assert_equal 0
[
r lpushx xlist a
]
assert_equal 0
[
r rpushx xlist a
]
assert_equal 1
[
r rpush xlist b
]
assert_equal 2
[
r rpush xlist c
]
assert_equal 3
[
r rpushx xlist d
]
assert_equal 4
[
r lpushx xlist a
]
assert_encoding ziplist xlist
assert_equal
{
a b c d
}
[
r lrange xlist 0 10
]
assert_equal 5
[
r linsert xlist before c zz
]
assert_equal
{
a b zz c d
}
[
r lrange xlist 0 10
]
assert_equal 6
[
r linsert xlist after c yy
]
assert_equal
{
a b zz c yy d
}
[
r lrange xlist 0 10
]
assert_equal 7
[
r linsert xlist after d dd
]
assert_equal 7
[
r linsert xlist after bad ddd
]
assert_equal
{
a b zz c yy d dd
}
[
r lrange xlist 0 10
]
assert_equal 8
[
r linsert xlist before a aa
]
assert_equal 8
[
r linsert xlist before bad aaa
]
assert_equal
{
aa a b zz c yy d dd
}
[
r lrange xlist 0 10
]
}
test
{
LPUSHX, RPUSHX, LPUSHXAFTER, RPUSHXAFTER - regular list
}
{
set large_value
"aaaaaaaaaaaaaaaaa"
r del xlist
assert_equal 0
[
r lpushx xlist a
]
assert_equal 0
[
r rpushx xlist a
]
assert_equal 1
[
r rpush xlist $large_value
]
assert_equal 2
[
r rpush xlist c
]
assert_equal 3
[
r rpushx xlist d
]
assert_equal 4
[
r lpushx xlist a
]
assert_encoding list xlist
assert_equal
{
a aaaaaaaaaaaaaaaaa c d
}
[
r lrange xlist 0 10
]
assert_equal 5
[
r linsert xlist before c zz
]
assert_equal
{
a aaaaaaaaaaaaaaaaa zz c d
}
[
r lrange xlist 0 10
]
assert_equal 6
[
r linsert xlist after c yy
]
assert_equal
{
a aaaaaaaaaaaaaaaaa zz c yy d
}
[
r lrange xlist 0 10
]
assert_equal 7
[
r linsert xlist after d dd
]
assert_equal 7
[
r linsert xlist after bad ddd
]
assert_equal
{
a aaaaaaaaaaaaaaaaa zz c yy d dd
}
[
r lrange xlist 0 10
]
assert_equal 8
[
r linsert xlist before a aa
]
assert_equal 8
[
r linsert xlist before bad aaa
]
assert_equal
{
aa a aaaaaaaaaaaaaaaaa zz c yy d dd
}
[
r lrange xlist 0 10
]
}
test
{
DEL a list - ziplist
}
{
assert_equal 1
[
r del myziplist2
]
assert_equal 0
[
r exists myziplist2
]
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment