Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
c7df85a4
Commit
c7df85a4
authored
Jan 13, 2010
by
antirez
Browse files
list API is now thread safe
parent
b74880b4
Changes
3
Hide whitespace changes
Inline
Side-by-side
adlist.c
View file @
c7df85a4
...
@@ -165,14 +165,14 @@ void listReleaseIterator(listIter *iter) {
...
@@ -165,14 +165,14 @@ void listReleaseIterator(listIter *iter) {
}
}
/* Create an iterator in the list private iterator structure */
/* Create an iterator in the list private iterator structure */
void
listRewind
(
list
*
list
)
{
void
listRewind
(
list
*
list
,
listIter
*
li
)
{
li
st
->
iter
.
next
=
list
->
head
;
li
->
next
=
list
->
head
;
li
st
->
iter
.
direction
=
AL_START_HEAD
;
li
->
direction
=
AL_START_HEAD
;
}
}
void
listRewindTail
(
list
*
list
)
{
void
listRewindTail
(
list
*
list
,
listIter
*
li
)
{
li
st
->
iter
.
next
=
list
->
tail
;
li
->
next
=
list
->
tail
;
li
st
->
iter
.
direction
=
AL_START_TAIL
;
li
->
direction
=
AL_START_TAIL
;
}
}
/* Return the next element of an iterator.
/* Return the next element of an iterator.
...
@@ -202,11 +202,6 @@ listNode *listNext(listIter *iter)
...
@@ -202,11 +202,6 @@ listNode *listNext(listIter *iter)
return
current
;
return
current
;
}
}
/* List Yield just call listNext() against the list private iterator */
listNode
*
listYield
(
list
*
list
)
{
return
listNext
(
&
list
->
iter
);
}
/* Duplicate the whole list. On out of memory NULL is returned.
/* Duplicate the whole list. On out of memory NULL is returned.
* On success a copy of the original list is returned.
* On success a copy of the original list is returned.
*
*
...
...
adlist.h
View file @
c7df85a4
...
@@ -51,7 +51,6 @@ typedef struct list {
...
@@ -51,7 +51,6 @@ typedef struct list {
void
(
*
free
)(
void
*
ptr
);
void
(
*
free
)(
void
*
ptr
);
int
(
*
match
)(
void
*
ptr
,
void
*
key
);
int
(
*
match
)(
void
*
ptr
,
void
*
key
);
unsigned
int
len
;
unsigned
int
len
;
listIter
iter
;
}
list
;
}
list
;
/* Functions implemented as macros */
/* Functions implemented as macros */
...
@@ -82,9 +81,8 @@ void listReleaseIterator(listIter *iter);
...
@@ -82,9 +81,8 @@ void listReleaseIterator(listIter *iter);
list
*
listDup
(
list
*
orig
);
list
*
listDup
(
list
*
orig
);
listNode
*
listSearchKey
(
list
*
list
,
void
*
key
);
listNode
*
listSearchKey
(
list
*
list
,
void
*
key
);
listNode
*
listIndex
(
list
*
list
,
int
index
);
listNode
*
listIndex
(
list
*
list
,
int
index
);
void
listRewind
(
list
*
list
);
void
listRewind
(
list
*
list
,
listIter
*
li
);
void
listRewindTail
(
list
*
list
);
void
listRewindTail
(
list
*
list
,
listIter
*
li
);
listNode
*
listYield
(
list
*
list
);
/* Directions for iterators */
/* Directions for iterators */
#define AL_START_HEAD 0
#define AL_START_HEAD 0
...
...
redis.c
View file @
c7df85a4
...
@@ -1018,9 +1018,10 @@ static void closeTimedoutClients(void) {
...
@@ -1018,9 +1018,10 @@ static void closeTimedoutClients(void) {
redisClient
*
c
;
redisClient
*
c
;
listNode
*
ln
;
listNode
*
ln
;
time_t
now
=
time
(
NULL
);
time_t
now
=
time
(
NULL
);
listIter
li
;
listRewind
(
server
.
clients
);
listRewind
(
server
.
clients
,
&
li
);
while
((
ln
=
list
Yield
(
server
.
clients
))
!=
NULL
)
{
while
((
ln
=
list
Next
(
&
li
))
!=
NULL
)
{
c
=
listNodeValue
(
ln
);
c
=
listNodeValue
(
ln
);
if
(
server
.
maxidletime
&&
if
(
server
.
maxidletime
&&
!
(
c
->
flags
&
REDIS_SLAVE
)
&&
/* no timeout for slaves */
!
(
c
->
flags
&
REDIS_SLAVE
)
&&
/* no timeout for slaves */
...
@@ -1711,10 +1712,11 @@ static void glueReplyBuffersIfNeeded(redisClient *c) {
...
@@ -1711,10 +1712,11 @@ static void glueReplyBuffersIfNeeded(redisClient *c) {
int
copylen
=
0
;
int
copylen
=
0
;
char
buf
[
GLUEREPLY_UP_TO
];
char
buf
[
GLUEREPLY_UP_TO
];
listNode
*
ln
;
listNode
*
ln
;
listIter
li
;
robj
*
o
;
robj
*
o
;
listRewind
(
c
->
reply
);
listRewind
(
c
->
reply
,
&
li
);
while
((
ln
=
list
Yield
(
c
->
reply
)))
{
while
((
ln
=
list
Next
(
&
li
)))
{
int
objlen
;
int
objlen
;
o
=
ln
->
value
;
o
=
ln
->
value
;
...
@@ -2076,6 +2078,7 @@ static int processCommand(redisClient *c) {
...
@@ -2076,6 +2078,7 @@ static int processCommand(redisClient *c) {
static
void
replicationFeedSlaves
(
list
*
slaves
,
struct
redisCommand
*
cmd
,
int
dictid
,
robj
**
argv
,
int
argc
)
{
static
void
replicationFeedSlaves
(
list
*
slaves
,
struct
redisCommand
*
cmd
,
int
dictid
,
robj
**
argv
,
int
argc
)
{
listNode
*
ln
;
listNode
*
ln
;
listIter
li
;
int
outc
=
0
,
j
;
int
outc
=
0
,
j
;
robj
**
outv
;
robj
**
outv
;
/* (args*2)+1 is enough room for args, spaces, newlines */
/* (args*2)+1 is enough room for args, spaces, newlines */
...
@@ -2106,8 +2109,8 @@ static void replicationFeedSlaves(list *slaves, struct redisCommand *cmd, int di
...
@@ -2106,8 +2109,8 @@ static void replicationFeedSlaves(list *slaves, struct redisCommand *cmd, int di
* be sure to free objects if there is no slave in a replication state
* be sure to free objects if there is no slave in a replication state
* able to be feed with commands */
* able to be feed with commands */
for
(
j
=
0
;
j
<
outc
;
j
++
)
incrRefCount
(
outv
[
j
]);
for
(
j
=
0
;
j
<
outc
;
j
++
)
incrRefCount
(
outv
[
j
]);
listRewind
(
slaves
);
listRewind
(
slaves
,
&
li
);
while
((
ln
=
list
Yield
(
slaves
)))
{
while
((
ln
=
list
Next
(
&
li
)))
{
redisClient
*
slave
=
ln
->
value
;
redisClient
*
slave
=
ln
->
value
;
/* Don't feed slaves that are still waiting for BGSAVE to start */
/* Don't feed slaves that are still waiting for BGSAVE to start */
...
@@ -2922,11 +2925,12 @@ static int rdbSaveObject(FILE *fp, robj *o) {
...
@@ -2922,11 +2925,12 @@ static int rdbSaveObject(FILE *fp, robj *o) {
}
else
if
(
o
->
type
==
REDIS_LIST
)
{
}
else
if
(
o
->
type
==
REDIS_LIST
)
{
/* Save a list value */
/* Save a list value */
list
*
list
=
o
->
ptr
;
list
*
list
=
o
->
ptr
;
listIter
li
;
listNode
*
ln
;
listNode
*
ln
;
listRewind
(
list
);
if
(
rdbSaveLen
(
fp
,
listLength
(
list
))
==
-
1
)
return
-
1
;
if
(
rdbSaveLen
(
fp
,
listLength
(
list
))
==
-
1
)
return
-
1
;
while
((
ln
=
listYield
(
list
)))
{
listRewind
(
list
,
&
li
);
while
((
ln
=
listNext
(
&
li
)))
{
robj
*
eleobj
=
listNodeValue
(
ln
);
robj
*
eleobj
=
listNodeValue
(
ln
);
if
(
rdbSaveStringObject
(
fp
,
eleobj
)
==
-
1
)
return
-
1
;
if
(
rdbSaveStringObject
(
fp
,
eleobj
)
==
-
1
)
return
-
1
;
...
@@ -5362,9 +5366,10 @@ static void sortCommand(redisClient *c) {
...
@@ -5362,9 +5366,10 @@ static void sortCommand(redisClient *c) {
if
(
sortval
->
type
==
REDIS_LIST
)
{
if
(
sortval
->
type
==
REDIS_LIST
)
{
list
*
list
=
sortval
->
ptr
;
list
*
list
=
sortval
->
ptr
;
listNode
*
ln
;
listNode
*
ln
;
listIter
li
;
listRewind
(
list
);
listRewind
(
list
,
&
li
);
while
((
ln
=
list
Yield
(
list
)))
{
while
((
ln
=
list
Next
(
&
li
)))
{
robj
*
ele
=
ln
->
value
;
robj
*
ele
=
ln
->
value
;
vector
[
j
].
obj
=
ele
;
vector
[
j
].
obj
=
ele
;
vector
[
j
].
u
.
score
=
0
;
vector
[
j
].
u
.
score
=
0
;
...
@@ -5392,6 +5397,8 @@ static void sortCommand(redisClient *c) {
...
@@ -5392,6 +5397,8 @@ static void sortCommand(redisClient *c) {
}
}
dictReleaseIterator
(
di
);
dictReleaseIterator
(
di
);
}
}
printf
(
"**************************** %d == %d
\n
"
,
j
,
vectorlen
);
redisAssert
(
j
==
vectorlen
);
redisAssert
(
j
==
vectorlen
);
/* Now it's time to load the right scores in the sorting vector */
/* Now it's time to load the right scores in the sorting vector */
...
@@ -5460,13 +5467,15 @@ static void sortCommand(redisClient *c) {
...
@@ -5460,13 +5467,15 @@ static void sortCommand(redisClient *c) {
addReplySds
(
c
,
sdscatprintf
(
sdsempty
(),
"*%d
\r\n
"
,
outputlen
));
addReplySds
(
c
,
sdscatprintf
(
sdsempty
(),
"*%d
\r\n
"
,
outputlen
));
for
(
j
=
start
;
j
<=
end
;
j
++
)
{
for
(
j
=
start
;
j
<=
end
;
j
++
)
{
listNode
*
ln
;
listNode
*
ln
;
listIter
li
;
if
(
!
getop
)
{
if
(
!
getop
)
{
addReplyBulkLen
(
c
,
vector
[
j
].
obj
);
addReplyBulkLen
(
c
,
vector
[
j
].
obj
);
addReply
(
c
,
vector
[
j
].
obj
);
addReply
(
c
,
vector
[
j
].
obj
);
addReply
(
c
,
shared
.
crlf
);
addReply
(
c
,
shared
.
crlf
);
}
}
listRewind
(
operations
);
listRewind
(
operations
,
&
li
);
while
((
ln
=
list
Yield
(
operations
)))
{
while
((
ln
=
list
Next
(
&
li
)))
{
redisSortOperation
*
sop
=
ln
->
value
;
redisSortOperation
*
sop
=
ln
->
value
;
robj
*
val
=
lookupKeyByPattern
(
c
->
db
,
sop
->
pattern
,
robj
*
val
=
lookupKeyByPattern
(
c
->
db
,
sop
->
pattern
,
vector
[
j
].
obj
);
vector
[
j
].
obj
);
...
@@ -5491,12 +5500,14 @@ static void sortCommand(redisClient *c) {
...
@@ -5491,12 +5500,14 @@ static void sortCommand(redisClient *c) {
/* STORE option specified, set the sorting result as a List object */
/* STORE option specified, set the sorting result as a List object */
for
(
j
=
start
;
j
<=
end
;
j
++
)
{
for
(
j
=
start
;
j
<=
end
;
j
++
)
{
listNode
*
ln
;
listNode
*
ln
;
listIter
li
;
if
(
!
getop
)
{
if
(
!
getop
)
{
listAddNodeTail
(
listPtr
,
vector
[
j
].
obj
);
listAddNodeTail
(
listPtr
,
vector
[
j
].
obj
);
incrRefCount
(
vector
[
j
].
obj
);
incrRefCount
(
vector
[
j
].
obj
);
}
}
listRewind
(
operations
);
listRewind
(
operations
,
&
li
);
while
((
ln
=
list
Yield
(
operations
)))
{
while
((
ln
=
list
Next
(
&
li
)))
{
redisSortOperation
*
sop
=
ln
->
value
;
redisSortOperation
*
sop
=
ln
->
value
;
robj
*
val
=
lookupKeyByPattern
(
c
->
db
,
sop
->
pattern
,
robj
*
val
=
lookupKeyByPattern
(
c
->
db
,
sop
->
pattern
,
vector
[
j
].
obj
);
vector
[
j
].
obj
);
...
@@ -6136,9 +6147,10 @@ static void syncCommand(redisClient *c) {
...
@@ -6136,9 +6147,10 @@ static void syncCommand(redisClient *c) {
* registering differences since the server forked to save */
* registering differences since the server forked to save */
redisClient
*
slave
;
redisClient
*
slave
;
listNode
*
ln
;
listNode
*
ln
;
listIter
li
;
listRewind
(
server
.
slaves
);
listRewind
(
server
.
slaves
,
&
li
);
while
((
ln
=
list
Yield
(
server
.
slaves
)))
{
while
((
ln
=
list
Next
(
&
li
)))
{
slave
=
ln
->
value
;
slave
=
ln
->
value
;
if
(
slave
->
replstate
==
REDIS_REPL_WAIT_BGSAVE_END
)
break
;
if
(
slave
->
replstate
==
REDIS_REPL_WAIT_BGSAVE_END
)
break
;
}
}
...
@@ -6235,9 +6247,10 @@ static void sendBulkToSlave(aeEventLoop *el, int fd, void *privdata, int mask) {
...
@@ -6235,9 +6247,10 @@ static void sendBulkToSlave(aeEventLoop *el, int fd, void *privdata, int mask) {
static
void
updateSlavesWaitingBgsave
(
int
bgsaveerr
)
{
static
void
updateSlavesWaitingBgsave
(
int
bgsaveerr
)
{
listNode
*
ln
;
listNode
*
ln
;
int
startbgsave
=
0
;
int
startbgsave
=
0
;
listIter
li
;
listRewind
(
server
.
slaves
);
listRewind
(
server
.
slaves
,
&
li
);
while
((
ln
=
list
Yield
(
server
.
slaves
)))
{
while
((
ln
=
list
Next
(
&
li
)))
{
redisClient
*
slave
=
ln
->
value
;
redisClient
*
slave
=
ln
->
value
;
if
(
slave
->
replstate
==
REDIS_REPL_WAIT_BGSAVE_START
)
{
if
(
slave
->
replstate
==
REDIS_REPL_WAIT_BGSAVE_START
)
{
...
@@ -6269,9 +6282,11 @@ static void updateSlavesWaitingBgsave(int bgsaveerr) {
...
@@ -6269,9 +6282,11 @@ static void updateSlavesWaitingBgsave(int bgsaveerr) {
}
}
if
(
startbgsave
)
{
if
(
startbgsave
)
{
if
(
rdbSaveBackground
(
server
.
dbfilename
)
!=
REDIS_OK
)
{
if
(
rdbSaveBackground
(
server
.
dbfilename
)
!=
REDIS_OK
)
{
listRewind
(
server
.
slaves
);
listIter
li
;
listRewind
(
server
.
slaves
,
&
li
);
redisLog
(
REDIS_WARNING
,
"SYNC failed. BGSAVE failed"
);
redisLog
(
REDIS_WARNING
,
"SYNC failed. BGSAVE failed"
);
while
((
ln
=
list
Yield
(
server
.
slaves
)))
{
while
((
ln
=
list
Next
(
&
li
)))
{
redisClient
*
slave
=
ln
->
value
;
redisClient
*
slave
=
ln
->
value
;
if
(
slave
->
replstate
==
REDIS_REPL_WAIT_BGSAVE_START
)
if
(
slave
->
replstate
==
REDIS_REPL_WAIT_BGSAVE_START
)
...
@@ -6792,9 +6807,10 @@ static int rewriteAppendOnlyFile(char *filename) {
...
@@ -6792,9 +6807,10 @@ static int rewriteAppendOnlyFile(char *filename) {
/* Emit the RPUSHes needed to rebuild the list */
/* Emit the RPUSHes needed to rebuild the list */
list
*
list
=
o
->
ptr
;
list
*
list
=
o
->
ptr
;
listNode
*
ln
;
listNode
*
ln
;
listIter
li
;
listRewind
(
list
);
listRewind
(
list
,
&
li
);
while
((
ln
=
list
Yield
(
list
)))
{
while
((
ln
=
list
Next
(
&
li
)))
{
char
cmd
[]
=
"*3
\r\n
$5
\r\n
RPUSH
\r\n
"
;
char
cmd
[]
=
"*3
\r\n
$5
\r\n
RPUSH
\r\n
"
;
robj
*
eleobj
=
listNodeValue
(
ln
);
robj
*
eleobj
=
listNodeValue
(
ln
);
...
@@ -7080,7 +7096,7 @@ static int vmFreePage(off_t page) {
...
@@ -7080,7 +7096,7 @@ static int vmFreePage(off_t page) {
* note: I implemented this function just after watching an episode of
* note: I implemented this function just after watching an episode of
* Battlestar Galactica, where the hybrid was continuing to say "JUMP!"
* Battlestar Galactica, where the hybrid was continuing to say "JUMP!"
*/
*/
static
int
vmFindContiguousPages
(
off_t
*
first
,
in
t
n
)
{
static
int
vmFindContiguousPages
(
off_t
*
first
,
off_
t
n
)
{
off_t
base
,
offset
=
0
,
since_jump
=
0
,
numfree
=
0
;
off_t
base
,
offset
=
0
,
since_jump
=
0
,
numfree
=
0
;
if
(
server
.
vm_near_pages
==
REDIS_VM_MAX_NEAR_PAGES
)
{
if
(
server
.
vm_near_pages
==
REDIS_VM_MAX_NEAR_PAGES
)
{
...
@@ -7469,6 +7485,10 @@ static void vmThreadedIOCompletedJob(aeEventLoop *el, int fd, void *privdata,
...
@@ -7469,6 +7485,10 @@ static void vmThreadedIOCompletedJob(aeEventLoop *el, int fd, void *privdata,
/* Ooops... no space! */
/* Ooops... no space! */
freeIOJob
(
j
);
freeIOJob
(
j
);
}
else
{
}
else
{
/* Note that we need to mark this pages as used now,
* if the job will be canceled, we'll mark them as freed
* again. */
vmMarkPagesUsed
(
j
->
page
,
j
->
pages
);
j
->
type
=
REDIS_IOJOB_DO_SWAP
;
j
->
type
=
REDIS_IOJOB_DO_SWAP
;
lockThreadedIO
();
lockThreadedIO
();
queueIOJob
(
j
);
queueIOJob
(
j
);
...
@@ -7494,7 +7514,6 @@ static void vmThreadedIOCompletedJob(aeEventLoop *el, int fd, void *privdata,
...
@@ -7494,7 +7514,6 @@ static void vmThreadedIOCompletedJob(aeEventLoop *el, int fd, void *privdata,
key
->
vtype
=
j
->
val
->
type
;
key
->
vtype
=
j
->
val
->
type
;
decrRefCount
(
val
);
/* Deallocate the object from memory. */
decrRefCount
(
val
);
/* Deallocate the object from memory. */
dictGetEntryVal
(
de
)
=
NULL
;
dictGetEntryVal
(
de
)
=
NULL
;
vmMarkPagesUsed
(
j
->
page
,
j
->
pages
);
redisLog
(
REDIS_DEBUG
,
redisLog
(
REDIS_DEBUG
,
"VM: object %s swapped out at %lld (%lld pages) (threaded)"
,
"VM: object %s swapped out at %lld (%lld pages) (threaded)"
,
(
unsigned
char
*
)
key
->
ptr
,
(
unsigned
char
*
)
key
->
ptr
,
...
@@ -7549,9 +7568,10 @@ static void vmCancelThreadedIOJob(robj *o) {
...
@@ -7549,9 +7568,10 @@ static void vmCancelThreadedIOJob(robj *o) {
/* Search for a matching key in one of the queues */
/* Search for a matching key in one of the queues */
for
(
i
=
0
;
i
<
3
;
i
++
)
{
for
(
i
=
0
;
i
<
3
;
i
++
)
{
listNode
*
ln
;
listNode
*
ln
;
listIter
li
;
listRewind
(
lists
[
i
]);
listRewind
(
lists
[
i
]
,
&
li
);
while
((
ln
=
list
Yield
(
lists
[
i
]
))
!=
NULL
)
{
while
((
ln
=
list
Next
(
&
li
))
!=
NULL
)
{
iojob
*
job
=
ln
->
value
;
iojob
*
job
=
ln
->
value
;
if
(
job
->
canceled
)
continue
;
/* Skip this, already canceled. */
if
(
job
->
canceled
)
continue
;
/* Skip this, already canceled. */
...
@@ -7570,6 +7590,12 @@ static void vmCancelThreadedIOJob(robj *o) {
...
@@ -7570,6 +7590,12 @@ static void vmCancelThreadedIOJob(robj *o) {
job
->
canceled
=
1
;
job
->
canceled
=
1
;
break
;
break
;
}
}
/* Mark the pages as free since the swap didn't happened
* or happened but is not discarded. */
if
(
job
->
type
==
REDIS_IOJOB_DO_SWAP
)
vmMarkPagesFree
(
job
->
page
,
job
->
pages
);
/* Finally we have to adjust the storage type of the object
* in order to "UNDO" the operaiton. */
if
(
o
->
storage
==
REDIS_VM_LOADING
)
if
(
o
->
storage
==
REDIS_VM_LOADING
)
o
->
storage
=
REDIS_VM_SWAPPED
;
o
->
storage
=
REDIS_VM_SWAPPED
;
else
if
(
o
->
storage
==
REDIS_VM_SWAPPING
)
else
if
(
o
->
storage
==
REDIS_VM_SWAPPING
)
...
...
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