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
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