Commit Graph

55 Commits

Author SHA1 Message Date
antirez
da04e6ed44 Keyspace events added for more commands. 2013-01-28 13:14:56 +01:00
antirez
8766e81079 Fix decrRefCount() prototype from void to robj pointer.
decrRefCount used to get its argument as a void* pointer in order to be
used as destructor where a 'void free_object(void*)' prototype is
expected. However this made simpler to introduce bugs by freeing the
wrong pointer. This commit fixes the argument type and introduces a new
wrapper called decrRefCountVoid() that can be used when the void*
argument is needed.
2013-01-28 13:14:53 +01:00
guiquanz
9d09ce3981 Fixed many typos. 2013-01-19 10:59:44 +01:00
antirez
2f87cf8b01 Blocking POP: use a dictionary to store keys clinet side.
To store the keys we block for during a blocking pop operation, in the
case the client is blocked for more data to arrive, we used a simple
linear array of redis objects, in the blockingState structure:

    robj **keys;
    int count;

However in order to fix issue #801 we also use a dictionary in order to
avoid to end in the blocked clients queue for the same key multiple
times with the same client.

The dictionary was only temporary, just to avoid duplicates, but since
we create / destroy it there is no point in doing this duplicated work,
so this commit simply use a dictionary as the main structure to store
the keys we are blocked for. So instead of the previous fields we now
just have:

    dict *keys;

This simplifies the code and reduces the work done by the server during
a blocking POP operation.
2012-12-02 20:43:15 +01:00
antirez
4e6dd7bc86 Client should not block multiple times on the same key.
Sending a command like:

BLPOP foo foo foo foo 0

Resulted into a crash before this commit since the client ended being
inserted in the waiting list for this key multiple times.
This resulted into the function handleClientsBlockedOnLists() to fail
because we have code like that:

    if (de) {
        list *clients = dictGetVal(de);
        int numclients = listLength(clients);

        while(numclients--) {
            listNode *clientnode = listFirst(clients);

            /* server clients here... */
        }
    }

The code to serve clients used to remove the served client from the
waiting list, so if a client is blocking multiple times, eventually the
call to listFirst() will return NULL or worse will access random memory
since the list may no longer exist as it is removed by the function
unblockClientWaitingData() if there are no more clients waiting for this
list.

To avoid making the rest of the implementation more complex, this commit
modifies blockForKeys() so that a client will be put just a single time
into the waiting list for a given key.

Since it is Saturday, I hope this fixes issue #801.
2012-12-02 20:43:07 +01:00
antirez
4365e5b2d3 BSD license added to every C source and header file. 2012-11-08 18:31:32 +01:00
antirez
7eb850ef0e A reimplementation of blocking operation internals.
Redis provides support for blocking operations such as BLPOP or BRPOP.
This operations are identical to normal LPOP and RPOP operations as long
as there are elements in the target list, but if the list is empty they
block waiting for new data to arrive to the list.

All the clients blocked waiting for th same list are served in a FIFO
way, so the first that blocked is the first to be served when there is
more data pushed by another client into the list.

The previous implementation of blocking operations was conceived to
serve clients in the context of push operations. For for instance:

1) There is a client "A" blocked on list "foo".
2) The client "B" performs `LPUSH foo somevalue`.
3) The client "A" is served in the context of the "B" LPUSH,
synchronously.

Processing things in a synchronous way was useful as if "A" pushes a
value that is served by "B", from the point of view of the database is a
NOP (no operation) thing, that is, nothing is replicated, nothing is
written in the AOF file, and so forth.

However later we implemented two things:

1) Variadic LPUSH that could add multiple values to a list in the
context of a single call.
2) BRPOPLPUSH that was a version of BRPOP that also provided a "PUSH"
side effect when receiving data.

This forced us to make the synchronous implementation more complex. If
client "B" is waiting for data, and "A" pushes three elemnents in a
single call, we needed to propagate an LPUSH with a missing argument
in the AOF and replication link. We also needed to make sure to
replicate the LPUSH side of BRPOPLPUSH, but only if in turn did not
happened to serve another blocking client into another list ;)

