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
a092f20d
Commit
a092f20d
authored
Sep 06, 2019
by
antirez
Browse files
handleClientsBlockedOnKeys() refactoring.
parent
89ad0ca5
Changes
1
Show whitespace changes
Inline
Side-by-side
src/blocked.c
View file @
a092f20d
...
...
@@ -229,54 +229,13 @@ void disconnectAllBlockedClients(void) {
}
}
/* This function should be called by Redis every time a single command,
* a MULTI/EXEC block, or a Lua script, terminated its execution after
* being called by a client. It handles serving clients blocked in
* lists, streams, and sorted sets, via a blocking commands.
*
* All the keys with at least one client blocked that received at least
* one new element via some write operation are accumulated into
* the server.ready_keys list. This function will run the list and will
* serve clients accordingly. Note that the function will iterate again and
* again as a result of serving BRPOPLPUSH we can have new blocking clients
* to serve because of the PUSH side of BRPOPLPUSH.
*
* This function is normally "fair", that is, it will server clients
* using a FIFO behavior. However this fairness is violated in certain
* edge cases, that is, when we have clients blocked at the same time
* in a sorted set and in a list, for the same key (a very odd thing to
* do client side, indeed!). Because mismatching clients (blocking for
* a different type compared to the current key type) are moved in the
* other side of the linked list. However as long as the key starts to
* be used only for a single type, like virtually any Redis application will
* do, the function is already fair. */
void
handleClientsBlockedOnKeys
(
void
)
{
while
(
listLength
(
server
.
ready_keys
)
!=
0
)
{
list
*
l
;
/* Point server.ready_keys to a fresh list and save the current one
* locally. This way as we run the old list we are free to call
* signalKeyAsReady() that may push new elements in server.ready_keys
* when handling clients blocked into BRPOPLPUSH. */
l
=
server
.
ready_keys
;
server
.
ready_keys
=
listCreate
();
while
(
listLength
(
l
)
!=
0
)
{
listNode
*
ln
=
listFirst
(
l
);
readyList
*
rl
=
ln
->
value
;
/* First of all remove this key from db->ready_keys so that
* we can safely call signalKeyAsReady() against this key. */
dictDelete
(
rl
->
db
->
ready_keys
,
rl
->
key
);
/* Serve clients blocked on list key. */
robj
*
o
=
lookupKeyWrite
(
rl
->
db
,
rl
->
key
);
if
(
o
!=
NULL
&&
o
->
type
==
OBJ_LIST
)
{
dictEntry
*
de
;
/* Helper function for handleClientsBlockedOnKeys(). This function is called
* when there may be clients blocked on a list key, and there may be new
* data to fetch (the key is ready). */
void
serveClientsBlockedOnListKey
(
robj
*
o
,
readyList
*
rl
)
{
/* We serve clients in the same order they blocked for
* this key, from the first blocked to the last. */
de
=
dictFind
(
rl
->
db
->
blocking_keys
,
rl
->
key
);
dictEntry
*
de
=
dictFind
(
rl
->
db
->
blocking_keys
,
rl
->
key
);
if
(
de
)
{
list
*
clients
=
dictGetVal
(
de
);
int
numclients
=
listLength
(
clients
);
...
...
@@ -329,15 +288,15 @@ void handleClientsBlockedOnKeys(void) {
}
/* We don't call signalModifiedKey() as it was already called
* when an element was pushed on the list. */
}
/* Serve clients blocked on sorted set key. */
else
if
(
o
!=
NULL
&&
o
->
type
==
OBJ_ZSET
)
{
dictEntry
*
de
;
}
/* Helper function for handleClientsBlockedOnKeys(). This function is called
* when there may be clients blocked on a sorted set key, and there may be new
* data to fetch (the key is ready). */
void
serveClientsBlockedOnSortedSetKey
(
robj
*
o
,
readyList
*
rl
)
{
/* We serve clients in the same order they blocked for
* this key, from the first blocked to the last. */
de
=
dictFind
(
rl
->
db
->
blocking_keys
,
rl
->
key
);
dictEntry
*
de
=
dictFind
(
rl
->
db
->
blocking_keys
,
rl
->
key
);
if
(
de
)
{
list
*
clients
=
dictGetVal
(
de
);
int
numclients
=
listLength
(
clients
);
...
...
@@ -376,10 +335,12 @@ void handleClientsBlockedOnKeys(void) {
decrRefCount
(
argv
[
1
]);
}
}
}
}
/* Serve clients blocked on stream key. */
else
if
(
o
!=
NULL
&&
o
->
type
==
OBJ_STREAM
)
{
/* Helper function for handleClientsBlockedOnKeys(). This function is called
* when there may be clients blocked on a stream key, and there may be new
* data to fetch (the key is ready). */
void
serveClientsBlockedOnStreamKey
(
robj
*
o
,
readyList
*
rl
)
{
dictEntry
*
de
=
dictFind
(
rl
->
db
->
blocking_keys
,
rl
->
key
);
stream
*
s
=
o
->
ptr
;
...
...
@@ -467,6 +428,58 @@ void handleClientsBlockedOnKeys(void) {
}
}
}
}
/* This function should be called by Redis every time a single command,
* a MULTI/EXEC block, or a Lua script, terminated its execution after
* being called by a client. It handles serving clients blocked in
* lists, streams, and sorted sets, via a blocking commands.
*
* All the keys with at least one client blocked that received at least
* one new element via some write operation are accumulated into
* the server.ready_keys list. This function will run the list and will
* serve clients accordingly. Note that the function will iterate again and
* again as a result of serving BRPOPLPUSH we can have new blocking clients
* to serve because of the PUSH side of BRPOPLPUSH.
*
* This function is normally "fair", that is, it will server clients
* using a FIFO behavior. However this fairness is violated in certain
* edge cases, that is, when we have clients blocked at the same time
* in a sorted set and in a list, for the same key (a very odd thing to
* do client side, indeed!). Because mismatching clients (blocking for
* a different type compared to the current key type) are moved in the
* other side of the linked list. However as long as the key starts to
* be used only for a single type, like virtually any Redis application will
* do, the function is already fair. */
void
handleClientsBlockedOnKeys
(
void
)
{
while
(
listLength
(
server
.
ready_keys
)
!=
0
)
{
list
*
l
;
/* Point server.ready_keys to a fresh list and save the current one
* locally. This way as we run the old list we are free to call
* signalKeyAsReady() that may push new elements in server.ready_keys
* when handling clients blocked into BRPOPLPUSH. */
l
=
server
.
ready_keys
;
server
.
ready_keys
=
listCreate
();
while
(
listLength
(
l
)
!=
0
)
{
listNode
*
ln
=
listFirst
(
l
);
readyList
*
rl
=
ln
->
value
;
/* First of all remove this key from db->ready_keys so that
* we can safely call signalKeyAsReady() against this key. */
dictDelete
(
rl
->
db
->
ready_keys
,
rl
->
key
);
/* Serve clients blocked on list key. */
robj
*
o
=
lookupKeyWrite
(
rl
->
db
,
rl
->
key
);
if
(
o
!=
NULL
)
{
if
(
o
->
type
==
OBJ_LIST
)
serveClientsBlockedOnListKey
(
o
,
rl
);
else
if
(
o
->
type
==
OBJ_ZSET
)
serveClientsBlockedOnSortedSetKey
(
o
,
rl
);
else
if
(
o
->
type
==
OBJ_STREAM
)
serveClientsBlockedOnStreamKey
(
o
,
rl
);
}
/* Free this item. */
...
...
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