107 Commits

Author SHA1 Message Date
antirez
aa32f92338 Introduction of a new string encoding: EMBSTR
Previously two string encodings were used for string objects:

1) REDIS_ENCODING_RAW: a string object with obj->ptr pointing to an sds
stirng.

2) REDIS_ENCODING_INT: a string object where the obj->ptr void pointer
is casted to a long.

This commit introduces a experimental new encoding called
REDIS_ENCODING_EMBSTR that implements an object represented by an sds
string that is not modifiable but allocated in the same memory chunk as
the robj structure itself.

The chunk looks like the following:

+--------------+-----------+------------+--------+----+
| robj data... | robj->ptr | sds header | string | \0 |
+--------------+-----+-----+------------+--------+----+
                     |                       ^
                     +-----------------------+

The robj->ptr points to the contiguous sds string data, so the object
can be manipulated with the same functions used to manipulate plan
string objects, however we need just on malloc and one free in order to
allocate or release this kind of objects. Moreover it has better cache
locality.

This new allocation strategy should benefit both the memory usage and
the performances. A performance gain between 60 and 70% was observed
during micro-benchmarks, however there is more work to do to evaluate
the performance impact and the memory usage behavior.
2013-07-22 10:31:38 +02:00
antirez
f28d386cc5 Keyspace events: it is now possible to select subclasses of events.
When keyspace events are enabled, the overhead is not sever but
noticeable, so this commit introduces the ability to select subclasses
of events in order to avoid to generate events the user is not
interested in.

The events can be selected using redis.conf or CONFIG SET / GET.
2013-01-28 13:15:12 +01:00
antirez
f2d1105618 Keyspace events added for more commands. 2013-01-28 13:14:56 +01:00
antirez
3394db6361 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
df7a5b7157 Fixed many typos. 2013-01-19 10:59:44 +01:00
antirez
b775d5c3e9 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
5f622803ec 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
a32d1ddff6 BSD license added to every C source and header file. 2012-11-08 18:31:32 +01:00
antirez
8574733f48 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
c4b413e7f7 Document mostly dead code in RPOPLPUSH implementation. 2012-04-18 17:38:02 +02:00
Premysl Hruby
f3fa6655c6 use server.unixtime instead of time(NULL) where possible (cluster.c not checked though) 2012-03-27 17:39:58 +02:00
antirez
6b56c5fd03 Better implementation for BRPOP/BLPOP in the non blocking case. 2012-02-29 14:41:57 +01:00
antirez
38c49acd48 lpush arguments vector rewrite modified for more speed and to memory leak removal. 2012-02-29 13:38:30 +01:00
antirez
2b84687811 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
ef34fd54ed Var renamed into pushGenericCommand() to better reflect what it means. 2012-02-28 16:17:55 +01:00
antirez
884c2f0e68 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
c1cc254d62 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
d6c3b3004e dict.c API names modified to be more coincise and consistent. 2011-11-08 17:07:55 +01:00
antirez
357f49db2f replaced redisAssert() with redisAssertWithInfo() in a shitload of places. 2011-10-04 18:43:03 +02:00
antirez
2dab3fdc64 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
1912b1fd64 fixed typos in the comments of rpoplpushHandlePush() 2011-09-12 10:04:23 +02:00
Hampus Wessman
5c0db2df35 Fix crash when chaining brpoplpush with other blocking commands. 2011-09-07 19:08:48 +02:00
antirez
ee2dc83094 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
7192cd5cb7 Fix for bug 561 and other related problems 2011-06-20 17:19:36 +02:00
antirez
9ecb0c7c29 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
51a298862a variadic LPUSH/RPUSH 2011-04-15 16:35:27 +02:00
Pieter Noordhuis
a282e91b0f Clarify comment 2011-02-03 12:56:53 +01:00
Pieter Noordhuis
f9120df538 Reply with single null bulk for unsuccesful BRPOPLPUSH 2011-02-03 12:56:50 +01:00
Pieter Noordhuis
418603038c Remove client from list of unblocked clients when it is free'd 2011-01-17 10:04:13 +01:00
antirez
a8d2f3796d 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
31cfc6bf21 Merge remote branch 'pietern/brpoplpush' 2010-12-14 16:26:37 +01:00
antirez
fda6e59e9a 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
02fb4e921d Don't execute commands for clients when they are unblocked 2010-12-06 16:39:39 +01:00
Pieter Noordhuis
845da0b0d3 Fix case and indent 2010-12-06 16:04:42 +01:00
Pieter Noordhuis
0e83e79f73 Check other blocked clients when value could not be pushed 2010-12-06 16:04:10 +01:00
Pieter Noordhuis
778e9f7cb8 Move code for pushing on a (blocking) RPOPLPUSH 2010-12-06 14:48:58 +01:00
Pieter Noordhuis
58e59db7b5 Rename blpop_blocked_clients to bpop_blocked_clients 2010-12-06 14:05:01 +01:00
Pieter Noordhuis
5e9adbdeb1 Move timeout logic 2010-12-06 13:45:48 +01:00
Michel Martens & Damian Janowski
c126fa01bb Fix BRPOPLPUSH behavior for all use cases. 2010-11-29 23:52:07 -03:00
Damian Janowski & Michel Martens
a8ad4e3b1d Adhere to conventions. 2010-11-29 23:52:07 -03:00
Damian Janowski & Michel Martens
60ea6205b7 Rename bstate to bpop. 2010-11-29 23:52:07 -03:00
Damian Janowski & Michel Martens
d754ed676a Remove warning. 2010-11-29 23:52:07 -03:00
Damian Janowski & Michel Martens
20cea44779 Handle BRPOPLPUSH inside a transaction. 2010-11-29 23:52:07 -03:00
Damian Janowski & Michel Martens
6902b0c2d0 Refactor code for BRPOPLPUSH. 2010-11-29 23:52:07 -03:00
Damian Janowski & Michel Martens
c8454233e4 Move to struct. 2010-11-29 23:52:07 -03:00
Damian Janowski & Michel Martens
f1e2a70b23 BRPOPLPUSH. 2010-11-29 23:52:07 -03:00
Damian Janowski & Michel Martens
74b37889c1 Fix case in RPOPLPUSH. 2010-11-29 23:52:07 -03:00
Pieter Noordhuis
000b46faac Convert objects in the command procs instead of the protocol code 2010-10-17 17:21:41 +02:00
Pieter Noordhuis
70768b4051 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