This were complex but with a few of mutually recursive functions
everything worked as expected... until one day we introduced scripting
in Redis.

Scripting + synchronous blocking operations = Issue #614.

Basically you can't "rewrite" a script to have just a partial effect on
the replicas and AOF file if the script happened to serve a few blocked
clients.

The solution to all this problems, implemented by this commit, is to
change the way we serve blocked clients. Instead of serving the blocked
clients synchronously, in the context of the command performing the PUSH
operation, it is now an asynchronous and iterative process:

1) If a key that has clients blocked waiting for data is the subject of
a list push operation, We simply mark keys as "ready" and put it into a
queue.
2) Every command pushing stuff on lists, as a variadic LPUSH, a script,
or whatever it is, is replicated verbatim without any rewriting.
3) Every time a Redis command, a MULTI/EXEC block, or a script,
completed its execution, we run the list of keys ready to serve blocked
clients (as more data arrived), and process this list serving the
blocked clients.
4) As a result of "3" maybe more keys are ready again for other clients
(as a result of BRPOPLPUSH we may have push operations), so we iterate
back to step "3" if it's needed.

The new code has a much simpler semantics, and a simpler to understand
implementation, with the disadvantage of not being able to "optmize out"
a PUSH+BPOP as a No OP.

This commit will be tested with care before the final merge, more tests
will be added likely.
2012-09-17 10:26:46 +02:00
antirez
5ba79bda7f Document mostly dead code in RPOPLPUSH implementation. 2012-04-18 17:38:02 +02:00
Premysl Hruby
d194905449 use server.unixtime instead of time(NULL) where possible (cluster.c not checked though) 2012-03-27 17:39:58 +02:00
antirez
c1db214eeb Better implementation for BRPOP/BLPOP in the non blocking case. 2012-02-29 14:41:57 +01:00
antirez
cd8bdea31b lpush arguments vector rewrite modified for more speed and to memory leak removal. 2012-02-29 13:38:30 +01:00
antirez
eeb34eff52 Added a new API to replicate an additional command after the replication of the currently executed command, in order to propagte the LPUSH originating from RPOPLPUSH and indirectly by BRPOPLPUSH. 2012-02-28 18:03:08 +01:00
antirez
edba65d090 Var renamed into pushGenericCommand() to better reflect what it means. 2012-02-28 16:17:55 +01:00
antirez
3c08fdae71 64 bit instances are no longer limited to have at max 2^32-1 elements in lists. 2012-01-31 10:35:52 +01:00
BigCat
706b32e0e0 Fix issue #247 : Accepting non-integer parameters when shouldn't
Using `getLongFromObjectOrReply` instead of `atoi` if possible.
The following functions are modified.

