Compare commits

..
1816 Commits
Author SHA1 Message Date
antirez 53bc8a77d1 Cluster test: add tmp dir to Git repo. 2014-05-26 18:06:48 +02:00
Matt Stancliff 033d717295 Fix test framework to detect proper server PID
Previously the PID format was:
[PID] Timestamp

But it recently changed to:
PID:X Timestamp

The tcl testing framework was grabbing the PID from \[\d+\], but
that's not valid anymore.

Now we grab the pid from "PID: <PID>" in the part of Redis startup
output to the right of the ASCII logo.
2014-05-26 17:58:49 +02:00
Matt Stancliff 186adefd56 Disable recursive watchdog signal handler
If we are in the signal handler, we don't want to handle
the signal again.  In extreme cases, this can cause a stack overflow
and segfault Redis.

Fixes #1771
2014-05-26 17:53:37 +02:00
antirez 4fe4c4b34d Redis 2.9.54 (Redis 3.0.0 beta-5). 2014-05-26 16:38:11 +02:00
antirez eea0d41fb9 Cluster: always allow ok -> fail switch in clusterUpdateState().
There is a time defined by REDIS_CLUSTER_WRITABLE_DELAY where fail -> ok
switch is not possible after startup as a master for some time, however
the contrary (ok -> fail) should always be possible.
2014-05-26 16:36:14 +02:00
antirez 672e2672aa Cluster test: catch FLUSHALL errors on node reset.
FLUSHALL will fail on read-only slaves, but there the command is not
needed in order to reset the instance with CLUSTER RESET so errors can
be ignored.
2014-05-26 16:36:11 +02:00
antirez df0c8c28ad Sentinel example config: explain you don't need to specify slaves. 2014-05-26 10:18:04 +02:00
antirez b5f0d0d6f9 Redis 2.9.53 (Redis 3.0.0 beta-4). 2014-05-23 16:08:38 +02:00
antirez 7f8ea7a50f Cluster test: basic failover unit added. 2014-05-23 15:54:53 +02:00
antirez 29aed9c48f Cluster test: move basic read/write test into a procedure. 2014-05-23 15:54:53 +02:00
antirez 81af783fec Cluster test: more reliable 01-faildet unit.
Do things in a sequence that prevents failover during failure detection.
2014-05-23 15:54:53 +02:00
antirez e62e3c4cb2 3.0 Changelog typo fixed. lost -> list. 2014-05-23 09:49:45 +02:00
antirez 5697f4f85d Document log format change in 3.0 Changelog. 2014-05-23 09:28:32 +02:00
antirez 90bbf1159b redisLogFromHandler() format changed to match new logs format. 2014-05-23 09:26:04 +02:00
antirez 9996c37e74 Tag every log line with role.
Every log contains, just after the pid, a single character that provides
information about the role of an instance:

S - Slave
M - Master
C - Writing child
X - Sentinel
2014-05-23 09:26:04 +02:00
antirez 33f63ff988 Cluster: slave validity factor is now user configurable.
Check the commit changes in the example redis.conf for more information.
2014-05-23 09:26:04 +02:00
antirez 308c570e04 Test: AOF test false positive when running in slow hosts.
The bug was triggered by running the test with Valgrind (which is a lot
slower and more sensible to timing issues) after the recent changes
that made Redis more promptly able to reply with the -LOADING error.
2014-05-23 09:26:04 +02:00
antirez 1d70312028 Test: dump.tcl fixed for RESTORE new error msg. 2014-05-23 09:26:04 +02:00
antirez 0e1b5ff63b Fix an error in redis-trib where we always talk with same node.
While iterating the list of nodes we want to set the slot as stable in
the current node, not always in the first node of the list.
2014-05-23 09:26:04 +02:00
antirez c268d1ebd5 redis-trib fix improved: move keys from N nodes to owner. 2014-05-23 09:26:04 +02:00
antirez 32ca949c76 redis-trib fix: use MIGRATE REPLACE when fixing slots.
This fixes issue #1765.
2014-05-23 09:26:04 +02:00
antirez 122157f220 Regression test for issue #1764. 2014-05-20 17:45:50 +02:00
antirez d357e3ee8f Remove trailing spaces from scripting.c 2014-05-20 17:45:50 +02:00
antirez d0c84acc97 Remove trailing spaces from sentinel.c. 2014-05-20 17:45:50 +02:00
michael-grunder 6f49395148 Fix LUA_OBJCACHE segfault.
When scanning the argument list inside of a redis.call() invocation
for pre-cached values, there was no check being done that the
argument we were on was in fact within the bounds of the cache size.

So if a redis.call() command was ever executed with more than 32
arguments (current cache size #define setting) redis-server could
segfault.
2014-05-20 17:45:50 +02:00
antirez 440ee603b7 Cluster test: better failure detection test and framework improvements. 2014-05-20 17:45:50 +02:00
antirez a7fd2eb594 Cluster test: failure detection initial tests. 2014-05-20 17:45:50 +02:00
antirez a82c000bdb Cluster test: proper initialization at unit startup. 2014-05-20 17:45:50 +02:00
antirez 8c6e86805c Cluster: use clusterSetNodeAsMaster() during slave failover.
clusterHandleSlaveFailover() was reimplementing what
clusterSetNodeAsMaster() without any good reason.
2014-05-20 17:45:50 +02:00
antirez 41a7241603 Cluster: clear todo_before_sleep flags when executing actions.
Thanks to this change, when there is some code like:

    clusterDoBeforeSleep(CLUSTER_TODO_UPDATE_STATE|...);
    ... and later before returning to the event loop ...
    clusterUpdateState();

The clusterUpdateState() function will clar the flag and will not be
repeated in the clusterBeforeSleep() function. This especially important
for config save/fsync flags which are slow to execute and not a good
idea to repeat without a good reason.

This is implemented for all the CLUSTER_TODO flags.
2014-05-20 17:45:50 +02:00
antirez 5685d15af1 Fixed typo in CLUSTER RESET implementation. 2014-05-20 17:45:50 +02:00
antirez 5efa5501e8 CLUSTER RESET implemented.
The new command is able to reset a cluster node so that it starts again
as a fresh node. By default the command performs a soft reset (the same
as calling it as CLUSTER RESET SOFT), and the following steps are
performed:

1) All slots are set as unassigned.
2) The list of known nodes is flushed.
3) Node is set as master if it is a slave.

When an hard reset is performed with CLUSTER RESET HARD the following
additional operations are performed:

4) A new Node ID is created at random.
5) Epochs are set to 0.

CLUSTER RESET is useful both when the sysadmin wants to reconfigure a
node with a different role (for example turning a slave into a master)
and for testing purposes.

It also may play a role in automatically provisioned Redis Clusters,
since it allows to reset a node back to the initial state in order to be
reconfigured.
2014-05-20 17:45:50 +02:00
antirez 687f84a377 Remove trailing spaces from cluster.c file. 2014-05-20 17:45:50 +02:00
antirez d279024081 Cluster test: added function assert_cluster_state. 2014-05-20 17:45:50 +02:00
antirez be1594905f Cluster: don't accept cluster bus connections during startup. 2014-05-20 17:45:50 +02:00
antirez b8a71e5a77 Cluster: better handling of stolen slots.
The previous code handling a lost slot (by another master with an higher
configuration for the slot) was defensive, considering it an error and
putting the cluster in an odd state requiring redis-cli fix.

This was changed, because actually this only happens either in a
legitimate way, with failovers, or when the admin messed with the config
in order to reconfigure the cluster. So the new code instead will try to
make sure that the keys stored match the new slots map, by removing all
the keys in the slots we lost ownership from.

The function that deletes the keys from the lost slots is called only
if the node does not lose all its slots (resulting in a reconfiguration
as a slave of the node that got ownership). This is an optimization
since the replication code will anyway flush all the instance data in
a faster way.
2014-05-20 17:45:49 +02:00
antirez f727000f0c cluster.tcl: fix redis links leak in refresh_nodes_map. 2014-05-20 17:45:49 +02:00
antirez 4db4a5d5d6 cluster.tcl: saner error handling.
Better handling of connection errors in order to update the table and
recovery, populate the startup nodes table after fetching the list of
nodes.

More work to do about it, it is still not as reliable as
redis-rb-cluster implementation which is the minimal reference
implementation for Redis Cluster clients.
2014-05-20 17:45:49 +02:00
antirez d9227938c8 redis.tcl: return I/O error message when peer closes connection. 2014-05-20 17:45:49 +02:00
antirez e10ee0728a Cluster: fixed data_age computation / check integer overflow. 2014-05-20 17:45:49 +02:00
antirez e84dcabf83 Cluster: forced failover implemented.
Using CLUSTER FAILOVER FORCE it is now possible to failover a master in
a forced way, which means:

1) No check to understand if the master is up is performed.
2) No data age of the slave is checked. Evan a slave with very old data
   can manually failover a master in this way.
3) No chat with the master is attempted to reach its replication offset:
   the master can just be down.
2014-05-20 17:45:49 +02:00
antirez b5cdd42bf3 Cluster: bypass data_age check for manual failovers.
Automatic failovers only happen in Redis Cluster if the slave trying to
be elected was disconnected from its master for no more than 10 times
the node-timeout value. However there should be no such a check for
manual failovers, since these are initiated by the sysadmin that, in
theory, knows what she is doing when a slave is selected to be promoted.
2014-05-20 17:45:49 +02:00
antirez 26eb7ec731 HyperLogLog regression test for issue #1762. 2014-05-19 15:45:22 +02:00
Mike Trinkala 73737c4b85 Correct the HyperLogLog stale cache flag to prevent unnecessary computations.
Set the MSB as documented.
2014-05-19 15:45:22 +02:00
Akos Vandra 15a1c261ea Fixed possible buffer overflow bug if RDB file is corrupted.
(Note: commit message modified by @antirez for clarity).
2014-05-12 15:56:17 +02:00
Akos Vandra ef92a30767 fixed possible buffer overflow error 2014-05-12 15:56:17 +02:00
antirez d3ddeff2d2 redis-trib create: use CONFIG SET-CONFIG-EPOCH before joining the cluster.
This way there is no need for the conflict resolution algo to be used in
order to start with a cluster where each node has a different
configEpoch.
2014-05-12 15:56:17 +02:00
antirez ce5e625a5e Sentinel: Add "dir /tmp" directive in example sentinel.conf. 2014-05-12 15:56:17 +02:00
antirez 34b68b7e89 redis-trib import: trap MIGRATE errors. 2014-05-12 15:56:17 +02:00
antirez bdfa26fb51 redis-trib.rb: MIGRATE hardcoded timeout set to 15 sec.
Will be configurable / adaptive at some point but let's start with a
saner value compared to 1 sec which is not a good idea for big data
structures stored into a single key.
2014-05-12 15:56:17 +02:00
antirez 0a707babb1 RESTORE: reply with -BUSYKEY special error code.
The error when the target key is busy was a generic one, while it makes
sense to be able to distinguish between the target key busy error and
the others easily.
2014-05-12 15:56:17 +02:00
antirez 85d2a8091c Cluster: initial ability to import data from standalone instance. 2014-05-12 15:56:17 +02:00
antirez fafe29cd4c CLUSTER MEET: better error messages when address is invalid.
Fixes issue #1734.
2014-05-12 15:56:17 +02:00
antirez 5fef9b63d2 redis-trib: allow support for mandatory options. 2014-05-12 15:56:16 +02:00
antirez 8522f295fa DEBUG POPULATE: call dictExpand() to avoid useless rehashing. 2014-05-09 15:05:26 +02:00
antirez 83c92d50a6 Cluster: bulk-accept new nodes connections.
The same change was operated for normal client connections. This is
important for Cluster as well, since when a node rejoins the cluster,
when a partition heals or after a restart, it gets flooded with new
connection attempts by all the other nodes trying to form a full
mesh again.
2014-05-09 15:05:26 +02:00
antirez ed18587f52 Cluster: clusterAcceptHandler() comments updated to match the code. 2014-05-09 15:05:26 +02:00
antirez 6eadeb7236 Sentinel: log when a failover will be attempted again.
When a Sentinel performs a failover (successful or not), or when a
Sentinel votes for a different Sentinel trying to start a failover, it
sets a min delay before it will try to get elected for a failover.

While not strictly needed, because if multiple Sentinels will try
to failover the same master at the same time, only one configuration
will eventually win, this serialization is practically very useful.
Normal failovers are cleaner: one Sentinel starts to failover, the
others update their config when the Sentinel performing the failover
is able to get the selected slave to move from the role of slave to the
one of master.

However currently this timeout was implicit, so users could see
Sentinels not reacting, after a failed failover, for some time, without
giving any feedback in the logs to the poor sysadmin waiting for clues.

This commit makes Sentinels more verbose about the delay: when a master
is down and a failover attempt is not performed because the delay has
still not elaped, something like that will be logged:

    Next failover delay: I will not start a failover
    before Thu May  8 16:48:59 2014
2014-05-08 16:49:41 +02:00
antirez c738f0f4fc Sentinel: generate +config-update-from event when a new config is received.
This event makes clear, before the switch-master event is generated,
that a Sentinel received a configuration update from another Sentinel.
2014-05-08 16:49:41 +02:00
antirez d8ffd2b2ba REDIS_ENCODING_EMBSTR_SIZE_LIMIT set to 39.
The new value is the limit for the robj + SDS header + string +
null-term to stay inside the 64 bytes Jemalloc arena in 64 bits
systems.
2014-05-08 15:40:43 +02:00
antirez 35b94422f6 Scripting test: check that Lua can call commands rewirting argv.
SPOP, tested in the new test, is among the commands rewritng the
client->argv argument vector (it gets rewritten as SREM) for command
replication purposes.

Because of recent optimizations to client->argv caching in the context
of the Lua internal Redis client, it is important to test for SPOP to be
callable from Lua without bad effects to the other commands.
2014-05-07 16:12:38 +02:00
antirez 1255460c96 Test: handle new osx 'leaks' error.
Sometimes the process is still there but no longer in a state that can
be checked (after being killed). This used to happen after a call to
SHUTDOWN NOSAVE in the scripting unit, causing a false positive.
2014-05-07 16:12:38 +02:00
antirez baf930176b Scripting: objects caching for Lua c->argv creation.
Reusing small objects when possible is a major speedup under certain
conditions, since it is able to avoid the malloc/free pattern that
otherwise is performed for every argument in the client command vector.
2014-05-07 16:12:38 +02:00
antirez 77503edf10 Scripting: Use faster API for Lua client c->argv creation.
Replace the three calls to Lua API lua_tostring, lua_lua_strlen,
and lua_isstring, with a single call to lua_tolstring.

~ 5% consistent speed gain measured.
2014-05-07 16:12:38 +02:00
antirez d757d400c1 Scripting: don't call lua_gc() after Lua script run.
Calling lua_gc() after every script execution is too expensive, and
apparently does not make the execution smoother: the same peak latency
was measured before and after the commit.

This change accounts for scripts execution speedup in the order of 10%.
2014-05-07 16:12:38 +02:00
antirez ef164836b1 Scripting: cache argv in luaRedisGenericCommand().
~ 4% consistently measured speed improvement.
2014-05-07 16:12:38 +02:00
antirez 5c291ba9f6 Fixed missing c->bufpos reset in luaRedisGenericCommand().
Bug introduced when adding a fast path to avoid copying the reply buffer
for small replies that fit into the client static buffer.
2014-05-07 16:12:38 +02:00
antirez 4b1cb0c44f Scripting: replace tolower() with faster code in evalGenericCommand().
The function showed up consuming a non trivial amount of time in the
profiler output. After this change benchmarking gives a 6% speed
improvement that can be consistently measured.
2014-05-07 16:12:38 +02:00
antirez b1f3bf8858 Scripting: luaRedisGenericCommand() fast path for buffer-only replies.
When the reply is only contained in the client static output buffer, use
a fast path avoiding the dynamic allocation of an SDS string to
concatenate the client reply objects.
2014-05-07 16:12:38 +02:00
antirez 473a8bd7d8 Define HAVE_ATOMIC for clang. 2014-05-07 16:12:38 +02:00
antirez 650b48ea7c Scripting: simpler reply buffer creation in luaRedisGenericCommand().
It if faster to just create the string with a single sdsnewlen() call.
If c->bufpos is zero, the call will simply be like sdsemtpy().
2014-05-07 16:12:38 +02:00
antirez b7a6a6c486 Redis 2.9.52 (Redis 3.0.0 beta-3). 2014-05-05 10:29:00 +02:00
antirez 402b1170bc Test: cluster/base, check that we can write/read from cluster. 2014-05-05 09:37:39 +02:00
antirez f188fa4a15 Cluster: Tcl cluster client: handle MOVED/ASK. 2014-05-05 09:37:39 +02:00
antirez 5069e0b9cd Cluster: Tcl cluster client: slots-nodes map and close method.
Now the client is able to actually run commands in a Redis Cluster
assuming the slots->nodes map is stable.
2014-05-05 09:37:39 +02:00
antirez 9fe28612b9 Cluster: Tcl cluster client: build nodes representation. 2014-05-05 09:37:39 +02:00
antirez a5b7065bdf Cluster: Tcl cluster client: get nodes description. 2014-05-05 09:37:39 +02:00
antirez 1826167519 Cluster: Tcl cluster client key -> hashslot. 2014-05-05 09:37:39 +02:00
antirez 43570e9319 Cluster test: Tcl cluster library initial skeleton. 2014-05-05 09:37:39 +02:00
antirez 4ca7c5bcde Cluster test: check for state=ok after slot allocation. 2014-05-05 09:37:39 +02:00
antirez c4c7389fea CLUSTER SET-CONFIG-EPOCH implemented.
Initially Redis Cluster accepted that after cluster creation all the
nodes were at configEpoch 0, evolving from zero as failovers happen.

However later the semantic was made more strict in order to make sure a
cluster has always all the master nodes with a different configEpoch,
which is more robust in some corner case (especially resulting from
errors by the system administrator).

To assign different configEpochs to different nodes at startup was a
task performed naturally by the config conflicts resolution algorithm
(see the Cluster specification). However this works well only for small
clusters or when there are actually just a few collisions, since it is
designed for exceptional cases.

When a large cluster is created hundred of nodes can be at epoch 0, so
the conflict resolution code is slow to provide an unique config to each
node. For this reason this new command was introduced. It can be called
only when a node is totally fresh: no other nodes known, and configEpoch
set to zero, so it is safe even against misuses.

redis-trib will use the new command in order to start the cluster
already setting an incremental unique config to every node.
2014-05-05 09:37:39 +02:00
antirez 6fc17adcd8 Cluster test: slots allocation. 2014-05-05 09:37:39 +02:00
antirez 0906ca8a3e Cluster test: use 20 instances.
This makes tests a bit slower, but it is better to test things at a
decent scale instead of using just a few nodes, and for a few tests we
actually need so many nodes.
2014-05-05 09:37:39 +02:00
antirez 402815cc3f Cluster / Sentinel test: instances count moved to run.tcl. 2014-05-05 09:37:39 +02:00
antirez 6e60e2467b Cluster test: config epoch conflict resolution. 2014-05-05 09:37:39 +02:00
antirez b1f6f2ace0 Cluster test: auto-discovery to form full mesh. 2014-05-05 09:37:39 +02:00
antirez e244bee60c Cluster test: check that every node has a different ID. 2014-05-05 09:37:39 +02:00
antirez 6b4e9558bd Cluster test: basic cluster nodes info access functions. 2014-05-05 09:37:39 +02:00
antirez a11ae385e9 CLIENT LIST speedup via peerid caching + smart allocation.
This commit adds peer ID caching in the client structure plus an API
change and the use of sdsMakeRoomFor() in order to improve the
reallocation pattern to generate the CLIENT LIST output.

Both the changes account for a very significant speedup.
2014-04-28 18:17:02 +02:00
antirez bb00154f0e Use sdscatfmt() in getClientInfoString() to make it faster. 2014-04-28 18:17:02 +02:00
antirez e285a57073 Added new sdscatfmt() %u and %U format specifiers.
This commit also fixes a bug in the implementation of sdscatfmt()
resulting from stale references to the SDS string header after
sdsMakeRoomFor() calls.
2014-04-28 18:17:02 +02:00
antirez 0ab06bb500 sdscatfmt() added to SDS library.
sdscatprintf() relies on printf() family libc functions and is sometimes
too slow in critical code paths. sdscatfmt() is an alternative which is:

1) Far less capable.
2) Format specifier uncompatible.
3) Faster.

It is suitable to be used in those speed critical code paths such as
CLIENT LIST output generation.
2014-04-28 18:17:02 +02:00
antirez eeab60d1d5 Test: fixed scripting.tcl test false positive. 2014-04-28 18:17:02 +02:00
antirez cdd2bd5632 Process events with processEventsWhileBlocked() when blocked.
When we are blocked and a few events a processed from time to time, it
is smarter to call the event handler a few times in order to handle the
accept, read, write, close cycle of a client in a single pass, otherwise
there is too much latency added for clients to receive a reply while the
server is busy in some way (for example during the DB loading).
2014-04-28 18:17:02 +02:00
antirez 357b039fdb Accept multiple clients per iteration.
When the listening sockets readable event is fired, we have the chance
to accept multiple clients instead of accepting a single one. This makes
Redis more responsive when there is a mass-connect event (for example
after the server startup), and in workloads where a connect-disconnect
pattern is used often, so that multiple clients are waiting to be
accepted continuously.

As a side effect, this commit makes the LOADING, BUSY, and similar
errors much faster to deliver to the client, making Redis more
responsive when there is to return errors to inform the clients that the
server is blocked in an not interruptible operation.
2014-04-28 18:17:02 +02:00
antirez ba86119414 AE_ERR -> ANET_ERR in acceptUnixHandler().
No actual changes since the value is the same.
2014-04-28 18:17:02 +02:00
antirez a8464828b6 Redis Cluster test framework skeleton. 2014-04-28 18:17:02 +02:00
antirez 3acae3dee3 While ANET_ERR is -1, check syscall retval for -1 itself. 2014-04-28 18:17:02 +02:00
antirez b008863edb clusterLoadConfig() REDIS_ERR retval semantics refined.
We should return REDIS_ERR to signal we can't read the configuration
because there is no config file only after checking errno, othewise
we risk to rewrite an existing file that was not accessible for some
other reason.
2014-04-28 18:17:02 +02:00
antirez 71d71814a9 Lock nodes.conf to avoid multiple processes using the same file.
This was a common source of problems among users.
The solution adopted is not bullet-proof as if the user deletes the
nodes.conf file manually, and starts a new instance with the same
nodes.conf file path, two instances will use the same file. However
following this reasoning the user may drop a nuclear bomb into the
datacenter as well.
2014-04-28 18:17:02 +02:00
antirez a0050e5030 Sentinel test files / directories layout improved.
The test now runs in a self-contained directory.
The general abstractions to run the tests in an environment where
mutliple instances are executed at the same time was extrapolated into
instances.tcl, that will be reused to test Redis Cluster.
2014-04-28 18:17:02 +02:00
antirez 3bff0291d8 Test: spawn_instance now supports additional config. 2014-04-28 18:17:02 +02:00
Matt Stancliff 08174e730f Add test for deleting an expired key
Verify proper expire-before-delete behavior.

This test passes with the expire-before-delete commit and fails
without it.
2014-04-23 16:14:34 +02:00
Matt Stancliff e687621e15 Check key expiration before deleting
Deleting an expired key should return 0, not success.

Fixes #1648
2014-04-23 16:14:34 +02:00
Glauber Costa 0c8fdb349c fix null pointer access with no file pointer
I happen to be working on a system that lacks urandom. While the code does try
to handle this case and artificially create some bytes if the file pointer is
empty, it does try to close it unconditionally, leading to a segfault.
2014-04-23 15:35:07 +02:00
kingsumos 19ac9af09f fix cluster node description showing wrong slot allocation 2014-04-23 15:35:07 +02:00
Kevin Menard 7b25ff4bf7 Fixed typos. 2014-04-23 15:34:47 +02:00
antirez 7b670805cf Missing return REDIS_ERR added to processMultibulkBuffer().
When we set a protocol error we should return with REDIS_ERR to let the
caller know it should stop processing the client.

Bug found in a code auditing related to issue #1699.
2014-04-23 10:21:30 +02:00
antirez e99e45be38 redis-cli help.h updated. 2014-04-22 16:14:59 +02:00
antirez 25f72e9e0d generate-command-help.rb updated with new hyperloglog group. 2014-04-22 16:14:59 +02:00
antirez aff94a706e Fuzzy test for ZREMRANGEBYLEX added. 2014-04-18 16:14:34 +02:00
antirez 5b5dd73093 ZREMRANGEBYLEX memory leak removed calling zslFreeLexRange(). 2014-04-18 16:14:34 +02:00
antirez ca6c793844 PFCOUNT multi-key test added. 2014-04-18 16:14:34 +02:00
antirez 82556c1687 Speedup hllRawSum() processing 8 bytes per iteration.
The internal HLL raw encoding used by PFCOUNT when merging multiple keys
is aligned to 8 bits (1 byte per register) so we can exploit this to
improve performances by processing multiple bytes per iteration.

In benchmarks the new code was several times faster with HLLs with many
registers set to zero, while no slowdown was observed with populated
HLLs.
2014-04-18 16:14:34 +02:00
antirez 5e928eff64 Speedup SUM(2^-reg[m]) in HyperLogLog computation.
When the register is set to zero, we need to add 2^-0 to E, which is 1,
but it is faster to just add 'ez' at the end, which is the number of
registers set to zero, a value we need to compute anyway.
2014-04-18 16:14:34 +02:00
antirez 00726b2e0e PFCOUNT support for multi-key union. 2014-04-18 16:14:34 +02:00
antirez 57b34a73c2 HyperLogLog low level merge extracted from PFMERGE. 2014-04-18 16:14:34 +02:00
antirez 816e22bc6f ZREMRANGEBYLEX implemented. 2014-04-18 16:14:34 +02:00
antirez d28b239fe9 Always pass sorted set range objects by reference. 2014-04-18 16:14:34 +02:00
antirez 69d0585d61 ZREMRANGE* commands refactored into a single generic function. 2014-04-18 16:14:34 +02:00
antirez 53ca563ff7 Sorted set lex ranges stress tester. 2014-04-18 16:14:34 +02:00
antirez 5e1224dc1d Basic ZRANGEBYLEX / ZLEXCOUNT tests. 2014-04-17 00:08:35 +02:00
antirez 964faba650 Pass by pointer and release of lex ranges.
Given that the code was written with a 2 years pause... something
strange happened in the middle. So there was no function to free a
lex range min/max objects, and in some places the range was passed by
value.
2014-04-17 00:08:35 +02:00
antirez 5e21acec54 ZLEXCOUNT implemented.
Like ZCOUNT for lexicographical ranges.
2014-04-16 15:09:47 +02:00
antirez 00aa96f34b More HyperLogLog tests. 2014-04-16 15:09:47 +02:00
antirez a3848a7429 HyperLogLog invalid representation error code set to INVALIDOBJ. 2014-04-16 15:09:47 +02:00
antirez 030336d4ef PFDEBUG TODENSE added.
Converts HyperLogLogs from sparse to dense. Used for testing.
2014-04-16 15:09:47 +02:00
antirez e4c2afb9c0 User-defined switch point between sparse-dense HLL encodings. 2014-04-16 15:09:47 +02:00
antirez e19e078c77 PFSELFTEST improved with sparse encoding checks. 2014-04-16 15:09:47 +02:00
antirez 66f67208d3 PFDEBUG ENCODING added. 2014-04-16 15:09:47 +02:00
antirez db929041b5 Set HLL_SPARSE_MAX to 3000.
After running a few benchmarks, 3000 looks like a reasonable value to
keep HLLs with a few thousand elements small while the CPU cost is
still not huge.

This covers all the cases where the dense representation would use N
orders of magnitude more space, like in the case of many HLLs with
carinality of a few tens or hundreds.

It is not impossible that in the future this gets user configurable,
however it is easy to pick an unreasoable value just looking at savings
in the space dimension without checking what happens in the time
dimension.
2014-04-16 15:09:47 +02:00
antirez 90b67e416a Error message for invalid HLL objects unified. 2014-04-16 15:09:47 +02:00
antirez fdace9bc50 PFMERGE fixed to work with sparse encoding. 2014-04-16 15:09:47 +02:00
antirez 64fbd15706 Mark PFDEBUG as write command in the commands table.
It is safer since it is able to have side effects.
2014-04-16 15:09:47 +02:00
antirez 159926a170 Correctly replicate PFDEBUG GETREG.
Even if it is a debugging command, make sure that when it forces a
change in encoding, the command is propagated.
2014-04-16 15:09:47 +02:00
antirez fc33779283 Added assertion in hllSparseAdd() when promotion to dense occurs.
If we converted to dense, a register must be updated in the dense
representation.
2014-04-16 15:09:47 +02:00
antirez 67e15a0ff7 hllSparseAdd(): speed optimization.
Mostly by reordering opcodes check conditional by frequency of opcodes
in larger sparse-encoded HLLs.
2014-04-16 15:09:47 +02:00
antirez ed52bbe134 Detect corrupted sparse HLLs in hllSparseSum(). 2014-04-16 15:09:46 +02:00
antirez fd137b0781 hllSparseAdd(): faster code removing conditional.
Bottleneck found profiling. Big run time improvement found when testing
after the change.
2014-04-16 15:09:46 +02:00
antirez 8b3d5a8eb0 Comment typo in hllSparseAdd(). first -> fits. 2014-04-16 15:09:46 +02:00
antirez 46f9a78d9c Merge adjacent VAL opcodes in hllSparseAdd().
As more values are added splitting ZERO or XZERO opcodes, try to merge
adjacent VAL opcodes if they have the same value.
2014-04-16 15:09:46 +02:00
antirez 9f12467c9c More robust HLL_SPARSE macros protecting 'p' with parens.
Now the macros will work with arguments such as "ptr+1".
2014-04-16 15:09:46 +02:00
antirez 10bc0aea8d hllSparseAdd() opcode seek stop condition fixed. 2014-04-16 15:09:46 +02:00
antirez 8be9394ec7 Fixed error message generation in PFDEBUG GETREG.
Bulk length for registers was emitted too early, so if there was a bug
the reply looked like a long array with just one element, blocking the
client as result.
2014-04-16 15:09:46 +02:00
antirez 8cc09325c8 Fixed memmove() count in hllSparseAdd(). 2014-04-16 15:09:46 +02:00
antirez da084bdf84 hllSparseAdd(): more correct dense conversion conditional.
We want to promote if the total string size exceeds the resulting size
after the upgrade.
2014-04-16 15:09:46 +02:00
antirez a7dbd28cff hllSparseToDense(): sanity check added.
The function checks if all the HLL_REGISTERS were processed during the
convertion from sparse to dense encoding, returning REDIS_OK or
REDIS_ERR to signal a corruption problem.

A bug in PFDEBUG GETREG was fixed: when the object is converted to the
dense representation we need to reassign the new pointer to the header
structure pointer.
2014-04-16 15:09:46 +02:00
antirez cf500998e8 PFDEBUG DECODE added.
Provides a human readable description of the opcodes composing a
run-length encoded HLL (sparse encoding).
The command is only useful for debugging / development tasks.
2014-04-16 15:09:46 +02:00
antirez 2c4a1eccda PFDEBUG added, PFGETREG removed.
PFDEBUG will be the interface to do debugging tasks with a key
containing an HLL object.
2014-04-16 15:09:46 +02:00
antirez 5786846122 hllSparseToDense API changed to take ref to object.
The new API takes directly the object doing everything needed to
turn it into a dense representation, including setting the new
representation as object->ptr.
2014-04-16 15:09:46 +02:00
antirez 68fb3019a0 hllSparseAdd() sanity check for span != 0 added. 2014-04-16 15:09:46 +02:00
antirez e7e6aa49d0 Fix hllSparseAdd() new sequence replacement when next is NULL.
sdsIncrLen() must be called anyway even if we are replacing the last
oppcode of the sparse representation.
2014-04-16 15:09:46 +02:00
antirez b964380817 Fix seqlen computation in hllSparseAdd(). 2014-04-16 15:09:46 +02:00
antirez 1c6671ab90 Abstract hllSparseAdd() / hllDenseAdd() via hllAdd(). 2014-04-16 15:09:46 +02:00
antirez e3f5a38695 hllSparseSum(): multiply 1 * runlen for zero entries. 2014-04-16 15:09:46 +02:00
antirez 5b69b984b3 Macro HLL_SPARSE_XZERO_LEN fixed. 2014-04-16 15:09:46 +02:00
antirez 2c1fa11124 Fix HLL sparse object creation #2.
Two vars initialized to wrong values in createHLLObject().
2014-04-16 15:09:46 +02:00
antirez 0b9f09c4e0 Increment pointer while iterating sparse HLL object. 2014-04-16 15:09:46 +02:00
antirez e526d32635 Fix HLL sparse object creation.
The function didn't considered the fact that each XZERO opcode is
two bytes.
2014-04-16 15:09:46 +02:00
antirez ccbabf01e1 Create HyperLogLog objects with sparse encoding. 2014-04-16 15:09:46 +02:00
antirez df5782f4d0 HyperLogLog sparse to dense conversion function. 2014-04-16 15:09:46 +02:00
antirez e872394176 HyperLogLog sparse representation initial implementation.
Code never tested, but the basic layout is shaped in this commit.
Also missing:

1) Sparse -> Dense conversion function.
2) New HLL object creation using the sparse representation.
3) Implementation of PFMERGE for the sparse representation.
2014-04-16 15:09:46 +02:00
antirez 4e12ecdba5 hllCount() refactored to support multiple representations. 2014-04-16 15:09:46 +02:00
antirez 05b5032302 hllAdd() refactored into two functions.
Also dense representation access macro renamed accordingly.
2014-04-16 15:09:46 +02:00
antirez 4407ca6fc8 HyperLogLog refactoring to support different encodings.
Metadata are now placed at the start of the representation as an header.
There is a proper structure to access the representation.
Still work to do in order to truly abstract the implementation from the
representation, commands still work assuming dense representation.
2014-04-16 15:09:46 +02:00
antirez 099ae637ab HyperLogLog sparse representation slightly modified.
After running a few simulations with different alternative encodings,
it was found that the VAL opcode performs better using 5 bits for the
value and 2 bits for the run length, at least for cardinalities in the
range of interest.
2014-04-16 15:09:46 +02:00
antirez 2b531f729d HyperLogLog sparse representation description and macros. 2014-04-16 15:09:46 +02:00
antirez 437cddee0d Add casting to match printf format.
adjustOpenFilesLimit() and clusterUpdateSlotsWithConfig() that were
assuming uint64_t is the same as unsigned long long, which is true
probably for all the systems out there that we target, but still GCC
emitted a warning since technically they are two different types.
2014-04-16 15:09:46 +02:00
antirez 109ec9c6a5 ZRANGEBYLEX and ZREVRANGEBYLEX implementation. 2014-04-16 15:09:46 +02:00
antirez f5bdaf366e PFCOUNT: always unshare/decode the object.
This will be a non-op most of the times since the object will be
unshared / decoded, however it is more technically correct to start this
way since the object may be decoded even in the read-only code path.
2014-04-16 15:09:46 +02:00
antirez ae6103ebf6 tryObjectEncoding() refactoring.
We also avoid to re-create an object that is already in EMBSTR encoding.
2014-04-16 15:09:46 +02:00
antirez 63ba5f5a8c Changed HyperLogLog hash seed to a non-zero value.
Using a seed of zero has the side effect of having the empty string
hashing to what is a very special case in the context of HyperLogLog: a
very long run of zeroes.

This did not influenced the correctness of the result with 16k registers
because of the harmonic mean, but still it is inconvenient that a so
obvious value maps to a so special hash.

The seed 0xadc83b19 is used instead, which is the first 64 bits of the
SHA1 of the empty string.

Reference: issue #1657.
2014-04-16 15:09:46 +02:00
antirez e0389f031e Initial HyperLogLog tests. 2014-04-16 15:09:45 +02:00
antirez 5056450b02 Return "WRONGTYPE" error on PF* type mismatch. 2014-04-16 15:09:45 +02:00
antirez f553fc442f Fix PFADD infinite loop.
We need to guarantee that the last bit is 1, otherwise an element may
hash to just zeroes with probability 1/(2^64) and trigger an infinite
loop.

See issue #1657.
2014-04-16 15:09:45 +02:00
antirez 19938b9103 Make hll-gnuplot-graph.rb callable from cli. 2014-04-16 15:09:45 +02:00
antirez 628b9fa535 Remove HyperLogLog type checking duplicated code. 2014-04-16 15:09:45 +02:00
antirez aecb59b0b2 PFGETREG added for testing purposes.
The new command allows to get a dump of the registers stored
into an HyperLogLog data structure for testing / debugging purposes.
2014-04-16 15:09:45 +02:00
antirez e6fda1c9ed PFCOUNT: unshare the object when cached cardinality is modified. 2014-04-16 15:09:45 +02:00
antirez 9c7bb351ab PFSELFTEST improved to test the approximation error. 2014-04-16 15:09:45 +02:00
antirez 80d7f7081c hll-gnuplot-graph.rb improved with new filter.
The function to generate graphs is also more flexible as now includes
step and max value. The step of the samples generation function is no
longer limited to min step of 1000.
2014-04-16 15:09:45 +02:00
antirez 6415fe5623 HyperLogLog: added magic / version.
This will allow future changes like compressed representations.
Currently the magic is not checked for performance reasons but this may
change in the future, for example if we add new types encoded in strings
that may have the same size of HyperLogLogs.
2014-04-16 15:09:45 +02:00
Raymond Myers f403fca654 Fixed pfadd/pfcount commands emitting hll* events instead of pf* events 2014-04-16 15:09:45 +02:00
Raymond Myers 21c9372454 Change HLL* to PF* in error messages 2014-04-16 15:09:45 +02:00
antirez f307a51049 Include redis.h before other stuff in hyperloglog.c.
Otherwise fmacros.h is included later and this may break compilation on
different systems.
2014-04-16 15:09:45 +02:00
antirez 08516c1ab6 HyperLogLog API prefix modified from "P" to "PF".
Using both the initials of Philippe Flajolet instead of just "P".
2014-04-16 15:09:45 +02:00
antirez 0c01e293ef Makefile.dep updated with hyperloglog.o deps. 2014-04-16 15:09:45 +02:00
antirez e262442fd4 HyperLogLog: make API use the P prefix in honor of Philippe Flajolet. 2014-04-16 15:09:45 +02:00
antirez 8ad9123a14 HLLMERGE fixed by adding a... missing loop! 2014-04-16 15:09:45 +02:00
antirez 9cb2b5003f hll-gnuplot-graph.rb: added new filter "all". 2014-04-16 15:09:45 +02:00
antirez 07daaa6ec4 HyperLogLog apply bias correction using a polynomial.
Better results can be achieved by compensating for the bias of the raw
approximation just after 2.5m (when LINEARCOUNTING is no longer used) by
using a polynomial that approximates the bias at a given cardinality.

The curve used was found using this web page:

    http://www.xuru.org/rt/PR.asp

That performs polynomial regression given a set of values.
2014-04-16 15:09:45 +02:00
antirez 691846e38d HLLMERGE implemented.
Merge N HLL data structures by selecting the max value for every
M[i] register among the set of HLLs.
2014-04-16 15:09:45 +02:00
antirez 7f18689a00 HLLCOUNT is technically a write command
When we update the cached value, we need to propagate the command and
signal the key as modified for WATCH.
2014-04-16 15:09:45 +02:00
antirez 6672e101e8 HLLADD: propagate write when only variable name is given.
The following form is given:

    HLLADD myhll

No element is provided in the above case so if 'myhll' var does not
exist the result is to just create an empty HLL structure, and no update
will be performed on the registers.

In this case, the DB should still be set dirty and the command
propagated.
2014-04-16 15:09:45 +02:00
antirez df2c02785a hll-gnuplot-graph.rb: Use |error| when filter is :max 2014-04-16 15:09:45 +02:00
antirez dc774e1bdc Ignore txt files inside utils/hyperloglog.
Those are generated to trace graphs using gnuplot.
2014-04-16 15:09:45 +02:00
antirez 00cb4c5dee HyperLogLog: use LINEARCOUNTING up to 3m.
The HyperLogLog original paper suggests using LINEARCOUNTING for
cardinalities < 2.5m, however for P=14 the median / max error
curves show that a value of '3' is the best pick for m = 16384.
2014-04-16 15:09:45 +02:00
antirez 2c1b4dcd40 hll-gnuplot-graph.rb added to plot HyperLogLog error graphs. 2014-04-16 15:09:45 +02:00
antirez 7acccc7ef9 HyperLogLog approximated cardinality caching.
The more we add elements to an HyperLogLog counter, the smaller is
the probability that we actually update some register.

From this observation it is easy to see how it is possible to use
caching of a previously computed cardinality and reuse it to serve
HLLCOUNT queries as long as no register was updated in the data
structure.

This commit does exactly this by using just additional 8 bytes for the
data structure to store a 64 bit unsigned integer value cached
cardinality. When the most significant bit of the 64 bit integer is set,
it means that the value computed is no longer usable since at least a
single register was modified and we need to recompute it at the next
call of HLLCOUNT.

The value is always stored in little endian format regardless of the
actual CPU endianess.
2014-04-16 15:09:45 +02:00
antirez 8be30eca17 String value unsharing refactored into proper function.
All the Redis functions that need to modify the string value of a key in
a destructive way (APPEND, SETBIT, SETRANGE, ...) require to make the
object unshared (if refcount > 1) and encoded in raw format (if encoding
is not already REDIS_ENCODING_RAW).

This was cut & pasted many times in multiple places of the code. This
commit puts the small logic needed into a function called
dbUnshareStringValue().
2014-04-16 15:09:45 +02:00
antirez f3aa086b6d Use endian neutral hash function for HyperLogLog.
We need to be sure that you can save a dataset in a Redis instance,
reload it in a different architecture, and continue to count in the same
HyperLogLog structure.

So 32 and 64 bit, little or bit endian, must all guarantee to output the
same hash for the same element.
2014-04-16 15:09:45 +02:00
antirez f704678d07 HyperLogLog internal representation modified.
The new representation is more obvious, starting from the LSB of the
first byte and using bits going to MSB, and passing to next byte as
needed.

There was also a subtle error: first two bits were unused, everything
was carried over on the right of two bits, even if it worked because of
the code requirement of always having a byte more at the end.

During the rewrite the code was made safer trying to avoid undefined
behavior due to shifting an uint8_t for more than 8 bits.
2014-04-16 15:09:45 +02:00
antirez c1f97815ca Remove a few useless operations from hllCount() fast path. 2014-04-16 15:09:45 +02:00
antirez c16f638dc5 HLLCOUNT 3x faster taking fast path for default params. 2014-04-16 15:09:45 +02:00
antirez e6d57660ed Use processor base types in HLL_(GET|SET)_REGISTER.
This speedups the macros by a noticeable factor.
2014-04-16 15:09:45 +02:00
antirez 650b21fb2c HyperLogLog: use precomputed table for 2^(-M[i]). 2014-04-16 15:09:45 +02:00
antirez 6aa1b23269 hll-err.rb: speedup using pipelining. 2014-04-16 15:09:44 +02:00
antirez a0b27c329a hll-err.rb added to test error rate of Redis HyperLogLog. 2014-04-16 15:09:44 +02:00
antirez 7d04f823e1 HyperLogLog algorithm fixed in two ways.
There was an error in the computation of 2^register, and the sequence of
zeroes computed after the hashing did not included the "1".
2014-04-16 15:09:44 +02:00
antirez 93e5876a72 HLLCOUNT implemented. 2014-04-16 15:09:44 +02:00
antirez bb57749a86 HLLADD implemented. 2014-04-16 15:09:44 +02:00
antirez 0faae58091 hllAdd() low level HyperLogLog "add" implemented. 2014-04-16 15:09:44 +02:00
antirez c03e7ceaaa HyperLogLog: redefine constants using "P". 2014-04-16 15:09:44 +02:00
antirez f4839dfb27 HLL_SET_REGISTER fixed.
There was an error in the first version of the macro.
Now the HLLSELFTEST test reports success.
2014-04-16 15:09:44 +02:00
antirez 87dd31427c Use REDIS_HLL_REGISTER_MAX when possible. 2014-04-16 15:09:44 +02:00
antirez 3610af42b2 HLL_(SET|GET)_REGISTER types fixed. 2014-04-16 15:09:44 +02:00
antirez c7344144f4 HLLSELFTEST command implemented.
To test the bitfield array of counters set/get macros from the Redis Tcl
suite is hard, so a specialized command that is able to test the
internals was developed.
2014-04-16 15:09:44 +02:00
antirez be20651435 HyperLogLog: initial sketch of registers access. 2014-04-16 15:09:44 +02:00
antirez 8c6ce3dd6a Cluster: last_vote_epoch -> lastVoteEpoch.
Use cammel case for epochs that are persisted on disk.
2014-04-16 15:09:44 +02:00
antirez 1080e272de Cluster: save/restore vars that must persist after recovery.
This fixes issue #1479.
2014-04-16 15:09:44 +02:00
antirez 47fbbd9fbc Cluster: handshake "already known" error logged to VERBOSE.
This is not really an error but something that always happens for
example when creating a new cluster, or if the sysadmin rejoins manually
a node that is already known.

Since useless logs don't help, moved to VERBOSE level.
2014-04-16 15:09:44 +02:00
antirez 6875a15858 Cluster: clusterHandleConfigEpochCollision() fixed.
New config epochs must always be obtained incrementing the currentEpoch,
that is itself guaranteed to be >= the max configEpoch currently known
to the node.
2014-04-16 15:09:44 +02:00
antirez 74fd89b321 Cluster: better logging for clusterUpdateSlotsConfigWith(). 2014-04-16 15:09:44 +02:00
antirez cf8f72c184 Cluster: CLUSTER SETSLOT implementation comment updated.
Update the comment since the implementation details changed.
2014-04-16 15:09:44 +02:00
antirez 6837863902 Cluster: redis-trib cluster allocation more even across nodes.
redis-trib used to allocate slots not considering fractions of nodes
when computing the slots_per_node amount. So the fractional part was
carried over till the end of the allocation, where the last node
received a few more slots than any other (or a lot more if the cluster
was composed of many nodes).

The computation was changed to allocate slots more evenly when they are
not exactly divisible for the number of masters we have.
2014-04-16 15:09:44 +02:00
antirez 431573ae98 Cluster: configEpoch collisions resolution.
The slave election in Redis Cluster guarantees that slaves promoted to
masters always end with unique config epochs, however failures during
manual reshardings, software bugs and operational errors may in theory
cause two nodes to have the same configEpoch.

This commit introduces a mechanism to eventually always end with different
configEpochs if a collision ever happens.

As a (wanted) side effect, this also ensures that after a new cluster
is created, all nodes will end with a different configEpoch automatically.
2014-04-16 15:09:44 +02:00
antirez 8a3dde208d Cluster: stay within 80 cols. 2014-04-16 15:09:44 +02:00
antirez 046e691a6f Fix off by one bug in freeMemoryIfNeeded() eviction pool.
Bug found by the continuous integration test running the Redis
with valgrind:

==6245== Invalid read of size 8
==6245==    at 0x4C2DEEF: memcpy@GLIBC_2.2.5 (mc_replace_strmem.c:876)
==6245==    by 0x41F9E6: freeMemoryIfNeeded (redis.c:3010)
==6245==    by 0x41D2CC: processCommand (redis.c:2069)

memmove() size argument was accounting for an extra element, going
outside the bounds of the array.
2014-03-25 10:32:50 +01:00
antirez 74d86dc13b Test: do not complain when "leaks" can't run because process died. 2014-03-25 09:34:07 +01:00
antirez c69c40a4ae adjustOpenFilesLimit() refactoring.
In this commit:
* Decrement steps are semantically differentiated from the reserved FDs.
  Previously both values were 32 but the meaning was different.
* Make it clear that we save setrlimit errno.
* Don't explicitly handle wrapping of 'f', but prevent it from
  happening.
* Add comments to make the function flow more readable.

This integrates PR #1630
2014-03-25 09:07:17 +01:00
Matt Stancliff b2a02cc92d Fix potentially incorrect errno usage
errno may be reset by the previous call to redisLog, so capture
the original value for proper error reporting.
2014-03-25 09:07:17 +01:00
Matt Stancliff 01fe750c6a Add REDIS_MIN_RESERVED_FDS define for open fds
Also update the original REDIS_EVENTLOOP_FDSET_INCR to
include REDIS_MIN_RESERVED_FDS. REDIS_EVENTLOOP_FDSET_INCR
exists to make sure more than (maxclients+RESERVED) entries
are allocated, but we can only guarantee that if we include
the current value of REDIS_MIN_RESERVED_FDS as a minimum
for the INCR size.
2014-03-25 09:07:17 +01:00
Matt Stancliff 1e7b99809b Fix infinite loop on startup if ulimit too low
Fun fact: rlim_t is an unsigned long long on all platforms.

Continually subtracting from a rlim_t makes it get smaller
and smaller until it wraps, then you're up to 2^64-1.

This was causing an infinite loop on Redis startup if
your ulimit was extremely (almost comically) low.

The case of (f > oldlimit) would never be met in a case like:

    f = 150
    while (f > 20) f -= 128

Since f is unsigned, it can't go negative and would
take on values of:

    Iteration 1: 150 - 128 => 22
    Iteration 2:  22 - 128 => 18446744073709551510
    Iterations 3-∞: ...

To catch the wraparound, we use the previous value of f
stored in limit.rlimit_cur.  If we subtract from f and
get a larger number than the value it had previously,
we print an error and exit since we don't have enough
file descriptors to help the user at this point.

Thanks to @bs3g for the inspiration to fix this problem.
Patches existed from @bs3g at antirez#1227, but I needed to repair a few other
parts of Redis simultaneously, so I didn't get a chance to use them.
2014-03-25 09:07:17 +01:00
Matt Stancliff f701a347b8 Improve error handling around setting ulimits
The log messages about open file limits have always
been slightly opaque and confusing.  Here's an attempt to
fix their wording, detail, and meaning.  Users will have a
better understanding of how to fix very common problems
with these reworded messages.

Also, we handle a new error case when maxclients becomes less
than one, essentially rendering the server unusable.  We
now exit on startup instead of leaving the user with a server
unable to handle any connections.

This fixes antirez#356 as well.
2014-03-25 09:07:17 +01:00
Matt Stancliff 6f4be45997 Replace magic 32 with REDIS_EVENTLOOP_FDSET_INCR
32 was the additional number of file descriptors Redis
would reserve when managing a too-low ulimit.  The
number 32 was in too many places statically, so now
we use a macro instead that looks more appropriate.

When Redis sets up the server event loop, it uses:
    server.maxclients+REDIS_EVENTLOOP_FDSET_INCR

So, when reserving file descriptors, it makes sense to
reserve at least REDIS_EVENTLOOP_FDSET_INCR FDs instead
of only 32.  Currently, REDIS_EVENTLOOP_FDSET_INCR is
set to 128 in redis.h.

Also, I replaced the static 128 in the while f < old loop
with REDIS_EVENTLOOP_FDSET_INCR as well, which results
in no change since it was already 128.

Impact: Users now need at least maxclients+128 as
their open file limit instead of maxclients+32 to obtain
actual "maxclients" number of clients.  Redis will carve
the extra REDIS_EVENTLOOP_FDSET_INCR file descriptors it
needs out of the "maxclients" range instead of failing
to start (unless the local ulimit -n is too low to accomidate
the request).
2014-03-25 09:07:17 +01:00
Matt Stancliff 49b576cb6c Fix maxclients error handling
Everywhere in the Redis code base, maxclients is treated
as an int with (int)maxclients or `maxclients = atoi(source)`,
so let's make maxclients an int.

This fixes a bug where someone could specify a negative maxclients
on startup and it would work (as well as set maxclients very high)
because:

    unsigned int maxclients;
    char *update = "-300";
    maxclients = atoi(update);
    if (maxclients < 1) goto fail;

But, (maxclients < 1) can only catch the case when maxclients
is exactly 0.  maxclients happily sets itself to -300, which isn't
-300, but rather 4294966996, which isn't < 1, so... everything
"worked."

maxclients config parsing checks for the case of < 1, but maxclients
CONFIG SET parsing was checking for case of < 0 (allowing
maxclients to be set to 0).  CONFIG SET parsing is now updated to
match config parsing of < 1.

It's tempting to add a MINIMUM_CLIENTS define, but... I didn't.

These changes were inspired by antirez#356, but this doesn't
fix that issue.
2014-03-25 09:07:17 +01:00
antirez 317ec18214 Fixed undefined variable value with certain code paths.
In sentinelFlushConfig() fd could be undefined when the following if
statement was true:

        if (rewrite_status == -1) goto werr;

This could cause random file descriptors to get closed.
2014-03-24 21:10:00 +01:00
Matt Stancliff 19ecf7cdba Use LRU_CLOCK() instead of function getLRUClock()
lookupKey() uses LRU_CLOCK(), so it seems object
creation should use LRU_CLOCK() too.
2014-03-24 21:10:00 +01:00
Matt Stancliff 73c2bcca85 Sentinel: Notify user when config can't be saved 2014-03-24 21:10:00 +01:00
Matt Stancliff 65e0452886 Fix data loss when save AOF/RDB with no free space
Previously, the (!fp) would only catch lack of free space
under OS X.  Linux waits to discover it can't write until
it actually writes contents to disk.

(fwrite() returns success even if the underlying file
has no free space to write into.  All the errors
only show up at flush/sync/close time.)

Fixes antirez/redis#1604
2014-03-24 21:10:00 +01:00
Matt Stancliff 4af72d326e Cluster: Restore proper trib master iteration
This got removed in 2e5c394 during a new feature addition.

The prior commit had "break if masters.length == masters_count"
but we are guaranteed to aready have that condition met since
otherwise we would haven't gotten this far.

Without this break statement, it's possible some masters may
be forgotten and have zero replicas while other masters have
more than their requested number of replicas.

Thanks to carlos for pointing out this regression at:
https://groups.google.com/forum/#!topic/redis-db/_WVVqDw5B7c
2014-03-24 21:10:00 +01:00
Matt Stancliff ee18135a19 Cluster: Fix trib create when masters==replicas
This bug was introduced in 2e5c394f during a refactor.

It took me a while to understand what was going on with
the code, so I've refactored it further by:
  - Replacing boolean values with meaningful symbols
  - Replacing 'i' with a meaningful variable name
  - Adding the proper abort check
  - Factoring out now duplicated conditionals
  - Adding optional verbose logging (we're inside *four*
    different looping constructs, so it takes a while to
    figure out where all the moving parts are)
  - Updating comment for the section

This fixes a problem when the number of master instances
equaled the number of replica instances.  Before, when
there were equal numbers of both, nodes_count would go to
zero, but the while loop would spin in i < @replicas because
i would never be updated (because the nodes_list of each ip
was length == 0, which triggered an endless loop of
next -> i = 0 -> 0 < 1? -> true -> next -> i = 0 ...)

Thanks to carlo who found this problem at:
https://groups.google.com/forum/#!topic/redis-db/_WVVqDw5B7c
2014-03-24 21:10:00 +01:00
Jan-Erik Rediger 9fa96697a9 Fixed a few typos. 2014-03-24 21:10:00 +01:00
Matt Stancliff a7478079a1 Cluster: remove variable causing warning
GCC-4.9 warned about this, but clang didn't.

This commit fixes warning:
sentinel.c: In function 'sentinelReceiveHelloMessages':
sentinel.c:2156:43: warning: variable 'master' set but not used [-Wunused-but-set-variable]
     sentinelRedisInstance *ri = c->data, *master;
2014-03-24 21:10:00 +01:00
Jan-Erik Rediger 46904ae22b Finally fix the install_server.sh script.
Includes changes from a dozen bug reports and pull requests.
Was tested on Ubuntu, Debian and CentOS.
2014-03-24 18:12:55 +01:00
antirez 2dd8c46249 Sample and cache RSS in serverCron().
Obtaining the RSS (Resident Set Size) info is slow in Linux and OSX.
This slowed down the generation of the INFO 'memory' section.

Since the RSS does not require to be a real-time measurement, we
now sample it with server.hz frequency (10 times per second by default)
and use this value both to show the INFO rss field and to compute the
fragmentation ratio.

Practically this does not make any difference for memory profiling of
Redis but speeds up the INFO call significantly.
2014-03-24 12:03:41 +01:00
antirez ae211be98b sdscatvprintf(): Try to use a static buffer.
For small content the function now tries to use a static buffer to avoid
a malloc/free cycle that is too costly when the function is used in the
context of performance critical code path such as INFO output generation.

This change was verified to have positive effects in the execution speed
of the INFO command.
2014-03-24 10:23:55 +01:00
antirez 571d6b01de Cache uname() output across INFO calls.
Uname was profiled to be a slow syscall. It produces always the same
output in the context of a single execution of Redis, so calling it at
every INFO output generation does not make too much sense.

The uname utsname structure was modified as a static variable. At the
same time a static integer was added to check if we need to call uname
the first time.
2014-03-24 10:02:55 +01:00
antirez 06b2a389eb sdscatvprintf(): guess buflen using format length.
sdscatvprintf() uses a loop where it tries to output the formatted
string in a buffer of the initial length, if there was not enough room,
a buffer of doubled size is tried and so forth.

The initial guess for the buffer length was very poor, an hardcoded
"16". This caused the printf to be processed multiple times without a
good reason. Given that printf functions are already not fast, the
overhead was significant.

The new heuristic is to use a buffer 4 times the length of the format
buffer, and 32 as minimal size. This appears to be a good balance for
typical uses of the function inside the Redis code base.

This change improved INFO command performances 3 times.
2014-03-24 09:44:49 +01:00
antirez fd70c68c97 Add test-lru.rb to utils.
This is a program useful to evaluate the Redis LRU algorithm behavior.
2014-03-21 09:57:02 +01:00
antirez 24c350245d Use getLRUClock() instead of server.lruclock to create objects.
Thanks to Matt Stancliff for noticing this error. It was in the original
code but somehow I managed to remove the change from the commit...
2014-03-21 09:57:02 +01:00
antirez 7f274e3bfe The default maxmemory policy is now noeviction.
This is safer as by default maxmemory should just set a memory limit
without any key to be deleted, unless the policy is set to something
more relaxed.
2014-03-21 09:57:02 +01:00
antirez a219339ee0 Use 24 bits for the lru object field and improve resolution.
There were 2 spare bits inside the Redis object structure that are now
used in order to enlarge 4x the range of the LRU field.

At the same time the resolution was improved from 10 to 1 second: this
still provides 194 days before the LRU counter overflows (restarting from
zero).

This is not a problem since it only causes lack of eviction precision for
objects not touched for a very long time, and the lack of precision is
only temporary.
2014-03-21 09:57:02 +01:00
antirez 9928b53102 Default LRU samples is now 5. 2014-03-21 09:57:02 +01:00
antirez fd5e8c0132 Use new dictGetRandomKeys() API to get samples for eviction.
The eviction quality degradates a bit in my tests, but since the API is
faster, it allows to raise the number of samples, and overall is a win.
2014-03-21 09:57:02 +01:00
antirez 10c8d86242 struct dictEntry -> dictEntry. 2014-03-21 09:57:02 +01:00
antirez 26292670fa Added dictGetRandomKeys() to dict.c: mass get random entries.
This new function is useful to get a number of random entries from an
hash table when we just need to do some sampling without particularly
good distribution.

It just jumps at a random place of the hash table and returns the first
N items encountered by scanning linearly.

The main usefulness of this function is to speedup Redis internal
sampling of the key space, for example for key eviction or expiry.
2014-03-21 09:57:02 +01:00
antirez c641074a21 LRU eviction pool implementation.
This is an improvement over the previous eviction algorithm where we use
an eviction pool that is persistent across evictions of keys, and gets
populated with the best candidates for evictions found so far.

It allows to approximate LRU eviction at a given number of samples
better than the previous algorithm used.
2014-03-21 09:57:02 +01:00
antirez c9ac817cc0 Fix OBJECT IDLETIME return value converting to seconds.
estimateObjectIdleTime() returns a value in milliseconds now, so we need
to scale the output of OBJECT IDLETIME to seconds.
2014-03-21 09:57:02 +01:00
antirez 205c2ccc0c Obtain LRU clock in a resolution dependent way.
For testing purposes it is handy to have a very high resolution of the
LRU clock, so that it is possible to experiment with scripts running in
just a few seconds how the eviction algorithms works.

This commit allows Redis to use the cached LRU clock, or a value
computed on demand, depending on the resolution. So normally we have the
good performance of a precomputed value, and a clock that wraps in many
days using the normal resolution, but if needed, changing a define will
switch behavior to an high resolution LRU clock.
2014-03-21 09:57:02 +01:00
antirez 561e793472 Specify lruclock in redisServer structure via REDIS_LRU_BITS.
The padding field was totally useless: removed.
2014-03-21 09:57:02 +01:00
antirez 8f0b74910a Specify LRU resolution in milliseconds. 2014-03-21 09:57:02 +01:00
antirez 63aacbe86c Set LRU parameters via REDIS_LRU_BITS define. 2014-03-21 09:57:02 +01:00
antirez 8b6a674a5d Unify stats reset for CONFIG RESETSTAT / initServer().
Now CONFIG RESETSTAT makes sure to reset all the fields, and in the
future it will be simpler to avoid missing new fields.
2014-03-21 09:57:02 +01:00
antirez 128dcee43d Sentinel: sentinelRefreshInstanceInfo() minor refactoring.
Test sentinel.tilt condition on top and return if it is true.
This allows to remove the check for the tilt condition in the remaining
code paths of the function.
2014-03-21 09:57:02 +01:00
antirez b104015fb3 Sentinel test: 02 unit better coverage + refactoring. 2014-03-21 09:57:02 +01:00
antirez f5f281f906 Sentinel test: foreach_instance_id implements 'break'. 2014-03-21 09:57:02 +01:00
antirez f308f67703 Sentinel: instance_is_killed proc added to sentinel.tcl. 2014-03-21 09:57:02 +01:00
antirez 0774d4928a Sentinel: propagate down-after-ms changes to slaves and sentinels. 2014-03-21 09:57:02 +01:00
antirez a86e24de93 Sentinel: down-after-milliseconds is not master-specific.
addReplySentinelRedisInstance() modified so that this field is displayed
for all the kind of instances: Sentinels, Masters, Slaves.
2014-03-21 09:57:02 +01:00
antirez 9997b51ff8 Sentinel failure detection implementation improved.
Failure detection in Sentinel is ping-pong based. It used to work by
remembering the last time a valid PONG reply was received, and checking
if the reception time was too old compared to the current current time.

PINGs were sent at a fixed interval of 1 second.

This works in a decent way, but does not scale well when we want to set
very small values of "down-after-milliseconds" (this is the node
timeout basically).

This commit reiplements the failure detection making a number of
changes. Some changes are inspired to Redis Cluster failure detection
code:

* A new last_ping_time field is added in representation of instances.
  If non zero, we have an active ping that was sent at the specified
  time. When a valid reply to ping is received, the field is zeroed
  again.
* last_ping_time is not reset when we reconnect the link or send a new
  ping, so from our point of view it represents the time we started
  waiting for the instance to reply to our pings without receiving a
  reply.
* last_ping_time is now used in order to check if the instance is
  timed out. This means that we can have a node timeout of 100
  milliseconds and yet the system will work well since the new check is
  not bound to the period used to send pings.
* Pings are now sent every second, or often if the value of
  down-after-milliseconds is less than one second. With a lower limit of
  10 HZ ping frequency.
* Link reconnection code was improved. This is used in order to try to
  reconnect the link when we are at 50% of the node timeout without a
  valid reply received yet. However the old code triggered unnecessary
  reconnections when the node timeout was very small. Now that should be
  ok.

The new code passes the tests but more testing is needed and more unit
tests stressing the failure detector, so currently this is merged only
in the unstable branch.
2014-03-21 09:57:02 +01:00
antirez 04cd7f773d Sentinel: use CLIENT SETNAME when connecting to Redis.
This makes debugging / monitoring of Sentinels simpler since you can
identify sentinels in CLIENT LIST output of Redis instances.
2014-03-21 09:57:02 +01:00
antirez 32f188cdf7 redis-trib: call MIGRATE via r.client.call as fix for redis-rb API changes.
See issue #1593.

Thanks to @badboy for suggesting the direct client.call fix.
2014-03-15 11:02:59 +01:00
Matt Stancliff 0c8f0079f9 Fix segfault from accessing array out of bounds
argc == 2; argv[2] == crash
2014-03-14 22:57:29 +01:00
antirez 668a95a583 Sentinel: be safe under crash-recovery assumptions.
Sentinel's main safety argument is that there are no two configurations
for the same master with the same version (configuration epoch).

For this to be true Sentinels require to be authorized by a majority.
Additionally Sentinels require to do two important things:

* Never vote again for the same epoch.
* Never exchange an old vote for a fresh one.

The first prerequisite, in a crash-recovery system model, requires to
persist the master->leader_epoch on durable storage before to reply to
messages. This was not the case.

We also make sure to persist the current epoch in order to never reply
to stale votes requests from other Sentinels, after a recovery.

The configuration is persisted by making use of fsync(), this is
considered in the context of this code a good enough guarantee that
after a restart our durable state is restored, however this may not
always be the case depending on the kind of hardware and operating
system used.
2014-03-14 22:57:25 +01:00
antirez ca2a3b3240 Sentinel: fake PUBLISH command to receive HELLO messages.
Now the way HELLO messages are received is unified.
Now it is no longer needed for Sentinels to converge to the higher
configuration for a master to be able to chat via some Redis instance,
the are able to directly exchanges configurations.

Note that this commit does not include the (trivial) change needed to
send HELLO messages to Sentinel instances as well, since for an error I
committed the change in the previous commit that refactored hello
messages processing into a separated function.
2014-03-14 11:09:32 +01:00
antirez ee513ee958 Sentinel: HELLO processing refactored into sentinelProcessHelloMessage(). 2014-03-14 11:09:32 +01:00
antirez 9e82461af0 Linenoise updated, multiline mode enabled in redis-cli. 2014-03-13 15:11:41 +01:00
antirez e0ef510630 Redis 2.9.51 (Redis 3.0.0 beta-2). 2014-03-11 16:13:39 +01:00
antirez e917de12d0 Cluster: flag the transaction as dirty for the new redirections. 2014-03-11 15:19:00 +01:00
antirez 07036ad45e redis-trib: new subcommand 'call'. Exec command in all nodes.
Example:

./redis-trib.rb call 192.168.1.11:7000 config get cluster-node-timeout
2014-03-11 15:02:41 +01:00
antirez a02424e29b redis-trib: create subcommand is now able to assign spare slaves.
Example: if the user will try to configure a cluster with 9 nodes,
asking for 1 slave for master, redis-trib will configure a 4 masters
cluster with 1 slave each as usually, but this time will assign the
spare node as a slave of one of the masters.
2014-03-11 15:02:41 +01:00
antirez 412a759a83 Cluster: update node configEpoch on UPDATE messages.
The UPDATE message contains the configEpoch of the node configuration
advertised in the packet. Update it if needed.
2014-03-11 15:02:41 +01:00
antirez 48702e0011 Cluster: set slot error if we receive an update for a busy slot.
By manually modifying nodes configurations in random ways, it is possible
to create the following scenario:

A is serving keys for slot 10
B is manually configured to serve keys for slot 10

A receives an update from B (or another node) where it is informed that
the slot 10 is now claimed by B with a greater configuration epoch,
however A still has keys from slot 10.

With this commit A will put the slot in error setting it in IMPORTING
state, so that redis-trib can detect the issue.
2014-03-11 15:02:41 +01:00
antirez efd0346ea3 Cluster: clarified a comment in clusterUpdateSlotsConfigWith(). 2014-03-11 15:02:41 +01:00
antirez 47e3f1f16c Cluster: flush importing/migrating state when master is turned into slave. 2014-03-11 15:02:41 +01:00
antirez 117557192e Cluster: clusterCloseAllSlots() added. 2014-03-11 15:02:41 +01:00
antirez 01eee56f4f DEBUG ERROR implemented.
The new "error" subcommand of the DEBUG command can reply with an user
selected error, specified as its sole argument:

    DEBUG ERROR "LOADING please wait..."

The error is generated just prefixing the command argument with a "-"
character, and replacing newlines with spaces (since error replies can't
include newlines).

The goal of the command is to help in Client libraries unit tests by
making simple to simulate a command call triggering a given error.
2014-03-11 11:10:33 +01:00
antirez ab8e1bbcdc DEBUG CMDKEYS: provide some guarantee to getKeysFromCommand().
getKeysFromCommand() is designed to be called with the command arguments
passing the basic arity checks described in the command table.

DEBUG CMDKEYS must provide the same guarantees for calling
getKeysFromCommand() to be safe.
2014-03-11 11:10:33 +01:00
antirez 94129415bf Cluster: make sortGetKeys() able to handle multiple STORE options.
It does not make sense to pass multiple store options, so, better to
handle it ;-)
2014-03-11 11:10:33 +01:00
antirez db0d9f4326 DEBUG CMDKEYS added for getKeysFromCommand() testing.
Examples:

    redis 127.0.0.1:6379> debug cmdkeys set foo bar
    1) "foo"
    redis 127.0.0.1:6379> debug cmdkeys mget a b c
    1) "a"
    2) "b"
    3) "c"
    redis 127.0.0.1:6379> debug cmdkeys zunionstore foo 2 a b
    1) "a"
    2) "b"
    3) "foo"
    redis 127.0.0.1:6379> debug cmdkeys ping
    (empty list or set)
2014-03-11 11:10:33 +01:00
antirez 3b80e0a41d Cluster: don't allow BY option of SORT as well.
There is the exception of a "constant" BY pattern that is used in order
to signal to don't sort at all. In this case no lookup is needed so it
is possible to support this case in Cluster mode.
2014-03-11 11:10:33 +01:00
antirez 399fca8f45 Cluster: SORT get keys helper implemented. 2014-03-11 11:10:33 +01:00
antirez 0c38b3c934 Cluster: evalGetKeys() fixed: was not setting keys count. 2014-03-11 11:10:33 +01:00
antirez d7451a0110 Cluster: don't allow GET option in cluster mode.
The commit also refactors a bit the error handling during SORT option
parsing.
2014-03-11 11:10:33 +01:00
antirez c3aff0c20a Fixed memory leak in SORT LIMIT option argument parsing on error. 2014-03-11 11:10:33 +01:00
antirez fdf737e132 Cluster: getKeysFromCommand() top comment improved. 2014-03-11 11:10:33 +01:00
antirez 81efa0d296 Cluster: evalGetKey() added for EVAL/EVALSHA.
Previously we used zunionInterGetKeys(), however after this function was
fixed to account for the destination key (not needed when the API was
designed for "diskstore") the two set of commands can no longer be served
by an unique keys-extraction function.
2014-03-11 11:10:09 +01:00
antirez 0618d26b89 Cluster: getKeysFromCommand() and related: top-comments added. 2014-03-11 11:10:09 +01:00
antirez a2a72b87e0 Cluster: getKeysFromCommand() API cleaned up.
This API originated from the "diskstore" experiment, not for Redis
Cluster itself, so there were legacy/useless things trying to
differentiate between keys that are going to be overwritten and keys
that need to be fetched from disk (preloaded).

All useless with Cluster, so removed with the result of code
simplification.
2014-03-11 11:10:09 +01:00
antirez c8485703f5 Cluster: some zunionInterGetKeys() comment trimmed.
Everything was pretty clear again from the initial statements.
2014-03-11 11:10:09 +01:00
antirez d610d2343d Cluster: abort on port too high error.
It also fixes multi-line comment style to be consistent with the rest of
the code base.

Related to #1555.
2014-03-11 11:10:09 +01:00
antirez 2a951ce502 Cluster: be explicit about passing NULL as bind addr for connect.
The code was already correct but it was using that bindaddr[0] is set to
NULL as a side effect of current implementation if no bind address is
configured. This is not guarnteed to hold true in the future.
2014-03-11 11:10:09 +01:00
antirez 9c9914d779 Cluster: log error when anetTcpNonBlockBindConnect() fails. 2014-03-11 11:10:09 +01:00
antirez 3119f4f694 Cluster: better timeout and retry time for failover.
When node-timeout is too small, in the order of a few milliseconds,
there is no way the voting process can terminate during that time, so we
set a lower limit for the failover timeout of two seconds.

The retry time is set to two times the failover timeout time, so it is
at least 4 seconds.
2014-03-11 11:10:09 +01:00
Matt Stancliff 14f77b343a Fix key extraction for z{union,inter}store
The previous implementation wasn't taking into account
the storage key in position 1 being a requirement (it
was only counting the source keys in positions 3 to N).

Fixes antirez/redis#1581
2014-03-11 11:10:09 +01:00
antirez 63fc5dc8b1 Typo in sentinel.conf, exists -> exits. 2014-03-11 11:10:09 +01:00
antirez afe28cfd75 Cluster: fix conditional generating TRYAGAIN error. 2014-03-11 11:10:09 +01:00
antirez aa5898f53e Redis Cluster: support for multi-key operations. 2014-03-11 11:10:09 +01:00
Matt Stancliff c0915ad1a0 Reset op_sec_last_sample_ops when reset requested
This value needs to be set to zero (in addition to
stat_numcommands) or else people may see
a negative operations per second count after they
run CONFIG RESETSTAT.

Fixes antirez/redis#1577
2014-03-11 11:10:09 +01:00
Matt Stancliff 4b3c87a027 Remove redundant IP length definition
REDIS_CLUSTER_IPLEN had the same value as
REDIS_IP_STR_LEN.  They were both #define'd
to the same INET6_ADDRSTRLEN.
2014-03-11 11:10:09 +01:00
Matt Stancliff 7c8964a8cf Remove some redundant code
Function nodeIp2String in cluster.c is exactly
anetPeerToString with a pre-extracted fd.
2014-03-11 11:09:37 +01:00
Matt Stancliff 7c359449d5 Fix return value check for anetTcpAccept
anetTcpAccept returns ANET_ERR, not AE_ERR.

This isn't a physical error since both ANET_ERR
and AE_ERR are -1, but better to be consistent.
2014-03-11 11:09:37 +01:00
Jan-Erik Rediger 6766fc561e Small typo fixed 2014-03-11 11:09:37 +01:00
Matt Stancliff 9a7cf31960 Bind source address for cluster communication
The first address specified as a bind parameter
(server.bindaddr[0]) gets used as the source IP
for cluster communication.

If no bind address is specified by the user, the
behavior is unchanged.

This patch allows multiple Redis Cluster instances
to communicate when running on the same interface
of the same host.
2014-03-11 11:09:37 +01:00
zhanghailei 503938022f refer to updateLRUClock's comment REDIS_LRU_CLOCK_MAX is 22 bits,but #define REDIS_LRU_CLOCK_MAX ((1<<21)-1) only 21 bits 2014-03-11 11:09:37 +01:00
zhanghailei 7eec424953 FIXED a typo more thank should be more than 2014-03-11 11:09:37 +01:00
zhanghailei 0abe98cb4d According to context,the size should be 16 rather than 64 2014-03-11 11:09:37 +01:00
Matt Stancliff a0ea8f235e Cluster: error out quicker if port is unusable
The default cluster control port is 10,000 ports higher than
the base Redis port.  If Redis is started on a too-high port,
Cluster can't start and everything will exit later anyway.
2014-03-11 11:09:37 +01:00
Matt Stancliff 6f4b5ef6d5 Fix "can't bind to address" error reporting.
Report the actual port used for the listening attempt instead of
server.port.

Originally, Redis would just listen on server.port.
But, with clustering, Redis uses a Cluster Port too,
so we can't say server.port is always where we are listening.

If you tried to launch Redis with a too-high port number (any
port where Port+10000 > 65535), Redis would refuse to start, but
only print an error saying it can't connect to the Redis port.

This patch fixes much confusions.
2014-03-11 11:09:37 +01:00
antirez 4d5ba5962c Cast saveparams[].seconds to long for %ld format specifier. 2014-03-05 11:26:46 +01:00
antirez ef4e465316 Sentinel test: set less time sensitive defaults.
This commit sets the failover timeout to 30 seconds instead of the 180
seconds default, and allows to reconfigure multiple slaves at the same
time.

This makes tests less sensible to timing, with the result that there are
less false positives due to normal behaviors that require time to
succeed or to be retried.

However the long term solution is probably some way in order to detect
when a test failed because of timing issues (for example split brain
during leader election) and retry it.
2014-03-05 10:22:07 +01:00
antirez 313f8831ed Sentinel: more aggressive failover start desynchronization.
Sentinel needs to avoid split brain conditions due to multiple sentinels
trying to get voted at the exact same time.

So far some desynchronization was provided by fluctuating server.hz,
that is the frequency of the timer function call. However the
desynchonization provided in this way was not enough when using many
Sentinel instances, especially when a large quorum value is used in
order to force a greater degree of agreement (more than N/2+1).

It was verified that it was likely to trigger a split brain
condition, forcing the system to try again after a timeout.
Usually the system will succeed after a few retries, but this is not
optimal.

This commit desynchronizes instances in a more effective way to make it
likely that the first attempt will be successful.
2014-03-05 10:22:07 +01:00
antirez 5ee2394474 CONFIG REWRITE should be logged at WARNING level. 2014-03-05 10:22:07 +01:00
antirez fa8aca5236 Sentinel test: debugging console improved. 2014-03-05 10:22:07 +01:00
antirez cf746c398c Sentinel test: initial debugging console. 2014-03-05 10:22:07 +01:00
antirez cbf51b60a2 Sentinel test: be more patient in create_redis_master_slave_cluster. 2014-03-05 10:22:07 +01:00
antirez 23a12bb8c1 Sentiel test: add test start time in output. 2014-03-05 10:22:07 +01:00
antirez d2e16801f0 Cluster: invalidate current transaction on redirections. 2014-03-05 10:22:07 +01:00
antirez 21557a0d8b Sentinel test: use 1000 as retry in initial 00 unit test. 2014-03-05 10:22:07 +01:00
antirez 290a5d7ff6 Sentinel test: initial tests in 03 unit. 2014-03-05 10:22:07 +01:00
antirez b2668466f4 Sentinel test: foreach_instance_id now supports 'continue'. 2014-03-05 10:22:07 +01:00
antirez a76bca16e6 Sentienl test: fixed typo in unit 03 top comment. 2014-03-05 10:22:07 +01:00
antirez 1d9eb47f9d Document why we update peak memory in INFO. 2014-03-05 10:22:07 +01:00
antirez e4833ed8bf Fix configEpoch assignment when a cluster slot gets "closed".
This is still code to rework in order to use agreement to obtain a new
configEpoch when a slot is migrated, however this commit handles the
special case that happens when the nodes are just started and everybody
has a configEpoch of 0. In this special condition to have the maximum
configEpoch is not enough as the special epoch 0 is not unique (all the
others are).

This does not fixes the intrinsic race condition of a failover happening
while we are resharding, that will be addressed later.
2014-03-05 10:22:07 +01:00
Matt Stancliff 7c092b679f Force INFO used_memory_peak to match peak memory
used_memory_peak only updates in serverCron every server.hz,
but Redis can use more memory and a user can request memory
INFO before used_memory_peak gets updated in the next
cron run.

This patch updates used_memory_peak to the current
memory usage if the current memory usage is higher
than the recorded used_memory_peak value.

(And it only calls zmalloc_used_memory() once instead of
twice as it was doing before.)
2014-03-05 10:22:07 +01:00
michael-grunder 23addbb5a3 Improved bigkeys with progress, pipelining and summary
This commit reworks the redis-cli --bigkeys command to provide more
information about our progress as well as output summary information
when we're done.

 - We now show an approximate percentage completion as we go
 - Hiredis pipelining is used for TYPE and SIZE retreival
 - A summary of keyspace distribution and overall breakout at the end
2014-03-05 10:22:07 +01:00
antirez a46811693d Sentinel test: Makefile target added. 2014-02-28 16:00:14 +01:00
antirez 32db37c3c4 BITPOS fuzzy testing. 2014-02-27 15:52:43 +01:00
antirez 1d62f83364 Basic BITPOS tests. 2014-02-27 15:52:43 +01:00
antirez 9104f1e672 warnigns -> warnings in redisBitpos(). 2014-02-27 15:52:43 +01:00
antirez eacc0951a2 More consistent BITPOS behavior with bit=0 and ranges.
With the new behavior it is possible to specify just the start in the
range (the end will be assumed to be the first byte), or it is possible
to specify both start and end.

This is useful to change the behavior of the command when looking for
zeros inside a string.

1) If the user specifies both start and end, and no 0 is found inside
   the range, the command returns -1.

2) If instead no range is specified, or just the start is given, even
   if in the actual string no 0 bit is found, the command returns the
   first bit on the right after the end of the string.

So for example if the string stored at key foo is "\xff\xff":

    BITPOS foo (returns 16)
    BITPOS foo 0 -1 (returns -1)
    BITPOS foo 0 (returns 16)

The idea is that when no end is given the user is just looking for the
first bit that is zero and can be set to 1 with SETBIT, as it is
"available". Instead when a specific range is given, we just look for a
zero within the boundaries of the range.
2014-02-27 15:52:43 +01:00
antirez 1f8005ca09 Initial implementation of BITPOS.
It appears to work but more stress testing, and both unit tests and
fuzzy testing, is needed in order to ensure the implementation is sane.
2014-02-27 15:52:43 +01:00
antirez cbeaf17374 Added two more BITCOUNT tests stressing misaligned access. 2014-02-27 15:52:43 +01:00
antirez 9c206cc8e8 BITCOUNT fuzzy test with random start/end added.
It was verified in practice that this test is able to stress much more
the implementation by introducing errors that were only trivially to
detect with different offsets but impossible to detect starting always
at zero and counting bits the full length of the string.
2014-02-27 15:52:43 +01:00
antirez 24265edb6c Fix misaligned word access in redisPopcount(). 2014-02-27 15:52:43 +01:00
Matt Stancliff 7e274194bf Fix IP representation in clusterMsgDataGossip 2014-02-27 15:52:43 +01:00
antirez d242b698f4 Sentinel test: add stub for unit 04. 2014-02-25 15:55:21 +01:00
antirez cd8b149dff Sentinel test: added TODO items in 02 unit. 2014-02-25 15:55:21 +01:00
antirez c12ebb4633 Sentinel test: check role at end of unit 01. 2014-02-25 15:09:46 +01:00
michael-grunder a2b3f2eae2 Update --bigkeys to use SCAN
This commit changes the findBigKeys() function in redis-cli.c to use the new
SCAN command for iterating the keyspace, rather than RANDOMKEY.  Because we
can know when we're done using SCAN, it will exit after exhausting the keyspace.
2014-02-25 15:09:46 +01:00
antirez cb7ccc9ad0 Sentinel test: kill masters instead of using DEBUG SLEEP in all tests. 2014-02-25 15:09:46 +01:00
antirez 48fa34bf9e redis-cli: also remove useless uint8_t. 2014-02-25 15:09:46 +01:00
antirez ff20d05650 redis-cli: don't use uint64_t where actually not needed.
The computation is just something to take the CPU busy, no need to use a
specific type. Since stdint.h was not included this prevented
compilation on certain systems.
2014-02-25 15:09:46 +01:00
antirez 6a95ddb248 redis-cli: check argument existence for --pattern. 2014-02-25 15:09:46 +01:00
antirez 2431b63ff4 redis-cli: --intrinsic-latency run mode added. 2014-02-25 15:09:46 +01:00
antirez 68e9597e8a redis-cli: added comments to split program in parts. 2014-02-25 15:09:46 +01:00
antirez 31ed0911fa Sentinel test: restart instances left killed by previous unit.
An unit can abort in the middle for an error. The next unit should not
assume that the instances are in a clean state, and must restart what
was left killed.
2014-02-25 10:24:16 +01:00
antirez edf48d17a2 Sentinel test: jump to next unit on test failure.
Sentinel tests are designed to be dependent on the previous tests in the
same unit, so usually we can't continue with the next test in the same
unit if a previous test failed.
2014-02-25 10:24:16 +01:00
antirez 7f521d764f Sentinel test: test majority crashing Sentinels.
The test was previously performed by removing the master from the
Sentinel monitored masters. The test with the Sentinels crashed is
more similar to real-world partitions / failures.
2014-02-25 10:24:16 +01:00
antirez 491bcbaf73 Sentinel test: restart_instance should refresh pid attrib.
Also kill_instance was modified to warn when a test will try to kill the
same instance multiple times for error.
2014-02-25 10:24:16 +01:00
antirez 55643361f1 Sentinel test: more stuff mored from 00-base to init.
The area a number of mandatory tests to craete a stable setup for
testing that is not too sensitive to timing issues. All those tests
moved to includes/init-tests, and marked as (init).
2014-02-25 10:24:16 +01:00
antirez 4f6ed3412e Sentinel: log quorum with +monitor event. 2014-02-25 10:24:16 +01:00
antirez 55a2e10b03 Sentinel test: removed useless code to set SDOWN timeout.
The new common initialization code used to start a new unit already set
the timeout to 2000 milliseconds.
2014-02-25 10:24:16 +01:00
antirez 56e18ba4f6 Sentinel: generate +monitor events at startup. 2014-02-25 10:24:16 +01:00
antirez cd68a1d45a Sentinel: log +monitor and +set events.
Now that we have a runtime configuration system, it is very important to
be able to log how the Sentinel configuration changes over time because
of API calls.
2014-02-25 10:24:16 +01:00
antirez 4af2acf2b0 Sentinel: added missing exit(1) after checking for config file. 2014-02-25 10:24:16 +01:00
antirez fecfd721df Sentinel test: tmp dir and gitignore added. 2014-02-25 10:24:16 +01:00
antirez b18109e351 Sentinel test: minor fixes to --pause-on-error. 2014-02-25 10:24:16 +01:00
antirez 2ed707bcaa Sentinel test: --pause-on-error option added.
Pause the test with running instances available for state inspection on
error.
2014-02-25 10:24:16 +01:00
antirez 2666f737b0 Sentinel test: added empty units to fill later. 2014-02-25 10:24:16 +01:00
antirez 6e2e6d5b8c Sentinel: IDONTKNOW error removed.
This error was conceived for the older version of Sentinel that worked
via master redirection and that was not able to get configuration
updates from other Sentinels via the Pub/Sub channel of masters or
slaves.

This reply does not make sense today, every Sentinel should reply with
the best information it has currently. The error will make even more
sense in the future since the plan is to allow Sentinels to update the
configuration of other Sentinels via gossip with a direct chat without
the prerequisite that they have at least a monitored instance in common.
2014-02-25 10:24:16 +01:00
antirez ec593b582e Sentinel test: framework improved and conf-update unit added.
It is now possible to kill and restart sentinel or redis instances for
more real-world testing.

The 01 unit tests the capability of Sentinel to update the configuration
of Sentinels rejoining the cluster, however the test is pretty trivial
and more tests should be added.
2014-02-25 10:24:16 +01:00
Matt Stancliff 5a8c9f94a6 Add cluster or sentinel to proc title
If you launch redis with `redis-server --sentinel` then
in a ps, your output only says "redis-server IP:Port" — this
patch changes the proc title to include [sentinel] or
[cluster] depending on the current server mode:
e.g.  "redis-server IP:Port [sentinel]"
      "redis-server IP:Port [cluster]"
2014-02-25 10:24:16 +01:00
antirez ef01bbe1f5 Sentinel test: move init tests as includes.
Most units will start with these two basic tests to create an
environment where the real tests are ran.
2014-02-25 10:24:16 +01:00
antirez 2b4bc4f900 Sentinel test: ability to run just a subset of test files. 2014-02-25 10:24:16 +01:00
Matt Stancliff 21a7f9e7ef Auto-enter slaveMode when SYNC from redis-cli
If someone asks for SYNC or PSYNC from redis-cli,
automatically enter slaveMode (as if they ran
redis-cli --slave) and continue printing the replication
stream until either they Ctrl-C or the master gets disconnected.
2014-02-25 10:24:16 +01:00
antirez 48d74f2039 Sentinel: report instances role switch events.
This is useful mostly for debugging of issues.
2014-02-20 12:28:18 +01:00
antirez 8a6774e209 Sentinel test: some reliability fixes to 00-base tests. 2014-02-20 12:28:18 +01:00
antirez 6bb42b5bfe Sentinel test: check that role matches at end of 00-base. 2014-02-20 12:28:18 +01:00
antirez 37be5987e6 Sentinel test: ODOWN and agreement. 2014-02-20 12:28:18 +01:00
antirez b037c897ae Sentinel test: check reconfig of slaves and old master. 2014-02-20 12:28:18 +01:00
antirez f7cb83778b Sentinel test: basic failover tested. Framework improvements. 2014-02-20 12:28:18 +01:00
antirez a11749f9f6 Sentinel test: basic tests for MONITOR and auto-discovery. 2014-02-20 12:28:18 +01:00
antirez 8292dd50cd Sentinel test: info fields, master-slave setup, fixes. 2014-02-20 12:28:18 +01:00
antirez 68a3d5602e Prefix test file names with numbers to force exec order. 2014-02-20 12:28:18 +01:00
antirez bbbe68aa0d Sentinel test: provide basic commands to access instances. 2014-02-20 12:28:18 +01:00
antirez 6e4662e479 Sentinel: SENTINEL_SLAVE_RECONF_RETRY_PERIOD -> RECONF_TIMEOUT
Rename define to match the new meaning.
2014-02-18 10:30:47 +01:00
antirez bd31fcf16e Sentinel: fix slave promotion timeout.
If we can't reconfigure a slave in time during failover, go forward as
anyway the slave will be fixed by Sentinels in the future, once they
detect it is misconfigured.

Otherwise a failover in progress may never terminate if for some reason
the slave is uncapable to sync with the master while at the same time
it is not disconnected.
2014-02-18 10:30:47 +01:00
antirez 2a35abcf12 Sentinel: initial testing framework.
Nothing tested at all so far... Just the infrastructure spawning N
Sentinels and N Redis instances that the test will use again and again.
2014-02-17 17:39:23 +01:00
antirez c1786693b1 Test: colorstr moved to util.tcl. 2014-02-17 17:39:19 +01:00
antirez 48af4d4f26 Test: code to test server availability refactored.
Some inline test moved into server_is_up procedure.
Also find_available_port was moved into util since it is going
to be used for the Sentinel test as well.
2014-02-17 17:39:15 +01:00
antirez 58b6dd9beb Get absoulte config file path before processig 'dir'.
The code tried to obtain the configuration file absolute path after
processing the configuration file. However if config file was a relative
path and a "dir" statement was processed reading the config, the absolute
path obtained was wrong.

With this fix the absolute path is obtained before processing the
configuration while the server is still in the original directory where
it was executed.
2014-02-17 17:39:12 +01:00
antirez c36a5dce54 Sentinel: better specify startup errors due to config file.
Now it logs the file name if it is not accessible. Also there is a
different error for the missing config file case, and for the non
writable file case.
2014-02-17 17:39:09 +01:00
antirez 3c1672da7d Update cached time in rdbLoad() callback.
server.unixtime and server.mstime are cached less precise timestamps
that we use every time we don't need an accurate time representation and
a syscall would be too slow for the number of calls we require.

Such an example is the initialization and update process of the last
interaction time with the client, that is used for timeouts.

However rdbLoad() can take some time to load the DB, but at the same
time it did not updated the time during DB loading. This resulted in the
bug described in issue #1535, where in the replication process the slave
loads the DB, creates the redisClient representation of its master, but
the timestamp is so old that the master, under certain conditions, is
sensed as already "timed out".

Thanks to @yoav-steinberg and Redis Labs Inc for the bug report and
analysis.
2014-02-13 15:13:38 +01:00
antirez 116617c5e7 Log when CONFIG REWRITE goes bad. 2014-02-13 14:33:53 +01:00
antirez 767846dc5b Test: regression for issue #1549.
It was verified that reverting the commit that fixes the bug, the test
no longer passes.
2014-02-13 12:27:10 +01:00
antirez 14143fbede Fix script cache bug in the scripting engine.
This commit fixes a serious Lua scripting replication issue, described
by Github issue #1549. The root cause of the problem is that scripts
were put inside the script cache, assuming that slaves and AOF already
contained it, even if the scripts sometimes produced no changes in the
data set, and were not actaully propagated to AOF/slaves.

Example:

    eval "if tonumber(KEYS[1]) > 0 then redis.call('incr', 'x') end" 1 0

Then:

    evalsha <sha1 step 1 script> 1 0

At this step sha1 of the script is added to the replication script cache
(the script is marked as known to the slaves) and EVALSHA command is
transformed to EVAL. However it is not dirty (there is no changes to db),
so it is not propagated to the slaves. Then the script is called again:

    evalsha <sha1 step 1 script> 1 1

At this step master checks that the script already exists in the
replication script cache and doesn't transform it to EVAL command. It is
dirty and propagated to the slaves, but they fail to evaluate the script
as they don't have it in the script cache.

The fix is trivial and just uses the new API to force the propagation of
the executed command regardless of the dirty state of the data set.

Thank you to @minus-infinity on Github for finding the issue,
understanding the root cause, and fixing it.
2014-02-13 12:16:31 +01:00
antirez 0296aab6da AOF write error: retry with a frequency of 1 hz. 2014-02-12 16:57:08 +01:00
antirez dd73a7bf43 AOF: don't abort on write errors unless fsync is 'always'.
A system similar to the RDB write error handling is used, in which when
we can't write to the AOF file, writes are no longer accepted until we
are able to write again.

For fsync == always we still abort on errors since there is currently no
easy way to avoid replying with success to the user otherwise, and this
would violate the contract with the user of only acknowledging data
already secured on disk.
2014-02-12 16:57:04 +01:00
antirez 910b6d34f2 Redis 2.9.50 (Redis 3.0.0 beta-1) 2014-02-11 10:47:54 +01:00
antirez 0725988a07 Cluster: clusterDelNode(): remove node from master's slaves. 2014-02-11 10:34:14 +01:00
antirez 4513d8fcd4 Cluster: UPDATE messages are the norm and verbose.
Logging them at WARNING level was of little utility and of sure disturb.
2014-02-11 10:22:05 +01:00
antirez 9721255178 Cluster: redis-trib fix: handling of another trivial case. 2014-02-11 10:22:02 +01:00
antirez 6d550f2de4 Cluster: configEpoch assignment in SETNODE improved.
Avoid to trash a configEpoch for every slot migrated if this node has
already the max configEpoch across the cluster.

Still work to do in this area but this avoids both ending with a very
high configEpoch without any reason and to flood the system with fsyncs.
2014-02-11 10:21:58 +01:00
antirez 585e9fb886 Cluster: clusterSetStartupEpoch() made more generally useful.
The actual goal of the function was to get the max configEpoch found in
the cluster, so make it general by removing the assignment of the max
epoch to currentEpoch that is useful only at startup.
2014-02-11 10:21:55 +01:00
antirez 8b5196addf Cluster: always increment the configEpoch in SETNODE after import.
Removed a stale conditional preventing the configEpoch from incrementing
after the import in certain conditions. Since the master got a new slot
it should always claim a new configuration.
2014-02-11 10:21:52 +01:00
antirez 2e3f6b0fb3 Cluster: on resharding upgrade version of receiving node.
The node receiving the hash slot needs to have a version that wins over
the other versions in order to force the ownership of the slot.

However the current code is far from perfect since a failover can happen
during the manual resharding. The fix is a work in progress but the
bottom line is that the new version must either be voted as usually,
set by redis-trib manually after it makes sure can't be used by other
nodes, or reserved configEpochs could be used for manual operations (for
example odd versions could be never used by slaves and are always used
by CLUSTER SETSLOT NODE).
2014-02-11 00:39:24 +01:00
antirez a221ae5ce2 Cluster: fsync at every SETSLOT command puts too pressure on disks.
During slots migration redis-trib can send a number of SETSLOT commands.
Fsyncing every time is a bit too much in production as verified
empirically.

To make sure configs are fsynced on all nodes after a resharding
redis-trib may send something like CLUSTER CONFSYNC.

In this case fsyncs were not providing too much value since anyway
processes can crash in the middle of the resharding of an hash slot, and
redis-trib should be able to recover from this condition anyway.
2014-02-11 00:39:20 +01:00
antirez 77c6fa65f1 Cluster: conditions to clear "migrating" on slot for SETSLOT ... NODE changed.
If the slot is manually assigned to another node, clear the migrating
status regardless of the fact it was previously assigned to us or not,
as long as we no longer have keys for this slot.

This avoid a race during slots migration that may leave the slot in
migrating status in the source node, since it received an update message
from the destination node that is already claiming the slot.

This way we are sure that redis-trib at the end of the slot migration is
always able to close the slot correctly.
2014-02-11 00:39:14 +01:00
antirez f406a09495 Cluster: remove debugging xputs from redis-trib. 2014-02-11 00:39:11 +01:00
antirez 01de246843 Cluster: redis-trib fix: cover new case of open slot.
The case is the trivial one a single node claiming the slot as
migrating, without nodes claiming it as importing.
2014-02-11 00:39:08 +01:00
antirez 8f25428772 redis-trib: log event after we have reference to 'master'. 2014-02-11 00:39:05 +01:00
antirez cc97305ec3 Cluster: don't update slave's master if we don't know it.
There is no way we can update the slave's node->slaveof pointer if we
don't know the master (no node with such an ID in our tables).
2014-02-11 00:39:02 +01:00
antirez fa6f4f21c3 Cluster: ignore slot config changes if we are importing it. 2014-02-11 00:38:59 +01:00
antirez 30214fff3e Cluster: update configEpoch after manually messing with slots. 2014-02-11 00:38:56 +01:00
antirez cfcb09bf76 Cluster: redis-trib, more info about open slots error. 2014-02-11 00:38:53 +01:00
antirez 8e12fae05e Cluster: fixed inverted arguments in logging function call. 2014-02-10 17:21:17 +01:00
antirez 6a01545744 Cluster: clear the FAIL status for masters without slots.
Masters without slots don't participate to the cluster but just do
redirections, no need to take them in FAIL state if they are back
reachable.
2014-02-10 17:19:16 +01:00
antirez 969a4f1db3 Cluster: replica migration should only work for masters serving slots. 2014-02-10 17:08:47 +01:00
antirez cb92a1ef08 Cluster: redis-trib del-node variable typo fixed. 2014-02-10 16:59:17 +01:00
antirez 6987a95952 Cluster: clusterReadHandler() fixed to work with new message header. 2014-02-10 16:28:44 +01:00
antirez ad85f520f8 Cluster: don't propagate PUBLISH two times.
PUBLISH both published messages via Cluster bus and replication when
cluster was enabled, resulting in duplicated message in the slave.
2014-02-10 16:05:26 +01:00
antirez b82b66b51d Cluster: signature changed to "RCmb" (Redis Cluster message bus).
Sounds better after all.
2014-02-10 16:05:22 +01:00
antirez b6e04f5584 Cluster: discard bus messages with version != 0. 2014-02-10 16:05:18 +01:00
antirez 0ee1a78c86 Cluster: added signature + version in bus packets. 2014-02-10 16:05:15 +01:00
antirez ff6a75a0c1 3.0 release notes added. 2014-02-10 15:36:02 +01:00
antirez b1c3c6e518 Old Changelog file removed from unstable branch. 2014-02-10 15:19:12 +01:00
antirez dca95f241c Cluster: redis-trib: options table entry for add-node fixed. 2014-02-10 12:34:21 +01:00
antirez 6df4ffe639 Don't count time to feed MONITORs in SLOWLOG. 2014-02-07 18:29:20 +01:00
antirez 142281dc79 Cluster: keys slot computation now supports hash tags.
Currently this is marginally useful, only to make sure two keys are in
the same hash slot when the cluster is stable (no rehashing in
progress).

In the future it is possible that support will be added to run
mutli-keys operations with keys in the same hash slot.
2014-02-07 17:39:01 +01:00
antirez 2d6eb68993 Sentinel: allow SHUTDOWN command in Sentinel mode. 2014-02-07 11:22:24 +01:00
antirez 970de3e9c0 Check for EAGAIN in sendBulkToSlave().
Sometime an osx master with a Linux server over a slow link caused
a strange error where osx called the writable function for
the socket but actually apparently there was no room in the socket
buffer to accept the write: write(2) call returned an EAGAIN error,
that was not checked, so we considered write(2) == 0 always as a connection
reset, which was unfortunate since the bulk transfer has to start again.

Also more errors are logged with the WARNING level in the same code path
now.
2014-02-05 16:38:10 +01:00
antirez 04fe000bf8 Cluster: fixed MF condition in clusterHandleSlaveFailover().
For manual failover we need a manual failover in progress, and that
mf_can_start is true (master offset received and matched).
2014-02-05 16:01:56 +01:00
antirez c6f02fd67a Cluster: CLUSTER FAILOVER replies with OK and logs the event. 2014-02-05 15:52:38 +01:00
antirez c72449af30 Cluster: check that a MF is in progress in manualFailoverCheckTimeout().
Otherwise it is always detected as a manual failover timed out.
2014-02-05 15:45:24 +01:00
antirez b7402bcad5 Cluster: force AUTH ACK on manual failover.
When a slave requests masters vote for a manual failover, the
REQUEST_AUTH message is flagged in a special way in order to force the
masters to give the authorization even if the master is not marked as
failing.
2014-02-05 13:10:03 +01:00
antirez 4cf0cd5719 Cluster: manual failover initial implementation. 2014-02-05 13:01:24 +01:00
antirez 4919a13f50 CLIENT PAUSE and related API implemented.
The API is one of the bulding blocks of CLUSTER FAILOVER command that
executes a manual failover in Redis Cluster. However exposed as a
command that the user can call directly, it makes much simpler to
upgrade a standalone Redis instance using a slave in a safer way.

The commands works like that:

    CLIENT PAUSE <milliesconds>

All the clients that are not slaves and not in MONITOR state are paused
for the specified number of milliesconds. This means that slaves are
normally served in the meantime.

At the end of the specified amount of time all the clients are unblocked
and will continue operations normally. This command has no effects on
the population of the slow log, since clients are not blocked in the
middle of operations but only when there is to process new data.

Note that while the clients are unblocked, still new commands are
accepted and queued in the client buffer, so clients will likely not
block while writing to the server while the pause is active.
2014-02-04 16:16:09 +01:00
antirez b089ba98cc Scripting: expire keys in scripts only at first access.
Keys expiring in the middle of the execution of Lua scripts are to
create inconsistencies in masters and / or AOF files. See the following
example:

    if redis.call("exists",KEYS[1]) == 1
    then
        redis.call("incr","mycounter")
    end

    if redis.call("exists",KEYS[1]) == 1
    then
        return redis.call("incr","mycounter")
    end

The script executes two times the same *if key exists then incrementcounter*
logic. However the two executions will work differently in the master and
the slaves, provided some unlucky timing happens.

In the master the first time the key may still exist, while the second time
the key may no longer exist. This will result in the key incremented just one
time. However as a side effect the master will generate a synthetic
`DEL` command in the replication channel in order to force the slaves to
expire the key (given that key expiration is master-driven).

When the same script will run in the slave, the key will no longer be
there, so the script will not increment the key.

The key idea used to implement the expire-at-first-lookup semantics was
provided by Marc Gravell.
2014-02-03 16:15:53 +01:00
antirez b770079f2c Allow CONFIG and SHUTDOWN while in stale-slave state. 2014-02-03 15:51:03 +01:00
antirez 89884e8f6e Scripting: use mstime() and mstime_t for lua_time_start.
server.lua_time_start is expressed in milliseconds. Use mstime_t instead
of long long, and populate it with mstime() instead of ustime()/1000.

Functionally identical but more natural.
2014-02-03 15:45:40 +01:00
Salvatore Sanfilippo b0335287ac Merge pull request #1534 from gdi2290/patch-1
update copyright year
2014-02-03 02:18:24 -08:00
PatrickJS 79270cae64 update copyright year 2014-02-03 02:10:54 -08:00
antirez 331de6930a Test: fixed osx msg passing issue in testing framework.
The Redis test uses a server-clients model in order to parallelize the
execution of different tests. However in recent versions of osx not
setting the channel to a binary encoding caused issues even if AFAIK no
binary data is really sent via this channel. However now the channels
are deliberately set to a binary encoding and this solves the issue.

The exact issue was the test not terminating and giving the impression
of running forever, since test clients or servers were unable to
exchange the messages to continue.
2014-01-31 16:27:03 +01:00
antirez e40d3e28e8 Redis.conf comment about tcp-backlog option improved. 2014-01-31 14:59:50 +01:00
antirez 7be946fde2 Option "backlog" renamed "tcp-backlog".
This is especially important since we already have a concept of backlog
(the replication backlog).
2014-01-31 14:56:10 +01:00
Nenad Merdanovic d76aa96d1a Add support for listen(2) backlog definition
In high RPS environments, the default listen backlog is not sufficient, so
giving users the power to configure it is the right approach, especially
since it requires only minor modifications to the code.
2014-01-31 14:52:10 +01:00
antirez b8bfbf46c5 Cluster: fix an error in migration-barrier comment in redis.conf. 2014-01-31 11:31:50 +01:00
antirez cbfdd13b3a Cluster: barrer -> barrier in redis.conf. 2014-01-31 11:30:49 +01:00
antirez a7d30681c9 Cluster: configurable replicas migration barrier.
It is possible to configure the min number of additional working slaves
a master should be left with, for a slave to migrate to an orphaned
master.
2014-01-31 11:26:36 +01:00
antirez 3ff1bb4b2e Sentinel: check arity for SENTINEL MASTER command.
This fixes issue #1530.
2014-01-31 10:13:38 +01:00
antirez 6c9359add1 Cluster: perform orphaned masters check before continue statements.
The check was placed in a way that conflicted with the continue
statements used by the node hearth beat code later that needs to skip
the current node sometimes. Moved at the start of the function so that's
always executed.
2014-01-30 18:23:31 +01:00
antirez c2507b0ff6 Cluster: replica migration implementation.
This feature allows slaves to migrate to orphaned masters (masters
without working slaves), as long as a set of conditions are met,
including the fact that the migrating slave needs to be in a
master-slaves ring with at least another slave working.
2014-01-30 18:05:11 +01:00
antirez 5b4020fb42 Cluster: swap two code blocks to have a more obvious flow. 2014-01-30 16:34:23 +01:00
antirez 4beaaff8ea Cluster: remove not needed return statement breaking failover. 2014-01-29 17:28:46 +01:00
antirez 3582054982 Cluster: broadcast pong to other slaves in the same ring.
When we schedule a failover, broadcast a PONG to the slaves.
The other slaves that plan to get elected will do the same too, this way
it is likely that every slave will have a good picture of its own rank.

Note that this is N*N messages where N is the number of slaves for the
failing master, however usually even large clusters have many master
nodes but a limited number of replicas per node, so this is harmless.
2014-01-29 17:19:55 +01:00
antirez e2b59621a8 Cluster: log offset when announcing the failover election delay. 2014-01-29 17:16:10 +01:00
antirez 940531e9b7 Cluster: added progressive election delay according to slave rank.
Note that when we compute the initial delay, there are probably still
more up to date information to receive from slaves with new offsets, so
the delay is recomputed when new data is available.
2014-01-29 16:53:45 +01:00
antirez 6f54032080 Cluster: function clusterGetSlaveRank() added.
Return the number of slaves for the same master having a better
replication offset of the current slave, that is, the slave "rank" used
to pick a delay before the request for election.
2014-01-29 16:39:04 +01:00
antirez 40cd38f0c4 Cluster: update node replication offset from bus packets headers. 2014-01-29 16:01:00 +01:00
antirez 9d4ded7ec6 Cluster: refactoring: new macros to check node flags. 2014-01-29 12:17:16 +01:00
antirez 099bd336db Cluster: use myself instead of server->cluster.myself. 2014-01-29 11:38:14 +01:00
antirez e36bd8b43e Cluster: added a global myself pointer in cluster.c.
Accessing to the 'myself' node, the node representing the currently
running instance, is handy without the need to type
server.cluster->myself every time.
2014-01-29 11:22:22 +01:00
antirez f1e09d8c41 Cluster: clusterBroadcastPong() improved with target selection.
Now we can broadcast a pong to all the instances or just the local
slaves (that is useful for replication offset propagation).
2014-01-29 11:08:52 +01:00
antirez befcf6259e Cluster: broadcast master/slave replication offset in bus header. 2014-01-28 16:51:50 +01:00
antirez 8b32bd483a Cluster: limit cluster.h to 80 cols. 2014-01-28 16:34:23 +01:00
antirez 0b1b25c51c Cluster: introduced repl_offset fields in clusterNode.
The two fields are used in order to remember the latest known
replication offset and the time we received it from other slave nodes.

This will be used by slaves in order to start the election procedure
with a delay that is proportional to the rank of the slave among the
other slaves for this master, when sorted for replication offset.

Usually this allows the slave with the most updated offset to win the
election and replace the failing master in the cluster.
2014-01-28 16:28:07 +01:00
antirez 72f1715e45 Fixed inverted if condition in MISCONF error code path. 2014-01-28 10:11:12 +01:00
antirez 23f4e9f0d9 Don't log MONITOR clients as disconnecting slaves. 2014-01-25 11:53:53 +01:00
antirez 40377fa522 Cluster: redis-trib set-timeout implemented. 2014-01-24 15:06:01 +01:00
antirez 0f9422d575 Cluster: update slaves lists in clusterSetMaster(). 2014-01-22 18:46:53 +01:00
antirez 5383ab0bc6 Cluster: CLUSTER SLAVES subcommand added. 2014-01-22 18:38:42 +01:00
antirez 603e480fd5 Cluster: clusterGenNodesDescription() refactored into two functions. 2014-01-22 18:36:12 +01:00
antirez 1cf532dc37 redis-cli --help output improved with --scan and periods. 2014-01-22 12:07:42 +01:00
antirez 994c5b26dd redis-cli: support for --scan option. 2014-01-22 12:04:08 +01:00
antirez 172f14d48c Use fflush() before fsync() in rio.c.
Incremental flushing in rio.c is only used to avoid huge kernel buffers
synched to slow disks creating big latency spikes, so this fix has no
durability implications, however it is certainly more correct to make
sure that the FILE buffers are flushed to the kernel before calling
fsync on the file descriptor.

Thanks to Li Shao Kai for reporting this issue in the Redis mailing
list.
2014-01-22 09:54:55 +01:00
antirez 80e80668f4 Cluster: master nodes wait before rejoining the cluster after reboot.
One of the simple heuristics used by Redis Cluster in order to avoid
losing data in the typical failure modes created by the asynchronous
replication with the slaves (a master is unable, when accepting a
write, to immediately tell if it should be really accepted or refused
because of a configuration change), is to wait some time before to
rejoin the cluster after being partitioned away from the majority of
instances.

A similar condition happens when a master is restarted. It does not know
if it was already failed over, nor if all the clients have already an
updated configuration about the cluster map, so it is possible that
clients will try to write to stale masters that were restarted.

In a similar way this commit changes masters behavior so they wait
2000 milliseconds before accepting writes after a reboot. There is
nothing special about 2 seconds if not to be a value supposedly larger
a few orders of magnitude compared to the cluster bus communication
latencies.
2014-01-20 11:52:52 +01:00
antirez e6970e204f Cluster: debug printf statemets removed.
These were committed for error after being inserted in order to fix an
issue.
2014-01-20 11:19:04 +01:00
antirez e4a5605c9a Cluster: don't rewrite slaveof config directive in cluster mode. 2014-01-20 11:10:42 +01:00
antirez 437fc2cb56 Cluster: fix error reporting when slaveof is found in config. 2014-01-20 11:08:14 +01:00
antirez ac3850cabd Cluster: allow CLUSTER REPLICATE to switch master.
The code was doing checks for slaves that should be done only when the
instance is currently a master. Switching a slave from a master to
another one should just work.
2014-01-17 18:22:35 +01:00
antirez abd6308d27 Set server.repl_down_since to 0 when changing master.
When an instance is potentially set to replicate with another master, it
is conceptually disconnected forever, since we have no old copy of the
dataset for this master in memory.
2014-01-17 18:20:31 +01:00
antirez 36c24bcca0 Cluster: redis-trib shows number of replicas of masters. 2014-01-17 17:56:45 +01:00
antirez 27ed9da383 Cluster: redis-trib help output format modified. 2014-01-17 12:32:49 +01:00
antirez a68c9ba97e Cluster: redis-trib shows what a slave replicates + fixes.
Also the :replicates info field in the node object is now correctly
populated. This also fixes the :replicas field computation.
2014-01-17 12:06:18 +01:00
antirez b451176734 Cluster: redis-trib addnode is now able to add replicas. 2014-01-17 11:48:42 +01:00
antirez 30d9c1dc32 Cluster: fix redis-trib help subcommand. 2014-01-17 10:29:40 +01:00
antirez 17d0c3e85a Cluster: redis-trib delnode implementation. 2014-01-16 18:22:03 +01:00
antirez 3d455393a6 Cluster: don't let a node forget its own master.
redis-trib should make sure to reconfigure slaves of a node to remove
from the cluster to replicate with other nodes before sending CLUSTER
FORGET.
2014-01-16 17:49:35 +01:00
antirez 9531c84807 Cluster: redis-trib help output improved.
Show options if any. Clarify that for some command any node address is
ok.
2014-01-16 16:23:33 +01:00
antirez 0c373207fa Cluster: don't forget yourself with CLUSTER FORGET. 2014-01-16 09:46:23 +01:00
antirez 3e948970fe Cluster: use the node blacklist in CLUSTER FORGET.
CLUSTER FORGET is not useful if we can't remove a node from all the
nodes of our cluster because of the Gossip protocol that keeps adding
a given node to nodes where we already tried to remove it.

So now CLUSTER FORGET implements a nodes blacklist that is set and
checked by the Gossip section processing function. This way before a
node is re-added at least 60 seconds must elapse since the FORGET
execution.

This means that redis-trib has some time to remove a node from a whole
cluster. It is possible that in the future it will be uesful to raise
the 60 sec figure to something bigger.
2014-01-15 16:50:45 +01:00
antirez ccf268fa17 Cluster: fix clusterBlacklistAddNode() by setting right expire time.
The hash table value should be set to now + 60 seconds otherwise it
expires immediately.
2014-01-15 16:49:31 +01:00
antirez 4e1861155f Cluster: clusterBlacklistAddNode() key lookup fixed.
We can't lookup by node->name that's not an SDS string but a plain C
array in the node structure.
2014-01-15 16:45:07 +01:00
antirez b51be7b34f Cluster: clusterBlacklistExists() requires blacklist cleanup before lookup. 2014-01-15 16:06:54 +01:00
antirez a81340abaf Cluster: set a minimum rejoin delay if node_timeout is too small.
The rejoin delay usually is the node timeout. However if the node
timeout is too small, we set it to 500 milliseconds, that is a value
chosen to be greater than most setups RTT / instances latency figures
so that likely communication with other nodes happen before rejoining.
2014-01-15 12:34:33 +01:00
antirez a687cbc19c Cluster: periodically call clusterUpdateState() when cluster is down.
Usually we update the cluster state (to understand if we should accept
queries or reply with an error) only when there is a change in the state
of the nodes. However for the "delayed rejoin" feature to work, that is,
for a master to wait some time before accepting queries again after it
rejoins the majority, we need to periodically update the last time when
the node was partitioned away from the majority.

With this commit if the cluster is down we update the state ten times
per second.
2014-01-15 12:26:12 +01:00
antirez 25ddefdea3 Cluster: range checking in getSlotOrReply() fixed.
See issue #1426 on Github.
2014-01-15 11:33:46 +01:00
antirez fb659cd334 Cluster: ignore empty lines in nodes.conf.
Even without the user messing manually with the file, it is still
possible to have blank lines (just a single "\n" per line) because of
how the nodes.conf update/write process works.
2014-01-15 11:23:41 +01:00
antirez 6c63df3031 Cluster: atomic update of nodes.conf file.
The way the file was generated was unsafe and leaded to nodes.conf file
corruption (zero length file) on server stop/crash during the creation
of the file.

The previous file update method was as simple as open with O_TRUNC
followed by the write call. While the write call was a single one with
the full payload, ensuring no half-written files for POSIX semantics,
stopping the server just after the open call resulted into a zero-length
file (all the nodes information lost!).
2014-01-15 10:31:20 +01:00
antirez 28273394cb Cluster: support to read from slave nodes.
A client can enter a special cluster read-only mode using the READONLY
command: if the client read from a slave instance after this command,
for slots that are actually served by the instance's master, the queries
will be processed without redirection, allowing clients to read from
slaves (but without any kind fo read-after-write guarantee).

The READWRITE command can be used in order to exit the readonly state.
2014-01-14 16:33:16 +01:00
antirez aacbba2607 Fix typo in aofRewriteBufferAppend() comment. 2014-01-14 15:37:49 +01:00
antirez 5189485625 Set REDIS_AOF_REWRITE_MIN_SIZE to 64mb.
64mb is the default value in redis.conf. For some reason instead the
hard-coded default was 1mb that is too small.
2014-01-14 11:27:28 +01:00
antirez d5763dceaf SENTINEL SET master quorum implemented. 2014-01-14 09:23:26 +01:00
antirez fe86f890b0 SENTINEL SET: error on bad option name + flush config on error. 2014-01-13 11:55:57 +01:00
antirez f822516e43 SENTINEL SET implemented.
The new command allows to change master-specific configurations
at runtime. All the settable parameters can be retrivied via the
SENTINEL MASTER command, so there is no equivalent "GET" command.
2014-01-13 11:53:29 +01:00
antirez 3cdcaff069 Sentinel: fix wrong arity error message. 2014-01-13 11:05:13 +01:00
antirez 964f6b17e9 Sentinel: SENTINEL REMOVE command added.
The command totally removes a monitored master.
2014-01-10 15:39:36 +01:00
antirez cf2835519e Sentinel: releaseSentinelRedisInstance() top comment fixed.
The claim about unlinking the instance from the connected hash tables
was the opposite of the reality. Also the current actual behavior is
safer in most cases, so it is better to manually unlink when needed.
2014-01-10 15:33:42 +01:00
antirez 9d0f46c6f5 Sentinel: flush config on disk when new master is added. 2014-01-10 15:22:06 +01:00
antirez d4f296bc1d anetResolveIP() prototype added to anet.h. 2014-01-10 15:18:41 +01:00
antirez 39f9f449b0 Sentinel: SENTINEL MONITOR command implemented.
It allows to add new masters to monitor at runtime.
2014-01-10 15:18:24 +01:00
antirez 774f0bd45e anetResolveIP() added to anet.c.
The new function is used when we want to normalize an IP address without
performing a DNS lookup if the string to resolve is not a valid IP.

This is useful every time only IPs are valid inputs or when we want to
skip DNS resolution that is slow during runtime operations if we are
required to block.
2014-01-10 15:02:39 +01:00
antirez c42e4bd0b6 Sentinel: added SENTINEL MASTER <name> command.
With SENTINEL MASTERS it was already possible to list all the configured
masters, but not a specific one.
2014-01-10 14:41:52 +01:00
antirez 2bb9cd464e Add all the configurable fields to addReplySentinelRedisInstance().
Note: the auth password with the master is voluntarily not exposed.
2014-01-10 14:31:41 +01:00
antirez 5a7d04ee7b Trip comment to 80 cols in SentinelCommand(). 2014-01-10 14:13:04 +01:00
antirez 5d08413b13 Test: regression for issues #1483. 2014-01-09 11:19:03 +01:00
antirez 58c8a071a5 Fix RESTORE ttl handling in 32 bit archs.
long was used instead of long long in order to handle a 64 bit
resolution millisecond timestamp.

This fixes issue #1483.
2014-01-09 11:09:23 +01:00
antirez e1ab2991c3 Fix keyspace events flags-to-string conversion.
Fixes issue #1491 on Github.
2014-01-08 17:18:34 +01:00
antirez a2f9947827 Test: stress events flags to/from string conversion. 2014-01-08 17:18:30 +01:00
antirez 90a81b4ebb Don't send REPLCONF ACK to old masters.
Masters not understanding REPLCONF ACK will reply with errors to our
requests causing a number of possible issues.

This commit detects a global replication offest set to -1 at the end of
the replication, and marks the client representing the master with the
REDIS_PRE_PSYNC flag.

Note that this flag was called REDIS_PRE_PSYNC_SLAVE but now it is just
REDIS_PRE_PSYNC as it is used for both slaves and masters starting with
this commit.

This commit fixes issue #1488.
2014-01-08 14:28:16 +01:00
antirez 3f92e05637 Clarify a comment in slaveTryPartialResynchronization(). 2014-01-08 14:28:13 +01:00
antirez fdf50e1e3d Log disconnection with slave only when ip:port is available. 2013-12-25 18:41:53 +01:00
antirez 2041882286 anetPeerToString / SockName: port can be NULL on errors too. 2013-12-25 18:41:49 +01:00
antirez a2a900356e anetTcpGenericConnect() bug introduced in 9d19977 fixed.
Durign a refactoring I mispelled _port for port.
This is one of the reasons I never used _varname myself.
2013-12-25 18:41:45 +01:00
antirez cb23d510f4 Remove useless goto from anetTcpGenericConnect(). 2013-12-25 18:41:41 +01:00
antirez 491f681088 anetTcpGenericConnect() code improved + 1 bug fix.
Now the socket is closed if anetNonBlock() fails, and in general the
code structure makes it harder to introduce this kind of bugs in the
future.

Reference: pull request #1059.
2013-12-25 18:15:28 +01:00
antirez f510549044 Cluster: clusterProcessPacket() was not 80 cols friendly.
The function actually needs to be split into sub-functions at some
point in the future.
2013-12-25 17:57:36 +01:00
antirez e789384255 Fix CONFIG REWRITE handling of unknown options.
There were two problems with the implementation.

1) "save" was not correctly processed when no save point was configured,
   as reported in issue #1416.
2) The way the code checked if an option existed in the "processed"
   dictionary was wrong, as we add the element with as a key associated
   with a NULL value, so dictFetchValue() can't be used to check for
   existance, but dictFind() must be used, that returns NULL only if the
   entry does not exist at all.
2013-12-23 12:50:27 +01:00
antirez 7e9433cee1 Configuring port to 0 disables IP socket as specified.
This was no longer the case with 2.8 becuase of a bug introduced with
the IPv6 support. Now it is fixed.

This fixes issue #1287 and #1477.
2013-12-23 11:31:35 +01:00
antirez 94e8c9e77e Make new masters inherit replication offsets.
Currently replication offsets could be used into a limited way in order
to understand, out of a set of slaves, what is the one with the most
updated data. For example this comparison is possible of N slaves
were replicating all with the same master.

However the replication offset was not transferred from master to slaves
(that are later promoted as masters) in any way, so for instance if
there were three instances A, B, C, with A master and B and C
replication from A, the following could happen:

C disconnects from A.
B is turned into master.
A is switched to master of B.
B receives some write.

In this context there was no way to compare the offset of A and C,
because B would use its own local master replication offset as
replication offset to initialize the replication with A.

With this commit what happens is that when B is turned into master it
inherits the replication offset from A, making A and C comparable.
In the above case assuming no inconsistencies are created during the
disconnection and failover process, A will show to have a replication
offset greater than C.

Note that this does not mean offsets are always comparable to understand
what is, in a set of instances, since in more complex examples the
replica with the higher replication offset could be partitioned away
when picking the instance to elect as new master. However this in
general improves the ability of a system to try to pick a good replica
to promote to master.
2013-12-22 11:43:25 +01:00
antirez ba5eb44d14 Slave disconnection is an event worth logging. 2013-12-22 10:15:35 +01:00
antirez 66ec1412fe Redis Cluster: add repl_ping_slave_period to slave data validity time.
When the configured node timeout is very small, the data validity time
(maximum data age for a slave to try a failover) is too little (ten
times the configured node timeout) when the replication link with the
master is mostly idle. In this case we'll receive some data from the
master only every server.repl_ping_slave_period to refresh the last
interaction with the master.

This commit adds to the max data validity time the slave ping period to
avoid this problem of slaves sensing too old data without a good reason.
However this max data validity time is likely a setting that should be
configurable by the Redis Cluster user in a way completely independent
from the node timeout.
2013-12-22 10:05:16 +01:00
antirez b2dedd9da8 Log when a slave lose the connection with its master. 2013-12-21 00:23:37 +01:00
antirez 658aff9d29 Redis Cluster: move node failure reports logging from VERBOSE to NOTICE level. 2013-12-21 00:04:53 +01:00
antirez 5a404c87c1 Redis Cluster: remove no longer relevant comment. 2013-12-20 14:40:11 +01:00
antirez fda4cba912 Redis Cluster: reconfigure replication when master changes address. 2013-12-20 12:47:22 +01:00
antirez d7374032c0 Redis Cluster: handshake code refactoring + Gossip IP switch detection.
This commit makes it simple to start an handshake with a specific node
address, and uses this in order to detect a node IP change and start a
new handshake in order to fix the IP if possible.
2013-12-20 12:38:03 +01:00
antirez a2c938c834 Redis Cluster: delay state change when in the majority again.
As specified in the Redis Cluster specification, when a node can reach
the majority again after a period in which it was partitioend away with
the minorty of masters, wait some time before accepting queries, to
provide a reasonable amount of time for other nodes to upgrade its
configuration.

This lowers the probabilities of both a client and a master with not
updated configuration to rejoin the cluster at the same time, with a
stale master accepting writes.
2013-12-20 09:56:18 +01:00
antirez 305d7f29f3 Clarify include directive behavior in example redis.conf. 2013-12-19 16:02:31 +01:00
antirez b3632319a4 CONFIG REWRITE: no special handling or include and rename-command.
CONFIG REWRITE is now wiser and does not touch what it does not
understand inside redis.conf.
2013-12-19 15:57:11 +01:00
Yubao Liu 7da423f79f CONFIG REWRITE: don't throw some options on config rewrite
Those options will be thrown without this patch:
  include, rename-command, min-slaves-to-write, min-slaves-max-lag,
appendfilename.
2013-12-19 15:56:48 +01:00
antirez 3b9cf3ed3a CONFIG REWRITE: old development comments removed. 2013-12-19 15:30:06 +01:00
antirez b221e13dac CONFIG REWRITE: don't wipe unknown options.
With this commit options not explicitly rewritten by CONFIG REWRITE are
not touched at all. These include new options that may not have support
for REWRITE, and other special cases like rename-command and include.
2013-12-19 15:25:45 +01:00
antirez 6d184e02be Example redis.conf formatted to better show appendfilename option. 2013-12-19 10:18:45 +01:00
antirez 7a666ac419 Cluster: set n->slaves to NULL in clusterNodeResetSlaves().
The value was otherwise undefined, so next time the node was promoted
again from slave to master, adding a slave to the list of slaves
would likely crash the server or result into undefined behavior.
2013-12-17 14:50:24 +01:00
antirez fda91dbde3 Cluster: check link is valid before sending UPDATE. 2013-12-17 12:28:37 +01:00
antirez f57bb36ce7 Cluster: initialize todo_before_sleep flags to 0. 2013-12-17 12:22:02 +01:00
antirez c70c0c6db7 Cluster: use proper type mstime_t for ping delay var. 2013-12-17 10:27:36 +01:00
antirez 7c1cbdceb2 Cluster: use an hardcoded 60 sec timeout in redis-trib connections.
Later this should be configurable from the command line but at least now
we use something more appropriate for our use case compared to the
redis-rb default timeout.
2013-12-17 10:00:33 +01:00
antirez 47815d38e0 Fixed clearNodeFailureIfNeeded() time type to mstime_t.
This prevented 32bit cluster instances from clearing the FAIL flag when
needed.
2013-12-17 09:45:52 +01:00
antirez e88e6a6334 Cluster: use long long for timestamps in clusterGenNodesDescription().
Ping sent and pong received fields need to be casted to long long to be
printed correctly into 32 bit systems.
2013-12-17 09:38:11 +01:00
antirez 2dfc5e35a9 Makefile.dep updated. 2013-12-13 13:10:05 +01:00
antirez b1ba58f341 SDIFF iterator misuse bug regression test added.
See commit c00453d for more info about the bug.
2013-12-13 11:37:13 +01:00
antirez c00453da1d SDIFF iterator misuse fixed in diff algorithm #1.
The bug could be easily triggered by:

    SADD foo a b c 1 2 3 4 5 6
    SDIFF foo foo

When the key was the same in two sets, an unsafe iterator was used to
check existence of elements in the same set we were iterating.
Usually this would just result into a wrong output, however with the
dict.c API misuse protection we have in place, the result was actually
an assertion failed that was triggered by the CI test, while creating
random datasets for the "MASTER and SLAVE consistency" test.
2013-12-13 11:34:21 +01:00
antirez 5320148883 Sentinel: dead code removed. 2013-12-13 11:01:13 +01:00
antirez 452dea30f6 Makefile: remove odd syntax not compatible with some make versions.
See issue #1448.
2013-12-12 15:19:39 +01:00
Salvatore Sanfilippo 62e4956936 Merge pull request #1415 from Dieken/fix-typo
fix typo in redis.conf and sentinel.conf
2013-12-12 02:30:11 -08:00
Salvatore Sanfilippo a99c751d6c Merge pull request #1460 from codeeply/simplify2
comment mistake fixed
2013-12-12 02:23:44 -08:00
codeeply 0f06f8df07 comment mistake fixed 2013-12-12 16:33:29 +08:00
antirez a5ec247f13 Replication: publish the slave_repl_offset when disconnected from master.
When a slave was disconnected from its master the replication offset was
reported as -1. Now it is reported as the replication offset of the
previous master, so that failover can be performed using this value in
order to try to select a slave with more processed data from a set of
slaves of the old master.
2013-12-11 15:23:15 +01:00
Salvatore Sanfilippo 0a89d9a0b1 Merge pull request #1451 from yossigo/unbalanced-quotes-fix
Return proper error on requests with an unbalanced number of quotes.
2013-12-11 03:06:18 -08:00
Yossi Gottlieb 88a5cede88 Fix wrong repldboff type which causes dropped replication in rare cases. 2013-12-11 11:38:02 +01:00
Yubao Liu 6d5fa2e06c fix typo in redis.conf and sentinel.conf 2013-12-11 15:46:42 +08:00
antirez 11120689c4 Slaves heartbeats during sync improved.
The previous fix for false positive timeout detected by master was not
complete. There is another blocking stage while loading data for the
first synchronization with the master, that is, flushing away the
current data from the DB memory.

This commit uses the newly introduced dict.c callback in order to make
some incremental work (to send "\n" heartbeats to the master) while
flushing the old data from memory.

It is hard to write a regression test for this issue unfortunately. More
support for debugging in the Redis core would be needed in terms of
functionalities to simulate a slow DB loading / deletion.
2013-12-10 18:47:31 +01:00
antirez 2eb781b35b dict.c: added optional callback to dictEmpty().
Redis hash table implementation has many non-blocking features like
incremental rehashing, however while deleting a large hash table there
was no way to have a callback called to do some incremental work.

This commit adds this support, as an optiona callback argument to
dictEmpty() that is currently called at a fixed interval (one time every
65k deletions).
2013-12-10 18:46:24 +01:00
antirez 2c4ab8a534 Log empty DB + Loading data into two separated messages. 2013-12-10 18:43:25 +01:00
antirez 7c531eb5ad Don't send more than 1 newline/sec while loading RDB. 2013-12-10 18:43:19 +01:00
antirez 27db38d069 Slaves heartbeat while loading RDB files.
Starting with Redis 2.8 masters are able to detect timed out slaves,
while before 2.8 only slaves were able to detect a timed out master.

Now that timeout detection is bi-directional the following problem
happens as described "in the field" by issue #1449:

1) Master and slave setup with big dataset.
2) Slave performs the first synchronization, or a full sync
   after a failed partial resync.
3) Master sends the RDB payload to the slave.
4) Slave loads this payload.
5) Master detects the slave as timed out since does not receive back the
   REPLCONF ACK acknowledges.

Here the problem is that the master has no way to know how much the
slave will take to load the RDB file in memory. The obvious solution is
to use a greater replication timeout setting, but this is a shame since
for the 0.1% of operation time we are forced to use a timeout that is
not what is suited for 99.9% of operation time.

This commit tries to fix this problem with a solution that is a bit of
an hack, but that modifies little of the replication internals, in order
to be back ported to 2.8 safely.

During the RDB loading time, we send the master newlines to avoid
being sensed as timed out. This is the same that the master already does
while saving the RDB file to still signal its presence to the slave.

The single newline is used because:

1) It can't desync the protocol, as it is only transmitted all or
nothing.
2) It can be safely sent while we don't have a client structure for the
master or in similar situations just with write(2).
2013-12-09 20:26:00 +01:00
antirez eaf1bfb88b Handle inline requested terminated with just \n. 2013-12-09 13:28:39 +01:00
Yossi Gottlieb 6e70c01148 Return proper error on requests with an unbalanced number of quotes. 2013-12-08 12:58:12 +02:00
antirez c590549e40 Sentinel: fix reported role info sampling.
The way the role change was recoded was not sane and too much
convoluted, causing the role information to be not always updated.

This commit fixes issue #1445.
2013-12-06 12:46:56 +01:00
antirez 2b414a4b5f Sentinel: fix reported role fields when master is reset.
When there is a master address switch, the reported role must be set to
master so that we have a chance to re-sample the INFO output to check if
the new address is reporting the right role.

Otherwise if the role was wrong, it will be sensed as wrong even after
the address switch, and for enough time according to the role change
time, for Sentinel consider the master SDOWN.

This fixes isue #1446, that describes the effects of this bug in
practice.
2013-12-06 11:37:46 +01:00
antirez 8534a290d3 Fixed typo in redis.conf. 2013-12-06 10:48:46 +01:00
Salvatore Sanfilippo 2ef57f8d47 Merge pull request #1439 from AnuragRamdasan/patch-3
Grammar fix.
2013-12-05 09:53:45 -08:00
Anurag Ramdasan 839ed7a60b Grammar fix. 2013-12-05 23:15:47 +05:30
Salvatore Sanfilippo 026e561446 Merge pull request #1438 from AnuragRamdasan/patch-2
fixed typo
2013-12-05 08:18:20 -08:00
Anurag Ramdasan fb6b9b14bd fixed typo 2013-12-05 21:47:17 +05:30
Salvatore Sanfilippo cbaad0b26f Merge pull request #1437 from AnuragRamdasan/patch-1
Fixed grammar: 'usually' to 'usual'
2013-12-05 07:42:05 -08:00
Anurag Ramdasan 74431b80a3 Fixed grammar: 'usually' to 'usual' 2013-12-05 21:09:31 +05:30
antirez 11e81a1e9a Fixed grammar: before H the article is a, not an. 2013-12-05 16:35:32 +01:00
antirez 74da4a574f Fixed typos in redis.conf file. 2013-12-05 16:28:35 +01:00
antirez 58713c6b13 Fix clients timeout handling.
During the refactoring of blocking operations, commit
82b672f633, a bug was introduced where
a milliseconds time is compared to a seconds time, so all the clients
always appear to timeout if timeout is set to non-zero value.

Thanks to Jonathan Leibiusky for finding the bug and helping verifying
the cause and fix.
2013-12-05 14:55:07 +01:00
antirez c5618e7fdd WAIT command: synchronous replication for Redis. 2013-12-04 16:20:03 +01:00
antirez c2f305545a blocked.c API commented. 2013-12-03 18:03:15 +01:00
antirez 82b672f633 BLPOP blocking code refactored to be generic & reusable. 2013-12-03 17:43:53 +01:00
antirez 2e027c48e5 Removed old comments and dead code from freeClient(). 2013-12-03 13:54:06 +01:00
antirez e4025ea926 Grammar fix in freeClient(). 2013-12-03 13:40:41 +01:00
antirez f80cf7363a Sentinel: don't write HZ when flushing config.
See issue #1419.
2013-12-02 15:56:10 +01:00
antirez dffebbc904 Sentinel: better time desynchronization.
Sentinels are now desynchronized in a better way changing the time
handler frequency between 10 and 20 HZ. This way on average a
desynchronization of 25 milliesconds is produced that should be larger
enough compared to network latency, avoiding most split-brain condition
during the vote.

Now that the clocks are desynchronized, to have larger random delays when
performing operations can be easily achieved in the following way.
Take as example the function that starts the failover, that is
called with a frequency between 10 and 20 HZ and will start the
failover every time there are the conditions. By just adding as an
additional condition something like rand()%4 == 0, we can amplify the
desynchronization between Sentinel instances easily.

See issue #1419.
2013-12-02 12:29:42 +01:00
antirez 6fa42b7507 Cluster: nodes re-addition blacklist API. 2013-12-02 11:12:23 +01:00
antirez 8f18345ef0 Cluster: basic data structures for nodes black list. 2013-11-29 17:37:06 +01:00
antirez 3db825fde4 Cluster: some code about clusterHandleSlaveFailover() marginally improved.
80 cols friendly, some minor change to the code to make it simpler.
2013-11-29 16:17:05 +01:00
antirez 55f90b11c9 Stop writes on MISCONF only if instance is a master.
From the point of view of the slave not accepting writes from the master
can only create a bigger consistency issue.
2013-11-28 16:29:26 +01:00
antirez 60817bb262 Reply to PING with error when there is a MISCONF state. 2013-11-28 16:17:10 +01:00
antirez 0addf8aff1 Sentinel: log vote received from other Sentinels. 2013-11-28 15:23:46 +01:00
Salvatore Sanfilippo c7136269c6 Merge pull request #1401 from huangz1990/fix_sentinel_bug
fix a bug in sentinel.c about pub/sub link
2013-11-26 06:15:25 -08:00
huangz1990 86a540a66e fix a bug in sentinel.c about pub/sub link 2013-11-26 19:55:51 +08:00
antirez 6f4fd55762 Sentinel: fixes inverted strcmp() test preventing config updates.
The result of this one-char bug was pretty serious, if the new master
had the same port of the previous master, but just a different IP
address, non-leader Sentinels would not be able to recognize the
configuration change.

This commit fixes issue #1394.

Many thanks to @shanemadden that reported the bug and helped
investigating it.
2013-11-25 10:59:53 +01:00
antirez 8d547ebd56 Sentinel: fix type specifier for Hello msg generation.
This fixes issue #1395.
2013-11-25 10:24:34 +01:00
antirez fcebd9b0f9 Fix false positive in memory efficiency test.
Fixes issue #1298.
2013-11-25 10:21:46 +01:00
antirez 37b43c8a24 Sentinel: example sentinel.conf updated. 2013-11-21 17:07:00 +01:00
antirez cc6053681f Sentinel: different comments updated to new implementation. 2013-11-21 16:22:59 +01:00
antirez 685e79998c Sentinel: cleanup around SENTINEL_INFO_VALIDITY_TIME. 2013-11-21 16:05:41 +01:00
antirez 489d889726 Sentinel: removed mem leak and useless code. 2013-11-21 15:43:55 +01:00
antirez 1ca56ea796 Merge branch 'newsentinel' into unstable 2013-11-21 15:01:25 +01:00
antirez f55ad3038f Sentinel: manual failover works again. 2013-11-21 12:39:47 +01:00
antirez 297de1ab26 Sentinel: test for writable config file.
This commit introduces a funciton called when Sentinel is ready for
normal operations to avoid putting Sentinel specific stuff in redis.c.
2013-11-21 12:28:15 +01:00
antirez d920177f8d Sentinel: check for disconnected links in sentinelSendHello().
Does not fix any bug as the test is performed by the caller, but better
to have the check.
2013-11-21 11:35:50 +01:00
antirez 8810167d13 Sentinel: Hello message sending code refactored. 2013-11-21 11:31:06 +01:00
antirez 0101c2bcfe Sentinel: select slave with best (greater) replication offset. 2013-11-20 16:05:36 +01:00
antirez a6ebd910d8 Sentinel: take the replication offset in slaves state. 2013-11-20 15:53:21 +01:00
antirez b1f5a0b3ec CONFIG REWRITE: don't add the signature if it already exists.
At the end of the file, CONFIG REWRITE adds a comment line that:

    # Generated by CONFIG REWRITE

Followed by the additional config options required. However this was
added again and again at every rewrite in praticular conditions (when a
given set of options change in a given time during the time).

Now if it was alrady encountered, it is not added a second time.

This is especially important for Sentinel that rewrites the config at
every state change.
2013-11-19 17:58:11 +01:00
antirez 37a51a2568 Sentinel: distinguish between is-master-down-by-addr requests.
Some are just to know if the master is down, and in this case the runid
in the request is set to "*", others are actually in order to seek for a
vote and get elected. In the latter case the runid is set to the runid
of the instance seeking for the vote.
2013-11-19 16:50:04 +01:00
antirez b22d1beea0 Sentinel: various fixes to leader election implementation. 2013-11-19 16:20:42 +01:00
antirez 1f9728cb20 Sentinel: failover script execution fixed. 2013-11-19 12:34:46 +01:00
antirez 90635488ce Sentinel: no longer used defines removed. 2013-11-19 11:24:36 +01:00
antirez 0a35f65301 Sentinel: when writing config on disk, remember sentinels runid. 2013-11-19 11:11:43 +01:00
antirez 5450833d02 Sentinel: arity of known-sentinel/slave is 4 not 3. 2013-11-19 11:03:47 +01:00
antirez b8a94463b7 Sentinel: rewriteConfigSentinelOption() sub-iterators var typo fixed. 2013-11-19 10:59:50 +01:00
antirez 16237d78c8 Sentinel: call sentinelFlushConfig() to persist state when needed.
Also the sentinel configuration rewriting was modified in order to
account for failover in progress, where we need to provide the promoted
slave address as master address, and the old master address as one of
the slaves address.
2013-11-19 10:55:43 +01:00
antirez e257ab2bfe Sentinel: sentinelFlushConfig() to CONFIG REWRITE + fsync. 2013-11-19 10:13:04 +01:00
antirez 5998769c28 Sentinel: CONFIG REWRITE support for Sentinel config. 2013-11-19 09:48:12 +01:00
antirez 47df12d5d9 Sentinel: can-failover option removed, many comments fixed. 2013-11-19 09:28:47 +01:00
antirez cd4ff9992b Fix typo 'configuraiton' in rewriteConfigRewriteLine() comment. 2013-11-18 18:18:10 +01:00
antirez 232cdb95ab Sentinel: added config options useful to take state on config rewrite.
We'll use CONFIG REWRITE (internally) in order to store the new
configuration of a Sentinel after the internal state changes. In order
to do so, we need configuration options (that usually the user will not
touch at all) about config epoch of the master, Sentinels and Slaves
known for this master, and so forth.
2013-11-18 16:03:03 +01:00
antirez 3a374b0511 Sentinel: failover abort function simplified. 2013-11-18 11:43:35 +01:00
antirez e0750acf11 Sentinel: slaves reconfig delay modified.
The time Sentinel waits since the slave is detected to be configured to
the wrong master, before reconfiguring it, is now the failover_timeout
time as this makes more sense in order to give the Sentinel performing
the failover enoung time to reconfigure the slaves slowly (if required
by the configuration).

Also we now PUBLISH more frequently the new configuraiton as this allows
to switch the reapprearing master back to slave faster.
2013-11-18 11:37:24 +01:00
antirez 83316f515c Sentinel: failover restart time is now multiple of failover timeout.
Also defaulf failover timeout changed to 3 minutes as the failover is a
fairly fast procedure most of the times, unless there are a very big
number of slaves and the user picked to configure them sequentially (in
that case the user should change the failover timeout accordingly).
2013-11-18 11:30:08 +01:00
antirez 3a56013acb Sentinel: state machine and timeouts simplified. 2013-11-18 11:12:58 +01:00
antirez 4be53b1c5d Sentinel: election timeout define. 2013-11-18 10:08:06 +01:00
antirez 69d826a354 Sentinel: fix address of master in Hello messages.
Once we switched configuration during a failover, we should advertise
the new address.

This was a serious race condition as the Sentinel performing the
failover for a moment advertised the old address with the new
configuration epoch: once trasmitted to the other Sentinels the broken
configuration would remain there forever, until the next failover
(because a greater configuration epoch is required to overwrite an older
one).
2013-11-14 10:25:55 +01:00
antirez e4c65e72c6 Sentinel: master address selection in get-master-address refactored. 2013-11-14 10:23:54 +01:00
antirez c0d7229364 Sentinel: fix conditional to only affect slaves with wrong master. 2013-11-14 10:23:05 +01:00
antirez dfbd9c5aeb Sentinel: simplify and refactor slave reconfig code. 2013-11-14 00:36:43 +01:00
antirez 64ad6648a8 Sentinel: reconfigure slaves to right master. 2013-11-14 00:29:38 +01:00
antirez 3e27d678da Sentinel: remember last time slave changed master. 2013-11-14 00:20:15 +01:00
antirez 8297745fa6 Sentinel: redirect-to-master is not ok with new algorithm.
Now Sentinel believe the current configuration is always the winner and
should be applied by Sentinels instead of trying to adapt our view of
the cluster based on what we observe.

So the only way to modify what a Sentinel believe to be the truth is to
win an election and advertise the new configuration via Pub / Sub with a
greater configuration epoch.
2013-11-13 17:03:48 +01:00
antirez 76a88f56e5 Sentinel: safer slave reconfig, master reported role should match. 2013-11-13 17:02:09 +01:00
antirez ddaad9fe2d Sentinel: role reporting fixed and added in SENTINEL output. 2013-11-13 16:39:57 +01:00
antirez a0afa66f4b Sentinel: being a master and reporting as slave is considered SDOWN. 2013-11-13 16:28:56 +01:00
antirez 17718fdcba Sentinel: make sure role_reported is always updated. 2013-11-13 16:21:58 +01:00
antirez 46a053d34b Sentinel: track role change time. Wait before reconfigurations. 2013-11-13 16:18:23 +01:00
antirez 9e40c46f5e Sentinel: fix no-down check in master->slave conversion code. 2013-11-13 13:43:59 +01:00
antirez ae35b7e240 Sentinel: readd slaves back after a master reset. 2013-11-13 13:01:11 +01:00
antirez 6bd4f6bffe Sentinel: sentinelResetMaster() new flag to avoid removing set of sentinels.
This commit also removes some dead code and cleanup generic flags.
2013-11-13 10:30:45 +01:00
antirez 1569af1f23 Sentinel: receive Pub/Sub messages from slaves. 2013-11-12 23:07:33 +01:00
antirez dfa5f8b777 Sentinel: change event name when converting master to slave. 2013-11-12 23:00:17 +01:00
antirez 24158d1488 Sentinel: added config-epoch to SENTINEL masters output. 2013-11-12 17:22:04 +01:00
antirez d2bc6dc39a Sentinel: new failover algo, desync slaves and update config epoch. 2013-11-12 17:07:31 +01:00
antirez 4a128b949d Sentinel: when starting failover seek for votes ASAP. 2013-11-12 16:38:02 +01:00
antirez e6b9d5e97e Sentinel: +new-epoch events. 2013-11-12 13:35:25 +01:00
antirez 54c447be52 Sentinel: wait some time between failover attempts. 2013-11-12 13:30:31 +01:00
antirez ab4b2ec88f Sentinel: allow to vote for myself. 2013-11-12 11:32:40 +01:00
antirez b6b65b29c0 Sentinel: fix PUBLISH to masters and slaves. 2013-11-12 11:12:48 +01:00
antirez 90ab62fd5e Sentinel: epoch introduced in leader vote. 2013-11-12 11:09:35 +01:00
antirez 8c1bf9a2bd Sentinel: leadership handling changes WIP.
Changes to leadership handling.

Now the leader gets selected by every Sentinel, for a specified epoch,
when the SENTINEL is-master-down-by-addr is sent.

This command now includes the runid and the currentEpoch of the instance
seeking for a vote. The Sentinel only votes a single time in a given
epoch.

Still a work in progress, does not even compile at this stage.
2013-11-11 18:30:14 +01:00
antirez 0bac36d0a1 Sentinel: handle Hello messages received via slaves correctly.
Even when messages are received via the slave, we should perform
operations (like adding a new Sentinel) in the context of the master.
2013-11-11 17:12:27 +01:00
antirez 9e1b27d49e Sentinel: remove code not useful in the new design. 2013-11-11 12:06:11 +01:00
antirez b93b0adc89 Sentinel: epoch introduced.
Sentinel state now includes the idea of current epoch and config epoch.
In the Hello message, that is now published both on masters and slaves,
a Sentinel no longer just advertises itself but also broadcasts its
current view of the configuration: the master name / ip / port and its
current epoch.

Sentinels receiving such information switch to the new master if the
configuration epoch received is newer and the ip / port of the master
are indeed different compared to the previos ones.
2013-11-11 11:05:58 +01:00
antirez b2f834390c Log to what master a slave is going to connect to. 2013-11-11 09:25:36 +01:00
antirez a5e7358a12 Cluster: removed not needed newline at end of redisLog() msg. 2013-11-08 17:28:02 +01:00
antirez 28071caf38 Cluster: send a single UPDATE packet for now. 2013-11-08 17:25:49 +01:00
antirez d289c628b1 Cluster: replace hardcoded 4096 for bus msg len with sizeof(). 2013-11-08 17:19:19 +01:00
antirez 94a07d5901 Cluster: slots update refactored + UPDATE msg processing.
Now there is a function that handles the update of the local slot
configuration every time we have some new info about a node and its set
of served slots and configEpoch.

Moreoever the UPDATE packets are now processed when received (it was a
work in progress in the previous commit).
2013-11-08 17:02:10 +01:00
antirez dc43f66eac Cluster: UPDATE msg data structure and sending function. 2013-11-08 16:26:50 +01:00
antirez 6c6572be95 Cluster: refactoring of slots update code and more.
The commit also introduces detection of nodes publishing not updated
configuration. More work in progress to send an UPDATE packet to inform
of the config change.
2013-11-08 10:32:16 +01:00
antirez d3588dc194 Fix broken rdbWriteRaw() return value check in rdb.c.
Thanks to @PhoneLi for reporting.
2013-11-07 23:53:18 +01:00
antirez d75ab87226 redis-trib: fixed slot allocation when --replicas is used. 2013-11-07 16:12:06 +01:00
antirez e1a1d904de Merge branch 'unstable' of github.com:/antirez/redis into unstable 2013-11-06 11:30:44 +01:00
antirez 80da056c29 Sentinel: sentinelSendSlaveOf() was missing a var and the prototype. 2013-11-06 11:23:53 +01:00
antirez 23800d9e49 Sentinel: increment pending_commands counter in two more places.
AUTH and SCRIPT KILL were sent without incrementing the pending commands
counter. Clearly this needs some kind of wrapper doing it for the caller
in order to be less bug prone.
2013-11-06 11:21:44 +01:00
antirez 671c1dfb56 Sentinel: always send CONFIG REWRITE when changing instance role.
This change makes Sentinel less fragile about a number of failure modes.

This commit also fixes a different bug as a side effect, SLAVEOF command
was sent multiple times without incrementing the pending commands count.
2013-11-06 11:13:27 +01:00
Salvatore Sanfilippo b5ec3ede7a Merge pull request #1365 from yaauie/deprecate-redis-copy-script
Deprecate utils/redis-copy.rb in favor of redis-copy gem
2013-11-06 00:42:03 -08:00
Ryan Biesemeyer ae8642fb79 Deprecate utils/redis-copy.rb in favor of redis-copy gem 2013-11-06 08:31:57 +00:00
antirez 5fd6dee0e6 Fixed typo in parseScanCursorOrReply(): ad -> at.
Thanks to @badboy for reporting it.
2013-11-05 17:23:11 +01:00
antirez ebcb6251e6 SCAN code refactored to parse cursor first.
The previous implementation of SCAN parsed the cursor in the generic
function implementing SCAN, SSCAN, HSCAN and ZSCAN.

The actual higher-level command implementation only checked for empty
keys and return ASAP in that case. The result was that inverting the
arguments of, for instance, SSCAN for example and write:

    SSCAN 0 key

Instead of

    SSCAN key 0

Resulted into no error, since 0 is a non-existing key name very likely.
Just the iterator returned no elements at all.

In order to fix this issue the code was refactored to extract the
function to parse the cursor and return the error. Every higher level
command implementation now parses the cursor and later checks if the key
exist or not.
2013-11-05 15:47:50 +01:00
antirez b4048dfec0 SCAN: when iterating ziplists or intsets always return cursor of 0.
The previous implementation assumed that the first call always happens
with cursor set to 0, this may not be the case, and we want to return 0
anyway otherwise the (broken) client code will loop forever.
2013-11-05 15:32:25 +01:00
antirez 101d4bf867 Use strtoul() instead of sscanf() in SCAN implementation. 2013-11-05 15:30:21 +01:00
antirez bf79c0cda2 Added tests for [SHZ]SCAN with MATCH. 2013-11-05 15:19:44 +01:00
antirez f56f78d159 HSCAN/ZSCAN: skip value when matching.
This fixes issue #1360 and #1362.
2013-11-05 12:16:29 +01:00
antirez 1a0cea33a0 Cluster: initialize senderConfigEpoch and senderCurrentEpoch for warnings suppression. 2013-11-05 12:01:07 +01:00
antirez eb95d28898 Pass int64_t to intsetGet() instead of long long. 2013-11-05 11:57:30 +01:00
antirez 20fb91fd31 removed not used vars in dictScan(). 2013-11-05 11:56:11 +01:00
antirez 6cf230ea91 Initial support for --replicas in redis-trib. 2013-11-05 11:24:24 +01:00
antirez 9fba193a59 SSCAN with integer encoded object test improved. 2013-10-31 10:37:27 +01:00
antirez c4ca5f99bf Inverted variable boolean value and name after scanGenericCommand() refactoring. 2013-10-31 10:35:56 +01:00
antirez 8fc85a1218 scanGenericCommand() refactoring and handling of integer encoded elements.
This commit fixes issue #1354.
2013-10-31 10:32:39 +01:00
antirez e6bb738b87 Regression test added for [SHZ]SCAN issue #1354. 2013-10-31 09:43:21 +01:00
antirez 0b8a0ca4bc Test: added a SCAN test trying to trigger HT resize. 2013-10-30 16:50:25 +01:00
antirez 6cb52256c9 Test: added ZSCAN test. 2013-10-30 16:25:53 +01:00
antirez 1b960378e8 Test: added HSCAN test. 2013-10-30 16:24:39 +01:00
antirez ddc80e026f Test: added SSCAN test. 2013-10-30 11:58:04 +01:00
antirez 5fdb94fd98 SCAN test keys sorting turned into more idiomatic Tcl. 2013-10-30 11:36:12 +01:00
antirez a881827b6e SCAN: tests moved to unit/scan.tcl. 2013-10-30 11:34:01 +01:00
antirez 3c7a0677b0 redis-benchmark: update help for new __rand_int__ form. 2013-10-28 18:13:42 +01:00
antirez 9b2d44e63f Aesthetic fix (missing space) into HSCAN and ZSCAN implementations.
Thanks to @badboy for reporting.
2013-10-28 13:20:11 +01:00
antirez 2c643ffa8d ZSCAN implemented. 2013-10-28 11:36:42 +01:00
antirez e50090aa06 HSCAN implemented. 2013-10-28 11:35:26 +01:00
antirez 4a1f1cc0d7 SSCAN implemented. 2013-10-28 11:17:32 +01:00
antirez dfeaa84d46 dictScan(): empty hash table requires special handling. 2013-10-28 11:17:18 +01:00
antirez cd8cb49dc4 SCAN is a random command and does not require output sorting.
Sorting the output helps when we want to turn a non-deterministic into a
deterministic command, in that case this is not possible.
2013-10-28 11:13:43 +01:00
antirez 442ae833b2 SCAN: refactored into scanGenericCommand.
The new implementation is capable of iterating the keyspace but also
sets, hashes, and sorted sets, and can be used to implement SSCAN, ZSCAN
and HSCAN.
2013-10-28 11:11:34 +01:00
antirez 7bd45659b9 Fixed typos in dictScan() comment. 2013-10-25 17:05:55 +02:00
antirez 34c207227c dictScan() algorithm documented. 2013-10-25 17:01:30 +02:00
antirez 48ea8a0a11 SCAN: stay inside 80 cols. 2013-10-25 12:01:49 +02:00
antirez df13adb037 Revert "Fixed typo in SCAN comment. iff -> if."
Probably here Pieter means "if and only if".

This reverts commit 43fdf3b404.
2013-10-25 12:00:13 +02:00
antirez a25fe0b28d SCAN: simplify keys list cleanup using listSetFreeMethod(). 2013-10-25 11:58:03 +02:00
antirez 0471b90844 SCAN: Fix test after option renamed from PATTERN to MATCH. 2013-10-25 11:55:28 +02:00
antirez fd1b0ad07c SCAN: improve variable names for readability. 2013-10-25 11:54:45 +02:00
antirez 908eba5a8f SCAN: remove additional newlines to conform to Redis code base. 2013-10-25 11:51:08 +02:00
antirez 6e55e543c6 SCAN: remove useless assertion, already enforced by command table. 2013-10-25 11:49:08 +02:00
antirez 64722b0946 SCAN: use define REDIS_LONGSTR_SIZE instead of fixed len. 2013-10-25 11:48:18 +02:00
antirez 43fdf3b404 Fixed typo in SCAN comment. iff -> if. 2013-10-25 11:46:02 +02:00
antirez 9c88ace927 SCAN option name changed: pattern -> match. 2013-10-25 11:45:32 +02:00
Pieter Noordhuis b63fbea5e4 Fix error in scan algorithm
The irrelevant bits shouldn't be masked to 1. This can result in slots being
skipped when the hash table is resized between calls to the iterator.
2013-10-25 10:50:03 +02:00
Pieter Noordhuis 7a6cfb18f3 SCAN requires at least 1 argument 2013-10-25 10:49:56 +02:00
Pieter Noordhuis 7f490b197f Add SCAN command 2013-10-25 10:49:48 +02:00
antirez 85f52ebcd8 Cluster: rough support for sub-command options in redis-trib. 2013-10-11 17:33:19 +02:00
antirez 0c9f60a628 Cluster: there is a lower limit for the handshake timeout. 2013-10-11 10:34:32 +02:00
antirez 1447d28c0f Cluster: data_age conversion to milliseconds fixed. 2013-10-09 16:36:06 +02:00
antirez 573c2fea91 Cluster: clusterCron() freq is now 10h. Still ping 1 node every sec.
After the change in clusterCron() frequency of call, we still want to
ping just one random node every second.
2013-10-09 16:29:17 +02:00
antirez e5864c73b6 Cluster: example redis.conf updated from sec to ms for cluster-node-timeout. 2013-10-09 16:21:27 +02:00
antirez ba42428633 Cluster: time switched from seconds to milliseconds.
All the internal state of cluster involving time is now using mstime_t
and mstime() in order to use milliseconds resolution.

Also the clusterCron() function is called with a 10 hz frequency instead
of 1 hz.

The cluster node_timeout must be also configured in milliseconds by the
user in redis.conf.
2013-10-09 16:19:26 +02:00
antirez 929b6a4480 Cluster: cluster stuff moved from redis.h to cluster.h. 2013-10-09 15:38:05 +02:00
antirez 6fa9b1a420 Merge branch 'bettercluster' into unstable 2013-10-08 13:04:33 +02:00
antirez ae2763f564 Cluster: masters don't vote for a slave with stale config.
When a slave requests our vote, the configEpoch he claims for its master
and the set of served slots must be greater or equal to the configEpoch
of the nodes serving these slots in the current configuraiton of the
master granting its vote.

In other terms, masters don't vote for slaves having a stale
configuration for the slots they want to serve.
2013-10-08 12:45:35 +02:00
antirez f7d6ad4366 Cluster: fix slave data age computation when master is still connected. 2013-10-07 16:07:13 +02:00
antirez 2c3301b9f5 Cluster: log message improved when FAIL is cleared from a slave node. 2013-10-07 15:44:58 +02:00
antirez 72f38cd70f Cluster: slave nodes advertise master slots bitmap and configEpoch. 2013-10-07 11:31:12 +02:00
antirez 0150c70b2b Replication: install the write handler when reusing a cached master.
Sometimes when we resurrect a cached master after a successful partial
resynchronization attempt, there is pending data in the output buffers
of the client structure representing the master (likely REPLCONF ACK
commands).

If we don't reinstall the write handler, it will never be installed
again by addReply*() family functions as they'll assume that if there is
already data pending, the write handler is already installed.

This bug caused some slaves after a successful partial sync to never
send REPLCONF ACK, and continuously being detected as timing out by the
master, with a disconnection / reconnection loop.
2013-10-04 16:14:54 +02:00
antirez 1461422ce6 Replication: install the write handler when reusing a cached master.
Sometimes when we resurrect a cached master after a successful partial
resynchronization attempt, there is pending data in the output buffers
of the client structure representing the master (likely REPLCONF ACK
commands).

If we don't reinstall the write handler, it will never be installed
again by addReply*() family functions as they'll assume that if there is
already data pending, the write handler is already installed.

This bug caused some slaves after a successful partial sync to never
send REPLCONF ACK, and continuously being detected as timing out by the
master, with a disconnection / reconnection loop.
2013-10-04 16:12:25 +02:00
antirez 6d8c2a4848 Replication: fix master timeout.
Since we started sending REPLCONF ACK from slaves to masters, the
lastinteraction field of the client structure is always refreshed as
soon as there is room in the socket output buffer, so masters in timeout
are detected with too much delay (the socket buffer takes a lot of time
to be filled by small REPLCONF ACK <number> entries).

This commit only counts data received as interactions with a master,
solving the issue.
2013-10-04 13:01:45 +02:00
antirez b41570f719 Replication: fix master timeout.
Since we started sending REPLCONF ACK from slaves to masters, the
lastinteraction field of the client structure is always refreshed as
soon as there is room in the socket output buffer, so masters in timeout
are detected with too much delay (the socket buffer takes a lot of time
to be filled by small REPLCONF ACK <number> entries).

This commit only counts data received as interactions with a master,
solving the issue.
2013-10-04 12:59:24 +02:00
antirez d62ae1ec05 PSYNC: safer handling of PSYNC requests.
There was a bug that over-esteemed the amount of backlog available,
however this could only happen when a slave was asking for an offset
that was in the "future" compared to the master replication backlog.

Now this case is handled well and logged as an incident in the master
log file.
2013-10-04 12:27:30 +02:00
antirez 4f9a69399b Add REWRITE to CONFIG subcommands help message. 2013-10-04 12:27:26 +02:00
antirez 37e06bd952 PSYNC: safer handling of PSYNC requests.
There was a bug that over-esteemed the amount of backlog available,
however this could only happen when a slave was asking for an offset
that was in the "future" compared to the master replication backlog.

Now this case is handled well and logged as an incident in the master
log file.
2013-10-04 12:25:09 +02:00
antirez 7afc0dd59a Cluster: new clusterDoBeforeSleep() API.
The new API is able to remember operations to perform before returning
to the event loop, such as checking if there is the failover quorum for
a slave, save and fsync the configuraiton file, and so forth.

Because this operations are performed before returning on the event
loop we are sure that messages that are sent in the same event loop run
will be delivered *after* the configuration is already saved, that is a
requirement sometimes. For instance we want to publish a new epoch only
when it is already stored in nodes.conf in order to avoid returning back
in the logical clock when a node is restarted.

This new API provides a big performance advantage compared to saving and
possibly fsyncing the configuration file multiple times in the same
event loop run, especially in the case of big clusters with tens or
hundreds of nodes.
2013-10-03 09:58:06 +02:00
antirez 211dcbe339 Cluster: update cluster config when slave changes master. 2013-10-02 12:27:12 +02:00
antirez 6c4d904baf Cluster: bus messages stats in CLUSTER info. 2013-10-02 10:10:08 +02:00
antirez abe81781ae Cluster: FAIL messages from unknown senders are handled better.
Previously the event was not logged but instead the node reported an
unknown packet type received.
2013-10-02 09:42:45 +02:00
antirez 7970ebd80a Cluster: senderCurrentEpoch == node currentEpoch was too strict.
We can accept a vote as long as its epoch is >= the epoch at which we
started the voting process. There is no need for it to be exactly the
same.
2013-10-01 17:21:28 +02:00
antirez f1bfd8233b Cluster: fix typo in clusterProcessPacket() comment. 2013-10-01 15:40:20 +02:00
antirez 1dedf9aa36 Cluster: time field removed from cluster messages header.
The new algorithm does not check replies time as checking for the
currentEpoch in the reply ensures that the reply is about the current
election process.
2013-09-30 16:19:44 +02:00
antirez 2b93a19537 Add REWRITE to CONFIG subcommands help message. 2013-09-30 11:53:18 +02:00
antirez 2d0844ee37 Cluster: log message shortened. 2013-09-30 11:51:58 +02:00
antirez 707ff0f714 Make clear that runids are not cluster node IDs. 2013-09-30 11:48:09 +02:00
antirez 4dc247eb31 Cluster: detect cluster reconfiguration when master slots drop to 0.
The old algorithm used a PROMOTED flag and explicitly checks about
slave->master convertions. Wit the new cluster meta-data propagation
algorithm we just look at the configEpoch to check if we need to
reconfigure slots, then:

1) If a node is a master but it reaches zero served slots becuase of
reconfiguration.
2) If a node is a slave but the master reaches zero served slots because
of a reconfiguration.

We switch as a replica of the new slots owner.
2013-09-30 11:45:26 +02:00
antirez 62b1591439 Cluster: re-order failover operations to make it safer.
We need to:

1) Increment the configEpoch.
2) Save it to disk and fsync the file.
3) Broadcast the PONG with the new configuration.

If other nodes will receive the updated configuration we need to be sure
to restart with this new config in the event of a crash.
2013-09-30 10:16:48 +02:00
antirez b187517719 Cluster: when upading the configEpoch for a node, save config on disk ASAP. 2013-09-30 10:16:25 +02:00
antirez 03ca903983 Cluster: fsync data when saving the cluster config. 2013-09-30 10:13:07 +02:00
antirez 026e63392e Cluster: update the node configEpoch when newer is detected. 2013-09-27 09:55:41 +02:00
antirez 7c4b8f29e7 Cluster: react faster when a slave wins an election. 2013-09-26 16:54:43 +02:00
antirez 42fa46e49a Cluster: removed an old source of delay to start the slave failover. 2013-09-26 13:28:19 +02:00
antirez a445aa30a0 Cluster: master node now uses new protocol to vote. 2013-09-26 13:00:41 +02:00
antirez fb9b76fe14 Cluster: slave node now uses the new protocol to get elected. 2013-09-26 11:13:17 +02:00
Michel Martens 347ab78e90 Document the redis-cli --csv option. 2013-09-26 10:12:46 +02:00
antirez 656c3ffe4a Cluster: fix redis-trib node config fingerprinting for new nodes format. 2013-09-25 12:58:06 +02:00
antirez 341ed1d1a8 Cluster: fix redis-trib for added configEpoch field in CLUSTER NODES. 2013-09-25 12:44:56 +02:00
antirez 32b5410af9 Cluster: add currentEpoch to CLUSTER INFO. 2013-09-25 12:38:36 +02:00
antirez 6ec795d2cf Cluster: update our currentEpoch when a greater one is seen. 2013-09-25 12:36:29 +02:00
antirez d426ada891 Cluster: broadcast currentEpoch and configEpoch in packets header. 2013-09-25 11:53:35 +02:00
antirez 12483b0061 Cluster: configEpoch added in cluster nodes description. 2013-09-25 11:47:13 +02:00
antirez da257afe57 htonu64() and ntohu64 added to endianconv.h. 2013-09-25 09:26:36 +02:00
antirez 3c9bb8751a Cluster: PFAIL -> FAIL transition allowed for slaves.
First change: now there is no need to be a master in order to detect a
failure, however the majority of masters signaling PFAIL or FAIL is needed.

This change is important because it allows slaves rejoining the cluster
after a partition to sense the FAIL condition so that eventually all the
nodes agree on failures.
2013-09-20 11:26:44 +02:00
antirez 925ea9f858 Cluster: added time field in cluster bus messages.
The time is sent in requests, and copied back in reply packets.
This way the receiver can compare the time field in a reply with its
local clock and check the age of the request associated with this reply.

This is an easy way to discard delayed replies. Note that only a clock
is used here, that is the one of the node sending the packet. The
receiver only copies the field back into the reply, so no
synchronization is needed between clocks of different hosts.
2013-09-20 09:22:21 +02:00
antirez 7bec743e66 Allow AUTH / PING when disconnected from slave and serve-stale-data is no. 2013-09-17 09:46:06 +02:00
antirez d0e327413b Cluster: don't add an handshake node for the same ip:port pair multiple times. 2013-09-04 15:52:16 +02:00
antirez 72587e6cc5 Cluster: free HANDSHAKE nodes after node_timeout.
Handshake nodes should turn into normal nodes or be freed in a
reasonable amount of time, otherwise they'll keep accumulating if the
address they are associated with is not reachable for some reason.
2013-09-04 12:41:21 +02:00
antirez 2debce325b redis-cli: fix big keys search when the key no longer exist.
The code freed a reply object that was never created, resulting in a
segfault every time randomkey returned a key that was deleted before we
queried it for size.
2013-09-04 10:35:53 +02:00
antirez 8eff339ca4 Cluster: CLUSTER SAVECONFIG command added. 2013-09-04 10:33:00 +02:00
antirez 528201ad6c Cluster: don't save HANDSHAKE nodes in nodes.conf. 2013-09-04 10:25:26 +02:00
antirez e5d5da6f7c Cluster: always use safe iteartors to iterate server.cluster->nodes. 2013-09-04 10:07:50 +02:00
Maxim Zakharov 43fe2d0d97 mistype fixed 2013-09-03 15:15:51 +02:00
Maxim Zakharov 70e82e5c79 A mistype fixed 2013-09-03 15:15:48 +02:00
antirez 354a5de270 Cluster: clusterReadHandler() reworked to be more correct and simpler to follow. 2013-09-03 11:43:52 +02:00
antirez 1036b4b21b Cluster: use non-blocking I/O for the cluster bus. 2013-09-03 11:43:52 +02:00
antirez f6efb6cdec Cluster: fixed a bug in clusterSendPublish() due to inverted statements.
The code used to copy the header *after* the 'hdr' pointer was already
switched to the new buffer. Of course we need to do the reverse.
2013-09-03 11:43:43 +02:00
antirez e9d97b453e Test: Lua stack leak regression test added. 2013-08-30 08:59:11 +02:00
antirez f79b1cb49e Test: added a memory efficiency test. 2013-08-29 16:23:57 +02:00
antirez 41d3147344 Fixed critical memory leak from EVAL.
Multiple missing calls to lua_pop prevented the error handler function
pushed on the stack for lua_pcall() to be popped before returning,
causing a memory leak in almost all the code paths of EVAL (both
successful calls and calls returning errors).

This caused two issues: Lua leaking memory (and this was very visible
from INFO memory output, as the 'used_memory_lua' field reported an
always increasing amount of memory used), and as a result slower and
slower GC cycles resulting in all the CPU being used.

Thanks to Tanguy Le Barzic for noticing something was wrong with his 2.8
slave, and for creating a testing EC2 environment where I was able to
investigate the issue.
2013-08-29 11:54:03 +02:00
yihuang 9bb91d198c fix lua_cmsgpack pack map as array 2013-08-27 15:19:25 +02:00
antirez e29e426b43 Fix an hypothetical issue in processMultibulkBuffer(). 2013-08-27 13:00:06 +02:00
antirez 8811d49009 Remove useful check from tryObjectEncoding().
We are sure the string is large, since when the sds optimization branch
is entered it means that it was not possible to encode it as EMBSTR for
size concerns.
2013-08-27 12:36:52 +02:00
antirez 38b2e65e15 tryObjectEncoding(): optimize sds strings if possible.
When no encoding is possible, at least try to reallocate the sds string
with one that does not waste memory (with free space at the end of the
buffer) when the string is large enough.
2013-08-27 12:15:13 +02:00
antirez 6672bc8b3b tryObjectEncoding(): don't call stringl2() for too big strings.
We are sure that a string that is longer than 21 chars cannot be
represented by a 64 bit signed integer, as -(2^64) is 21 chars:

strlen(-18446744073709551616) => 21
2013-08-27 11:56:47 +02:00
antirez ff9d66c4a9 Don't over-allocate the sds string for large bulk requests.
The call to sdsMakeRoomFor() did not accounted for the amount of data
already present in the query buffer, resulting into over-allocation.
2013-08-27 11:54:38 +02:00
antirez e21803348a DEBUG SDSLEN added.
This command is only useful for low-level debugging of memory issues due
to sds wasting memory as empty buffer at the end of the string.
2013-08-27 11:53:49 +02:00
antirez b34126e378 Update server.lastbgsave_status when fork() fails. 2013-08-27 10:16:29 +02:00
antirez 003cc8a4f5 Only run the fast active expire cycle if master & enabled. 2013-08-27 09:31:55 +02:00
antirez 303dde3757 Don't update node pong time via gossip.
This feature was implemented in the initial days of the Redis Cluster
implementaiton but is not a good idea at all.

1) It depends on clocks to be synchronized, that is already very bad.
2) Moreover it adds a bug where the pong time is updated via gossip so
no new PING is ever sent by the current node, with the effect of no PONG
received, no update of tables, no clearing of PFAIL flag.

In general to trust other nodes about the reachability of other nodes is
a broken distributed programming model.
2013-08-26 16:16:25 +02:00
antirez 6ae37b0e1d Cluster: set event handler in cluster bus listening socket.
The commit using listenToPort() introduced this bug by no longer
creating the event handler to handle incoming messages from the cluster
bus.
2013-08-22 14:53:53 +02:00
antirez 81a6a9639a Use listenToPort() in cluster.c as well. 2013-08-22 14:05:07 +02:00
antirez 4f310e05c0 Opening TCP listening ports refactored into a function. 2013-08-22 14:01:16 +02:00
antirez 0f0cc88589 Print error message when can't bind * on any address. 2013-08-22 13:02:59 +02:00
antirez 042776aff7 Cluster: fix CLUSTER MEET ip address validation.
This was broken by the IPv6 support patches.
2013-08-22 11:54:28 +02:00
antirez 9cf30132cc Cluster: process MEET packets as PING packets.
Somewhat a previous commit broken this so CLUSTER MEET was no longer
working.
2013-08-22 11:53:28 +02:00
antirez b804afcf01 Use a safe dict.c iterator in clusterCron(). 2013-08-21 15:51:15 +02:00
antirez 35a977c499 Fix for issue #1214 simplified. 2013-08-21 11:36:09 +02:00
Salvatore Sanfilippo 038e356dbc Merge pull request #1214 from kaoshijuan/unstable
fixed initServer fail problem
2013-08-21 02:18:41 -07:00
antirez 7e9929e12e Use printf %zu specifier to print private_dirty. 2013-08-20 12:04:57 +02:00
antirez 1c08302edc dictFingerprint(): cast pointers to integer of same size. 2013-08-20 11:49:55 +02:00
antirez 00ddc3500c Revert "Fixed type in dict.c comment: 265 -> 256."
This reverts commit 6253180abd.
2013-08-19 17:25:48 +02:00
antirez 6253180abd Fixed type in dict.c comment: 265 -> 256. 2013-08-19 15:10:37 +02:00
antirez 1c75408457 assert.h replaced with redisassert.h when appropriate.
Also a warning was suppressed by including unistd.h in redisassert.h
(needed for _exit()).
2013-08-19 15:01:21 +02:00
antirez ca294c6b1e Added redisassert.h as drop in replacement for assert.h.
By using redisassert.h version of assert() you get stack traces in the
log instead of a process disappearing on assertions.
2013-08-19 15:01:15 +02:00
antirez 905d4822da dictFingerprint() fingerprinting made more robust.
The previous hashing used the trivial algorithm of xoring the integers
together. This is not optimal as it is very likely that different
hash table setups will hash the same, for instance an hash table at the
start of the rehashing process, and at the end, will have the same
fingerprint.

Now we hash N integers in a smarter way, by summing every integer to the
previous hash, and taking the integer hashing again (see the code for
further details). This way it is a lot less likely that we get a
collision. Moreover this way of hashing explicitly protects from the
same set of integers in a different order to hash to the same number.

This commit is related to issue #1240.
2013-08-19 15:01:12 +02:00
antirez 3039e806d8 Fix comments for correctness in zunionInterGenericCommand().
Related to issue #1240.
2013-08-19 15:01:05 +02:00
antirez cfb9d025c6 Properly init/release iterators in zunionInterGenericCommand().
This commit does mainly two things:

1) It fixes zunionInterGenericCommand() by removing mass-initialization
of all the iterators used, so that we don't violate the unsafe iterator
API of dictionaries. This fixes issue #1240.

2) Since the zui* APIs required the allocator to be initialized in the
zsetopsrc structure in order to use non-iterator related APIs, this
commit fixes this strict requirement by accessing objects directly via
the op->subject->ptr pointer we have to the object.
2013-08-19 15:01:01 +02:00
antirez 48cde3fe47 dict.c iterator API misuse protection.
dict.c allows the user to create unsafe iterators, that are iterators
that will not touch the dictionary data structure in any way, preventing
copy on write, but at the same time are limited in their usage.

The limitation is that when itearting with an unsafe iterator, no call
to other dictionary functions must be done inside the iteration loop,
otherwise the dictionary may be incrementally rehashed resulting into
missing elements in the set of the elements returned by the iterator.

However after introducing this kind of iterators a number of bugs were
found due to misuses of the API, and we are still finding
bugs about this issue. The bugs are not trivial to track because the
effect is just missing elements during the iteartion.

This commit introduces auto-detection of the API misuse. The idea is
that an unsafe iterator has a contract: from initialization to the
release of the iterator the dictionary should not change.

So we take a fingerprint of the dictionary state, xoring a few important
dict properties when the unsafe iteartor is initialized. We later check
when the iterator is released if the fingerprint is still the same. If it
is not, we found a misuse of the iterator, as not allowed API calls
changed the internal state of the dictionary.

This code was checked against a real bug, issue #1240.

This is what Redis prints (aborting) when a misuse is detected:

Assertion failed: (iter->fingerprint == dictFingerprint(iter->d)),
function dictReleaseIterator, file dict.c, line 587.
2013-08-19 15:00:57 +02:00
antirez 7398930756 Use precomptued objects for bulk and mbulk prefixes. 2013-08-12 12:50:49 +02:00
antirez c06de115af replicationFeedSlaves() func name typo: feedReplicationBacklogWithObject -> feedReplicationBacklog. 2013-08-12 12:50:45 +02:00
antirez dcc48a8143 replicationFeedSlave() reworked for correctness and speed.
The previous code using a static buffer as an optimization was lame:

1) Premature optimization, actually it was *slower* than naive code
   because resulted into the creation / destruction of the object
   encapsulating the output buffer.
2) The code was very hard to test, since it was needed to have specific
   tests for command lines exceeding the size of the static buffer.
3) As a result of "2" the code was bugged as the current tests were not
   able to stress specific corner cases.

It was replaced with easy to understand code that is safer and faster.
2013-08-12 12:50:29 +02:00
antirez aa05128f51 Fix a PSYNC bug caused by a variable name typo. 2013-08-12 11:51:35 +02:00
antirez 610224d0d0 Fix sdsempty() prototype in sds.h. 2013-08-12 11:38:21 +02:00
antirez 89ffba9133 Replication: better way to send a preamble before RDB payload.
During the replication full resynchronization process, the RDB file is
transfered from the master to the slave. However there is a short
preamble to send, that is currently just the bulk payload length of the
file in the usual Redis form $..length..<CR><LF>.

This preamble used to be sent with a direct write call, assuming that
there was alway room in the socket output buffer to hold the few bytes
needed, however this does not scale in case we'll need to send more
stuff, and is not very robust code in general.

This commit introduces a more general mechanism to send a preamble up to
2GB in size (the max length of an sds string) in a non blocking way.
2013-08-12 10:29:14 +02:00
antirez db862e8ef0 redis-benchmark: changes to random arguments substitution.
Before this commit redis-benchmark supported random argumetns in the
form of :rand:000000000000. In every string of that form, the zeros were
replaced with a random number of 12 digits at every command invocation.

However this was far from perfect as did not allowed to generate simply
random numbers as arguments, there was always the :rand: prefix.

Now instead every argument in the form __rand_int__ is replaced with a
12 digits number. Note that "__rand_int__" is 12 characters itself.

In order to implement the new semantic, it was needed to change a few
thigns in the internals of redis-benchmark, as new clients are created
cloning old clients, so without a stable prefix such as ":rand:" the old
way of cloning the client was no longer able to understand, from the old
command line, what was the position of the random strings to substitute.

Now instead a client structure is passed as a reference for cloning, so
that we can directly clone the offsets inside the command line.
2013-08-08 16:42:08 +02:00
antirez 92ab77f8d5 redis-benchmark: replace snprintf()+memcpy with faster code.
This change was profiler-driven, but the actual effect is hard to
measure in real-world redis benchmark runs.
2013-08-08 14:33:14 +02:00
Salvatore Sanfilippo de698798bc Merge pull request #1234 from badboy/patch-2
Little typo
2013-08-07 07:08:04 -07:00
Jan-Erik Rediger 74c0af21f5 Little typo 2013-08-07 16:05:09 +02:00
antirez 36a0947185 redis-benchmark: fix memory leak introduced by 346256f 2013-08-07 16:00:18 +02:00
antirez 346256f933 redis-benchmark: max pipeline length hardcoded limit removed. 2013-08-07 15:58:58 +02:00
antirez 6cbfdd9520 redis-benchmark: fix db selection when :rand: feature is used. 2013-08-06 19:01:54 +02:00
antirez d52c9b6cdb redis-benchmark: ability to SELECT a specifid db number. 2013-08-06 18:50:54 +02:00
antirez 112fa47978 Add per-db average TTL information in INFO output.
Example:

db0:keys=221913,expires=221913,avg_ttl=655

The algorithm uses a running average with only two samples (current and
previous). Keys found to be expired are considered at TTL zero even if
the actual TTL can be negative.

The TTL is reported in milliseconds.
2013-08-06 15:00:43 +02:00
antirez 4befe73b60 activeExpireCycle(): fix about fast cycle early start.
We don't want to repeat a fast cycle too soon, the previous code was
broken, we need to wait two times the period *since* the start of the
previous cycle in order to avoid there is an even space between cycles:

.-> start                   .-> second start
|                           |
+-------------+-------------+--------------+
| first cycle |    pause    | second cycle |
+-------------+-------------+--------------+

The second and first start must be PERIOD*2 useconds apart hence the *2
in the new code.
2013-08-06 12:59:04 +02:00
antirez 6500fabfb8 Some activeExpireCycle() refactoring. 2013-08-06 12:55:49 +02:00
antirez d398f38879 Remove dead code and fix comments for new expire code. 2013-08-06 12:36:13 +02:00
antirez 66a26471dc Darft #2 for key collection algo: more improvements.
This commit makes the fast collection cycle time configurable, at
the same time it does not allow to run a new fast collection cycle
for the same amount of time as the max duration of the fast
collection cycle.
2013-08-05 16:14:28 +02:00
antirez b09ea1bd90 Draft #1 of a new expired keys collection algorithm.
The main idea here is that when we are no longer to expire keys at the
rate the are created, we can't block more in the normal expire cycle as
this would result in too big latency spikes.

For this reason the commit introduces a "fast" expire cycle that does
not run for more than 1 millisecond but is called in the beforeSleep()
hook of the event loop, so much more often, and with a frequency bound
to the frequency of executed commnads.

The fast expire cycle is only called when the standard expiration
algorithm runs out of time, that is, consumed more than
REDIS_EXPIRELOOKUPS_TIME_PERC of CPU in a given cycle without being able
to take the number of already expired keys that are yet not collected
to a number smaller than 25% of the number of keys.

You can test this commit with different loads, but a simple way is to
use the following:

Extreme load with pipelining:

redis-benchmark -r 100000000 -n 100000000  \
        -P 32 set ele:rand:000000000000 foo ex 2

Remove the -P32 in order to avoid the pipelining for a more real-world
load.

In another terminal tab you can monitor the Redis behavior with:

redis-cli -i 0.1 -r -1 info keyspace

and

redis-cli --latency-history

Note: this commit will make Redis printing a lot of debug messages, it
is not a good idea to use it in production.
2013-08-05 12:05:22 +02:00
antirez cd0ea1f202 Test: regression test for issue #1221. 2013-07-29 17:39:28 +02:00
antirez c151eb6d92 Fix replicationFeedSlaves() off-by-one bug.
This fixes issue #1221.
2013-07-28 12:49:34 +02:00
antirez bf56948fd0 Remove dead variable bothsds from object.c.
Thanks to @run and @badboy for spotting this.
Triva: clang was not able to provide me a warning about that when
compiling.

This closes #1024 and #1207, committing the change myself as the pull
requests no longer apply cleanly after other changes to the same
function.
2013-07-28 11:00:09 +02:00
antirez 320fa02b9b Use latest sds.c in the hiredis library under deps. 2013-07-25 10:32:19 +02:00
Allan a0e986d7f2 fixed initServer fail while having no IPv6 nor IPv4 2013-07-25 15:36:00 +08:00
Allan cba7a4e69a fixed initServer failed if no IPV4 or no IPV6 2013-07-25 15:28:33 +08:00
antirez 3ccc17a4a5 Ignore sdsrange return value. 2013-07-24 18:59:54 +02:00
Allan 1e7cff23b3 fixed bug issue of #1213 2013-07-24 21:34:55 +08:00
antirez 6ea8e0949c sdsrange() does not need to return a value.
Actaully the string is modified in-place and a reallocation is never
needed, so there is no need to return the new sds string pointer as
return value of the function, that is now just "void".
2013-07-24 11:21:39 +02:00
antirez 75b760a72d Inline protocol improved to accept quoted strings. 2013-07-24 10:37:55 +02:00
antirez 076c2623ac Every function inside sds.c is now commented. 2013-07-23 16:35:55 +02:00
antirez ec7f480e11 getStringObjectSdsUsedMemory() function added.
Now that EMBSTR encoding exists we calculate the amount of memory used
by the SDS part of a Redis String object in two different ways:

1) For raw string object, the size of the allocation is considered.
2) For embstr objects, the length of the string itself is used.

The new function takes care of this logic.
2013-07-23 11:50:17 +02:00
antirez ddccd0ed58 Test: regression test for issue #1208. 2013-07-22 23:40:48 +02:00
antirez dbaa5b0b9a Fix setDeferredMultiBulkLength() c->reply_bytes handling with EMBSTR
This function missed proper handling of reply_bytes when gluing to the
previous object was used. The issue was introduced with the EMBSTR new
string object encoding.

This fixes issue #1208.
2013-07-22 23:29:12 +02:00
antirez 7ed7652846 Fixed a possible bug in client->reply_bytes computation. 2013-07-22 11:05:55 +02:00
antirez a31693417d Fix replicationFeedSlaves() to use sdsEncodedObject() macro. 2013-07-22 10:36:27 +02:00
antirez 894eba07c8 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 b9cc90a119 addReplyDouble(): format infinite in a libc agnostic way.
There are systems that when printing +/- infinte with printf-family
functions will not use the usual "inf" "-inf", but different strings.
Handle that explicitly.

Fixes issue #930.
2013-07-17 15:05:25 +02:00
antirez f590dd82ce Fixed typo in rio.h, simgle -> single. 2013-07-16 15:43:36 +02:00
yoav 63d15dfc87 Chunked loading of RDB to prevent redis from stalling reading very large keys. 2013-07-16 15:41:24 +02:00
antirez 9d520a7f70 Make sure that ZADD can accept the full range of double values.
This fixes issue #1194, that contains many details.

However in short, it was possible for ZADD to not accept as score values
that was however possible to obtain with multiple calls to ZINCRBY, like
in the following example:

redis 127.0.0.1:6379> zadd k 2.5e-308 m
(integer) 1
redis 127.0.0.1:6379> zincrby k -2.4e-308 m
"9.9999999999999694e-310"
redis 127.0.0.1:6379> zscore k m
"9.9999999999999694e-310"
redis 127.0.0.1:6379> zadd k 9.9999999999999694e-310 m1
(error) ERR value is not a valid float

The problem was due to strtod() returning ERANGE in the following case
specified by POSIX:

"If the correct value would cause an underflow, a value whose magnitude
is no greater than the smallest normalized positive number in the return
type shall be returned and errno set to [ERANGE].".

Now instead the returned value is accepted even when ERANGE is returned
as long as the return value of the function is not negative or positive
HUGE_VAL or zero.
2013-07-16 15:05:13 +02:00
Salvatore Sanfilippo 34e2065830 Merge pull request #1193 from tnm/patch-1
Make sure the log standardizes on 'timeout'
2013-07-12 14:12:04 -07:00
Ted Nyman f39a0bdb77 Make sure the log standardizes on 'timeout' 2013-07-12 14:06:27 -07:00
antirez 123b221dc9 Use the environment locale for strcoll() collation. 2013-07-12 13:38:43 +02:00
antirez cf1579a798 SORT ALPHA: use collation instead of binary comparison.
Note that we only do it when STORE is not used, otherwise we want an
absolutely locale independent and binary safe sorting in order to ensure
AOF / replication consistency.

This is probably an unexpected behavior violating the least surprise
rule, but there is currently no other simple / good alternative.
2013-07-12 12:02:36 +02:00
antirez 81e55ec0f3 Fixed compareStringObject() and introduced collateStringObject().
compareStringObject was not always giving the same result when comparing
two exact strings, but encoded as integers or as sds strings, since it
switched to strcmp() when at least one of the strings were not sds
encoded.

For instance the two strings "123" and "123\x00456", where the first
string was integer encoded, would result into the old implementation of
compareStringObject() to return 0 as if the strings were equal, while
instead the second string is "greater" than the first in a binary
comparison.

The same compasion, but with "123" encoded as sds string, would instead
return a value < 0, as it is correct. It is not impossible that the
above caused some obscure bug, since the comparison was not always
deterministic, and compareStringObject() is used in the implementation
of skiplists, hash tables, and so forth.

At the same time, collateStringObject() was introduced by this commit, so
that can be used by SORT command to return sorted strings usign
collation instead of binary comparison. See next commit.
2013-07-12 11:56:52 +02:00
Salvatore Sanfilippo 2ed64e1f7a Merge pull request #1192 from badboy/ipv6-rediscli
Wrap IPv6 in brackets in the prompt.
2013-07-12 01:55:09 -07:00
Jan-Erik Rediger 1b696dc07c Wrap IPv6 in brackets in the prompt. 2013-07-11 17:47:55 +02:00
antirez 73ae8558c1 Sentinel: embed IPv6 address into [] when naming slave/sentinel instance. 2013-07-11 16:38:40 +02:00
antirez 3fc7f324d2 Sentinel: use comma as separator to publish hello messages.
We use comma to play well with IPv6 addresses, but the implementation is
still able to parse the old messages separated by colons.
2013-07-11 16:37:47 +02:00
antirez 4735f03c5a hiredis: minimal IPv6 support. 2013-07-11 13:11:27 +02:00
antirez 5c5ebb0b9a Sentinel: make sure published addr/id buffer is large enough.
With ipv6 support we need more space, so we account for the IP address
max size plus what we need for the Run ID, port, flags.
2013-07-10 14:44:38 +02:00
antirez bd3c897e9f anet.c: save some vertical space. 2013-07-10 14:37:13 +02:00
antirez d83dca4c79 anet.c: use SO_REUSEADDR when creating listening sockets.
It used to be ok, but the socket option was removed when adding IPv6
support.
2013-07-10 14:34:58 +02:00
antirez d1cbad6d14 Use getClientPeerId() for MONITOR implementation. 2013-07-09 16:21:21 +02:00
antirez d0001fe810 getClientPeerId() refactored into two functions. 2013-07-09 15:46:34 +02:00
antirez e4c019e7a8 getClientPeerId() now reports errors.
We now also use it in CLIENT KILL implementation.
2013-07-09 15:28:30 +02:00
antirez 5cdc5da990 getClientPeerID introduced.
The function returns an unique identifier for the client, as ip:port for
IPv4 and IPv6 clients, or as path:0 for Unix socket clients.

See the top comment in the function for more info.
2013-07-09 12:49:20 +02:00
antirez 631d656a94 All IP string repr buffers are now REDIS_IP_STR_LEN bytes. 2013-07-09 11:32:52 +02:00
antirez f19e267e9a IPv6: bind IPv4 and IPv6 interfaces by default. 2013-07-09 10:47:17 +02:00
antirez 90038906f4 Fix old anetPeerToString() API call in replication.c 2013-07-08 16:11:52 +02:00
antirez c76df73010 Revert "Document port6 and bind6 config options."
IPv6 support is not going to use IPv6 specific options, just it will be
possible to specify all the ipv4 / ipv6 addresses of the interfaces to
bind, otherwise connections will be accepted from all the interfaces in
both IPv4 and IPv6 addresses.

This reverts commit 93570e179e.
2013-07-08 16:08:43 +02:00
Geoff Garside e04fdf26fe Add IPv6 support to sentinel.c.
This has been done by exposing the anetSockName() function anet.c
to be used when the sentinel is publishing its existence to the masters.

This implementation is very unintelligent as it will likely break if used
with IPv6 as the nested colons will break any parsing of the PUBLISH string
by the master.
2013-07-08 16:08:36 +02:00
Geoff Garside a68e3d4c6a Cleanup main() and BACKTRACE mistaken pulled while rebasing. 2013-07-08 16:07:26 +02:00
Geoff Garside 1ca4008d14 Fix calls to anetPeerToString() missing buffer size. 2013-07-08 16:07:26 +02:00
Geoff Garside 93570e179e Document port6 and bind6 config options.
Add commented port6 and bind6 options to default redis.conf file.
2013-07-08 16:06:44 +02:00
Geoff Garside 56df827198 Add anetTcp6Server() function.
Refactor the common code from anetTcpServer into internal function which
can be used by both anetTcpServer and anetTcp6Server.
2013-07-08 15:58:14 +02:00
Geoff Garside 72a3922617 Add static anetV6Only() function.
This function sets the IPV6_V6ONLY option to 1 to use separate stack
IPv6 sockets.
2013-07-08 15:58:14 +02:00
Geoff Garside 62a3b7e3d9 Change anetTcpGenericConnect to use AF_UNSPEC.
This allows anetTcpGenericConnect to try to connect to AF_INET6
addresses in addition to any resolved AF_INET addresses.
2013-07-08 15:58:14 +02:00
Geoff Garside ca78446c55 Mark places that might want changing for IPv6.
Any places which I feel might want to be updated to work differently
with IPv6 have been marked with a comment starting "IPV6:".

Currently the only comments address places where an IP address is
combined with a port using the standard : separated form. These may want
to be changed when printing IPv6 addresses to wrap the address in []
such as

	[2001:db8::c0:ffee]:6379

instead of

	2001:db8::c0:ffee:6379

as the latter format is a technically valid IPv6 address and it is hard
to distinguish the IPv6 address component from the port unless you know
the port is supposed to be there.
2013-07-08 15:58:14 +02:00
Geoff Garside 96b02dc055 Expand ip char buffers which are too small for v6.
Increase the size of character buffers being used to store printable IP
addresses so that they can safely store IPv6 addresses.
2013-07-08 15:58:14 +02:00
Geoff Garside f7d9a92d4e Mark ip string buffers which could be reduced.
In two places buffers have been created with a size of 128 bytes which
could be reduced to INET6_ADDRSTRLEN to still hold a full IP address.
These places have been marked as they are presently big enough to handle
the needs of storing a printable IPv6 address.
2013-07-08 15:57:23 +02:00
Geoff Garside e6bf4c2676 Update clusterCommand to handle AF_INET6 addresses
Changes the sockaddr_in to a sockaddr_storage. Attempts to convert the
IP address into an AF_INET or AF_INET6 before returning an "Invalid IP
address" error. Handles converting the sockaddr from either AF_INET or
AF_INET6 back into a string for storage in the clusterNode ip field.
2013-07-08 15:57:23 +02:00
Geoff Garside 5be83eecac Update node2IpString to handle AF_INET6 addresses.
Change the sockaddr_in to sockaddr_storage which is capable of storing
both AF_INET and AF_INET6 sockets. Uses the sockaddr_storage ss_family
to correctly return the printable IP address and port.

Function makes the assumption that the buffer is of at least
REDIS_CLUSTER_IPLEN bytes in size.
2013-07-08 15:57:23 +02:00
Geoff Garside 6181455ac6 Update REDIS_CLUSTER_IPLEN to INET6_ADDRSTRLEN.
Change REDIS_CLUSTER_IPLEN to INET6_ADDRSTRLEN so that the clusterNode
ip character buffer is big enough to hold an IPv6 address.
2013-07-08 15:57:23 +02:00
Geoff Garside 23f4d905ce Update anetPeerToString to handle AF_INET6 addrs.
Change the sockaddr_in to sockaddr_storage which is capable of storing
both AF_INET and AF_INET6 sockets. Uses the sockaddr_storage ss_family
to correctly return the printable IP address and port.
2013-07-08 15:57:22 +02:00
Geoff Garside fa723d98d6 Update anetTcpAccept to handle AF_INET6 addresses.
Change the sockaddr_in to sockaddr_storage which is capable of storing
both AF_INET and AF_INET6 sockets. Uses the sockaddr_storage ss_family
to correctly return the printable IP address and port.
2013-07-08 15:57:22 +02:00
Geoff Garside e7b34e8dc3 Update anetResolve to resolve AF_INET6 as well.
Change the getaddrinfo(3) hints family from AF_INET to AF_UNSPEC to
allow resolution of IPv6 addresses as well as IPv4 addresses. The
function will return the IP address of whichever address family is
preferenced by the operating system. Most current operating systems
will preference AF_INET6 over AF_INET.

Unfortunately without attempting to establish a connection to the
remote address we can't know if the host is capable of using the
returned IP address. It might be desirable to have anetResolve
accept an additional argument specifying the AF_INET/AF_INET6 address
the caller would like to receive. Currently though it does not appear
as though the anetResolve function is ever used within Redis.
2013-07-08 15:57:22 +02:00
Geoff Garside 2345cee335 Update calls to anetResolve to include buffer size 2013-07-08 15:57:22 +02:00
Geoff Garside ee5a6df101 Update calls to anetPeerToString to include ip_len. 2013-07-08 15:57:22 +02:00
Geoff Garside b39e827d22 Add missing includes for getpeername.
getpeername(2) requires <sys/socket.h> which on some systems also
requires <sys/types.h>. Include both to avoid compilation warnings.
2013-07-08 15:55:39 +02:00
Geoff Garside 9cfa02fe73 Add macro to define clusterNode.ip buffer size.
Add REDIS_CLUSTER_IPLEN macro to define the size of the clusterNode ip
character array. Additionally use this macro in inet_ntop(3) calls where
the size of the array was being defined manually.

The REDIS_CLUSTER_IPLEN is defined as INET_ADDRSTRLEN which defines the
correct size of a buffer to store an IPv4 address in. The
INET_ADDRSTRLEN macro itself is defined in the <netinet/in.h> header
file and should be portable across the majority of systems.
2013-07-08 15:55:39 +02:00
Geoff Garside 6e894f02cf Fix cluster.c inet_ntop use of sizeof(n->ip).
Using sizeof with an array will only return expected results if the
array is created in the scope of the function where sizeof is used. This
commit changes the inet_ntop calls so that they use the fixed buffer
value as defined in redis.h which is 16.
2013-07-08 15:51:37 +02:00
Geoff Garside 693b640510 Use inet_pton(3) in clusterCommand.
Replace inet_aton(3) call with the more future proof inet_pton(3)
function which is capable of handling additional address families.
2013-07-08 15:51:37 +02:00
Geoff Garside a6ea707cec Use inet_ntop(3) in nodeIp2String & clusterCommand
Replace inet_ntoa(3) calls with the more future proof inet_ntop(3)
function which is capable of handling additional address families.
2013-07-08 15:51:37 +02:00
Geoff Garside f5494a427e Update anetTcpAccept & anetPeerToString calls.
Add the additional ip buffer length argument to function calls of
anetTcpAccept and anetPeerToString in network.c and cluster.c
2013-07-08 15:51:37 +02:00
Geoff Garside ef839f9006 Use inet_ntop(3) in anet. #apichange
Replace inet_ntoa(3) calls with the more future proof inet_ntop(3)
function which is capable of handling additional address families.

API Change: anetTcpAccept() & anetPeerToString() additional argument
  additional argument required to specify the length of the character
  buffer the IP address is written to in order to comply with
  inet_ntop(3) function semantics.
2013-07-08 15:50:15 +02:00
Geoff Garside e0cb24351c Use getaddrinfo(3) in a anetTcpServer.
Change anetTcpServer() function to use getaddrinfo(3) to perform
address resolution, socket creation and binding. Resolved addresses
are limited to those reachable by the AF_INET address family.
2013-07-08 15:49:22 +02:00
Geoff Garside 0e01ce1b13 Use getaddrinfo(3) in anetTcpGenericConnect.
Change anetTcpGenericConnect() function to use getaddrinfo(3) to
perform address resolution, socket creation and connection. Resolved
addresses are limited to those reachable by the AF_INET family.
2013-07-08 15:49:22 +02:00
Geoff Garside 580b7dce9b Add anetSetReuseAddr(err, fd) static function.
Extract setting SO_REUSEADDR socket option into separate function
so the same code can be more easily used by anetCreateSocket and
other functions.
2013-07-08 15:49:22 +02:00
Geoff Garside 071963c855 Use getaddrinfo(3) in anetResolve. #apichange
Change anetResolve() function to use getaddrinfo(3) to resolve hostnames.
Resolved hostnames are limited to those reachable by the AF_INET address
family.

API Change: anetResolve requires additional argument.
  additional argument required to specify the length of the character
  buffer the IP address is written to in order to comply with
  inet_ntop(3) function semantics. inet_ntop(3) replaces inet_ntoa(3)
  as it has been designed to be compatible with more address families.
2013-07-08 15:47:57 +02:00
antirez 64b3b9b1d4 Example redis.conf: bind to multiple interfaces documented. 2013-07-08 10:42:22 +02:00
antirez 98eecb70eb Binding multiple IPs done properly with multiple sockets. 2013-07-05 11:47:20 +02:00
antirez 2160effc78 Revert "Cluster: use new anet.c listening socket creation API."
This reverts commit 016ac38a21.
2013-07-05 11:08:44 +02:00
antirez c978b864f7 Revert "anet.c: Allow creation of TCP listening sockets bound to N addresses."
Bind() can't be called multiple times against the same socket, multiple
sockets are required to bind multiple interfaces, silly me.

This reverts commit bd234d62bb.
2013-07-05 11:07:55 +02:00
antirez 90b0d66cce Ability to bind multiple addresses. 2013-07-04 18:50:15 +02:00
antirez 016ac38a21 Cluster: use new anet.c listening socket creation API. 2013-07-04 18:49:49 +02:00
antirez bd234d62bb anet.c: Allow creation of TCP listening sockets bound to N addresses. 2013-07-04 18:48:46 +02:00
antirez 585b0a61ce sds.c: new function sdsjoin() to join strings. 2013-07-04 18:30:59 +02:00
antirez 1135e9faa2 redis-cli: introduced --pipe-timeout.
When in --pipe mode, after all the data transfer to the server is
complete, now redis-cli waits at max the specified amount of
seconds (30 by default, use 0 to wait forever) without receiving any
reply at all from the server. After this time limit the operation is
aborted with an error.

That's related to issue #681.
2013-07-03 12:22:03 +02:00
antirez fbb97c6b13 redis-cli --pipe: send final ECHO in a safer way.
If the protocol read from stdin happened to contain grabage (invalid
random chars), in the previous implementation it was possible to end
with something like:

dksfjdksjflskfjl*2\r\n$4\r\nECHO....

That is invalid as the *2 should start into a new line. Now we prefix
the ECHO with a CRLF that has no effects on the server but prevents this
issues most of the times.

Of course if the offending wrong sequence is something like:

$3248772349\r\n

No one is going to save us as Redis will wait for data in the context of
a big argument, so this fix does not cover all the cases.

This partially fixes issue #681.
2013-07-03 11:59:44 +02:00
antirez 7e63167d27 pqsort.c: remove the "switch to insertion sort" optimization.
It causes catastrophic performance for certain inputs.

Relevant NetBSD commit:

http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/stdlib/qsort.c?rev=1.20&content-type=text/x-cvsweb-markup&only_with_tag=MAIN

This fixes issue #968.
2013-07-02 17:47:32 +02:00
Salvatore Sanfilippo 7d626d4975 Merge pull request #776 from charsyam/ziplist-bug
fix randstring bug in ziplist.c
2013-07-02 03:18:18 -07:00
antirez 1b10522a08 Only allow basenames for dbfilename and appendfilename.
This fixes issue #1094.
2013-07-02 12:14:28 +02:00
antirez 6978aeb3bf pathIsBaseName() added to utils.c
The function is used to test that the specified string looks like just
as the basename of a path, without any absolute or relative path.
2013-07-02 12:08:07 +02:00
antirez 0781ad6899 getAbsolutePath() moved into utils.c 2013-07-02 11:56:52 +02:00
antirez de9a221749 CONFIG SET maxclients. 2013-06-28 17:08:03 +02:00
antirez 8e2d082066 ae.c event loop: API to resize the fd set size on the run. 2013-06-28 16:39:49 +02:00
antirez 3130670b97 Allow SHUTDOWN in loading state. 2013-06-27 12:18:29 +02:00
antirez 13585dd677 function renamed: popcount_binary -> redisPopcount. 2013-06-26 15:19:06 +02:00
Salvatore Sanfilippo bae60ede1d Merge pull request #1111 from yamt/netbsd3
netbsd support
2013-06-26 06:17:02 -07:00
antirez 8ca265cdb7 Don't disconnect pre PSYNC replication clients for timeout.
Clients using SYNC to replicate are older implementations, such as
redis-cli --slave, and are not designed to acknowledge the master with
REPLCONF ACK commands, so we don't have any feedback and should not
disconnect them on timeout.
2013-06-26 10:11:20 +02:00
antirez d5f1e4b0b5 Test: add some AOF testing to EVALSHA replication test. 2013-06-25 15:49:07 +02:00
antirez 73d7955c6f Flush the replication script cache after SCRIPT FLUSH. 2013-06-25 15:36:48 +02:00
antirez 882e36366f Test: EVALSHA replication. 2013-06-25 15:35:48 +02:00
antirez d1f2d0733c Test: randomInt() behavior commented. 2013-06-25 15:32:37 +02:00
antirez 7e5be50cbf Test: replication-3 test speedup in master-slave setup. 2013-06-25 15:13:14 +02:00
antirez fb67468813 Force propagation of SCRIPT LOAD to AOF. 2013-06-25 12:49:56 +02:00
antirez e27b136069 SCRIPT FLUSH comment minor pedantic improvement. 2013-06-25 10:56:59 +02:00
antirez 82ea1c6f5d Move Replication Script Cache initialization in safer place.
It should be called just one time at startup and not every time the Lua
scripting engine is re-initialized, otherwise memory is leaked.
2013-06-24 19:27:49 +02:00
antirez f0bf5fd8c7 Use the RSC to replicate EVALSHA unmodified.
This commit uses the Replication Script Cache in order to avoid
translating EVALSHA into EVAL whenever possible for both the AOF and
slaves.
2013-06-24 18:57:31 +02:00
antirez 94ec7db470 Replication of scripts as EVALSHA: sha1 caching implemented.
This code is only responsible to take an LRU-evicted fixed length cache
of SHA1 that we are sure all the slaves received.

In this commit only the implementation is provided, but the Redis core
does not use it to actually send EVALSHA to slaves when possible.
2013-06-24 10:26:04 +02:00
antirez 515a26bbc1 New API to force propagation.
The old REDIS_CMD_FORCE_REPLICATION flag was removed from the
implementation of Redis, now there is a new API to force specific
executions of a command to be propagated to AOF / Replication link:

    void forceCommandPropagation(int flags);

The new API is also compatible with Lua scripting, so a script that will
execute commands that are forced to be propagated, will also be
propagated itself accordingly even if no change to data is operated.

As a side effect, this new design fixes the issue with scripts not able
to propagate PUBLISH to slaves (issue #873).
2013-06-21 12:07:53 +02:00
Salvatore Sanfilippo b0c2cdd6a7 Merge pull request #1167 from badboy/patch-1
Initialize char* to NULL to remove compiler warning
2013-06-20 07:56:31 -07:00
Jan-Erik Rediger 5ac7ca9c94 Initialize char* to NULL to remove compiler warning 2013-06-20 17:53:35 +03:00
antirez 519c9e11d1 Allow PUBSUB NUMSUB without channels.
The result is an empty list but it is handy to call it programmatically.
2013-06-20 15:34:56 +02:00
antirez 455563faec PUBSUB command implemented.
Currently it implements three subcommands:

PUBSUB CHANNELS [<pattern>]    List channels with non-zero subscribers.
PUBSUB NUMSUB [channel_1 ...]  List number of subscribers for channels.
PUBSUB NUMPAT                  Return number of subscribed patterns.
2013-06-20 15:32:00 +02:00
antirez 4c0f8c4e5a Sentinel: parse new INFO replication output correctly.
Sentinel was not able to detect slaves when connected to a very recent
version of Redis master since a previos non-backward compatible change
to INFO broken the parsing of the slaves ip:port INFO output.

This fixes issue #1164
2013-06-20 10:23:23 +02:00
antirez b02bb47e67 Test: regression test for #1163. 2013-06-19 18:53:07 +02:00
antirez f8ba3b5668 Fix comment typo in integration/aof.tcl. 2013-06-19 18:31:33 +02:00
antirez d363299af3 Allow writes from scripts called by AOF loading in read-only slaves.
This fixes issue #1163
2013-06-19 18:25:03 +02:00
antirez 338cd4835d Fix logStackTrace() when logging to stdout.
When the semantics changed from logfile = NULL to logfile = "" to log
into standard output, no proper change was made to logStackTrace() to
make it able to work with the new setup.

This commit fixes the issue.
2013-06-19 14:44:40 +02:00
antirez 9c2c878e45 Lua script errors format more unified.
lua_pcall error handler now formats errors in a way more similar to
luaPushError() so that errors generated in different contexts look alike.
2013-06-18 19:30:56 +02:00
antirez 51adc6e1bc Lua scripting: improve error reporting.
When calling Lua scripts we try to report not just the error but
information about the code line causing the error.
2013-06-18 17:33:35 +02:00
Salvatore Sanfilippo b96ba52cfa Merge pull request #1124 from ioddly/fix-issue-1121
Try to report source of bad Lua API calls
2013-06-17 03:14:31 -07:00
Salvatore Sanfilippo 82d782d3b5 Merge pull request #819 from Keruspe/unstable
test-server: only listen to 127.0.0.1
2013-06-17 03:08:14 -07:00
Marc-Antoine Perennou edd7eb9b7d test-server: only listen to 127.0.0.1
Signed-off-by: Marc-Antoine Perennou <Marc-Antoine@Perennou.com>
2013-06-12 22:49:32 +02:00
antirez dfc98dccf4 Cluster: detect nodes address change. 2013-06-12 10:50:07 -07:00
antirez d427373f01 clusterProcessPacket() comments improved for correctness. 2013-06-11 21:34:34 +02:00
antirez cf71b82111 Binary safe dump of object content in redisLogObjectDebugInfo(). 2013-06-04 15:53:53 +02:00
antirez b6a2878aa5 CONFIG SET: accept slave-priority zero, it is valid. 2013-05-31 19:31:36 +02:00
antirez ca35de1d1f Test: avoid a false positive in min-slaves test. 2013-05-31 11:43:30 +02:00
antirez 434a86dbd8 Tests added for min-slaves feature. 2013-05-30 18:54:28 +02:00
antirez 915c06a96c Refresh good slaves count after CONFIG SET min-slaves-...
This way just after the CONFIG SET enabling the min-slaves feature it is
possible to write to the database without delays.
2013-05-30 12:23:41 +02:00
antirez 88441bf18f New INFO field "min_slaves_good_slaves".
When min-slaves-to-write feature is active, this field reports the
number of slaves considered good (online state, lag within the specified
range).
2013-05-30 12:18:31 +02:00
antirez 1a54d5963e Refresh good slaves count when setting slave state as online. 2013-05-30 12:13:25 +02:00
antirez d64d2e21c9 Make tests compatible with new INFO replication output. 2013-05-30 11:43:43 +02:00
antirez 2ec7875cbf min-replicas-to-write: only deny write commands.
I guess I needed another coffee...
2013-05-30 11:30:09 +02:00
antirez ed599d3aca min-slaves-to-write: don't accept writes with less than N replicas.
This feature allows the user to specify the minimum number of
connected replicas having a lag less or equal than the specified
amount of seconds for writes to be accepted.
2013-05-30 11:30:04 +02:00
antirez cbdb2153c5 min-slaves-to-write: initial description of the feature in redis.conf 2013-05-30 11:29:58 +02:00
antirez 888400ebd5 repl_offset field in INFO replication is now just offset. 2013-05-29 19:56:33 +02:00
antirez 37c29e037b Slaves list in INFO output: lag added, format changed.
There is a new 'lag' information in the list of slaves, in the
"replication" section of the INFO output.

Also the format was changed in a backward incompatible way in order to
make it more easy to parse if new fields are added in the future, as the
new format is comma separated but has named fields (no longer positional
fields).
2013-05-29 19:54:44 +02:00
antirez 091ed386f7 Accept REPLCONF in any state. 2013-05-28 15:26:20 +02:00
antirez a864cae2a5 A comment about BLPOP timeout did not reflected actual behavior. 2013-05-27 19:34:14 +02:00
antirez 1909b8753d Version bumped to 2.9.11 2013-05-27 11:44:04 +02:00
antirez c9b55a29d6 redis.conf updated: repl-timeout now uesd by masters as well. 2013-05-27 11:42:45 +02:00
antirez 3c82c85fcf Close connection with timedout slaves.
Now masters, using the time at which the last REPLCONF ACK was received,
are able to explicitly disconnect slaves that are no longer responding.

Previously the only chance was to see a very long output buffer, that
was highly suboptimal.
2013-05-27 11:42:42 +02:00
antirez e06a560466 Send ACK to master once every second.
ACKs can be also used as a base for synchronous replication. However in
that case they'll be explicitly requested by the master when the client
sends a request that needs to be replicated synchronously.
2013-05-27 11:42:38 +02:00
antirez efd87031d0 Don't ACK the master after every command.
Sending an ACK is now moved into the replicationSendAck() function.
2013-05-27 11:42:35 +02:00
antirez dd0adbb777 Make sure that REPLCONF ACK really has no return value. 2013-05-27 11:42:30 +02:00
antirez 0292c5f7ae Replication: send REPLCONF ACK to master. 2013-05-27 11:42:25 +02:00
antirez 6b4635f4f5 REPLCONF ACK command.
This special command is used by the slave to inform the master the
amount of replication stream it currently consumed.

it does not return anything so that we not need to consume additional
bandwidth needed by the master to reply something.

The master can do a number of things knowing the amount of stream
processed, such as understanding the "lag" in bytes of the slave, verify
if a given command was already processed by the slave, and so forth.
2013-05-27 11:42:17 +02:00
antirez a950f48906 Fixed a bug in no queueing replies to master. 2013-05-25 01:00:07 +02:00
antirez dd937030f0 Replication: don't even queue replies to master commands.
When master send commands, there is no need for the slave to reply.
Redis used to queue the reply in the output buffer and discard the reply
later, this is a waste of work and it is not clear why it was this way
(I sincerely don't remember).

This commit changes it in order to don't queue the reply at all.

All tests passing.
2013-05-24 18:58:57 +02:00
antirez c853239a5e Top comment for prepareClientToWrite() clarified.
We don't write the output buffer to the client socket for slaves only if
the slave is not online.
2013-05-24 18:41:43 +02:00
ioddly c3229c33b1 Try to report source of bad Lua API calls 2013-05-22 18:17:58 -05:00
antirez 5d0f408d42 Don't stop reading redis.conf if line has no args.
Should be "continue" and was "return".

This fixes issue #1110
2013-05-18 16:21:52 +02:00
YAMAMOTO Takashi 9fcead7a59 don't assume time_t == long
time_t is always 64bit on recent versions of NetBSD.
2013-05-17 17:22:39 +09:00
YAMAMOTO Takashi ae82867664 use nanosleep instead of usleep
SUSv3 says that:
	The useconds argument shall be less than one million. If the value of
	useconds is 0, then the call has no effect.
and actually NetBSD's implementation rejects such a value with EINVAL.
use nanosleep which has no such a limitation instead.
2013-05-17 17:21:28 +09:00
YAMAMOTO Takashi b2dd0849ce rename popcount to popcount_binary to avoid a conflict with NetBSD libc
NetBSD-current's libc has a function named popcount.
hiding these extensions using feature macros is not possible because
redis uses other extensions covered by the same feature macro.
eg. inet_aton
2013-05-17 17:21:28 +09:00
YAMAMOTO Takashi 0a20ad40de don't define _XOPEN_SOURCE for NetBSD
on NetBSD, defining _XOPEN_SOURCE hides extensions
like inet_aton, strcasecmp, etc.
2013-05-17 17:19:02 +09:00
antirez 92f18d04a0 Merge branch 'config-rewrite' into unstable 2013-05-15 11:58:21 +02:00
antirez 78167807be Use memtoll() when parsing the backlog-size option. 2013-05-15 11:55:14 +02:00
antirez 25f2be6267 CONFIG REWRITE: backlog size is a bytes option. 2013-05-15 11:39:29 +02:00
antirez cd48e4fc40 CONFIG REWRITE: bindaddr -> bind. 2013-05-15 11:38:43 +02:00
antirez 8a44e6c490 CONFIG REWRITE: when rewriting amount of bytes use GB, MB, KB if possible. 2013-05-15 11:33:02 +02:00
antirez c590e18d15 CONFIG REWRITE: correctly escape the notify-keyspace-events option. 2013-05-15 11:15:31 +02:00
antirez 328843849f CONFIG REWRITE: "active-rehashing" -> "activerehashing". 2013-05-15 11:09:19 +02:00
antirez 402a0f1ca0 CONFIG REWRITE: fixed typo in AOF fsync policy. 2013-05-15 11:06:56 +02:00
antirez 72e980231c CONFIG REWRITE: repl-disable-tcp-nodelay is a boolean option. 2013-05-15 11:04:53 +02:00
antirez 86a6aad984 Test default config modified to set logfile to empty string.
Required because of recent changes in the way logfile is set to standard
output.
2013-05-15 10:19:14 +02:00
antirez 310dbba01c Added a define for most configuration defaults.
Also the logfile option was modified to always have an explicit value
and to log to stdout when an empty string is used as log file.

Previously there was special handling of the string "stdout" that set
the logfile to NULL, this always required some special handling.
2013-05-15 10:12:29 +02:00
antirez 9e74d216e1 CONFIG REWRITE: Use sane perms when creating redis.conf from scratch. 2013-05-14 12:45:04 +02:00
antirez e252045454 CONFIG REWRITE: actually rewrite the config file, atomically. 2013-05-14 12:32:25 +02:00
antirez 25e049cc68 redis-cli: help.h updated. 2013-05-14 11:23:16 +02:00
antirez 78f94d90eb CONFIG REWRITE: remove orphaned lines. 2013-05-14 11:17:18 +02:00
antirez ee721f1e5c CONFIG REWRITE: strip multiple empty lines. 2013-05-14 10:22:55 +02:00
antirez c184f36d21 CONFIG REWRITE: support for client-output-buffer-limit. 2013-05-13 18:34:18 +02:00
antirez d95592b116 CONFIG REWRITE: support for dir and slaveof. 2013-05-13 11:26:49 +02:00
antirez 2bc31e55ee CONFIG REWRITE: support for save and syslog-facility. 2013-05-13 11:11:45 +02:00
antirez 7e049fafd3 CONFIG REWRITE: Initial support code and design. 2013-05-13 11:11:12 +02:00
antirez 5947f170f9 Obtain absoute path of configuration file, expose it in INFO. 2013-05-09 16:57:59 +02:00
antirez e938575220 Test: more PSYNC tests (backlog TTL). 2013-05-09 12:52:04 +02:00
antirez a7486a6592 Version bumped to 2.9.10 2013-05-08 15:24:40 +02:00
antirez 16f2c3ea14 Test: check that replication partial sync works if we break the link.
The test checks both successful syncs and unsuccessful ones by changing
the backlog size.
2013-05-08 13:01:44 +02:00
antirez c87dd0fe49 Test: various issues with the replication-4.tcl test fixed.
The test actually worked, but vars for master and slave were inverted
and sometimes used incorrectly.
2013-05-08 11:58:26 +02:00
antirez 0ae1b5b0a1 Revert "use long long instead of size_t make it more safe"
This reverts commit 2c75f2cf1a.

After further analysis, it is very unlikely that we'll raise the
string size limit to > 512MB, and at the same time such big strings
will be used in 32 bit systems.

Better to revert to size_t so that 32 bit processors will not be
forced to use a 64 bit counter in normal operations, that is currently
completely useless.
2013-05-08 10:01:27 +02:00
Salvatore Sanfilippo c1ae7d2377 Merge pull request #1093 from july2993/unstable
in 32bit machine, popcount don't work with a input string length up to 5...
2013-05-08 00:49:33 -07:00
antirez 5885a34b67 Added more info about 32 bit builds into README. 2013-05-08 09:48:38 +02:00
Jiahao Huang 2c75f2cf1a use long long instead of size_t make it more safe 2013-05-07 23:37:22 +08:00
Jiahao Huang e3ed78d43b in 32bit machine, popcount don't work with a input string length up to 512 MB,
bitcount commant may return negtive integer with string length more than 256 MB
2013-05-07 19:55:57 +08:00
antirez 5c9f6d4f55 Cluster: link reconnection on delayed PONG reply.
When the PONG delay is half the cluster node timeout, the link gets
disconnected (and later automatically reconnected) in order to ensure
that it's not just a dead connection issue.

However this operation is only performed if the link is old enough, in
order to avoid to disconnect the same link again and again (and among
the other problems, never receive the PONG because of that).

Note: when the link is reconnected, the 'ping_sent' field is not updated
even if a new ping is sent using the new connection, so we can still
reliably detect a node ping timeout.
2013-05-03 15:43:03 +02:00
antirez 1315b9f246 Cluster: restore PING sent time on reconnections. 2013-05-03 15:42:59 +02:00
antirez ae71731019 Cluster: PING/PONG handling redesigned. 2013-05-03 15:42:38 +02:00
antirez a120560f70 Cluster: process config from PING packets as we do for PONG.
Also clusterBroadcastPing() was renamed into clusterBroadcastPong()
that's what the function is actually doing.
2013-05-03 15:41:34 +02:00
antirez 8a51c067ad Cluster: createClusterLink() comment fixed for grammar. 2013-05-03 15:41:29 +02:00
antirez 0d9c1f536b CONFIG SET server.masterauth aesthetic change.
This is just to make the code exactly like the above instance used for
requirepass. No actual change nor the original code violated the Redis
coding style.
2013-05-02 17:20:49 +02:00
Michel Martens 649b304e0f Reset masterauth if an empty string is configured. 2013-05-02 17:19:11 +02:00
charsyam 9cd06e4406 Fix AOF bug: expire could be removed from key on AOF rewrite.
There was a race condition in the AOF rewrite code that, with bad enough
timing, could cause a volatile key just about to expire to be turned
into a non-volatile key. The bug was never reported to cause actualy
issues, but was found analytically by an user in the Redis mailing list:

https://groups.google.com/forum/?fromgroups=#!topic/redis-db/Kvh2FAGK4Uk

This commit fixes issue #1079.
2013-05-02 15:35:59 +02:00
antirez e5ef85c444 Sentinel: changes to tilt mode.
Tilt mode was too aggressive (not processing INFO output), this
resulted in a few problems:

1) Redirections were not followed when in tilt mode. This opened a
   window to misinform clients about the current master when a Sentinel
   was in tilt mode and a fail over happened during the time it was not
   able to update the state.

2) It was possible for a Sentinel exiting tilt mode to detect a false
   fail over start, if a slave rebooted with a wrong configuration
   about at the same time. This used to happen since in tilt mode we
   lose the information that the runid changed (reboot).

   Now instead the Sentinel in tilt mode will still remove the instance
   from the list of slaves if it changes state AND runid at the same
   time.

Both are edge conditions but the changes should overall improve the
reliability of Sentinel.
2013-04-30 15:08:29 +02:00
antirez ef05a78e7e Sentinel: more sensible delay in master demote after tilt. 2013-04-30 15:08:22 +02:00
antirez 214adc5051 Lua updated to version 5.1.5. 2013-04-29 12:00:54 +02:00
antirez 48ede0d84d Sentinel: only demote old master into slave under certain conditions.
We used to always turn a master into a slave if the DEMOTE flag was set,
as this was a resurrecting master instance.

However the following race condition is possible for a Sentinel that
got partitioned or internal issues (tilt mode), and was not able to
refresh the state in the meantime:

1) Sentinel X is running, master is instance "A".
3) "A" fails, sentinels will promote slave "B" as master.
2) Sentinel X goes down because of a network partition.
4) "A" returns available, Sentinels will demote it as a slave.
5) "B" fails, other Sentinels will promote slave "A" as master.
6) At this point Sentinel X comes back.

When "X" comes back he thinks that:

"B" is the master.
"A" is the slave to demote.

We want to avoid that Sentinel "X" will demote "A" into a slave.
We also want that Sentinel "X" will detect that the conditions changed
and will reconfigure itself to monitor the right master.

There are two main ways for the Sentinel to reconfigure itself after
this event:

1) If "B" is reachable and already configured as a slave by other
sentinels, "X" will perform a redirection to "A".
2) If there are not the conditions to demote "A", the fact that "A"
reports to be a master will trigger a failover detection in "X", that
will end into a reconfiguraiton to monitor "A".

However if the Sentinel was not reachable, its state may not be updated,
so in case it titled, or was partiitoned from the master instance of the
slave to demote, the new implementation waits some time (enough to
guarantee we can detect the new INFO, and new DOWN conditions).

If after some time still there are not the right condiitons to demote
the instance, the DEMOTE flag is cleared.
2013-04-26 17:02:13 +02:00
antirez 1965e22aa1 Sentinel: always redirect on master->slave transition.
Sentinel redirected to the master if the instance changed runid or it
was the first time we got INFO, and a role change was detected from
master to slave.

While this is a good idea in case of slave->master, since otherwise we
could detect a failover without good reasons just after a reboot with a
slave with a wrong configuration, in the case of master->slave
transition is much better to always perform the redirection for the
following reasons:

1) A Sentinel may go down for some time. When it is back online there is
no other way to understand there was a failover.
2) Pointing clients to a slave seems to be always the wrong thing to do.
3) There is no good rationale about handling things differently once an
instance is rebooted (runid change) in that case.
2013-04-24 11:30:17 +02:00
antirez d264122f6a Config option to turn AOF rewrite incremental fsync on/off. 2013-04-24 10:57:07 +02:00
antirez 336d722fba AOF: sync data on disk every 32MB when rewriting.
This prevents the kernel from putting too much stuff in the output
buffers, doing too heavy I/O all at once. So the goal of this commit is
to split the disk pressure due to the AOF rewrite process into smaller
spikes.

Please see issue #1019 for more information.
2013-04-24 10:26:31 +02:00
antirez 91f4213ddf rio.c: added ability to fdatasync() from time to time while writing. 2013-04-24 10:26:30 +02:00
antirez c4656119b6 Test: fix RDB test checking file permissions.
When the test is executed using the root account, setting the permission
to 222 does not work as expected, as root can read files with 222
permission.

Now we skip the test if root is detected.

This fixes issue #1034 and the duplicated #1040 issue.

Thanks to Jan-Erik Rediger (@badboy on Github) for finding a way to reproduce the issue.
2013-04-23 14:16:50 +02:00
antirez 4ed2581a92 Test: split conceptually unrelated comments in RDB test. 2013-04-22 11:25:49 +02:00
antirez 8e222c888f Sentinel: turn old master into a slave when it comes back. 2013-04-19 16:47:24 +02:00
antirez 9d823fc222 More explicit panic message on out of memory. 2013-04-19 15:11:34 +02:00
xiaost7 ecdbaf4695 Cluster: fix clusterNode.name print format on debug message.
It was %40s instead of %.40s, and since the string is not null
terminated it caused random garbage to be displayed, and possibly a
crash.
2013-04-19 09:53:43 +02:00
antirez d04afd62d6 Redis/Jemalloc Gitignore were too aggressive.
Redis gitignore was too aggressive since simply broken.

Jemalloc gitignore was too agressive because it is conceived to just
keep the files that allow to generate all the rest in development
environments (so for instance the "configure" file is excluded).
2013-04-18 16:23:15 +02:00
antirez f8ae70cf7c redis-cli: raise error on bad command line switch.
Previously redis-cli never tried to raise an error when an unrecognized
switch was encountered, as everything after the initial options is to be
transmitted to the server.

However this is too liberal, as there are no commands starting with "-".
So the new behavior is to produce an error if there is an unrecognized
switch starting with "-". This should not break past redis-cli usages
but should prevent broken options to be silently discarded.

As far the first token not starting with "-" is encountered, all the
rest is considered to be part of the command, so you cna still use
strings starting with "-" as values, like in:

    redis-cli --port 6380 set foo --my-value
2013-04-11 13:17:25 +02:00
antirez 0280c2f252 redis-cli: --latency-history mode implemented. 2013-04-11 13:11:41 +02:00
antirez b84570dece Cluster: reconfigure additonal slaves on failover. 2013-04-09 12:13:26 +02:00
antirez d1aee359c0 Cluster: CONFIG SET cluster-node-timeout. 2013-04-09 11:29:51 +02:00
antirez 68cf249f81 Cluster: use server.cluster_node_timeout directly.
We used to copy this value into the server.cluster structure, however this
was not necessary.

The reason why we don't directly use server.cluster->node_timeout is
that things that can be configured via redis.conf need to be directly
available in the server structure as server.cluster is allocated later
only if needed in order to reduce the memory footprint of non-cluster
instances.
2013-04-09 11:24:18 +02:00
antirez ef4f25ff6e Cluster: configdigest field no longer used. Removed. 2013-04-09 11:07:25 +02:00
antirez f09b2508f4 Cluster: properly send ping to nodes not pinged foro too much time.
In commit d728ec6 it was introduced the concept of sending a ping to
every node not receiving a ping since node_timeout/2 seconds.
However the code was located in a place that was not executed because of
a previous conditional causing the loop to re-iterate.

This caused false positives in nodes availability detection.

The current code is still not perfect as a node may be detected to be in
PFAIL state even if it does not reply for just node_timeout/2 seconds
that is not correct. There is a plan to improve this code ASAP.
2013-04-08 19:40:20 +02:00
antirez ace86cfaef Test: remove useless statements and comments from test default config. 2013-04-04 14:30:05 +02:00
antirez d5b383477e Cluster: move REDIS_CLUSTER_FAILOVER_DELAY near other timing defines. 2013-04-04 14:23:34 +02:00
antirez 3cc6e7d01d Cluster: CONFIG GET cluster-node-timeout. 2013-04-04 14:21:01 +02:00
antirez 05fa4f4034 Cluster: node timeout is now configurable. 2013-04-04 12:29:10 +02:00
antirez 00bab23c41 Cluster: turn hardcoded node timeout multiplicators into defines.
Most Redis Cluster time limits are expressed in terms of the configured
node timeout. Turn them into defines.
2013-04-04 12:04:11 +02:00
antirez 8419397665 Make rio.c comment 80-columns friendly. 2013-04-03 12:41:14 +02:00
antirez b237de33d1 Throttle BGSAVE attempt on saving error.
When a BGSAVE fails, Redis used to flood itself trying to BGSAVE at
every next cron call, that is either 10 or 100 times per second
depending on configuration and server version.

This commit does not allow a new automatic BGSAVE attempt to be
performed before a few seconds delay (currently 5).

This avoids both the auto-flood problem and filling the disk with
logs at a serious rate.

The five seconds limit, considering a log entry of 200 bytes, will use
less than 4 MB of disk space per day that is reasonable, the sysadmin
should notice before of catastrofic events especially since by default
Redis will stop serving write queries after the first failed BGSAVE.

This fixes issue #849
2013-04-02 14:05:50 +02:00
antirez b14fda7deb Version bumped to 2.9.9. 2013-04-02 11:55:23 +02:00
Salvatore Sanfilippo 63457d1a5d Merge pull request #1017 from jbergstroem/build-improvements
Build improvements
2013-04-02 02:24:52 -07:00
charsyam 86d87e3554 Support for case unsensitive SET options. 2013-03-29 10:33:52 +01:00
antirez dfc31a1ee8 Test: Extended SET tests. 2013-03-28 16:25:24 +01:00
antirez 30d5d416e6 Extended SET command implemented (issue #931). 2013-03-28 15:40:19 +01:00
antirez 140260409e EXPIRE should not resurrect keys. Issue #1026. 2013-03-28 12:45:07 +01:00
antirez 601cea665d Test: regression test for issue #1026. 2013-03-28 11:46:14 +01:00
antirez 3816e7bda9 Better DEBUG error message when num of arguments is wrong. 2013-03-28 11:39:29 +01:00
antirez 1b13adf388 Test: verify that lazy-expire works. 2013-03-28 11:36:49 +01:00
antirez 32a83c8206 DEBUG set-active-expire added.
We need the ability to disable the activeExpireCycle() (active
expired key collection) call for testing purposes.
2013-03-27 17:55:02 +01:00
antirez 252cf3052d Test: test replication of MULTI/EXEC. 2013-03-27 11:44:50 +01:00
antirez 40b692e822 Test: Restore DB back to 9 after testing MULTI/EXEC with DB 5. 2013-03-27 11:30:23 +01:00
antirez 7572dc47da Test: new functions to capture and analyze the replication stream. 2013-03-27 11:29:47 +01:00
antirez 4fa30b781e redis-trib: ClusterNode #info_string output modified.
The hope is that the new one is more readable.
2013-03-26 18:16:03 +01:00
antirez df69155e8a Allow SELECT while loading the DB.
Fixes issue #1024.
2013-03-26 13:51:17 +01:00
antirez 873f328fd8 TTL / PTTL commands: two bugs fixed.
This commit fixes two corner cases for the TTL command.

1) When the key was already logically expired (expire time older
than current time) the command returned -1 instead of -2.

2) When the key was existing and the expire was found to be exactly 0
(the key was just about to expire), the command reported -1 (that is, no
expire) instead of a TTL of zero (that is, about to expire).
2013-03-26 11:45:22 +01:00
antirez 8bb5eb7357 Flag PUBLISH as read-only in the command table. 2013-03-26 11:09:22 +01:00
antirez 71f3e74317 Transactions: propagate MULTI/EXEC only when needed.
MULTI/EXEC is now propagated to the AOF / Slaves only once we encounter
the first command that is not a read-only one inside the transaction.

The old behavior was to always propagate an empty MULTI/EXEC block when
the transaction was composed just of read only commands, or even
completely empty. This created two problems:

1) It's a bandwidth waste in the replication link and a space waste
   inside the AOF file.

2) We used to always increment server.dirty to force the propagation of
   the EXEC command, resulting into triggering RDB saves more often
   than needed.

Note: even read-only commands may also trigger writes that will be
propagated, when we access a key that is found expired and Redis will
synthesize a DEL operation. However there is no need for this to stay
inside the transaction itself, but only to be ordered.

So for instance something like:

    MULTI
    GET foo
    SET key zap
    EXEC

May be propagated into:

    DEL foo
    MULTI
    SET key zap
    EXEC

While the DEL is outside the transaction, the commands are delivered in
the right order and it is not possible for other commands to be inserted
between DEL and MULTI.
2013-03-26 10:58:10 +01:00
antirez 02c269e27e Transactions: use discardTransaction() in EXEC implementation. 2013-03-26 10:48:15 +01:00
antirez 2f49734029 Transactions: use the propagate() API to propagate MULTI.
The behavior is the same, but the code is now cleaner and uses the
proper interface instead of dealing directly with AOF/replication
functions.
2013-03-26 10:27:45 +01:00
Salvatore Sanfilippo afce010639 Merge pull request #1003 from NanXiao/patch-3
Update config.c
2013-03-25 11:30:59 -07:00
antirez c39e34d007 Cluster: when slave changes master, remove it from the old master. 2013-03-25 15:01:25 +01:00
antirez 70091a2f63 redis-trib: wait cluster join after cluster creation. 2013-03-25 13:14:17 +01:00
antirez 34c1871e9f Cluster: set node role on successful handshake. 2013-03-25 13:03:01 +01:00
antirez cda0cdfb70 redis-trib: Don't use colorization if TERM != xterm. 2013-03-25 12:51:53 +01:00
antirez 4286d8b979 redis-trib: initial output colorization 2013-03-25 12:50:38 +01:00
antirez 797d98e906 Test: obuf-limits test false positive removed.
Fixes #621.
2013-03-25 11:56:34 +01:00
antirez 09aa55a334 redis-cli --stat, stolen from redis-tools.
Redis-tools is a connection of tools no longer mantained that was
intented as a way to economically make sense of Redis in the pre-vmware
sponsorship era. However there was a nice redis-stat utility, this
commit imports one of the functionalities of this tool here in redis-cli
as it seems to be pretty useful.

Usage: redis-cli --stat

The output is similar to vmstat in the format, but with Redis specific
stuff of course.

From the point of view of the monitored instance, only INFO is used in
order to grab data.
2013-03-22 17:54:32 +01:00
antirez c195289e5e redis-trib: All output wrapped by a specific function.
This is needed in order to colorize it as next step.
We use conventions in output messages such as

>>> This is an action
*** This is a warning
[ERR] This is an error
[OK] That's fine

And so forth, so that a color will be associated checking the first
three chars.
2013-03-22 17:39:43 +01:00
antirez be7bdd376e redis-trib: fix open slot correction.
Slot zero was hardcoded (!)
2013-03-22 13:03:33 +01:00
antirez 813d7cbdd1 redis-trib: added cluster_error method to add errors. 2013-03-22 12:59:18 +01:00
antirez d7eae8d8d7 redis-trib: fixed ClusterNode migrating/importing slots detection. 2013-03-22 12:54:04 +01:00
antirez 1baa153028 redis-trib: added some more output for check. 2013-03-22 12:47:49 +01:00
antirez 77bba91b48 redis-trib: fixed type has_flags? -> has_flag. 2013-03-22 12:28:06 +01:00
antirez 4dded0c187 redis-trib: ignore slaves when resharding. 2013-03-21 18:17:06 +01:00
antirez 47da76576e redis-trib: fix conditional otherwise always true. 2013-03-21 17:22:14 +01:00
antirez a89d435d8e Cluster: move slotToKeyFlush() to emptyDb().
This way we are sure to destroy the slot->key map every time we destroy
the DB, for instance when reloading a DB due to replication.
2013-03-21 17:13:08 +01:00
antirez ed47f77977 redis-trib: initial support to fix "open" slots.
Open slots are slots found in importing or migrating slot when a
cluster check is performed.
2013-03-21 17:11:54 +01:00
antirez 1a6df1049d redis-trib: load info about importing/migrating slots from node. 2013-03-21 16:31:53 +01:00
antirez a8b09faf3d Cluster: comment no longer in sync with code removed. 2013-03-21 10:47:10 +01:00
Johan Bergström 8080e1cfbe use install as default installer (except on SunOS) 2013-03-21 13:32:08 +11:00
antirez 8c1bc8e865 Cluster: clear the PROMOTED slave directly into clusterSetMaster().
This way we make sure every time a master is turned into a replica
the flag will be cleared.
2013-03-20 11:51:44 +01:00
antirez e006407fd0 Cluster: master node must clear its hash slots when turning into a slave.
When a master turns into a slave after a failover event, make sure to
clear the assigned slots before setting up the replication, as a slave
should never claim slots in an explicit way, but just take over the
master slots when replacing its master.
2013-03-20 11:32:35 +01:00
antirez 506f9a42b0 Cluster: new flag PROMOTED introduced.
A slave node set this flag for itself when, after receiving authorization
from the majority of nodes, it turns itself into a master.

At the same time now this flag is tested by nodes receiving a PING
message before reconfiguring after a failover event. This makes the
system more robust: even if currently there is no way to manually turn
a slave into a master it is possible that we'll have such a feature in
the future, or that simply because of misconfiguration a node joins the
cluster as master while others believe it's a slave. This alone is now
no longer enough to trigger reconfiguration as other nodes will check
for the PROMOTED flag.

The PROMOTED flag is cleared every time the node is turned back into a
replica of some other node.
2013-03-20 10:48:42 +01:00
antirez 026b9483db Cluster: add sender flags in cluster bus messages header.
Sender flags were not propagated for the sender, but only for nodes in
the gossip section. This is odd and in the next commits we'll need to
get updated flags for the sender node, so this commit adds a new field
in the cluster messages header.

The message header is the same size as we reused some free space that
was marked as 'unused' because of alignment concerns.
2013-03-20 10:32:00 +01:00
antirez d15b027d91 Cluster: turn old master into a replica of node that failed over.
So when the failing master node is back in touch with the cluster,
instead of remaining unused it is converted into a replica of the
new master, ready to perform the fail over if the new master node
will fail at some point.

Note that as a side effect clients with stale configuration are now
not an issue as well, as the node converted into a slave will not
accept queries but will redirect clients accordingly.
2013-03-20 00:30:47 +01:00
antirez 4d62623015 Cluster: node replication role change handle improved.
The code handling a master that turns into a slave or the contrary was
improved in order to avoid repeating the same operations. Also
the readability and conceptual simplicity was improved.
2013-03-19 16:01:30 +01:00
antirez 88221f88c0 Cluster: new command CLUSTER FLUSHSLOTS.
It's just a simpler way to CLUSTER DELSLOTS with all the slots as
arguments, in order to obtain a node without assigned slots for
reconfiguration.
2013-03-19 09:58:05 +01:00
antirez 7d3e32d526 redis-trib: don't load cluster config from nodes in FAIL state. 2013-03-19 09:46:12 +01:00
Johan Bergström dc4003be71 Silence mkdir output 2013-03-17 18:37:38 +11:00
Johan Bergström 348be19b5f Only pass -rdynamic as linker option 2013-03-17 17:49:57 +11:00
Johan Bergström 33a4bc2c70 Remove extra spaces 2013-03-17 17:23:45 +11:00
Johan Bergström 978c895b69 make check is a common naming convention for tests 2013-03-16 18:40:22 +11:00
Johan Bergström a66195629b Inherit CC for Lua 2013-03-16 18:38:37 +11:00
Johan Bergström ada7aa7ac9 Spaces to tabs 2013-03-16 18:35:20 +11:00
Johan Bergström bea60bec75 Slightly refactor CFLAGS/LDFLAGS/LIBS
This way, we can avoid -rdynamic and -pthread warnings on darwin.
2013-03-16 18:33:42 +11:00
antirez e28e61e839 Cluster: when failing over claim master slots. 2013-03-15 16:53:41 +01:00
antirez b8127e337a Version incremented to 2.9.8 after major cluster progresses. 2013-03-15 16:45:45 +01:00
antirez dd091661d4 Cluster: log when a slave asks for failover authorization. 2013-03-15 16:44:08 +01:00
antirez 1375b0611b Cluster: slaves start failover with a small delay.
Redis Cluster can cope with a minority of nodes not informed about the
failure of a master in time for some reason (netsplit or node not
functioning properly, blocked, ...) however to wait a few seconds before
to start the failover will make most "normal" failovers simpler as the
FAIL message will propagate before the slave election happens.
2013-03-15 16:39:49 +01:00
antirez d512a09c20 Cluster: a bit more serious node role change handling. 2013-03-15 16:35:16 +01:00
antirez 004fbef847 Cluster: remove node from master slaves when it turns into a master.
Also, a few nearby comments improved.
2013-03-15 16:16:19 +01:00
antirez 44c92f5aeb Cluster: slave failover implemented. 2013-03-15 16:11:34 +01:00
antirez 1d8f302e0d Cluster: election -> promotion in two comments. 2013-03-15 15:44:49 +01:00
antirez bf82195467 Cluster: added function to broadcast pings.
See the function top-comment for info why this is useful sometimes.
2013-03-15 15:43:58 +01:00
antirez 892e98548a Cluster: don't broadcast messages to HANDSHAKE nodes.
Also don't check for NOADDR as we check that node->link is not NULL
that's enough.
2013-03-15 15:36:36 +01:00
antirez 76a3954f4a Cluster: fix clusterHandleSlaveFailover() conditional: quorum is enough. 2013-03-15 13:20:34 +01:00
antirez 90e99a2082 Cluster: two lame bugs fixed in FAILOVER AUTH messages generation. 2013-03-14 21:27:12 +01:00
antirez aeacaa57e6 Cluster: code to process messages moved in the right if-else chain. 2013-03-14 21:21:58 +01:00
antirez 35f05c66b6 Cluster: handle FAILOVER_AUTH_ACK messages.
That's trivial as we just need to increment the count of masters that
received with an ACK.
2013-03-14 16:43:13 +01:00
antirez c2595500ac Cluster: request failover authorization, log if we have quorum.
However the failover is yet not really performed.
2013-03-14 16:39:02 +01:00
antirez 7fa42b801d Cluster: clusterSendFailoverAuth() implementation. 2013-03-14 16:31:57 +01:00
NanXiao 79a13b46fb Update config.c
Fix bug in configGetCommand function: get correct masterauth value.
2013-03-14 13:52:43 +08:00
antirez f59ff6fe61 Cluster: clusterSendFailoverAuthIfNeeded() work in progress. 2013-03-13 19:08:03 +01:00
antirez 44f6fdab60 Cluster: handle FAILOVER_AUTH_REQUEST in clusterProcessPacket().
However currently the control is passed to a function doing nothing at
all.
2013-03-13 18:38:08 +01:00
antirez ece95b2dea Cluster: sanity check FAILOVER_AUTH_REQUEST messages for proper length. 2013-03-13 17:31:26 +01:00
antirez 66144337bf Cluster: use 'else if' for mutually exclusive conditionals. 2013-03-13 17:27:06 +01:00
antirez db7c17e969 Cluster: FAILOVER_AUTH_REQUEST message type introduced.
This message is sent by a slave that is ready to failover its master to
other nodes to get the authorization from the majority of masters.
2013-03-13 17:21:20 +01:00
antirez 575cbc9990 Cluster: clusterHandleSlaveFailover() stub. 2013-03-13 13:10:49 +01:00
antirez 1902a9c532 Replication: master_link_down_since_seconds initial value should be huge.
server.repl_down_since used to be initialized to the current time at
startup. This is wrong since the replication never started. Clients
testing this filed to check if data is uptodate should never believe
data is recent if we never ever connected to our master.
2013-03-13 12:54:48 +01:00
antirez 3d448bda39 Cluster: call clusterHandleSlaveFailover() when our master is down. 2013-03-13 12:44:02 +01:00
antirez ae94fe7e48 Test: make sure broken RDB checksum is detected. 2013-03-13 11:12:45 +01:00
antirez 82b0eae690 Test: more RDB loading checks.
A test for issue #1001 is included.
2013-03-13 10:04:33 +01:00
antirez 0b74a85678 Test: check that Redis starts empty without an RDB file. 2013-03-12 19:55:33 +01:00
antirez 79a6844e44 rdbLoad(): rework code to save vertical space. 2013-03-12 19:46:33 +01:00
Salvatore Sanfilippo 9925c7c670 Merge pull request #1001 from djanowski/fatal-errors-rdb-load
Abort when opening the RDB file results in an error other than ENOENT.
2013-03-12 11:40:36 -07:00
Damian Janowski 4178a80282 Abort when opening the RDB file results in an error other than ENOENT.
This fixes cases where the RDB file does exist but can't be accessed for
any reason. For instance, when the Redis process doesn't have enough
permissions on the file.
2013-03-12 14:37:50 -03:00
antirez 215bfaea16 Set default for stop_writes_on_bgsave_err in initServerConfig().
It was placed for error in initServer() that's called after the
configuation is already loaded, causing issue #1000.
2013-03-12 18:34:08 +01:00
antirez 91d3b487e7 redis-cli --bigkeys: don't crash with empty DBs. 2013-03-12 09:58:00 +01:00
antirez 2d851333a6 activeExpireCycle() smarter with many DBs and under expire pressure.
activeExpireCycle() tries to test just a few DBs per iteration so that
it scales if there are many configured DBs in the Redis instance.
However this commit makes it a bit smarter when one a few of those DBs
are under expiration pressure and there are many many keys to expire.

What we do is to remember if in the last iteration had to return because
we ran out of time. In that case the next iteration we'll test all the
configured DBs so that we are sure we'll test again the DB under
pressure.

Before of this commit after some mass-expire in a given DB the function
tested just a few of the next DBs, possibly empty, a few per iteration,
so it took a long time for the function to reach again the DB under
pressure. This resulted in a lot of memory being used by already expired
keys and never accessed by clients.
2013-03-11 11:10:33 +01:00
antirez 08b107e405 In databasesCron() never test more DBs than we have. 2013-03-11 10:51:03 +01:00
antirez 4b1ccdfd49 Make comment name match var name in activeExpireCycle(). 2013-03-11 10:42:14 +01:00
antirez 1f7d2c1e27 Optimize inner loop of activeExpireCycle() for no-expires case. 2013-03-09 11:48:54 +01:00
antirez 5f5aa487f9 REDIS_DBCRON_DBS_PER_SEC -> REDIS_DBCRON_DBS_PER_CALL 2013-03-09 11:44:20 +01:00
antirez db29d71a30 activeExpireCycle(): process only a small number of DBs per iteration.
This small number of DBs is set to 16 so actually in the default
configuraiton Redis should behave exactly like in the past.
However the difference is that when the user configures a very large
number of DBs we don't do an O(N) operation, consuming a non trivial
amount of CPU per serverCron() iteration.
2013-03-08 17:48:58 +01:00
antirez 40a2da159c Use unsigned integers for DB ids, for defined wrap-to-zero. 2013-03-08 17:41:20 +01:00
antirez 7ac3b3a486 Only resize/rehash a few databases per cron iteration.
This is the first step to lower the CPU usage when many databases are
configured. The other is to also process a limited number of DBs per
call in the active expire cycle.
2013-03-08 14:01:12 +01:00
antirez dfd732dff3 Actually call databasesCron() inside serverCron(). 2013-03-08 13:59:50 +01:00
antirez cd9dcd1835 Move Redis databases background processing to databasesCron(). 2013-03-08 12:34:05 +01:00
antirez f0b807cd47 Cluster: update cluster state on PFAIL flag set/cleared on nodes. 2013-03-07 15:40:53 +01:00
antirez 299b8f76c2 Cluster: mark cluster state as fail of majority of masters is unreachable. 2013-03-07 15:36:59 +01:00
antirez abf06fd5ff Cluster: log global cluster state change. 2013-03-07 15:22:32 +01:00
antirez 3dad8196b7 Cluster: clusterUpdateState() function simplified.
Also the NEEDHELP Cluster state was removed as it will no longer be
used by Redis Cluster.
2013-03-06 18:25:40 +01:00
Gengliang Wang 042ed270c8 Removed useless "return" statements in pubsub.c
(original commit message edited)
2013-03-06 16:49:20 +01:00
antirez 7b190a08cf API to lookup commands with their original name.
A new server.orig_commands table was added to the server structure, this
contains a copy of the commant table unaffected by rename-command
statements in redis.conf.

A new API lookupCommandOrOriginal() was added that checks both tables,
new first, old later, so that rewriteClientCommandVector() and friends
can lookup commands with their new or original name in order to fix the
client->cmd pointer when the argument vector is renamed.

This fixes the segfault of issue #986, but does not fix a wider range of
problems resulting from renaming commands that actually operate on data
and are registered into the AOF file or propagated to slaves... That is
command renaming should be handled with care.
2013-03-06 16:28:26 +01:00
antirez 4d62912619 Add a warning about command renaming in redis.conf. 2013-03-06 15:47:16 +01:00
antirez bfa25441e7 Handle a non-impossible empty argv in loadServerConfigFromString().
Usually this does not happens since we trim for " \t\r\n", but if there
are other chars that return true with isspace(), we may end with an
empty argv. Better to handle the condition in an explicit way.
2013-03-06 12:40:48 +01:00
antirez 8c193af696 redis-cli: use sdsfreesplitres() instead of hand-coding it. 2013-03-06 12:38:32 +01:00
antirez 011fa89ac9 Cluster: sdssplitargs_free() -> sdsfreesplitres(). 2013-03-06 12:38:06 +01:00
antirez 729a3432ba sds.c: sdssplitargs_free() removed as it was a duplicate. 2013-03-06 12:38:06 +01:00
antirez cf4d7737bb More specific error message in loadServerConfigFromString(). 2013-03-06 12:24:12 +01:00
antirez 4ea89e64c0 sdssplitargs(): on error set *argc to 0.
This makes programs not checking the return value for NULL much safer
since with this change:

1) It is still possible to iterate the zero-length result without
crashes.
2) sdssplitargs_free will work against NULL and 0 count.
2013-03-06 12:21:31 +01:00
antirez 5cabae84e6 sdssplitargs(): now returns NULL only on error.
An empty input string also resulted into the function returning NULL
making it harder for the caller to distinguish between error and empty
string without checking the original input string length.
2013-03-06 12:21:21 +01:00
charsyam 1303f02be6 Don't segfault on unbalanced quotes. 2013-03-06 11:54:02 +01:00
antirez 304ef5e283 Allow AUTH while loading the DB in memory.
While Redis is loading the AOF or RDB file in memory only a subset of
commands are allowed. This commit adds AUTH to this subset.
2013-03-06 11:50:38 +01:00
antirez 1025dd7786 Cluster: connect to our master ASAP after startup if we are a slave node. 2013-03-05 16:12:08 +01:00
antirez bac57ad14b Cluster: more robust FAIL flag cleaup.
If we have a master in FAIL state that's reachable again, and apparently
no one is going to serve its slots, clear the FAIL flag and let the
cluster continue with its operations again.
2013-03-05 15:05:32 +01:00
antirez 1a02b7440a Cluster: new node field fail_time.
This is the unix time at which we set the FAIL flag for the node.
It is only valid if FAIL is set.

The idea is to use it in order to make the cluster more robust, for
instance in order to revert a FAIL state if it is long-standing but
still slots are assigned to this node, that is, no one is going to fix
these slots apparently.
2013-03-05 13:15:05 +01:00
antirez d3b4662347 Cluster: don't check keys hash slots when the source is our master.
Usually we redirect clients to the right hash slot, however we don't
want to do that with our master, we want just to mirror it.
2013-03-05 13:02:44 +01:00
antirez 31ac376051 Cluster: slaveof not allowed in redis.conf as well. 2013-03-05 12:58:22 +01:00
antirez b7d085fc0d Cluster: SLAVEOF command not allowed in cluster mode. 2013-03-05 12:39:41 +01:00
antirez e4b481a5f6 Cluster: A comment updated in clusterCron(). 2013-03-05 12:17:30 +01:00
antirez d728ec6dee Cluster: send a ping to every node we never contacted in timeout/2 seconds.
Usually we try to send just 1 ping every second, however when we detect
we are going to have unreliable failure detection because we can't ping
some node in time, send an additional ping.

This should only happen with very large clusters or when the the node
timeout is set to a very low value.
2013-03-05 12:16:02 +01:00
antirez e7628be2a7 Cluster: set node->slaveof correctly when a node state is updated. 2013-03-05 11:50:11 +01:00
antirez d6457577d4 Cluster: don't perform startup slots sanity check for slaves.
If we are a cluster node the DB content will not match our configured
slots. Don't do the check at all.
2013-03-04 19:47:00 +01:00
antirez d334897e80 Cluster: fix maximum line length when loading config.
There are pathological cases where the line can be even longer a single
node may contain all the slots in importing/migrating state.
2013-03-04 19:45:36 +01:00
antirez 3be893123f Make sure replicationSetMaster() works when ip argument is not an sds. 2013-03-04 15:39:55 +01:00
antirez b8a28bf442 Cluster: actually setup replication in CLUSTER REPLICATE. 2013-03-04 15:27:58 +01:00
antirez 7bead003e2 SLAVEOF command refactored into a proper API.
We now have replicationSetMaster() and replicationUnsetMaster() that can
be called in other contexts (for instance Redis Cluster).
2013-03-04 13:22:21 +01:00
antirez 0c01088b51 Cluster: REPLICATE subcommand and stub for clusterSetMaster(). 2013-03-04 13:15:09 +01:00
charsyam bc84c399f8 adding check error code
adding check error code
2013-03-04 11:20:11 +01:00
antirez 3b3974410e redis-cli: use keepalive socket option.
This should improve things in two ways:

1) Prevent timeouts caused by the execution of long commands.
2) Improve detection of real connection errors.

This is mostly effective only on Linux because of the bogus default
keepalive settings. In Linux we have OS-specific calls to set the
keepalive interval to reasonable values.
2013-03-04 11:14:32 +01:00
Salvatore Sanfilippo 174e51cb75 Merge pull request #967 from 0x20h/fix-git-diff
suppress external diff program when using git diff.
2013-03-04 01:57:01 -08:00
Stam He d783860457 point 2 of slave-serve-stale-data miss '-' between 'stale' and 'data' 2013-03-04 10:49:07 +01:00
antirez caf9b24a7d Cluster: don't set the slot as unassigned because of PONG info.
As stated in the comment this is usually due to a resharding in progress
so the client should be still redirected to the old node that will
handle the redirection elsewhere.
2013-02-28 15:54:29 +01:00
antirez 0d77440b26 Cluster: better handling of slots changes in PONG packets.
The new code makes sure that the node slots bitmap is always consistent
with the cluster->slots array.
2013-02-28 15:41:54 +01:00
antirez 5f8fd27ace Cluster: refactoring of clusterNode*Bit to use helper bitmap functions. 2013-02-28 15:23:09 +01:00
antirez d21d6b666f Cluster: use node->numslots instead of popcount() where possible. 2013-02-28 15:13:32 +01:00
antirez 4521115b17 Cluster: new field in cluster node structure, "numslots".
Before a relatively slow popcount() operation was needed every time we
needed to get the number of slots served by a given cluster node.
Now we just need to check an integer that is taken in sync with the
bitmap.
2013-02-28 15:11:05 +01:00
antirez a2566d6618 Cluster: don't gossip about nodes that are not useful to the cluster. 2013-02-28 15:00:09 +01:00
antirez bc922dc688 redis-trib: skip nodes without slots when creating the config signature. 2013-02-28 13:12:56 +01:00
antirez 64942fca01 redis-trib help. 2013-02-27 18:02:22 +01:00
antirez d45d184118 Cluster: CLUSTER FORGET implemented. 2013-02-27 17:55:59 +01:00
antirez d2b8281b3f Cluster: added a missing return on CLUSTER SETSLOT. 2013-02-27 17:53:48 +01:00
antirez 7ddc0fe652 redis-trib: skip noaddr and disconnected nodes while loading cluster info. 2013-02-27 17:23:11 +01:00
antirez d20dea3eb7 Cluster: blank node address when flagging it as NOADDR. 2013-02-27 17:09:33 +01:00
antirez 2dcb5ab72b Cluster: add comments in sub-sections of CLUSTER command. 2013-02-27 16:12:59 +01:00
antirez 96dd210970 redis-trib: initial implementation of addnode command. 2013-02-27 15:58:41 +01:00
antirez f7dac639a9 Remove warning when printing redisBuildId(). 2013-02-27 12:33:27 +01:00
antirez e4682c82e3 Remove too agressive/spamming log in rdb.c. 2013-02-27 12:29:20 +01:00
antirez f9b5ca29fd Use GCC printf format attribute for redisLog().
This commit also fixes redisLog() statements producing warnings.
2013-02-27 12:27:15 +01:00
antirez c35b065a64 Better panic message for failed time event creation. 2013-02-27 12:00:11 +01:00
Stam He e431a97660 add a check for aeCreateTimeEvent
1) Add a check for aeCreateTimeEvent in function initServer.
2013-02-27 11:57:35 +01:00
Stam He 9c8be6cab9 Set proctitle: avoid the use of __attribute__((constructor)).
This cased a segfault in some Linux system and was GCC-specific.

Commit modified by @antirez:

1) Stripped away the part to set the proc title via config for now.
2) Handle initialization of setproctitle only when the replacement
   is used.
3) Don't require GCC now that the attribute constructor is no
   longer used.
2013-02-27 11:50:35 +01:00
antirez deb1f4d841 setproctitle.c: declar tmp as static so valgrind will not detect a leak. 2013-02-26 15:51:33 +01:00
antirez d0992d6e8b Cluster: a few random fixes to the new failure detection. 2013-02-26 15:15:44 +01:00
antirez f288b07563 Cluster: log the event when we clear the FAIL flag. 2013-02-26 15:03:38 +01:00
antirez 97ffcd351b Cluster: use the failure report API to reimplement failure detection.
The new system detects a failure only when there is quorum from masters.
2013-02-26 14:58:39 +01:00
antirez 6356cf6808 Set process name in ps output to make operations safer.
This commit allows Redis to set a process name that includes the binding
address and the port number in order to make operations simpler.

Redis children processes doing AOF rewrites or RDB saving change the
name into redis-aof-rewrite and redis-rdb-bgsave respectively.

This in general makes harder to kill the wrong process because of an
error and makes simpler to identify saving children.

This feature was suggested by Arnaud GRANAL in the Redis Google Group,
Arnaud also pointed me to the setproctitle.c implementation includeed in
this commit.

This feature should work on all the Linux, OSX, and all the three major
BSD systems.
2013-02-26 11:52:12 +01:00
antirez 1b1b3f6c06 Cluster: invert two functions declarations in more natural order. 2013-02-26 11:19:48 +01:00
antirez d5e8b0a47f Cluster: cleanup idle failure reports every time we remove one.
This is not very important as anyway when the function counting the
number of reports is called the cleanup is performed. However with this
change if only part of the nodes that reported the failure will report
the node is back ok, we'll cleanup the older entries ASAP. In complex
split net split scenarios, and when we are dealing with clusters having
nodes in the order of ~ 1000, this can save some CPU.
2013-02-26 11:15:18 +01:00
antirez 9cb578ced0 Cluster: new function clusterNodeDelFailureReport() for failure reports.
This is the missing part of the API that will be used to reimplement
failure detection of Cluster nodes.
2013-02-25 19:13:22 +01:00
Salvatore Sanfilippo b26bb768bc Merge pull request #969 from serphen/unstable
Fix error "repl-backlog-size must be 1 or greater"
2013-02-25 09:38:15 -08:00
Arnaud Granal 3d588b37ce Fix error "repl-backlog-size must be 1 or greater"
The parameter repl-backlog-size is not parsed correctly in the configuration file. argv[0] is parsed instead of argv[1].
2013-02-25 19:25:48 +02:00
antirez 18f537083a Cluster: no limits for the count parameter of CLUSTER GETKEYSINSLOT.
Not sure why I set a limit to 1 million keys, there is no reason for
this artificial limit, and anyway this is s a stupid limit because it is
already high enough to create latency issues. So let's the users shoot
on their feet because maybe they just actually know what they are doing.
2013-02-25 12:41:13 +01:00
antirez 544bbe5387 Cluster: validate slot number in CLUSTER COUNTKEYSINSLOT. 2013-02-25 12:40:32 +01:00
antirez 996a643752 Cluster: use O(log(N)) algo for countKeysInSlot(). 2013-02-25 12:37:50 +01:00
antirez d4fa40655d Cluster: new sub-command CLUSTER COUNTKEYSINSLOT.
The new sub-command uses the new countKeysInSlot() API and allows a
cluster client to get the number of keys for a given hashslot.
2013-02-25 12:04:31 +01:00
antirez a517c89321 Cluster: verifyClusterConfigWithData() implemented. 2013-02-25 11:43:49 +01:00
antirez 9947b0d96d A comment in main() clarified. 2013-02-25 11:40:21 +01:00
antirez d2154254be Cluster: fix case for getKeysInSlot() and countKeysInSlot().
Redis functions start in low case. A few functions about cluster were
capitalized the wrong way.
2013-02-25 11:25:40 +01:00
antirez c2eb4a606f Cluster: use CountKeysInSlot() when we just need the count. 2013-02-25 11:23:04 +01:00
antirez ad3bca1fdf Cluster: added stub for verifyClusterConfigWithData().
See the top-comment for the function in this commit for details about
what the function is supposed to do.
2013-02-25 11:20:17 +01:00
antirez 1abce14611 Cluster: added new API countKeysInSlot().
This is similar to getKeysInSlot() but just returns the number of keys
found in a given hash slot, without returning the keys.
2013-02-25 11:15:03 +01:00
0x20h 977035b7b5 suppress external diff program when using git diff. 2013-02-24 18:17:46 +01:00
antirez 825e07f2fd Cluster: if no previous config exists, create the myself node as master. 2013-02-22 19:24:01 +01:00
antirez f4093753e4 Cluster: add cluster_size field in CLUSTER INFO output. 2013-02-22 19:20:38 +01:00
antirez d218a4e244 Cluster: new state information, cluster size.
The definition of cluster size is: the number of known nodes in the
cluster that are masters and serving at least an hash slot.
2013-02-22 19:18:30 +01:00
antirez 5c55ed9388 Cluster: remove warning adding clusterNodeSetSlotBit() prototype. 2013-02-22 17:45:49 +01:00
antirez 974929770b Cluster: introduced a failure reports system.
A §Redis Cluster node used to mark a node as failing when itself
detected a failure for that node, and a single acknowledge was received
about the possible failure state.

The new API will be used in order to possible to require that N other
nodes have a PFAIL or FAIL state for a given node for a node to set it
as failing.
2013-02-22 17:43:35 +01:00
antirez 36af851550 redis-trib: check that all the nodes agree about the slots configuration. 2013-02-22 12:25:16 +01:00
antirez 51b5058d04 redis-trib: skeleton of coverage fix for "keys in multiple nodes" case. 2013-02-22 11:33:10 +01:00
antirez a81c598f95 redis-trib: handle slot coverage fix in the "no nodes with keys" case. 2013-02-22 10:23:53 +01:00
antirez 392e0fa7eb Cluster: fix case of slotToKey...() functions. 2013-02-22 10:16:21 +01:00
antirez d04770988d Cluster: empty the internal sorted set mapping keys to slots on FLUSHDB/ALL. 2013-02-22 10:15:32 +01:00
antirez efe51dfff5 redis-trib: specify single node address when fixing coverage. 2013-02-22 10:05:07 +01:00
antirez 915e81335e redis-trib: ability to fix uncovered slots for the trivial case. 2013-02-21 18:10:06 +01:00
antirez 619d3945f8 redis-trib: fixed typo in method name. 2013-02-21 16:58:27 +01:00
antirez 07b6322735 Cluster: more correct update of slots state when PONG is received. 2013-02-21 16:52:06 +01:00
antirez c6da9d9fac Call clusterUpdateState() after CLUSTER SETSLOT too. 2013-02-21 16:31:22 +01:00
antirez 3a99d1228a Aesthetic change to make a line more 80-cols friendly. 2013-02-21 16:24:48 +01:00
antirez 5fd9f701da redis-trib: move instance vars in the right class. 2013-02-21 13:06:59 +01:00
antirez 7898bf4b7e redis-trib: some refactoring and skeleton of the "fix" command. 2013-02-21 13:00:41 +01:00
antirez dc4af60628 Cluster: clusterAddSlot() was not doing what stated in the comment. 2013-02-21 11:51:17 +01:00
antirez fdb57233e2 Cluster: always use cluster(Add|Del)Slot to modify the cluster slots table. 2013-02-21 11:44:58 +01:00
antirez 786b8d6c87 Use RESTORE-ASKING for MIGRATE when in cluster mode. 2013-02-20 17:36:54 +01:00
antirez ea7fc82a4a Cluster: new command flag forcing implicit ASKING.
Also using this new flag the RESTORE-ASKING command was implemented that
will be used by MIGRATE.
2013-02-20 17:28:35 +01:00
antirez 9ec1b709f5 Cluster: ASKING command fixed, state was not retained. 2013-02-20 17:07:52 +01:00
antirez b8d8b9ec41 redis-trib: set the migrating slot in the correct way when resharding. 2013-02-20 15:29:53 +01:00
antirez 9a04e12cc0 Cluster: I/O errors are now logged at DEBUG level. 2013-02-20 13:18:51 +01:00
antirez 917dd53216 redis-trib: make a few comments 80-cols friendly. 2013-02-15 17:11:55 +01:00
antirez 455da35c7f Cluster: specific error code for cluster down condition. 2013-02-15 16:53:24 +01:00
antirez 522c3255db Merge branch 'unstable' of github.com:antirez/redis into unstable 2013-02-15 16:45:04 +01:00
antirez 02796ba7a7 Cluster: sanity checks on the cluster bus message length. 2013-02-15 16:44:39 +01:00
antirez 8853698a6f Removed useless newlines from hashTypeCurrentObject(). 2013-02-15 13:12:55 +01:00
antirez 6b9c661838 Cluster: make valgrind happy initializing all the bytes of the node IP. 2013-02-15 12:58:35 +01:00
antirez 7371d5e248 Remove wrong decrRefCount() from getNodeByQuery().
This fixes issue #607.
2013-02-15 11:57:53 +01:00
antirez 20f52b5b78 Top comment for getNodeByQuery() improved. 2013-02-15 11:50:54 +01:00
antirez 6b641f3aeb redis-cli: update prompt on cluster redirection. 2013-02-14 18:49:08 +01:00
antirez e0e15bd06d Cluster: with 16384 slots we need bigger buffers. 2013-02-14 15:36:33 +01:00
antirez 1a32d99b28 Cluster: move cluster config file out of config state.
This makes us able to avoid allocating the cluster state structure if
cluster is not enabled, but still we can handle the configuration
directive that sets the cluster config filename.
2013-02-14 15:20:02 +01:00
antirez 1649e509c3 Cluster: the cluster state structure is now heap allocated. 2013-02-14 13:20:56 +01:00
antirez 9dfd11c3da Cluster: Initialize ip and port in createClusterNode(). 2013-02-14 13:01:28 +01:00
antirez a26690e8b5 Cluster: redis-trib updated to use 16384 hash slots. 2013-02-14 12:55:34 +01:00
antirez ebd666db47 Cluster: from 4096 to 16384 hash slots. 2013-02-14 12:49:16 +01:00
antirez 072c91fe13 PSYNC: another change to unexpected reply from PSYNC. 2013-02-13 18:43:40 +01:00
antirez 0e1be5347b PSYNC: More robust handling of unexpected reply to PSYNC. 2013-02-13 18:33:33 +01:00
antirez 7404b95833 Avoid compiler warning by casting to match printf() specifier. 2013-02-13 13:38:20 +01:00
antirez 3419c8ce70 Replication: more strict error checking for master PING reply. 2013-02-12 16:53:27 +01:00
antirez dc24a6b132 Return a specific NOAUTH error if authentication is required. 2013-02-12 16:25:41 +01:00
antirez 24f258360b Replication: added new stats counting full and partial resynchronizations. 2013-02-12 15:33:54 +01:00
antirez ac8c89cb20 Test: avoid false positives in CLIENT SETNAME closed connection test. 2013-02-12 13:27:24 +01:00
antirez 7f9bc42f17 Merge remote-tracking branch 'origin/unstable' into unstable 2013-02-12 12:59:15 +01:00
antirez 04bdb3a2a4 Add missing bracket removed for error after rebase of PSYNC. 2013-02-12 12:56:32 +01:00
antirez 3af478e9ef PSYNC: debugging printf() calls are now logs at DEBUG level. 2013-02-12 12:52:22 +01:00
antirez 89b48f0825 Remove harmless warning in slaveTryPartialResynchronization(). 2013-02-12 12:52:21 +01:00
antirez 0ed6daa48b PSYNC: don't use the client buffer to send +CONTINUE and +FULLRESYNC.
When we are preparing an handshake with the slave we can't touch the
connection buffer as it'll be used to accumulate differences between
the sent RDB file and what arrives next from clients.

So in short we can't use addReply() family functions.

However we just use write(2) because we know that the socket buffer is
empty, since a prerequisite for SYNC to work is that the static buffer
and the output list are empty, and in general it is not expected that a
client SYNCs after doing some heavy I/O with the master.

However a short write connection is explicitly handled to avoid
fragility (we simply close the connection and the slave will retry).
2013-02-12 12:52:21 +01:00
antirez d2a0348a49 SYNC not allowed with pending data on the static output buffer. 2013-02-12 12:52:21 +01:00
antirez da315d3325 Log the unexpected string received in place of the SYNC payload length. 2013-02-12 12:52:21 +01:00
antirez 41d64a7516 After SLAVEOF <newslave> don't allow chained slaves to PSYNC. 2013-02-12 12:52:21 +01:00
antirez 078882025e PSYNC: work in progress, preview #2, rebased to unstable. 2013-02-12 12:52:21 +01:00
antirez e34a35a511 Use the new unified protocol to send SELECT to slaves.
SELECT was still transmitted to slaves using the inline protocol, that
is conceived mostly for humans to type into telnet sessions, and is
notably not understood by redis-cli --slave.

Now the new protocol is used instead.
2013-02-12 12:50:28 +01:00
antirez 4b83ad4e1f Use replicationFeedSlaves() to send PING to slaves.
A Redis master sends PING commands to slaves from time to time: doing
this ensures that even if absence of writes, the master->slave channel
remains active and the slave can feel the master presence, instead of
closing the connection for timeout.

This commit changes the way PINGs are sent to slaves in order to use the
standard interface used to replicate all the other commands, that is,
the function replicationFeedSlaves().

With this change the stream of commands sent to every slave is exactly
the same regardless of their exact state (Transferring RDB for first
synchronization or slave already online). With the previous
implementation the PING was only sent to online slaves, with the result
that the output stream from master to slaves was not identical for all
the slaves: this is a problem if we want to implement partial resyncs in
the future using a global replication stream offset.

TL;DR: this commit should not change the behaviour in practical terms,
but is just something in preparation for partial resynchronization
support.
2013-02-12 12:50:28 +01:00
antirez 7465ac7ab1 Emit SELECT to slaves in a centralized way.
Before this commit every Redis slave had its own selected database ID
state. This was not actually useful as the emitted stream of commands
is identical for all the slaves.

Now the the currently selected database is a global state that is set to
-1 when a new slave is attached, in order to force the SELECT command to
be re-emitted for all the slaves.

This change is useful in order to implement replication partial
resynchronization in the future, as makes sure that the stream of
commands received by slaves, including SELECT commands, are exactly the
same for every slave connected, at any time.

In this way we could have a global offset that can identify a specific
piece of the master -> slaves stream of commands.
2013-02-12 12:50:28 +01:00
Salvatore Sanfilippo 3043f890a5 Merge pull request #941 from svnpenn/patch-1
Format to fit 80 columns
2013-02-12 01:30:39 -08:00
antirez 1a27d41156 Makefile: valgrind target added (forces -O0 and libc malloc). 2013-02-11 12:11:28 +01:00
antirez 93ae95de74 TCP keep-alive. Better documentation in redis.conf. 2013-02-09 01:17:59 +01:00
Steven Penny 3244d8bc0c Format to fit 80 columns
This makes it readable on GitHub and editors without auto wrapping.
2013-02-08 12:11:06 -06:00
antirez 76a5b21c3a Tcp keep-alive: send three probes before detectin an error.
Otherwise we end with less reliable connections because it's too easy
that a single packet gets lost.
2013-02-08 17:06:01 +01:00
antirez 98b1a852b4 tcp-keepalive option documented in redis.conf. 2013-02-08 17:03:11 +01:00
antirez 124a635bc5 Set SO_KEEPALIVE on client sockets if configured to do so. 2013-02-08 16:40:59 +01:00
antirez ee21c18e5d Add SO_KEEPALIVE support to anet.c. 2013-02-08 16:30:26 +01:00
antirez a6c2f9012f Make all WATCHers dirty when the slave reloads the DB. 2013-02-08 10:26:19 +01:00
antirez 46dd4c62b3 LASTSAVE is a "random" command. 2013-02-07 19:13:00 +01:00
antirez b70b459b0e TCP_NODELAY after SYNC: changes to the implementation. 2013-02-05 12:04:30 +01:00
charsyam c85647f354 Turn off TCP_NODELAY on the slave socket after SYNC.
Further details from @antirez:

It was reported by @StopForumSpam on Twitter that the Redis replication
link was strangely using multiple TCP packets for multiple commands.
This wastes a lot of bandwidth and is due to the TCP_NODELAY option we
enable on the socket after accepting a new connection.

However the master -> slave channel is a one-way channel since Redis
replication is asynchronous, so there is no point in trying to reduce
the latency, we should aim to reduce the bandwidth. For this reason this
commit introduces the ability to disable the nagle algorithm on the
socket after a successful SYNC.

This feature is off by default because the delay can be up to 40
milliseconds with normally configured Linux kernels.
2013-02-05 12:04:25 +01:00
antirez fd7350b084 Test: No clients timeout while testing. 2013-02-05 12:02:46 +01:00
Salvatore Sanfilippo bb7aa1772c Merge pull request #906 from jbergstroem/tclsh-agnostic
Make redis test suite tcl version agnostic, v2
2013-02-05 02:43:56 -08:00
Salvatore Sanfilippo 58463e0505 Merge pull request #933 from RockLi/unstable
retval doesn't initalized
2013-02-05 01:48:49 -08:00
Rock Li 8063155cd0 retval doesn't initalized
If each if conditions are all fail, variable retval will under uninitlized
2013-02-05 15:56:04 +08:00
Salvatore Sanfilippo f95b393603 Merge pull request #928 from davidcelis/unstable
Fix a few typos and improve grammar of redis.conf
2013-02-04 01:32:31 -08:00
Salvatore Sanfilippo 74f4f29880 Merge pull request #929 from ltnwgl/unstable
Fix a bug in srandmemberWithCountCommand()
2013-02-04 01:21:18 -08:00
Gengliang Wang 002747336a Fix a bug in srandmemberWithCountCommand()
In CASE 2, the call sunionDiffGenericCommand will involve the string "srandmember" 
> sadd foo one
(integer 1)
> sadd srandmember two
(integer 2)
> srandmember foo 3
1)"one"
2)"two"
2013-02-04 14:01:08 +08:00
David Celis 81144645b4 Fix a few typos and improve grammar of redis.conf
Make several edits to the example redis.conf configuration file for
improved flow and grammar.

Signed-off-by: David Celis <me@davidcel.is>
2013-02-03 11:40:07 -08:00
antirez 089cbe643f Sentinel: advertise the promoted slave address only after successful setup. 2013-01-31 17:19:21 +01:00
Salvatore Sanfilippo aca005c246 Merge pull request #914 from catwell/unstable
fix comments forgotten in #285 (zipmap -> ziplist)
2013-01-31 03:37:48 -08:00
antirez ad297a1a67 Z*STORE event fixed: generate del only if resulting sorted set is empty. 2013-01-29 13:50:01 +01:00
antirez e41d1d77e3 Generate del events when S*STORE commands delete the destination key. 2013-01-29 13:43:13 +01:00
antirez d2b27f1d96 Tests for keyspace notifications. 2013-01-28 13:15:22 +01:00
antirez 4dfb5752e0 Send 'expired' events when a key expires by lookup. 2013-01-28 13:15:19 +01:00
antirez 562b2bd6a7 Keyspace notifications: fixed a leak and a bug introduced in the latest commit. 2013-01-28 13:15:16 +01:00
antirez fce016d31b 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 1c0c551776 decrRefCount -> decrRefCountVoid in list constructor. 2013-01-28 13:15:08 +01:00
antirez 40f822da73 Enable keyspace events notification when testing. 2013-01-28 13:15:01 +01:00
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
antirez 2d20e68fe4 notifyKeyspaceEvent(): release channel names using the right pointers. 2013-01-28 13:14:49 +01:00
antirez 5b9357a6b3 Initial test events for the new keyspace notification API. 2013-01-28 13:14:46 +01:00
antirez 2ea9518a53 Fixed over-80-cols comment in db.c 2013-01-28 13:14:42 +01:00
antirez 08d8bb57df Two fixes to initial keyspace notifications API. 2013-01-28 13:14:39 +01:00
antirez 4cdbce341e Keyspace events notification API. 2013-01-28 13:14:36 +01:00
Pierre Chapuis 50d43a9823 fix comments forgotten in #285 (zipmap -> ziplist) 2013-01-28 11:07:17 +01:00
Johan Bergström 1154283577 Use info nameofexectuable to find current executable 2013-01-24 09:37:18 +11:00
Johan Bergström acb046773d Enforce tcl 8.5 or newer 2013-01-24 09:36:59 +11:00
Johan Bergström a405979f5f Check available tcl versions 2013-01-24 09:25:47 +11:00
antirez 61853a9c75 Lua struct library updated to version 0.2.
There was a bug in the previous version of this library that caused a
crash under the circumstances described in issue #901.

The newer version of the library appears to be fixed (I tested it
manually with valgrind and everything seems fine now).

For more information about this library please visit this web site:

    http://www.inf.puc-rio.br/~roberto/struct/
2013-01-23 10:50:48 +01:00
antirez 88015b89a0 redis-cli --bigkeys output is now simpler to understand. 2013-01-21 19:15:58 +01:00
antirez 2039f1a38a UNSUBSCRIBE and PUNSUBSCRIBE: always provide a reply.
UNSUBSCRIBE and PUNSUBSCRIBE commands are designed to mass-unsubscribe
the client respectively all the channels and patters if called without
arguments.

However when these functions are called without arguments, but there are
no channels or patters we are subscribed to, the old behavior was to
don't reply at all.

This behavior is broken, as every command should always reply.
Also it is possible that we are no longer subscribed to a channels but we
are subscribed to patters or the other way around, and the client should
be notified with the correct number of subscriptions.

Also it is not pretty that sometimes we did not receive a reply at all
in a redis-cli session from these commands, blocking redis-cli trying
to read the reply.

This fixes issue #714.
2013-01-21 19:02:26 +01:00
antirez 93f61bb2a4 Fixed a bug in memtest progress bar, that had no actual effects.
This closes issue #859, thanks to @erbenmo.
2013-01-21 12:34:22 +01:00
Salvatore Sanfilippo 442235fe40 Merge pull request #869 from bilalhusain/patch-2
s/adiacent/adjacent/
2013-01-21 03:19:02 -08:00
Salvatore Sanfilippo 6db93e6740 Merge pull request #883 from deepsolo9/fix-typos-deepsolo9
fixed some typos in Redis.c
2013-01-21 03:12:03 -08:00
Salvatore Sanfilippo 4698f6756b Merge pull request #884 from kaerast/patch-1
Typo in sentinel.conf
2013-01-21 03:11:25 -08:00
antirez cd892d015d Not every __sun has backtrace().
I don't know how to test for Open Solaris that has support for
backtrace() so for now removing the #ifdef that breaks compilation under
other Solaris flavors.
2013-01-21 12:06:54 +01:00
antirez e50cdbe461 Additionally two typos fixed thanks to @jodal 2013-01-19 13:46:14 +01:00
antirez 79a0ef62db Whitelist SIGUSR1 to avoid auto-triggering errors.
This commit fixes issue #875 that was caused by the following events:

1) There is an active child doing BGSAVE.
2) flushall is called (or any other condition that makes Redis killing
the saving child process).
3) An error is sensed by Redis as the child exited with an error (killed
by a singal), that stops accepting write commands until a BGSAVE happens
to be executed with success.

Whitelisting SIGUSR1 and making sure Redis always uses this signal in
order to kill its own children fixes the issue.
2013-01-19 13:30:38 +01:00
antirez ab247fc176 Clear server.shutdown_asap on failed shutdown.
When a SIGTERM is received Redis schedules a shutdown. However if it
fails to perform the shutdown it must be clear the shutdown_asap flag
otehrwise it will try again and again possibly making the server
unusable.
2013-01-19 13:19:41 +01:00
antirez 08d200baeb Slowlog: don't log EXEC but just the executed commands.
The Redis Slow Log always used to log the slow commands executed inside
a MULTI/EXEC block. However also EXEC was logged at the end, which is
perfectly useless.

Now EXEC is no longer logged and a test was added to test this behavior.

This fixes issue #759.
2013-01-19 12:53:21 +01:00
guiquanz 9d09ce3981 Fixed many typos. 2013-01-19 10:59:44 +01:00
Salvatore Sanfilippo 61dfc2e521 Merge pull request #887 from charsyam/redis-cli-prompt
redis-cli prompt bug fix
2013-01-19 01:32:28 -08:00
Salvatore Sanfilippo 74f137308e Merge pull request #895 from badboy/catch_con_error
redis-cli: always exit if connection fails.
2013-01-19 01:27:56 -08:00
Salvatore Sanfilippo 947f1689d3 Merge pull request #896 from bitterb/fix-client-command-error-message
Fix an error reply for CLIENT command
2013-01-19 01:25:01 -08:00
bitterb c2dc172a9d Fix an error reply for CLIENT command 2013-01-19 14:11:33 +09:00
Salvatore Sanfilippo 21b3ff9ba0 Merge pull request #893 from nparry/fix-redis-cli-rdb
redis-cli --rdb fails if server sends a ping
2013-01-18 02:41:29 -08:00
Jan-Erik Rediger 59046a7373 Always exit if connection fails.
This avoids unnecessary core dumps. Fixes antirez/redis#894
2013-01-18 10:13:10 +01:00
Nathan Parry 1920cab3bc redis-cli --rdb fails if server sends a ping
Redis pings slaves in "pre-synchronization stage" with newlines. (See
https://github.com/antirez/redis/blob/2.6.9/src/replication.c#L814)
However, redis-cli does not expect this - it sees the newline as the end
of the bulk length line, and ends up returning 0 as bulk the length.
This manifests as the following when running redis-cli:

    $ ./src/redis-cli --rdb some_file
    SYNC sent to master, writing 0 bytes to 'some_file'
    Transfer finished with success.

With this commit, we just ignore leading newlines while reading the bulk
length line.

To reproduce the problem, load enough data into Redis so that the
preparation of the RDB snapshot takes long enough for a ping to occur
while redis-cli is waiting for the data.
2013-01-18 00:10:58 -05:00
charsyam e396236651 redis-cli prompt bug fix 2013-01-16 17:20:54 -08:00
antirez a0c24821e2 redis-cli: save an RDB dump from remote server to local file. 2013-01-16 19:44:37 +01:00
Alice Kærast 8937f5e500 Typo in sentinel.conf
Fixes a minor typo in sentinel.conf
2013-01-16 15:02:06 +00:00
Hu Weiwei 1dc2d6dc47 fixed some typos. 2013-01-16 18:04:43 +08:00
antirez ea1f503cfe Tests for CLIENT GETNAME/SETNAME. 2013-01-15 13:34:17 +01:00
antirez 9b89ab06c4 Typo fixed, ASCI -> ASCII. 2013-01-15 13:34:13 +01:00
antirez 1971740f0c CLIENT GETNAME and CLIENT SETNAME introduced.
Sometimes it is much simpler to debug complex Redis installations if it
is possible to assign clients a name that is displayed in the CLIENT
LIST output.

This is the case, for example, for "leaked" connections. The ability to
provide a name to the client makes it quite trivial to understand what
is the part of the code implementing the client not releasing the
resources appropriately.

Behavior:

    CLIENT SETNAME: set a name for the client, or remove the current
                    name if an empty name is set.
    CLIENT GETNAME: get the current name, or a nil.
    CLIENT LIST: now displays the client name if any.

Thanks to Mark Gravell for pushing this idea forward.
2013-01-15 13:34:10 +01:00
antirez ef99e146a8 Undo slave-master handshake when SLAVEOF sets a new slave.
Issue #828 shows how Redis was not correctly undoing a non-blocking
connection attempt with the previous master when the master was set to a
new address using the SLAVEOF command.

This was also a result of lack of refactoring, so now there is a
function to cancel the non blocking handshake with the master.
The new function is now used when SLAVEOF NO ONE is called or when
SLAVEOF is used to set the master to a different address.
2013-01-15 13:33:24 +01:00
antirez a33869c330 Makefile.dep updated. 2013-01-11 23:50:32 +01:00
antirez f5fa6824db Comment in the call() function clarified a bit. 2013-01-10 11:19:40 +01:00
antirez a5cc063c17 Test: added regression for issue #872. 2013-01-10 11:10:31 +01:00
antirez baee565029 Multiple fixes for EVAL (issue #872).
1) The event handler was no restored after a timeout condition if the
   command was eventually executed with success.
2) The command was not converted to EVAL in case of errors in the middle
   of the execution.
3) Terrible duplication of code without any apparent reason.
2013-01-10 10:46:05 +01:00
Bilal Husain 717e5ffb45 s/adiacent/adjacent/
fixed typo in a comment (step 2 memcheck)
2013-01-09 21:46:58 +05:30
antirez d7740fc8f3 Better error reporting when fd event creation fails. 2013-01-03 14:29:34 +01:00
antirez e9261b1e2d ae.c: set errno when error is not a failing syscall.
In this way the caller is able to perform better error checking or to
use strerror() without the risk of meaningless error messages being
displayed.
2013-01-03 14:29:20 +01:00
antirez 4dc1e0dd30 Fix overflow in mstime() in redis-cli and benchmark.
The problem does not exist in the Redis server implementation of mstime()
but is only limited to redis-cli and redis-benchmark.

Thix fixes issue #839.
2012-12-20 15:20:55 +01:00
antirez ebbc4ebb26 CONTRIBUTING updated with request to add BSD license. 2012-12-17 11:13:54 +01:00
antirez d01aad329c Added missing license and copyright in deps/hiredis. 2012-12-17 11:11:09 +01:00
antirez f1481d4a03 serverCron() frequency is now a runtime parameter (was REDIS_HZ).
REDIS_HZ is the frequency our serverCron() function is called with.
A more frequent call to this function results into less latency when the
server is trying to handle very expansive background operations like
mass expires of a lot of keys at the same time.

Redis 2.4 used to have an HZ of 10. This was good enough with almost
every setup, but the incremental key expiration algorithm was working a
bit better under *extreme* pressure when HZ was set to 100 for Redis
2.6.

However for most users a latency spike of 30 milliseconds when million
of keys are expiring at the same time is acceptable, on the other hand a
default HZ of 100 in Redis 2.6 was causing idle instances to use some
CPU time compared to Redis 2.4. The CPU usage was in the order of 0.3%
for an idle instance, however this is a shame as more energy is consumed
by the server, if not important resources.

This commit introduces HZ as a runtime parameter, that can be queried by
INFO or CONFIG GET, and can be modified with CONFIG SET. At the same
time the default frequency is set back to 10.

In this way we default to a sane value of 10, but allows users to
easily switch to values up to 500 for near real-time applications if
needed and if they are willing to pay this small CPU usage penalty.
2012-12-14 17:10:40 +01:00
Salvatore Sanfilippo a4d68dc541 Merge pull request #824 from ptjm/unstable
Define _XOPEN_SOURCE appropriately on NetBSD.
2012-12-12 09:34:41 -08:00
Patrick TJ McPhee 289942b625 Define _XOPEN_SOURCE appropriately on NetBSD. 2012-12-12 10:49:12 -05:00
antirez 705874e31d Fix config.h endianess detection to work on Linux / PPC64.
Config.h performs endianess detection including OS-specific headers to
define the endianess macros, or when this is not possible, checking the
processor type via ifdefs.

Sometimes when the OS-specific macro is included, only __BYTE_ORDER is
defined, while BYTE_ORDER remains undefined. There is code at the end of
config.h endianess detection in order to define the macros without the
underscore, but it was not working correctly.

This commit fixes endianess detection fixing Redis on Linux / PPC64 and
possibly other systems.
2012-12-11 17:01:00 +01:00
Salvatore Sanfilippo bf0852e5ed Merge pull request #807 from bmcmanus/issue-804
Resolution for Issue #804 Add Default-Start and Default-Stop LSB tags for RedHat startup...
2012-12-03 03:30:13 -08:00
antirez ab2924cff3 Memory leak fixed: release client's bpop->keys dictionary.
Refactoring performed after issue #801 resolution (see commit
2f87cf8b01) introduced a memory leak that
is fixed by this commit.

I simply forgot to free the new allocated dictionary in the client
structure trusting the output of "make test" on OSX.

However due to changes in the "leaks" utility the test was no longer
testing memory leaks. This problem was also fixed.

Fortunately the CI test running at ci.redis.io spotted the bug in the
valgrind run.

The leak never ended into a stable release.
2012-12-03 12:12:53 +01:00
antirez a18ca73681 Test: fixed osx "leaks" support in test.
Due to changes in recent releases of osx leaks utility, the osx leak
detection no longer worked. Now it is fixed in a way that should be
backward compatible.
2012-12-03 12:06:38 +01:00
Brian J. McManus bb58e517a9 Issue 804 Add Default-Start and Default-Stop LSB tags for RedHat startup and update-rc.d compatability. 2012-12-02 21:46:37 -07: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 c135b856c6 Test: regression for issue #801. 2012-12-02 20:43:11 +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 f50e658455 SDIFF is now able to select between two algorithms for speed.
SDIFF used an algorithm that was O(N) where N is the total number
of elements of all the sets involved in the operation.

The algorithm worked like that:

ALGORITHM 1:

1) For the first set, add all the members to an auxiliary set.
2) For all the other sets, remove all the members of the set from the
auxiliary set.

So it is an O(N) algorithm where N is the total number of elements in
all the sets involved in the diff operation.

Cristobal Viedma suggested to modify the algorithm to the following:

ALGORITHM 2:

1) Iterate all the elements of the first set.
2) For every element, check if the element also exists in all the other
remaining sets.
3) Add the element to the auxiliary set only if it does not exist in any
of the other sets.

The complexity of this algorithm on the worst case is O(N*M) where N is
the size of the first set and M the total number of sets involved in the
operation.

However when there are elements in common, with this algorithm we stop
the computation for a given element as long as we find a duplicated
element into another set.

I (antirez) added an additional step to algorithm 2 to make it faster,
that is to sort the set to subtract from the biggest to the
smallest, so that it is more likely to find a duplicate in a larger sets
that are checked before the smaller ones.

WHAT IS BETTER?

None of course, for instance if the first set is much larger than the
other sets the second algorithm does a lot more work compared to the
first algorithm.

Similarly if the first set is much smaller than the other sets, the
original algorithm will less work.

So this commit makes Redis able to guess the number of operations
required by each algorithm, and select the best at runtime according
to the input received.

However, since the second algorithm has better constant times and can do
less work if there are duplicated elements, an advantage is given to the
second algorithm.
2012-11-30 16:36:42 +01:00
antirez b4abbaf755 redis-benchmark: seed the PRNG with time() at startup. 2012-11-30 15:41:09 +01:00
antirez 395d663d29 SDIFF fuzz test added. 2012-11-30 01:35:34 +01:00
antirez 925090f476 Make an EXEC test more latency proof. 2012-11-29 16:12:14 +01:00
antirez 2f62c9663c Introduced the Build ID in INFO and --version output.
The idea is to be able to identify a build in a unique way, so for
instance after a bug report we can recognize that the build is the one
of a popular Linux distribution and perform the debugging in the same
environment.
2012-11-29 14:20:08 +01:00
antirez b1b602a928 On crash memory test rewrote so that it actaully works.
1) We no longer test location by location, otherwise the CPU write cache
completely makes our business useless.
2) We still need a memory test that operates in steps from the first to
the last location in order to never hit the cache, but that is still
able to retain the memory content.

This was tested using a Linux box containing a bad memory module with a
zingle bit error (always zero).

So the final solution does has an error propagation step that is:

1) Invert bits at every location.
2) Swap adiacent locations.
3) Swap adiacent locations again.
4) Invert bits at every location.
5) Swap adiacent locations.
6) Swap adiacent locations again.

Before and after these steps, and after step 4, a CRC64 checksum is computed.
If the three CRC64 checksums don't match, a memory error was detected.
2012-11-29 10:24:35 +01:00
antirez 7383c3b129 Jemalloc updated to version 3.2.0. 2012-11-28 18:39:35 +01:00
charsyam dee0b939fc Remove unnecessary condition in _dictExpandIfNeeded (dict.c) 2012-11-28 11:44:39 +01:00
antirez c87a40897c Merge remote-tracking branch 'origin/unstable' into unstable 2012-11-28 11:41:27 +01:00
Matt Arsenault 504e5072eb It's a watchdog, not a watchdong. 2012-11-28 11:35:19 +01:00
Salvatore Sanfilippo 23d517d2c4 Merge pull request #787 from charsyam/remove-warning-bio
remove compile warning bioKillThreads
2012-11-23 03:44:18 -08:00
charsyam d7c7ac4a57 remove compile warning bioKillThreads 2012-11-23 05:52:39 +08:00
antirez 95f68f7b0f EVALSHA is now case insensitive.
EVALSHA used to crash if the SHA1 was not lowercase (Issue #783).
Fixed using a case insensitive dictionary type for the sha -> script
map used for replication of scripts.
2012-11-22 15:50:00 +01:00
antirez cceb0c5b4a Fix integer overflow in zunionInterGenericCommand().
This fixes issue #761.
2012-11-22 15:28:28 +01:00
antirez 65606b3bc6 Test: MULTI state is cleared after EXECABORT error. 2012-11-22 10:32:20 +01:00
antirez 4977ab79af Test: make sure EXEC fails after previous transaction errors. 2012-11-22 10:32:16 +01:00
antirez 9c00f07897 Test: MULTI/EXEC tests moved into multi.tcl. 2012-11-22 10:32:12 +01:00
antirez 3d1391272a Safer handling of MULTI/EXEC on errors.
After the transcation starts with a MULIT, the previous behavior was to
return an error on problems such as maxmemory limit reached. But still
to execute the transaction with the subset of queued commands on EXEC.

While it is true that the client was able to check for errors
distinguish QUEUED by an error reply, MULTI/EXEC in most client
implementations uses pipelining for speed, so all the commands and EXEC
are sent without caring about replies.

With this change:

1) EXEC fails if at least one command was not queued because of an
error. The EXECABORT error is used.
2) A generic error is always reported on EXEC.
3) The client DISCARDs the MULTI state after a failed EXEC, otherwise
pipelining multiple transactions would be basically impossible:
After a failed EXEC the next transaction would be simply queued as
the tail of the previous transaction.
2012-11-22 10:32:07 +01:00
antirez 7536991726 Make bio.c threads killable ASAP if needed.
We use this new bio.c feature in order to stop our I/O threads if there
is a memory test to do on crash. In this case we don't want anything
else than the main thread to run, otherwise the other threads may mess
with the heap and the memory test will report a false positive.
2012-11-22 10:12:11 +01:00
antirez 5a9e3f5842 Fast memory test on Redis crash. 2012-11-21 13:24:44 +01:00
antirez 3cb432837c Use more fine grained HAVE macros instead of HAVE_PROCFS. 2012-11-21 13:17:38 +01:00
charsyam 52b52a3508 fix randstring bug 2012-11-20 02:50:31 +08:00
antirez 49b6452351 Children creating AOF or RDB files now report memory used by COW.
Finally Redis is able to report the amount of memory used by
copy-on-write while saving an RDB or writing an AOF file in background.

Note that this information is currently only logged (at NOTICE level)
and not shown in INFO because this is less trivial (but surely doable
with some minor form of interprocess communication).

The reason we can't capture this information on the parent before we
call wait3() is that the Linux kernel will release the child memory
ASAP, and only retain the minimal state for the process that is useful
to report the child termination to the parent.

The COW size is obtained by summing all the Private_Dirty fields found
in the "smap" file inside the proc filesystem for the process.

All this is Linux specific and is not available on other systems.
2012-11-19 12:02:08 +01:00
antirez 3bfeb9c1a7 zmalloc_get_private_dirty() function added (Linux only).
For non Linux systmes it just returns 0.

This function is useful to estimate copy-on-write because of childs
saving stuff on disk.
2012-11-19 11:47:35 +01:00
antirez af0b220756 zmalloc: kill unused __size parameter in update_zmalloc_stat_alloc() macro. 2012-11-14 12:52:38 +01:00
antirez a779b7e901 Merge branch 'migrate-cache' into unstable 2012-11-14 12:21:23 +01:00
antirez 989a7820ca Test: more MIGRATE tests. 2012-11-14 12:12:52 +01:00
antirez 2feef47aa1 MIGRATE: retry one time on I/O error.
Now that we cache connections, a retry attempt makes sure that the
operation don't fail just because there is an existing connection error
on the socket, like the other end closing the connection.

Unfortunately this condition is not detectable using
getsockopt(SO_ERROR), so the only option left is to retry.

We don't retry on timeouts.
2012-11-14 11:30:24 +01:00
antirez 17411f7afd Test: check if MIGRATE is caching connections. 2012-11-14 10:58:34 +01:00
antirez aa2bf6ba8b TTL API change: TTL returns -2 for non existing keys.
The previous behavior was to return -1 if:

1) Existing key but without an expire set.
2) Non existing key.

Now the second case is handled in a different, and TTL will return -2
if the key does not exist at all.

PTTL follows the same behavior as well.
2012-11-12 23:04:36 +01:00
antirez 05705bc8bb MIGRATE: fix default timeout to 1000 milliseconds.
When a timeout <= 0 is provided we set a default timeout of 1 second.
It was set to 1 millisecond for an error resulting from a recent change.
2012-11-12 18:54:35 +01:00
antirez c8852ebf19 MIGRATE count of cached sockets in INFO output. 2012-11-12 14:01:56 +01:00
antirez 149b527a74 MIGRATE timeout should be in milliseconds.
While it is documented that the MIGRATE timeout is in milliseconds, it
was in seconds instead. This commit fixes the problem.
2012-11-12 14:01:02 +01:00
antirez e23d281e48 MIGRATE TCP connections caching.
By caching TCP connections used by MIGRATE to chat with other Redis
instances a 5x performance improvement was measured with
redis-benchmark against small keys.

This can dramatically speedup cluster resharding and other processes
where an high load of MIGRATE commands are used.
2012-11-12 00:47:24 +01:00
antirez 5513397de7 Copyright date fixed in COPYING file. 2012-11-08 19:14:42 +01:00
antirez 399669fc6f Make clear that contributing code to the Redis project means to release it under the terms of the BSD license. 2012-11-08 18:43:20 +01:00
antirez 4365e5b2d3 BSD license added to every C source and header file. 2012-11-08 18:31:32 +01:00
antirez 1237d71c4e COPY and REPLACE options for MIGRATE.
With COPY now MIGRATE does not remove the key from the source instance.
With REPLACE it uses RESTORE REPLACE on the target host so that even if
the key already eixsts in the target instance it will be overwritten.

The options can be used together.
2012-11-07 15:32:27 +01:00
antirez e5b5763f56 REPLACE option for RESTORE.
The REPLACE option deletes an existing key with the same name (if any)
and materializes the new one. The default behavior without RESTORE is to
return an error if a key already exists.
2012-11-07 10:57:23 +01:00
antirez c4b0b6854e Type mismatch errors are now prefixed with WRONGTYPE.
So instead to reply with a generic error like:

-ERR ... wrong kind of value ...

now it replies with:

-WRONGTYPE ... wrong kind of value ...

This makes this particular error easy to check without resorting to
(fragile) pattern matching of the error string (however the error string
used to be consistent already).

Client libraries should return a specific exeption type for this error.

Most of the commit is about fixing unit tests.
2012-11-06 20:25:34 +01:00
Salvatore Sanfilippo 06851a93de Merge pull request #741 from Run/typo
fix a typo in redis.h line 595 comment
2012-11-02 04:10:47 -07:00
antirez 05d8e2c938 More robust handling of AOF rewrite child.
After the wait3() syscall we used to do something like that:

    if (pid == server.rdb_child_pid) {
        backgroundSaveDoneHandler(exitcode,bysignal);
    } else {
        ....
    }

So the AOF rewrite was handled in the else branch without actually
checking if the pid really matches. This commit makes the check explicit
and logs at WARNING level if the pid returned by wait3() does not match
neither the RDB or AOF rewrite child.
2012-11-01 22:39:39 +01:00
Yecheng Fu f0266532fc fix typo in comments (redis.c, networking.c) 2012-11-01 22:26:46 +01:00
antirez 2ea41242f6 Unix socket clients properly displayed in MONITOR and CLIENT LIST.
This also fixes issue #745.
2012-11-01 22:10:45 +01:00
antirez d36fb95a10 32 bit build fixed on Linux.
It failed because of the way jemalloc was compiled (without passing the
right flags to make, but just to configure). Now the same set of flags
are also passed to the make command, fixing the issue.

This fixes issue #744
2012-11-01 15:40:48 +01:00
Runzhen Wang c23c657cdd fix a typo in redis.h line 595 comment 2012-11-01 02:14:22 +08:00
Salvatore Sanfilippo 021d16b643 Merge pull request #726 from yamt/typo
fix a typo in a comment
2012-10-31 01:29:04 -07:00
antirez 973cb21a01 Invert two sides of if expression in SET to avoid a lookup.
Because of the short circuit behavior of && inverting the two sides of
the if expression avoids an hash table lookup if the non-EX variant of
SET is called.

Thanks to Weibin Yao (@yaoweibin on github) for spotting this.
2012-10-31 09:23:05 +01:00
antirez b16e423430 No longer used macro rdbIsOpcode() removed. 2012-10-30 19:10:46 +01:00
antirez 08a4f12e76 help.h update (adds bitop, bitcount, evalsha...) 2012-10-30 18:57:20 +01:00
antirez c5cca554d9 Ctrl+w support in linenoise. 2012-10-26 16:06:25 +02:00
antirez 89423052ca Marginally more robust glibc version test for sync_file_range detection. 2012-10-26 15:55:12 +02:00
charsyam 4800331bf8 patch config.h for sync_file_range 2012-10-26 04:27:58 +08:00
antirez d2f83d4a76 Fix compilation on Linux kernels or glibc versions lacking sync_file_range().
This fixes issue #667.

Many thanks to Didier Spezia for the fix.
2012-10-25 22:01:20 +02:00
antirez 68fc64afd4 Update memory peak stats while loading RDB / AOF. 2012-10-24 12:21:41 +02:00
YAMAMOTO Takashi 164d57c60d fix a typo in a comment 2012-10-24 17:47:56 +09:00
antirez 89e74abfb6 A filed called slave_read_only added in INFO output.
This was an important information missing from the INFO output in the
replication section.

It obviously reflects if the slave is read only or not.
2012-10-22 19:21:47 +02:00
Salvatore Sanfilippo ecd82f59fe Merge pull request #693 from ghurrell/dict-h-typos
Fix (cosmetic) typos in dict.h
2012-10-22 02:55:23 -07:00
Schuster e5f794ff3a redis-check-dump now understands dumps produced by Redis 2.6
(Commit message from @antirez as it was missign in the original commits,
also the patch was modified a bit to still work with 2.4 dumps and to
avoid if expressions that are always true due to checked types range)

This commit changes redis-check-dump to account for new encodings and
for the new MSTIME expire format. It also refactors the test for valid
type into a function.

The code is still compatible with Redis 2.4 generated dumps.

This fixes issue #709.
2012-10-22 11:44:20 +02:00
antirez c2661ed761 Default memory limit for 32bit instanced moved from 3.5 GB to 3 GB.
In some system, notably osx, the 3.5 GB limit was too far and not able
to prevent a crash for out of memory. The 3 GB limit works better and it
is still a lot of memory within a 4 GB theorical limit so it's not going
to bore anyone :-)

This fixes issue #711
2012-10-22 10:43:39 +02:00
antirez acfe3675e3 Differentiate SCRIPT KILL error replies.
When calling SCRIPT KILL currently you can get two errors:

* No script in timeout (busy) state.
* The script already performed a write.

It is useful to be able to distinguish the two errors, but right now both
start with "ERR" prefix, so string matching (that is fragile) must be used.

This commit introduces two different prefixes.

-NOTBUSY and -UNKILLABLE respectively to reply with an error when no
script is busy at the moment, and when the script already executed a
write operation and can not be killed.
2012-10-22 10:31:28 +02:00
antirez a1b1c1ea3a Fix MULTI / EXEC rendering in MONITOR output.
Before of this commit it used to be like this:

MULTI
EXEC
... actual commands of the transaction ...

Because after all that is the natural order of things. Transaction
commands are queued and executed *only after* EXEC is called.

However this makes debugging with MONITOR a mess, so the code was
modified to provide a coherent output.

What happens is that MULTI is rendered in the MONITOR output as far as
possible, instead EXEC is propagated only after the transaction is
executed, or even in the case it fails because of WATCH, so in this case
you'll simply see:

MULTI
EXEC

An empty transaction.
2012-10-16 17:35:50 +02:00
antirez be6cbd3a6e Allow AUTH when Redis is busy because of timedout Lua script.
If the server is password protected we need to accept AUTH when there is
a server busy (-BUSY) condition, otherwise it will be impossible to send
SHUTDOWN NOSAVE or SCRIPT KILL.

This fixes issue #708.
2012-10-11 18:34:05 +02:00
Salvatore Sanfilippo d10a01bb6d Merge pull request #707 from NanXiao/patch-1
Update src/redis-benchmark.c
2012-10-10 02:18:14 -07:00
NanXiao 9eb3a7bc6b Update src/redis-benchmark.c
The code of current implementation:

if (c->pending == 0) clientDone(c);
In clientDone function, the c's memory has been freed, then the loop will continue: while(c->pending). The memory of c has been freed now, so c->pending is invalid (c is an invalid pointer now), and this will cause memory dump in some platforams(eg: Solaris).

So I think the code should be modified as:
if (c->pending == 0)
{
clientDone(c);
break;
}
and this will not lead to while(c->pending).
2012-10-10 17:08:43 +08:00
antirez 278304cc4d CONTRIBUTING file updated. 2012-10-06 12:04:27 +02:00
dvir volk 34f37fb7d3 fixed server install script to rewrite the default configuration file and not a template, and removed the old config template
Conflicts:

	utils/redis.conf.tpl
2012-10-05 12:32:58 +02:00
antirez da920e75d4 Hash function switched to murmurhash2.
The previously used hash function, djbhash, is not secure against
collision attacks even when the seed is randomized as there are simple
ways to find seed-independent collisions.

The new hash function appears to be safe (or much harder to exploit at
least) in this case, and has better distribution.

Better distribution does not always means that's better. For instance in
a fast benchmark with "DEBUG POPULATE 1000000" I obtained the following
results:

    1.6 seconds with djbhash
    2.0 seconds with murmurhash2

This is due to the fact that djbhash will hash objects that follow the
pattern `prefix:<id>` and where the id is numerically near, to near
buckets. This improves the locality.

However in other access patterns with keys that have no relation
murmurhash2 has some (apparently minimal) speed advantage.

On the other hand a better distribution should significantly
improve the quality of the distribution of elements returned with
dictGetRandomKey() that is used in SPOP, SRANDMEMBER, RANDOMKEY, and
other commands.

Everything considered, and under the suspect that this commit fixes a
security issue in Redis, we are switching to the new hash function.
If some serious speed regression will be found in the future we'll be able
to step back easiliy.

This commit fixes issue #663.
2012-10-05 11:20:13 +02:00
antirez c43aea7e9f Warn when configured maxmemory value seems odd.
This commit warns the user with a log at "warning" level if:

1) After the server startup the maxmemory limit was found to be < 1MB.
2) After a CONFIG SET command modifying the maxmemory setting the limit
is set to a value that is smaller than the currently used memory.

The behaviour of the Redis server is unmodified, and this wil not make
the CONFIG SET command or a wrong configuration in redis.conf less
likely to create problems, but at least this will make aware most users
about a possbile error they committed without resorting to external
help.

However no warning is issued if, as a result of loading the AOF or RDB
file, we are very near the maxmemory setting, or key eviction will be
needed in order to go under the specified maxmemory setting. The reason
is that in servers configured as a cache with an aggressive
maxmemory-policy most of the times restarting the server will cause this
condition to happen if persistence is not switched off.

This fixes issue #429.
2012-10-05 11:16:22 +02:00
antirez 2b73b3509a Include time.h in ae.c as we now use time(). 2012-10-05 10:10:43 +02:00
Jokea b7b2a1cc5e Force expire all timer events when system clock skew is detected.
When system time changes back, the timer will not worker properly
hence some core functionality of redis will stop working(e.g. replication,
bgsave, etc). See issue #633 for details.

The patch saves the previous time and when a system clock skew is detected,
it will force expire all timers.

Modiifed by @antirez: the previous time was moved into the eventLoop
structure to make sure the library is still thread safe as long as you
use different event loops into different threads (otherwise you need
some synchronization). More comments added about the reasoning at the
base of the patch, that's worth reporting here:

/* If the system clock is moved to the future, and then set back to the
 * right value, time events may be delayed in a random way. Often this
 * means that scheduled operations will not be performed soon enough.
 *
 * Here we try to detect system clock skews, and force all the time
 * events to be processed ASAP when this happens: the idea is that
 * processing events earlier is less dangerous than delaying them
 * indefinitely, and practice suggests it is. */
2012-10-04 19:30:42 +02:00
antirez f0b9f80345 "Timeout receiving bulk data" error message modified.
The new message now contains an hint about modifying the repl-timeout
configuration directive if the problem persists.

This should normally not be needed, because while the master generates
the RDB file it makes sure to send newlines to the replication channel
to prevent timeouts. However there are times when masters running on
very slow systems can completely stop for seconds during the RDB saving
process. In such a case enlarging the timeout value can fix the problem.

See issue #695 for an example of this problem in an EC2 deployment.
2012-10-04 11:52:16 +02:00
antirez 9a914a632d "SORT by nosort" (skip sorting) respect sorted set ordering.
When SORT is called with the option BY set to a string constant not
inclduing the wildcard character "*", there is no way to sort the output
so any ordering is valid. This allows the SORT internals to optimize its
work and don't really sort the output at all.

However it was odd that this option was not able to retain the natural
order of a sorted set. This feature was requested by users multiple
times as sometimes to call SORT with GET against sorted sets as a way to
mass-fetch objects can be handy.

This commit introduces two things:

1) The ability of SORT to return sorted sets elements in their natural
ordering when `BY nosort` is specified, accordingly to `DESC / ASC` options.
2) The ability of SORT to optimize this case further if LIMIT is passed
as well, avoiding to really fetch the whole sorted set, but directly
obtaining the specified range.

Because in this case the sorting is always deterministic, no
post-sorting activity is performed when SORT is called from a Lua
script.

This commit fixes issue #98.
2012-10-03 14:54:43 +02:00
Greg Hurrell 4b1f6ad3e7 Fix (cosmetic) typos in dict.h 2012-10-02 22:01:26 -07:00
antirez ece77037e9 Revert "Scripting: redis.NIL to return nil bulk replies."
This reverts commit e061d797d7.

Conflicts:

	src/scripting.c
2012-10-01 10:10:31 +02:00
antirez 9c21b72bb9 Scripting: add helper functions redis.error_reply() and redis.status_reply().
A previous commit introduced Redis.NIL. This commit adds similar helper
functions to return tables with a single field set to the specified
string so that instead of using 'return {err="My Error"}' it is possible
to use a more idiomatic form:

    return redis.error_reply("My Error")
    return redis.status_reply("OK")
2012-09-28 16:54:57 +02:00
antirez 6dd1693c0e Scripting: redis.NIL to return nil bulk replies.
Lua arrays can't contain nil elements (see
http://www.lua.org/pil/19.1.html for more information), so Lua scripts
were not able to return a multi-bulk reply containing nil bulk
elements inside.

This commit introduces a special conversion: a table with just
a "nilbulk" field set to a boolean value is converted by Redis as a nil
bulk reply, but at the same time for Lua this type is not a "nil" so can
be used inside Lua arrays.

This type is also assigned to redis.NIL, so the following two forms
are equivalent and will be able to return a nil bulk reply as second
element of a three elements array:

    EVAL "return {1,redis.NIL,3}" 0
    EVAL "return {1,{nilbulk=true},3}" 0

The result in redis-cli will be:

    1) (integer) 1
    2) (nil)
    3) (integer) 3
2012-09-28 14:26:20 +02:00
antirez db100c4671 Sentinel: Support for AUTH. 2012-09-26 18:59:54 +02:00
antirez 0ee3f05518 Test for SRANDMEMBER with <count>. 2012-09-21 11:55:36 +02:00
antirez 578c94597f SRANDMEMBER <count> leak fixed.
For "CASE 4" (see code) we need to free the element if it's already in
the result dictionary and adding it failed.
2012-09-21 11:55:32 +02:00
antirez be90c803e3 Added the SRANDMEMBER key <count> variant.
SRANDMEMBER called with just the key argument can just return a single
random element from a Redis Set. However many users need to return
multiple unique elements from a Set, this is not a trivial problem to
handle in the client side, and for truly good performance a C
implementation was required.

After many requests for this feature it was finally implemented.

The problem implementing this command is the strategy to follow when
the number of elements the user asks for is near to the number of
elements that are already inside the set. In this case asking random
elements to the dictionary API, and trying to add it to a temporary set,
may result into an extremely poor performance, as most add operations
will be wasted on duplicated elements.

For this reason this implementation uses a different strategy in this
case: the Set is copied, and random elements are returned to reach the
specified count.

The code actually uses 4 different algorithms optimized for the
different cases.

If the count is negative, the command changes behavior and allows for
duplicated elements in the returned subset.
2012-09-21 11:55:28 +02:00
antirez d310fbedab Fix compilation on FreeBSD. Thanks to @koobs on twitter. 2012-09-17 12:46:06 +02:00
antirez b5b2aceaf6 .gitignore modified to be more general with less entries. 2012-09-17 10:49:48 +02: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 bfc197c3b6 Make sure that SELECT argument is an integer or return an error.
Unfortunately we had still the lame atoi() without any error checking in
place, so "SELECT foo" would work as "SELECT 0". This was not an huge
problem per se but some people expected that DB can be strings and not
just numbers, and without errors you get the feeling that they can be
numbers, but not the behavior.

Now getLongFromObjectOrReply() is used as almost everybody else across
the code, generating an error if the number is not an integer or
overflows the long type.

Thanks to @mipearson for reporting that on Twitter.
2012-09-11 10:32:04 +02:00
antirez 978e5177fd Match printf format with actual type in genRedisInfoString(). 2012-09-10 12:42:55 +02:00
antirez 74e57d0ece BITCOUNT regression test for #582 fixed for 32 bit target.
Bug #582 was not present in 32 bit builds of Redis as
getObjectFromLong() will return an error for overflow.

This commit makes sure that the test does not fail because of the error
returned when running against 32 bit builds.
2012-09-05 17:50:10 +02:00
Haruto Otake 749aac72ad BITCOUNT: fix segmentation fault.
remove unsafe and unnecessary cast.
until now, this cast may lead segmentation fault when end > UINT_MAX

setbit foo 0 1
bitcount  0 4294967295
=> ok
bitcount  0 4294967296
=> cause segmentation fault.

Note by @antirez: the commit was modified a bit to also change the
string length type to long, since it's guaranteed to be at max 512 MB in
size, so we can work with the same type across all the code path.

A regression test was also added.
2012-09-05 16:19:04 +02:00
Salvatore Sanfilippo 24bc807b5c Merge pull request #576 from saj/fix-slave-ping-period
Bug fix: slaves being pinged every second
2012-09-05 06:59:37 -07:00
antirez 36741b2c81 Scripting: Force SORT BY constant determinism inside SORT itself.
SORT is able to return (faster than when ordering) unordered output if
the "BY" clause is used with a constant value. However we try to play
well with scripting requirements of determinism providing always sorted
outputs when SORT (and other similar commands) are called by Lua
scripts.

However we used the general mechanism in place in scripting in order to
reorder SORT output, that is, if the command has the "S" flag set, the
Lua scripting engine will take an additional step when converting a
multi bulk reply to Lua value, calling a Lua sorting function.

This is suboptimal as we can do it faster inside SORT itself.
This is also broken as issue #545 shows us: basically when SORT is used
with a constant BY, and additionally also GET is used, the Lua scripting
engine was trying to order the output as a flat array, while it was
actually a list of key-value pairs.

What we do know is to recognized if the caller of SORT is the Lua client
(since we can check this using the REDIS_LUA_CLIENT flag). If so, and if
a "don't sort" condition is triggered by the BY option with a constant
string, we force the lexicographical sorting.

This commit fixes this bug and improves the performance, and at the same
time simplifies the implementation. This does not mean I'm smart today,
it means I was stupid when I committed the original implementation ;)
2012-09-05 01:17:49 +02:00
antirez 9bd0e097aa Sentinel: reply -IDONTKNOW to get-master-addr-by-name on lack of info.
If we don't have any clue about a master since it never replied to INFO
so far, reply with an -IDONTKNOW error to SENTINEL
get-master-addr-by-name requests.
2012-09-04 16:06:53 +02:00
antirez 8bdde086ac Sentinel: more easy master redirection if master is a slave.
Before this commit Sentienl used to redirect master ip/addr if the
current instance reported to be a slave only if this was the first INFO
output received, and the role was found to be slave.

Now instead also if we find that the runid is different, and the
reported role is slave, we also redirect to the reported master ip/addr.

This unifies the behavior of Sentinel in the case of a reboot (where it
will see the first INFO output with the wrong role and will perform the
redirection), with the behavior of Sentinel in the case of a change in
what it sees in the INFO output of the master.
2012-09-04 15:52:04 +02:00
antirez bb66fc3120 Send an async PING before starting replication with master.
During the first synchronization step of the replication process, a Redis
slave connects with the master in a non blocking way. However once the
connection is established the replication continues sending the REPLCONF
command, and sometimes the AUTH command if needed. Those commands are
send in a partially blocking way (blocking with timeout in the order of
seconds).

Because it is common for a blocked master to accept connections even if
it is actually not able to reply to the slave requests, it was easy for
a slave to block if the master had serious issues, but was still able to
accept connections in the listening socket.

For this reason we now send an asynchronous PING request just after the
non blocking connection ended in a successful way, and wait for the
reply before to continue with the replication process. It is very
unlikely that a master replying to PING can't reply to the other
commands.

This solution was proposed by Didier Spezia (Thanks!) so that we don't
need to turn all the replication process into a non blocking affair, but
still the probability of a slave blocked is minimal even in the event of
a failing master.

Also we now use getsockopt(SO_ERROR) in order to check errors ASAP
in the event handler, instead of waiting for actual I/O to return an
error.

This commit fixes issue #632.
2012-09-02 12:24:38 +02:00
antirez e323635c2d Scripting: Reset Lua fake client reply_bytes after command execution.
Lua scripting uses a fake client in order to run commands in the context
of a client, accumulate the reply, and convert it into a Lua object
to return to the caller. This client is reused again and again, and is
referenced by the server.lua_client globally accessible pointer.

However after every call to redis.call() or redis.pcall(), that is
handled by the luaRedisGenericCommand() function, the reply_bytes field
of the client was not set back to zero. This filed is used to estimate
the amount of memory currently used in the reply. Because of the lack of
reset, script after script executed, this value used to get bigger and
bigger, and in the end on 32 bit systems it triggered the following
assert:

    redisAssert(c->reply_bytes < ULONG_MAX-(1024*64));

On 64 bit systems this does not happen because it takes too much time to
reach values near to 2^64 for users to see the practical effect of the
bug.

Now in the cleanup stage of luaRedisGenericCommand() we reset the
reply_bytes counter to zero, avoiding the issue. It is not practical to
add a test for this bug, but the fix was manually tested using a
debugger.

This commit fixes issue #656.
2012-08-31 11:15:02 +02:00
antirez 46c31a150a Scripting: require at least one argument for redis.call().
Redis used to crash with a call like the following:

    EVAL "redis.call()" 0

Now the explicit check for at least one argument prevents the problem.

This commit fixes issue #655.
2012-08-31 10:28:13 +02:00
antirez 6276434ad2 Sentinel: do not crash against slaves not publishing the runid.
Older versions of Redis (before 2.4.17) don't publish the runid field in
INFO. This commit makes Sentinel able to handle that without crashing.
2012-08-30 18:01:52 +02:00
antirez 58186b9dcf Sentinel: INFO command implementation. 2012-08-29 12:44:24 +02:00
antirez 8246e58abe Sentinel: add Redis execution mode to INFO output.
The new "redis_mode" field in the INFO output will show if Redis is
running in standalone mode, cluster, or sentinel mode.
2012-08-29 11:44:01 +02:00
antirez 712656e848 Sentinel: added documentation about slave-priority in redis.conf 2012-08-28 17:53:18 +02:00
antirez 3ec701e059 Sentinel: Sentinel-side support for slave priority.
The slave priority that is now published by Redis in INFO output is
now used by Sentinel in order to select the slave with minimum priority
for promotion, and in order to consider slaves with priority set to 0 as
not able to play the role of master (they will never be promoted by
Sentinel).

The "slave-priority" field is now one of the fileds that Sentinel
publishes when describing an instance via the SENTINEL commands such as
"SENTINEL slaves mastername".
2012-08-28 17:45:01 +02:00
antirez 169a44cbd6 Sentinel: Redis-side support for slave priority.
A Redis slave can now be configured with a priority, that is an integer
number that is shown in INFO output and can be get and set using the
redis.conf file or the CONFIG GET/SET command.

This field is used by Sentinel during slave election. A slave with lower
priority is preferred. A slave with priority zero is never elected (and
is considered to be impossible to elect even if it is the only slave
available).

A next commit will add support in the Sentinel side as well.
2012-08-28 17:20:26 +02:00
antirez c14e0ecafd Sentinel: suppress harmless warning by initializing 'table' to NULL.
Note that the assertion guarantees that one of the if branches setting
table is always entered.
2012-08-28 12:56:05 +02:00
antirez 784b93087c Incrementally flush RDB on disk while loading it from a master.
This fixes issue #539.

Basically if there is enough free memory the OS may buffer the RDB file
that the slave transfers on disk from the master. The file may
actually be flused on disk at once by the operating system when it gets
closed by Redis, causing the close system call to block for a long time.

This patch is a modified version of one provided by yoav-steinberg of
@garantiadata (the original version was posted in the issue #539
comments), and tries to flush the OS buffers incrementally (every 8 MB
of loaded data).
2012-08-28 12:47:33 +02:00
antirez 1caa627e4e Fix a forget zmalloc_oom() -> zmalloc_oom_handler() replacement. 2012-08-24 15:40:22 +02:00
antirez 6fdc635447 Better Out of Memory handling.
The previous implementation of zmalloc.c was not able to handle out of
memory in an application-specific way. It just logged an error on
standard error, and aborted.

The result was that in the case of an actual out of memory in Redis
where malloc returned NULL (In Linux this actually happens under
specific overcommit policy settings and/or with no or little swap
configured) the error was not properly logged in the Redis log.

This commit fixes this problem, fixing issue #509.
Now the out of memory is properly reported in the Redis log and a stack
trace is generated.

The approach used is to provide a configurable out of memory handler
to zmalloc (otherwise the default one logging the event on the
standard output is used).
2012-08-24 12:55:37 +02:00
antirez 850789ce73 Sentinel: send SCRIPT KILL on -BUSY reply and SDOWN instance.
From the point of view of Redis an instance replying -BUSY is down,
since it is effectively not able to reply to user requests. However
a looping script is a recoverable condition in Redis if the script still
did not performed any write to the dataset. In that case performing a
fail over is not optimal, so Sentinel now tries to restore the normal server
condition killing the script with a SCRIPT KILL command.

If the script already performed some write before entering an infinite
(or long enough to timeout) loop, SCRIPT KILL will not work and the
fail over will be triggered anyway.
2012-08-24 12:29:54 +02:00
antirez 01477753e6 Sentinel: fixed a crash on script execution.
The call to sentinelScheduleScriptExecution() lacked the final NULL
argument to signal the end of arguments. This resulted into a crash.
2012-08-24 12:10:24 +02:00
Salvatore Sanfilippo 724371d748 Merge pull request #628 from pietern/unstable-zip
Fix ziplist edge case
2012-08-22 02:32:27 -07:00
antirez 227b429364 redis-benchmark: disable big buffer cleanup in hiredis context.
This new hiredis features allows us to reuse a previous context reader
buffer even if already very big in order to maximize performances with
big payloads (Usually hiredis re-creates buffers when they are too big
and unused in order to save memory).
2012-08-21 17:31:44 +02:00
antirez d6704c9bd0 hiredis library updated.
This version of hiredis merges modifications of the Redis fork with
latest changes in the hiredis repository.

The same version was pushed on the hiredis repository and will probably
merged into the master branch in short time.
2012-08-21 17:27:01 +02:00
Pieter Noordhuis 3cc2904e3e Set p to its new offset before modifying it 2012-08-13 14:13:09 -07:00
Pieter Noordhuis 5117c20ab5 Add ziplist test for deleting next to last entries 2012-08-13 14:09:40 -07:00
antirez cada7f9671 Sentinel: SENTINEL FAILOVER command implemented.
This command can be used in order to force a Sentinel instance to start
a failover for the specified master, as leader, forcing the failover
even if the master is up.

The commit also adds some minor refactoring and other improvements to
functions already implemented that make them able to work when the
master is not in SDOWN condition. For instance slave selection
assumed that we ask INFO every second to every slave, this is true
only when the master is in SDOWN condition, so slave selection did not
worked when the master was not in SDOWN condition.
2012-08-03 12:41:27 +02:00
antirez 6275004ca6 Sentinel: client reconfiguration script execution.
This commit adds support to optionally execute a script when one of the
following events happen:

* The failover starts (with a slave already promoted).
* The failover ends.
* The failover is aborted.

The script is called with enough parameters (documented in the example
sentinel.conf file) to provide information about the old and new ip:port
pair of the master, the role of the sentinel (leader or observer) and
the name of the master.

The goal of the script is to inform clients of the configuration change
in a way specific to the environment Sentinel is running, that can't be
implemented in a genereal way inside Sentinel itself.
2012-08-02 18:40:30 +02:00
Salvatore Sanfilippo 2990c366e8 Merge pull request #613 from tobstarr/patch-1
Fix version numbers
2012-08-02 05:37:10 -07:00
Tobias Schwab 2dccf1e4ce Fix version numbers 2012-08-02 15:10:51 +03:00
antirez fd92b366b0 Sentinel: when leader in wait-start, sense another leader as race.
When we are in wait start, if another leader (or any other external
entity) turns a slave into a master, abort the failover, and detect it
as an observer.

Note that the wait-start state is mainly there for this reason but the
abort was yet not implemented.

This adds a new sentinel event -failover-abort-race.
2012-07-31 17:11:26 +02:00
antirez 91c15ed1b5 Sentinel: sentinelRefreshInstanceInfo() comments improved a bit. 2012-07-31 16:18:15 +02:00
Michael Parker f1d187bb3e Use correct variable name for value to convert.
Note by @antirez: this code was never compiled because utils.c lacked the
float.h include, so we never noticed this variable was mispelled in the
past.

This should provide a noticeable speed boost when saving certain types
of databases with many sorted sets inside.
2012-07-31 11:48:00 +02:00
antirez ed2a691aba Sentinel: sentinel.conf self-documenation improved. 2012-07-31 11:05:21 +02:00
antirez 75084e057d Sentinel: abort failover when in wait-start if master is back.
When we are a Leader Sentinel in wait-start state, starting with this
commit the failover is aborted if the master returns online.

This improves the way we handle a notable case of net split, that is the
split between Sentinels and Redis servers, that will be a very common
case of split becase Sentinels will often be installed in the client's
network and servers can be in a differnt arm of the network.

When Sentinels and Redis servers are isolated the master is in ODOWN
condition since the Sentinels can agree about this state, however the
failover does not start since there are no good slaves to promote (in
this specific case all the slaves are unreachable).

However when the split is resolved, Sentinels may sense the slave back
a moment before they sense the master is back, so the failover may start
without a good reason (since the master is actually working too).

Now this condition is reversible, so the failover will be aborted
immediately after if the master is detected to be working again, that
is, not in SDOWN nor in ODOWN condition.
2012-07-31 10:19:34 +02:00
antirez 7f5bdba434 Merge remote-tracking branch 'origin/unstable' into unstable 2012-07-28 20:55:17 +02:00
antirez 3f194a9d25 Sentinel: scripts execution engine improved.
We no longer use a vanilla fork+execve but take a queue of jobs of
scripts to execute, with retry on error, timeouts, and so forth.

Currently this is used only for notifications but soon the ability to
also call clients reconfiguration scripts will be added.
2012-07-28 20:54:27 +02:00
Jeremy Zawodny 78b606acc2 comment fix
improve English a bit. :-)
2012-07-28 20:54:26 +02:00
Salvatore Sanfilippo f3a6143199 Merge pull request #606 from badboy/patch-1
Include sys/wait.h to avoid compiler warning
2012-07-28 02:51:56 -07:00
Jan-Erik Rediger c6c19c8372 Include sys/wait.h to avoid compiler warning
gcc warned about an implicit declaration of function 'wait3'. 
Including this header fixes this.
2012-07-28 12:33:01 +03:00
Salvatore Sanfilippo ed7b308c1c Merge pull request #587 from saj/truncate-short-write-from-aof
Truncate short write from the AOF
2012-07-27 03:56:48 -07:00
Salvatore Sanfilippo 04950a9e4d Merge pull request #586 from saj/aof_last_bgrewrite_status
New in INFO: aof_last_bgrewrite_status
2012-07-27 03:55:20 -07:00
antirez ce7b838fb9 Sentinel: don't start a failover as leader if there is no good slave. 2012-07-26 12:09:40 +02:00
Salvatore Sanfilippo a3593ee4d0 Merge pull request #604 from jzawodn/patch-1
comment fix
2012-07-25 08:31:57 -07:00
Jeremy Zawodny 7617a6f272 comment fix
improve English a bit. :-)
2012-07-25 08:29:11 -07:00
antirez baace5fc42 Sentinel: ability to execute notification scripts. 2012-07-25 16:33:37 +02:00
Salvatore Sanfilippo 42c571864e Merge pull request #603 from mrb/fix_sentinel_config_warning
Fix warning in redis.c for sentinel config load
2012-07-25 07:15:53 -07:00
Salvatore Sanfilippo 7c15dd1596 Merge pull request #602 from mrb/sentinel_docs
Some cleanup in sentinel.conf
2012-07-25 07:15:02 -07:00
mrb f1c8661e74 Fix warning in redis.c for sentinel config load 2012-07-25 09:55:53 -04:00
mrb 23023fc626 Some cleanup in sentinel.conf 2012-07-25 09:52:26 -04:00
antirez 672102c2ce Sentinel: abort failover if no good slave is available.
The previous behavior of the state machine was to wait some time and
retry the slave selection, but this is not robust enough against drastic
changes in the conditions of the monitored instances.

What we do now when the slave selection fails is to abort the failover
and return back monitoring the master. If the ODOWN condition is still
present a new failover will be triggered and so forth.

This commit also refactors the code we use to abort a failover.
2012-07-25 11:32:19 +02:00
antirez 9e5bef38e6 Sentinel: reset pending_commands in a more generic way. 2012-07-24 18:57:26 +02:00
antirez a23a5b6c7d Prevent a spurious +sdown event on switch.
When we reset the master we should start with clean timestamps for ping
replies otherwise we'll detect a spurious +sdown event, because on
+master-switch event the previous master instance was probably in +sdown
condition. Since we updated the address we should count time from
scratch again.

Also this commit makes sure to explicitly reset the count of pending
commands, now we can do this because of the new way the hiredis link
is closed.
2012-07-24 18:46:04 +02:00
antirez d918e6f127 Sentinel: debugging message removed. 2012-07-24 18:20:05 +02:00
antirez 75fb6e5b8a Sentinel: changes to connection handling and redirection.
We disconnect the Redis instances hiredis link in a more robust way now.
Also we change the way we perform the redirection for the +switch-master
event, that is not just an instance reset with an address change.

Using the same system we now implement the +redirect-to-master event
that is triggered by an instance that is configured to be master but
found to be a slave at the first INFO reply. In that case we monitor the
master instead, logging the incident as an event.
2012-07-24 18:15:44 +02:00
antirez 2179c26916 Sentinel: check that instance still exists in reply callbacks.
We can't be sure the instance object still exists when the reply
callback is called.
2012-07-24 16:37:57 +02:00
antirez d876d6feac Sentinel: more robust failover detection as observer.
Sentinel observers detect failover checking if a slave attached to the
monitored master turns into its replication state from slave to master.
However while this change may in theory only happen after a SLAVEOF NO
ONE command, in practie it is very easy to reboot a slave instance with
a wrong configuration that turns it into a master, especially if it was
a past master before a successfull failover.

This commit changes the detection policy so that if an instance goes
from slave to master, but at the same time the runid has changed, we
sense a reboot, and in that case we don't detect a failover at all.

This commit also introduces the "reboot" sentinel event, that is logged
at "warning" level (so this will trigger an admin notification).

The commit also fixes a problem in the disconnect handler that assumed
that the instance object always existed, that is not the case. Now we
no longer assume that redisAsyncFree() will call the disconnection
handler before returning.
2012-07-24 12:42:40 +02:00
antirez 1bbdf1709f Fixed an error in the example sentinel.conf. 2012-07-23 15:08:36 +02:00
antirez be2be3d903 Typo. 2012-07-23 15:06:55 +02:00
antirez 6b5daa2df2 First implementation of Redis Sentinel.
This commit implements the first, beta quality implementation of Redis
Sentinel, a distributed monitoring system for Redis with notification
and automatic failover capabilities.

More info at http://redis.io/topics/sentinel
2012-07-23 13:14:44 +02:00
antirez 03f412ddef Merge remote-tracking branch 'origin/unstable' into unstable 2012-07-22 17:18:42 +02:00
antirez 5d73073f6e Allow Pub/Sub in contexts where other commands are blocked.
Redis loading data from disk, and a Redis slave disconnected from its
master with serve-stale-data disabled, are two conditions where
commands are normally refused by Redis, returning an error.

However there is no reason to disable Pub/Sub commands as well, given
that this layer does not interact with the dataset. To allow Pub/Sub in
as many contexts as possible is especially interesting now that Redis
Sentinel uses Pub/Sub of a Redis master as a communication channel
between Sentinels.

This commit allows Pub/Sub to be used in the above two contexts where
it was previously denied.
2012-07-22 17:18:16 +02:00
Salvatore Sanfilippo cddf5946fc Merge pull request #593 from steevel/unstable
Check that we have connection before enabling pipe mode
2012-07-21 11:12:35 -07:00
antirez b62bdf1c64 Don't assume that "char" is signed.
For the C standard char can be either signed or unsigned, it's up to the
compiler, but Redis assumed that it was signed in a few places.

The practical effect of this patch is that now Redis 2.6 will run
correctly in every system where char is unsigned, notably the RaspBerry
PI and other ARM systems with GCC.

Thanks to Georgi Marinov (@eesn on twitter) that reported the problem
and allowed me to use his RaspBerry via SSH to trace and fix the issue!
2012-07-18 12:04:58 +02:00
Saj Goonatilleke 55302e9e28 Truncate short write from the AOF
If Redis only manages to write out a partial buffer, the AOF file won't
load back into Redis the next time it starts up.  It is better to
discard the short write than waste time running redis-check-aof.
2012-07-18 10:35:17 +10:00
Saj Goonatilleke 48553a29e8 New in INFO: aof_last_bgrewrite_status
Behaves like rdb_last_bgsave_status -- even down to reporting 'ok' when
no rewrite has been done yet.  (You might want to check that
aof_last_rewrite_time_sec is not -1.)
2012-07-18 09:54:55 +10:00
Steeve Lennmark e9828cb6f7 Check that we have connection before enabling pipe mode 2012-07-15 14:35:02 +02:00
Salvatore Sanfilippo a2db8e4801 Merge pull request #569 from jokea/unstable
mark fd as writable when EPOLLERR or EPOLLHUP is returned by epoll_wait.
2012-07-09 03:14:08 -07:00
Saj Goonatilleke 9edfe63553 Bug fix: slaves being pinged every second
REDIS_REPL_PING_SLAVE_PERIOD controls how often the master should
transmit a heartbeat (PING) to its slaves.  This period, which defaults
to 10, is measured in seconds.

Redis 2.4 masters used to ping their slaves every ten seconds, just like
it says on the tin.

The Redis 2.6 masters I have been experimenting with, on the other hand,
ping their slaves *every second*.  (master_last_io_seconds_ago never
approaches 10.)  I think the ping period was inadvertently slashed to
one-tenth of its nominal value around the time REDIS_HZ was introduced.
This commit reintroduces correct ping schedule behaviour.
2012-07-05 14:29:27 +10:00
jokea 93b0075d33 mark fd as writable when EPOLLERR or EPOLLHUP is returned by epoll_wait. 2012-06-29 12:06:38 +08:00
antirez 36def8fd9a Typo in comment. 2012-06-27 11:26:44 +02:00
antirez 3a32897856 REPLCONF internal command introduced.
The REPLCONF command is an internal command (not designed to be directly
used by normal clients) that allows a slave to set some replication
related state in the master before issuing SYNC to start the
replication.

The initial motivation for this command, and the only reason currently
it is used by the implementation, is to let the slave instance
communicate its listening port to the slave, so that the master can
show all the slaves with their listening ports in the "replication"
section of the INFO output.

This allows clients to auto discover and query all the slaves attached
into a master.

Currently only a single option of the REPLCONF command is supported, and
it is called "listening-port", so the slave now starts the replication
process with something like the following chat:

    REPLCONF listening-prot 6380
    SYNC

Note that this works even if the master is an older version of Redis and
does not understand REPLCONF, because the slave ignores the REPLCONF
error.

In the future REPLCONF can be used for partial replication and other
replication related features where there is the need to exchange
information between master and slave.

NOTE: This commit also fixes a bug: the INFO outout already carried
information about slaves, but the port was broken, and was obtained
with getpeername(2), so it was actually just the ephemeral port used
by the slave to connect to the master as a client.
2012-06-27 09:43:57 +02:00
antirez 5410168c6e Fixed comment typo into time_independent_strcmp(). 2012-06-21 14:25:53 +02:00
antirez 31a1439bfd Fixed a timing attack on AUTH (Issue #560).
The way we compared the authentication password using strcmp() allowed
an attacker to gain information about the password using a well known
class of attacks called "timing attacks".

The bug appears to be practically not exploitable in most modern systems
running Redis since even using multiple bytes of differences in the
input at a time instead of one the difference in running time in in the
order of 10 nanoseconds, making it hard to exploit even on LAN. However
attacks always get better so we are providing a fix ASAP.

The new implementation uses two fixed length buffers and a constant time
comparison function, with the goal of:

1) Completely avoid leaking information about the content of the
password, since the comparison is always performed between 512
characters and without conditionals.
2) Partially avoid leaking information about the length of the
password.

About "2" we still have a stage in the code where the real password and
the user provided password are copied in the static buffers, we also run
two strlen() operations against the two inputs, so the running time
of the comparison is a fixed amount plus a time proportional to
LENGTH(A)+LENGTH(B). This means that the absolute time of the operation
performed is still related to the length of the password in some way,
but there is no way to change the input in order to get a difference in
the execution time in the comparison that is not just proportional to
the string provided by the user (because the password length is fixed).

Thus in practical terms the user should try to discover LENGTH(PASSWORD)
looking at the whole execution time of the AUTH command and trying to
guess a proportionality between the whole execution time and the
password length: this appears to be mostly unfeasible in the real world.

Also protecting from this attack is not very useful in the case of Redis
as a brute force attack is anyway feasible if the password is too short,
while with a long password makes it not an issue that the attacker knows
the length.
2012-06-21 11:50:01 +02:00
antirez 5b63ccce6c Fix c->reply_bytes computation in setDeferredMultiBulkLength()
In order to implement reply buffer limits introduced in 2.6 and useful
to close the connection under user-selected circumastances of big output
buffers (for instance slow consumers in pub/sub, a blocked slave, and so
forth) Redis takes a counter with the amount of used memory in objects
inside the output list stored into c->reply.

The computation was broken in the function setDeferredMultiBulkLength(),
in the case the object was glued with the next one. This caused the
c->reply_bytes field to go out of sync, be subtracted more than needed,
and wrap back near to ULONG_MAX values.

This commit fixes this bug and adds an assertion that is able to trap
this class of problems.

This problem was discovered looking at the INFO output of an unrelated
issue (issue #547).
2012-06-15 10:03:25 +02:00
antirez ba779119b8 ziplistFind(): don't assume that entries are comparable by encoding.
Because Redis 2.6 introduced new integer encodings it is no longer true
that if two entries have a different encoding they are not equal.

An old ziplist can be loaded from an RDB file generated with Redis 2.4,
in this case for instance a small unsigned integers is encoded with a
16 bit encoding, while in Redis 2.6 a more specific 8 bit encoding
format is used.

Because of this bug hashes ended with duplicated values or fields lookup
failed, causing many bad behaviors.
This in turn caused a crash while converting the ziplist encoded hash into
a real hash table because an assertion was raised on duplicated elements.

This commit fixes issue #547.

Many thanks to Pinterest's Marty Weiner and colleagues for discovering
the problem and helping us in the debugging process.
2012-06-14 16:01:27 +02:00
Salvatore Sanfilippo 96b8ff3760 Merge pull request #552 from tnm/unstable
Standardize punctuation in redis-cli help.
2012-06-13 01:25:52 -07:00
Ted Nyman d665dd0865 Standardize punctuation in redis-cli help.
Right there is a mix of help entries ending with periods or
without periods. This standardizes the end of command as without
periods, which seems to be the general custom in most unix tools,
at least.
2012-06-12 22:35:00 -07:00
antirez 84d9ef4f31 Added a new hash fuzzy tester.
The new fuzzy tester also removes elements from the hash instead of just
adding random fields. This should increase the probability to find bugs
in the implementations of the hash type internal representations.
2012-06-12 15:21:54 +02:00
antirez ee789e157c Dump ziplist hex value on failed assertion.
The ziplist -> hashtable conversion code is triggered every time an hash
value must be promoted to a full hash table because the number or size of
elements reached the threshold.

If a problem in the ziplist causes the same field to be present
multiple times, the assertion of successful addition of the element
inside the hash table will fail, crashing server with a failed
assertion, but providing little information about the problem.

This code adds a new logging function to perform the hex dump of binary
data, and makes sure that the ziplist -> hashtable conversion code uses
this new logging facility to dump the content of the ziplist when the
assertion fails.

This change was originally made in order to investigate issue #547.
2012-06-12 00:41:48 +02:00
antirez c0de45924c New test: hash ziplist -> hashtable encoding conversion.
A new stress test was added to stress test the code converting a ziplist
into an hash table.

In this commit also randomValue helper function was modified to also
return negative values.
2012-06-11 15:19:46 +02:00
antirez 80e808b6d6 EVAL replication test: less false positives.
wait_for_condition is now used instead of the usual "after 1000" (that
is the way to sleep in Tcl). This should avoid to find the replica in
a state where it is loading the RDB in memory, returning -LOADING error.

This test used to fail when running the test over valgrind, due to the
added latencies.
2012-06-02 23:29:57 +02:00
Alex Mitrofanov 51857c7e5c Fixed RESTORE hash failure (Issue #532)
(additional commit notes by antirez@gmail.com):

The rdbIsObjectType() macro was not updated when the new RDB object type
of ziplist encoded hashes was added.

As a result RESTORE, that uses rdbLoadObjectType(), failed when a
ziplist encoded hash was loaded.
This does not affected normal RDB loading because in that case we use
the lower-level function rdbLoadType().

The commit also adds a regression test.
2012-06-02 10:24:27 +02:00
antirez c7a25200e2 RDB type loading functions clarified in comments.
Improved comments to make clear that rdbLoadType() just loads a
general TYPE in the context of RDB that can be an object type or an
expire type, end-of-file, and so forth.

While rdbLoadObjectType() enforces that the type is a valid Object Type
otherwise it returns -1.
2012-06-02 10:21:57 +02:00
antirez 1419406e8d BITOP bug when called against non existing keys fixed.
In the issue #529 an user reported a bug that can be triggered with the
following code:

flushdb
set a
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
bitop or x a b

The bug was introduced with the speed optimization in commit 8bbc076
that specializes every BITOP operation loop up to the minimum length of
the input strings.

However the computation of the minimum length contained an error when a
non existing key was present in the input, after a key that was non zero
length.

This commit fixes the bug and adds a regression test for it.
2012-05-31 21:52:47 +02:00
antirez bc70b8e5f4 Tests modified to account for INFO fields renaming.
Commit 33e1db36fa modified the name of a
few INFO fields. This commit changes the Redis test to account for this
changes.
2012-05-25 15:20:59 +02:00
antirez 33e1db36fa Four new persistence fields in INFO. A few renamed.
The 'persistence' section of INFO output now contains additional four
fields related to RDB and AOF persistence:

 rdb_last_bgsave_time_sec       Duration of latest BGSAVE in sec.
 rdb_current_bgsave_time_sec    Duration of current BGSAVE in sec.
 aof_last_rewrite_time_sec      Duration of latest AOF rewrite in sec.
 aof_current_rewrite_time_sec   Duration of current AOF rewrite in sec.

The 'current' fields are set to -1 if a BGSAVE / AOF rewrite is not in
progress. The 'last' fileds are set to -1 if no previous BGSAVE / AOF
rewrites were performed.

Additionally a few fields in the persistence section were renamed for
consistency:

 changes_since_last_save -> rdb_changes_since_last_save
 bgsave_in_progress -> rdb_bgsave_in_progress
 last_save_time -> rdb_last_save_time
 last_bgsave_status -> rdb_last_bgsave_status
 bgrewriteaof_in_progress -> aof_rewrite_in_progress
 bgrewriteaof_scheduled -> aof_rewrite_scheduled

After the renaming, fields in the persistence section start with rdb_ or
aof_ prefix depending on the persistence method they describe.
The field 'loading' and related fields are not prefixed because they are
unique for both the persistence methods.
2012-05-25 12:11:30 +02:00
antirez d866803818 BITOP command 10x speed improvement.
This commit adds a fast-path to the BITOP that can be used for all the
bytes from 0 to the minimal length of the string, and if there are
at max 16 input keys.

Often the intersected bitmaps are roughly the same size, so this
optimization can provide a 10x speed boost to most real world usages
of the command.

Bytes are processed four full words at a time, in loops specialized
for the specific BITOP sub-command, without the need to check for
length issues with the inputs (since we run this algorithm only as far
as there is data from all the keys at the same time).

The remaining part of the string is intersected in the usual way using
the slow but generic algorith.

It is possible to do better than this with inputs that are not roughly
the same size, sorting the input keys by length, by initializing the
result string in a smarter way, and noticing that the final part of the
output string composed of only data from the longest string does not
need any proecessing since AND, OR and XOR against an empty string does
not alter the output (zero in the first case, and the original string in
the other two cases).

More implementations will be implemented later likely, but this should
be enough to release Redis 2.6-RC4 with bitops merged in.

Note: this commit also adds better testing for BITOP NOT command, that
is currently the faster and hard to optimize further since it just
flips the bits of a single input string.
2012-05-24 15:20:20 +02:00
antirez fa4a5d5922 BITOP: handle integer encoded objects correctly.
A bug in the implementation caused BITOP to crash the server if at least
one one of the source objects was integer encoded.

The new implementation takes an additional array of Redis objects
pointers and calls getDecodedObject() to get a reference to a string
encoded object, and then uses decrRefCount() to release the object.

Tests modified to cover the regression and improve coverage.
2012-05-24 15:20:16 +02:00
antirez 7c34643f15 BITCOUNT performance improved.
At Redis's default optimization level the command is now much faster,
always using a constant-time bit manipualtion technique to count bits
instead of GCC builtin popcount, and unrolling the loop.

The current implementation performance is 1.5GB/s in a MBA 11" (1.8 Ghz
i7) compiled with both GCC and clang.

The algorithm used is described here:

http://graphics.stanford.edu/~seander/bithacks.html
2012-05-24 15:20:11 +02:00
antirez 80f8028e3c bitop.c renamed bitops.c
bitop.c contains the "Bit related string operations" so it seems more
logical to call it bitops instead of bitop.
This also makes it matching the name of the test (unit/bitops.tcl).
2012-05-24 15:20:06 +02:00
antirez 01d3a7e736 Bit operations tests improved.
Fuzzing tests of BITCOUNT / BITOP are iterated multiple times.
The new BITCOUNT fuzzing test uses random strings in a wider interval of
lengths including zero-len strings.
2012-05-24 15:20:02 +02:00
antirez 343d3bd287 popcount() optimization for speed.
We run the array by 32 bit words instead of processing it byte per byte.
If the code is compiled using GCC __builtin_popcount() builtin function
is used instead.
2012-05-24 15:19:58 +02:00
antirez dbbbe49ef5 BITCOUNT refactoring.
The low level popualtion counting function is now separated from the
BITCOUNT command implementation, so that the low level function can be
further optimized and eventually used in other contexts if needed.
2012-05-24 15:19:55 +02:00
antirez 760e776526 Bit-related string operations moved to bitop.c
All the general string operations are implemented in t_string.c, however
the bit operations, while targeting the string type, are better served
in a specific file where we have the implementations of the following
four commands and helper functions:

    GETBIT
    SETBIT
    BITOP
    BITCOUNT

In the future this file will probably contain more code related to
making the BITOP and BITCOUNT operations faster.
2012-05-24 15:19:51 +02:00
antirez a3f2b4895b BITOP and BITCOUNT tests.
The Redis implementation is tested against Tcl implementations of the
same operation. Both fuzzing and testing of specific aspects of the
commands behavior are performed.
2012-05-24 15:19:48 +02:00
antirez 0bd6d68e34 New commands: BITOP and BITCOUNT.
The motivation for this new commands is to be search in the usage of
Redis for real time statistics. See the article "Fast real time metrics
using Redis".

http://blog.getspool.com/2011/11/29/fast-easy-realtime-metrics-using-redis-bitmaps/

In general Redis strings when used as bitmaps using the SETBIT/GETBIT
command provide a very space-efficient and fast way to store statistics.
For instance in a web application with users, every user can be
associated with a key that shows every day in which the user visited the
web service. This information can be really valuable to extract user
behaviour information.

With Redis bitmaps doing this is very simple just saying that a given
day is 0 (the data the service was put online) and all the next days are
1, 2, 3, and so forth. So with SETBIT it is possible to set the bit
corresponding to the current day every time the user visits the site.

It is possible to take the count of the bit sets on the run, this is
extremely easy using a Lua script. However a fast bit count native
operation can be useful, especially if it can operate on ranges, or when
the string is small like in the case of days (even if you consider many
years it is still extremely little data).

For this reason BITOP was introduced. The command counts the number of
bits set to 1 in a string, with optional range:

BITCOUNT key [start end]

The start/end parameters are similar to GETRANGE. If omitted the whole
string is tested.

Population counting is more useful when bit-level operations like AND,
OR and XOR are avaialble. For instance I can test multiple users to see
the number of days three users visited the site at the same time. To do
this we can take the AND of all the bitmaps, and then count the set bits.

For this reason the BITOP command was introduced:

BITOP [AND|OR|XOR|NOT] dest_key src_key1 src_key2 src_key3 ... src_keyN

In the special case of NOT (that inverts the bits) only one source key
can be passed.

The judicious use of BITCOUNT and BITOP combined can lead to interesting
use cases with very space efficient representation of data.

The implementation provided is still not tested and optimized for speed,
next commits will introduce unit tests. Later the implementation will be
profiled to see if it is possible to gain an important amount of speed
without making the code much more complex.
2012-05-24 15:19:43 +02:00
antirez 6f05a65336 Add aof_rewrite_buffer_length INFO field.
The INFO output, persistence section, already contained the field
describing the size of the current AOF buffer to flush on disk. However
the other AOF buffer, used to accumulate changes during an AOF rewrite,
was not mentioned in the INFO output.

This commit introduces a new field called aof_rewrite_buffer_length with
the length of the rewrite buffer.
2012-05-24 15:19:18 +02:00
antirez 47ca4b6e28 Allow an AOF rewrite buffer > 2GB (Fix for issue #504).
During the AOF rewrite process, the parent process needs to accumulate
the new writes in an in-memory buffer: when the child will terminate the
AOF rewriting process this buffer (that ist the difference between the
dataset when the rewrite was started, and the current dataset) is
flushed to the new AOF file.

We used to implement this buffer using an sds.c string, but sds.c has a
2GB limit. Sometimes the dataset can be big enough, the amount of writes
so high, and the rewrite process slow enough that we overflow the 2GB
limit, causing a crash, documented on github by issue #504.

In order to prevent this from happening, this commit introduces a new
system to accumulate writes, implemented by a linked list of blocks of
10 MB each, so that we also avoid paying the reallocation cost.

Note that theoretically modern operating systems may implement realloc()
simply as a remaping of the old pages, thus with very good performances,
see for instance the mremap() syscall on Linux. However this is not
always true, and jemalloc by default avoids doing this because there are
issues with the current implementation of mremap().

For this reason we are using a linked list of blocks instead of a single
block that gets reallocated again and again.

The changes in this commit lacks testing, that will be performed before
merging into the unstable branch. This fix will not enter 2.4 because it
is too invasive. However 2.4 will log a warning when the AOF rewrite
buffer is near to the 2GB limit.
2012-05-24 15:19:15 +02:00
antirez ef37997608 Dead code removed from replication.c.
The user @jokea noticed that the following line of code into
replication.c made little sense:

    addReplySds(slave,sdsempty());

Investigating a bit I found that this was introduced by commit 6208b3a7
three years ago in the early stages of Redis. The code apparently is not
useful at all, so I'm removing it.

This change will not be backported into 2.4 so that in the rare case
this should introduce a bug, we'll have a chance to detect it into the
development branch. However following the code path it seems like the
code is not useful at all, so the risk is truly small.
2012-05-24 11:35:21 +02:00
jokea e150ce3ce6 Set fd to writable when poll(2) detects POLLERR or POLLHUP event. 2012-05-23 11:33:32 +02:00
antirez 348ee1a40a Fixed issue #516 (ZINTERSTORE mixing sets and zsets).
Weeks ago trying to fix an harmless GCC warning I introduced a bug in
the ziplist-encoded implementations of sorted sets.

The bug completely broke zuiNext() iterator, that is used in the
ZINTERSTORE and ZUNIONSTORE implementation, so those two commands are no
longer reliable starting from Redis version 2.4.12 and latest 2.6.0-RC
releases.

This commit fixes the problem and adds a regression test.
2012-05-23 11:12:43 +02:00
antirez 2bcd18a2e9 Redis test: include bug report on crash.
Due to a change in the format of the bug report in case of crash of
failed assertion the test suite was no longer able to properly log it.
Instead just a protocol error was logged by the Redis TCL client that
provided no clue about the actual problem.

This commit resolves the issue by logging everything from the first line
of the log including the string REDIS BUG REPORT, till the end of the
file.
2012-05-22 13:13:24 +02:00
antirez 5a55999304 Use comments to split aof.c into sections.
This makes the code more readable, it is still not the case to split the
file itself into three different files, but the logical separation
improves the readability especially since new commits are going to
introduce an additional section.
2012-05-21 16:50:05 +02:00
antirez d44a36e006 TODO file removed.
The list of things to do is since long time in two places:

1) Github issues.
2) I've a private TOOD list of random ideas, what makes sense is later
moved to github issues. So github is anyway the true source of things to
do.
2012-05-20 23:49:08 +02:00
antirez d165f78561 Deleted jemalloc.orig from /deps.
In the commit upgrading jemalloc to version 3.0.0 I added the old
version of Jemalloc in the 'jemalloc.orig' directory for an error.
This commit removes the not useful version of jemalloc.
2012-05-16 12:23:45 +02:00
antirez ad4c0b4117 Jemalloc updated to 3.0.0.
Full changelog here:

http://www.canonware.com/cgi-bin/gitweb.cgi?p=jemalloc.git;a=blob_plain;f=ChangeLog;hb=master

Notable improvements from the point of view of Redis:

1) Bugfixing.
2) Support for Valgrind.
3) Support for OSX Lion, FreeBSD.
2012-05-16 11:09:45 +02:00
Pieter Noordhuis 3c72c94aae Whitespace 2012-05-15 11:19:01 +02:00
Dave Pacheco 6d31277048 use port_getn instead of port_get 2012-05-15 11:18:58 +02:00
Dave Pacheco 05da63da0c first cut at event port support 2012-05-15 11:18:54 +02:00
Pieter Noordhuis f16d090c72 Fix install target on OSX (see #495) 2012-05-15 11:18:50 +02:00
antirez e9f0419c99 Added time.h include in redis-cli.
redis-cli.c uses the time() function to seed the PRNG, but time.h was
not included. This was not noticed since sys/time.h is included and was
enough in most systems (but not correct). With Ubuntu 12.04 GCC
generates a warning that made us aware of the issue.
2012-05-14 17:35:51 +02:00
antirez b3624f5a16 activeExpireCycle(): better precision in max time used.
activeExpireCycle() can consume no more than a few milliseconds per
iteration. This commit improves the precision of the check for the time
elapsed in two ways:

1) We check every 16 iterations instead of the main loop instead of 256.
2) We reset iterations at the start of the function and not every time
   we switch to the next database, so the check is correctly performed
   every 16 iterations.
2012-05-14 16:04:41 +02:00
antirez 61daf8914d Impovements for: Redis timer, hashes rehashing, keys collection.
A previous commit introduced REDIS_HZ define that changes the frequency
of calls to the serverCron() Redis function. This commit improves
different related things:

1) Software watchdog: now the minimal period can be set according to
REDIS_HZ. The minimal period is two times the timer period, that is:

    (1000/REDIS_HZ)*2 milliseconds

2) The incremental rehashing is now performed in the expires dictionary
as well.

3) The activeExpireCycle() function was improved in different ways:

- Now it checks if it already used too much time using microseconds
  instead of milliseconds for better precision.
- The time limit is now calculated correctly, in the previous version
  the division was performed before of the multiplication resulting in
  a timelimit of 0 if HZ was big enough.
- Databases with less than 1% of buckets fill in the hash table are
  skipped, because getting random keys is too expensive in this
  condition.

4) tryResizeHashTables() is now called at every timer call, we need to
   match the number of calls we do to the expired keys colleciton cycle.

5) REDIS_HZ was raised to 100.
2012-05-13 21:52:35 +02:00
antirez 9434349236 Redis timer interrupt frequency configurable as REDIS_HZ.
Redis uses a function called serverCron() that is very similar to the
timer interrupt of an operating system. This function is used to handle
a number of asynchronous things, like active expired keys collection,
clients timeouts, update of statistics, things related to the cluster
and replication, triggering of BGSAVE and AOF rewrite process, and so
forth.

In the past the timer was called 1 time per second. At some point it was
raised to 10 times per second, but it still was fixed and could not be
changed even at compile time, because different functions called from
serverCron() assumed a given fixed frequency.

This commmit makes the frequency configurable, so that it is simpler to
pick a good tradeoff between overhead of this function (that is usually
very small) and the responsiveness of Redis during a few critical
circumstances where a lot of work is done inside the timer.

An example of such a critical condition is mass-expire of a lot of keys
in the same second. Up to a given percentage of CPU time is used to
perform expired keys collection per expire cylce. Now changing the
REDIS_HZ macro it is possible to do less work but more times per second
in order to block the server for less time.

If this patch will work well in our tests it will enter Redis 2.6-final.
2012-05-13 16:40:29 +02:00
antirez f333788fbc Comment improved so that the code goal is more clear. Thx to @agladysh. 2012-05-11 22:33:28 +02:00
antirez 1dcc95d081 More incremental active expired keys collection process.
If a large amonut of keys are all expiring about at the same time, the
"active" expired keys collection cycle used to block as far as the
percentage of already expired keys was >= 25% of the total population of
keys with an expire set.

This could block the server even for many seconds in order to reclaim
memory ASAP. The new algorithm uses at max a small amount of
milliseconds per cycle, even if this means reclaiming the memory less
promptly it also means a more responsive server.
2012-05-11 19:17:31 +02:00
antirez 27737964c4 If the computer running the Redis test is slow, we revert to --clients 1 to avoid false positives. 2012-05-11 17:26:16 +02:00
antirez ea66be6080 redis-cli pipe mode: handle EINTR properly as well so that SIGSTOP/SIGCONT are handled correctly. 2012-05-11 16:08:57 +02:00
antirez f6bd9122c0 redis-cli pipe mode: handle EAGAIN while writing to socket. 2012-05-11 10:45:12 +02:00
antirez 8c6301462b Fix PREFIX typo in Makefile. 2012-05-09 20:45:19 +02:00
antirez b26808a532 Allow PREFIX to be overrided in Makefile. 2012-05-09 10:34:52 +02:00
antirez 088c508abc redis-cli --pipe for mass import. 2012-05-07 16:37:18 +02:00
Pieter Noordhuis bf21941686 Compare integers in ziplist regardless of encoding
Because of the introduction of new integer encoding types for ziplists
in the 2.6 tree, the same integer value may have a different encoding in
different versions of the ziplist implementation. This means that the
encoding can NOT be used as a fast path in comparing integers.
2012-05-06 10:06:21 +02:00
Salvatore Sanfilippo abf54ee73c Merge pull request #494 from quiver/init-fixes
fix several bugs of init.d scripts
2012-05-04 04:41:02 -07:00
quiver c4286feabe fix several bugs of init.d scripts
- PIDFILE environ variable was not properly retrieved
- chkconfig command failed
2012-05-04 20:07:00 +09:00
antirez af3853c3bf syncio.c read / write functions reworked for correctness and performance.
The new implementation start reading / writing before blocking with
aeWait(), likely the descriptor can accept writes or has buffered data
inside and we can go faster, otherwise we get an error and wait.

This change has effects on speed but also on correctness: on socket
errors when we perform non blocking connect(2) write is performed ASAP
and the error is returned ASAP before waiting.

So the practical effect is that now a Redis slave is more available if it
can not connect to the master, previously the slave continued to block on
syncWrite() trying to send SYNC, and serving commands very slowly.
2012-05-02 22:41:50 +02:00
antirez 299290d3a4 Remove useless trailing space in SYNC command sent to master. 2012-05-02 21:47:53 +02:00
antirez ae62d29d1d Use specific error if master is down and slave-serve-stale-data is set to no.
We used to reply -ERR ... message ..., now the reply is
instead -MASTERDOWN ... message ... so that it can be distinguished
easily by the other error conditions.
2012-05-02 20:57:55 +02:00
antirez 92997d06ea Test "Turning off AOF kills the background writing child if any" is now more reliable. 2012-05-02 11:40:46 +02:00
Pieter Noordhuis cc4f65fea4 Use safe dictionary iterator from KEYS
Every matched key in a KEYS call is checked for expiration. When the key
is set to expire, the call to `getExpire` will assert that the key also
exists in the main dictionary. This in turn causes a rehashing step to
be executed. Rehashing a dictionary when there is an iterator active may
result in the iterator emitting duplicate entries, or not emitting some
entries at all. By using a safe iterator, the rehash step is omitted.
2012-05-01 10:52:03 +02:00
Harmen 2ac546e00c Show problem with 'keys' command with specific command sequence. 2012-05-01 10:51:59 +02:00
antirez d9241b35e5 Properly wait the slave to sync with master in BRPOPLPUSH test. 2012-04-30 10:55:03 +02:00
antirez 2d4b55214f A more lightweight implementation of issue 141 regression test. 2012-04-29 17:16:44 +02:00
antirez ffe003dcbe memtest.c fixed to actually use v1 and v2 in memtest_fill_value(). 2012-04-27 16:29:44 +02:00
antirez 841048f2c8 redis-cli commands description in help.h updated. 2012-04-27 15:57:27 +02:00
antirez 0ad10db220 Set LUA_MASKCOUNT hook more selectively. Fixes issue #480.
An user reported a crash with Redis scripting (see issue #480 on
github), inspection of the kindly provided strack trace showed that
server.lua_caller was probably set to NULL. The stack trace also slowed
that the call to the hook was originating from a point where we just
used to set/get a few global variables in the Lua state.

What was happening is that we did not set the timeout hook selectively
only when the user script was called. Now we set it more selectively,
specifically only in the context of the lua_pcall() call, and make sure
to remove the hook when the call returns. Otherwise the hook can get
called in random contexts every time we do something with the Lua
state.
2012-04-27 11:41:25 +02:00
antirez a3eb7ac87d Re-introduce -g -rdynamic -ggdb when linking, fixing strack traces.
A previous commit removed -g -rdynamic -ggdb as LDFLAGS, not allowing
Redis to produce a stack trace wth symbol names on crash.
This commit fixes the issue.
2012-04-26 16:53:11 +02:00
antirez 11bd247d2b Produce the stack trace in an async safe way. 2012-04-26 16:28:54 +02:00
antirez 3ada43e732 Don't use an alternative stack for SIGSEGV & co.
This commit reverts most of c575766202, in
order to use back main stack for signal handling.

The main reason is that otherwise it is completely pointless that we do
a lot of efforts to print the stack trace on crash, and the content of
the stack and registers as well. Using an alternate stack broken this
feature completely.
2012-04-26 16:21:19 +02:00
antirez 28ccb53008 Redis test: More reliable BRPOPLPUSH replication test.
Now it uses the new wait_for_condition testing primitive.
Also wait_for_condition implementation was fixed in this commit to properly
escape the expr command and its argument.
2012-04-26 11:25:13 +02:00
antirez 57356b80cd Merge remote-tracking branch 'origin/unstable' into unstable 2012-04-26 11:17:47 +02:00
antirez 5080e625d3 Redis test: scripting EVALSHA replication test more reliable.
A new primitive wait_for_condition was introduced in the scripting
engine that makes waiting for events simpler, so that it is simpler to
write tests that are more resistant to timing issues.
2012-04-26 11:16:52 +02:00
Salvatore Sanfilippo d445988c68 Merge pull request #481 from dtran320/unstable
Spelling: s/synchrnonization/synchronization
2012-04-25 13:39:13 -07:00
David Tran 31788f50b7 Spelling: s/synchrnonization/synchronization 2012-04-25 12:21:56 -07:00
antirez d9237055ba Explicitly use bash for install_server.sh. Fixes issue #397 2012-04-24 19:14:03 +02:00
antirez 29c8cf0116 redis-check-dump now is RDB version 6 ready. 2012-04-24 19:05:27 +02:00
antirez 7dbc514de7 Spurious debugging printf removed. 2012-04-24 17:15:21 +02:00
antirez a76b9063d0 Added two new encodings to ziplist.c
1) One integer "immediate" encoding that can encode from 0 to 12 in the
encoding byte itself.
2) One 8 bit signed integer encoding that can encode 8 bit signed small
integers in a single byte.

The idea is to exploit all the not used bits we have around in a
backward compatible way.
2012-04-24 17:04:00 +02:00
antirez 053d56a1fa rdbLoad() should check REDIS_RDB_VERSION instead of hardcoded number. 2012-04-24 12:53:30 +02:00
antirez f22cff43a6 ziplist.c: added comments about the new 24 bit encoding. 2012-04-24 12:52:36 +02:00
Grisha Trubetskoy 5a86ab4799 Add a 24bit integer to ziplists to save one byte for ints that can
fit in 24 bits (thanks to antirez for catching and solving the two's compliment
bug).

Increment REDIS_RDB_VERSION to 6
2012-04-24 12:02:19 +02:00
antirez 21661d7acc Fixed a bug in propagation of PUBLISH via the cluster bus.
This bug was spotted by clang on FreeBSD.
2012-04-24 11:28:10 +02:00
antirez e54fe9a79f A few compiler warnings suppressed. 2012-04-24 11:11:55 +02:00
antirez a66a496349 Fix and refactoring of code used to get registers on crash.
This fixes compilation on FreeBSD (and possibly other systems) by
not using ucontext_t at all if HAVE_BACKTRACE is not defined.
Also the ifdefs to get the registers are modified to explicitly test for the
operating system in the first level, and the arch in the second level
of nesting.
2012-04-24 11:11:35 +02:00
antirez c4a4755286 Ziplist encoding now tested with negative integers as well. 2012-04-23 17:27:46 +02:00
Salvatore Sanfilippo d344228734 Merge pull request #421 from ErikDubbelboer/sds-const
Added consts keyword where possible
2012-04-23 02:34:19 -07:00
Salvatore Sanfilippo c22e0eecd5 Merge pull request #461 from schlenk/unstable
Replace some unnecessary calls to echo and cat in tests
2012-04-23 02:07:21 -07:00
antirez 4e7cc35f1a New time limit for protocol desync test set to 30 seconds to reduce false positives. 2012-04-23 10:57:43 +02:00
antirez a3f990818d Remove loadfile() access from the scripting engine. 2012-04-23 10:43:24 +02:00
antirez eb6e7eb94d Even inside #if 0 comments are comments. 2012-04-21 21:49:21 +02:00
antirez 92cc20ecfe Merge remote-tracking branch 'origin/unstable' into unstable 2012-04-21 20:35:51 +02:00
antirez d3701d2714 Limit memory used by big SLOWLOG entries.
Two limits are added:

1) Up to SLOWLOG_ENTRY_MAX_ARGV arguments are logged.
2) Up to SLOWLOG_ENTRY_MAX_STRING bytes per argument are logged.
3) slowlog-max-len is set to 128 by default (was 1024).

The number of remaining arguments / bytes is logged in the entry
so that the user can understand better the nature of the logged command.
2012-04-21 20:34:45 +02:00
Salvatore Sanfilippo 7d3ee4172f Merge pull request #440 from ErikDubbelboer/spelling
Fixed some spelling errors in comments
2012-04-21 03:31:06 -07:00
Salvatore Sanfilippo 28d1ee2cda Merge pull request #414 from chobits/unstable
fix typos in tests/assets/default.conf
2012-04-21 03:27:15 -07:00
antirez fd72fe261d README now makes clear that our support for solaris derived systems is "best effort". 2012-04-21 12:08:26 +02:00
antirez 60e2e5b50d redis.conf AOF section comments improved. 2012-04-20 00:04:07 +02:00
antirez 47db53c3c3 New tests related to scripts max execution time. 2012-04-19 23:49:33 +02:00
antirez e3923a3508 SHUTDOWN NOSAVE now can stop a non returning script. Issue #466. 2012-04-19 23:35:15 +02:00
antirez 1e35ae7486 Currenly not used code in dict.c commented out. 2012-04-18 23:56:07 +02:00
antirez 5498e7bc76 Tests for scripting PRNG. 2012-04-18 23:50:16 +02:00
antirez 5386f72d00 redis-cli --bigkeys output modified to be simpler to read.. 2012-04-18 20:53:37 +02:00
antirez f26761aa10 redis-cli --bigkeys 2012-04-18 20:33:02 +02:00
antirez cddfd67ed4 Test SDIFF with first set empty. 2012-04-18 18:13:31 +02:00
antirez 4264459141 Test SINTER against same integer elements, but different set encoding. 2012-04-18 18:10:48 +02:00
antirez f800942f64 Test SINTER with non existing key. 2012-04-18 18:05:02 +02:00
antirez 88f77a2b7e Added an SMOVE test where src and dest key are the same. 2012-04-18 18:00:12 +02:00
antirez e51a218aaa New hash fuzzing test. 2012-04-18 17:56:17 +02:00
antirez 5ba79bda7f Document mostly dead code in RPOPLPUSH implementation. 2012-04-18 17:38:02 +02:00
antirez 79daddd5ba Explicit RPOP/LPOP tests. 2012-04-18 17:32:48 +02:00
antirez 7aa0dfd014 Test LINSERT syntax error. 2012-04-18 17:22:14 +02:00
antirez 94e5c1d7e5 Test LINDEX out of range index. 2012-04-18 17:17:53 +02:00
Salvatore Sanfilippo d162f9eb64 Merge pull request #456 from pietern/unstable-mkopts
Persist Makefile flags (unstable)
2012-04-18 07:25:59 -07:00
antirez acf41c96cb Marginally cleaner lookupKeyByPattern() implementation.
just fieldobj itself as sentinel of the fact a field object is used or
not, instead of using the filed length, that may be confusing both for
people and for the compiler emitting a warning.
2012-04-18 11:37:14 +02:00
antirez 8ec9b03c6b More robust maxclients test. 2012-04-18 11:34:18 +02:00
antirez a5f8341245 Two small fixes to maxclients handling.
1) Don't accept maxclients set to < 0
2) Allow maxclients < 1024, it is useful for testing.
2012-04-18 11:31:24 +02:00
Michael Schlenker 875944a23f Replace unnecessary calls to echo and cat
Tcl's exec can send data to stdout itself, no need to call cat/echo for
that usually.
2012-04-17 22:20:54 +02:00
antirez 6a3f0ac68a Added test for SORT corner case: pattern ending with just "->". 2012-04-17 16:28:59 +02:00
antirez 3c25c4a691 lookupKeyByPattern() used by SORT GET/BY rewritten. Fixes issue #460.
lookupKeyByPattern() was implemented with a trick to speedup the lookup
process allocating two fake Redis obejcts on the stack. However now that
we propagate expires to the slave as DEL operations the lookup of the
key may result into a call to expireIfNeeded() having the stack
allocated object as argument, that may in turn use it to create the
protocol to send to the slave. But since this fake obejcts are
inherently read-only this is a problem.

As a side effect of this fix there are no longer size limits in the
pattern to be used with GET/BY option of SORT.

See https://github.com/antirez/redis/issues/460 for bug details.
2012-04-17 13:05:09 +02:00
antirez 0705ff3f04 Less false positives in maxclients test, hopefully. 2012-04-17 10:04:42 +02:00
Pieter Noordhuis 7e7b69fee1 Persist make settings and trigger rebuild if anything changes 2012-04-13 17:52:33 -07:00
Pieter Noordhuis 34c943b395 Don't set flags recursively 2012-04-13 17:52:33 -07:00
Pieter Noordhuis 620357fc8f Remove unused LIBS variable 2012-04-13 17:52:33 -07:00
Pieter Noordhuis caba585121 First set defaults, then do composition 2012-04-13 17:52:33 -07:00
Pieter Noordhuis c04278ba3b Question mark assignment is not needed 2012-04-13 17:52:33 -07:00
Pieter Noordhuis 166cf8a3b8 Ignore gcov/lcov artifacts 2012-04-13 17:52:33 -07:00
Pieter Noordhuis 0342dd7647 The lcov target shouldn't clean
This is not needed because every change in compiler/linker flags
triggers a cleanup.
2012-04-13 17:52:30 -07:00
Pieter Noordhuis 631539a5f2 Rename ADD_*FLAGS -> REDIS_*FLAGS, REDIS_*FLAGS -> FINAL_*FLAGS
This reflects that REDIS_*FLAGS will only be used for compilation of
Redis and not for its dependencies. Similarly, that FINAL_*FLAGS are
composed of other variables and holds the options that are finally
passed to the compiler and linker.
2012-04-13 17:34:31 -07:00
antirez 93a74949d7 Merge branch 'strict.lua' into unstable 2012-04-13 16:16:13 +02:00
antirez c18405c909 A few var names fixed in Makefile.
I modified it for error in a previous commit doing search & replace.
2012-04-13 16:13:56 +02:00
antirez 13a21caae3 New test for scripting engine: DECR_IF_GT. 2012-04-13 15:23:32 +02:00
antirez 6f659f34cf EVAL errors are more clear now. 2012-04-13 15:12:16 +02:00
antirez 3a02140415 Use Lua tostring() before concatenation. 2012-04-13 14:54:49 +02:00
antirez 3cd4ad267c Tests modified to match the new global protection implementation. 2012-04-13 13:40:57 +02:00
antirez d86c4a7bf0 mt.declared is no longer needed.
Lua global protection can now be simpified becuase we no longer have the
global() function. It's useless to occupy memory with this table, it is
also not faster because the metamethods we use are only called when a
global object does not exist or we are trying to create it from a
script.
2012-04-13 13:36:08 +02:00
antirez 6663653f51 Stop access to global vars. Not configurable.
After considering the interaction between ability to delcare globals in
scripts using the 'global' function, and the complexities related to
hanlding replication and AOF in a sane way with globals AND ability to
turn protection On and Off, we reconsidered the design. The new design
makes clear that there is only one good way to write Redis scripts, that
is not using globals. In the rare cases state must be retained across
calls a Redis key can be used.
2012-04-13 13:26:59 +02:00
antirez c9edd1b28a Globals protection global() function modified for speed and correctness. 2012-04-13 12:13:02 +02:00
antirez 2fd7c9efde Tests for lua globals protection. 2012-04-13 11:48:45 +02:00
antirez 37b29ef2fa Scripting: globals protection can now be switched on/off. 2012-04-13 11:23:45 +02:00
antirez 6e05f333a2 Print arch bits with redis-server -v 2012-04-12 11:50:18 +02:00
antirez 4c442e9d88 memtest.c: integer overflow fixed. 2012-04-12 11:49:52 +02:00
antirez 91e56965a3 Make gcov fixed. 2012-04-12 11:51:58 +02:00
antirez 9c83aec955 Makefile now introduces Redis-specific CFLAGS / LDFLAGS. Gcov target fixed. Added comments to describe how it works. 2012-04-12 11:09:38 +02:00
Salvatore Sanfilippo 0d83011a11 Merge pull request #449 from ErikDubbelboer/unstable
added explanation for the magic 511 backlog number
2012-04-11 09:25:44 -07:00
Erik Dubbelboer 815c06f2f7 added explanation for the magic 511 backlog number 2012-04-11 17:04:31 +02:00
antirez ced068955d Makefile.dep updated. 2012-04-11 12:12:30 +02:00
antirez a470689d2e make dep: redirect output to Makefile.dep. 2012-04-11 12:12:05 +02:00
antirez c44ab51da1 Make inline functions rioRead/Write/Tell static. This fixes issue #447. 2012-04-11 11:58:32 +02:00
antirez d98b03b791 Macros ULONG_ONEZERO / ULONG_ZEROONE were inverted in #ifdef to test 32/64 bit arch. 2012-04-11 11:32:22 +02:00
Pieter Noordhuis 0a08d2b0e5 Clean up Makefiles
Remove unused variables. Instead of overriding non-standard variables
such as ARCH and PROF, use standard variables CFLAGS and LDFLAGS to
override Makefile settings. Move dependencies generated by `make dep` to
a separate file.
2012-04-11 11:24:17 +02:00
Pieter Noordhuis 3f7438ef9b Everything x86 is little endian 2012-04-11 11:03:30 +02:00
antirez f2f2ba1b3a Comment typo fixed. Clusetr -> Cluster. 2012-04-11 10:57:02 +02:00
antirez 0b913c650d Check write(2) return value to avoid warnings, because in this context failing write is not critical. 2012-04-10 16:48:28 +02:00
antirez a3fb7fd4f6 Minor MIGRATE implementation simplification about ttl handling. 2012-04-10 16:46:29 +02:00
antirez 0882715710 Version 2.9.7. 2012-04-10 16:34:33 +02:00
antirez 84bcd3aa24 It is now possible to enable/disable RDB checksum computation from redis.conf or via CONFIG SET/GET. Also CONFIG SET support added for rdbcompression as well. 2012-04-10 15:47:10 +02:00
antirez 82e32055d8 RDB files now embed a crc64 checksum. Version of RDB bumped to 5. 2012-04-09 22:40:41 +02:00
antirez 8491f1d9fd Fixed compilation of new rio.c changes (typos and so forth.) 2012-04-09 12:36:44 +02:00
antirez 46738646d4 dump/restore fixed to use the new crc64 API. 2012-04-09 12:33:57 +02:00
antirez 736b7c3f04 Add checksum computation to rio.c 2012-04-09 12:33:09 +02:00
antirez 88c1d9550d crc64.c modified for incremental computation. 2012-04-09 12:20:47 +02:00
antirez 5a181d43cb rio.c file somewhat documented so that the casual reader can understand what's going on without reading the code. 2012-04-09 11:11:00 +02:00
antirez a3af8d8e49 Test for maxclients. 2012-04-08 11:16:40 +02:00
Erik Dubbelboer e1d9857b12 Update src/rdb.c 2012-04-07 15:48:30 +03:00
Erik Dubbelboer 8d16e7a3c6 Update src/dict.c 2012-04-07 15:45:53 +03:00
Erik Dubbelboer 65fd32ab0a Fixed some spelling errors in the comments 2012-04-07 14:40:29 +02:00
antirez 69e7958918 Added new test to check that "CONFIG appendonly no" actually kills the background AOF operation in progress if any. 2012-04-07 13:22:04 +02:00
antirez 2cbdab903f For coverage testing use exit() instead of _exit() when termiating saving children. 2012-04-07 12:11:23 +02:00
antirez 4ce22375f4 Tests for MONITOR. 2012-04-07 11:26:24 +02:00
antirez 09f66a0be8 New client info field added to CLIENT LIST output: multi, containing the length of the current pipeline. Test modified accordingly. 2012-04-07 11:14:52 +02:00
antirez 4cb8bb2952 Never used function stringObjectEqualsMs() removed. 2012-04-07 02:10:48 +02:00
antirez f02aa7bb79 Removed dead code: function rdbSaveTime() is no longer used since RDB now saves expires in milliseconds. 2012-04-07 02:03:29 +02:00
antirez 0daf7a2d16 Two new tests for BGREWRTIEAOF.
Check for scheduled rewrite if a BGSAVAE is in progress.
Check for error if a rewrite is already in progress.
2012-04-06 23:52:53 +02:00
antirez ff79ab71db redis.tcl: no longer leave unread replies if an error happens during a MULTI/EXEC block. 2012-04-06 23:52:28 +02:00
antirez 618a922957 New INFO field in persistence section: bgrewriteaof_scheduled. 2012-04-06 21:12:50 +02:00
antirez 321a724da5 version bumped to 2.9.6 2012-04-06 12:27:17 +02:00
jokea 3e1e1ac27d implement aeWait using poll(2). Fixes issue #267. 2012-04-06 11:47:17 +02:00
antirez 70381bbf82 expireGenericCommand(): better variable names and a top-comment that describes the function's behavior. 2012-04-05 15:52:08 +02:00
Premysl Hruby c6bf4a0034 for (p)expireat use absolute time, without double recomputation 2012-04-05 15:46:21 +02:00
Premysl Hruby d48d1309c6 fix mstime() ommited while comparing if key is already expired 2012-04-05 15:46:15 +02:00
Premysl Hruby c35b4e845b add support for generation of lcov coverage reports 2012-04-05 12:23:35 +02:00
Salvatore Sanfilippo 0934a4df93 Merge pull request #430 from anydot/f-testsuite
Two changes of testsuite (killing redis and new option)
2012-04-05 01:56:12 -07:00
Salvatore Sanfilippo d84f776e87 Merge pull request #426 from anydot/fix-rm-vm-comments
remove mentions of VM in comments
2012-04-05 01:54:09 -07:00
Salvatore Sanfilippo 0d5f4ba7cd Merge pull request #431 from anydot/f-signal
allocate alternate signal stack, change of sigaction flags for sigterm
2012-04-05 01:52:40 -07:00
Premysl Hruby ebba7b3c92 future-proof version comparison 2012-04-05 10:41:28 +02:00
antirez 459e2975f4 On slow computers, 10 seconds are not enough for this heavy replication test. 2012-04-04 19:54:23 +02:00
antirez 4b8c966140 Structure field controlling the INFO field master_link_down_since_seconds initialized correctly to avoid strange INFO output at startup when a slave has yet to connect to its master. 2012-04-04 18:32:22 +02:00
antirez 5ad1faa090 New "os" field in INFO output providing information about the operating system. 2012-04-04 15:38:13 +02:00
antirez bb0fbc840d SLAVEOF is not a write command. 2012-04-04 15:11:30 +02:00
antirez 9a322ab730 Print milliseconds of the current second in log lines timestamps. Sometimes precise timing is very important for debugging. 2012-04-04 15:11:17 +02:00
Premysl Hruby c575766202 allocate alternate signal stack, change of sigaction flags for sigterm 2012-04-03 17:40:31 +02:00
antirez 1ad4d50805 redis-cli help.h updated. Script to generate it updated as well. 2012-04-03 15:30:33 +02:00
antirez 15113dcd3d More MIGRATE tests. 2012-04-03 15:10:51 +02:00
antirez 12e91892a0 Another fix for MIGRATE. 2012-04-03 15:10:42 +02:00
Premysl Hruby 9184f8fd00 in kill_server send the signal once, then wait for up to 5sec before sending lethal SIGKILL 2012-04-03 14:20:52 +02:00
Premysl Hruby 7cc17ed8ff new option for choosing number of test clients to run 2012-04-03 14:20:52 +02:00
antirez 84e5684bca Two fixed for MIGRATE: fix TTL propagation and fix transferring of data bigger than 64k. 2012-04-03 12:17:40 +02:00
antirez e7957ca628 When the user-provided 'maxclients' value is too big for the max number of files we can open, at least try to search the max the OS is allowing (in steps of 256 filedes). 2012-04-03 11:53:45 +02:00
antirez 06e178708e MIGRATE test modified because the implementation changed. 2012-04-02 16:38:59 +02:00
antirez 31f2ecf436 MIGRATE now let the client distinguish I/O errors and timeouts from other erros. 2012-04-02 16:38:24 +02:00
antirez f8ea19e539 DUMP/RESTORE now use CRC64 instead of truncated SHA1. 2012-04-02 13:10:39 +02:00
antirez 9510d65dc8 CRC64 implementation added to Redis code base. 2012-04-02 12:31:44 +02:00
Premysl Hruby 8918de9202 remove mentions of VM in comments 2012-04-02 11:56:03 +02:00
antirez ab8232d022 DUMP, RESTORE, MIGRATE tests. 2012-04-02 11:44:25 +02:00
antirez 70d848e1fa RESTORE ability to set a TTL fixed, bug introduced with millisecond expires. 2012-04-02 11:14:47 +02:00
antirez a149ce6875 Prettify source code of create/verify DUMP payload. 2012-04-02 10:52:39 +02:00
antirez bd04465931 DUMP / RESTORE: store RDB version in little endian. 2012-04-02 10:46:24 +02:00
antirez 4de6c9a055 New DUMP format includes RDB version and truncated SHA1 checksum. 2012-04-01 12:51:40 +02:00
antirez 2281f90c9b Merge remote-tracking branch 'origin/unstable' into unstable 2012-04-01 10:15:07 +02:00
Salvatore Sanfilippo a7138a4cf8 Merge pull request #425 from ThePicard/unstable
chkconfig in install_server.sh doesn't work because of a typo
2012-04-01 01:14:52 -07:00
ThePicard b0c6ee1d1d Fixed a typo in install_server.sh 2012-03-31 23:39:58 -07:00
antirez d0ace5a314 Write RDB magic using a REDIS_RDB_VERSION define that is defined inside rdb.h 2012-03-31 17:08:40 +02:00
antirez 609ea08445 redis-trib: fix the MIGRATE call that now has milliseconds timeout (were seconds before). 2012-03-31 11:28:37 +02:00
antirez 9157549fad syncio.c calls in replication.c fixed for the new millisecond timeout API. 2012-03-31 11:23:30 +02:00
antirez 04d360fdcd Better syncio.c with millisecond resolution. 2012-03-31 11:21:45 +02:00
Erik Dubbelboer 0a2ff52eae Added consts keyword where possible 2012-03-30 21:19:51 +02:00
antirez c2672a06cd Purely aesthetic code change. 2012-03-30 10:39:34 +02:00
Joseph Jang f892797e1b Fixed a memory leak with replication
occurs when two or more dbs are replicated and at least one of them is >db10
2012-03-30 10:34:29 +02:00
antirez 22c9c4076b Regression test for issue 417 (memory leak when replicating to DB with id >= 10) 2012-03-30 10:26:07 +02:00
Xiaochen Wang f2305046ef fix typos in tests/assets/default.conf 2012-03-29 18:23:04 +08:00
antirez 0cdecca141 Protect globals access in Lua scripting. 2012-03-29 12:02:28 +02:00
antirez 4cba71e898 Fixed typo in comment: "te" -> "the". 2012-03-29 09:33:29 +02:00
antirez 179e54d2a9 Fix for slaves chains. Force resync of slaves (simply disconnecting them) when SLAVEOF turns a master into a slave. 2012-03-29 09:24:02 +02:00
antirez 6aa2f98938 Test for redis.sha1hex(). 2012-03-28 20:47:50 +02:00
Nathan Fritz 52ae8af807 added redis.sha1hex(string) as lua scripting function.
(The original implementation was modified by @antirez to conform Redis
coding standards.)
2012-03-28 20:37:40 +02:00
antirez 5471b8babd Fixes for redisLogFromHandler(). 2012-03-28 13:51:23 +02:00
antirez a7d12cbaf1 Log from signal handlers is now safer. 2012-03-28 13:45:39 +02:00
antirez 1043c8064b Merge branch 'watchdog' into unstable 2012-03-28 13:16:19 +02:00
antirez 0fefb5bbeb Redis test: regexp to check if valgrind reported errors modified. Now we no longer look at the total count because this includes "possibly lost" bytes that are not interesting for Redis (tons of false positives because of how sds.c works). 2012-03-28 10:55:17 +02:00
Salvatore Sanfilippo e4669c045d Merge pull request #389 from huangz1990/patch-1
fix typo
2012-03-27 14:00:08 -07:00
Salvatore Sanfilippo 44f26aea0c Merge pull request #407 from anydot/fixes
Fixes around time usage
2012-03-27 13:58:24 -07:00
Premysl Hruby b57dbdbba3 remove disk-store related comments 2012-03-27 18:46:51 +02:00
Premysl Hruby 8af9fe841c declare hashDictType as external too 2012-03-27 18:18:57 +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
Premysl Hruby 024f213b12 fix time() instead of mstime() in expireIfNeeded 2012-03-27 17:31:21 +02:00
antirez d174eed5d7 define zlibc_free() in a way that is not shadowed by jemalloc. 2012-03-27 16:54:53 +02:00
antirez 23c0cdd2ad Produce the watchlog warning log in a way that is safer from a signal handler. Fix a memory leak in the backtrace generation function. 2012-03-27 15:24:33 +02:00
antirez aa96122d96 Mask SIGALRM everything but in the main thread.
This is required to ensure that the signal will be delivered to the main
thread when the watchdog timer expires.
2012-03-27 13:48:57 +02:00
antirez a354da9acd Correctly set the SIGARLM timer for the software watchdog. 2012-03-27 12:11:37 +02:00
antirez 39bd025c29 Redis software watchdog. 2012-03-27 11:47:51 +02:00
antirez a323870450 SIGSEGV handler refactored so that we can reuse stack trace and current client logging functionalities in other contexts. 2012-03-27 10:40:07 +02:00
antirez ca09ad4d64 CONFIG RESETSTAT resets two more fields. 2012-03-25 11:43:19 +02:00
antirez c1d01b3c57 New INFO field aof_delayed_fsync introduced.
This new field counts all the times Redis is configured with AOF enabled and
fsync policy 'everysec', but the previous fsync performed by the
background thread was not able to complete within two seconds, forcing
Redis to perform a write against the AOF file while the fsync is still
in progress (likely a blocking operation).
2012-03-25 11:27:35 +02:00
antirez 512f682340 convert-zipmap-hash-on-load false positive fixed.
Apparently because the sample RDB file was not copied before every test
Redis had a chance to replace it with a newly written one, so that the
next test could fail.
2012-03-25 11:02:16 +02:00
antirez 0f9997845a Merge remote-tracking branch 'origin/unstable' into unstable 2012-03-24 12:07:58 +01:00
antirez 74f10793c8 When running the test in valgrind mode, pass the right flags to show memory leaks stack traces but only including the "definitely lost" items. 2012-03-24 12:07:14 +01:00
antirez 1b247d1333 Add used allocator in redis-server -v output. 2012-03-24 11:53:03 +01:00
antirez c79373482f convert-zipmap-hash-on-load test enabled 2012-03-24 11:42:20 +01:00
antirez 6c658d5554 Contextualize comment. 2012-03-23 20:24:40 +01:00
antirez 58e34e6cb1 Fixed memory leak in hash loading. 2012-03-23 20:24:34 +01:00
antirez 03116904c3 RDB load of different encodings test added. 2012-03-23 20:24:30 +01:00
antirez bd376d13f8 Big endian fix. The bug was introduced because of a typo. 2012-03-23 12:42:20 +01:00
antirez 6f0e77ca19 Replicate HINCRBYFLOAT as HSET. 2012-03-23 10:22:58 +01:00
antirez 7b558b1d64 Code style hack. 2012-03-22 18:17:09 +01:00
antirez 1f6146df0c Result of INCRBYFLOAT and HINCRBYFLOAT should never be in exponential form, and also should never contain trailing zeroes. This is not possible with vanilla printf() format specifiers, so we alter the output. 2012-03-22 18:17:05 +01:00
antirez ba864e09d4 Comments about security of slave-read-only in redis.coinf. 2012-03-21 12:26:05 +01:00
antirez b22eab8faf Correctly create shared.oomerr as an sds string. 2012-03-21 12:11:07 +01:00
antirez 7dcdd281f5 DEBUG should not be flagged as w otherwise we can not call DEBUG DIGEST and other commands against read only slaves. 2012-03-20 17:53:47 +01:00
antirez f3fd419fc9 Support for read-only slaves. Semantical fixes.
This commit introduces support for read only slaves via redis.conf and CONFIG GET/SET commands. Also various semantical fixes are implemented here:

1) MULTI/EXEC with only read commands now work where the server is into a state where writes (or commands increasing memory usage) are not allowed. Before this patch everything inside a transaction would fail in this conditions.

2) Scripts just calling read-only commands will work against read only
slaves, when the server is out of memory, or when persistence is into an
error condition. Before the patch EVAL always failed in this condition.
2012-03-20 17:32:48 +01:00
antirez 7a0c72f345 redis_init_script template updated. 2012-03-20 13:07:59 +01:00
antirez 0d44d50792 Suppress warnings compiling redis-cli with certain gcc versions. 2012-03-19 19:28:49 +01:00
antirez bb0aadbe21 Read-only flag removed from PUBLISH command. 2012-03-19 19:16:41 +01:00
antirez d4a515c56d Memory addressing test implemented. 2012-03-19 14:02:34 +01:00
antirez d033ccb0af More memory tests implemented. Default number of iterations lowered to a more acceptable value of 50. 2012-03-18 18:03:27 +01:00
antirez a5801142a4 Fixed typo. 2012-03-18 17:27:56 +01:00
antirez 1a197a3c1a Number of iteration of --test-memory is now 300 (several minutes per gigabyte). Memtest86 and Memtester links are also displayed while running the test. 2012-03-18 17:25:00 +01:00
antirez 525be599a8 On crash suggest to give --test-memory a try. 2012-03-18 11:35:35 +01:00
antirez fb068dc91d Memory test function now less boring thanks to screen-wide progress bar. 2012-03-16 21:19:53 +01:00
antirez 54e0fa1c27 Hem... actual memtest.c file added. 2012-03-16 17:21:49 +01:00
antirez c5166e3fc5 First implementation of --test-memory. Still a work in progress. 2012-03-16 17:17:39 +01:00
antirez c9d3dda29c Fix for issue #391.
Use a simple protocol between clientsCron() and helper functions to
understand if the client is still valind and clientsCron() should
continue processing or if the client was freed and we should continue
with the next one.
2012-03-15 20:55:14 +01:00
huangz1990 9448ddb0c6 fix typo 2012-03-15 14:27:14 +08:00
antirez ae22bf1ef6 Reclaim space from the client querybuf if needed. 2012-03-14 15:32:30 +01:00
antirez 739803c064 sds.c: sdsAllocSize() function added. 2012-03-14 14:58:26 +01:00
antirez 9555f8f21b sds.c new function sdsRemoveFreeSpace().
The new function is used in order to resize the string allocation so
that only the minimal allocation possible is used, removing all the free
space at the end of the string normally used to improve efficiency of
concatenation operations.
2012-03-14 10:13:23 +01:00
antirez 529bde82ec Call all the helper functions needed by clientsCron() as clientsCronSomething() for clarity. 2012-03-14 09:56:22 +01:00
antirez 6df450b77c CLIENT LIST test modified to reflect the new output. 2012-03-13 18:06:29 +01:00
antirez d19015be12 Process async client checks like client timeouts and BLPOP timeouts incrementally using a circular list. 2012-03-13 18:05:11 +01:00
antirez bbaeda402c Added a qbuf-free field to CLIENT LIST output. 2012-03-13 13:26:33 +01:00
antirez e74dca73d9 Client creation time in redisClient structure. New age field in CLIENT LIST output. 2012-03-13 13:05:08 +01:00
antirez 573373802e c->bufpos initialization moved for aesthetics. 2012-03-13 12:59:27 +01:00
antirez c3e7441dad RDB hashes loading, fixed another bug in the loading of HT-encoded hashes: when the hash entry is too big for ziplist, add the field, then convert. The code used to break before the new entry was inserted, resulting into missing fields in the loaded Hash object. 2012-03-13 11:00:18 +01:00
antirez c3c856228d RDB hashes loading fixed removing the assertion that failed every time an HT-encoded hash was loaded. 2012-03-13 09:49:11 +01:00
Salvatore Sanfilippo 79642420b0 Merge pull request #378 from quiver/unstable
fix typo of redis.conf
2012-03-10 04:22:29 -08:00
quiver 96e9f8d5e3 fix typo of redis.conf 2012-03-10 21:09:34 +09:00
antirez 64b4c33c0b Build dependencies updated. 2012-03-10 12:40:03 +01:00
antirez f12d0224f3 RDB4 support in redis-check-dump. 2012-03-10 12:38:42 +01:00
antirez c7d7d0a80f RDB version is no 4, because small hashes are now encoded as ziplists, so older versions of Redis will not understand this format. 2012-03-10 12:35:31 +01:00
69 changed files with 9200 additions and 1225 deletions
+142 -304
View File
@@ -1,9 +1,7 @@
Redis 2.8 release notes
Redis 3.0 release notes
=======================
** IMPORTANT ** Check the 'Migrating from 2.6 to 2.8' section at the end of
this file for information about what changed between 2.6 and
2.8 and how this may affect your application.
WARNING: Redis 3.0 is currently a BETA not suitable for production environments.
--------------------------------------------------------------------------------
Upgrade urgency levels:
@@ -14,67 +12,80 @@ HIGH: There is a critical bug that may affect a subset of users. Upgrade!
CRITICAL: There is a critical bug affecting MOST USERS. Upgrade ASAP.
--------------------------------------------------------------------------------
--[ Redis 2.8.11 ] Release date: 11 Jun 2014
--[ Redis 3.0.0 Beta 5 (version 2.9.54) ] Release date: 26 may 2014
# UPGRADE URGENCY: HIGH if you use Lua scripting, LOW otherwise.
This is the 5th beta of Redis 3.0.0. It does not include any real
worthwhile change (just three days passed since the previous beta), but
fixes two stupid bugs preventing cluster tests to pass.
* [FIX] A previous fix for Lua -> Redis numerical precision enhancement
introduced a new problem. In Redis 2.8.10 commands called from Lua
passing a string that "looks like" a very large number, may actually
use as argument the string converted as a float. This bug is now
fixed.
* [FIX] Now commands other than *PUSH* adding elements to a list will be able
to awake clients blocked in a blocking POP operation.
* [FIX] Cygwin compilation fixes.
--[ Redis 3.0.0 Beta 4 (version 2.9.53) ] Release date: 23 may 2014
--[ Redis 2.8.10 ] Release date: 5 Jun 2014
This is the fourth beta of Redis 3.0.0.
# UPGRADE URGENCY: HIGH if you use min-slaves-to-write option.
>> General changes
* [FIX] IMPORTANT! A min-slaves-to-write option active in a slave totally
prevented the slave from acception the master stream of commands.
This release includes testes for min-slaves-to-write, and a fix
for this issue.
* [FIX] Sometimes DEL returned 1 for already expired keys. Fixed.
* [FIX] Fix test false positive because new osx 'leaks' output.
* [FIX] PFCOUNT HLL cache invalidation fixed: no wrong value was reported
but the cache was not used at all, leading to lower performances.
* [FIX] Accept(2) multiple clients per readable-event invocation, and better
processing of I/O while loading or busy running a timedout script.
Basically now the LOADING / BUSY errors are reported at a decent
speed.
* [FIX] A softwaer watchdog crash fixed.
* [FIX] Fixed a Lua -> Redis numerical precision loss.
* [NEW] Scripting engine performances improvements.
* [NEW] Log format slightly changed to report current node role.
* [NEW] Lua scripting engine speed improved.
* [NEW] Sentinel generates one new event for humans to understand better
what is happening during a failover: +config-update-from.
Also the time at which a failover will be re-attempted is logged.
* [FIX] Correct the HyperLogLog stale cache flag to prevent unnecessary
computation.
--[ Redis 2.8.9 ] Release date: 22 Apr 2014
>> Cluster changes
# UPGRADE URGENCY: LOW, only new features introduced, no bugs fixed.
* [NEW] redis-trib: ability to import data from standalone Redis instances.
* [NEW] redis-trib: "fix" subcommand much better at fixing errors.
* [NEW] CLUSTER FAILOVER FORCE implemented.
* [NEW] CLUSTER RESET implemented, it is now possible to completely reset
nodes and create a new cluster without restarting anything.
* [NEW] Slave validity factor (max estimated data age to still failover)
is now under the control of the user, and can be configured via
redis.conf or CONFIG SET. Option name cluster-slave-validity-factor.
* [NEW] Cluster test: failure detection and failover initial tests.
* [NEW] CLUSTER MEET: better error messages when address is invalid.
* [NEW] Bulk-accept new Cluster nodes in the Cluster bus instead of
performing just a single accept() per event fired.
* [NEW] The HyperLogLog data structure. You can read more about it
in this blog post. http://antirez.com/news/75
* [NEW] The Sorted Set data type has now support for lexicographic range
queries, check the new commands ZRANGEBYLEX, ZLEXCOUNT and
ZREMRANGEBYLEX, which are documented at http://redis.io.
* [FIX] Bypass data_age check for manual failovers.
* [FIX] Fixed data_age computation / check integer overflow.
* [FIX] Various fixes to Tcl client.tcl Redis Cluster client used in tests.
* [FIX] Better handling of stolen slots.
* [FIX] Don't accept cluster bus connections during startup.
--[ Redis 2.8.8 ] Release date: 25 Mar 2014
>> Sentinel changes
# UPGRADE URGENCY: HIGH for Redis, LOW for Sentinel. There is a potentially
critical bug fix causing data loss in Redis but it requires
a combination of disk full and the use of the
SHUTDOWN command.
* [NEW] Generate +config-update-from event when a new config is received.
* [NEW] Log when a failover will be re-attempted again.
* [FIX] Fixed data loss when SHUTDOWN was used with a disk full condition.
* [FIX] Fixed a memory leak in the SORT syntax error processing.
* [FIX] When Sentinel down-after-milliseconds parameter is modified at runtime
now it gets propagated to all the slaves and sentinel instances
of the master.
* [FIX] `install_server.sh` script finally fixed.
* [FIX] Different fixes to maxclients handling.
* [FIX] Sentinel: Add "dir /tmp" directive in example sentinel.conf.
--[ Redis 3.0.0 Beta 3 (version 2.9.52) ] Release date: 5 may 2014
This is the third beta of Redis 3.0.0.
>> General changes
* [NEW] New data structure: the HyperLogLog (see 2.8 release notes).
* [NEW] Lexicograhical range queries in sorted sets (see 2.8 release notes).
* [NEW] LRU algorithm precision greatly improved.
* [FIX] Redis is now much more responsive to reply with LOADING / BUSY errors.
>> Cluster changes
* [NEW] Cluster testing framework and initial tests.
* [NEW] Cluster epochs collision resolution (make Redis Cluster more resilient
to admin and programming errors).
* [NEW] Persist / fsync some global state to ensure correct crash-recovery
semantics.
* [NEW] New command introduced: CLUSTER SET-CONFIG-EPOCH, still not used
by redis-trib. Will be used to speedup the assignment of unique
epochs to different nodes at cluster creation time. For now this is
handled as a side effect of the cluster epochs collision resolution.
* [FIX] Different fixes to redis-trib cluster creation.
* [FIX] Fix an error in the CLUSTER NODES output for nodes slots.
>> Sentinel changes
* [NEW] Sentinels are now able to send update messages in a peer-to-peer
fashion even if no Redis instances are available. Now the Sentinel
@@ -87,24 +98,12 @@ CRITICAL: There is a critical bug affecting MOST USERS. Upgrade ASAP.
* [NEW] Sentinel now uses CLIENT SETNAME so that it is easy to identify
Sentinels using CLIENT LIST among other clients.
* [NEW] Sentinel failure detection and reconnection code improved.
* [NEW] Use all 24 bits (instead of 22) for the Redis objects LRU field.
Note that the new LRU algorithm using eviction pools was not backported
from unstable for safery / code maturity concerns.
* [NEW] Majory speedup for the INFO command (it is now 6 times faster).
* [NEW] More Sentinel unit tests.
* [NEW] New command DEBUG ERROR returns the specified error. Example:
DEBUG ERROR "LOADING database". This is handy to write Redis client
libraries unit tests.
* [NEW] redis-cli now supports multi-line editing via updated linenoise lib.
Thanks to Matt Stancliff and Jan-Erik Rediger for the work done in the context
of this release.
--[ Redis 3.0.0 Beta 2 (version 2.9.51) ] Release date: 11 mar 2014
--[ Redis 2.8.7 ] Release date: 5 Mar 2014
This is the second beta of Redis 3.0.0.
# UPGRADE URGENCY: LOW for Redis, LOW for Sentinel. However this release adds
new features so users may want to upgrade in order to
exploit the new functionalities.
>> General changes
* [FIX] Sometimes the absolute config file path was obtained in a wrong way.
This happened when there was a "dir" directive inside the config file
@@ -112,46 +111,11 @@ of this release.
path to redis-server or redis-sentinel executables.
* [FIX] redis-cli: Automatically enter --slave mode when SYNC or PSYNC are
called during an interactive session.
* [FIX] Sentinel "IDONTKNOW" error removed as it does not made sense with the
new Sentinel design. This error was actually a fix for a design error
in the first implementation of Sentinel.
* [FIX] Sentinel: added a missing exit() call to abort after config file
checks at startup. This error was introduced with an improvement in
a previous 2.8 release.
* [FIX] BITCOUNT: fixed unaligned access causing issues in sparc and other
archs not capable of dealing with unaligned accesses. This also makes
the code faster in archs where unaligned accesses are allowed.
* [FIX] Sentinel: better nodes fail over start time desynchronization to avoid
split-brain during the voting process needed to get authorization to
fail over. This means the system is less likely to need to retry
and will fail over faster. No changes in behavior / correctness.
* [FIX] Force INFO used_memory_peak to match peak memory. This generated some
confusion among users even if it was not an actual bug.
* [NEW] Sentinel unit tests and framework. More tests needed and units must
be improved in order to have less false positives, but it is a start
and features a debugging console that is useful to fix tests or to
inspect bugs causing tests failures.
* [NEW] New Sentinel events: +/-monitor and +set used to monitor when an
instance to monitor is added or removed, or when a configuration
is modified via SENTINEL SET.
* [NEW] Redis-cli updated to use SCAN instead of random sampling via
RANDOMKEY in order to implement --bigkeys feature. Moreover the
implementation now supports pipelining and reports more information
at the end of the scan. Much faster, much better. A special thank
you to Michael Grunder for this improvement.
* [NEW] redis-cli now supports a new --intrinsic-latency mode that is able
to meter the latency of a system due to kernel / hypervisor.
How to use it is explained at http://redis.io/topics/latency.
* [NEW] New command BITPOS: find first bit set or clear in a bitmap.
* [NEW] CONFIG REWRITE calls are now logged.
--[ Redis 2.8.6 ] Release date: 13 Feb 2014
# UPGRADE URGENCY: HIGH for Redis, LOW for Sentinel. Redis users using Lua
scripts with EVALSHA and attached slaves and/or AOF
persistence should consider upgrading ASAP.
* [FIX] Fixed an critical EVALSHA script cache bug: scripts executed may not
propagate to AOF / Slaves correctly under certain conditions.
See issue #1549 at Github for more information.
@@ -162,232 +126,106 @@ of this release.
* [FIX] Don't count the time needed to populate the buffers of clients waiting
in MONITOR mode when populating the Slow Log entries.
* [NEW] Redis-cli updated to use SCAN instead of random sampling via
RANDOMKEY in order to implement --bigkeys feature. Moreover the
implementation now supports pipelining and reports more information
at the end of the scan. Much faster, much better. A special thank
you to Michael Grunder for this improvement.
* [NEW] redis-cli now supports a new --intrinsic-latency mode that is able
to meter the latency of a system due to kernel / hypervisor.
How to use it is explained at http://redis.io/topics/latency.
* [NEW] New command BITPOS: find first bit set or clear in a bitmap.
* [NEW] CONFIG REWRITE calls are now logged.
* [NEW] AOF write errors (like no space on device) no longer abort Redis if the
fsync policy is none or every second. The database enters a read-only
mode where every write is refused with an error. Normal operations are
restored as soon as Redis is able to append again data to the AOF file.
* [NEW] Sentinel now accepts SHUTDOWN command.
--[ Redis 2.8.5 ] Release date: 4 Feb 2014
# UPGRADE URGENCY: HIGH for Redis, LOW for Sentinel. Redis users using Lua
scripts with expires, and Redis users relying on the
ability of Redis to block writes on RDB saving errors
should plan to upgrade ASAP.
>> Cluster changes
* [FIX] Fixed a replication bug caused by Lua scripts + expired keys: keys could
expire in the middle of scripts causing non-deterministic behavior.
* [FIX] MISCONFIG error if condition fixed, the server was no longer able
to stop writes on RDB misconfiguration after this error was introduced.
* [FIX] REDIS_AOF_REWRITE_MIN_SIZE is now 64mb like example redis.conf default.
* [FIX] Perform fflush() before fsync() in rio.c (bug without actual effects).
* [FIX] Don't log MONITOR clients as disconnecting slaves.
* [FIX] SENTINEL MASTER arity check fixed. Crashed the Sentinel instance when
the command was given without arguments.
* [FIX] Bind the first interface listed in the "bind" configuration directive
if any, in order to perform outgoing connections. This fixes Cluster
usage when an address is bound but there are multiple interfaces that
may be used to connect with other nodes.
* [FIX] When an "Importing" slot is closed via CLUSTER SETSLOT NODE ...
increment the configEpoch in the special case it is zero.
* [FIX] Current transaction is invalidated on redirection errors.
* [FIX] Abort if port does not allow for a valid cluster bus port that is
always at fixed +10000 offset.
* [FIX] Keys extraction algorithm fixed for ZUNIONSTORE/ZINTERSTORE and SORT.
* [FIX] Better failover timeout and retry times: failover should now work
reliabily when node-timeout is very small (a few milliseconds).
* [FIX] Don't allow SORT GET/BY options in Cluster mode.
* [FIX] Clear importing/migrating state when turning from master to slave role.
* [FIX] Set slot error if we receive an update for a busy slot.
* [FIX] Update node configEpoch on UPDATE messages.
* [NEW] Allow CONFIG and SHUTDOWN while in stale-slave state.
* [NEW] Support for configurable TCP listen(2) backlog size.
* [NEW] redis-cli supports SCAN via the --scan and --pattern options.
* [NEW] SENTINEL SET master quorum via runtime API implemented.
* [NEW] Support multi-key operations as long as keys resolve to the same
hash slot, and the slot is not migrating, or it is migrating but all
the mentioned keys are available.
* [NEW] New DEBUG command CMDKEYS available to debug / test keys identification
in Redis commands.
* [NEW] redis-trib: create subcommand is now able to assign spare slaves.
* [NEW] redis-trib: new subcommand 'call'. Exec command in all nodes.
--[ Redis 2.8.4 ] Release date: 13 Jan 2014
# UPGRADE URGENCY: MODERATE for Redis and Sentinel.
>> Sentinel changes
* [FIX] Makefile compatibility with non common make variants improved.
* [FIX] SDIFF crash in very unlikely to trigger state fixed.
* [FIX] Config rewriting fixed: don't wipe options unknown to the rewrite
process.
* [FIX] Set TCP port to 0 works again to disable TCP networking.
* [FIX] Fixed replication with old Redis instances as masters by not
sending REPLCONF ACK to them.
* [FIX] Fix keyspace notifications rewrite and CONFIG GET output.
* [FIX] Fix RESTORE TTL handling in 32 bit systems (32 bit overflow).
* [FIX] Sentinel "IDONTKNOW" error removed as it does not made sense with the
new Sentinel design. This error was actually a fix for a design error
in the first implementation of Sentinel.
* [FIX] Sentinel: added a missing exit() call to abort after config file
checks at startup. This error was introduced with an improvement in
a previous 2.8 release.
* [FIX] Sentinel: better nodes fail over start time desynchronization to avoid
split-brain during the voting process needed to get authorization to
fail over. This means the system is less likely to need to retry
and will fail over faster. No changes in behavior / correctness.
* [NEW] Sentinel now has a run time configuration API.
* [NEW] Log when we lost connection with master or slave.
* [NEW] When instance is turned from slave to master now inherits the
old master replication offset when possible. This improves the
Sentinel failover procedure.
* [NEW] Sentinel unit tests and framework. More tests needed and units must
be improved in order to have less false positives, but it is a start
and features a debugging console that is useful to fix tests or to
inspect bugs causing tests failures.
* [NEW] New Sentinel events: +/-monitor and +set used to monitor when an
instance to monitor is added or removed, or when a configuration
is modified via SENTINEL SET.
--[ Redis 2.8.3 ] Release date: 11 Dec 2013
--[ Redis 3.0.0 Beta 1 (version 2.9.50) ] Release date: 11 Feb 2014
# UPGRADE URGENCY: MODERATE for Redis, HIGH for Sentinel.
This is the first beta of Redis 3.0.0.
* [FIX] Sentinel instance role sampling fixed, the system is now more
reliable during failover and when reconfiguring instances with
non matching configuration.
* [FIX] Inline requests are now handled even when terminated with just LF.
* [FIX] Replication timeout handling greatly improved, now the slave is able
to ping the master while removing the old data from memory, and while
loading the new RDB file. This avoid false timeouts sensed by
masters.
* [FIX] Fixed a replication bug involving 32 bit instances and big datasets
hard to compress that resulted into more than 2GB of RDB file sent.
* [FIX] Return error for inline requests with unbalanced quotes.
* [FIX] Publish the slave replication offset even when disconnected from the
master if there is still a cached master instance.
The following is a list of improvements in Redis 3.0, compared to Redis 2.8.
--[ Redis 2.8.2 ] Release date: 2 Dec 2013
* [NEW] Redis Cluster: a distributed implementation of a subset of Redis.
* [NEW] New "embedded string" object encoding resulting in less cache
misses. Big speed gain under certain work loads.
* [NEW] WAIT command to block waiting for a write to be transmitted to
the specified number of slaves.
* [NEW] MIGRATE connection caching. Much faster keys migraitons.
* [NEW] MIGARTE new options COPY and REPLACE.
* [NEW] CLIENT PAUSE command: stop processing client requests for a
specified amount of time.
# UPGRADE URGENCY: MODERATE for both Redis and Sentinel.
* [FIX] Sentinel better desynchronization to avoid split-brain elections
where no Sentinel managed to get elected.
* [FIX] Stop accepting writes on "MISCONF" error only if master, not slave.
* [FIX] Reply to PING with an error on "MISCONF" errors.
--[ Redis 2.8.1 ] Release date: 25 Nov 2013
# UPGRADE URGENCY: LOW for Redis, CRITICAL for Senitnel. You don't need to
upgrade your Redis instances but it is highly recommended
to upgrade and restart all the Sentinel processes.
* [FIX] Fixed a bug in "new Sentinel" config propagation.
* [FIX] Fixed a false positive in Redis tests.
--[ Redis 2.8.0 ] Release date: 22 Nov 2013
# UPGRADE URGENCY: LOW, unless you want to upgrade to new Sentinel code.
* [FIX] Fixed an error in rdbWriteRaw() that should have no practical impact.
* [NEW] Log the new master when SLAVEOF command is used.
* [NEW] Sentinel code synchronized with the unstable branch, the new Sentinel
is a reimplementation that uses more reliable algorithms.
--[ Redis 2.8 Release Candidate 6 (2.7.106) ] Release date: 6 Nov 2013
This is the 6th release candidate of Redis 2.8 (official version is 2.7.106).
# UPGRADE URGENCY: LOW, only new features back ported, no fixes.
* [NEW] SCAN, SSCAN, HSCAN, ZSCAN commands.
--[ Redis 2.8 Release Candidate 5 (2.7.105) ] Release date: 9 Oct 2013
This is the 5th release candidate of Redis 2.8 (official version is 2.7.105).
Important bugs fixed inside.
# UPGRADE URGENCY: HIGH because of many non critical replication bugs fixed.
* [FIX] redis-cli: don't crash with --bigkeys when the key no longer exist.
* [FIX] Allow AUTH / PING when disconnected from slave and serve-stale-data is no.
* [FIX] PSYNC: safer handling of PSYNC requests with offsets in the future.
* [FIX] Replication: Fix master timeout detection.
* [FIX] Replication: Correctly install the write handler after successful PSYNC.
--[ Redis 2.8 Release Candidate 4 (2.7.104) ] Release date: 30 Aug 2013
This is the fourth release candidate of Redis 2.8 (official version is 2.7.104).
Important bugs fixed inside.
# UPGRADE URGENCY: HIGH because of the EVAL memory leak.
* [FIX] Fixed a serious EVAL memory leak in the Lua stack.
* [FIX] Fixed server startup when no IPv6 address exists in any interface.
* [FIX] Send MISCONFIG error when BGSAVE fails because can't fork.
* [FIX] Memory efficiency with large (> a few kbytes) values improved considerably.
* [NEW] DEBUG SDSLEN for sds memory debugging.
--[ Redis 2.8 Release Candidate 3 (2.7.103) ] Release date: 19 Aug 2013
This is the third release candidate of Redis 2.8 (official version is 2.7.103).
Important bugs fixed inside.
# UPGRADE URGENCY: HIGH
* [FIX] Improved expired keys collection algorithm. Even under heavy load keys
to be expired can't accumulate because of lack of CPU time.
* [FIX] Replication speed regression fixed (issue #1238).
* [FIX] Fixed an hard to trigger PSYNC bug.
* [FIX] Fixed Issue #1240, ZUNIONSTORE could lead to wrong result.
* [NEW] Add per-db average TTL information in INFO output.
* [NEW] redis-benchmark improvements.
* [NEW] dict.c API wrong usage detection.
--[ Redis 2.8 Release Candidate 2 (2.7.102) ] Release date: 30 Jul 2013
This is the second release candidate of Redis 2.8 (official version is 2.7.102).
Important bugs fixed inside.
# UPGRADE URGENCY: HIGH
* [FIX] Fixed a critical replication bug, see issue #1221.
* [NEW] The new inline protocol now accepts quoted strings like, for example
you can now type in a telnet session: set 'foo bar' "hello world\n".
--[ Redis 2.8 Release Candidate 1 (2.7.101) ] Release date: 18 Jul 2013
This is the first release candidate of Redis 2.8 (official version is 2.7.101).
The following is a list of improvements in Redis 2.8, compared to Redis 2.6.
* [NEW] Slaves are now able to partially resynchronize with the master, so most
of the times a full resynchronization with the RDB creation in the master
side is not needed when the master-slave link is disconnected for a short
amount of time.
* [NEW] Experimental IPv6 support.
* [NEW] Slaves explicitly ping masters now, a master is able to detect a timed out
slave independently.
* [NEW] Masters can stop accepting writes if not enough slaves with a given
maximum latency are connected.
* [NEW] Keyspace changes notifications via Pub/Sub.
* [NEW] CONFIG SET maxclients is now available.
* [NEW] Ability to bind multiple IP addresses.
* [NEW] Set process names so that you can recognize, in the "ps" command output,
the listening port of an instance, or if it is a saving child.
* [NEW] Automatic memory check on crash.
* [NEW] CONFIG REWRITE is able to materialize the changes in the configuration
operated using CONFIG SET into the redis.conf file.
* [NEW] More NetBSD friendly code base.
* [NEW] PUBSUB command for Pub/Sub introspection capabilities.
* [NEW] EVALSHA can now be replicated as such, without requiring to be expanded
to a full EVAL for the replication link.
* [NEW] Better Lua scripts error reporting.
* [NEW] SDIFF performance improved.
* [FIX] A number of bugfixes.
Migrating from 2.6 to 2.8
Migrating from 2.8 to 3.0
=========================
Redis 2.6 is mostly a strict subset of 2.8. However there are a few things
that you should be aware of:
Redis 3.0 is mostly a strict subset of 2.8, you should not have any problem
upgrading your application from 2.8 to 3.0. However this is a list of small
non-backward compatible changes introduced in the 3.0 release:
The following commands changed behavior:
* The TTL and PTTL commands now return -2 if the key does not exist and
-1 if it exists but has no associated expire. Redis 2.6 and previous
versions used to return -1 for both the conditions.
* SORT with ALPHA now sorts according to local collation locale if no STORE
option is used.
* ZADD/ZINCRBY are now able to accept a bigger range of values as valid
scores, that is, all the values you may end having as a result of
calling ZINCRBY multiple times.
* Many errors are now prefixed by a more specific error code instead of
the generic -ERR, for example -WRONGTYPE, -NOAUTH, ...
* PUBLISH called inside Lua scripts is now correctly propagated to slaves.
The following redis.conf and CONFIG GET / SET parameters changed:
* logfile now uses the empty string in order to log to standard output,
so 'logfile stdout' is now invalid, use 'logfile ""' instead.
The following INFO fields changed format in a non-backward compatible way:
* The list of slaves in INFO is now in field=value format.
Replication:
Redis 2.8 can be used as slave for Redis 2.6, but doing this is only
a good idea for the short amount of time needed to upgrade your servers.
We suggest to update both master and slaves at about the same time.
* The log format was modified. The prefix of each line included the pid
in the following format [1234]. Now instead it is 1234:? Where
'?' is actually the role of the instance. M for master, S for slave, C
if this process is a saving child (for RDB/AOF), and X for Sentinel.
--------------------------------------------------------------------------------
Credits: Where not specified the implementation and design is done by
Salvatore Sanfilippo. Thanks to VMware and Pivotal for making all
this possible. Also many thanks to all the other contributors and the amazing
community we have.
Salvatore Sanfilippo. Thanks to Pivotal for making all this possible.
Also many thanks to all the other contributors and the amazing community
we have.
See commit messages for more credits.
+98 -6
View File
@@ -416,15 +416,18 @@ slave-priority 100
#
# The default is:
#
# maxmemory-policy volatile-lru
# maxmemory-policy noeviction
# LRU and minimal TTL algorithms are not precise algorithms but approximated
# algorithms (in order to save memory), so you can select as well the sample
# size to check. For instance for default Redis will check three keys and
# pick the one that was used less recently, you can change the sample size
# using the following configuration directive.
# algorithms (in order to save memory), so you can tune it for speed or
# accuracy. For default Redis will check five keys and pick the one that was
# used less recently, you can change the sample size using the following
# configuration directive.
#
# maxmemory-samples 3
# The default of 5 produces good enough results. 10 Approximates very closely
# true LRU but costs a bit more CPU. 3 is very fast but not very accurate.
#
# maxmemory-samples 5
############################## APPEND ONLY MODE ###############################
@@ -538,6 +541,95 @@ auto-aof-rewrite-min-size 64mb
# Set it to 0 or a negative value for unlimited execution without warnings.
lua-time-limit 5000
################################ REDIS CLUSTER ###############################
#
# Normal Redis instances can't be part of a Redis Cluster; only nodes that are
# started as cluster nodes can. In order to start a Redis instance as a
# cluster node enable the cluster support uncommenting the following:
#
# cluster-enabled yes
# Every cluster node has a cluster configuration file. This file is not
# intended to be edited by hand. It is created and updated by Redis nodes.
# Every Redis Cluster node requires a different cluster configuration file.
# Make sure that instances running in the same system does not have
# overlapping cluster configuration file names.
#
# cluster-config-file nodes-6379.conf
# Cluster node timeout is the amount of milliseconds a node must be unreachable
# for it to be considered in failure state.
# Most other internal time limits are multiple of the node timeout.
#
# cluster-node-timeout 15000
# A slave of a failing master will avoid to start a failover if its data
# looks too old.
#
# There is no simple way for a slave to actually have a exact measure of
# its "data age", so the following two checks are performed:
#
# 1) If there are multiple slaves able to failover, they exchange messages
# in order to try to give an advantage to the slave with the best
# replication offset (more data from the master processed).
# Slaves will try to get their rank by offset, and apply to the start
# of the failover a delay proportional to their rank.
#
# 2) Every single slave computes the time of the last interaction with
# its master. This can be the last ping or command received (if the master
# is still in the "connected" state), or the time that elapsed since the
# disconnection with the master (if the replication link is currently down).
# If the last interaction is too old, the slave will not try to failover
# at all.
#
# The point "2" can be tuned by user. Specifically a slave will not perform
# the failover if, since the last interaction with the master, the time
# elapsed is greater than:
#
# (node-timeout * slave-validity-factor) + repl-ping-slave-period
#
# So for example if node-timeout is 30 seconds, and the slave-validity-factor
# is 10, and assuming a default repl-ping-slave-period of 10 seconds, the
# slave will not try to failover if it was not able to talk with the master
# for longer than 310 seconds.
#
# A large slave-validity-factor may allow slaves with too old data to failover
# a master, while a too small value may prevent the cluster from being able to
# elect a slave at all.
#
# For maximum availability, it is possible to set the slave-validity-factor
# to a value of 0, which means, that slaves will always try to failover the
# master regardless of the last time they interacted with the master.
# (However they'll always try to apply a delay proportional to their
# offset rank).
#
# Zero is the only value able to guarantee that when all the partitions heal
# the cluster will always be able to continue.
#
# cluster-slave-validity-factor 10
# Cluster slaves are able to migrate to orphaned masters, that are masters
# that are left without working slaves. This improves the cluster ability
# to resist to failures as otherwise an orphaned master can't be failed over
# in case of failure if it has no working slaves.
#
# Slaves migrate to orphaned masters only if there are still at least a
# given number of other working slaves for their old master. This number
# is the "migration barrier". A migration barrier of 1 means that a slave
# will migrate only if there is at least 1 other working slave for its master
# and so forth. It usually reflects the number of slaves you want for every
# master in your cluster.
#
# Default is 1 (slaves migrate only if their masters remain with at least
# one slave). To disable migration just set it to a very large value.
# A value of 0 can be set but is useful only for debugging and dangerous
# in production.
#
# cluster-migration-barrier 1
# In order to setup your cluster make sure to read the documentation
# available at http://redis.io web site.
################################## SLOW LOG ###################################
# The Redis Slow Log is a system to log queries that exceeded a specified
+14
View File
@@ -0,0 +1,14 @@
#!/bin/sh
TCL_VERSIONS="8.5 8.6"
TCLSH=""
for VERSION in $TCL_VERSIONS; do
TCL=`which tclsh$VERSION 2>/dev/null` && TCLSH=$TCL
done
if [ -z $TCLSH ]
then
echo "You need tcl 8.5 or newer in order to run the Redis Sentinel test"
exit 1
fi
$TCLSH tests/cluster/run.tcl $*
+1 -1
View File
@@ -11,4 +11,4 @@ then
echo "You need tcl 8.5 or newer in order to run the Redis Sentinel test"
exit 1
fi
$TCLSH tests/sentinel.tcl $*
$TCLSH tests/sentinel/run.tcl $*
+1 -1
View File
@@ -107,7 +107,7 @@ endif
REDIS_SERVER_NAME=redis-server
REDIS_SENTINEL_NAME=redis-sentinel
REDIS_SERVER_OBJ=adlist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o migrate.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crc64.o bitops.o sentinel.o notify.o setproctitle.o hyperloglog.o
REDIS_SERVER_OBJ=adlist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o
REDIS_CLI_NAME=redis-cli
REDIS_CLI_OBJ=anet.o sds.o adlist.o redis-cli.o zmalloc.o release.o anet.o ae.o crc64.o
REDIS_BENCHMARK_NAME=redis-benchmark
+70 -63
View File
@@ -1,29 +1,38 @@
adlist.o: adlist.c adlist.h zmalloc.h
ae.o: ae.c ae.h zmalloc.h config.h ae_kqueue.c ae_select.c ae_evport.c ae_epoll.c
ae.o: ae.c ae.h zmalloc.h config.h ae_kqueue.c ae_epoll.c ae_select.c ae_evport.c
ae_epoll.o: ae_epoll.c
ae_evport.o: ae_evport.c
ae_kqueue.o: ae_kqueue.c
ae_select.o: ae_select.c
anet.o: anet.c fmacros.h anet.h
aof.o: aof.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h bio.h
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h bio.h
bio.o: bio.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h bio.h
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h bio.h
bitops.o: bitops.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
blocked.o: blocked.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
cluster.o: cluster.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h cluster.h endianconv.h
config.o: config.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h cluster.h
crc16.o: crc16.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
crc64.o: crc64.c
db.o: db.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h cluster.h
debug.o: debug.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h sha1.h crc64.h bio.h
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h sha1.h crc64.h bio.h
dict.o: dict.c fmacros.h dict.h zmalloc.h redisassert.h
endianconv.o: endianconv.c
hyperloglog.o: hyperloglog.c redis.h fmacros.h config.h \
@@ -34,86 +43,84 @@ intset.o: intset.c intset.h zmalloc.h endianconv.h config.h
lzf_c.o: lzf_c.c lzfP.h
lzf_d.o: lzf_d.c lzfP.h
memtest.o: memtest.c config.h
migrate.o: migrate.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h endianconv.h
multi.o: multi.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
networking.o: networking.c redis.h fmacros.h config.h \
../deps/lua/src/lua.h ../deps/lua/src/luaconf.h ae.h sds.h dict.h \
adlist.h zmalloc.h anet.h ziplist.h intset.h version.h util.h rdb.h \
rio.h
../deps/lua/src/lua.h ../deps/lua/src/luaconf.h ae.h sds.h dict.h \
adlist.h zmalloc.h anet.h ziplist.h intset.h version.h util.h rdb.h \
rio.h
notify.o: notify.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
object.o: object.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
pqsort.o: pqsort.c
pubsub.o: pubsub.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
rand.o: rand.c
rdb.o: rdb.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h lzf.h zipmap.h \
endianconv.h
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h lzf.h zipmap.h \
endianconv.h
redis-benchmark.o: redis-benchmark.c fmacros.h ae.h \
../deps/hiredis/hiredis.h sds.h adlist.h zmalloc.h
../deps/hiredis/hiredis.h sds.h adlist.h zmalloc.h
redis-check-aof.o: redis-check-aof.c fmacros.h config.h
redis-check-dump.o: redis-check-dump.c lzf.h crc64.h
redis-cli.o: redis-cli.c fmacros.h version.h ../deps/hiredis/hiredis.h \
sds.h zmalloc.h ../deps/linenoise/linenoise.h help.h anet.h ae.h
sds.h zmalloc.h ../deps/linenoise/linenoise.h help.h anet.h ae.h
redis.o: redis.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h slowlog.h bio.h \
asciilogo.h
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h cluster.h slowlog.h \
bio.h asciilogo.h
release.o: release.c release.h version.h crc64.h
replication.o: replication.c redis.h fmacros.h config.h \
../deps/lua/src/lua.h ../deps/lua/src/luaconf.h ae.h sds.h dict.h \
adlist.h zmalloc.h anet.h ziplist.h intset.h version.h util.h rdb.h \
rio.h
../deps/lua/src/lua.h ../deps/lua/src/luaconf.h ae.h sds.h dict.h \
adlist.h zmalloc.h anet.h ziplist.h intset.h version.h util.h rdb.h \
rio.h
rio.o: rio.c fmacros.h rio.h sds.h util.h crc64.h config.h redis.h \
../deps/lua/src/lua.h ../deps/lua/src/luaconf.h ae.h dict.h adlist.h \
zmalloc.h anet.h ziplist.h intset.h version.h rdb.h
../deps/lua/src/lua.h ../deps/lua/src/luaconf.h ae.h dict.h adlist.h \
zmalloc.h anet.h ziplist.h intset.h version.h rdb.h
scripting.o: scripting.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h sha1.h rand.h \
../deps/lua/src/lauxlib.h ../deps/lua/src/lualib.h
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h sha1.h rand.h \
../deps/lua/src/lauxlib.h ../deps/lua/src/lua.h ../deps/lua/src/lualib.h
sds.o: sds.c sds.h zmalloc.h
sentinel.o: sentinel.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h \
../deps/hiredis/hiredis.h ../deps/hiredis/async.h
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h \
../deps/hiredis/hiredis.h ../deps/hiredis/async.h \
../deps/hiredis/hiredis.h
setproctitle.o: setproctitle.c
sha1.o: sha1.c sha1.h config.h
slowlog.o: slowlog.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h slowlog.h
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h slowlog.h
sort.o: sort.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h pqsort.h
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h pqsort.h
syncio.o: syncio.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
t_hash.o: t_hash.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
t_list.o: t_list.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
t_set.o: t_set.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
t_string.o: t_string.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
t_zset.o: t_zset.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
util.o: util.c fmacros.h util.h sds.h
ziplist.o: ziplist.c zmalloc.h util.h sds.h ziplist.h endianconv.h \
config.h redisassert.h
config.h redisassert.h
zipmap.o: zipmap.c zmalloc.h endianconv.h config.h
zmalloc.o: zmalloc.c config.h zmalloc.h
+28 -4
View File
@@ -234,11 +234,12 @@ static int anetCreateSocket(char *err, int domain) {
#define ANET_CONNECT_NONE 0
#define ANET_CONNECT_NONBLOCK 1
static int anetTcpGenericConnect(char *err, char *addr, int port, int flags)
static int anetTcpGenericConnect(char *err, char *addr, int port,
char *source_addr, int flags)
{
int s = ANET_ERR, rv;
char portstr[6]; /* strlen("65535") + 1; */
struct addrinfo hints, *servinfo, *p;
struct addrinfo hints, *servinfo, *bservinfo, *p, *b;
snprintf(portstr,sizeof(portstr),"%d",port);
memset(&hints,0,sizeof(hints));
@@ -258,6 +259,24 @@ static int anetTcpGenericConnect(char *err, char *addr, int port, int flags)
if (anetSetReuseAddr(err,s) == ANET_ERR) goto error;
if (flags & ANET_CONNECT_NONBLOCK && anetNonBlock(err,s) != ANET_OK)
goto error;
if (source_addr) {
int bound = 0;
/* Using getaddrinfo saves us from self-determining IPv4 vs IPv6 */
if ((rv = getaddrinfo(source_addr, NULL, &hints, &bservinfo)) != 0) {
anetSetError(err, "%s", gai_strerror(rv));
goto end;
}
for (b = bservinfo; b != NULL; b = b->ai_next) {
if (bind(s,b->ai_addr,b->ai_addrlen) != -1) {
bound = 1;
break;
}
}
if (!bound) {
anetSetError(err, "bind: %s", strerror(errno));
goto end;
}
}
if (connect(s,p->ai_addr,p->ai_addrlen) == -1) {
/* If the socket is non-blocking, it is ok for connect() to
* return an EINPROGRESS error here. */
@@ -287,12 +306,17 @@ end:
int anetTcpConnect(char *err, char *addr, int port)
{
return anetTcpGenericConnect(err,addr,port,ANET_CONNECT_NONE);
return anetTcpGenericConnect(err,addr,port,NULL,ANET_CONNECT_NONE);
}
int anetTcpNonBlockConnect(char *err, char *addr, int port)
{
return anetTcpGenericConnect(err,addr,port,ANET_CONNECT_NONBLOCK);
return anetTcpGenericConnect(err,addr,port,NULL,ANET_CONNECT_NONBLOCK);
}
int anetTcpNonBlockBindConnect(char *err, char *addr, int port, char *source_addr)
{
return anetTcpGenericConnect(err,addr,port,source_addr,ANET_CONNECT_NONBLOCK);
}
int anetUnixGenericConnect(char *err, char *path, int flags)
+1
View File
@@ -45,6 +45,7 @@
int anetTcpConnect(char *err, char *addr, int port);
int anetTcpNonBlockConnect(char *err, char *addr, int port);
int anetTcpNonBlockBindConnect(char *err, char *addr, int port, char *source_addr);
int anetUnixConnect(char *err, char *path);
int anetUnixNonBlockConnect(char *err, char *path);
int anetRead(int fd, char *buf, int count);
+3 -1
View File
@@ -499,6 +499,7 @@ struct redisClient *createFakeClient(void) {
c->argv = NULL;
c->bufpos = 0;
c->flags = 0;
c->btype = REDIS_BLOCKED_NONE;
/* We set the fake client as a slave waiting for the synchronization
* so that Redis will not try to send replies to this client. */
c->replstate = REDIS_REPL_WAIT_BGSAVE_START;
@@ -506,6 +507,7 @@ struct redisClient *createFakeClient(void) {
c->reply_bytes = 0;
c->obuf_soft_limit_reached_time = 0;
c->watched_keys = listCreate();
c->peerid = NULL;
listSetFreeMethod(c->reply,decrRefCountVoid);
listSetDupMethod(c->reply,dupClientReplyValue);
initClientMultiState(c);
@@ -641,7 +643,7 @@ int rioWriteBulkObject(rio *r, robj *obj) {
* in a child process when this function is called). */
if (obj->encoding == REDIS_ENCODING_INT) {
return rioWriteBulkLongLong(r,(long)obj->ptr);
} else if (obj->encoding == REDIS_ENCODING_RAW) {
} else if (sdsEncodedObject(obj)) {
return rioWriteBulkString(r,obj->ptr,sdslen(obj->ptr));
} else {
redisPanic("Unknown string encoding");
+4 -4
View File
@@ -261,12 +261,12 @@ void getbitCommand(redisClient *c) {
byte = bitoffset >> 3;
bit = 7 - (bitoffset & 0x7);
if (o->encoding != REDIS_ENCODING_RAW) {
if (byte < (size_t)ll2string(llbuf,sizeof(llbuf),(long)o->ptr))
bitval = llbuf[byte] & (1 << bit);
} else {
if (sdsEncodedObject(o)) {
if (byte < sdslen(o->ptr))
bitval = ((uint8_t*)o->ptr)[byte] & (1 << bit);
} else {
if (byte < (size_t)ll2string(llbuf,sizeof(llbuf),(long)o->ptr))
bitval = llbuf[byte] & (1 << bit);
}
addReply(c, bitval ? shared.cone : shared.czero);
+158
View File
@@ -0,0 +1,158 @@
/* blocked.c - generic support for blocking operations like BLPOP & WAIT.
*
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* ---------------------------------------------------------------------------
*
* API:
*
* getTimeoutFromObjectOrReply() is just an utility function to parse a
* timeout argument since blocking operations usually require a timeout.
*
* blockClient() set the REDIS_BLOCKED flag in the client, and set the
* specified block type 'btype' filed to one of REDIS_BLOCKED_* macros.
*
* unblockClient() unblocks the client doing the following:
* 1) It calls the btype-specific function to cleanup the state.
* 2) It unblocks the client by unsetting the REDIS_BLOCKED flag.
* 3) It puts the client into a list of just unblocked clients that are
* processed ASAP in the beforeSleep() event loop callback, so that
* if there is some query buffer to process, we do it. This is also
* required because otherwise there is no 'readable' event fired, we
* already read the pending commands. We also set the REDIS_UNBLOCKED
* flag to remember the client is in the unblocked_clients list.
*
* processUnblockedClients() is called inside the beforeSleep() function
* to process the query buffer from unblocked clients and remove the clients
* from the blocked_clients queue.
*
* replyToBlockedClientTimedOut() is called by the cron function when
* a client blocked reaches the specified timeout (if the timeout is set
* to 0, no timeout is processed).
* It usually just needs to send a reply to the client.
*
* When implementing a new type of blocking opeation, the implementation
* should modify unblockClient() and replyToBlockedClientTimedOut() in order
* to handle the btype-specific behavior of this two functions.
*/
#include "redis.h"
/* Get a timeout value from an object and store it into 'timeout'.
* The final timeout is always stored as milliseconds as a time where the
* timeout will expire, however the parsing is performed according to
* the 'unit' that can be seconds or milliseconds.
*
* Note that if the timeout is zero (usually from the point of view of
* commands API this means no timeout) the value stored into 'timeout'
* is zero. */
int getTimeoutFromObjectOrReply(redisClient *c, robj *object, mstime_t *timeout, int unit) {
long long tval;
if (getLongLongFromObjectOrReply(c,object,&tval,
"timeout is not an integer or out of range") != REDIS_OK)
return REDIS_ERR;
if (tval < 0) {
addReplyError(c,"timeout is negative");
return REDIS_ERR;
}
if (tval > 0) {
if (unit == UNIT_SECONDS) tval *= 1000;
tval += mstime();
}
*timeout = tval;
return REDIS_OK;
}
/* Block a client for the specific operation type. Once the REDIS_BLOCKED
* flag is set client query buffer is not longer processed, but accumulated,
* and will be processed when the client is unblocked. */
void blockClient(redisClient *c, int btype) {
c->flags |= REDIS_BLOCKED;
c->btype = btype;
server.bpop_blocked_clients++;
}
/* This function is called in the beforeSleep() function of the event loop
* in order to process the pending input buffer of clients that were
* unblocked after a blocking operation. */
void processUnblockedClients(void) {
listNode *ln;
redisClient *c;
while (listLength(server.unblocked_clients)) {
ln = listFirst(server.unblocked_clients);
redisAssert(ln != NULL);
c = ln->value;
listDelNode(server.unblocked_clients,ln);
c->flags &= ~REDIS_UNBLOCKED;
c->btype = REDIS_BLOCKED_NONE;
/* Process remaining data in the input buffer. */
if (c->querybuf && sdslen(c->querybuf) > 0) {
server.current_client = c;
processInputBuffer(c);
server.current_client = NULL;
}
}
}
/* Unblock a client calling the right function depending on the kind
* of operation the client is blocking for. */
void unblockClient(redisClient *c) {
if (c->btype == REDIS_BLOCKED_LIST) {
unblockClientWaitingData(c);
} else if (c->btype == REDIS_BLOCKED_WAIT) {
unblockClientWaitingReplicas(c);
} else {
redisPanic("Unknown btype in unblockClient().");
}
/* Clear the flags, and put the client in the unblocked list so that
* we'll process new commands in its query buffer ASAP. */
c->flags &= ~REDIS_BLOCKED;
c->flags |= REDIS_UNBLOCKED;
c->btype = REDIS_BLOCKED_NONE;
server.bpop_blocked_clients--;
listAddNodeTail(server.unblocked_clients,c);
}
/* This function gets called when a blocked client timed out in order to
* send it a reply of some kind. */
void replyToBlockedClientTimedOut(redisClient *c) {
if (c->btype == REDIS_BLOCKED_LIST) {
addReply(c,shared.nullmultibulk);
} else if (c->btype == REDIS_BLOCKED_WAIT) {
addReplyLongLong(c,replicationCountAcksByOffset(c->bpop.reploffset));
} else {
redisPanic("Unknown btype in replyToBlockedClientTimedOut().");
}
}
+4432
View File
File diff suppressed because it is too large Load Diff
+237
View File
@@ -0,0 +1,237 @@
#ifndef __REDIS_CLUSTER_H
#define __REDIS_CLUSTER_H
/*-----------------------------------------------------------------------------
* Redis cluster data structures, defines, exported API.
*----------------------------------------------------------------------------*/
#define REDIS_CLUSTER_SLOTS 16384
#define REDIS_CLUSTER_OK 0 /* Everything looks ok */
#define REDIS_CLUSTER_FAIL 1 /* The cluster can't work */
#define REDIS_CLUSTER_NAMELEN 40 /* sha1 hex length */
#define REDIS_CLUSTER_PORT_INCR 10000 /* Cluster port = baseport + PORT_INCR */
/* The following defines are amunt of time, sometimes expressed as
* multiplicators of the node timeout value (when ending with MULT). */
#define REDIS_CLUSTER_DEFAULT_NODE_TIMEOUT 15000
#define REDIS_CLUSTER_DEFAULT_SLAVE_VALIDITY 10 /* Slave max data age factor. */
#define REDIS_CLUSTER_FAIL_REPORT_VALIDITY_MULT 2 /* Fail report validity. */
#define REDIS_CLUSTER_FAIL_UNDO_TIME_MULT 2 /* Undo fail if master is back. */
#define REDIS_CLUSTER_FAIL_UNDO_TIME_ADD 10 /* Some additional time. */
#define REDIS_CLUSTER_FAILOVER_DELAY 5 /* Seconds */
#define REDIS_CLUSTER_DEFAULT_MIGRATION_BARRIER 1
#define REDIS_CLUSTER_MF_TIMEOUT 5000 /* Milliseconds to do a manual failover. */
#define REDIS_CLUSTER_MF_PAUSE_MULT 2 /* Master pause manual failover mult. */
/* Redirection errors returned by getNodeByQuery(). */
#define REDIS_CLUSTER_REDIR_NONE 0 /* Node can serve the request. */
#define REDIS_CLUSTER_REDIR_CROSS_SLOT 1 /* Keys in different slots. */
#define REDIS_CLUSTER_REDIR_UNSTABLE 2 /* Keys in slot resharding. */
#define REDIS_CLUSTER_REDIR_ASK 3 /* -ASK redirection required. */
#define REDIS_CLUSTER_REDIR_MOVED 4 /* -MOVED redirection required. */
struct clusterNode;
/* clusterLink encapsulates everything needed to talk with a remote node. */
typedef struct clusterLink {
mstime_t ctime; /* Link creation time */
int fd; /* TCP socket file descriptor */
sds sndbuf; /* Packet send buffer */
sds rcvbuf; /* Packet reception buffer */
struct clusterNode *node; /* Node related to this link if any, or NULL */
} clusterLink;
/* Cluster node flags and macros. */
#define REDIS_NODE_MASTER 1 /* The node is a master */
#define REDIS_NODE_SLAVE 2 /* The node is a slave */
#define REDIS_NODE_PFAIL 4 /* Failure? Need acknowledge */
#define REDIS_NODE_FAIL 8 /* The node is believed to be malfunctioning */
#define REDIS_NODE_MYSELF 16 /* This node is myself */
#define REDIS_NODE_HANDSHAKE 32 /* We have still to exchange the first ping */
#define REDIS_NODE_NOADDR 64 /* We don't know the address of this node */
#define REDIS_NODE_MEET 128 /* Send a MEET message to this node */
#define REDIS_NODE_PROMOTED 256 /* Master was a slave propoted by failover */
#define REDIS_NODE_NULL_NAME "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
#define nodeIsMaster(n) ((n)->flags & REDIS_NODE_MASTER)
#define nodeIsSlave(n) ((n)->flags & REDIS_NODE_SLAVE)
#define nodeInHandshake(n) ((n)->flags & REDIS_NODE_HANDSHAKE)
#define nodeHasAddr(n) (!((n)->flags & REDIS_NODE_NOADDR))
#define nodeWithoutAddr(n) ((n)->flags & REDIS_NODE_NOADDR)
#define nodeTimedOut(n) ((n)->flags & REDIS_NODE_PFAIL)
#define nodeFailed(n) ((n)->flags & REDIS_NODE_FAIL)
/* This structure represent elements of node->fail_reports. */
struct clusterNodeFailReport {
struct clusterNode *node; /* Node reporting the failure condition. */
mstime_t time; /* Time of the last report from this node. */
} typedef clusterNodeFailReport;
struct clusterNode {
mstime_t ctime; /* Node object creation time. */
char name[REDIS_CLUSTER_NAMELEN]; /* Node name, hex string, sha1-size */
int flags; /* REDIS_NODE_... */
uint64_t configEpoch; /* Last configEpoch observed for this node */
unsigned char slots[REDIS_CLUSTER_SLOTS/8]; /* slots handled by this node */
int numslots; /* Number of slots handled by this node */
int numslaves; /* Number of slave nodes, if this is a master */
struct clusterNode **slaves; /* pointers to slave nodes */
struct clusterNode *slaveof; /* pointer to the master node */
mstime_t ping_sent; /* Unix time we sent latest ping */
mstime_t pong_received; /* Unix time we received the pong */
mstime_t fail_time; /* Unix time when FAIL flag was set */
mstime_t voted_time; /* Last time we voted for a slave of this master */
mstime_t repl_offset_time; /* Unix time we received offset for this node */
long long repl_offset; /* Last known repl offset for this node. */
char ip[REDIS_IP_STR_LEN]; /* Latest known IP address of this node */
int port; /* Latest known port of this node */
clusterLink *link; /* TCP/IP link with this node */
list *fail_reports; /* List of nodes signaling this as failing */
};
typedef struct clusterNode clusterNode;
typedef struct clusterState {
clusterNode *myself; /* This node */
uint64_t currentEpoch;
int state; /* REDIS_CLUSTER_OK, REDIS_CLUSTER_FAIL, ... */
int size; /* Num of master nodes with at least one slot */
dict *nodes; /* Hash table of name -> clusterNode structures */
dict *nodes_black_list; /* Nodes we don't re-add for a few seconds. */
clusterNode *migrating_slots_to[REDIS_CLUSTER_SLOTS];
clusterNode *importing_slots_from[REDIS_CLUSTER_SLOTS];
clusterNode *slots[REDIS_CLUSTER_SLOTS];
zskiplist *slots_to_keys;
/* The following fields are used to take the slave state on elections. */
mstime_t failover_auth_time; /* Time of previous or next election. */
int failover_auth_count; /* Number of votes received so far. */
int failover_auth_sent; /* True if we already asked for votes. */
int failover_auth_rank; /* This slave rank for current auth request. */
uint64_t failover_auth_epoch; /* Epoch of the current election. */
/* Manual failover state in common. */
mstime_t mf_end; /* Manual failover time limit (ms unixtime).
It is zero if there is no MF in progress. */
/* Manual failover state of master. */
clusterNode *mf_slave; /* Slave performing the manual failover. */
/* Manual failover state of slave. */
long long mf_master_offset; /* Master offset the slave needs to start MF
or zero if stil not received. */
int mf_can_start; /* If non-zero signal that the manual failover
can start requesting masters vote. */
/* The followign fields are uesd by masters to take state on elections. */
uint64_t lastVoteEpoch; /* Epoch of the last vote granted. */
int todo_before_sleep; /* Things to do in clusterBeforeSleep(). */
long long stats_bus_messages_sent; /* Num of msg sent via cluster bus. */
long long stats_bus_messages_received; /* Num of msg rcvd via cluster bus.*/
} clusterState;
/* clusterState todo_before_sleep flags. */
#define CLUSTER_TODO_HANDLE_FAILOVER (1<<0)
#define CLUSTER_TODO_UPDATE_STATE (1<<1)
#define CLUSTER_TODO_SAVE_CONFIG (1<<2)
#define CLUSTER_TODO_FSYNC_CONFIG (1<<3)
/* Redis cluster messages header */
/* Note that the PING, PONG and MEET messages are actually the same exact
* kind of packet. PONG is the reply to ping, in the exact format as a PING,
* while MEET is a special PING that forces the receiver to add the sender
* as a node (if it is not already in the list). */
#define CLUSTERMSG_TYPE_PING 0 /* Ping */
#define CLUSTERMSG_TYPE_PONG 1 /* Pong (reply to Ping) */
#define CLUSTERMSG_TYPE_MEET 2 /* Meet "let's join" message */
#define CLUSTERMSG_TYPE_FAIL 3 /* Mark node xxx as failing */
#define CLUSTERMSG_TYPE_PUBLISH 4 /* Pub/Sub Publish propagation */
#define CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST 5 /* May I failover? */
#define CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK 6 /* Yes, you have my vote */
#define CLUSTERMSG_TYPE_UPDATE 7 /* Another node slots configuration */
#define CLUSTERMSG_TYPE_MFSTART 8 /* Pause clients for manual failover */
/* Initially we don't know our "name", but we'll find it once we connect
* to the first node, using the getsockname() function. Then we'll use this
* address for all the next messages. */
typedef struct {
char nodename[REDIS_CLUSTER_NAMELEN];
uint32_t ping_sent;
uint32_t pong_received;
char ip[REDIS_IP_STR_LEN]; /* IP address last time it was seen */
uint16_t port; /* port last time it was seen */
uint16_t flags;
uint32_t notused; /* for 64 bit alignment */
} clusterMsgDataGossip;
typedef struct {
char nodename[REDIS_CLUSTER_NAMELEN];
} clusterMsgDataFail;
typedef struct {
uint32_t channel_len;
uint32_t message_len;
unsigned char bulk_data[8]; /* defined as 8 just for alignment concerns. */
} clusterMsgDataPublish;
typedef struct {
uint64_t configEpoch; /* Config epoch of the specified instance. */
char nodename[REDIS_CLUSTER_NAMELEN]; /* Name of the slots owner. */
unsigned char slots[REDIS_CLUSTER_SLOTS/8]; /* Slots bitmap. */
} clusterMsgDataUpdate;
union clusterMsgData {
/* PING, MEET and PONG */
struct {
/* Array of N clusterMsgDataGossip structures */
clusterMsgDataGossip gossip[1];
} ping;
/* FAIL */
struct {
clusterMsgDataFail about;
} fail;
/* PUBLISH */
struct {
clusterMsgDataPublish msg;
} publish;
/* UPDATE */
struct {
clusterMsgDataUpdate nodecfg;
} update;
};
typedef struct {
char sig[4]; /* Siganture "RCmb" (Redis Cluster message bus). */
uint32_t totlen; /* Total length of this message */
uint16_t ver; /* Protocol version, currently set to 0. */
uint16_t notused0; /* 2 bytes not used. */
uint16_t type; /* Message type */
uint16_t count; /* Only used for some kind of messages. */
uint64_t currentEpoch; /* The epoch accordingly to the sending node. */
uint64_t configEpoch; /* The config epoch if it's a master, or the last
epoch advertised by its master if it is a
slave. */
uint64_t offset; /* Master replication offset if node is a master or
processed replication offset if node is a slave. */
char sender[REDIS_CLUSTER_NAMELEN]; /* Name of the sender node */
unsigned char myslots[REDIS_CLUSTER_SLOTS/8];
char slaveof[REDIS_CLUSTER_NAMELEN];
char notused1[32]; /* 32 bytes reserved for future usage. */
uint16_t port; /* Sender TCP base port */
uint16_t flags; /* Sender node flags */
unsigned char state; /* Cluster state from the POV of the sender */
unsigned char mflags[3]; /* Message flags: CLUSTERMSG_FLAG[012]_... */
union clusterMsgData data;
} clusterMsg;
#define CLUSTERMSG_MIN_LEN (sizeof(clusterMsg)-sizeof(union clusterMsgData))
/* Message flags better specify the packet content or are used to
* provide some information about the node state. */
#define CLUSTERMSG_FLAG0_PAUSED (1<<0) /* Master paused for manual failover. */
#define CLUSTERMSG_FLAG0_FORCEACK (1<<1) /* Give ACK to AUTH_REQUEST even if
master is up. */
/* ---------------------- API exported outside cluster.c -------------------- */
clusterNode *getNodeByQuery(redisClient *c, struct redisCommand *cmd, robj **argv, int argc, int *hashslot, int *ask);
#endif /* __REDIS_CLUSTER_H */
+68 -7
View File
@@ -29,6 +29,7 @@
*/
#include "redis.h"
#include "cluster.h"
#include <fcntl.h>
#include <sys/stat.h>
@@ -81,6 +82,7 @@ void resetServerSaveParams() {
void loadServerConfigFromString(char *config) {
char *err = NULL;
int linenum = 0, totlines, i;
int slaveof_linenum = 0;
sds *lines;
lines = sdssplitlen(config,strlen(config),"\n",1,&totlines);
@@ -248,6 +250,7 @@ void loadServerConfigFromString(char *config) {
goto loaderr;
}
} else if (!strcasecmp(argv[0],"slaveof") && argc == 3) {
slaveof_linenum = linenum;
server.masterhost = sdsnew(argv[1]);
server.masterport = atoi(argv[2]);
server.repl_state = REDIS_REPL_CONNECT;
@@ -414,6 +417,34 @@ void loadServerConfigFromString(char *config) {
err = "Target command name already exists"; goto loaderr;
}
}
} else if (!strcasecmp(argv[0],"cluster-enabled") && argc == 2) {
if ((server.cluster_enabled = yesnotoi(argv[1])) == -1) {
err = "argument must be 'yes' or 'no'"; goto loaderr;
}
} else if (!strcasecmp(argv[0],"cluster-config-file") && argc == 2) {
zfree(server.cluster_configfile);
server.cluster_configfile = zstrdup(argv[1]);
} else if (!strcasecmp(argv[0],"cluster-node-timeout") && argc == 2) {
server.cluster_node_timeout = strtoll(argv[1],NULL,10);
if (server.cluster_node_timeout <= 0) {
err = "cluster node timeout must be 1 or greater"; goto loaderr;
}
} else if (!strcasecmp(argv[0],"cluster-migration-barrier")
&& argc == 2)
{
server.cluster_migration_barrier = atoi(argv[1]);
if (server.cluster_migration_barrier < 0) {
err = "cluster migration barrier must zero or positive";
goto loaderr;
}
} else if (!strcasecmp(argv[0],"cluster-slave-validity-factor")
&& argc == 2)
{
server.cluster_slave_validity_factor = atoi(argv[1]);
if (server.cluster_slave_validity_factor < 0) {
err = "cluster slave validity factor must be zero or positive";
goto loaderr;
}
} else if (!strcasecmp(argv[0],"lua-time-limit") && argc == 2) {
server.lua_time_limit = strtoll(argv[1],NULL,10);
} else if (!strcasecmp(argv[0],"slowlog-log-slower-than") &&
@@ -484,6 +515,15 @@ void loadServerConfigFromString(char *config) {
}
sdsfreesplitres(argv,argc);
}
/* Sanity checks. */
if (server.cluster_enabled && server.masterhost) {
linenum = slaveof_linenum;
i = linenum-1;
err = "slaveof directive not allowed in cluster mode";
goto loaderr;
}
sdsfreesplitres(lines,totlines);
return;
@@ -539,8 +579,8 @@ void loadServerConfig(char *filename, char *options) {
void configSetCommand(redisClient *c) {
robj *o;
long long ll;
redisAssertWithInfo(c,c->argv[2],c->argv[2]->encoding == REDIS_ENCODING_RAW);
redisAssertWithInfo(c,c->argv[2],c->argv[3]->encoding == REDIS_ENCODING_RAW);
redisAssertWithInfo(c,c->argv[2],sdsEncodedObject(c->argv[2]));
redisAssertWithInfo(c,c->argv[3],sdsEncodedObject(c->argv[3]));
o = c->argv[3];
if (!strcasecmp(c->argv[2]->ptr,"dbfilename")) {
@@ -857,6 +897,18 @@ void configSetCommand(redisClient *c) {
ll < 0) goto badfmt;
server.repl_min_slaves_max_lag = ll;
refreshGoodSlavesCount();
} else if (!strcasecmp(c->argv[2]->ptr,"cluster-node-timeout")) {
if (getLongLongFromObject(o,&ll) == REDIS_ERR ||
ll <= 0) goto badfmt;
server.cluster_node_timeout = ll;
} else if (!strcasecmp(c->argv[2]->ptr,"cluster-migration-barrier")) {
if (getLongLongFromObject(o,&ll) == REDIS_ERR ||
ll < 0) goto badfmt;
server.cluster_migration_barrier = ll;
} else if (!strcasecmp(c->argv[2]->ptr,"cluster-slave-validity-factor")) {
if (getLongLongFromObject(o,&ll) == REDIS_ERR ||
ll < 0) goto badfmt;
server.cluster_slave_validity_factor = ll;
} else {
addReplyErrorFormat(c,"Unsupported CONFIG parameter: %s",
(char*)c->argv[2]->ptr);
@@ -906,7 +958,7 @@ void configGetCommand(redisClient *c) {
char *pattern = o->ptr;
char buf[128];
int matches = 0;
redisAssertWithInfo(c,o,o->encoding == REDIS_ENCODING_RAW);
redisAssertWithInfo(c,o,sdsEncodedObject(o));
/* String values */
config_get_string_field("dbfilename",server.rdb_filename);
@@ -959,6 +1011,9 @@ void configGetCommand(redisClient *c) {
config_get_numerical_field("min-slaves-to-write",server.repl_min_slaves_to_write);
config_get_numerical_field("min-slaves-max-lag",server.repl_min_slaves_max_lag);
config_get_numerical_field("hz",server.hz);
config_get_numerical_field("cluster-node-timeout",server.cluster_node_timeout);
config_get_numerical_field("cluster-migration-barrier",server.cluster_migration_barrier);
config_get_numerical_field("cluster-slave-validity-factor",server.cluster_slave_validity_factor);
/* Bool (yes/no) values */
config_get_bool_field("no-appendfsync-on-rewrite",
@@ -1381,7 +1436,7 @@ void rewriteConfigEnumOption(struct rewriteConfigState *state, char *option, int
char *enum_name, *matching_name = NULL;
int enum_val, def_val, force;
sds line;
va_start(ap, value);
while(1) {
enum_name = va_arg(ap,char*);
@@ -1393,7 +1448,7 @@ void rewriteConfigEnumOption(struct rewriteConfigState *state, char *option, int
if (value == enum_val) matching_name = enum_name;
}
va_end(ap);
force = value != def_val;
line = sdscatprintf(sdsempty(),"%s %s",option,matching_name);
rewriteConfigRewriteLine(state,option,line,force);
@@ -1450,8 +1505,9 @@ void rewriteConfigSlaveofOption(struct rewriteConfigState *state) {
sds line;
/* If this is a master, we want all the slaveof config options
* in the file to be removed. */
if (server.masterhost == NULL) {
* in the file to be removed. Note that if this is a cluster instance
* we don't want a slaveof directive inside redis.conf. */
if (server.cluster_enabled || server.masterhost == NULL) {
rewriteConfigMarkAsProcessed(state,"slaveof");
return;
}
@@ -1723,6 +1779,11 @@ int rewriteConfig(char *path) {
rewriteConfigNumericalOption(state,"auto-aof-rewrite-percentage",server.aof_rewrite_perc,REDIS_AOF_REWRITE_PERC);
rewriteConfigBytesOption(state,"auto-aof-rewrite-min-size",server.aof_rewrite_min_size,REDIS_AOF_REWRITE_MIN_SIZE);
rewriteConfigNumericalOption(state,"lua-time-limit",server.lua_time_limit,REDIS_LUA_TIME_LIMIT);
rewriteConfigYesNoOption(state,"cluster-enabled",server.cluster_enabled,0);
rewriteConfigStringOption(state,"cluster-config-file",server.cluster_configfile,REDIS_DEFAULT_CLUSTER_CONFIG_FILE);
rewriteConfigNumericalOption(state,"cluster-node-timeout",server.cluster_node_timeout,REDIS_CLUSTER_DEFAULT_NODE_TIMEOUT);
rewriteConfigNumericalOption(state,"cluster-migration-barrier",server.cluster_migration_barrier,REDIS_CLUSTER_DEFAULT_MIGRATION_BARRIER);
rewriteConfigNumericalOption(state,"cluster-slave-validity-factor",server.cluster_slave_validity_factor,REDIS_CLUSTER_DEFAULT_SLAVE_VALIDITY);
rewriteConfigNumericalOption(state,"slowlog-log-slower-than",server.slowlog_log_slower_than,REDIS_SLOWLOG_LOG_SLOWER_THAN);
rewriteConfigNumericalOption(state,"slowlog-max-len",server.slowlog_max_len,REDIS_SLOWLOG_MAX_LEN);
rewriteConfigNotifykeyspaceeventsOption(state);
+88
View File
@@ -0,0 +1,88 @@
#include "redis.h"
/*
* Copyright 2001-2010 Georges Menie (www.menie.org)
* Copyright 2010-2012 Salvatore Sanfilippo (adapted to Redis coding style)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University of California, Berkeley nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* CRC16 implementation according to CCITT standards.
*
* Note by @antirez: this is actually the XMODEM CRC 16 algorithm, using the
* following parameters:
*
* Name : "XMODEM", also known as "ZMODEM", "CRC-16/ACORN"
* Width : 16 bit
* Poly : 1021 (That is actually x^16 + x^12 + x^5 + 1)
* Initialization : 0000
* Reflect Input byte : False
* Reflect Output CRC : False
* Xor constant to output CRC : 0000
* Output for "123456789" : 31C3
*/
static const uint16_t crc16tab[256]= {
0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
};
uint16_t crc16(const char *buf, int len) {
int counter;
uint16_t crc = 0;
for (counter = 0; counter < len; counter++)
crc = (crc<<8) ^ crc16tab[((crc>>8) ^ *buf++)&0x00FF];
return crc;
}
+215 -36
View File
@@ -28,12 +28,14 @@
*/
#include "redis.h"
#include "cluster.h"
#include <signal.h>
#include <ctype.h>
void SlotToKeyAdd(robj *key);
void SlotToKeyDel(robj *key);
void slotToKeyAdd(robj *key);
void slotToKeyDel(robj *key);
void slotToKeyFlush(void);
/*-----------------------------------------------------------------------------
* C-level DB API
@@ -48,7 +50,7 @@ robj *lookupKey(redisDb *db, robj *key) {
* Don't do it if we have a saving child, as this will trigger
* a copy on write madness. */
if (server.rdb_child_pid == -1 && server.aof_child_pid == -1)
val->lru = server.lruclock;
val->lru = LRU_CLOCK();
return val;
} else {
return NULL;
@@ -93,7 +95,7 @@ void dbAdd(redisDb *db, robj *key, robj *val) {
int retval = dictAdd(db->dict, copy, val);
redisAssertWithInfo(NULL,key,retval == REDIS_OK);
if (val->type == REDIS_LIST) signalListAsReady(db, key);
if (server.cluster_enabled) slotToKeyAdd(key);
}
/* Overwrite an existing key with a new value. Incrementing the reference
@@ -102,7 +104,7 @@ void dbAdd(redisDb *db, robj *key, robj *val) {
*
* The program is aborted if the key was not already present. */
void dbOverwrite(redisDb *db, robj *key, robj *val) {
struct dictEntry *de = dictFind(db->dict,key->ptr);
dictEntry *de = dictFind(db->dict,key->ptr);
redisAssertWithInfo(NULL,key,de != NULL);
dictReplace(db->dict, key->ptr, val);
@@ -134,7 +136,7 @@ int dbExists(redisDb *db, robj *key) {
*
* The function makes sure to return keys not already expired. */
robj *dbRandomKey(redisDb *db) {
struct dictEntry *de;
dictEntry *de;
while(1) {
sds key;
@@ -161,6 +163,7 @@ int dbDelete(redisDb *db, robj *key) {
* the key, because it is shared with the main dictionary. */
if (dictSize(db->expires) > 0) dictDelete(db->expires,key->ptr);
if (dictDelete(db->dict,key->ptr) == DICT_OK) {
if (server.cluster_enabled) slotToKeyDel(key);
return 1;
} else {
return 0;
@@ -198,7 +201,7 @@ robj *dbUnshareStringValue(redisDb *db, robj *key, robj *o) {
redisAssert(o->type == REDIS_STRING);
if (o->refcount != 1 || o->encoding != REDIS_ENCODING_RAW) {
robj *decoded = getDecodedObject(o);
o = createStringObject(decoded->ptr, sdslen(decoded->ptr));
o = createRawStringObject(decoded->ptr, sdslen(decoded->ptr));
decrRefCount(decoded);
dbOverwrite(db,key,o);
}
@@ -214,6 +217,7 @@ long long emptyDb(void(callback)(void*)) {
dictEmpty(server.db[j].dict,callback);
dictEmpty(server.db[j].expires,callback);
}
if (server.cluster_enabled) slotToKeyFlush();
return removed;
}
@@ -250,6 +254,7 @@ void flushdbCommand(redisClient *c) {
signalFlushedDb(c->db->id);
dictEmpty(c->db->dict,NULL);
dictEmpty(c->db->expires,NULL);
if (server.cluster_enabled) slotToKeyFlush();
addReply(c,shared.ok);
}
@@ -303,6 +308,10 @@ void selectCommand(redisClient *c) {
"invalid DB index") != REDIS_OK)
return;
if (server.cluster_enabled && id != 0) {
addReplyError(c,"SELECT is not allowed in cluster mode");
return;
}
if (selectDb(c,id) == REDIS_ERR) {
addReplyError(c,"invalid DB index");
} else {
@@ -528,16 +537,16 @@ void scanGenericCommand(redisClient *c, robj *o, unsigned long cursor) {
/* Filter element if it does not match the pattern. */
if (!filter && use_pattern) {
if (kobj->encoding == REDIS_ENCODING_INT) {
if (sdsEncodedObject(kobj)) {
if (!stringmatchlen(pat, patlen, kobj->ptr, sdslen(kobj->ptr), 0))
filter = 1;
} else {
char buf[REDIS_LONGSTR_SIZE];
int len;
redisAssert(kobj->encoding == REDIS_ENCODING_INT);
len = ll2string(buf,sizeof(buf),(long)kobj->ptr);
if (!stringmatchlen(pat, patlen, buf, len, 0)) filter = 1;
} else {
if (!stringmatchlen(pat, patlen, kobj->ptr, sdslen(kobj->ptr), 0))
filter = 1;
}
}
@@ -698,6 +707,11 @@ void moveCommand(redisClient *c) {
redisDb *src, *dst;
int srcid;
if (server.cluster_enabled) {
addReplyError(c,"MOVE is not allowed in cluster mode");
return;
}
/* Obtain source and target DB pointers */
src = c->db;
srcid = c->db->id;
@@ -955,6 +969,8 @@ void persistCommand(redisClient *c) {
* API to get key arguments from commands
* ---------------------------------------------------------------------------*/
/* The base case is to use the keys position as given in the command table
* (firstkey, lastkey, step). */
int *getKeysUsingCommandTable(struct redisCommand *cmd,robj **argv, int argc, int *numkeys) {
int j, i = 0, last, *keys;
REDIS_NOTUSED(argv);
@@ -974,42 +990,36 @@ int *getKeysUsingCommandTable(struct redisCommand *cmd,robj **argv, int argc, in
return keys;
}
int *getKeysFromCommand(struct redisCommand *cmd,robj **argv, int argc, int *numkeys, int flags) {
/* Return all the arguments that are keys in the command passed via argc / argv.
*
* The command returns the positions of all the key arguments inside the array,
* so the actual return value is an heap allocated array of integers. The
* length of the array is returned by reference into *numkeys.
*
* 'cmd' must be point to the corresponding entry into the redisCommand
* table, according to the command name in argv[0].
*
* This function uses the command table if a command-specific helper function
* is not required, otherwise it calls the command-specific function. */
int *getKeysFromCommand(struct redisCommand *cmd, robj **argv, int argc, int *numkeys) {
if (cmd->getkeys_proc) {
return cmd->getkeys_proc(cmd,argv,argc,numkeys,flags);
return cmd->getkeys_proc(cmd,argv,argc,numkeys);
} else {
return getKeysUsingCommandTable(cmd,argv,argc,numkeys);
}
}
/* Free the result of getKeysFromCommand. */
void getKeysFreeResult(int *result) {
zfree(result);
}
int *noPreloadGetKeys(struct redisCommand *cmd,robj **argv, int argc, int *numkeys, int flags) {
if (flags & REDIS_GETKEYS_PRELOAD) {
*numkeys = 0;
return NULL;
} else {
return getKeysUsingCommandTable(cmd,argv,argc,numkeys);
}
}
int *renameGetKeys(struct redisCommand *cmd,robj **argv, int argc, int *numkeys, int flags) {
if (flags & REDIS_GETKEYS_PRELOAD) {
int *keys = zmalloc(sizeof(int));
*numkeys = 1;
keys[0] = 1;
return keys;
} else {
return getKeysUsingCommandTable(cmd,argv,argc,numkeys);
}
}
int *zunionInterGetKeys(struct redisCommand *cmd,robj **argv, int argc, int *numkeys, int flags) {
/* Helper function to extract keys from following commands:
* ZUNIONSTORE <destkey> <num-keys> <key> <key> ... <key> <options>
* ZINTERSTORE <destkey> <num-keys> <key> <key> ... <key> <options> */
int *zunionInterGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys) {
int i, num, *keys;
REDIS_NOTUSED(cmd);
REDIS_NOTUSED(flags);
num = atoi(argv[2]->ptr);
/* Sanity check. Don't return any key if the command is going to
@@ -1018,8 +1028,177 @@ int *zunionInterGetKeys(struct redisCommand *cmd,robj **argv, int argc, int *num
*numkeys = 0;
return NULL;
}
keys = zmalloc(sizeof(int)*num);
/* Keys in z{union,inter}store come from two places:
* argv[1] = storage key,
* argv[3...n] = keys to intersect */
keys = zmalloc(sizeof(int)*(num+1));
/* Add all key positions for argv[3...n] to keys[] */
for (i = 0; i < num; i++) keys[i] = 3+i;
/* Finally add the argv[1] key position (the storage key target). */
keys[num] = 1;
*numkeys = num+1; /* Total keys = {union,inter} keys + storage key */
return keys;
}
/* Helper function to extract keys from the following commands:
* EVAL <script> <num-keys> <key> <key> ... <key> [more stuff]
* EVALSHA <script> <num-keys> <key> <key> ... <key> [more stuff] */
int *evalGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys) {
int i, num, *keys;
REDIS_NOTUSED(cmd);
num = atoi(argv[2]->ptr);
/* Sanity check. Don't return any key if the command is going to
* reply with syntax error. */
if (num > (argc-3)) {
*numkeys = 0;
return NULL;
}
keys = zmalloc(sizeof(int)*num);
*numkeys = num;
/* Add all key positions for argv[3...n] to keys[] */
for (i = 0; i < num; i++) keys[i] = 3+i;
return keys;
}
/* Helper function to extract keys from the SORT command.
*
* SORT <sort-key> ... STORE <store-key> ...
*
* The first argument of SORT is always a key, however a list of options
* follow in SQL-alike style. Here we parse just the minimum in order to
* correctly identify keys in the "STORE" option. */
int *sortGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys) {
int i, j, num, *keys;
REDIS_NOTUSED(cmd);
num = 0;
keys = zmalloc(sizeof(int)*2); /* Alloc 2 places for the worst case. */
keys[num++] = 1; /* <sort-key> is always present. */
/* Search for STORE option. By default we consider options to don't
* have arguments, so if we find an unknown option name we scan the
* next. However there are options with 1 or 2 arguments, so we
* provide a list here in order to skip the right number of args. */
struct {
char *name;
int skip;
} skiplist[] = {
{"limit", 2},
{"get", 1},
{"by", 1},
{NULL, 0} /* End of elements. */
};
for (i = 2; i < argc; i++) {
for (j = 0; skiplist[j].name != NULL; j++) {
if (!strcasecmp(argv[i]->ptr,skiplist[j].name)) {
i += skiplist[j].skip;
break;
} else if (!strcasecmp(argv[i]->ptr,"store") && i+1 < argc) {
/* Note: we don't increment "num" here and continue the loop
* to be sure to process the *last* "STORE" option if multiple
* ones are provided. This is same behavior as SORT. */
keys[num] = i+1; /* <store-key> */
break;
}
}
}
*numkeys = num;
return keys;
}
/* Slot to Key API. This is used by Redis Cluster in order to obtain in
* a fast way a key that belongs to a specified hash slot. This is useful
* while rehashing the cluster. */
void slotToKeyAdd(robj *key) {
unsigned int hashslot = keyHashSlot(key->ptr,sdslen(key->ptr));
zslInsert(server.cluster->slots_to_keys,hashslot,key);
incrRefCount(key);
}
void slotToKeyDel(robj *key) {
unsigned int hashslot = keyHashSlot(key->ptr,sdslen(key->ptr));
zslDelete(server.cluster->slots_to_keys,hashslot,key);
}
void slotToKeyFlush(void) {
zslFree(server.cluster->slots_to_keys);
server.cluster->slots_to_keys = zslCreate();
}
unsigned int getKeysInSlot(unsigned int hashslot, robj **keys, unsigned int count) {
zskiplistNode *n;
zrangespec range;
int j = 0;
range.min = range.max = hashslot;
range.minex = range.maxex = 0;
n = zslFirstInRange(server.cluster->slots_to_keys, &range);
while(n && n->score == hashslot && count--) {
keys[j++] = n->obj;
n = n->level[0].forward;
}
return j;
}
/* Remove all the keys in the specified hash slot.
* The number of removed items is returned. */
unsigned int delKeysInSlot(unsigned int hashslot) {
zskiplistNode *n;
zrangespec range;
int j = 0;
range.min = range.max = hashslot;
range.minex = range.maxex = 0;
n = zslFirstInRange(server.cluster->slots_to_keys, &range);
while(n && n->score == hashslot) {
robj *key = n->obj;
n = n->level[0].forward; /* Go to the next item before freeing it. */
incrRefCount(key); /* Protect the object while freeing it. */
dbDelete(&server.db[0],key);
decrRefCount(key);
j++;
}
return j;
}
unsigned int countKeysInSlot(unsigned int hashslot) {
zskiplist *zsl = server.cluster->slots_to_keys;
zskiplistNode *zn;
zrangespec range;
int rank, count = 0;
range.min = range.max = hashslot;
range.minex = range.maxex = 0;
/* Find first element in range */
zn = zslFirstInRange(zsl, &range);
/* Use rank of first element, if any, to determine preliminary count */
if (zn != NULL) {
rank = zslGetRank(zsl, zn->score, zn->obj);
count = (zsl->length - (rank - 1));
/* Find last element in range */
zn = zslLastInRange(zsl, &range);
/* Use rank of last element, if any, to determine the actual count */
if (zn != NULL) {
rank = zslGetRank(zsl, zn->score, zn->obj);
count -= (zsl->length - rank);
}
}
return count;
}
+24 -14
View File
@@ -41,12 +41,6 @@
#include "bio.h"
#endif /* HAVE_BACKTRACE */
#ifdef __CYGWIN__
#ifndef SA_ONSTACK
#define SA_ONSTACK 0x08000000
#endif
#endif
/* ================================= Debugging ============================== */
/* Compute the sha1 of string at 's' with 'len' bytes long.
@@ -298,7 +292,7 @@ void debugCommand(redisClient *c) {
addReplyStatusFormat(c,
"Value at:%p refcount:%d "
"encoding:%s serializedlength:%lld "
"lru:%d lru_seconds_idle:%lu",
"lru:%d lru_seconds_idle:%llu",
(void*)val, val->refcount,
strenc, (long long) rdbSavedObjectLen(val),
val->lru, estimateObjectIdleTime(val));
@@ -314,7 +308,7 @@ void debugCommand(redisClient *c) {
val = dictGetVal(de);
key = dictGetKey(de);
if (val->type != REDIS_STRING || val->encoding != REDIS_ENCODING_RAW) {
if (val->type != REDIS_STRING || !sdsEncodedObject(val)) {
addReplyError(c,"Not an sds encoded string.");
} else {
addReplyStatusFormat(c,
@@ -370,6 +364,24 @@ void debugCommand(redisClient *c) {
{
server.active_expire_enabled = atoi(c->argv[2]->ptr);
addReply(c,shared.ok);
} else if (!strcasecmp(c->argv[1]->ptr,"cmdkeys") && c->argc >= 3) {
struct redisCommand *cmd = lookupCommand(c->argv[2]->ptr);
int *keys, numkeys, j;
if (!cmd) {
addReplyError(c,"Invalid command specified");
return;
} else if ((cmd->arity > 0 && cmd->arity != c->argc-2) ||
((c->argc-2) < -cmd->arity))
{
addReplyError(c,"Invalid number of arguments specified for command");
return;
}
keys = getKeysFromCommand(cmd,c->argv+2,c->argc-2,&numkeys);
addReplyMultiBulkLen(c,numkeys);
for (j = 0; j < numkeys; j++) addReplyBulk(c,c->argv[keys[j]+2]);
getKeysFreeResult(keys);
} else if (!strcasecmp(c->argv[1]->ptr,"error") && c->argc == 3) {
sds errstr = sdsnewlen("-",1);
@@ -410,9 +422,7 @@ void _redisAssertPrintClientInfo(redisClient *c) {
char buf[128];
char *arg;
if (c->argv[j]->type == REDIS_STRING &&
c->argv[j]->encoding == REDIS_ENCODING_RAW)
{
if (c->argv[j]->type == REDIS_STRING && sdsEncodedObject(c->argv[j])) {
arg = (char*) c->argv[j]->ptr;
} else {
snprintf(buf,sizeof(buf),"Object type: %d, encoding: %d",
@@ -428,7 +438,7 @@ void redisLogObjectDebugInfo(robj *o) {
redisLog(REDIS_WARNING,"Object type: %d", o->type);
redisLog(REDIS_WARNING,"Object encoding: %d", o->encoding);
redisLog(REDIS_WARNING,"Object refcount: %d", o->refcount);
if (o->type == REDIS_STRING && o->encoding == REDIS_ENCODING_RAW) {
if (o->type == REDIS_STRING && sdsEncodedObject(o)) {
redisLog(REDIS_WARNING,"Object raw string len: %zu", sdslen(o->ptr));
if (sdslen(o->ptr) < 4096) {
sds repr = sdscatrepr(sdsempty(),o->ptr,sdslen(o->ptr));
@@ -692,7 +702,7 @@ void logCurrentClient(void) {
int j;
redisLog(REDIS_WARNING, "--- CURRENT CLIENT INFO");
client = getClientInfoString(cc);
client = catClientInfoString(sdsempty(),cc);
redisLog(REDIS_WARNING,"client: %s", client);
sdsfree(client);
for (j = 0; j < cc->argc; j++) {
@@ -854,7 +864,7 @@ void sigsegvHandler(int sig, siginfo_t *info, void *secret) {
"\n=== REDIS BUG REPORT END. Make sure to include from START to END. ===\n\n"
" Please report the crash opening an issue on github:\n\n"
" http://github.com/antirez/redis/issues\n\n"
" Suspect RAM error? Use redis-server --test-memory to verify it.\n\n"
" Suspect RAM error? Use redis-server --test-memory to veryfy it.\n\n"
);
/* free(messages); Don't call free() with possibly corrupted memory. */
if (server.daemonize) unlink(server.pidfile);
+53 -1
View File
@@ -324,7 +324,7 @@ int dictAdd(dict *d, void *key, void *val)
* a value returns the dictEntry structure to the user, that will make
* sure to fill the value field as he wishes.
*
* This function is also directly exposed to user API to be called
* This function is also directly exposed to the user API to be called
* mainly in order to store non-pointers inside the hash value, example:
*
* entry = dictAddRaw(dict,mykey);
@@ -649,6 +649,58 @@ dictEntry *dictGetRandomKey(dict *d)
return he;
}
/* This is a version of dictGetRandomKey() that is modified in order to
* return multiple entries by jumping at a random place of the hash table
* and scanning linearly for entries.
*
* Returned pointers to hash table entries are stored into 'des' that
* points to an array of dictEntry pointers. The array must have room for
* at least 'count' elements, that is the argument we pass to the function
* to tell how many random elements we need.
*
* The function returns the number of items stored into 'des', that may
* be less than 'count' if the hash table has less than 'count' elements
* inside.
*
* Note that this function is not suitable when you need a good distribution
* of the returned items, but only when you need to "sample" a given number
* of continuous elements to run some kind of algorithm or to produce
* statistics. However the function is much faster than dictGetRandomKey()
* at producing N elements, and the elements are guaranteed to be non
* repeating. */
int dictGetRandomKeys(dict *d, dictEntry **des, int count) {
int j; /* internal hash table id, 0 or 1. */
int stored = 0;
if (dictSize(d) < count) count = dictSize(d);
while(stored < count) {
for (j = 0; j < 2; j++) {
/* Pick a random point inside the hash table 0 or 1. */
unsigned int i = random() & d->ht[j].sizemask;
int size = d->ht[j].size;
/* Make sure to visit every bucket by iterating 'size' times. */
while(size--) {
dictEntry *he = d->ht[j].table[i];
while (he) {
/* Collect all the elements of the buckets found non
* empty while iterating. */
*des = he;
des++;
he = he->next;
stored++;
if (stored == count) return stored;
}
i = (i+1) & d->ht[j].sizemask;
}
/* If there is only one table and we iterated it all, we should
* already have 'count' elements. Assert this condition. */
assert(dictIsRehashing(d) != 0);
}
}
return stored; /* Never reached. */
}
/* Function to reverse bits. Algorithm from:
* http://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel */
static unsigned long rev(unsigned long v) {
+1
View File
@@ -157,6 +157,7 @@ dictIterator *dictGetSafeIterator(dict *d);
dictEntry *dictNext(dictIterator *iter);
void dictReleaseIterator(dictIterator *iter);
dictEntry *dictGetRandomKey(dict *d);
int dictGetRandomKeys(dict *d, dictEntry **des, int count);
void dictPrintStats(dict *d);
unsigned int dictGenHashFunction(const void *key, int len);
unsigned int dictGenCaseHashFunction(const unsigned char *buf, int len);
+10
View File
@@ -61,4 +61,14 @@ uint64_t intrev64(uint64_t v);
#define intrev64ifbe(v) intrev64(v)
#endif
/* The functions htonu64() and ntohu64() convert the specified value to
* network byte ordering and back. In big endian systems they are no-ops. */
#if (BYTE_ORDER == BIG_ENDIAN)
#define htonu64(v) (v)
#define ntohu64(v) (v)
#else
#define htonu64(v) intrev64(v)
#define ntohu64(v) intrev64(v)
#endif
#endif
-247
View File
@@ -1,247 +0,0 @@
#include "redis.h"
#include "endianconv.h"
/* -----------------------------------------------------------------------------
* DUMP, RESTORE and MIGRATE commands
* -------------------------------------------------------------------------- */
/* Generates a DUMP-format representation of the object 'o', adding it to the
* io stream pointed by 'rio'. This function can't fail. */
void createDumpPayload(rio *payload, robj *o) {
unsigned char buf[2];
uint64_t crc;
/* Serialize the object in a RDB-like format. It consist of an object type
* byte followed by the serialized object. This is understood by RESTORE. */
rioInitWithBuffer(payload,sdsempty());
redisAssert(rdbSaveObjectType(payload,o));
redisAssert(rdbSaveObject(payload,o));
/* Write the footer, this is how it looks like:
* ----------------+---------------------+---------------+
* ... RDB payload | 2 bytes RDB version | 8 bytes CRC64 |
* ----------------+---------------------+---------------+
* RDB version and CRC are both in little endian.
*/
/* RDB version */
buf[0] = REDIS_RDB_VERSION & 0xff;
buf[1] = (REDIS_RDB_VERSION >> 8) & 0xff;
payload->io.buffer.ptr = sdscatlen(payload->io.buffer.ptr,buf,2);
/* CRC64 */
crc = crc64(0,(unsigned char*)payload->io.buffer.ptr,
sdslen(payload->io.buffer.ptr));
memrev64ifbe(&crc);
payload->io.buffer.ptr = sdscatlen(payload->io.buffer.ptr,&crc,8);
}
/* Verify that the RDB version of the dump payload matches the one of this Redis
* instance and that the checksum is ok.
* If the DUMP payload looks valid REDIS_OK is returned, otherwise REDIS_ERR
* is returned. */
int verifyDumpPayload(unsigned char *p, size_t len) {
unsigned char *footer;
uint16_t rdbver;
uint64_t crc;
/* At least 2 bytes of RDB version and 8 of CRC64 should be present. */
if (len < 10) return REDIS_ERR;
footer = p+(len-10);
/* Verify RDB version */
rdbver = (footer[1] << 8) | footer[0];
if (rdbver != REDIS_RDB_VERSION) return REDIS_ERR;
/* Verify CRC64 */
crc = crc64(0,p,len-8);
memrev64ifbe(&crc);
return (memcmp(&crc,footer+2,8) == 0) ? REDIS_OK : REDIS_ERR;
}
/* DUMP keyname
* DUMP is actually not used by Redis Cluster but it is the obvious
* complement of RESTORE and can be useful for different applications. */
void dumpCommand(redisClient *c) {
robj *o, *dumpobj;
rio payload;
/* Check if the key is here. */
if ((o = lookupKeyRead(c->db,c->argv[1])) == NULL) {
addReply(c,shared.nullbulk);
return;
}
/* Create the DUMP encoded representation. */
createDumpPayload(&payload,o);
/* Transfer to the client */
dumpobj = createObject(REDIS_STRING,payload.io.buffer.ptr);
addReplyBulk(c,dumpobj);
decrRefCount(dumpobj);
return;
}
/* RESTORE key ttl serialized-value */
void restoreCommand(redisClient *c) {
long long ttl;
rio payload;
int type;
robj *obj;
/* Make sure this key does not already exist here... */
if (lookupKeyWrite(c->db,c->argv[1]) != NULL) {
addReplyError(c,"Target key name is busy.");
return;
}
/* Check if the TTL value makes sense */
if (getLongLongFromObjectOrReply(c,c->argv[2],&ttl,NULL) != REDIS_OK) {
return;
} else if (ttl < 0) {
addReplyError(c,"Invalid TTL value, must be >= 0");
return;
}
/* Verify RDB version and data checksum. */
if (verifyDumpPayload(c->argv[3]->ptr,sdslen(c->argv[3]->ptr)) == REDIS_ERR)
{
addReplyError(c,"DUMP payload version or checksum are wrong");
return;
}
rioInitWithBuffer(&payload,c->argv[3]->ptr);
if (((type = rdbLoadObjectType(&payload)) == -1) ||
((obj = rdbLoadObject(type,&payload)) == NULL))
{
addReplyError(c,"Bad data format");
return;
}
/* Create the key and set the TTL if any */
dbAdd(c->db,c->argv[1],obj);
if (ttl) setExpire(c->db,c->argv[1],mstime()+ttl);
signalModifiedKey(c->db,c->argv[1]);
addReply(c,shared.ok);
server.dirty++;
}
/* MIGRATE host port key dbid timeout */
void migrateCommand(redisClient *c) {
int fd;
long timeout;
long dbid;
long long ttl = 0, expireat;
robj *o;
rio cmd, payload;
/* Sanity check */
if (getLongFromObjectOrReply(c,c->argv[5],&timeout,NULL) != REDIS_OK)
return;
if (getLongFromObjectOrReply(c,c->argv[4],&dbid,NULL) != REDIS_OK)
return;
if (timeout <= 0) timeout = 1;
/* Check if the key is here. If not we reply with success as there is
* nothing to migrate (for instance the key expired in the meantime), but
* we include such information in the reply string. */
if ((o = lookupKeyRead(c->db,c->argv[3])) == NULL) {
addReplySds(c,sdsnew("+NOKEY\r\n"));
return;
}
/* Connect */
fd = anetTcpNonBlockConnect(server.neterr,c->argv[1]->ptr,
atoi(c->argv[2]->ptr));
if (fd == -1) {
addReplyErrorFormat(c,"Can't connect to target node: %s",
server.neterr);
return;
}
if ((aeWait(fd,AE_WRITABLE,timeout*1000) & AE_WRITABLE) == 0) {
addReplySds(c,sdsnew("-IOERR error or timeout connecting to the client\r\n"));
return;
}
/* Create RESTORE payload and generate the protocol to call the command. */
rioInitWithBuffer(&cmd,sdsempty());
redisAssertWithInfo(c,NULL,rioWriteBulkCount(&cmd,'*',2));
redisAssertWithInfo(c,NULL,rioWriteBulkString(&cmd,"SELECT",6));
redisAssertWithInfo(c,NULL,rioWriteBulkLongLong(&cmd,dbid));
expireat = getExpire(c->db,c->argv[3]);
if (expireat != -1) {
ttl = expireat-mstime();
if (ttl < 1) ttl = 1;
}
redisAssertWithInfo(c,NULL,rioWriteBulkCount(&cmd,'*',4));
redisAssertWithInfo(c,NULL,rioWriteBulkString(&cmd,"RESTORE",7));
redisAssertWithInfo(c,NULL,c->argv[3]->encoding == REDIS_ENCODING_RAW);
redisAssertWithInfo(c,NULL,rioWriteBulkString(&cmd,c->argv[3]->ptr,sdslen(c->argv[3]->ptr)));
redisAssertWithInfo(c,NULL,rioWriteBulkLongLong(&cmd,ttl));
/* Finally the last argument that is the serailized object payload
* in the DUMP format. */
createDumpPayload(&payload,o);
redisAssertWithInfo(c,NULL,rioWriteBulkString(&cmd,payload.io.buffer.ptr,
sdslen(payload.io.buffer.ptr)));
sdsfree(payload.io.buffer.ptr);
/* Tranfer the query to the other node in 64K chunks. */
{
sds buf = cmd.io.buffer.ptr;
size_t pos = 0, towrite;
int nwritten = 0;
while ((towrite = sdslen(buf)-pos) > 0) {
towrite = (towrite > (64*1024) ? (64*1024) : towrite);
nwritten = syncWrite(fd,buf+pos,towrite,timeout);
if (nwritten != (signed)towrite) goto socket_wr_err;
pos += nwritten;
}
}
/* Read back the reply. */
{
char buf1[1024];
char buf2[1024];
/* Read the two replies */
if (syncReadLine(fd, buf1, sizeof(buf1), timeout) <= 0)
goto socket_rd_err;
if (syncReadLine(fd, buf2, sizeof(buf2), timeout) <= 0)
goto socket_rd_err;
if (buf1[0] == '-' || buf2[0] == '-') {
addReplyErrorFormat(c,"Target instance replied with error: %s",
(buf1[0] == '-') ? buf1+1 : buf2+1);
} else {
robj *aux;
dbDelete(c->db,c->argv[3]);
signalModifiedKey(c->db,c->argv[3]);
addReply(c,shared.ok);
server.dirty++;
/* Translate MIGRATE as DEL for replication/AOF. */
aux = createStringObject("DEL",3);
rewriteClientCommandVector(c,2,aux,c->argv[3]);
decrRefCount(aux);
}
}
sdsfree(cmd.io.buffer.ptr);
close(fd);
return;
socket_wr_err:
addReplySds(c,sdsnew("-IOERR error or timeout writing to target instance\r\n"));
sdsfree(cmd.io.buffer.ptr);
close(fd);
return;
socket_rd_err:
addReplySds(c,sdsnew("-IOERR error or timeout reading from target node\r\n"));
sdsfree(cmd.io.buffer.ptr);
close(fd);
return;
}
+136 -44
View File
@@ -41,6 +41,17 @@ size_t zmalloc_size_sds(sds s) {
return zmalloc_size(s-sizeof(struct sdshdr));
}
/* Return the amount of memory used by the sds string at object->ptr
* for a string object. */
size_t getStringObjectSdsUsedMemory(robj *o) {
redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
switch(o->encoding) {
case REDIS_ENCODING_RAW: return zmalloc_size_sds(o->ptr);
case REDIS_ENCODING_EMBSTR: return sdslen(o->ptr);
default: return 0; /* Just integer encoding for now. */
}
}
void *dupClientReplyValue(void *o) {
incrRefCount((robj*)o);
return o;
@@ -97,12 +108,17 @@ redisClient *createClient(int fd) {
c->obuf_soft_limit_reached_time = 0;
listSetFreeMethod(c->reply,decrRefCountVoid);
listSetDupMethod(c->reply,dupClientReplyValue);
c->bpop.keys = dictCreate(&setDictType,NULL);
c->btype = REDIS_BLOCKED_NONE;
c->bpop.timeout = 0;
c->bpop.keys = dictCreate(&setDictType,NULL);
c->bpop.target = NULL;
c->bpop.numreplicas = 0;
c->bpop.reploffset = 0;
c->woff = 0;
c->watched_keys = listCreate();
c->pubsub_channels = dictCreate(&setDictType,NULL);
c->pubsub_patterns = listCreate();
c->peerid = NULL;
listSetFreeMethod(c->pubsub_patterns,decrRefCountVoid);
listSetMatchMethod(c->pubsub_patterns,listMatchObjects);
if (fd != -1) listAddNodeTail(server.clients,c);
@@ -182,12 +198,13 @@ void _addReplyObjectToList(redisClient *c, robj *o) {
if (listLength(c->reply) == 0) {
incrRefCount(o);
listAddNodeTail(c->reply,o);
c->reply_bytes += zmalloc_size_sds(o->ptr);
c->reply_bytes += getStringObjectSdsUsedMemory(o);
} else {
tail = listNodeValue(listLast(c->reply));
/* Append to this object when possible. */
if (tail->ptr != NULL &&
tail->encoding == REDIS_ENCODING_RAW &&
sdslen(tail->ptr)+sdslen(o->ptr) <= REDIS_REPLY_CHUNK_BYTES)
{
c->reply_bytes -= zmalloc_size_sds(tail->ptr);
@@ -197,7 +214,7 @@ void _addReplyObjectToList(redisClient *c, robj *o) {
} else {
incrRefCount(o);
listAddNodeTail(c->reply,o);
c->reply_bytes += zmalloc_size_sds(o->ptr);
c->reply_bytes += getStringObjectSdsUsedMemory(o);
}
}
asyncCloseClientOnOutputBufferLimitReached(c);
@@ -220,7 +237,7 @@ void _addReplySdsToList(redisClient *c, sds s) {
tail = listNodeValue(listLast(c->reply));
/* Append to this object when possible. */
if (tail->ptr != NULL &&
if (tail->ptr != NULL && tail->encoding == REDIS_ENCODING_RAW &&
sdslen(tail->ptr)+sdslen(s) <= REDIS_REPLY_CHUNK_BYTES)
{
c->reply_bytes -= zmalloc_size_sds(tail->ptr);
@@ -245,12 +262,12 @@ void _addReplyStringToList(redisClient *c, char *s, size_t len) {
robj *o = createStringObject(s,len);
listAddNodeTail(c->reply,o);
c->reply_bytes += zmalloc_size_sds(o->ptr);
c->reply_bytes += getStringObjectSdsUsedMemory(o);
} else {
tail = listNodeValue(listLast(c->reply));
/* Append to this object when possible. */
if (tail->ptr != NULL &&
if (tail->ptr != NULL && tail->encoding == REDIS_ENCODING_RAW &&
sdslen(tail->ptr)+len <= REDIS_REPLY_CHUNK_BYTES)
{
c->reply_bytes -= zmalloc_size_sds(tail->ptr);
@@ -261,7 +278,7 @@ void _addReplyStringToList(redisClient *c, char *s, size_t len) {
robj *o = createStringObject(s,len);
listAddNodeTail(c->reply,o);
c->reply_bytes += zmalloc_size_sds(o->ptr);
c->reply_bytes += getStringObjectSdsUsedMemory(o);
}
}
asyncCloseClientOnOutputBufferLimitReached(c);
@@ -282,7 +299,7 @@ void addReply(redisClient *c, robj *obj) {
* If the encoding is RAW and there is room in the static buffer
* we'll be able to send the object to the client without
* messing with its page. */
if (obj->encoding == REDIS_ENCODING_RAW) {
if (sdsEncodedObject(obj)) {
if (_addReplyToBuffer(c,obj->ptr,sdslen(obj->ptr)) != REDIS_OK)
_addReplyObjectToList(c,obj);
} else if (obj->encoding == REDIS_ENCODING_INT) {
@@ -394,6 +411,7 @@ void setDeferredMultiBulkLength(redisClient *c, void *node, long length) {
len = listNodeValue(ln);
len->ptr = sdscatprintf(sdsempty(),"*%ld\r\n",length);
len->encoding = REDIS_ENCODING_RAW; /* in case it was an EMBSTR. */
c->reply_bytes += zmalloc_size_sds(len->ptr);
if (ln->next != NULL) {
next = listNodeValue(ln->next);
@@ -401,7 +419,7 @@ void setDeferredMultiBulkLength(redisClient *c, void *node, long length) {
/* Only glue when the next node is non-NULL (an sds in this case) */
if (next->ptr != NULL) {
c->reply_bytes -= zmalloc_size_sds(len->ptr);
c->reply_bytes -= zmalloc_size_sds(next->ptr);
c->reply_bytes -= getStringObjectSdsUsedMemory(next);
len->ptr = sdscatlen(len->ptr,next->ptr,sdslen(next->ptr));
c->reply_bytes += zmalloc_size_sds(len->ptr);
listDelNode(c->reply,ln->next);
@@ -469,7 +487,7 @@ void addReplyMultiBulkLen(redisClient *c, long length) {
void addReplyBulkLen(redisClient *c, robj *obj) {
size_t len;
if (obj->encoding == REDIS_ENCODING_RAW) {
if (sdsEncodedObject(obj)) {
len = sdslen(obj->ptr);
} else {
long n = (long)obj->ptr;
@@ -672,8 +690,7 @@ void freeClient(redisClient *c) {
c->querybuf = NULL;
/* Deallocate structures used to block on blocking ops. */
if (c->flags & REDIS_BLOCKED)
unblockClientWaitingData(c);
if (c->flags & REDIS_BLOCKED) unblockClient(c);
dictRelease(c->bpop.keys);
/* UNWATCH all the keys */
@@ -714,8 +731,10 @@ void freeClient(redisClient *c) {
/* Master/slave cleanup Case 1:
* we lost the connection with a slave. */
if (c->flags & REDIS_SLAVE) {
if (c->replstate == REDIS_REPL_SEND_BULK && c->repldbfd != -1)
close(c->repldbfd);
if (c->replstate == REDIS_REPL_SEND_BULK) {
if (c->repldbfd != -1) close(c->repldbfd);
if (c->replpreamble) sdsfree(c->replpreamble);
}
list *l = (c->flags & REDIS_MONITOR) ? server.monitors : server.slaves;
ln = listSearchKey(l,c);
redisAssert(ln != NULL);
@@ -745,6 +764,7 @@ void freeClient(redisClient *c) {
if (c->name) decrRefCount(c->name);
zfree(c->argv);
freeClientMultiState(c);
sdsfree(c->peerid);
zfree(c);
}
@@ -793,10 +813,11 @@ void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
} else {
o = listNodeValue(listFirst(c->reply));
objlen = sdslen(o->ptr);
objmem = zmalloc_size_sds(o->ptr);
objmem = getStringObjectSdsUsedMemory(o);
if (objlen == 0) {
listDelNode(c->reply,listFirst(c->reply));
c->reply_bytes -= objmem;
continue;
}
@@ -852,12 +873,16 @@ void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
/* resetClient prepare the client to process the next command */
void resetClient(redisClient *c) {
redisCommandProc *prevcmd = c->cmd ? c->cmd->proc : NULL;
freeClientArgv(c);
c->reqtype = 0;
c->multibulklen = 0;
c->bulklen = -1;
/* We clear the ASKING flag as well if we are not inside a MULTI. */
if (!(c->flags & REDIS_MULTI)) c->flags &= (~REDIS_ASKING);
/* We clear the ASKING flag as well if we are not inside a MULTI, and
* if what we just executed is not the ASKING command itself. */
if (!(c->flags & REDIS_MULTI) && prevcmd != askingCommand)
c->flags &= (~REDIS_ASKING);
}
int processInlineBuffer(redisClient *c) {
@@ -923,7 +948,7 @@ int processInlineBuffer(redisClient *c) {
* multi bulk requests idempotent. */
static void setProtocolError(redisClient *c, int pos) {
if (server.verbosity >= REDIS_VERBOSE) {
sds client = getClientInfoString(c);
sds client = catClientInfoString(sdsempty(),c);
redisLog(REDIS_VERBOSE,
"Protocol error from client: %s", client);
sdsfree(client);
@@ -1073,6 +1098,9 @@ int processMultibulkBuffer(redisClient *c) {
void processInputBuffer(redisClient *c) {
/* Keep processing while there is something in the input buffer */
while(sdslen(c->querybuf)) {
/* Return if clients are paused. */
if (!(c->flags & REDIS_SLAVE) && clientsArePaused()) return;
/* Immediately abort if the client is in the middle of something. */
if (c->flags & REDIS_BLOCKED) return;
@@ -1158,7 +1186,7 @@ void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
return;
}
if (sdslen(c->querybuf) > server.client_max_querybuf_len) {
sds ci = getClientInfoString(c), bytes = sdsempty();
sds ci = catClientInfoString(sdsempty(),c), bytes = sdsempty();
bytes = sdscatrepr(bytes,c->querybuf,64);
redisLog(REDIS_WARNING,"Closing client that reached max query buffer length: %s (qbuf initial bytes: %s)", ci, bytes);
@@ -1189,7 +1217,7 @@ void getClientsMaxBuffers(unsigned long *longest_output_list,
*biggest_input_buffer = bib;
}
/* This is a helper function for getClientPeerId().
/* This is a helper function for genClientPeerId().
* It writes the specified ip/port to "peerid" as a null termiated string
* in the form ip:port if ip does not contain ":" itself, otherwise
* [ip]:port format is used (for IPv6 addresses basically). */
@@ -1213,7 +1241,7 @@ void formatPeerId(char *peerid, size_t peerid_len, char *ip, int port) {
* On failure the function still populates 'peerid' with the "?:0" string
* in case you want to relax error checking or need to display something
* anyway (see anetPeerToString implementation for more info). */
int getClientPeerId(redisClient *client, char *peerid, size_t peerid_len) {
int genClientPeerId(redisClient *client, char *peerid, size_t peerid_len) {
char ip[REDIS_IP_STR_LEN];
int port;
@@ -1229,12 +1257,26 @@ int getClientPeerId(redisClient *client, char *peerid, size_t peerid_len) {
}
}
/* Turn a Redis client into an sds string representing its state. */
sds getClientInfoString(redisClient *client) {
char peerid[REDIS_PEER_ID_LEN], flags[16], events[3], *p;
/* This function returns the client peer id, by creating and caching it
* if client->perrid is NULL, otherwise returning the cached value.
* The Peer ID never changes during the life of the client, however it
* is expensive to compute. */
char *getClientPeerId(redisClient *c) {
char peerid[REDIS_PEER_ID_LEN];
if (c->peerid == NULL) {
genClientPeerId(c,peerid,sizeof(peerid));
c->peerid = sdsnew(peerid);
}
return c->peerid;
}
/* Concatenate a string representing the state of a client in an human
* readable format, into the sds string 's'. */
sds catClientInfoString(sds s, redisClient *client) {
char flags[16], events[3], *p;
int emask;
getClientPeerId(client,peerid,sizeof(peerid));
p = flags;
if (client->flags & REDIS_SLAVE) {
if (client->flags & REDIS_MONITOR)
@@ -1250,6 +1292,7 @@ sds getClientInfoString(redisClient *client) {
if (client->flags & REDIS_UNBLOCKED) *p++ = 'u';
if (client->flags & REDIS_CLOSE_ASAP) *p++ = 'A';
if (client->flags & REDIS_UNIX_SOCKET) *p++ = 'U';
if (client->flags & REDIS_READONLY) *p++ = 'r';
if (p == flags) *p++ = 'N';
*p++ = '\0';
@@ -1258,23 +1301,23 @@ sds getClientInfoString(redisClient *client) {
if (emask & AE_READABLE) *p++ = 'r';
if (emask & AE_WRITABLE) *p++ = 'w';
*p = '\0';
return sdscatprintf(sdsempty(),
"addr=%s fd=%d name=%s age=%ld idle=%ld flags=%s db=%d sub=%d psub=%d multi=%d qbuf=%lu qbuf-free=%lu obl=%lu oll=%lu omem=%lu events=%s cmd=%s",
peerid,
return sdscatfmt(s,
"addr=%s fd=%i name=%s age=%I idle=%I flags=%s db=%i sub=%i psub=%i multi=%i qbuf=%U qbuf-free=%U obl=%U oll=%U omem=%U events=%s cmd=%s",
getClientPeerId(client),
client->fd,
client->name ? (char*)client->name->ptr : "",
(long)(server.unixtime - client->ctime),
(long)(server.unixtime - client->lastinteraction),
(long long)(server.unixtime - client->ctime),
(long long)(server.unixtime - client->lastinteraction),
flags,
client->db->id,
(int) dictSize(client->pubsub_channels),
(int) listLength(client->pubsub_patterns),
(client->flags & REDIS_MULTI) ? client->mstate.count : -1,
(unsigned long) sdslen(client->querybuf),
(unsigned long) sdsavail(client->querybuf),
(unsigned long) client->bufpos,
(unsigned long) listLength(client->reply),
getClientOutputBufferMemoryUsage(client),
(unsigned long long) sdslen(client->querybuf),
(unsigned long long) sdsavail(client->querybuf),
(unsigned long long) client->bufpos,
(unsigned long long) listLength(client->reply),
(unsigned long long) getClientOutputBufferMemoryUsage(client),
events,
client->lastcmd ? client->lastcmd->name : "NULL");
}
@@ -1285,14 +1328,11 @@ sds getAllClientsInfoString(void) {
redisClient *client;
sds o = sdsempty();
o = sdsMakeRoomFor(o,200*listLength(server.clients));
listRewind(server.clients,&li);
while ((ln = listNext(&li)) != NULL) {
sds cs;
client = listNodeValue(ln);
cs = getClientInfoString(client);
o = sdscatsds(o,cs);
sdsfree(cs);
o = catClientInfoString(o,client);
o = sdscatlen(o,"\n",1);
}
return o;
@@ -1310,11 +1350,10 @@ void clientCommand(redisClient *c) {
} else if (!strcasecmp(c->argv[1]->ptr,"kill") && c->argc == 3) {
listRewind(server.clients,&li);
while ((ln = listNext(&li)) != NULL) {
char peerid[REDIS_PEER_ID_LEN];
char *peerid;
client = listNodeValue(ln);
if (getClientPeerId(client,peerid,sizeof(peerid)) == REDIS_ERR)
continue;
peerid = getClientPeerId(client);
if (strcmp(peerid,c->argv[2]->ptr) == 0) {
addReply(c,shared.ok);
if (c == client) {
@@ -1359,6 +1398,13 @@ void clientCommand(redisClient *c) {
addReplyBulk(c,c->name);
else
addReply(c,shared.nullbulk);
} else if (!strcasecmp(c->argv[1]->ptr,"pause") && c->argc == 3) {
long long duration;
if (getTimeoutFromObjectOrReply(c,c->argv[2],&duration,UNIT_MILLISECONDS)
!= REDIS_OK) return;
pauseClients(duration);
addReply(c,shared.ok);
} else {
addReplyError(c, "Syntax error, try CLIENT (LIST | KILL ip:port | GETNAME | SETNAME connection-name)");
}
@@ -1513,7 +1559,7 @@ void asyncCloseClientOnOutputBufferLimitReached(redisClient *c) {
redisAssert(c->reply_bytes < ULONG_MAX-(1024*64));
if (c->reply_bytes == 0 || c->flags & REDIS_CLOSE_ASAP) return;
if (checkClientOutputBufferLimits(c)) {
sds client = getClientInfoString(c);
sds client = catClientInfoString(sdsempty(),c);
freeClientAsync(c);
redisLog(REDIS_WARNING,"Client %s scheduled to be closed ASAP for overcoming of output buffer limits.", client);
@@ -1542,6 +1588,52 @@ void flushSlavesOutputBuffers(void) {
}
}
/* Pause clients up to the specified unixtime (in ms). While clients
* are paused no command is processed from clients, so the data set can't
* change during that time.
*
* However while this function pauses normal and Pub/Sub clients, slaves are
* still served, so this function can be used on server upgrades where it is
* required that slaves process the latest bytes from the replication stream
* before being turned to masters.
*
* This function is also internally used by Redis Cluster for the manual
* failover procedure implemented by CLUSTER FAILOVER.
*
* The function always succeed, even if there is already a pause in progress.
* In such a case, the pause is extended if the duration is more than the
* time left for the previous duration. However if the duration is smaller
* than the time left for the previous pause, no change is made to the
* left duration. */
void pauseClients(mstime_t end) {
if (!server.clients_paused || end > server.clients_pause_end_time)
server.clients_pause_end_time = end;
server.clients_paused = 1;
}
/* Return non-zero if clients are currently paused. As a side effect the
* function checks if the pause time was reached and clear it. */
int clientsArePaused(void) {
if (server.clients_paused && server.clients_pause_end_time < server.mstime) {
listNode *ln;
listIter li;
redisClient *c;
server.clients_paused = 0;
/* Put all the clients in the unblocked clients queue in order to
* force the re-processing of the input buffer if any. */
listRewind(server.clients,&li);
while ((ln = listNext(&li)) != NULL) {
c = listNodeValue(ln);
if (c->flags & REDIS_SLAVE) continue;
listAddNodeTail(server.unblocked_clients,c);
}
}
return server.clients_paused;
}
/* This function is called by Redis in order to process a few events from
* time to time while blocked into some not interruptible operation.
* This allows to reply to clients with the -LOADING error while loading the
+154 -70
View File
@@ -32,10 +32,6 @@
#include <math.h>
#include <ctype.h>
#ifdef __CYGWIN__
#define strtold(a,b) ((long double)strtod((a),(b)))
#endif
robj *createObject(int type, void *ptr) {
robj *o = zmalloc(sizeof(*o));
o->type = type;
@@ -44,14 +40,54 @@ robj *createObject(int type, void *ptr) {
o->refcount = 1;
/* Set the LRU to the current lruclock (minutes resolution). */
o->lru = server.lruclock;
o->lru = LRU_CLOCK();
return o;
}
robj *createStringObject(char *ptr, size_t len) {
/* Create a string object with encoding REDIS_ENCODING_RAW, that is a plain
* string object where o->ptr points to a proper sds string. */
robj *createRawStringObject(char *ptr, size_t len) {
return createObject(REDIS_STRING,sdsnewlen(ptr,len));
}
/* Create a string object with encoding REDIS_ENCODING_EMBSTR, that is
* an object where the sds string is actually an unmodifiable string
* allocated in the same chunk as the object itself. */
robj *createEmbeddedStringObject(char *ptr, size_t len) {
robj *o = zmalloc(sizeof(robj)+sizeof(struct sdshdr)+len+1);
struct sdshdr *sh = (void*)(o+1);
o->type = REDIS_STRING;
o->encoding = REDIS_ENCODING_EMBSTR;
o->ptr = sh+1;
o->refcount = 1;
o->lru = LRU_CLOCK();
sh->len = len;
sh->free = 0;
if (ptr) {
memcpy(sh->buf,ptr,len);
sh->buf[len] = '\0';
} else {
memset(sh->buf,0,len+1);
}
return o;
}
/* Create a string object with EMBSTR encoding if it is smaller than
* REIDS_ENCODING_EMBSTR_SIZE_LIMIT, otherwise the RAW encoding is
* used.
*
* The current limit of 39 is chosen so that the biggest string object
* we allocate as EMBSTR will still fit into the 64 byte arena of jemalloc. */
#define REDIS_ENCODING_EMBSTR_SIZE_LIMIT 39
robj *createStringObject(char *ptr, size_t len) {
if (len <= REDIS_ENCODING_EMBSTR_SIZE_LIMIT)
return createEmbeddedStringObject(ptr,len);
else
return createRawStringObject(ptr,len);
}
robj *createStringObjectFromLongLong(long long value) {
robj *o;
if (value >= 0 && value < REDIS_SHARED_INTEGERS) {
@@ -93,9 +129,33 @@ robj *createStringObjectFromLongDouble(long double value) {
return createStringObject(buf,len);
}
/* Duplicate a string object, with the guarantee that the returned object
* has the same encoding as the original one.
*
* This function also guarantees that duplicating a small integere object
* (or a string object that contains a representation of a small integer)
* will always result in a fresh object that is unshared (refcount == 1).
*
* The resulting object always has refcount set to 1. */
robj *dupStringObject(robj *o) {
redisAssertWithInfo(NULL,o,o->encoding == REDIS_ENCODING_RAW);
return createStringObject(o->ptr,sdslen(o->ptr));
robj *d;
redisAssert(o->type == REDIS_STRING);
switch(o->encoding) {
case REDIS_ENCODING_RAW:
return createRawStringObject(o->ptr,sdslen(o->ptr));
case REDIS_ENCODING_EMBSTR:
return createEmbeddedStringObject(o->ptr,sdslen(o->ptr));
case REDIS_ENCODING_INT:
d = createObject(REDIS_STRING, NULL);
d->encoding = REDIS_ENCODING_INT;
d->ptr = o->ptr;
return d;
default:
redisPanic("Wrong encoding.");
break;
}
}
robj *createListObject(void) {
@@ -284,57 +344,76 @@ robj *tryObjectEncoding(robj *o) {
sds s = o->ptr;
size_t len;
if (o->encoding != REDIS_ENCODING_RAW)
return o; /* Already encoded */
/* It's not safe to encode shared objects: shared objects can be shared
* everywhere in the "object space" of Redis. Encoded objects can only
* appear as "values" (and not, for instance, as keys) */
if (o->refcount > 1) return o;
/* Currently we try to encode only strings */
/* Make sure this is a string object, the only type we encode
* in this function. Other types use encoded memory efficient
* representations but are handled by the commands implementing
* the type. */
redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
/* Check if we can represent this string as a long integer */
/* We try some specialized encoding only for objects that are
* RAW or EMBSTR encoded, in other words objects that are still
* in represented by an actually array of chars. */
if (!sdsEncodedObject(o)) return o;
/* It's not safe to encode shared objects: shared objects can be shared
* everywhere in the "object space" of Redis and may end in places where
* they are not handled. We handle them only as values in the keyspace. */
if (o->refcount > 1) return o;
/* Check if we can represent this string as a long integer.
* Note that we are sure that a string larger than 21 chars is not
* representable as a 32 nor 64 bit integer. */
len = sdslen(s);
if (len > 21 || !string2l(s,len,&value)) {
/* We can't encode the object...
*
* Do the last try, and at least optimize the SDS string inside
* the string object to require little space, in case there
* is more than 10% of free space at the end of the SDS string.
*
* We do that for larger strings, using the arbitrary value
* of 32 bytes. This code was backported from the unstable branch
* where this is performed when the object is too large to be
* encoded as EMBSTR. */
if (len > 32 &&
o->encoding == REDIS_ENCODING_RAW &&
sdsavail(s) > len/10)
if (len <= 21 && string2l(s,len,&value)) {
/* This object is encodable as a long. Try to use a shared object.
* Note that we avoid using shared integers when maxmemory is used
* because every object needs to have a private LRU field for the LRU
* algorithm to work well. */
if (server.maxmemory == 0 &&
value >= 0 &&
value < REDIS_SHARED_INTEGERS)
{
o->ptr = sdsRemoveFreeSpace(o->ptr);
decrRefCount(o);
incrRefCount(shared.integers[value]);
return shared.integers[value];
} else {
if (o->encoding == REDIS_ENCODING_RAW) sdsfree(o->ptr);
o->encoding = REDIS_ENCODING_INT;
o->ptr = (void*) value;
return o;
}
/* Return the original object. */
return o;
}
/* Ok, this object can be encoded...
*
* Can I use a shared object? Only if the object is inside a given range
*
* Note that we also avoid using shared integers when maxmemory is used
* because every object needs to have a private LRU field for the LRU
* algorithm to work well. */
if (server.maxmemory == 0 && value >= 0 && value < REDIS_SHARED_INTEGERS) {
/* If the string is small and is still RAW encoded,
* try the EMBSTR encoding which is more efficient.
* In this representation the object and the SDS string are allocated
* in the same chunk of memory to save space and cache misses. */
if (len <= REDIS_ENCODING_EMBSTR_SIZE_LIMIT) {
robj *emb;
if (o->encoding == REDIS_ENCODING_EMBSTR) return o;
emb = createEmbeddedStringObject(s,sdslen(s));
decrRefCount(o);
incrRefCount(shared.integers[value]);
return shared.integers[value];
} else {
o->encoding = REDIS_ENCODING_INT;
sdsfree(o->ptr);
o->ptr = (void*) value;
return o;
return emb;
}
/* We can't encode the object...
*
* Do the last try, and at least optimize the SDS string inside
* the string object to require little space, in case there
* is more than 10% of free space at the end of the SDS string.
*
* We do that only for relatively large strings as this branch
* is only entered if the length of the string is greater than
* REDIS_ENCODING_EMBSTR_SIZE_LIMIT. */
if (o->encoding == REDIS_ENCODING_RAW &&
sdsavail(s) > len/10)
{
o->ptr = sdsRemoveFreeSpace(o->ptr);
}
/* Return the original object. */
return o;
}
/* Get a decoded version of an encoded object (returned as a new object).
@@ -342,7 +421,7 @@ robj *tryObjectEncoding(robj *o) {
robj *getDecodedObject(robj *o) {
robj *dec;
if (o->encoding == REDIS_ENCODING_RAW) {
if (sdsEncodedObject(o)) {
incrRefCount(o);
return o;
}
@@ -374,19 +453,19 @@ int compareStringObjectsWithFlags(robj *a, robj *b, int flags) {
size_t alen, blen, minlen;
if (a == b) return 0;
if (a->encoding != REDIS_ENCODING_RAW) {
alen = ll2string(bufa,sizeof(bufa),(long) a->ptr);
astr = bufa;
} else {
if (sdsEncodedObject(a)) {
astr = a->ptr;
alen = sdslen(astr);
}
if (b->encoding != REDIS_ENCODING_RAW) {
blen = ll2string(bufb,sizeof(bufb),(long) b->ptr);
bstr = bufb;
} else {
alen = ll2string(bufa,sizeof(bufa),(long) a->ptr);
astr = bufa;
}
if (sdsEncodedObject(b)) {
bstr = b->ptr;
blen = sdslen(bstr);
} else {
blen = ll2string(bufb,sizeof(bufb),(long) b->ptr);
bstr = bufb;
}
if (flags & REDIS_COMPARE_COLL) {
return strcoll(astr,bstr);
@@ -415,7 +494,10 @@ int collateStringObjects(robj *a, robj *b) {
* this function is faster then checking for (compareStringObject(a,b) == 0)
* because it can perform some more optimization. */
int equalStringObjects(robj *a, robj *b) {
if (a->encoding != REDIS_ENCODING_RAW && b->encoding != REDIS_ENCODING_RAW){
if (a->encoding == REDIS_ENCODING_INT &&
b->encoding == REDIS_ENCODING_INT){
/* If both strings are integer encoded just check if the stored
* long is the same. */
return a->ptr == b->ptr;
} else {
return compareStringObjects(a,b) == 0;
@@ -424,7 +506,7 @@ int equalStringObjects(robj *a, robj *b) {
size_t stringObjectLen(robj *o) {
redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
if (o->encoding == REDIS_ENCODING_RAW) {
if (sdsEncodedObject(o)) {
return sdslen(o->ptr);
} else {
char buf[32];
@@ -441,7 +523,7 @@ int getDoubleFromObject(robj *o, double *target) {
value = 0;
} else {
redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
if (o->encoding == REDIS_ENCODING_RAW) {
if (sdsEncodedObject(o)) {
errno = 0;
value = strtod(o->ptr, &eptr);
if (isspace(((char*)o->ptr)[0]) ||
@@ -483,7 +565,7 @@ int getLongDoubleFromObject(robj *o, long double *target) {
value = 0;
} else {
redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
if (o->encoding == REDIS_ENCODING_RAW) {
if (sdsEncodedObject(o)) {
errno = 0;
value = strtold(o->ptr, &eptr);
if (isspace(((char*)o->ptr)[0]) || eptr[0] != '\0' ||
@@ -521,7 +603,7 @@ int getLongLongFromObject(robj *o, long long *target) {
value = 0;
} else {
redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
if (o->encoding == REDIS_ENCODING_RAW) {
if (sdsEncodedObject(o)) {
errno = 0;
value = strtoll(o->ptr, &eptr, 10);
if (isspace(((char*)o->ptr)[0]) || eptr[0] != '\0' ||
@@ -576,17 +658,19 @@ char *strEncoding(int encoding) {
case REDIS_ENCODING_ZIPLIST: return "ziplist";
case REDIS_ENCODING_INTSET: return "intset";
case REDIS_ENCODING_SKIPLIST: return "skiplist";
case REDIS_ENCODING_EMBSTR: return "embstr";
default: return "unknown";
}
}
/* Given an object returns the min number of seconds the object was never
/* Given an object returns the min number of milliseconds the object was never
* requested, using an approximated LRU algorithm. */
unsigned long estimateObjectIdleTime(robj *o) {
if (server.lruclock >= o->lru) {
return (server.lruclock - o->lru) * REDIS_LRU_CLOCK_RESOLUTION;
unsigned long long estimateObjectIdleTime(robj *o) {
unsigned long long lruclock = LRU_CLOCK();
if (lruclock >= o->lru) {
return (lruclock - o->lru) * REDIS_LRU_CLOCK_RESOLUTION;
} else {
return ((REDIS_LRU_CLOCK_MAX - o->lru) + server.lruclock) *
return (lruclock + (REDIS_LRU_CLOCK_MAX - o->lru)) *
REDIS_LRU_CLOCK_RESOLUTION;
}
}
@@ -623,7 +707,7 @@ void objectCommand(redisClient *c) {
} else if (!strcasecmp(c->argv[1]->ptr,"idletime") && c->argc == 3) {
if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk))
== NULL) return;
addReplyLongLong(c,estimateObjectIdleTime(o));
addReplyLongLong(c,estimateObjectIdleTime(o)/1000);
} else {
addReplyError(c,"Syntax error. Try OBJECT (refcount|encoding|idletime)");
}
+7 -4
View File
@@ -50,7 +50,7 @@ int listMatchPubsubPattern(void *a, void *b) {
/* Subscribe a client to a channel. Returns 1 if the operation succeeded, or
* 0 if the client was already subscribed to that channel. */
int pubsubSubscribeChannel(redisClient *c, robj *channel) {
struct dictEntry *de;
dictEntry *de;
list *clients = NULL;
int retval = 0;
@@ -80,7 +80,7 @@ int pubsubSubscribeChannel(redisClient *c, robj *channel) {
/* Unsubscribe a client from a channel. Returns 1 if the operation succeeded, or
* 0 if the client was not subscribed to the specified channel. */
int pubsubUnsubscribeChannel(redisClient *c, robj *channel, int notify) {
struct dictEntry *de;
dictEntry *de;
list *clients;
listNode *ln;
int retval = 0;
@@ -218,7 +218,7 @@ int pubsubUnsubscribeAllPatterns(redisClient *c, int notify) {
/* Publish a message */
int pubsubPublishMessage(robj *channel, robj *message) {
int receivers = 0;
struct dictEntry *de;
dictEntry *de;
listNode *ln;
listIter li;
@@ -306,7 +306,10 @@ void punsubscribeCommand(redisClient *c) {
void publishCommand(redisClient *c) {
int receivers = pubsubPublishMessage(c->argv[1],c->argv[2]);
forceCommandPropagation(c,REDIS_PROPAGATE_REPL);
if (server.cluster_enabled)
clusterPropagatePublish(c->argv[1],c->argv[2]);
else
forceCommandPropagation(c,REDIS_PROPAGATE_REPL);
addReplyLongLong(c,receivers);
}
+7 -8
View File
@@ -325,7 +325,7 @@ int rdbSaveStringObject(rio *rdb, robj *obj) {
if (obj->encoding == REDIS_ENCODING_INT) {
return rdbSaveLongLongAsStringObject(rdb,(long)obj->ptr);
} else {
redisAssertWithInfo(NULL,obj,obj->encoding == REDIS_ENCODING_RAW);
redisAssertWithInfo(NULL,obj,sdsEncodedObject(obj));
return rdbSaveRawString(rdb,obj->ptr,sdslen(obj->ptr));
}
}
@@ -796,7 +796,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
/* If we are using a ziplist and the value is too big, convert
* the object to a real list. */
if (o->encoding == REDIS_ENCODING_ZIPLIST &&
ele->encoding == REDIS_ENCODING_RAW &&
sdsEncodedObject(ele) &&
sdslen(ele->ptr) > server.list_max_ziplist_value)
listTypeConvert(o,REDIS_ENCODING_LINKEDLIST);
@@ -842,7 +842,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
}
/* This will also be called when the set was just converted
* to regular hash table encoded set */
* to a regular hash table encoded set */
if (o->encoding == REDIS_ENCODING_HT) {
dictAdd((dict*)o->ptr,ele,NULL);
} else {
@@ -870,9 +870,8 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
if (rdbLoadDoubleValue(rdb,&score) == -1) return NULL;
/* Don't care about integer-encoded strings. */
if (ele->encoding == REDIS_ENCODING_RAW &&
sdslen(ele->ptr) > maxelelen)
maxelelen = sdslen(ele->ptr);
if (sdsEncodedObject(ele) && sdslen(ele->ptr) > maxelelen)
maxelelen = sdslen(ele->ptr);
znode = zslInsert(zs->zsl,score,ele);
dictAdd(zs->dict,ele,&znode->score);
@@ -904,10 +903,10 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
/* Load raw strings */
field = rdbLoadStringObject(rdb);
if (field == NULL) return NULL;
redisAssert(field->encoding == REDIS_ENCODING_RAW);
redisAssert(sdsEncodedObject(field));
value = rdbLoadStringObject(rdb);
if (value == NULL) return NULL;
redisAssert(field->encoding == REDIS_ENCODING_RAW);
redisAssert(sdsEncodedObject(value));
/* Add pair to ziplist */
o->ptr = ziplistPush(o->ptr, field->ptr, sdslen(field->ptr), ZIPLIST_TAIL);
+2 -1
View File
@@ -555,6 +555,7 @@ static int cliReadReply(int output_raw_strings) {
printf("-> Redirected to slot [%d] located at %s:%d\n",
slot, config.hostip, config.hostport);
config.cluster_reissue_command = 1;
cliRefreshPrompt();
}
if (output) {
@@ -1831,7 +1832,7 @@ static void intrinsicLatencyMode(void) {
if (end > test_end) {
printf("\n%lld total runs (avg %lld microseconds per run).\n",
runs, run_time/runs);
printf("Worst run took %.02fx times the average.\n",
printf("Worst run took %.02fx times the avarege.\n",
(double) max_latency / (run_time/runs));
exit(0);
}
+1291
View File
File diff suppressed because it is too large Load Diff
+370 -82
View File
@@ -28,6 +28,7 @@
*/
#include "redis.h"
#include "cluster.h"
#include "slowlog.h"
#include "bio.h"
@@ -112,16 +113,18 @@ struct redisCommand *commandTable;
* server this data. Normally no command is accepted in this condition
* but just a few.
* M: Do not automatically propagate the command on MONITOR.
* k: Perform an implicit ASKING for this command, so the command will be
* accepted in cluster mode if the slot is marked as 'importing'.
*/
struct redisCommand redisCommandTable[] = {
{"get",getCommand,2,"r",0,NULL,1,1,1,0,0},
{"set",setCommand,-3,"wm",0,noPreloadGetKeys,1,1,1,0,0},
{"setnx",setnxCommand,3,"wm",0,noPreloadGetKeys,1,1,1,0,0},
{"setex",setexCommand,4,"wm",0,noPreloadGetKeys,1,1,1,0,0},
{"psetex",psetexCommand,4,"wm",0,noPreloadGetKeys,1,1,1,0,0},
{"set",setCommand,-3,"wm",0,NULL,1,1,1,0,0},
{"setnx",setnxCommand,3,"wm",0,NULL,1,1,1,0,0},
{"setex",setexCommand,4,"wm",0,NULL,1,1,1,0,0},
{"psetex",psetexCommand,4,"wm",0,NULL,1,1,1,0,0},
{"append",appendCommand,3,"wm",0,NULL,1,1,1,0,0},
{"strlen",strlenCommand,2,"r",0,NULL,1,1,1,0,0},
{"del",delCommand,-2,"w",0,noPreloadGetKeys,1,-1,1,0,0},
{"del",delCommand,-2,"w",0,NULL,1,-1,1,0,0},
{"exists",existsCommand,2,"r",0,NULL,1,1,1,0,0},
{"setbit",setbitCommand,4,"wm",0,NULL,1,1,1,0,0},
{"getbit",getbitCommand,3,"r",0,NULL,1,1,1,0,0},
@@ -207,8 +210,8 @@ struct redisCommand redisCommandTable[] = {
{"randomkey",randomkeyCommand,1,"rR",0,NULL,0,0,0,0,0},
{"select",selectCommand,2,"rl",0,NULL,0,0,0,0,0},
{"move",moveCommand,3,"w",0,NULL,1,1,1,0,0},
{"rename",renameCommand,3,"w",0,renameGetKeys,1,2,1,0,0},
{"renamenx",renamenxCommand,3,"w",0,renameGetKeys,1,2,1,0,0},
{"rename",renameCommand,3,"w",0,NULL,1,2,1,0,0},
{"renamenx",renamenxCommand,3,"w",0,NULL,1,2,1,0,0},
{"expire",expireCommand,3,"w",0,NULL,1,1,1,0,0},
{"expireat",expireatCommand,3,"w",0,NULL,1,1,1,0,0},
{"pexpire",pexpireCommand,3,"w",0,NULL,1,1,1,0,0},
@@ -233,7 +236,7 @@ struct redisCommand redisCommandTable[] = {
{"replconf",replconfCommand,-1,"arslt",0,NULL,0,0,0,0,0},
{"flushdb",flushdbCommand,1,"w",0,NULL,0,0,0,0,0},
{"flushall",flushallCommand,1,"w",0,NULL,0,0,0,0,0},
{"sort",sortCommand,-2,"wm",0,NULL,1,1,1,0,0},
{"sort",sortCommand,-2,"wm",0,sortGetKeys,1,1,1,0,0},
{"info",infoCommand,-1,"rlt",0,NULL,0,0,0,0,0},
{"monitor",monitorCommand,1,"ars",0,NULL,0,0,0,0,0},
{"ttl",ttlCommand,2,"r",0,NULL,1,1,1,0,0},
@@ -248,21 +251,27 @@ struct redisCommand redisCommandTable[] = {
{"punsubscribe",punsubscribeCommand,-1,"rpslt",0,NULL,0,0,0,0,0},
{"publish",publishCommand,3,"pltr",0,NULL,0,0,0,0,0},
{"pubsub",pubsubCommand,-2,"pltrR",0,NULL,0,0,0,0,0},
{"watch",watchCommand,-2,"rs",0,noPreloadGetKeys,1,-1,1,0,0},
{"watch",watchCommand,-2,"rs",0,NULL,1,-1,1,0,0},
{"unwatch",unwatchCommand,1,"rs",0,NULL,0,0,0,0,0},
{"restore",restoreCommand,4,"awm",0,NULL,1,1,1,0,0},
{"migrate",migrateCommand,6,"aw",0,NULL,0,0,0,0,0},
{"cluster",clusterCommand,-2,"ar",0,NULL,0,0,0,0,0},
{"restore",restoreCommand,-4,"awm",0,NULL,1,1,1,0,0},
{"restore-asking",restoreCommand,-4,"awmk",0,NULL,1,1,1,0,0},
{"migrate",migrateCommand,-6,"aw",0,NULL,0,0,0,0,0},
{"asking",askingCommand,1,"r",0,NULL,0,0,0,0,0},
{"readonly",readonlyCommand,1,"r",0,NULL,0,0,0,0,0},
{"readwrite",readwriteCommand,1,"r",0,NULL,0,0,0,0,0},
{"dump",dumpCommand,2,"ar",0,NULL,1,1,1,0,0},
{"object",objectCommand,-2,"r",0,NULL,2,2,2,0,0},
{"client",clientCommand,-2,"ar",0,NULL,0,0,0,0,0},
{"eval",evalCommand,-3,"s",0,zunionInterGetKeys,0,0,0,0,0},
{"evalsha",evalShaCommand,-3,"s",0,zunionInterGetKeys,0,0,0,0,0},
{"eval",evalCommand,-3,"s",0,evalGetKeys,0,0,0,0,0},
{"evalsha",evalShaCommand,-3,"s",0,evalGetKeys,0,0,0,0,0},
{"slowlog",slowlogCommand,-2,"r",0,NULL,0,0,0,0,0},
{"script",scriptCommand,-2,"ras",0,NULL,0,0,0,0,0},
{"time",timeCommand,1,"rR",0,NULL,0,0,0,0,0},
{"bitop",bitopCommand,-4,"wm",0,NULL,2,-1,1,0,0},
{"bitcount",bitcountCommand,-2,"r",0,NULL,1,1,1,0,0},
{"bitpos",bitposCommand,-3,"r",0,NULL,1,1,1,0,0},
{"wait",waitCommand,3,"rs",0,NULL,0,0,0,0,0},
{"pfselftest",pfselftestCommand,1,"r",0,NULL,0,0,0,0,0},
{"pfadd",pfaddCommand,-2,"wm",0,NULL,1,1,1,0,0},
{"pfcount",pfcountCommand,-2,"w",0,NULL,1,1,1,0,0},
@@ -270,6 +279,8 @@ struct redisCommand redisCommandTable[] = {
{"pfdebug",pfdebugCommand,-3,"w",0,NULL,0,0,0,0,0}
};
struct evictionPoolEntry *evictionPoolAlloc(void);
/*============================ Utility functions ============================ */
/* Low level logging. To use only for very big messages, otherwise
@@ -293,11 +304,21 @@ void redisLogRaw(int level, const char *msg) {
} else {
int off;
struct timeval tv;
int role_char;
pid_t pid = getpid();
gettimeofday(&tv,NULL);
off = strftime(buf,sizeof(buf),"%d %b %H:%M:%S.",localtime(&tv.tv_sec));
snprintf(buf+off,sizeof(buf)-off,"%03d",(int)tv.tv_usec/1000);
fprintf(fp,"[%d] %s %c %s\n",(int)getpid(),buf,c[level],msg);
if (server.sentinel_mode) {
role_char = 'X'; /* Sentinel. */
} else if (pid != server.pid) {
role_char = 'C'; /* RDB / AOF writing child. */
} else {
role_char = (server.masterhost ? 'S':'M'); /* Slave or Master. */
}
fprintf(fp,"%d:%c %s %c %s\n",
(int)getpid(),role_char, buf,c[level],msg);
}
fflush(fp);
@@ -334,13 +355,12 @@ void redisLogFromHandler(int level, const char *msg) {
if ((level&0xff) < server.verbosity || (log_to_stdout && server.daemonize))
return;
fd = log_to_stdout ? STDOUT_FILENO :
fd = log_to_stdout ? STDOUT_FILENO :
open(server.logfile, O_APPEND|O_CREAT|O_WRONLY, 0644);
if (fd == -1) return;
ll2string(buf,sizeof(buf),getpid());
if (write(fd,"[",1) == -1) goto err;
if (write(fd,buf,strlen(buf)) == -1) goto err;
if (write(fd," | signal handler] (",20) == -1) goto err;
if (write(fd,":signal-handler (",17) == -1) goto err;
ll2string(buf,sizeof(buf),time(NULL));
if (write(fd,buf,strlen(buf)) == -1) goto err;
if (write(fd,") ",2) == -1) goto err;
@@ -474,7 +494,7 @@ int dictEncObjKeyCompare(void *privdata, const void *key1,
unsigned int dictEncObjHash(const void *key) {
robj *o = (robj*) key;
if (o->encoding == REDIS_ENCODING_RAW) {
if (sdsEncodedObject(o)) {
return dictGenHashFunction(o->ptr, sdslen((sds)o->ptr));
} else {
if (o->encoding == REDIS_ENCODING_INT) {
@@ -576,6 +596,39 @@ dictType keylistDictType = {
dictListDestructor /* val destructor */
};
/* Cluster nodes hash table, mapping nodes addresses 1.2.3.4:6379 to
* clusterNode structures. */
dictType clusterNodesDictType = {
dictSdsHash, /* hash function */
NULL, /* key dup */
NULL, /* val dup */
dictSdsKeyCompare, /* key compare */
dictSdsDestructor, /* key destructor */
NULL /* val destructor */
};
/* Cluster re-addition blacklist. This maps node IDs to the time
* we can re-add this node. The goal is to avoid readding a removed
* node for some time. */
dictType clusterNodesBlackListDictType = {
dictSdsCaseHash, /* hash function */
NULL, /* key dup */
NULL, /* val dup */
dictSdsKeyCaseCompare, /* key compare */
dictSdsDestructor, /* key destructor */
NULL /* val destructor */
};
/* Migrate cache dict type. */
dictType migrateCacheDictType = {
dictSdsHash, /* hash function */
NULL, /* key dup */
NULL, /* val dup */
dictSdsKeyCompare, /* key compare */
dictSdsDestructor, /* key destructor */
NULL /* val destructor */
};
/* Replication cached script dict (server.repl_scriptcache_dict).
* Keys are sds SHA1 strings, while values are not used at all in the current
* implementation. */
@@ -653,7 +706,7 @@ void updateDictResizePolicy(void) {
*
* The parameter 'now' is the current time in milliseconds as is passed
* to the function to avoid too many gettimeofday() syscalls. */
int activeExpireCycleTryExpire(redisDb *db, struct dictEntry *de, long long now) {
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long t = dictGetSignedIntegerVal(de);
if (now > t) {
sds key = dictGetKey(de);
@@ -810,12 +863,10 @@ void activeExpireCycle(int type) {
}
}
void updateLRUClock(void) {
server.lruclock = (server.unixtime/REDIS_LRU_CLOCK_RESOLUTION) &
REDIS_LRU_CLOCK_MAX;
unsigned int getLRUClock(void) {
return (mstime()/REDIS_LRU_CLOCK_RESOLUTION) & REDIS_LRU_CLOCK_MAX;
}
/* Add a sample to the operations per second array of samples. */
void trackOperationsPerSecond(void) {
long long t = mstime() - server.ops_sec_last_sample_time;
@@ -856,9 +907,14 @@ int clientsCronHandleTimeout(redisClient *c) {
freeClient(c);
return 1;
} else if (c->flags & REDIS_BLOCKED) {
if (c->bpop.timeout != 0 && c->bpop.timeout < now) {
addReply(c,shared.nullmultibulk);
unblockClientWaitingData(c);
/* Blocked OPS timeout is handled with milliseconds resolution.
* However note that the actual resolution is limited by
* server.hz. */
mstime_t now_ms = mstime();
if (c->bpop.timeout != 0 && c->bpop.timeout < now_ms) {
replyToBlockedClientTimedOut(c);
unblockClient(c);
}
}
return 0;
@@ -1007,19 +1063,18 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
run_with_period(100) trackOperationsPerSecond();
/* We have just 22 bits per object for LRU information.
* So we use an (eventually wrapping) LRU clock with 10 seconds resolution.
* 2^22 bits with 10 seconds resolution is more or less 1.5 years.
/* We have just REDIS_LRU_BITS bits per object for LRU information.
* So we use an (eventually wrapping) LRU clock.
*
* Note that even if this will wrap after 1.5 years it's not a problem,
* everything will still work but just some object will appear younger
* to Redis. But for this to happen a given object should never be touched
* for 1.5 years.
* Note that even if the counter wraps it's not a big problem,
* everything will still work but some object will appear younger
* to Redis. However for this to happen a given object should never be
* touched for all the time needed to the counter to wrap, which is
* not likely.
*
* Note that you can change the resolution altering the
* REDIS_LRU_CLOCK_RESOLUTION define.
*/
updateLRUClock();
* REDIS_LRU_CLOCK_RESOLUTION define. */
server.lruclock = getLRUClock();
/* Record the max memory used since the server was started. */
if (zmalloc_used_memory() > server.stat_peak_memory)
@@ -1154,15 +1209,28 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
/* Close clients that need to be closed asynchronous */
freeClientsInAsyncFreeQueue();
/* Clear the paused clients flag if needed. */
clientsArePaused(); /* Don't check return value, just use the side effect. */
/* Replication cron function -- used to reconnect to master and
* to detect transfer failures. */
run_with_period(1000) replicationCron();
/* Run the sentinel timer if we are in sentinel mode. */
/* Run the Redis Cluster cron. */
run_with_period(100) {
if (server.cluster_enabled) clusterCron();
}
/* Run the Sentinel timer if we are in sentinel mode. */
run_with_period(100) {
if (server.sentinel_mode) sentinelTimer();
}
/* Cleanup expired MIGRATE cached sockets. */
run_with_period(1000) {
migrateCloseTimedoutSockets();
}
server.cronloops++;
return 1000/server.hz;
}
@@ -1172,32 +1240,41 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
* for ready file descriptors. */
void beforeSleep(struct aeEventLoop *eventLoop) {
REDIS_NOTUSED(eventLoop);
listNode *ln;
redisClient *c;
/* Run a fast expire cycle (the called function will return
* ASAP if a fast cycle is not needed). */
if (server.active_expire_enabled && server.masterhost == NULL)
activeExpireCycle(ACTIVE_EXPIRE_CYCLE_FAST);
/* Try to process pending commands for clients that were just unblocked. */
while (listLength(server.unblocked_clients)) {
ln = listFirst(server.unblocked_clients);
redisAssert(ln != NULL);
c = ln->value;
listDelNode(server.unblocked_clients,ln);
c->flags &= ~REDIS_UNBLOCKED;
/* Send all the slaves an ACK request if at least one client blocked
* during the previous event loop iteration. */
if (server.get_ack_from_slaves) {
robj *argv[3];
/* Process remaining data in the input buffer. */
if (c->querybuf && sdslen(c->querybuf) > 0) {
server.current_client = c;
processInputBuffer(c);
server.current_client = NULL;
}
argv[0] = createStringObject("REPLCONF",8);
argv[1] = createStringObject("GETACK",6);
argv[2] = createStringObject("*",1); /* Not used argument. */
replicationFeedSlaves(server.slaves, server.slaveseldb, argv, 3);
decrRefCount(argv[0]);
decrRefCount(argv[1]);
decrRefCount(argv[2]);
server.get_ack_from_slaves = 0;
}
/* Unblock all the clients blocked for synchronous replication
* in WAIT. */
if (listLength(server.clients_waiting_acks))
processClientsWaitingReplicas();
/* Try to process pending commands for clients that were just unblocked. */
if (listLength(server.unblocked_clients))
processUnblockedClients();
/* Write the AOF buffer on disk */
flushAppendOnlyFile(0);
/* Call the Redis Cluster before sleep function. */
if (server.cluster_enabled) clusterBeforeSleep();
}
/* =========================== Server initialization ======================== */
@@ -1248,6 +1325,8 @@ void createSharedObjects(void) {
"-EXECABORT Transaction discarded because of previous errors.\r\n"));
shared.noreplicaserr = createObject(REDIS_STRING,sdsnew(
"-NOREPLICAS Not enough good slaves to write.\r\n"));
shared.busykeyerr = createObject(REDIS_STRING,sdsnew(
"-BUSYKEY Target key name already exists.\r\n"));
shared.space = createObject(REDIS_STRING,sdsnew(" "));
shared.colon = createObject(REDIS_STRING,sdsnew(":"));
shared.plus = createObject(REDIS_STRING,sdsnew("+"));
@@ -1361,13 +1440,19 @@ void initServerConfig() {
server.repl_timeout = REDIS_REPL_TIMEOUT;
server.repl_min_slaves_to_write = REDIS_DEFAULT_MIN_SLAVES_TO_WRITE;
server.repl_min_slaves_max_lag = REDIS_DEFAULT_MIN_SLAVES_MAX_LAG;
server.cluster_enabled = 0;
server.cluster_node_timeout = REDIS_CLUSTER_DEFAULT_NODE_TIMEOUT;
server.cluster_migration_barrier = REDIS_CLUSTER_DEFAULT_MIGRATION_BARRIER;
server.cluster_slave_validity_factor = REDIS_CLUSTER_DEFAULT_SLAVE_VALIDITY;
server.cluster_configfile = zstrdup(REDIS_DEFAULT_CLUSTER_CONFIG_FILE);
server.lua_caller = NULL;
server.lua_time_limit = REDIS_LUA_TIME_LIMIT;
server.lua_client = NULL;
server.lua_timedout = 0;
server.migrate_cached_sockets = dictCreate(&migrateCacheDictType,NULL);
server.loading_process_events_interval_bytes = (1024*1024*2);
updateLRUClock();
server.lruclock = getLRUClock();
resetServerSaveParams();
appendServerSaveParams(60*60,1); /* save after 1 hour and 1 change */
@@ -1569,7 +1654,7 @@ int listenToPort(int port, int *fds, int *count) {
redisLog(REDIS_WARNING,
"Creating Server TCP listening socket %s:%d: %s",
server.bindaddr[j] ? server.bindaddr[j] : "*",
server.port, server.neterr);
port, server.neterr);
return REDIS_ERR;
}
anetNonBlock(NULL,fds[*count]);
@@ -1611,6 +1696,7 @@ void initServer() {
server.syslog_facility);
}
server.pid = getpid();
server.current_client = NULL;
server.clients = listCreate();
server.clients_to_close = listCreate();
@@ -1619,6 +1705,9 @@ void initServer() {
server.slaveseldb = -1; /* Force to emit the first SELECT command. */
server.unblocked_clients = listCreate();
server.ready_keys = listCreate();
server.clients_waiting_acks = listCreate();
server.get_ack_from_slaves = 0;
server.clients_paused = 0;
createSharedObjects();
adjustOpenFilesLimit();
@@ -1655,6 +1744,7 @@ void initServer() {
server.db[j].blocking_keys = dictCreate(&keylistDictType,NULL);
server.db[j].ready_keys = dictCreate(&setDictType,NULL);
server.db[j].watched_keys = dictCreate(&keylistDictType,NULL);
server.db[j].eviction_pool = evictionPoolAlloc();
server.db[j].id = j;
server.db[j].avg_ttl = 0;
}
@@ -1724,6 +1814,7 @@ void initServer() {
server.maxmemory_policy = REDIS_MAXMEMORY_NO_EVICTION;
}
if (server.cluster_enabled) clusterInit();
replicationScriptCacheInit();
scriptingInit();
slowlogInit();
@@ -1754,6 +1845,7 @@ void populateCommandTable(void) {
case 'l': c->flags |= REDIS_CMD_LOADING; break;
case 't': c->flags |= REDIS_CMD_STALE; break;
case 'M': c->flags |= REDIS_CMD_SKIP_MONITOR; break;
case 'k': c->flags |= REDIS_CMD_ASKING; break;
default: redisPanic("Unsupported command flag"); break;
}
f++;
@@ -2000,6 +2092,47 @@ int processCommand(redisClient *c) {
return REDIS_OK;
}
/* If cluster is enabled perform the cluster redirection here.
* However we don't perform the redirection if:
* 1) The sender of this command is our master.
* 2) The command has no key arguments. */
if (server.cluster_enabled &&
!(c->flags & REDIS_MASTER) &&
!(c->cmd->getkeys_proc == NULL && c->cmd->firstkey == 0))
{
int hashslot;
if (server.cluster->state != REDIS_CLUSTER_OK) {
flagTransaction(c);
addReplySds(c,sdsnew("-CLUSTERDOWN The cluster is down. Use CLUSTER INFO for more information\r\n"));
return REDIS_OK;
} else {
int error_code;
clusterNode *n = getNodeByQuery(c,c->cmd,c->argv,c->argc,&hashslot,&error_code);
if (n == NULL) {
flagTransaction(c);
if (error_code == REDIS_CLUSTER_REDIR_CROSS_SLOT) {
addReplySds(c,sdsnew("-CROSSSLOT Keys in request don't hash to the same slot\r\n"));
} else if (error_code == REDIS_CLUSTER_REDIR_UNSTABLE) {
/* The request spawns mutliple keys in the same slot,
* but the slot is not "stable" currently as there is
* a migration or import in progress. */
addReplySds(c,sdsnew("-TRYAGAIN Multiple keys request during rehashing of slot\r\n"));
} else {
redisPanic("getNodeByQuery() unknown error.");
}
return REDIS_OK;
} else if (n != server.cluster->myself) {
flagTransaction(c);
addReplySds(c,sdscatprintf(sdsempty(),
"-%s %d %s:%d\r\n",
(error_code == REDIS_CLUSTER_REDIR_ASK) ? "ASK" : "MOVED",
hashslot,n->ip,n->port));
return REDIS_OK;
}
}
}
/* Handle the maxmemory directive.
*
* First we try to free some memory if possible (if there are volatile
@@ -2037,8 +2170,7 @@ int processCommand(redisClient *c) {
/* Don't accept write commands if there are not enough good slaves and
* user configured the min-slaves-to-write option. */
if (server.masterhost == NULL &&
server.repl_min_slaves_to_write &&
if (server.repl_min_slaves_to_write &&
server.repl_min_slaves_max_lag &&
c->cmd->flags & REDIS_CMD_WRITE &&
server.repl_good_slaves_count < server.repl_min_slaves_to_write)
@@ -2112,6 +2244,7 @@ int processCommand(redisClient *c) {
addReply(c,shared.queued);
} else {
call(c,REDIS_CALL_FULL);
c->woff = server.master_repl_offset;
if (listLength(server.ready_keys))
handleClientsBlockedOnLists();
}
@@ -2127,6 +2260,8 @@ void closeListeningSockets(int unlink_unix_socket) {
for (j = 0; j < server.ipfd_count; j++) close(server.ipfd[j]);
if (server.sofd != -1) close(server.sofd);
if (server.cluster_enabled)
for (j = 0; j < server.cfd_count; j++) close(server.cfd[j]);
if (unlink_unix_socket && server.unixsocket) {
redisLog(REDIS_NOTICE,"Removing the unix socket file.");
unlink(server.unixsocket); /* don't care if this fails */
@@ -2305,7 +2440,8 @@ sds genRedisInfoString(char *section) {
static struct utsname name;
char *mode;
if (server.sentinel_mode) mode = "sentinel";
if (server.cluster_enabled) mode = "cluster";
else if (server.sentinel_mode) mode = "sentinel";
else mode = "standalone";
if (sections++) info = sdscat(info,"\r\n");
@@ -2513,7 +2649,8 @@ sds genRedisInfoString(char *section) {
"keyspace_misses:%lld\r\n"
"pubsub_channels:%ld\r\n"
"pubsub_patterns:%lu\r\n"
"latest_fork_usec:%lld\r\n",
"latest_fork_usec:%lld\r\n"
"migrate_cached_sockets:%ld\r\n",
server.stat_numconnections,
server.stat_numcommands,
getOperationsPerSecond(),
@@ -2527,7 +2664,8 @@ sds genRedisInfoString(char *section) {
server.stat_keyspace_misses,
dictSize(server.pubsub_channels),
listLength(server.pubsub_patterns),
server.stat_fork_time);
server.stat_fork_time,
dictSize(server.migrate_cached_sockets));
}
/* Replication */
@@ -2679,6 +2817,15 @@ sds genRedisInfoString(char *section) {
}
}
/* Cluster */
if (allsections || defsections || !strcasecmp(section,"cluster")) {
if (sections++) info = sdscat(info,"\r\n");
info = sdscatprintf(info,
"# Cluster\r\n"
"cluster_enabled:%d\r\n",
server.cluster_enabled);
}
/* Key space */
if (allsections || defsections || !strcasecmp(section,"keyspace")) {
if (sections++) info = sdscat(info,"\r\n");
@@ -2723,8 +2870,9 @@ void monitorCommand(redisClient *c) {
/* ============================ Maxmemory directive ======================== */
/* This function gets called when 'maxmemory' is set on the config file to limit
* the max memory used by the server, before processing a command.
/* freeMemoryIfNeeded() gets called when 'maxmemory' is set on the config
* file to limit the max memory used by the server, before processing a
* command.
*
* The goal of the function is to free enough memory to keep Redis under the
* configured memory limit.
@@ -2737,7 +2885,123 @@ void monitorCommand(redisClient *c) {
* function returns REDIS_OK, otherwise REDIS_ERR is returned, and the caller
* should block the execution of commands that will result in more memory
* used by the server.
*/
*
* ------------------------------------------------------------------------
*
* LRU approximation algorithm
*
* Redis uses an approximation of the LRU algorithm that runs in constant
* memory. Every time there is a key to expire, we sample N keys (with
* N very small, usually in around 5) to populate a pool of best keys to
* evict of M keys (the pool size is defined by REDIS_EVICTION_POOL_SIZE).
*
* The N keys sampled are added in the pool of good keys to expire (the one
* with an old access time) if they are better than one of the current keys
* in the pool.
*
* After the pool is populated, the best key we have in the pool is expired.
* However note that we don't remove keys from the pool when they are deleted
* so the pool may contain keys that no longer exist.
*
* When we try to evict a key, and all the entries in the pool don't exist
* we populate it again. This time we'll be sure that the pool has at least
* one key that can be evicted, if there is at least one key that can be
* evicted in the whole database. */
/* Create a new eviction pool. */
struct evictionPoolEntry *evictionPoolAlloc(void) {
struct evictionPoolEntry *ep;
int j;
ep = zmalloc(sizeof(*ep)*REDIS_EVICTION_POOL_SIZE);
for (j = 0; j < REDIS_EVICTION_POOL_SIZE; j++) {
ep[j].idle = 0;
ep[j].key = NULL;
}
return ep;
}
/* This is an helper function for freeMemoryIfNeeded(), it is used in order
* to populate the evictionPool with a few entries every time we want to
* expire a key. Keys with idle time smaller than one of the current
* keys are added. Keys are always added if there are free entries.
*
* We insert keys on place in ascending order, so keys with the smaller
* idle time are on the left, and keys with the higher idle time on the
* right. */
#define EVICTION_SAMPLES_ARRAY_SIZE 16
void evictionPoolPopulate(dict *sampledict, dict *keydict, struct evictionPoolEntry *pool) {
int j, k, count;
dictEntry *_samples[EVICTION_SAMPLES_ARRAY_SIZE];
dictEntry **samples;
/* Try to use a static buffer: this function is a big hit...
* Note: it was actually measured that this helps. */
if (server.maxmemory_samples <= EVICTION_SAMPLES_ARRAY_SIZE) {
samples = _samples;
} else {
samples = zmalloc(sizeof(samples[0])*server.maxmemory_samples);
}
#if 1 /* Use bulk get by default. */
count = dictGetRandomKeys(sampledict,samples,server.maxmemory_samples);
#else
count = server.maxmemory_samples;
for (j = 0; j < count; j++) samples[j] = dictGetRandomKey(sampledict);
#endif
for (j = 0; j < count; j++) {
unsigned long long idle;
sds key;
robj *o;
dictEntry *de;
de = samples[j];
key = dictGetKey(de);
/* If the dictionary we are sampling from is not the main
* dictionary (but the expires one) we need to lookup the key
* again in the key dictionary to obtain the value object. */
if (sampledict != keydict) de = dictFind(keydict, key);
o = dictGetVal(de);
idle = estimateObjectIdleTime(o);
/* Insert the element inside the pool.
* First, find the first empty bucket or the first populated
* bucket that has an idle time smaller than our idle time. */
k = 0;
while (k < REDIS_EVICTION_POOL_SIZE &&
pool[k].key &&
pool[k].idle < idle) k++;
if (k == 0 && pool[REDIS_EVICTION_POOL_SIZE-1].key != NULL) {
/* Can't insert if the element is < the worst element we have
* and there are no empty buckets. */
continue;
} else if (k < REDIS_EVICTION_POOL_SIZE && pool[k].key == NULL) {
/* Inserting into empty position. No setup needed before insert. */
} else {
/* Inserting in the middle. Now k points to the first element
* greater than the element to insert. */
if (pool[REDIS_EVICTION_POOL_SIZE-1].key == NULL) {
/* Free space on the right? Insert at k shifting
* all the elements from k to end to the right. */
memmove(pool+k+1,pool+k,
sizeof(pool[0])*(REDIS_EVICTION_POOL_SIZE-k-1));
} else {
/* No free space on right? Insert at k-1 */
k--;
/* Shift all elements on the left of k (included) to the
* left, so we discard the element with smaller idle time. */
sdsfree(pool[0].key);
memmove(pool,pool+1,sizeof(pool[0])*k);
}
}
pool[k].key = sdsdup(key);
pool[k].idle = idle;
}
if (samples != _samples) zfree(samples);
}
int freeMemoryIfNeeded(void) {
size_t mem_used, mem_tofree, mem_freed;
int slaves = listLength(server.slaves);
@@ -2779,7 +3043,7 @@ int freeMemoryIfNeeded(void) {
for (j = 0; j < server.dbnum; j++) {
long bestval = 0; /* just to prevent warning */
sds bestkey = NULL;
struct dictEntry *de;
dictEntry *de;
redisDb *db = server.db+j;
dict *dict;
@@ -2804,24 +3068,34 @@ int freeMemoryIfNeeded(void) {
else if (server.maxmemory_policy == REDIS_MAXMEMORY_ALLKEYS_LRU ||
server.maxmemory_policy == REDIS_MAXMEMORY_VOLATILE_LRU)
{
for (k = 0; k < server.maxmemory_samples; k++) {
sds thiskey;
long thisval;
robj *o;
struct evictionPoolEntry *pool = db->eviction_pool;
de = dictGetRandomKey(dict);
thiskey = dictGetKey(de);
/* When policy is volatile-lru we need an additional lookup
* to locate the real key, as dict is set to db->expires. */
if (server.maxmemory_policy == REDIS_MAXMEMORY_VOLATILE_LRU)
de = dictFind(db->dict, thiskey);
o = dictGetVal(de);
thisval = estimateObjectIdleTime(o);
while(bestkey == NULL) {
evictionPoolPopulate(dict, db->dict, db->eviction_pool);
/* Go backward from best to worst element to evict. */
for (k = REDIS_EVICTION_POOL_SIZE-1; k >= 0; k--) {
if (pool[k].key == NULL) continue;
de = dictFind(dict,pool[k].key);
/* Higher idle time is better candidate for deletion */
if (bestkey == NULL || thisval > bestval) {
bestkey = thiskey;
bestval = thisval;
/* Remove the entry from the pool. */
sdsfree(pool[k].key);
/* Shift all elements on its right to left. */
memmove(pool+k,pool+k+1,
sizeof(pool[0])*(REDIS_EVICTION_POOL_SIZE-k-1));
/* Clear the element on the right which is empty
* since we shifted one position to the left. */
pool[REDIS_EVICTION_POOL_SIZE-1].key = NULL;
pool[REDIS_EVICTION_POOL_SIZE-1].idle = 0;
/* If the key exists, is our pick. Otherwise it is
* a ghost and we need to try the next element. */
if (de) {
bestkey = dictGetKey(de);
break;
} else {
/* Ghost... */
continue;
}
}
}
}
@@ -2964,7 +3238,8 @@ void redisAsciiArt(void) {
char *buf = zmalloc(1024*16);
char *mode = "stand alone";
if (server.sentinel_mode) mode = "sentinel";
if (server.cluster_enabled) mode = "cluster";
else if (server.sentinel_mode) mode = "sentinel";
snprintf(buf,1024*16,ascii_logo,
REDIS_VERSION,
@@ -3045,10 +3320,15 @@ void redisOutOfMemoryHandler(size_t allocation_size) {
void redisSetProcTitle(char *title) {
#ifdef USE_SETPROCTITLE
setproctitle("%s %s:%d",
char *server_mode = "";
if (server.cluster_enabled) server_mode = " [cluster]";
else if (server.sentinel_mode) server_mode = " [sentinel]";
setproctitle("%s %s:%d%s",
title,
server.bindaddr_count ? server.bindaddr[0] : "*",
server.port);
server.port,
server_mode);
#else
REDIS_NOTUSED(title);
#endif
@@ -3139,6 +3419,14 @@ int main(int argc, char **argv) {
linuxOvercommitMemoryWarning();
#endif
loadDataFromDisk();
if (server.cluster_enabled) {
if (verifyClusterConfigWithData() == REDIS_ERR) {
redisLog(REDIS_WARNING,
"You can't have keys in a DB different than DB 0 when in "
"Cluster mode. Exiting.");
exit(1);
}
}
if (server.ipfd_count > 0)
redisLog(REDIS_NOTICE,"The server is now ready to accept connections on port %d", server.port);
if (server.sofd > 0)
+124 -24
View File
@@ -113,7 +113,7 @@
#define REDIS_DEFAULT_SLAVE_READ_ONLY 1
#define REDIS_DEFAULT_REPL_DISABLE_TCP_NODELAY 0
#define REDIS_DEFAULT_MAXMEMORY 0
#define REDIS_DEFAULT_MAXMEMORY_SAMPLES 3
#define REDIS_DEFAULT_MAXMEMORY_SAMPLES 5
#define REDIS_DEFAULT_AOF_FILENAME "appendonly.aof"
#define REDIS_DEFAULT_AOF_NO_FSYNC_ON_REWRITE 0
#define REDIS_DEFAULT_ACTIVE_REHASHING 1
@@ -161,6 +161,7 @@
#define REDIS_CMD_LOADING 512 /* "l" flag */
#define REDIS_CMD_STALE 1024 /* "t" flag */
#define REDIS_CMD_SKIP_MONITOR 2048 /* "M" flag */
#define REDIS_CMD_ASKING 4096 /* "k" flag */
/* Object types */
#define REDIS_STRING 0
@@ -180,6 +181,7 @@
#define REDIS_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
#define REDIS_ENCODING_INTSET 6 /* Encoded as intset */
#define REDIS_ENCODING_SKIPLIST 7 /* Encoded as skiplist */
#define REDIS_ENCODING_EMBSTR 8 /* Embedded sds string encoding */
/* Defines related to the dump file format. To store 32 bits lengths for short
* keys requires a lot of space, so we check the most significant 2 bits of
@@ -232,6 +234,13 @@
#define REDIS_FORCE_AOF (1<<14) /* Force AOF propagation of current cmd. */
#define REDIS_FORCE_REPL (1<<15) /* Force replication of current cmd. */
#define REDIS_PRE_PSYNC (1<<16) /* Instance don't understand PSYNC. */
#define REDIS_READONLY (1<<17) /* Cluster client is in read-only state. */
/* Client block type (btype field in client structure)
* if REDIS_BLOCKED flag is set. */
#define REDIS_BLOCKED_NONE 0 /* Not blocked, no REDIS_BLOCKED flag set. */
#define REDIS_BLOCKED_LIST 1 /* BLPOP & co. */
#define REDIS_BLOCKED_WAIT 2 /* WAIT for synchronous replication. */
/* Client request types */
#define REDIS_REQ_INLINE 1
@@ -318,7 +327,7 @@
#define REDIS_MAXMEMORY_ALLKEYS_LRU 3
#define REDIS_MAXMEMORY_ALLKEYS_RANDOM 4
#define REDIS_MAXMEMORY_NO_EVICTION 5
#define REDIS_DEFAULT_MAXMEMORY_POLICY REDIS_MAXMEMORY_VOLATILE_LRU
#define REDIS_DEFAULT_MAXMEMORY_POLICY REDIS_MAXMEMORY_NO_EVICTION
/* Scripting */
#define REDIS_LUA_TIME_LIMIT 5000 /* milliseconds */
@@ -379,7 +388,7 @@ typedef long long mstime_t; /* millisecond time type. */
/* The actual Redis Object */
#define REDIS_LRU_BITS 24
#define REDIS_LRU_CLOCK_MAX ((1<<REDIS_LRU_BITS)-1) /* Max value of obj->lru */
#define REDIS_LRU_CLOCK_RESOLUTION 1 /* LRU clock resolution in seconds */
#define REDIS_LRU_CLOCK_RESOLUTION 1000 /* LRU clock resolution in ms */
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
@@ -388,6 +397,12 @@ typedef struct redisObject {
void *ptr;
} robj;
/* Macro used to obtain the current LRU clock.
* If the current resolution is lower than the frequency we refresh the
* LRU clock (as it should be in production servers) we return the
* precomputed value, otherwise we need to resort to a function call. */
#define LRU_CLOCK() ((1000/server.hz <= REDIS_LRU_CLOCK_RESOLUTION) ? server.lruclock : getLRUClock())
/* Macro used to initialize a Redis object allocated on the stack.
* Note that this macro is taken near the structure definition to make sure
* we'll update it when the structure is changed, to avoid bugs like
@@ -399,13 +414,30 @@ typedef struct redisObject {
_var.ptr = _ptr; \
} while(0);
/* To improve the quality of the LRU approximation we take a set of keys
* that are good candidate for eviction across freeMemoryIfNeeded() calls.
*
* Entries inside the eviciton pool are taken ordered by idle time, putting
* greater idle times to the right (ascending order).
*
* Empty entries have the key pointer set to NULL. */
#define REDIS_EVICTION_POOL_SIZE 16
struct evictionPoolEntry {
unsigned long long idle; /* Object idle time. */
sds key; /* Key name. */
};
/* Redis database representation. There are multiple databases identified
* by integers from 0 (the default database) up to the max configured
* database. The database number is the 'id' field in the structure. */
typedef struct redisDb {
dict *dict; /* The keyspace for this DB */
dict *expires; /* Timeout of keys with a timeout set */
dict *blocking_keys; /* Keys with clients waiting for data (BLPOP) */
dict *ready_keys; /* Blocked keys that received a PUSH */
dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS */
int id;
struct evictionPoolEntry *eviction_pool; /* Eviction pool of keys */
int id; /* Database ID */
long long avg_ttl; /* Average TTL, just for stats */
} redisDb;
@@ -423,13 +455,22 @@ typedef struct multiState {
time_t minreplicas_timeout; /* MINREPLICAS timeout as unixtime. */
} multiState;
/* This structure holds the blocking operation state for a client.
* The fields used depend on client->btype. */
typedef struct blockingState {
/* Generic fields. */
mstime_t timeout; /* Blocking operation timeout. If UNIX current time
* is > timeout then the operation timed out. */
/* REDIS_BLOCK_LIST */
dict *keys; /* The keys we are waiting to terminate a blocking
* operation such as BLPOP. Otherwise NULL. */
time_t timeout; /* Blocking operation timeout. If UNIX current time
* is > timeout then the operation timed out. */
robj *target; /* The key that should receive the element,
* for BRPOPLPUSH. */
/* REDIS_BLOCK_WAIT */
int numreplicas; /* Number of replicas we are waiting for ACK. */
long long reploffset; /* Replication offset to reach. */
} blockingState;
/* The following structure represents a node in the server.ready_keys list,
@@ -476,16 +517,20 @@ typedef struct redisClient {
int repldbfd; /* replication DB file descriptor */
off_t repldboff; /* replication DB file offset */
off_t repldbsize; /* replication DB file size */
sds replpreamble; /* replication DB preamble. */
long long reploff; /* replication offset if this is our master */
long long repl_ack_off; /* replication ack offset, if this is a slave */
long long repl_ack_time;/* replication ack time, if this is a slave */
char replrunid[REDIS_RUN_ID_SIZE+1]; /* master run id if this is a master */
int slave_listening_port; /* As configured with: SLAVECONF listening-port */
multiState mstate; /* MULTI/EXEC state */
blockingState bpop; /* blocking state */
int btype; /* Type of blocking op if REDIS_BLOCKED. */
blockingState bpop; /* blocking state */
long long woff; /* Last write global replication offset. */
list *watched_keys; /* Keys WATCHED for MULTI/EXEC CAS */
dict *pubsub_channels; /* channels a client is interested in (SUBSCRIBE) */
list *pubsub_patterns; /* patterns a client is interested in (SUBSCRIBE) */
sds peerid; /* Cached peer ID. */
/* Response buffer */
int bufpos;
@@ -503,7 +548,7 @@ struct sharedObjectsStruct {
*emptymultibulk, *wrongtypeerr, *nokeyerr, *syntaxerr, *sameobjecterr,
*outofrangeerr, *noscripterr, *loadingerr, *slowscripterr, *bgsaveerr,
*masterdownerr, *roslaveerr, *execaborterr, *noautherr, *noreplicaserr,
*oomerr, *plus, *messagebulk, *pmessagebulk, *subscribebulk,
*busykeyerr, *oomerr, *plus, *messagebulk, *pmessagebulk, *subscribebulk,
*unsubscribebulk, *psubscribebulk, *punsubscribebulk, *del, *rpop, *lpop,
*lpush, *emptyscan, *minstring, *maxstring,
*select[REDIS_SHARED_SELECT_CMDS],
@@ -570,8 +615,11 @@ typedef struct redisOpArray {
* Global server state
*----------------------------------------------------------------------------*/
struct clusterState;
struct redisServer {
/* General */
pid_t pid; /* Main process pid. */
char *configfile; /* Absolute config file path, or NULL */
int hz; /* serverCron() calls frequency in hertz */
redisDb *db;
@@ -597,11 +645,16 @@ struct redisServer {
int ipfd[REDIS_BINDADDR_MAX]; /* TCP socket file descriptors */
int ipfd_count; /* Used slots in ipfd[] */
int sofd; /* Unix socket file descriptor */
int cfd[REDIS_BINDADDR_MAX];/* Cluster bus listening socket */
int cfd_count; /* Used slots in cfd[] */
list *clients; /* List of active clients */
list *clients_to_close; /* Clients to close asynchronously */
list *slaves, *monitors; /* List of slaves and MONITORs */
redisClient *current_client; /* Current client, only used on crash report */
char neterr[ANET_ERR_LEN]; /* Error buffer for anet.c */
int clients_paused; /* True if clients are currently paused */
mstime_t clients_pause_end_time; /* Time when we undo clients_paused */
char neterr[ANET_ERR_LEN]; /* Error buffer for anet.c */
dict *migrate_cached_sockets;/* MIGRATE cached sockets */
/* RDB / AOF loading information */
int loading; /* We are loading data from disk if true */
off_t loading_total_bytes;
@@ -735,6 +788,9 @@ struct redisServer {
dict *repl_scriptcache_dict; /* SHA1 all slaves are aware of. */
list *repl_scriptcache_fifo; /* First in, first out LRU eviction. */
int repl_scriptcache_size; /* Max number of elements. */
/* Synchronous replication. */
list *clients_waiting_acks; /* Clients waiting in WAIT command. */
int get_ack_from_slaves; /* If true we send REPLCONF GETACK. */
/* Limits */
int maxclients; /* Max number of simultaneous clients */
unsigned long long maxmemory; /* Max number of memory bytes to use */
@@ -766,6 +822,13 @@ struct redisServer {
list *pubsub_patterns; /* A list of pubsub_patterns */
int notify_keyspace_events; /* Events to propagate via Pub/Sub. This is an
xor of REDIS_NOTIFY... flags. */
/* Cluster */
int cluster_enabled; /* Is cluster enabled? */
mstime_t cluster_node_timeout; /* Cluster node timeout. */
char *cluster_configfile; /* Cluster auto-generated config file name. */
struct clusterState *cluster; /* State of the cluster */
int cluster_migration_barrier; /* Cluster replicas migration barrier. */
int cluster_slave_validity_factor; /* Slave max data age for failover. */
/* Scripting */
lua_State *lua; /* The Lua interpreter. We use just one for all clients */
redisClient *lua_client; /* The "fake client" to query Redis from Lua */
@@ -794,14 +857,15 @@ typedef struct pubsubPattern {
} pubsubPattern;
typedef void redisCommandProc(redisClient *c);
typedef int *redisGetKeysProc(struct redisCommand *cmd, robj **argv, int argc, int *numkeys, int flags);
typedef int *redisGetKeysProc(struct redisCommand *cmd, robj **argv, int argc, int *numkeys);
struct redisCommand {
char *name;
redisCommandProc *proc;
int arity;
char *sflags; /* Flags as string representation, one char per flag. */
int flags; /* The actual flags, obtained from the 'sflags' field. */
/* Use a function to determine keys arguments in a command line. */
/* Use a function to determine keys arguments in a command line.
* Used for Redis Cluster redirect. */
redisGetKeysProc *getkeys_proc;
/* What keys should be loaded in background when calling this command? */
int firstkey; /* The first argument that's a key (0 = no keys) */
@@ -877,6 +941,8 @@ extern struct redisServer server;
extern struct sharedObjectsStruct shared;
extern dictType setDictType;
extern dictType zsetDictType;
extern dictType clusterNodesDictType;
extern dictType clusterNodesBlackListDictType;
extern dictType dbDictType;
extern dictType shaScriptObjectDictType;
extern double R_Zero, R_PosInf, R_NegInf, R_Nan;
@@ -928,8 +994,8 @@ void *dupClientReplyValue(void *o);
void getClientsMaxBuffers(unsigned long *longest_output_list,
unsigned long *biggest_input_buffer);
void formatPeerId(char *peerid, size_t peerid_len, char *ip, int port);
int getClientPeerId(redisClient *client, char *peerid, size_t peerid_len);
sds getClientInfoString(redisClient *client);
char *getClientPeerId(redisClient *client);
sds catClientInfoString(sds s, redisClient *client);
sds getAllClientsInfoString(void);
void rewriteClientCommandVector(redisClient *c, int argc, ...);
void rewriteClientCommandArgument(redisClient *c, int i, robj *newval);
@@ -940,6 +1006,9 @@ int getClientLimitClassByName(char *name);
char *getClientLimitClassName(int class);
void flushSlavesOutputBuffers(void);
void disconnectSlaves(void);
int listenToPort(int port, int *fds, int *count);
void pauseClients(mstime_t duration);
int clientsArePaused(void);
int processEventsWhileBlocked(void);
#ifdef __GNUC__
@@ -968,7 +1037,6 @@ void listTypeConvert(robj *subject, int enc);
void unblockClientWaitingData(redisClient *c);
void handleClientsBlockedOnLists(void);
void popGenericCommand(redisClient *c, int where);
void signalListAsReady(redisDb *db, robj *key);
/* MULTI/EXEC/WATCH... */
void unwatchAllKeys(redisClient *c);
@@ -992,6 +1060,8 @@ void freeZsetObject(robj *o);
void freeHashObject(robj *o);
robj *createObject(int type, void *ptr);
robj *createStringObject(char *ptr, size_t len);
robj *createRawStringObject(char *ptr, size_t len);
robj *createEmbeddedStringObject(char *ptr, size_t len);
robj *dupStringObject(robj *o);
int isObjectRepresentableAsLongLong(robj *o, long long *llongval);
robj *tryObjectEncoding(robj *o);
@@ -1017,7 +1087,8 @@ char *strEncoding(int encoding);
int compareStringObjects(robj *a, robj *b);
int collateStringObjects(robj *a, robj *b);
int equalStringObjects(robj *a, robj *b);
unsigned long estimateObjectIdleTime(robj *o);
unsigned long long estimateObjectIdleTime(robj *o);
#define sdsEncodedObject(objptr) (objptr->encoding == REDIS_ENCODING_RAW || objptr->encoding == REDIS_ENCODING_EMBSTR)
/* Synchronous I/O with timeout */
ssize_t syncWrite(int fd, char *ptr, ssize_t size, long long timeout);
@@ -1032,14 +1103,18 @@ void replicationCron(void);
void replicationHandleMasterDisconnection(void);
void replicationCacheMaster(redisClient *c);
void resizeReplicationBacklog(long long newsize);
void replicationSetMaster(char *ip, int port);
void replicationUnsetMaster(void);
void refreshGoodSlavesCount(void);
void replicationScriptCacheInit(void);
void replicationScriptCacheFlush(void);
void replicationScriptCacheAdd(sds sha1);
int replicationScriptCacheExists(sds sha1);
void replicationSetMaster(char *ip, int port);
void replicationUnsetMaster(void);
void processClientsWaitingReplicas(void);
void unblockClientWaitingReplicas(redisClient *c);
int replicationCountAcksByOffset(long long offset);
void replicationSendNewlineToMaster(void);
long long replicationGetSlaveOffset(void);
/* Generic persistence functions */
void startLoading(FILE *fp);
@@ -1081,11 +1156,13 @@ zskiplistNode *zslInsert(zskiplist *zsl, double score, robj *obj);
unsigned char *zzlInsert(unsigned char *zl, robj *ele, double score);
int zslDelete(zskiplist *zsl, double score, robj *obj);
zskiplistNode *zslFirstInRange(zskiplist *zsl, zrangespec *range);
zskiplistNode *zslLastInRange(zskiplist *zsl, zrangespec *range);
double zzlGetScore(unsigned char *sptr);
void zzlNext(unsigned char *zl, unsigned char **eptr, unsigned char **sptr);
void zzlPrev(unsigned char *zl, unsigned char **eptr, unsigned char **sptr);
unsigned int zsetLength(robj *zobj);
void zsetConvert(robj *zobj, int encoding);
unsigned long zslGetRank(zskiplist *zsl, double score, robj *o);
/* Core functions */
int freeMemoryIfNeeded(void);
@@ -1117,6 +1194,7 @@ void adjustOpenFilesLimit(void);
void closeListeningSockets(int unlink_unix_socket);
void updateCachedTime(void);
void resetServerStats(void);
unsigned int getLRUClock(void);
/* Set data type */
robj *setTypeCreate(robj *value);
@@ -1193,18 +1271,28 @@ long long emptyDb(void(callback)(void*));
int selectDb(redisClient *c, int id);
void signalModifiedKey(redisDb *db, robj *key);
void signalFlushedDb(int dbid);
unsigned int GetKeysInSlot(unsigned int hashslot, robj **keys, unsigned int count);
unsigned int getKeysInSlot(unsigned int hashslot, robj **keys, unsigned int count);
unsigned int countKeysInSlot(unsigned int hashslot);
unsigned int delKeysInSlot(unsigned int hashslot);
int verifyClusterConfigWithData(void);
void scanGenericCommand(redisClient *c, robj *o, unsigned long cursor);
int parseScanCursorOrReply(redisClient *c, robj *o, unsigned long *cursor);
/* API to get key arguments from commands */
#define REDIS_GETKEYS_ALL 0
#define REDIS_GETKEYS_PRELOAD 1
int *getKeysFromCommand(struct redisCommand *cmd, robj **argv, int argc, int *numkeys, int flags);
int *getKeysFromCommand(struct redisCommand *cmd, robj **argv, int argc, int *numkeys);
void getKeysFreeResult(int *result);
int *noPreloadGetKeys(struct redisCommand *cmd,robj **argv, int argc, int *numkeys, int flags);
int *renameGetKeys(struct redisCommand *cmd,robj **argv, int argc, int *numkeys, int flags);
int *zunionInterGetKeys(struct redisCommand *cmd,robj **argv, int argc, int *numkeys, int flags);
int *zunionInterGetKeys(struct redisCommand *cmd,robj **argv, int argc, int *numkeys);
int *evalGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys);
int *sortGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys);
/* Cluster */
void clusterInit(void);
unsigned short crc16(const char *buf, int len);
unsigned int keyHashSlot(char *key, int keylen);
void clusterCron(void);
void clusterPropagatePublish(robj *channel, robj *message);
void migrateCloseTimedoutSockets(void);
void clusterBeforeSleep(void);
/* Sentinel */
void initSentinelConfig(void);
@@ -1216,6 +1304,13 @@ void sentinelIsRunning(void);
/* Scripting */
void scriptingInit(void);
/* Blocked clients */
void processUnblockedClients(void);
void blockClient(redisClient *c, int btype);
void unblockClient(redisClient *c);
void replyToBlockedClientTimedOut(redisClient *c);
int getTimeoutFromObjectOrReply(redisClient *c, robj *object, mstime_t *timeout, int unit);
/* Git SHA1 */
char *redisGitSHA1(void);
char *redisGitDirty(void);
@@ -1354,8 +1449,12 @@ void publishCommand(redisClient *c);
void pubsubCommand(redisClient *c);
void watchCommand(redisClient *c);
void unwatchCommand(redisClient *c);
void clusterCommand(redisClient *c);
void restoreCommand(redisClient *c);
void migrateCommand(redisClient *c);
void askingCommand(redisClient *c);
void readonlyCommand(redisClient *c);
void readwriteCommand(redisClient *c);
void dumpCommand(redisClient *c);
void objectCommand(redisClient *c);
void clientCommand(redisClient *c);
@@ -1367,6 +1466,7 @@ void bitopCommand(redisClient *c);
void bitcountCommand(redisClient *c);
void bitposCommand(redisClient *c);
void replconfCommand(redisClient *c);
void waitCommand(redisClient *c);
void pfselftestCommand(redisClient *c);
void pfaddCommand(redisClient *c);
void pfcountCommand(redisClient *c);
+197 -20
View File
@@ -39,6 +39,7 @@
void replicationDiscardCachedMaster(void);
void replicationResurrectCachedMaster(int newfd);
void replicationSendAck(void);
/* ---------------------------------- MASTER -------------------------------- */
@@ -238,7 +239,6 @@ void replicationFeedMonitors(redisClient *c, list *monitors, int dictid, robj **
int j;
sds cmdrepr = sdsnew("+");
robj *cmdobj;
char peerid[REDIS_PEER_ID_LEN];
struct timeval tv;
gettimeofday(&tv,NULL);
@@ -248,8 +248,7 @@ void replicationFeedMonitors(redisClient *c, list *monitors, int dictid, robj **
} else if (c->flags & REDIS_UNIX_SOCKET) {
cmdrepr = sdscatprintf(cmdrepr,"[%d unix:%s] ",dictid,server.unixsocket);
} else {
getClientPeerId(c,peerid,sizeof(peerid));
cmdrepr = sdscatprintf(cmdrepr,"[%d %s] ",dictid,peerid);
cmdrepr = sdscatprintf(cmdrepr,"[%d %s] ",dictid,getClientPeerId(c));
}
for (j = 0; j < argc; j++) {
@@ -343,7 +342,7 @@ int masterTryPartialResynchronization(redisClient *c) {
/* Run id "?" is used by slaves that want to force a full resync. */
if (master_runid[0] != '?') {
redisLog(REDIS_NOTICE,"Partial resynchronization not accepted: "
"Runid mismatch (Client asked for '%s', I'm '%s')",
"Runid mismatch (Client asked for runid '%s', my runid is '%s')",
master_runid, server.runid);
} else {
redisLog(REDIS_NOTICE,"Full resync requested by slave.");
@@ -447,7 +446,7 @@ void syncCommand(redisClient *c) {
return; /* No full resync needed, return. */
} else {
char *master_runid = c->argv[1]->ptr;
/* Increment stats for failed PSYNCs, but only if the
* runid is not "?", as this is used by slaves to force a full
* resync on purpose when they are not albe to partially
@@ -560,6 +559,11 @@ void replconfCommand(redisClient *c) {
c->repl_ack_time = server.unixtime;
/* Note: this command does not reply anything! */
return;
} else if (!strcasecmp(c->argv[j]->ptr,"getack")) {
/* REPLCONF GETACK is used in order to request an ACK ASAP
* to the slave. */
if (server.masterhost && server.master) replicationSendAck();
/* Note: this command does not reply anything! */
} else {
addReplyErrorFormat(c,"Unrecognized REPLCONF option: %s",
(char*)c->argv[j]->ptr);
@@ -576,23 +580,28 @@ void sendBulkToSlave(aeEventLoop *el, int fd, void *privdata, int mask) {
char buf[REDIS_IOBUF_LEN];
ssize_t nwritten, buflen;
if (slave->repldboff == 0) {
/* Write the bulk write count before to transfer the DB. In theory here
* we don't know how much room there is in the output buffer of the
* socket, but in practice SO_SNDLOWAT (the minimum count for output
* operations) will never be smaller than the few bytes we need. */
sds bulkcount;
bulkcount = sdscatprintf(sdsempty(),"$%lld\r\n",(unsigned long long)
slave->repldbsize);
if (write(fd,bulkcount,sdslen(bulkcount)) != (signed)sdslen(bulkcount))
{
sdsfree(bulkcount);
/* Before sending the RDB file, we send the preamble as configured by the
* replication process. Currently the preamble is just the bulk count of
* the file in the form "$<length>\r\n". */
if (slave->replpreamble) {
nwritten = write(fd,slave->replpreamble,sdslen(slave->replpreamble));
if (nwritten == -1) {
redisLog(REDIS_VERBOSE,"Write error sending RDB preamble to slave: %s",
strerror(errno));
freeClient(slave);
return;
}
sdsfree(bulkcount);
sdsrange(slave->replpreamble,nwritten,-1);
if (sdslen(slave->replpreamble) == 0) {
sdsfree(slave->replpreamble);
slave->replpreamble = NULL;
/* fall through sending data. */
} else {
return;
}
}
/* If the preamble was already transfered, send the RDB bulk data. */
lseek(slave->repldbfd,slave->repldboff,SEEK_SET);
buflen = read(slave->repldbfd,buf,REDIS_IOBUF_LEN);
if (buflen <= 0) {
@@ -662,6 +671,9 @@ void updateSlavesWaitingBgsave(int bgsaveerr) {
slave->repldboff = 0;
slave->repldbsize = buf.st_size;
slave->replstate = REDIS_REPL_SEND_BULK;
slave->replpreamble = sdscatprintf(sdsempty(),"$%lld\r\n",
(unsigned long long) slave->repldbsize);
aeDeleteFileEvent(server.el,slave->fd,AE_WRITABLE);
if (aeCreateFileEvent(server.el, slave->fd, AE_WRITABLE, sendBulkToSlave, slave) == AE_ERR) {
freeClient(slave);
@@ -1241,7 +1253,7 @@ int cancelReplicationHandshake(void) {
/* Set replication to the specified master address and port. */
void replicationSetMaster(char *ip, int port) {
sdsfree(server.masterhost);
server.masterhost = sdsdup(ip);
server.masterhost = sdsnew(ip);
server.masterport = port;
if (server.master) freeClient(server.master);
disconnectSlaves(); /* Force our slaves to resync with us as well. */
@@ -1250,6 +1262,7 @@ void replicationSetMaster(char *ip, int port) {
cancelReplicationHandshake();
server.repl_state = REDIS_REPL_CONNECT;
server.master_repl_offset = 0;
server.repl_down_since = 0;
}
/* Cancel replication, setting the instance as a master itself. */
@@ -1274,6 +1287,15 @@ void replicationUnsetMaster(void) {
}
void slaveofCommand(redisClient *c) {
/* SLAVEOF is not allowed in cluster mode as replication is automatically
* configured using the current address of the master node. */
if (server.cluster_enabled) {
addReplyError(c,"SLAVEOF not allowed in cluster mode.");
return;
}
/* The special host/port combination "NO" "ONE" turns the instance
* into a master. Otherwise the new master address is set. */
if (!strcasecmp(c->argv[1]->ptr,"no") &&
!strcasecmp(c->argv[2]->ptr,"one")) {
if (server.masterhost) {
@@ -1363,6 +1385,12 @@ void replicationCacheMaster(redisClient *c) {
/* Set fd to -1 so that we can safely call freeClient(c) later. */
c->fd = -1;
/* Invalidate the Peer ID cache. */
if (c->peerid) {
sdsfree(c->peerid);
c->peerid = NULL;
}
/* Caching the master happens instead of the actual freeClient() call,
* so make sure to adjust the replication state. This function will
* also set server.master to NULL. */
@@ -1522,7 +1550,156 @@ int replicationScriptCacheExists(sds sha1) {
return dictFind(server.repl_scriptcache_dict,sha1) != NULL;
}
/* --------------------------- REPLICATION CRON ----------------------------- */
/* ----------------------- SYNCHRONOUS REPLICATION --------------------------
* Redis synchronous replication design can be summarized in points:
*
* - Redis masters have a global replication offset, used by PSYNC.
* - Master increment the offset every time new commands are sent to slaves.
* - Slaves ping back masters with the offset processed so far.
*
* So synchronous replication adds a new WAIT command in the form:
*
* WAIT <num_replicas> <milliseconds_timeout>
*
* That returns the number of replicas that processed the query when
* we finally have at least num_replicas, or when the timeout was
* reached.
*
* The command is implemented in this way:
*
* - Every time a client processes a command, we remember the replication
* offset after sending that command to the slaves.
* - When WAIT is called, we ask slaves to send an acknowledgement ASAP.
* The client is blocked at the same time (see blocked.c).
* - Once we receive enough ACKs for a given offset or when the timeout
* is reached, the WAIT command is unblocked and the reply sent to the
* client.
*/
/* This just set a flag so that we broadcast a REPLCONF GETACK command
* to all the slaves in the beforeSleep() function. Note that this way
* we "group" all the clients that want to wait for synchronouns replication
* in a given event loop iteration, and send a single GETACK for them all. */
void replicationRequestAckFromSlaves(void) {
server.get_ack_from_slaves = 1;
}
/* Return the number of slaves that already acknowledged the specified
* replication offset. */
int replicationCountAcksByOffset(long long offset) {
listIter li;
listNode *ln;
int count = 0;
listRewind(server.slaves,&li);
while((ln = listNext(&li))) {
redisClient *slave = ln->value;
if (slave->replstate != REDIS_REPL_ONLINE) continue;
if (slave->repl_ack_off >= offset) count++;
}
return count;
}
/* WAIT for N replicas to acknowledge the processing of our latest
* write command (and all the previous commands). */
void waitCommand(redisClient *c) {
mstime_t timeout;
long numreplicas, ackreplicas;
long long offset = c->woff;
/* Argument parsing. */
if (getLongFromObjectOrReply(c,c->argv[1],&numreplicas,NULL) != REDIS_OK)
return;
if (getTimeoutFromObjectOrReply(c,c->argv[2],&timeout,UNIT_MILLISECONDS)
!= REDIS_OK) return;
/* First try without blocking at all. */
ackreplicas = replicationCountAcksByOffset(c->woff);
if (ackreplicas >= numreplicas || c->flags & REDIS_MULTI) {
addReplyLongLong(c,ackreplicas);
return;
}
/* Otherwise block the client and put it into our list of clients
* waiting for ack from slaves. */
c->bpop.timeout = timeout;
c->bpop.reploffset = offset;
c->bpop.numreplicas = numreplicas;
listAddNodeTail(server.clients_waiting_acks,c);
blockClient(c,REDIS_BLOCKED_WAIT);
/* Make sure that the server will send an ACK request to all the slaves
* before returning to the event loop. */
replicationRequestAckFromSlaves();
}
/* This is called by unblockClient() to perform the blocking op type
* specific cleanup. We just remove the client from the list of clients
* waiting for replica acks. Never call it directly, call unblockClient()
* instead. */
void unblockClientWaitingReplicas(redisClient *c) {
listNode *ln = listSearchKey(server.clients_waiting_acks,c);
redisAssert(ln != NULL);
listDelNode(server.clients_waiting_acks,ln);
}
/* Check if there are clients blocked in WAIT that can be unblocked since
* we received enough ACKs from slaves. */
void processClientsWaitingReplicas(void) {
long long last_offset = 0;
int last_numreplicas = 0;
listIter li;
listNode *ln;
listRewind(server.clients_waiting_acks,&li);
while((ln = listNext(&li))) {
redisClient *c = ln->value;
/* Every time we find a client that is satisfied for a given
* offset and number of replicas, we remember it so the next client
* may be unblocked without calling replicationCountAcksByOffset()
* if the requested offset / replicas were equal or less. */
if (last_offset && last_offset > c->bpop.reploffset &&
last_numreplicas > c->bpop.numreplicas)
{
unblockClient(c);
addReplyLongLong(c,last_numreplicas);
} else {
int numreplicas = replicationCountAcksByOffset(c->bpop.reploffset);
if (numreplicas >= c->bpop.numreplicas) {
last_offset = c->bpop.reploffset;
last_numreplicas = numreplicas;
unblockClient(c);
addReplyLongLong(c,numreplicas);
}
}
}
}
/* Return the slave replication offset for this instance, that is
* the offset for which we already processed the master replication stream. */
long long replicationGetSlaveOffset(void) {
long long offset = 0;
if (server.masterhost != NULL) {
if (server.master) {
offset = server.master->reploff;
} else if (server.cached_master) {
offset = server.cached_master->reploff;
}
}
/* offset may be -1 when the master does not support it at all, however
* this function is designed to return an offset that can express the
* amount of data processed by the master, so we return a positive
* integer. */
if (offset < 0) offset = 0;
return offset;
}
/* --------------------------- REPLICATION CRON ---------------------------- */
/* Replication cron funciton, called 1 time per second. */
void replicationCron(void) {
+6 -15
View File
@@ -232,23 +232,13 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
for (j = 0; j < argc; j++) {
char *obj_s;
size_t obj_len;
char dbuf[64];
if (lua_type(lua,j+1) == LUA_TNUMBER) {
/* We can't use lua_tolstring() for number -> string conversion
* since Lua uses a format specifier that loses precision. */
lua_Number num = lua_tonumber(lua,j+1);
obj_len = snprintf(dbuf,sizeof(dbuf),"%.17g",(double)num);
obj_s = dbuf;
} else {
obj_s = (char*)lua_tolstring(lua,j+1,&obj_len);
if (obj_s == NULL) break; /* Not a string. */
}
obj_s = (char*)lua_tolstring(lua,j+1,&obj_len);
if (obj_s == NULL) break; /* Not a string. */
/* Try to use a cached object. */
if (j < LUA_CMD_OBJCACHE_SIZE && cached_objects[j] &&
cached_objects_len[j] >= obj_len)
if (j < LUA_CMD_OBJCACHE_SIZE && cached_objects[j] &&
cached_objects_len[j] >= obj_len)
{
char *s = cached_objects[j]->ptr;
struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
@@ -385,7 +375,8 @@ cleanup:
* (we must be the only owner) for us to cache it. */
if (j < LUA_CMD_OBJCACHE_SIZE &&
o->refcount == 1 &&
o->encoding == REDIS_ENCODING_RAW &&
(o->encoding == REDIS_ENCODING_RAW ||
o->encoding == REDIS_ENCODING_EMBSTR) &&
sdslen(o->ptr) <= LUA_CMD_OBJCACHE_MAX_LEN)
{
struct sdshdr *sh = (void*)(((char*)(o->ptr))-(sizeof(struct sdshdr)));
+232 -27
View File
@@ -289,6 +289,84 @@ sds sdscpy(sds s, const char *t) {
return sdscpylen(s, t, strlen(t));
}
/* Helper for sdscatlonglong() doing the actual number -> string
* conversion. 's' must point to a string with room for at least
* SDS_LLSTR_SIZE bytes.
*
* The function returns the lenght of the null-terminated string
* representation stored at 's'. */
#define SDS_LLSTR_SIZE 21
int sdsll2str(char *s, long long value) {
char *p, aux;
unsigned long long v;
size_t l;
/* Generate the string representation, this method produces
* an reversed string. */
v = (value < 0) ? -value : value;
p = s;
do {
*p++ = '0'+(v%10);
v /= 10;
} while(v);
if (value < 0) *p++ = '-';
/* Compute length and add null term. */
l = p-s;
*p = '\0';
/* Reverse the string. */
p--;
while(s < p) {
aux = *s;
*s = *p;
*p = aux;
s++;
p--;
}
return l;
}
/* Identical sdsll2str(), but for unsigned long long type. */
int sdsull2str(char *s, unsigned long long v) {
char *p, aux;
size_t l;
/* Generate the string representation, this method produces
* an reversed string. */
p = s;
do {
*p++ = '0'+(v%10);
v /= 10;
} while(v);
/* Compute length and add null term. */
l = p-s;
*p = '\0';
/* Reverse the string. */
p--;
while(s < p) {
aux = *s;
*s = *p;
*p = aux;
s++;
p--;
}
return l;
}
/* Create an sds string from a long long value. It is much faster than:
*
* sdscatprintf(sdsempty(),"%lld\n", value);
*/
sds sdsfromlonglong(long long value) {
char buf[SDS_LLSTR_SIZE];
int len = sdsll2str(buf,value);
return sdsnewlen(buf,len);
}
/* Like sdscatpritf() but gets va_list instead of being variadic. */
sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
va_list cpy;
@@ -351,6 +429,122 @@ sds sdscatprintf(sds s, const char *fmt, ...) {
return t;
}
/* This function is similar to sdscatprintf, but much faster as it does
* not rely on sprintf() family functions implemented by the libc that
* are often very slow. Moreover directly handling the sds string as
* new data is concatenated provides a performance improvement.
*
* However this function only handles an incompatible subset of printf-alike
* format specifiers:
*
* %s - C String
* %S - SDS string
* %i - signed int
* %I - 64 bit signed integer (long long, int64_t)
* %u - unsigned int
* %U - 64 bit unsigned integer (unsigned long long, uint64_t)
* %% - Verbatim "%" character.
*/
sds sdscatfmt(sds s, char const *fmt, ...) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
size_t initlen = sdslen(s);
const char *f = fmt;
int i;
va_list ap;
va_start(ap,fmt);
f = fmt; /* Next format specifier byte to process. */
i = initlen; /* Position of the next byte to write to dest str. */
while(*f) {
char next, *str;
size_t l;
long long num;
unsigned long long unum;
/* Make sure there is always space for at least 1 char. */
if (sh->free == 0) {
s = sdsMakeRoomFor(s,1);
sh = (void*) (s-(sizeof(struct sdshdr)));
}
switch(*f) {
case '%':
next = *(f+1);
f++;
switch(next) {
case 's':
case 'S':
str = va_arg(ap,char*);
l = (next == 's') ? strlen(str) : sdslen(str);
if (sh->free < l) {
s = sdsMakeRoomFor(s,l);
sh = (void*) (s-(sizeof(struct sdshdr)));
}
memcpy(s+i,str,l);
sh->len += l;
sh->free -= l;
i += l;
break;
case 'i':
case 'I':
if (next == 'i')
num = va_arg(ap,int);
else
num = va_arg(ap,long long);
{
char buf[SDS_LLSTR_SIZE];
l = sdsll2str(buf,num);
if (sh->free < l) {
s = sdsMakeRoomFor(s,l);
sh = (void*) (s-(sizeof(struct sdshdr)));
}
memcpy(s+i,buf,l);
sh->len += l;
sh->free -= l;
i += l;
}
break;
case 'u':
case 'U':
if (next == 'u')
unum = va_arg(ap,unsigned int);
else
unum = va_arg(ap,unsigned long long);
{
char buf[SDS_LLSTR_SIZE];
l = sdsull2str(buf,unum);
if (sh->free < l) {
s = sdsMakeRoomFor(s,l);
sh = (void*) (s-(sizeof(struct sdshdr)));
}
memcpy(s+i,buf,l);
sh->len += l;
sh->free -= l;
i += l;
}
break;
default: /* Handle %% and generally %<unknown>. */
s[i++] = next;
sh->len += 1;
sh->free -= 1;
break;
}
break;
default:
s[i++] = *f;
sh->len += 1;
sh->free -= 1;
break;
}
f++;
}
va_end(ap);
/* Add null-term */
s[i] = '\0';
return s;
}
/* Remove the part of the string from left and from right composed just of
* contiguous characters found in 'cset', that is a null terminted C string.
*
@@ -538,25 +732,6 @@ void sdsfreesplitres(sds *tokens, int count) {
zfree(tokens);
}
/* Create an sds string from a long long value. It is much faster than:
*
* sdscatprintf(sdsempty(),"%lld\n", value);
*/
sds sdsfromlonglong(long long value) {
char buf[32], *p;
unsigned long long v;
v = (value < 0) ? -value : value;
p = buf+31; /* point to the last character */
do {
*p-- = '0'+(v%10);
v /= 10;
} while(v);
if (value < 0) *p-- = '-';
p++;
return sdsnewlen(p,32-(p-buf));
}
/* Append to the sds string "s" an escaped string representation where
* all the non-printable characters (tested with isprint()) are turned into
* escapes in the form "\n\r\a...." or "\x<hex-number>".
@@ -787,6 +962,7 @@ sds sdsjoin(char **argv, int argc, char *sep) {
#ifdef SDS_TEST_MAIN
#include <stdio.h>
#include "testhelp.h"
#include "limits.h"
int main(void) {
{
@@ -817,39 +993,61 @@ int main(void) {
sdsfree(x);
x = sdscatprintf(sdsempty(),"%d",123);
test_cond("sdscatprintf() seems working in the base case",
sdslen(x) == 3 && memcmp(x,"123\0",4) ==0)
sdslen(x) == 3 && memcmp(x,"123\0",4) == 0)
sdsfree(x);
x = sdstrim(sdsnew("xxciaoyyy"),"xy");
x = sdsnew("--");
x = sdscatfmt(x, "Hello %s World %I,%I--", "Hi!", LLONG_MIN,LLONG_MAX);
test_cond("sdscatfmt() seems working in the base case",
sdslen(x) == 60 &&
memcmp(x,"--Hello Hi! World -9223372036854775808,"
"9223372036854775807--",60) == 0)
sdsfree(x);
x = sdsnew("--");
x = sdscatfmt(x, "%u,%U--", UINT_MAX, ULLONG_MAX);
test_cond("sdscatfmt() seems working with unsigned numbers",
sdslen(x) == 35 &&
memcmp(x,"--4294967295,18446744073709551615--",35) == 0)
sdsfree(x);
x = sdsnew("xxciaoyyy");
sdstrim(x,"xy");
test_cond("sdstrim() correctly trims characters",
sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0)
y = sdsrange(sdsdup(x),1,1);
y = sdsdup(x);
sdsrange(y,1,1);
test_cond("sdsrange(...,1,1)",
sdslen(y) == 1 && memcmp(y,"i\0",2) == 0)
sdsfree(y);
y = sdsrange(sdsdup(x),1,-1);
y = sdsdup(x);
sdsrange(y,1,-1);
test_cond("sdsrange(...,1,-1)",
sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)
sdsfree(y);
y = sdsrange(sdsdup(x),-2,-1);
y = sdsdup(x);
sdsrange(y,-2,-1);
test_cond("sdsrange(...,-2,-1)",
sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0)
sdsfree(y);
y = sdsrange(sdsdup(x),2,1);
y = sdsdup(x);
sdsrange(y,2,1);
test_cond("sdsrange(...,2,1)",
sdslen(y) == 0 && memcmp(y,"\0",1) == 0)
sdsfree(y);
y = sdsrange(sdsdup(x),1,100);
y = sdsdup(x);
sdsrange(y,1,100);
test_cond("sdsrange(...,1,100)",
sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)
sdsfree(y);
y = sdsrange(sdsdup(x),100,100);
y = sdsdup(x);
sdsrange(y,100,100);
test_cond("sdsrange(...,100,100)",
sdslen(y) == 0 && memcmp(y,"\0",1) == 0)
@@ -871,6 +1069,13 @@ int main(void) {
y = sdsnew("bar");
test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0)
sdsfree(y);
sdsfree(x);
x = sdsnewlen("\a\n\0foo\r",7);
y = sdscatrepr(sdsempty(),x,sdslen(x));
test_cond("sdscatrepr(...data...)",
memcmp(y,"\"\\a\\n\\x00foo\\r\"",15) == 0)
{
int oldfree;
+1
View File
@@ -76,6 +76,7 @@ sds sdscatprintf(sds s, const char *fmt, ...)
sds sdscatprintf(sds s, const char *fmt, ...);
#endif
sds sdscatfmt(sds s, char const *fmt, ...);
sds sdstrim(sds s, const char *cset);
void sdsrange(sds s, int start, int end);
void sdsupdatelen(sds s);
+2 -2
View File
@@ -88,7 +88,7 @@ typedef struct sentinelAddr {
/* Failover machine different states. */
#define SENTINEL_FAILOVER_STATE_NONE 0 /* No failover in progress. */
#define SENTINEL_FAILOVER_STATE_WAIT_START 1 /* Wait for failover_start_time*/
#define SENTINEL_FAILOVER_STATE_WAIT_START 1 /* Wait for failover_start_time*/
#define SENTINEL_FAILOVER_STATE_SELECT_SLAVE 2 /* Select slave to promote */
#define SENTINEL_FAILOVER_STATE_SEND_SLAVEOF_NOONE 3 /* Slave -> Master */
#define SENTINEL_FAILOVER_STATE_WAIT_PROMOTION 4 /* Wait slave to change role */
@@ -2875,7 +2875,7 @@ void sentinelCheckSubjectivelyDown(sentinelRedisInstance *ri) {
if (ri->last_ping_time)
elapsed = mstime() - ri->last_ping_time;
/* Check if we are in need for a reconnection of one of the
/* Check if we are in need for a reconnection of one of the
* links, because we are detecting low activity.
*
* 1) Check if the command link seems connected, was connected not less
+1 -1
View File
@@ -63,7 +63,7 @@ slowlogEntry *slowlogCreateEntry(robj **argv, int argc, long long duration) {
} else {
/* Trim too long strings as well... */
if (argv[j]->type == REDIS_STRING &&
argv[j]->encoding == REDIS_ENCODING_RAW &&
sdsEncodedObject(argv[j]) &&
sdslen(argv[j]->ptr) > SLOWLOG_ENTRY_MAX_STRING)
{
sds s = sdsnewlen(argv[j]->ptr, SLOWLOG_ENTRY_MAX_STRING);
+29 -8
View File
@@ -194,6 +194,7 @@ void sortCommand(redisClient *c) {
int j, dontsort = 0, vectorlen;
int getop = 0; /* GET operation counter */
int int_convertion_error = 0;
int syntax_error = 0;
robj *sortval, *sortby = NULL, *storekey = NULL;
redisSortObject *vector; /* Resulting vector to sort */
@@ -236,9 +237,8 @@ void sortCommand(redisClient *c) {
(getLongFromObjectOrReply(c, c->argv[j+2], &limit_count, NULL)
!= REDIS_OK))
{
decrRefCount(sortval);
listRelease(operations);
return;
syntax_error++;
break;
}
j+=2;
} else if (!strcasecmp(c->argv[j]->ptr,"store") && leftargs >= 1) {
@@ -248,22 +248,43 @@ void sortCommand(redisClient *c) {
sortby = c->argv[j+1];
/* If the BY pattern does not contain '*', i.e. it is constant,
* we don't need to sort nor to lookup the weight keys. */
if (strchr(c->argv[j+1]->ptr,'*') == NULL) dontsort = 1;
if (strchr(c->argv[j+1]->ptr,'*') == NULL) {
dontsort = 1;
} else {
/* If BY is specified with a real patter, we can't accept
* it in cluster mode. */
if (server.cluster_enabled) {
addReplyError(c,"BY option of SORT denied in Cluster mode.");
syntax_error++;
break;
}
}
j++;
} else if (!strcasecmp(c->argv[j]->ptr,"get") && leftargs >= 1) {
if (server.cluster_enabled) {
addReplyError(c,"GET option of SORT denied in Cluster mode.");
syntax_error++;
break;
}
listAddNodeTail(operations,createSortOperation(
REDIS_SORT_GET,c->argv[j+1]));
getop++;
j++;
} else {
decrRefCount(sortval);
listRelease(operations);
addReply(c,shared.syntaxerr);
return;
syntax_error++;
break;
}
j++;
}
/* Handle syntax errors set during options parsing. */
if (syntax_error) {
decrRefCount(sortval);
listRelease(operations);
return;
}
/* For the STORE option, or when SORT is called from a Lua script,
* we want to force a specific ordering even when no explicit ordering
* was asked (SORT BY nosort). This guarantees that replication / AOF
@@ -418,7 +439,7 @@ void sortCommand(redisClient *c) {
if (alpha) {
if (sortby) vector[j].u.cmpobj = getDecodedObject(byval);
} else {
if (byval->encoding == REDIS_ENCODING_RAW) {
if (sdsEncodedObject(byval)) {
char *eptr;
vector[j].u.score = strtod(byval->ptr,&eptr);
+1 -4
View File
@@ -43,7 +43,7 @@ void hashTypeTryConversion(robj *o, robj **argv, int start, int end) {
if (o->encoding != REDIS_ENCODING_ZIPLIST) return;
for (i = start; i <= end; i++) {
if (argv[i]->encoding == REDIS_ENCODING_RAW &&
if (sdsEncodedObject(argv[i]) &&
sdslen(argv[i]->ptr) > server.hash_max_ziplist_value)
{
hashTypeConvert(o, REDIS_ENCODING_HT);
@@ -384,15 +384,12 @@ robj *hashTypeCurrentObject(hashTypeIterator *hi, int what) {
} else {
dst = createStringObjectFromLongLong(vll);
}
} else if (hi->encoding == REDIS_ENCODING_HT) {
hashTypeCurrentFromHashTable(hi, what, &dst);
incrRefCount(dst);
} else {
redisPanic("Unknown hash encoding");
}
return dst;
}
+25 -43
View File
@@ -29,6 +29,8 @@
#include "redis.h"
void signalListAsReady(redisClient *c, robj *key);
/*-----------------------------------------------------------------------------
* List API
*----------------------------------------------------------------------------*/
@@ -38,7 +40,7 @@
* objects are never too long. */
void listTypeTryConversion(robj *subject, robj *value) {
if (subject->encoding != REDIS_ENCODING_ZIPLIST) return;
if (value->encoding == REDIS_ENCODING_RAW &&
if (sdsEncodedObject(value) &&
sdslen(value->ptr) > server.list_max_ziplist_value)
listTypeConvert(subject,REDIS_ENCODING_LINKEDLIST);
}
@@ -232,7 +234,7 @@ void listTypeInsert(listTypeEntry *entry, robj *value, int where) {
int listTypeEqual(listTypeEntry *entry, robj *o) {
listTypeIterator *li = entry->li;
if (li->encoding == REDIS_ENCODING_ZIPLIST) {
redisAssertWithInfo(NULL,o,o->encoding == REDIS_ENCODING_RAW);
redisAssertWithInfo(NULL,o,sdsEncodedObject(o));
return ziplistCompare(entry->zi,o->ptr,sdslen(o->ptr));
} else if (li->encoding == REDIS_ENCODING_LINKEDLIST) {
return equalStringObjects(o,listNodeValue(entry->ln));
@@ -295,12 +297,15 @@ void listTypeConvert(robj *subject, int enc) {
void pushGenericCommand(redisClient *c, int where) {
int j, waiting = 0, pushed = 0;
robj *lobj = lookupKeyWrite(c->db,c->argv[1]);
int may_have_waiting_clients = (lobj == NULL);
if (lobj && lobj->type != REDIS_LIST) {
addReply(c,shared.wrongtypeerr);
return;
}
if (may_have_waiting_clients) signalListAsReady(c,c->argv[1]);
for (j = 2; j < c->argc; j++) {
c->argv[j] = tryObjectEncoding(c->argv[j]);
if (!lobj) {
@@ -704,6 +709,7 @@ void rpoplpushHandlePush(redisClient *c, robj *dstkey, robj *dstobj, robj *value
if (!dstobj) {
dstobj = createZiplistObject();
dbAdd(c->db,dstkey,dstobj);
signalListAsReady(c,dstkey);
}
signalModifiedKey(c->db,dstkey);
listTypePush(dstobj,value,REDIS_HEAD);
@@ -772,7 +778,7 @@ void rpoplpushCommand(redisClient *c) {
/* Set a client in blocking mode for the specified key, with the specified
* timeout */
void blockForKeys(redisClient *c, robj **keys, int numkeys, time_t timeout, robj *target) {
void blockForKeys(redisClient *c, robj **keys, int numkeys, mstime_t timeout, robj *target) {
dictEntry *de;
list *l;
int j;
@@ -802,13 +808,11 @@ void blockForKeys(redisClient *c, robj **keys, int numkeys, time_t timeout, robj
}
listAddNodeTail(l,c);
}
/* Mark the client as a blocked client */
c->flags |= REDIS_BLOCKED;
server.bpop_blocked_clients++;
blockClient(c,REDIS_BLOCKED_LIST);
}
/* Unblock a client that's waiting in a blocking operation such as BLPOP */
/* Unblock a client that's waiting in a blocking operation such as BLPOP.
* You should never call this function directly, but unblockClient() instead. */
void unblockClientWaitingData(redisClient *c) {
dictEntry *de;
dictIterator *di;
@@ -836,10 +840,6 @@ void unblockClientWaitingData(redisClient *c) {
decrRefCount(c->bpop.target);
c->bpop.target = NULL;
}
c->flags &= ~REDIS_BLOCKED;
c->flags |= REDIS_UNBLOCKED;
server.bpop_blocked_clients--;
listAddNodeTail(server.unblocked_clients,c);
}
/* If the specified key has clients blocked waiting for list pushes, this
@@ -849,19 +849,19 @@ void unblockClientWaitingData(redisClient *c) {
* made by a script or in the context of MULTI/EXEC.
*
* The list will be finally processed by handleClientsBlockedOnLists() */
void signalListAsReady(redisDb *db, robj *key) {
void signalListAsReady(redisClient *c, robj *key) {
readyList *rl;
/* No clients blocking for this key? No need to queue it. */
if (dictFind(db->blocking_keys,key) == NULL) return;
if (dictFind(c->db->blocking_keys,key) == NULL) return;
/* Key was already signaled? No need to queue it again. */
if (dictFind(db->ready_keys,key) != NULL) return;
if (dictFind(c->db->ready_keys,key) != NULL) return;
/* Ok, we need to queue this key into server.ready_keys. */
rl = zmalloc(sizeof(*rl));
rl->key = key;
rl->db = db;
rl->db = c->db;
incrRefCount(key);
listAddNodeTail(server.ready_keys,rl);
@@ -869,7 +869,7 @@ void signalListAsReady(redisDb *db, robj *key) {
* to avoid adding it multiple times into a list with a simple O(1)
* check. */
incrRefCount(key);
redisAssert(dictAdd(db->ready_keys,key,NULL) == DICT_OK);
redisAssert(dictAdd(c->db->ready_keys,key,NULL) == DICT_OK);
}
/* This is a helper function for handleClientsBlockedOnLists(). It's work
@@ -994,10 +994,10 @@ void handleClientsBlockedOnLists(void) {
if (value) {
/* Protect receiver->bpop.target, that will be
* freed by the next unblockClientWaitingData()
* freed by the next unblockClient()
* call. */
if (dstkey) incrRefCount(dstkey);
unblockClientWaitingData(receiver);
unblockClient(receiver);
if (serveClientBlockedOnList(receiver,
rl->key,dstkey,rl->db,value,
@@ -1030,32 +1030,14 @@ void handleClientsBlockedOnLists(void) {
}
}
int getTimeoutFromObjectOrReply(redisClient *c, robj *object, time_t *timeout) {
long tval;
if (getLongFromObjectOrReply(c,object,&tval,
"timeout is not an integer or out of range") != REDIS_OK)
return REDIS_ERR;
if (tval < 0) {
addReplyError(c,"timeout is negative");
return REDIS_ERR;
}
if (tval > 0) tval += server.unixtime;
*timeout = tval;
return REDIS_OK;
}
/* Blocking RPOP/LPOP */
void blockingPopGenericCommand(redisClient *c, int where) {
robj *o;
time_t timeout;
mstime_t timeout;
int j;
if (getTimeoutFromObjectOrReply(c,c->argv[c->argc-1],&timeout) != REDIS_OK)
return;
if (getTimeoutFromObjectOrReply(c,c->argv[c->argc-1],&timeout,UNIT_SECONDS)
!= REDIS_OK) return;
for (j = 1; j < c->argc-1; j++) {
o = lookupKeyWrite(c->db,c->argv[j]);
@@ -1114,10 +1096,10 @@ void brpopCommand(redisClient *c) {
}
void brpoplpushCommand(redisClient *c) {
time_t timeout;
mstime_t timeout;
if (getTimeoutFromObjectOrReply(c,c->argv[3],&timeout) != REDIS_OK)
return;
if (getTimeoutFromObjectOrReply(c,c->argv[3],&timeout,UNIT_SECONDS)
!= REDIS_OK) return;
robj *key = lookupKeyWrite(c->db, c->argv[1]);
+2 -7
View File
@@ -495,11 +495,8 @@ void srandmemberWithCountCommand(redisClient *c) {
if (encoding == REDIS_ENCODING_INTSET) {
retval = dictAdd(d,createStringObjectFromLongLong(llele),NULL);
} else if (ele->encoding == REDIS_ENCODING_RAW) {
} else {
retval = dictAdd(d,dupStringObject(ele),NULL);
} else if (ele->encoding == REDIS_ENCODING_INT) {
retval = dictAdd(d,
createStringObjectFromLongLong((long)ele->ptr),NULL);
}
redisAssert(retval == DICT_OK);
}
@@ -527,10 +524,8 @@ void srandmemberWithCountCommand(redisClient *c) {
encoding = setTypeRandomElement(set,&ele,&llele);
if (encoding == REDIS_ENCODING_INTSET) {
ele = createStringObjectFromLongLong(llele);
} else if (ele->encoding == REDIS_ENCODING_RAW) {
} else {
ele = dupStringObject(ele);
} else if (ele->encoding == REDIS_ENCODING_INT) {
ele = createStringObjectFromLongLong((long)ele->ptr);
}
/* Try to add the object to the dictionary. If it already exists
* free it, otherwise increment the number of objects we have
+9 -8
View File
@@ -954,7 +954,7 @@ unsigned char *zzlInsertAt(unsigned char *zl, unsigned char *eptr, robj *ele, do
int scorelen;
size_t offset;
redisAssertWithInfo(NULL,ele,ele->encoding == REDIS_ENCODING_RAW);
redisAssertWithInfo(NULL,ele,sdsEncodedObject(ele));
scorelen = d2string(scorebuf,sizeof(scorebuf),score);
if (eptr == NULL) {
zl = ziplistPush(zl,ele->ptr,sdslen(ele->ptr),ZIPLIST_TAIL);
@@ -1333,7 +1333,6 @@ void zremCommand(redisClient *c) {
zobj->ptr = zzlDelete(zobj->ptr,eptr);
if (zzlLength(zobj->ptr) == 0) {
dbDelete(c->db,key);
keyremoved = 1;
break;
}
}
@@ -1357,7 +1356,6 @@ void zremCommand(redisClient *c) {
if (htNeedsResize(zs->dict)) dictResize(zs->dict);
if (dictSize(zs->dict) == 0) {
dbDelete(c->db,key);
keyremoved = 1;
break;
}
}
@@ -1712,7 +1710,7 @@ int zuiLongLongFromValue(zsetopval *val) {
if (val->ele->encoding == REDIS_ENCODING_INT) {
val->ell = (long)val->ele->ptr;
val->flags |= OPVAL_VALID_LL;
} else if (val->ele->encoding == REDIS_ENCODING_RAW) {
} else if (sdsEncodedObject(val->ele)) {
if (string2ll(val->ele->ptr,sdslen(val->ele->ptr),&val->ell))
val->flags |= OPVAL_VALID_LL;
} else {
@@ -1747,7 +1745,7 @@ int zuiBufferFromValue(zsetopval *val) {
if (val->ele->encoding == REDIS_ENCODING_INT) {
val->elen = ll2string((char*)val->_buf,sizeof(val->_buf),(long)val->ele->ptr);
val->estr = val->_buf;
} else if (val->ele->encoding == REDIS_ENCODING_RAW) {
} else if (sdsEncodedObject(val->ele)) {
val->elen = sdslen(val->ele->ptr);
val->estr = val->ele->ptr;
} else {
@@ -1972,9 +1970,10 @@ void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
dictAdd(dstzset->dict,tmp,&znode->score);
incrRefCount(tmp); /* added to dictionary */
if (tmp->encoding == REDIS_ENCODING_RAW)
if (sdsEncodedObject(tmp)) {
if (sdslen(tmp->ptr) > maxelelen)
maxelelen = sdslen(tmp->ptr);
}
}
}
zuiClearIterator(&src[0]);
@@ -2018,9 +2017,10 @@ void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
dictAdd(dstzset->dict,tmp,&znode->score);
incrRefCount(zval.ele); /* added to dictionary */
if (tmp->encoding == REDIS_ENCODING_RAW)
if (sdsEncodedObject(tmp)) {
if (sdslen(tmp->ptr) > maxelelen)
maxelelen = sdslen(tmp->ptr);
}
}
zuiClearIterator(&src[i]);
}
@@ -2760,7 +2760,8 @@ void zrankGenericCommand(redisClient *c, int reverse) {
checkType(c,zobj,REDIS_ZSET)) return;
llen = zsetLength(zobj);
redisAssertWithInfo(c,ele,ele->encoding == REDIS_ENCODING_RAW);
redisAssertWithInfo(c,ele,sdsEncodedObject(ele));
if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
unsigned char *zl = zobj->ptr;
unsigned char *eptr, *sptr;
+1 -1
View File
@@ -1 +1 @@
#define REDIS_VERSION "2.8.11"
#define REDIS_VERSION "2.9.54"
+130
View File
@@ -0,0 +1,130 @@
# Cluster-specific test functions.
#
# Copyright (C) 2014 Salvatore Sanfilippo antirez@gmail.com
# This softare is released under the BSD License. See the COPYING file for
# more information.
# Returns a parsed CLUSTER NODES output as a list of dictionaries.
proc get_cluster_nodes id {
set lines [split [R $id cluster nodes] "\r\n"]
set nodes {}
foreach l $lines {
set l [string trim $l]
if {$l eq {}} continue
set args [split $l]
set node [dict create \
id [lindex $args 0] \
addr [lindex $args 1] \
flags [split [lindex $args 2] ,] \
slaveof [lindex $args 3] \
ping_sent [lindex $args 4] \
pong_recv [lindex $args 5] \
config_epoch [lindex $args 6] \
linkstate [lindex $args 7] \
slots [lrange $args 8 -1] \
]
lappend nodes $node
}
return $nodes
}
# Test node for flag.
proc has_flag {node flag} {
expr {[lsearch -exact [dict get $node flags] $flag] != -1}
}
# Returns the parsed myself node entry as a dictionary.
proc get_myself id {
set nodes [get_cluster_nodes $id]
foreach n $nodes {
if {[has_flag $n myself]} {return $n}
}
return {}
}
# Return the value of the specified CLUSTER INFO field.
proc CI {n field} {
get_info_field [R $n cluster info] $field
}
# Assuming nodes are reest, this function performs slots allocation.
# Only the first 'n' nodes are used.
proc cluster_allocate_slots {n} {
set slot 16383
while {$slot >= 0} {
# Allocate successive slots to random nodes.
set node [randomInt $n]
lappend slots_$node $slot
incr slot -1
}
for {set j 0} {$j < $n} {incr j} {
R $j cluster addslots {*}[set slots_${j}]
}
}
# Check that cluster nodes agree about "state", or raise an error.
proc assert_cluster_state {state} {
foreach_redis_id id {
if {[instance_is_killed redis $id]} continue
wait_for_condition 1000 50 {
[CI $id cluster_state] eq $state
} else {
fail "Cluster node $id cluster_state:[CI $id cluster_state]"
}
}
}
# Search the first node starting from ID $first that is not
# already configured as a slave.
proc cluster_find_available_slave {first} {
foreach_redis_id id {
if {$id < $first} continue
if {[instance_is_killed redis $id]} continue
set me [get_myself $id]
if {[dict get $me slaveof] eq {-}} {return $id}
}
fail "No available slaves"
}
# Add 'slaves' slaves to a cluster composed of 'masters' masters.
# It assumes that masters are allocated sequentially from instance ID 0
# to N-1.
proc cluster_allocate_slaves {masters slaves} {
for {set j 0} {$j < $slaves} {incr j} {
set master_id [expr {$j % $masters}]
set slave_id [cluster_find_available_slave $masters]
set master_myself [get_myself $master_id]
R $slave_id cluster replicate [dict get $master_myself id]
}
}
# Create a cluster composed of the specified number of masters and slaves.
proc create_cluster {masters slaves} {
cluster_allocate_slots $masters
if {$slaves} {
cluster_allocate_slaves $masters $slaves
}
assert_cluster_state ok
}
# Set the cluster node-timeout to all the reachalbe nodes.
proc set_cluster_node_timeout {to} {
foreach_redis_id id {
catch {R $id CONFIG SET cluster-node-timeout $to}
}
}
# Check if the cluster is writable and readable. Use node "id"
# as a starting point to talk with the cluster.
proc cluster_write_test {id} {
set prefix [randstring 20 20 alpha]
set port [get_instance_attrib redis $id port]
set cluster [redis_cluster 127.0.0.1:$port]
for {set j 0} {$j < 100} {incr j} {
$cluster set key.$j $prefix.$j
}
for {set j 0} {$j < 100} {incr j} {
assert {[$cluster get key.$j] eq "$prefix.$j"}
}
$cluster close
}
+25
View File
@@ -0,0 +1,25 @@
# Cluster test suite. Copyright (C) 2014 Salvatore Sanfilippo antirez@gmail.com
# This softare is released under the BSD License. See the COPYING file for
# more information.
cd tests/cluster
source cluster.tcl
source ../instances.tcl
source ../../support/cluster.tcl ; # Redis Cluster client.
set ::instances_count 20 ; # How many instances we use at max.
proc main {} {
parse_options
spawn_instance redis $::redis_base_port $::instances_count {
"cluster-enabled yes"
"appendonly yes"
}
run_tests
cleanup
}
if {[catch main e]} {
puts $::errorInfo
cleanup
}
+59
View File
@@ -0,0 +1,59 @@
# Check the basic monitoring and failover capabilities.
source "../tests/includes/init-tests.tcl"
if {$::simulate_error} {
test "This test will fail" {
fail "Simulated error"
}
}
test "Different nodes have different IDs" {
set ids {}
set numnodes 0
foreach_redis_id id {
incr numnodes
# Every node should just know itself.
set nodeid [dict get [get_myself $id] id]
assert {$nodeid ne {}}
lappend ids $nodeid
}
set numids [llength [lsort -unique $ids]]
assert {$numids == $numnodes}
}
test "It is possible to perform slot allocation" {
cluster_allocate_slots 5
}
test "After the join, every node gets a different config epoch" {
set trynum 60
while {[incr trynum -1] != 0} {
# We check that this condition is true for *all* the nodes.
set ok 1 ; # Will be set to 0 every time a node is not ok.
foreach_redis_id id {
set epochs {}
foreach n [get_cluster_nodes $id] {
lappend epochs [dict get $n config_epoch]
}
if {[lsort $epochs] != [lsort -unique $epochs]} {
set ok 0 ; # At least one collision!
}
}
if {$ok} break
after 1000
puts -nonewline .
flush stdout
}
if {$trynum == 0} {
fail "Config epoch conflict resolution is not working."
}
}
test "Nodes should report cluster_state is ok now" {
assert_cluster_state ok
}
test "It is possible to write and read from the cluster" {
cluster_write_test 0
}
+38
View File
@@ -0,0 +1,38 @@
# Check the basic monitoring and failover capabilities.
source "../tests/includes/init-tests.tcl"
test "Create a 5 nodes cluster" {
create_cluster 5 5
}
test "Cluster should start ok" {
assert_cluster_state ok
}
test "Killing two slave nodes" {
kill_instance redis 5
kill_instance redis 6
}
test "Cluster should be still up" {
assert_cluster_state ok
}
test "Killing one master node" {
kill_instance redis 0
}
# Note: the only slave of instance 0 is already down so no
# failover is possible, that would change the state back to ok.
test "Cluster should be down now" {
assert_cluster_state fail
}
test "Restarting master node" {
restart_instance redis 0
}
test "Cluster should be up again" {
assert_cluster_state ok
}
+35
View File
@@ -0,0 +1,35 @@
# Check the basic monitoring and failover capabilities.
source "../tests/includes/init-tests.tcl"
test "Create a 5 nodes cluster" {
create_cluster 5 5
}
test "Cluster is up" {
assert_cluster_state ok
}
test "Cluster is writable" {
cluster_write_test 0
}
test "Instance #5 is a slave" {
assert {[RI 5 role] eq {slave}}
}
test "Killing one master node" {
kill_instance redis 0
}
test "Cluster should eventually be up again" {
assert_cluster_state ok
}
test "Cluster is writable" {
cluster_write_test 1
}
test "Instance #5 is now a master" {
assert {[RI 5 role] eq {master}}
}
@@ -0,0 +1,54 @@
# Initialization tests -- most units will start including this.
test "(init) Restart killed instances" {
foreach type {redis} {
foreach_${type}_id id {
if {[get_instance_attrib $type $id pid] == -1} {
puts -nonewline "$type/$id "
flush stdout
restart_instance $type $id
}
}
}
}
test "Cluster nodes are reachable" {
foreach_redis_id id {
# Every node should just know itself.
assert {[R $id ping] eq {PONG}}
}
}
test "Cluster nodes hard reset" {
foreach_redis_id id {
catch {R $id flushall} ; # May fail for readonly slaves.
R $id cluster reset hard
R $id config set cluster-node-timeout 3000
}
}
test "Cluster Join and auto-discovery test" {
# Join node 0 with 1, 1 with 2, ... and so forth.
# If auto-discovery works all nodes will know every other node
# eventually.
set ids {}
foreach_redis_id id {lappend ids $id}
for {set j 0} {$j < [expr [llength $ids]-1]} {incr j} {
set a [lindex $ids $j]
set b [lindex $ids [expr $j+1]]
set b_port [get_instance_attrib redis $b port]
R $a cluster meet 127.0.0.1 $b_port
}
foreach_redis_id id {
wait_for_condition 1000 50 {
[llength [get_cluster_nodes $id]] == [llength $ids]
} else {
fail "Cluster failed to join into a full mesh."
}
}
}
test "Before slots allocation, all nodes report cluster failure" {
assert_cluster_state fail
}
+26 -28
View File
@@ -1,14 +1,19 @@
# Sentinel test suite. Copyright (C) 2014 Salvatore Sanfilippo antirez@gmail.com
# Multi-instance test framework.
# This is used in order to test Sentinel and Redis Cluster, and provides
# basic capabilities for spawning and handling N parallel Redis / Sentinel
# instances.
#
# Copyright (C) 2014 Salvatore Sanfilippo antirez@gmail.com
# This softare is released under the BSD License. See the COPYING file for
# more information.
package require Tcl 8.5
set tcl_precision 17
source tests/support/redis.tcl
source tests/support/util.tcl
source tests/support/server.tcl
source tests/support/test.tcl
source ../support/redis.tcl
source ../support/util.tcl
source ../support/server.tcl
source ../support/test.tcl
set ::verbose 0
set ::pause_on_error 0
@@ -17,45 +22,50 @@ set ::sentinel_instances {}
set ::redis_instances {}
set ::sentinel_base_port 20000
set ::redis_base_port 30000
set ::instances_count 5 ; # How many Sentinels / Instances we use at max
set ::pids {} ; # We kill everything at exit
set ::dirs {} ; # We remove all the temp dirs at exit
set ::run_matching {} ; # If non empty, only tests matching pattern are run.
if {[catch {cd tests/sentinel-tmp}]} {
puts "tests/sentinel-tmp directory not found."
if {[catch {cd tmp}]} {
puts "tmp directory not found."
puts "Please run this test from the Redis source root."
exit 1
}
# Spawn a redis or sentinel instance, depending on 'type'.
proc spawn_instance {type base_port count} {
proc spawn_instance {type base_port count {conf {}}} {
for {set j 0} {$j < $count} {incr j} {
set port [find_available_port $base_port]
incr base_port
puts "Starting $type #$j at port $port"
# Create a directory for this Sentinel.
# Create a directory for this instance.
set dirname "${type}_${j}"
lappend ::dirs $dirname
catch {exec rm -rf $dirname}
file mkdir $dirname
# Write the Sentinel config file.
# Write the instance config file.
set cfgfile [file join $dirname $type.conf]
set cfg [open $cfgfile w]
puts $cfg "port $port"
puts $cfg "dir ./$dirname"
puts $cfg "logfile log.txt"
# Add additional config files
foreach directive $conf {
puts $cfg $directive
}
close $cfg
# Finally exec it and remember the pid for later cleanup.
if {$type eq "redis"} {
set prgname redis-server
} else {
} elseif {$type eq "sentinel"} {
set prgname redis-sentinel
} else {
error "Unknown instance type."
}
set pid [exec ../../src/${prgname} $cfgfile &]
set pid [exec ../../../src/${prgname} $cfgfile &]
lappend ::pids $pid
# Check availability
@@ -116,14 +126,6 @@ proc parse_options {} {
}
}
proc main {} {
parse_options
spawn_instance sentinel $::sentinel_base_port $::instances_count
spawn_instance redis $::redis_base_port $::instances_count
run_tests
cleanup
}
# If --pause-on-error option was passed at startup this function is called
# on error in order to give the developer a chance to understand more about
# the error condition while the instances are still running.
@@ -218,7 +220,7 @@ proc test {descr code} {
}
proc run_tests {} {
set tests [lsort [glob ../sentinel-tests/*]]
set tests [lsort [glob ../tests/*]]
foreach test $tests {
if {$::run_matching ne {} && [string match $::run_matching $test] == 0} {
continue
@@ -361,7 +363,7 @@ proc kill_instance {type id} {
# Return true of the instance of the specified type/id is killed.
proc instance_is_killed {type id} {
set pid [get_instance_attrib $type $id pid]
return $pid == -1
expr {$pid == -1}
}
# Restart an instance previously killed by kill_instance
@@ -377,7 +379,7 @@ proc restart_instance {type id} {
} else {
set prgname redis-sentinel
}
set pid [exec ../../src/${prgname} $cfgfile &]
set pid [exec ../../../src/${prgname} $cfgfile &]
set_instance_attrib $type $id pid $pid
lappend ::pids $pid
@@ -390,7 +392,3 @@ proc restart_instance {type id} {
set_instance_attrib $type $id link [redis 127.0.0.1 $port]
}
if {[catch main e]} {
puts $::errorInfo
cleanup
}
+16 -1
View File
@@ -91,8 +91,13 @@ tags {"aof"} {
assert_equal 1 [is_alive $srv]
}
test "Fixed AOF: Keyspace should contain values that were parsable" {
test "Fixed AOF: Keyspace should contain values that were parsable" {
set client [redis [dict get $srv host] [dict get $srv port]]
wait_for_condition 50 100 {
[catch {$client ping} e] == 0
} else {
fail "Loading DB is taking too much time."
}
assert_equal "hello" [$client get foo]
assert_equal "" [$client get bar]
}
@@ -112,6 +117,11 @@ tags {"aof"} {
test "AOF+SPOP: Set should have 1 member" {
set client [redis [dict get $srv host] [dict get $srv port]]
wait_for_condition 50 100 {
[catch {$client ping} e] == 0
} else {
fail "Loading DB is taking too much time."
}
assert_equal 1 [$client scard set]
}
}
@@ -130,6 +140,11 @@ tags {"aof"} {
test "AOF+EXPIRE: List should be empty" {
set client [redis [dict get $srv host] [dict get $srv port]]
wait_for_condition 50 100 {
[catch {$client ping} e] == 0
} else {
fail "Loading DB is taking too much time."
}
assert_equal 0 [$client llen list]
}
}
-60
View File
@@ -6,66 +6,6 @@ start_server {tags {"repl"}} {
s -1 role
} {slave}
test {If min-slaves-to-write is honored, write is accepted} {
r config set min-slaves-to-write 1
r config set min-slaves-max-lag 10
r set foo 12345
wait_for_condition 50 100 {
[r -1 get foo] eq {12345}
} else {
fail "Write did not reached slave"
}
}
test {No write if min-slaves-to-write is < attached slaves} {
r config set min-slaves-to-write 2
r config set min-slaves-max-lag 10
catch {r set foo 12345} err
set err
} {NOREPLICAS*}
test {If min-slaves-to-write is honored, write is accepted (again)} {
r config set min-slaves-to-write 1
r config set min-slaves-max-lag 10
r set foo 12345
wait_for_condition 50 100 {
[r -1 get foo] eq {12345}
} else {
fail "Write did not reached slave"
}
}
test {No write if min-slaves-max-lag is > of the slave lag} {
r -1 deferred 1
r config set min-slaves-to-write 1
r config set min-slaves-max-lag 2
r -1 debug sleep 6
assert {[r set foo 12345] eq {OK}}
after 4000
catch {r set foo 12345} err
assert {[r -1 read] eq {OK}}
r -1 deferred 0
set err
} {NOREPLICAS*}
test {min-slaves-to-write is ignored by slaves} {
r config set min-slaves-to-write 1
r config set min-slaves-max-lag 10
r -1 config set min-slaves-to-write 1
r -1 config set min-slaves-max-lag 10
r set foo aaabbb
wait_for_condition 50 100 {
[r -1 get foo] eq {aaabbb}
} else {
fail "Write did not reached slave"
}
}
# Fix parameters for the next test to work
r config set min-slaves-to-write 0
r -1 config set min-slaves-to-write 0
r flushall
test {MASTER and SLAVE dataset should be identical after complex ops} {
createComplexDataset r 10000
after 500
+21
View File
@@ -0,0 +1,21 @@
# Sentinel test suite. Copyright (C) 2014 Salvatore Sanfilippo antirez@gmail.com
# This softare is released under the BSD License. See the COPYING file for
# more information.
cd tests/sentinel
source ../instances.tcl
set ::instances_count 5 ; # How many instances we use at max.
proc main {} {
parse_options
spawn_instance sentinel $::sentinel_base_port $::instances_count
spawn_instance redis $::redis_base_port $::instances_count
run_tests
cleanup
}
if {[catch main e]} {
puts $::errorInfo
cleanup
}
@@ -1,6 +1,6 @@
# Check the basic monitoring and failover capabilities.
source "../sentinel-tests/includes/init-tests.tcl"
source "../tests/includes/init-tests.tcl"
if {$::simulate_error} {
test "This test will fail" {
@@ -1,6 +1,6 @@
# Test Sentinel configuration consistency after partitions heal.
source "../sentinel-tests/includes/init-tests.tcl"
source "../tests/includes/init-tests.tcl"
test "We can failover with Sentinel 1 crashed" {
set old_port [RI $master_id tcp_port]
@@ -5,7 +5,7 @@
# 2) That partitioned slaves point to new master when they are partitioned
# away during failover and return at a latter time.
source "../sentinel-tests/includes/init-tests.tcl"
source "../tests/includes/init-tests.tcl"
proc 03_test_slaves_replication {} {
uplevel 1 {
+2
View File
@@ -0,0 +1,2 @@
redis_*
sentinel_*
+303
View File
@@ -0,0 +1,303 @@
# Tcl redis cluster client as a wrapper of redis.rb.
# Copyright (C) 2014 Salvatore Sanfilippo
# Released under the BSD license like Redis itself
#
# Example usage:
#
# set c [redis_cluster 127.0.0.1 6379 127.0.0.1 6380]
# $c set foo
# $c get foo
# $c close
package require Tcl 8.5
package provide redis_cluster 0.1
namespace eval redis_cluster {}
set ::redis_cluster::id 0
array set ::redis_cluster::startup_nodes {}
array set ::redis_cluster::nodes {}
array set ::redis_cluster::slots {}
# List of "plain" commands, which are commands where the sole key is always
# the first argument.
set ::redis_cluster::plain_commands {
get set setnx setex psetex append strlen exists setbit getbit
setrange getrange substr incr decr rpush lpush rpushx lpushx
linsert rpop lpop brpop llen lindex lset lrange ltrim lrem
sadd srem sismember scard spop srandmember smembers sscan zadd
zincrby zrem zremrangebyscore zremrangebyrank zremrangebylex zrange
zrangebyscore zrevrangebyscore zrangebylex zrevrangebylex zcount
zlexcount zrevrange zcard zscore zrank zrevrank zscan hset hsetnx
hget hmset hmget hincrby hincrbyfloat hdel hlen hkeys hvals
hgetall hexists hscan incrby decrby incrbyfloat getset move
expire expireat pexpire pexpireat type ttl pttl persist restore
dump bitcount bitpos pfadd pfcount
}
proc redis_cluster {nodes} {
set id [incr ::redis_cluster::id]
set ::redis_cluster::startup_nodes($id) $nodes
set ::redis_cluster::nodes($id) {}
set ::redis_cluster::slots($id) {}
set handle [interp alias {} ::redis_cluster::instance$id {} ::redis_cluster::__dispatch__ $id]
$handle refresh_nodes_map
return $handle
}
# Totally reset the slots / nodes state for the client, calls
# CLUSTER NODES in the first startup node available, populates the
# list of nodes ::redis_cluster::nodes($id) with an hash mapping node
# ip:port to a representation of the node (another hash), and finally
# maps ::redis_cluster::slots($id) with an hash mapping slot numbers
# to node IDs.
#
# This function is called when a new Redis Cluster client is initialized
# and every time we get a -MOVED redirection error.
proc ::redis_cluster::__method__refresh_nodes_map {id} {
# Contact the first responding startup node.
set idx 0; # Index of the node that will respond.
set errmsg {}
foreach start_node $::redis_cluster::startup_nodes($id) {
lassign [split $start_node :] start_host start_port
if {[catch {
set r {}
set r [redis $start_host $start_port]
set nodes_descr [$r cluster nodes]
$r close
} e]} {
if {$r ne {}} {catch {$r close}}
incr idx
if {[string length $errmsg] < 200} {
append errmsg " $start_node: $e"
}
continue ; # Try next.
} else {
break; # Good node found.
}
}
if {$idx == [llength $::redis_cluster::startup_nodes($id)]} {
error "No good startup node found. $errmsg"
}
# Put the node that responded as first in the list if it is not
# already the first.
if {$idx != 0} {
set l $::redis_cluster::startup_nodes($id)
set left [lrange $l 0 [expr {$idx-1}]]
set right [lrange $l [expr {$idx+1}] end]
set l [concat [lindex $l $idx] $left $right]
set ::redis_cluster::startup_nodes($id) $l
}
# Parse CLUSTER NODES output to populate the nodes description.
set nodes {} ; # addr -> node description hash.
foreach line [split $nodes_descr "\n"] {
set line [string trim $line]
if {$line eq {}} continue
set args [split $line " "]
lassign $args nodeid addr flags slaveof pingsent pongrecv configepoch linkstate
set slots [lrange $args 8 end]
if {$addr eq {:0}} {
set addr $start_host:$start_port
}
lassign [split $addr :] host port
# Connect to the node
set link {}
catch {set link [redis $host $port]}
# Build this node description as an hash.
set node [dict create \
id $nodeid \
addr $addr \
host $host \
port $port \
flags $flags \
slaveof $slaveof \
slots $slots \
link $link \
]
dict set nodes $addr $node
lappend ::redis_cluster::startup_nodes($id) $addr
}
# Close all the existing links in the old nodes map, and set the new
# map as current.
foreach n $::redis_cluster::nodes($id) {
catch {
[dict get $n link] close
}
}
set ::redis_cluster::nodes($id) $nodes
# Populates the slots -> nodes map.
dict for {addr node} $nodes {
foreach slotrange [dict get $node slots] {
lassign [split $slotrange -] start end
if {$end == {}} {set end $start}
for {set j $start} {$j <= $end} {incr j} {
dict set ::redis_cluster::slots($id) $j $addr
}
}
}
# Only retain unique entries in the startup nodes list
set ::redis_cluster::startup_nodes($id) [lsort -unique $::redis_cluster::startup_nodes($id)]
}
# Free a redis_cluster handle.
proc ::redis_cluster::__method__close {id} {
catch {
set nodes $::redis_cluster::nodes($id)
dict for {addr node} $nodes {
catch {
[dict get $node link] close
}
}
}
catch {unset ::redis_cluster::startup_nodes($id)}
catch {unset ::redis_cluster::nodes($id)}
catch {unset ::redis_cluster::slots($id)}
catch {interp alias {} ::redis_cluster::instance$id {}}
}
proc ::redis_cluster::__dispatch__ {id method args} {
if {[info command ::redis_cluster::__method__$method] eq {}} {
# Get the keys from the command.
set keys [::redis_cluster::get_keys_from_command $method $args]
if {$keys eq {}} {
error "Redis command '$method' is not supported by redis_cluster."
}
# Resolve the keys in the corresponding hash slot they hash to.
set slot [::redis_cluster::get_slot_from_keys $keys]
if {$slot eq {}} {
error "Invalid command: multiple keys not hashing to the same slot."
}
# Get the node mapped to this slot.
set node_addr [dict get $::redis_cluster::slots($id) $slot]
if {$node_addr eq {}} {
error "No mapped node for slot $slot."
}
# Execute the command in the node we think is the slot owner.
set retry 100
while {[incr retry -1]} {
if {$retry < 5} {after 100}
set node [dict get $::redis_cluster::nodes($id) $node_addr]
set link [dict get $node link]
if {[catch {$link $method {*}$args} e]} {
if {$link eq {} || \
[string range $e 0 4] eq {MOVED} || \
[string range $e 0 2] eq {I/O} \
} {
# MOVED redirection.
::redis_cluster::__method__refresh_nodes_map $id
set node_addr [dict get $::redis_cluster::slots($id) $slot]
continue
} elseif {[string range $e 0 2] eq {ASK}} {
# ASK redirection.
set node_addr [lindex $e 2]
continue
} else {
# Non redirecting error.
error $e $::errorInfo $::errorCode
}
} else {
# OK query went fine
return $e
}
}
error "Too many redirections or failures contacting Redis Cluster."
} else {
uplevel 1 [list ::redis_cluster::__method__$method $id] $args
}
}
proc ::redis_cluster::get_keys_from_command {cmd argv} {
set cmd [string tolower $cmd]
# Most Redis commands get just one key as first argument.
if {[lsearch -exact $::redis_cluster::plain_commands $cmd] != -1} {
return [list [lindex $argv 0]]
}
# Special handling for other commands
switch -exact $cmd {
mget {return $argv}
}
# All the remaining commands are not handled.
return {}
}
# Returns the CRC16 of the specified string.
# The CRC parameters are described in the Redis Cluster specification.
set ::redis_cluster::XMODEMCRC16Lookup {
0x0000 0x1021 0x2042 0x3063 0x4084 0x50a5 0x60c6 0x70e7
0x8108 0x9129 0xa14a 0xb16b 0xc18c 0xd1ad 0xe1ce 0xf1ef
0x1231 0x0210 0x3273 0x2252 0x52b5 0x4294 0x72f7 0x62d6
0x9339 0x8318 0xb37b 0xa35a 0xd3bd 0xc39c 0xf3ff 0xe3de
0x2462 0x3443 0x0420 0x1401 0x64e6 0x74c7 0x44a4 0x5485
0xa56a 0xb54b 0x8528 0x9509 0xe5ee 0xf5cf 0xc5ac 0xd58d
0x3653 0x2672 0x1611 0x0630 0x76d7 0x66f6 0x5695 0x46b4
0xb75b 0xa77a 0x9719 0x8738 0xf7df 0xe7fe 0xd79d 0xc7bc
0x48c4 0x58e5 0x6886 0x78a7 0x0840 0x1861 0x2802 0x3823
0xc9cc 0xd9ed 0xe98e 0xf9af 0x8948 0x9969 0xa90a 0xb92b
0x5af5 0x4ad4 0x7ab7 0x6a96 0x1a71 0x0a50 0x3a33 0x2a12
0xdbfd 0xcbdc 0xfbbf 0xeb9e 0x9b79 0x8b58 0xbb3b 0xab1a
0x6ca6 0x7c87 0x4ce4 0x5cc5 0x2c22 0x3c03 0x0c60 0x1c41
0xedae 0xfd8f 0xcdec 0xddcd 0xad2a 0xbd0b 0x8d68 0x9d49
0x7e97 0x6eb6 0x5ed5 0x4ef4 0x3e13 0x2e32 0x1e51 0x0e70
0xff9f 0xefbe 0xdfdd 0xcffc 0xbf1b 0xaf3a 0x9f59 0x8f78
0x9188 0x81a9 0xb1ca 0xa1eb 0xd10c 0xc12d 0xf14e 0xe16f
0x1080 0x00a1 0x30c2 0x20e3 0x5004 0x4025 0x7046 0x6067
0x83b9 0x9398 0xa3fb 0xb3da 0xc33d 0xd31c 0xe37f 0xf35e
0x02b1 0x1290 0x22f3 0x32d2 0x4235 0x5214 0x6277 0x7256
0xb5ea 0xa5cb 0x95a8 0x8589 0xf56e 0xe54f 0xd52c 0xc50d
0x34e2 0x24c3 0x14a0 0x0481 0x7466 0x6447 0x5424 0x4405
0xa7db 0xb7fa 0x8799 0x97b8 0xe75f 0xf77e 0xc71d 0xd73c
0x26d3 0x36f2 0x0691 0x16b0 0x6657 0x7676 0x4615 0x5634
0xd94c 0xc96d 0xf90e 0xe92f 0x99c8 0x89e9 0xb98a 0xa9ab
0x5844 0x4865 0x7806 0x6827 0x18c0 0x08e1 0x3882 0x28a3
0xcb7d 0xdb5c 0xeb3f 0xfb1e 0x8bf9 0x9bd8 0xabbb 0xbb9a
0x4a75 0x5a54 0x6a37 0x7a16 0x0af1 0x1ad0 0x2ab3 0x3a92
0xfd2e 0xed0f 0xdd6c 0xcd4d 0xbdaa 0xad8b 0x9de8 0x8dc9
0x7c26 0x6c07 0x5c64 0x4c45 0x3ca2 0x2c83 0x1ce0 0x0cc1
0xef1f 0xff3e 0xcf5d 0xdf7c 0xaf9b 0xbfba 0x8fd9 0x9ff8
0x6e17 0x7e36 0x4e55 0x5e74 0x2e93 0x3eb2 0x0ed1 0x1ef0
}
proc ::redis_cluster::crc16 {s} {
set s [encoding convertto ascii $s]
set crc 0
foreach char [split $s {}] {
scan $char %c byte
set crc [expr {(($crc<<8)&0xffff) ^ [lindex $::redis_cluster::XMODEMCRC16Lookup [expr {(($crc>>8)^$byte) & 0xff}]]}]
}
return $crc
}
# Hash a single key returning the slot it belongs to, Implemented hash
# tags as described in the Redis Cluster specification.
proc ::redis_cluster::hash {key} {
# TODO: Handle hash slots.
expr {[::redis_cluster::crc16 $key] & 16383}
}
# Return the slot the specified keys hash to.
# If the keys hash to multiple slots, an empty string is returned to
# signal that the command can't be run in Redis Cluster.
proc ::redis_cluster::get_slot_from_keys {keys} {
set slot {}
foreach k $keys {
set s [::redis_cluster::hash $k]
if {$slot eq {}} {
set slot $s
} elseif {$slot != $s} {
return {} ; # Error
}
}
return $slot
}
+6 -3
View File
@@ -1,5 +1,5 @@
# Tcl clinet library - used by test-redis.tcl script for now
# Copyright (C) 2009 Salvatore Sanfilippo
# Tcl client library - used by the Redis test
# Copyright (C) 2009-2014 Salvatore Sanfilippo
# Released under the BSD license like Redis itself
#
# Example usage:
@@ -170,7 +170,10 @@ proc ::redis::redis_read_reply fd {
- {return -code error [redis_read_line $fd]}
$ {redis_bulk_read $fd}
* {redis_multi_bulk_read $fd}
default {return -code error "Bad protocol, '$type' as reply type byte"}
default {
if {$type eq {}} {return -code error "I/O error reading reply"}
return -code error "Bad protocol, '$type' as reply type byte"
}
}
}
+1 -1
View File
@@ -236,7 +236,7 @@ proc start_server {options {code undefined}} {
# find out the pid
while {![info exists pid]} {
regexp {\[(\d+)\]} [exec cat $stdout] _ pid
regexp {PID:\s(\d+)} [exec cat $stdout] _ pid
after 100
}
+1 -1
View File
@@ -13,6 +13,7 @@ source tests/support/util.tcl
set ::all_tests {
unit/printver
unit/dump
unit/auth
unit/protocol
unit/basic
@@ -44,7 +45,6 @@ set ::all_tests {
unit/introspection
unit/limits
unit/obuf-limits
unit/dump
unit/bitops
unit/memefficiency
unit/hyperloglog
+81 -3
View File
@@ -31,12 +31,49 @@ start_server {tags {"dump"}} {
set e {}
catch {r restore foo 0 "..."} e
set e
} {*is busy*}
} {*BUSYKEY*}
test {RESTORE can overwrite an existing key with REPLACE} {
r set foo bar1
set encoded1 [r dump foo]
r set foo bar2
set encoded2 [r dump foo]
r del foo
r restore foo 0 $encoded1
r restore foo 0 $encoded2 replace
r get foo
} {bar2}
test {RESTORE can detect a syntax error for unrecongized options} {
catch {r restore foo 0 "..." invalid-option} e
set e
} {*syntax*}
test {DUMP of non existing key returns nil} {
r dump nonexisting_key
} {}
test {MIGRATE is caching connections} {
# Note, we run this as first test so that the connection cache
# is empty.
set first [srv 0 client]
r set key "Some Value"
start_server {tags {"repl"}} {
set second [srv 0 client]
set second_host [srv 0 host]
set second_port [srv 0 port]
assert_match {*migrate_cached_sockets:0*} [r -1 info]
r -1 migrate $second_host $second_port key 9 1000
assert_match {*migrate_cached_sockets:1*} [r -1 info]
}
}
test {MIGRATE cached connections are released after some time} {
after 15000
assert_match {*migrate_cached_sockets:0*} [r info]
}
test {MIGRATE is able to migrate a key between two instances} {
set first [srv 0 client]
r set key "Some Value"
@@ -56,6 +93,47 @@ start_server {tags {"dump"}} {
}
}
test {MIGRATE is able to copy a key between two instances} {
set first [srv 0 client]
r del list
r lpush list a b c d
start_server {tags {"repl"}} {
set second [srv 0 client]
set second_host [srv 0 host]
set second_port [srv 0 port]
assert {[$first exists list] == 1}
assert {[$second exists list] == 0}
set ret [r -1 migrate $second_host $second_port list 9 5000 copy]
assert {$ret eq {OK}}
assert {[$first exists list] == 1}
assert {[$second exists list] == 1}
assert {[$first lrange list 0 -1] eq [$second lrange list 0 -1]}
}
}
test {MIGRATE will not overwrite existing keys, unless REPLACE is used} {
set first [srv 0 client]
r del list
r lpush list a b c d
start_server {tags {"repl"}} {
set second [srv 0 client]
set second_host [srv 0 host]
set second_port [srv 0 port]
assert {[$first exists list] == 1}
assert {[$second exists list] == 0}
$second set list somevalue
catch {r -1 migrate $second_host $second_port list 9 5000 copy} e
assert_match {ERR*} $e
set res [r -1 migrate $second_host $second_port list 9 5000 copy replace]
assert {$ret eq {OK}}
assert {[$first exists list] == 1}
assert {[$second exists list] == 1}
assert {[$first lrange list 0 -1] eq [$second lrange list 0 -1]}
}
}
test {MIGRATE propagates TTL correctly} {
set first [srv 0 client]
r set key "Some Value"
@@ -133,9 +211,9 @@ start_server {tags {"dump"}} {
assert {[$second exists key] == 0}
set rd [redis_deferring_client]
$rd debug sleep 5.0 ; # Make second server unable to reply.
$rd debug sleep 1.0 ; # Make second server unable to reply.
set e {}
catch {r -1 migrate $second_host $second_port key 9 1000} e
catch {r -1 migrate $second_host $second_port key 9 500} e
assert_match {IOERR*} $e
}
}
+26 -41
View File
@@ -40,15 +40,15 @@ start_server {tags {"scripting"}} {
test {EVAL - is Lua able to call Redis API?} {
r set mykey myval
r eval {return redis.call('get',KEYS[1])} 1 mykey
r eval {return redis.call('get','mykey')} 0
} {myval}
test {EVALSHA - Can we call a SHA1 if already defined?} {
r evalsha fd758d1589d044dd850a6f05d52f2eefd27f033f 1 mykey
r evalsha 9bd632c7d33e571e9f24556ebed26c3479a87129 0
} {myval}
test {EVALSHA - Can we call a SHA1 in uppercase?} {
r evalsha FD758D1589D044DD850A6F05D52F2EEFD27F033F 1 mykey
r evalsha 9BD632C7D33E571E9F24556EBED26C3479A87129 0
} {myval}
test {EVALSHA - Do we get an error on invalid SHA1?} {
@@ -175,18 +175,18 @@ start_server {tags {"scripting"}} {
set e {}
r set foo bar
catch {
r eval {redis.call('lpush',KEYS[1],'val')} 1 foo
r eval "redis.call('lpush','foo','val')" 0
} e
set e
} {*against a key*}
test {SCRIPTING FLUSH - is able to clear the scripts cache?} {
r set mykey myval
set v [r evalsha fd758d1589d044dd850a6f05d52f2eefd27f033f 1 mykey]
set v [r evalsha 9bd632c7d33e571e9f24556ebed26c3479a87129 0]
assert_equal $v myval
set e ""
r script flush
catch {r evalsha fd758d1589d044dd850a6f05d52f2eefd27f033f 1 mykey} e
catch {r evalsha 9bd632c7d33e571e9f24556ebed26c3479a87129 0} e
set e
} {NOSCRIPT*}
@@ -204,25 +204,25 @@ start_server {tags {"scripting"}} {
test "In the context of Lua the output of random commands gets ordered" {
r del myset
r sadd myset a b c d e f g h i l m n o p q r s t u v z aa aaa azz
r eval {return redis.call('smembers',KEYS[1])} 1 myset
r eval {return redis.call('smembers','myset')} 0
} {a aa aaa azz b c d e f g h i l m n o p q r s t u v z}
test "SORT is normally not alpha re-ordered for the scripting engine" {
r del myset
r sadd myset 1 2 3 4 10
r eval {return redis.call('sort',KEYS[1],'desc')} 1 myset
r eval {return redis.call('sort','myset','desc')} 0
} {10 4 3 2 1}
test "SORT BY <constant> output gets ordered for scripting" {
r del myset
r sadd myset a b c d e f g h i l m n o p q r s t u v z aa aaa azz
r eval {return redis.call('sort',KEYS[1],'by','_')} 1 myset
r eval {return redis.call('sort','myset','by','_')} 0
} {a aa aaa azz b c d e f g h i l m n o p q r s t u v z}
test "SORT BY <constant> with GET gets ordered for scripting" {
r del myset
r sadd myset a b c
r eval {return redis.call('sort',KEYS[1],'by','_','get','#','get','_:*')} 1 myset
r eval {return redis.call('sort','myset','by','_','get','#','get','_:*')} 0
} {a {} b {} c {}}
test "redis.sha1hex() implementation" {
@@ -300,9 +300,9 @@ start_server {tags {"scripting"}} {
test {EVAL processes writes from AOF in read-only slaves} {
r flushall
r config set appendonly yes
r eval {redis.call("set",KEYS[1],"100")} 1 foo
r eval {redis.call("incr",KEYS[1])} 1 foo
r eval {redis.call("incr",KEYS[1])} 1 foo
r eval {redis.call("set","foo","100")} 0
r eval {redis.call("incr","foo")} 0
r eval {redis.call("incr","foo")} 0
wait_for_condition 50 100 {
[s aof_rewrite_in_progress] == 0
} else {
@@ -339,21 +339,6 @@ start_server {tags {"scripting"}} {
return redis.call('lrange','mylist',0,-1)
} 0
} {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100}
test {Number conversion precision test (issue #1118)} {
r eval {
local value = 9007199254740991
redis.call("set","foo",value)
return redis.call("get","foo")
} 0
} {9007199254740991}
test {String containing number precision test (regression of issue #1118)} {
r eval {
redis.call("set", "key", "12039611435714932082")
return redis.call("get", "key")
} 0
} {12039611435714932082}
}
# Start a new server since the last test in this stanza will kill the
@@ -380,7 +365,7 @@ start_server {tags {"scripting"}} {
test {Timedout scripts that modified data can't be killed by SCRIPT KILL} {
set rd [redis_deferring_client]
r config set lua-time-limit 10
$rd eval {redis.call('set',KEYS[1],'y'); while true do end} 1 x
$rd eval {redis.call('set','x','y'); while true do end} 0
after 200
catch {r ping} e
assert_match {BUSY*} $e
@@ -407,13 +392,13 @@ start_server {tags {"scripting repl"}} {
start_server {} {
test {Before the slave connects we issue two EVAL commands} {
# One with an error, but still executing a command.
# SHA is: 67164fc43fa971f76fd1aaeeaf60c1c178d25876
# SHA is: 6e8bd6bdccbe78899e3cc06b31b6dbf4324c2e56
catch {
r eval {redis.call('incr',KEYS[1]); redis.call('nonexisting')} 1 x
r eval {redis.call('incr','x'); redis.call('nonexisting')} 0
}
# One command is correct:
# SHA is: 6f5ade10a69975e903c6d07b10ea44c6382381a5
r eval {return redis.call('incr',KEYS[1])} 1 x
# SHA is: ae3477e27be955de7e1bc9adfdca626b478d3cb2
r eval {return redis.call('incr','x')} 0
} {2}
test {Connect a slave to the main instance} {
@@ -430,9 +415,9 @@ start_server {tags {"scripting repl"}} {
# The server should replicate successful and unsuccessful
# commands as EVAL instead of EVALSHA.
catch {
r evalsha 67164fc43fa971f76fd1aaeeaf60c1c178d25876 1 x
r evalsha 6e8bd6bdccbe78899e3cc06b31b6dbf4324c2e56 0
}
r evalsha 6f5ade10a69975e903c6d07b10ea44c6382381a5 1 x
r evalsha ae3477e27be955de7e1bc9adfdca626b478d3cb2 0
} {4}
test {If EVALSHA was replicated as EVAL, 'x' should be '4'} {
@@ -447,9 +432,9 @@ start_server {tags {"scripting repl"}} {
set rd [redis_deferring_client]
$rd brpop a 0
r eval {
redis.call("lpush",KEYS[1],"1");
redis.call("lpush",KEYS[1],"2");
} 1 a
redis.call("lpush","a","1");
redis.call("lpush","a","2");
} 0
set res [$rd read]
$rd close
wait_for_condition 50 100 {
@@ -462,9 +447,9 @@ start_server {tags {"scripting repl"}} {
test {EVALSHA replication when first call is readonly} {
r del x
r eval {if tonumber(ARGV[1]) > 0 then redis.call('incr', KEYS[1]) end} 1 x 0
r evalsha 6e0e2745aa546d0b50b801a20983b70710aef3ce 1 x 0
r evalsha 6e0e2745aa546d0b50b801a20983b70710aef3ce 1 x 1
r eval {if tonumber(KEYS[1]) > 0 then redis.call('incr', 'x') end} 1 0
r evalsha 38fe3ddf5284a1d48f37f824b4c4e826879f3cb9 1 0
r evalsha 38fe3ddf5284a1d48f37f824b4c4e826879f3cb9 1 1
wait_for_condition 50 100 {
[r -1 get x] eq {1}
} else {
+3 -3
View File
@@ -154,9 +154,9 @@ start_server {
r zadd zset 10 d
r zadd zset 3 e
r eval {
return {redis.call('sort',KEYS[1],'by','nosort','asc'),
redis.call('sort',KEYS[1],'by','nosort','desc')}
} 1 zset
return {redis.call('sort','zset','by','nosort','asc'),
redis.call('sort','zset','by','nosort','desc')}
} 0
} {{a c e b d} {d b e c a}}
test "SORT sorted set: +inf and -inf handling" {
-23
View File
@@ -408,29 +408,6 @@ start_server {
$rd read
} {}
test "BLPOP when new key is moved into place" {
set rd [redis_deferring_client]
$rd blpop foo 5
r lpush bob abc def hij
r rename bob foo
$rd read
} {foo hij}
test "BLPOP when result key is created by SORT..STORE" {
set rd [redis_deferring_client]
# zero out list from previous test without explicit delete
r lpop foo
r lpop foo
r lpop foo
$rd blpop foo 5
r lpush notfoo hello hola aguacate konichiwa zanzibar
r sort notfoo ALPHA store foo
$rd read
} {foo aguacate}
foreach {pop} {BLPOP BRPOP} {
test "$pop: with single empty list argument" {
set rd [redis_deferring_client]
+13
View File
@@ -0,0 +1,13 @@
The test-lru.rb program can be used in order to check the behavior of the
Redis approximated LRU algorithm against the theoretical output of true
LRU algorithm.
In order to use the program you need to recompile Redis setting the define
REDIS_LRU_CLOCK_RESOLUTION to 1, by editing redis.h.
This allows to execute the program in a fast way since the 1 ms resolution
is enough for all the objects to have a different enough time stamp during
the test.
The program is executed like this:
ruby test-lru.rb > /tmp/lru.html
+112
View File
@@ -0,0 +1,112 @@
require 'rubygems'
require 'redis'
r = Redis.new
r.config("SET","maxmemory","2000000")
r.config("SET","maxmemory-policy","allkeys-lru")
r.config("SET","maxmemory-samples",5)
r.config("RESETSTAT")
r.flushall
puts <<EOF
<html>
<body>
<style>
.box {
width:5px;
height:5px;
float:left;
margin: 1px;
}
.old {
border: 1px black solid;
}
.new {
border: 1px green solid;
}
.ex {
background-color: #666;
}
</style>
<pre>
EOF
# Fill
oldsize = r.dbsize
id = 0
while true
id += 1
r.set(id,"foo")
newsize = r.dbsize
break if newsize == oldsize
oldsize = newsize
end
inserted = r.dbsize
first_set_max_id = id
puts "#{r.dbsize} keys inserted"
# Access keys sequencially
puts "Access keys sequencially"
(1..first_set_max_id).each{|id|
r.get(id)
# sleep 0.001
}
# Insert more 50% keys. We expect that the new keys
half = inserted/2
puts "Insert enough keys to evict half the keys we inserted"
add = 0
while true
add += 1
id += 1
r.set(id,"foo")
break if r.info['evicted_keys'].to_i >= half
end
puts "#{add} additional keys added."
puts "#{r.dbsize} keys in DB"
# Check if evicted keys respect LRU
# We consider errors from 1 to N progressively more serious as they violate
# more the access pattern.
errors = 0
e = 1
edecr = 1.0/(first_set_max_id/2)
(1..(first_set_max_id/2)).each{|id|
e -= edecr if e > 0
e = 0 if e < 0
if r.exists(id)
errors += e
end
}
puts "#{errors} errors!"
puts "</pre>"
# Generate the graphical representation
(1..id).each{|id|
# Mark first set and added items in a different way.
c = "box"
if id <= first_set_max_id
c << " old"
else
c << " new"
end
# Add class if exists
c << " ex" if r.exists(id)
puts "<div class=\"#{c}\"></div>"
}
# Close HTML page
puts <<EOF
</body>
</html>
EOF