* lrangeCommand
* ltrimCommand
* lremCommand
* lindexCommand
* lsetCommand
* zunionInterGenericCommand
* genericZrangebyscoreCommand
* sortCommand
2011-12-19 19:48:35 +08:00
antirez
c0ba9ebe13 dict.c API names modified to be more coincise and consistent. 2011-11-08 17:07:55 +01:00
antirez
eab0e26e03 replaced redisAssert() with redisAssertWithInfo() in a shitload of places. 2011-10-04 18:43:03 +02:00
antirez
7cfeb8cccf Optimize LRANGE to scan the list starting from the head or the tail in order to traverse the minimal number of elements. Thanks to Didier Spezia for noticing the problem and providing a patch. 2011-09-14 15:10:28 +02:00
antirez
48082cc044 fixed typos in the comments of rpoplpushHandlePush() 2011-09-12 10:04:23 +02:00
Hampus Wessman
c47d152c8d Fix crash when chaining brpoplpush with other blocking commands. 2011-09-07 19:08:48 +02:00
antirez
09e2d9eeba Take a pointer to the relevant entry of the command table in the client structure. This is generally a more sounding design, simplifies a few functions prototype, and as a side effect fixes a bug related to the conversion of EXPIRE -1 to DEL: before of this fix Redis tried to convert it into an EXPIREAT in the AOF code, regardless of our rewrite of the command. 2011-07-08 12:59:30 +02:00
antirez
c1c9d551da Fix for bug 561 and other related problems 2011-06-20 17:19:36 +02:00
antirez
defb5f66a0 removed assert causing an illegal memory access. This was responsible of crashes during BLPOP and other list blocking operations. 2011-05-11 09:50:57 +02:00
antirez
fb2feae599 variadic LPUSH/RPUSH 2011-04-15 16:35:27 +02:00
Pieter Noordhuis
554a5dd2fc Clarify comment 2011-02-03 12:56:53 +01:00
Pieter Noordhuis
d5870d7ac3 Reply with single null bulk for unsuccesful BRPOPLPUSH 2011-02-03 12:56:50 +01:00
Pieter Noordhuis
3bcffcbe5b Remove client from list of unblocked clients when it is free'd 2011-01-17 10:04:13 +01:00
antirez
cea8c5cd75 touched key for WATCH refactored into a more general thing that can be used also for the cache system. Some more changes towards diskstore working. 2010-12-29 19:39:42 +01:00
antirez
f858c11d7d Merge remote branch 'pietern/brpoplpush' 2010-12-14 16:26:37 +01:00
antirez
d51ebef509 LRANGE converted into a COW friendly command. Some refactoring, comment, and new addReply*() family function added in the process. 2010-12-07 16:33:13 +01:00
Pieter Noordhuis
a4ce758155 Don't execute commands for clients when they are unblocked 2010-12-06 16:39:39 +01:00
Pieter Noordhuis
ecf9401415 Fix case and indent 2010-12-06 16:04:42 +01:00
Pieter Noordhuis
8a88c368ed Check other blocked clients when value could not be pushed 2010-12-06 16:04:10 +01:00
Pieter Noordhuis
ac06fc011d Move code for pushing on a (blocking) RPOPLPUSH 2010-12-06 14:48:58 +01:00
Pieter Noordhuis
5fa95ad763 Rename blpop_blocked_clients to bpop_blocked_clients 2010-12-06 14:05:01 +01:00
Pieter Noordhuis
c8a0070a61 Move timeout logic 2010-12-06 13:45:48 +01:00
Michel Martens & Damian Janowski
baa14ef913 Fix BRPOPLPUSH behavior for all use cases. 2010-11-29 23:52:07 -03:00
Damian Janowski & Michel Martens
8987bf23bf Adhere to conventions. 2010-11-29 23:52:07 -03:00
Damian Janowski & Michel Martens
e3c51c4b1b Rename bstate to bpop. 2010-11-29 23:52:07 -03:00
Damian Janowski & Michel Martens
59bd44d1c8 Remove warning. 2010-11-29 23:52:07 -03:00
Damian Janowski & Michel Martens
7c25a43adc Handle BRPOPLPUSH inside a transaction. 2010-11-29 23:52:07 -03:00
Damian Janowski & Michel Martens
ba3b474111 Refactor code for BRPOPLPUSH. 2010-11-29 23:52:07 -03:00
Damian Janowski & Michel Martens
357a841714 Move to struct. 2010-11-29 23:52:07 -03:00
Damian Janowski & Michel Martens
b2a7fd0cf7 BRPOPLPUSH. 2010-11-29 23:52:07 -03:00
Damian Janowski & Michel Martens
8a979f0390 Fix case in RPOPLPUSH. 2010-11-29 23:52:07 -03:00
Pieter Noordhuis
75b41de8ca Convert objects in the command procs instead of the protocol code 2010-10-17 17:21:41 +02:00
Pieter Noordhuis
9e83ac06ef Merge branch 'master' into networking-perf
Resolved conflict in src/db.c and changed adding an error to the reply
in blockingPopGenericCommand to use the new API.
2010-09-03 16:44:50 +02:00
Pieter Noordhuis
b70d355521 Use existing reply functions where possible 2010-09-02 19:52:04 +02:00
Pieter Noordhuis
0537e7bf80 Use specialized function to add multi bulk reply length 2010-09-02 12:51:14 +02:00
antirez
f7f12a606c resolved conflict merging pietern/bpop-timeout 2010-08-31 11:23:12 +02:00