diff -Nru redis-3.2.0/00-RELEASENOTES redis-3.2.1/00-RELEASENOTES --- redis-3.2.0/00-RELEASENOTES 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/00-RELEASENOTES 2016-06-17 13:15:21.000000000 +0000 @@ -10,6 +10,527 @@ CRITICAL: There is a critical bug affecting MOST USERS. Upgrade ASAP. -------------------------------------------------------------------------------- + +================================================================================ +Redis 3.2.1 Released Fri Jun 17 15:01:56 CEST 2016 +================================================================================ + +Upgrade urgency HIGH: Critical fix to Redis Sentinel, due to 3.2.0 regression + compared to 3.0. + +Hey, this is Redis 3.2.1, and this release should bring some grain of +maturity to Redis 3.2. The list of commits following this note will tell +you the details, but the main things addressed in this release are the +following: + +1. A critical bug in Sentinel was hopefully fixed. During the big 3.2 + refactoring of Redis Sentinel, in order to implement connection sharing + to make Sentinel able to scale better (few Sentinels to monitor many + masters), a bug was introduced that mis-counted the number of pending + commands in the Redis link. This in turn resulted into an inability to talk + with certain Redis instances. A common result of this bug was the inability + of Redis Sentinel to reconfigure back the old master, after a failover, + when it is reachable again, as the slave of the new master. This was due + to the inability to talk with the old master at all. + +2. BITFIELD bugs fixed. + +3. GEO commands fixes on syntax errors and edge cases. + +4. RESTORE now accepts dumps generated by older Redis versions. + +5. Jemalloc now is really configured to save you memory, for a problem a + change in the jemalloc configuration did not really survived when the + 3.2.0 release was finalized. + +6. TTL and TYPE command no longer alter the last access time of a key, for + LRU evictions purposes. A new TOUCH command was introduced *just* to + update the access time of a key. + +7. A bug was fixed in redis-cli, that connected to the instance running on the + port 6379 if there was one, regardless of what was specified. + +8. TCP keep alive is now enabled by default. This should fix most ghost + connections problems without resulting in any practical change in otherwise + sane deployments. + +9. A Sentinel crash that could happen during failovers was fixed. + +And of course, more minor things that you can read in the detailed log +below. There are still reported bugs for 3.2 that were not fixed in this +release, but nothing critical AFAIK, and I wanted to release this one ASAP, +so likely a new release will not be too far. + +Enjoy, +Salvatore + ++------------------------------------------------------------------------------- +| config set list-max-ziplist-size didn't support negative values, unlike config file +| By oranagra, 2016-05-22 20:35:14 +0300 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/8207e828043e37a0d7e058530d2886bb3ff395ff + + + src/config.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + ++------------------------------------------------------------------------------- +| Fix Sentinel pending commands counting. +| By antirez, 2016-06-16 19:24:34 +0200 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/6ad0371c9b4206a7a6692d50c9a301457baf9b6d + +This bug most experienced effect was an inability of Redis to +reconfigure back old masters to slaves after they are reachable again +after a failover. This was due to failing to reset the count of the +pending commands properly, so the master appeared fovever down. + +Was introduced in Redis 3.2 new Sentinel connection sharing feature +which is a lot more complex than the 3.0 code, but more scalable. + +Many thanks to people reporting the issue, and especially to +@sskorgal for investigating the issue in depth. + +Hopefully closes #3285. + + src/sentinel.c | 1 + + 1 file changed, 1 insertion(+) + ++------------------------------------------------------------------------------- +| redis-cli: really connect to the right server. +| By antirez, 2016-06-16 17:23:31 +0200 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/58f1d446c35e8fe62df7c9ebe10f3c40a386c022 + +I recently introduced populating the autocomplete help array with the +COMMAND command if available. However this was performed before parsing +the arguments, defaulting to instance 6379. After the connection is +performed it remains stable. + +The effect is that if there is an instance running on port 6339, +whatever port you specify is ignored and 6379 is connected to instead. +The right port will be selected only after a reconnection. + +Close #3314. + + src/redis-cli.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + ++------------------------------------------------------------------------------- +| Remove debug printing +| By Jan-Erik Rediger, 2016-05-21 13:50:01 +0200 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/b6007b324b81dbd4ffe519b3bdb19ab65fbb407f + + + src/redis-cli.c | 3 --- + 1 file changed, 3 deletions(-) + ++------------------------------------------------------------------------------- +| RESTORE: accept RDB dumps with older versions. +| By antirez, 2016-06-16 15:53:57 +0200 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/f592b4d3178963878084a522b4fd050772c335ae + +Reference issue #3218. + +Checking the code I can't find a reason why the original RESTORE +code was so opinionated about restoring only the current version. The +code in to `rdb.c` appears to be capable as always to restore data from +older versions of Redis, and the only places where it is needed the +current version in order to correctly restore data, is while loading the +opcodes, not the values itself as it happens in the case of RESTORE. + +For the above reasons, this commit enables RESTORE to accept older +versions of values payloads. + + src/cluster.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + ++------------------------------------------------------------------------------- +| CLIENT error message was out of date +| By oranagra, 2016-05-23 11:42:21 +0300 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/047ced4473ee35485e22e45db8b8b4a272bf1177 + + + src/networking.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + ++------------------------------------------------------------------------------- +| fix georadius returns multiple replies +| By oranagra, 2016-05-23 13:58:50 +0300 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/14e04847ac2960aefe31dccbec63d2503cf09ca5 + + + src/geo.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + ++------------------------------------------------------------------------------- +| Minor aesthetic fixes to PR #3264. +| By antirez, 2016-06-16 12:54:33 +0200 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/bd23ea3f9f3defbbdf512864ee1a88fd02665a7f + +Comment format fixed + local var modified from camel case to underscore +separators as Redis code base normally does (camel case is mostly used +for global symbols like structure names, function names, global vars, +...). + + src/bitops.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + ++------------------------------------------------------------------------------- +| check WRONGTYPE in BITFIELD before looping on the operations. +| By oranagra, 2016-05-24 23:31:36 +0300 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/2a3ee58ec73b6abdeeb4890937b25191119bce35 + +optimization: lookup key only once, and grow at once to the max need +fixes #3259 and #3221, and also an early return if wrongtype is discovered by SET + + src/bitops.c | 27 ++++++++++++++++++--------- + 1 file changed, 18 insertions(+), 9 deletions(-) + ++------------------------------------------------------------------------------- +| fix crash in BITFIELD GET on non existing key or wrong type see #3259 +| By oranagra, 2016-05-24 14:52:43 +0300 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/a2e27b810edfad18b3ecc9c176a4606f94a2f0e4 + +this was a bug in the recent refactoring: bee963c4459223d874e3294a0d8638a588d33c8e + + src/bitops.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + ++------------------------------------------------------------------------------- +| fix check when can't send the command to the promoted slave +| By MOON_CLJ, 2016-05-26 13:10:12 +0800 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/26555f5e008b099b888ef39cabec632f4b31a038 + + + src/sentinel.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + ++------------------------------------------------------------------------------- +| Test TOUCH and new TTL / TYPE behavior about object access time. +| By antirez, 2016-06-15 17:15:18 +0200 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/f1c237cb6a647ad5400b0ebce124fd9802ea7f89 + + + tests/test_helper.tcl | 1 + + tests/unit/introspection-2.tcl | 23 +++++++++++++++++++++++ + 2 files changed, 24 insertions(+) + ++------------------------------------------------------------------------------- +| GETRANGE: return empty string with negative, inverted start/end. +| By antirez, 2016-06-15 12:48:58 +0200 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/d4831e328759bf5bd07c2c6e6ce1d60e84ba196f + + + src/bitops.c | 4 ++-- + src/t_string.c | 4 ++++ + 2 files changed, 6 insertions(+), 2 deletions(-) + ++------------------------------------------------------------------------------- +| Remove additional round brackets from fix for #3282. +| By antirez, 2016-06-15 12:16:39 +0200 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/9942070f5a41fa3bc953e9628a7248aeb7c0befa + + + src/bitops.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + ++------------------------------------------------------------------------------- +| bitcount bug:return non-zero value when start > end (both negative) +| By wenduo, 2016-05-30 16:21:08 +0800 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/f45fa5d05f47a5729786a69962119c9b3dc12645 + + + src/bitops.c | 4 ++++ + 1 file changed, 4 insertions(+) + ++------------------------------------------------------------------------------- +| Regression test for #3282. +| By antirez, 2016-06-15 11:49:49 +0200 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/0cb86064e602a093a23b56943a7321fe1af64984 + + + tests/unit/bitops.tcl | 10 ++++++++++ + 1 file changed, 10 insertions(+) + ++------------------------------------------------------------------------------- +| TTL and TYPE LRU access fixed. TOUCH implemented. +| By antirez, 2016-06-14 15:33:59 +0200 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/b23aa6706ac79a1c86c64aef07bd35e38f10f842 + + + src/db.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++------- + src/server.c | 1 + + src/server.h | 6 +++++- + 3 files changed, 60 insertions(+), 8 deletions(-) + ++------------------------------------------------------------------------------- +| redis-cli help.h updated. +| By antirez, 2016-06-14 14:45:48 +0200 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/6e4204fec9c78f3300d887ebc3db014df2c8b33e + + + src/help.h | 43 +++++++++++++++++++++++++++++-------------- + 1 file changed, 29 insertions(+), 14 deletions(-) + ++------------------------------------------------------------------------------- +| Fix GEORADIUS wrong output with radius > Earth radius. +| By antirez, 2016-05-30 12:45:49 +0200 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/bb43f4cab2f756c0412ca2b94d9e29c3db5025ab + +Close #3266 + + deps/geohash-int/geohash_helper.c | 2 ++ + 1 file changed, 2 insertions(+) + ++------------------------------------------------------------------------------- +| Geo: fix typo in geohashEstimateStepsByRadius(). +| By antirez, 2016-05-30 15:31:19 +0200 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/16102bc0af0912a0c9a92aedddf796eb24a80b9e + +I'm the author of this line but I can't see a good reason for it to +don't be a typo, a step of 26 should be valid with 52 bits per +coordinate, moreover the line was: + + if (step > 26) step = 25; + +So a step of 26 was actually already used, except when one of 27 was +computed (which is invalid) only then it was trimmed to 25 instead of +26. + +All tests passing after the change. + + deps/geohash-int/geohash_helper.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + ++------------------------------------------------------------------------------- +| Avoid undefined behavior in BITFIELD implementation. +| By antirez, 2016-05-31 11:52:07 +0200 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/014bf8044285c6d401d83e6e24829d276ab837f9 + +Probably there is no compiler that will actaully break the code or raise +a signal for unsigned -> signed overflowing conversion, still it was +apparently possible to write it in a more correct way. + +All tests passing. + + src/bitops.c | 23 +++++++++++++++-------- + 1 file changed, 15 insertions(+), 8 deletions(-) + ++------------------------------------------------------------------------------- +| Now that SPOP can be called by scripts use BLPOP on 's' flag test. +| By antirez, 2016-05-31 16:43:21 +0200 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/b4e5e2ec1ad7e9d1f4e7e559b61e0ecd4e50f2da + + + tests/unit/scripting.tcl | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + ++------------------------------------------------------------------------------- +| Test: run GEO tests by default. +| By antirez, 2016-05-31 16:43:49 +0200 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/df419281a19e13429b27814a3e384f6f029c3519 + +Thanks to @oranagra for noticing it was missing. + + tests/test_helper.tcl | 1 + + 1 file changed, 1 insertion(+) + ++------------------------------------------------------------------------------- +| Enable tcp-keepalive by default. +| By antirez, 2016-06-13 12:03:14 +0200 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/40cfe13141c7178d22fd43e4ffbecc37686e0b43 + + + redis.conf | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + ++------------------------------------------------------------------------------- +| fix some compiler warnings +| By Pierre Chapuis, 2016-06-05 15:34:43 +0200 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/a650aaaf4f074ec428b450ef88799db1dcd34b0f + + + src/bitops.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + ++------------------------------------------------------------------------------- +| Fixed typo in Sentinel compareSlavesForPromotion() comment. +| By antirez, 2016-06-10 09:15:01 +0200 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/3fd4baf1e77f125a306d57b788b72de5026c0564 + + + src/sentinel.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + ++------------------------------------------------------------------------------- +| fix comment "b>a" to "a > b" +| By andyli, 2016-06-07 14:42:50 +0800 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/8d029a5950f4ef40723c02b5c486b171aff0189c + + + src/sentinel.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + ++------------------------------------------------------------------------------- +| fix pidfile in redis.conf +| By bogdanvlviv, 2016-04-19 14:43:06 +0300 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/6937f5960d1803ca0eda1ab6f4bc60023f50c914 + + + redis.conf | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + ++------------------------------------------------------------------------------- +| Include 'fd_set' type name +| By jspraul, 2016-06-07 16:46:00 -0400 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/b5758cc5ce6c51ff75c86f9216214fe4d5e4c257 + +Fix an MSYS2-build-breaking error: unknown type name ‘fd_set’ + src/ae_select.c | 1 + + 1 file changed, 1 insertion(+) + ++------------------------------------------------------------------------------- +| Allow SPOP from Lua scripts +| By Itamar Haber, 2016-05-28 20:01:46 +0300 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/620783e3b582e9ba6e1d8fbd47987281ce0b6317 + +The existing `R` flag appears to be sufficient and there's no apparent reason why the command should be blocked. + src/server.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + ++------------------------------------------------------------------------------- +| minor fixes - mainly signalModifiedKey, and GEORADIUS +| By oranagra, 2016-05-09 09:12:38 +0300 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/603234076f4e59967f331bc97de3c0db9947c8ef + + + src/geo.c | 1 + + src/sds.c | 8 ++++---- + src/server.c | 2 +- + src/server.h | 3 +-- + src/t_set.c | 9 ++++++--- + src/t_zset.c | 12 ++++++------ + 6 files changed, 19 insertions(+), 16 deletions(-) + ++------------------------------------------------------------------------------- +| Code to access object string bytes repeated 3x refactored into 1 function. +| By antirez, 2016-05-18 15:35:17 +0200 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/2e6b99499abb5ff1fbeee3bac4d064e5ff4ea256 + + + src/bitops.c | 74 ++++++++++++++++++++++++++++++++---------------------------- + 1 file changed, 39 insertions(+), 35 deletions(-) + ++------------------------------------------------------------------------------- +| fix crash in BITFIELD GET when key is integer encoded +| By oranagra, 2016-05-10 11:19:45 +0300 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/dcaeafc8280eb8329e7ce68e7ab02c67d98f0cf4 + + + src/bitops.c | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + ++------------------------------------------------------------------------------- +| Clarify that the LOG_STR_SIZE includes null term. +| By antirez, 2016-05-18 15:23:18 +0200 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/4ad088818a3353ebd619e8d43847b5d58108af20 + + + src/server.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + ++------------------------------------------------------------------------------- +| Test for BITFIELD regression #3221. +| By antirez, 2016-05-18 14:53:30 +0200 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/f991cdc3e19c187035855355808575efd6b4c149 + + + tests/unit/bitfield.tcl | 5 +++++ + 1 file changed, 5 insertions(+) + ++------------------------------------------------------------------------------- +| reduce struct padding by reordering members +| By oranagra, 2016-05-16 20:12:11 +0300 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/cb3e89e2cb0753d2d111eaeadc9c73cbe24025ab + + + src/quicklist.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + ++------------------------------------------------------------------------------- +| Actually use --with-lg-quantum=3 to build jemalloc. +| By antirez, 2016-05-18 11:58:36 +0200 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/a7f0fb448c110e125eece44dc955d6939e494daa + +This change is documented in deps/README.md but was lost in one way or +the other, neutralizing the benefits of 24 bytes size classes (and +others). + +Close #3208. + + deps/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + ++------------------------------------------------------------------------------- +| redis-cli: integrate help.h with COMMAND output. +| By antirez, 2016-05-07 13:03:25 +0200 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/029dc0d97fd492a2fd579796d4c1cc04053c7190 + +Use the COMMAND output to fill with partial information the built-in +help. This makes redis-cli able to at least complete commands that are +exported by the Redis server it is connected to, but were not available +in the help.h file when the redis-cli binary was compiled. + + src/redis-cli.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 70 insertions(+), 10 deletions(-) + ++------------------------------------------------------------------------------- +| Removed dofile() from Lua +| By Adam Baldwin, 2012-10-25 20:27:10 -0700 ++-------------------------------------------------------------------------------- +https://github.com/antirez/redis/commit/95def3aee044468504bb07633084afd49b085db3 + + + src/scripting.c | 2 ++ + 1 file changed, 2 insertions(+) + + ================================================================================ Redis 3.2.0 Released Fri May 06 08:47:10 CEST 2016 ================================================================================ diff -Nru redis-3.2.0/debian/changelog redis-3.2.1/debian/changelog --- redis-3.2.0/debian/changelog 2016-05-16 09:28:54.000000000 +0000 +++ redis-3.2.1/debian/changelog 2016-06-18 19:13:47.000000000 +0000 @@ -1,3 +1,10 @@ +redis (2:3.2.1-1) unstable; urgency=medium + + * New upstream release. + * Sync debian/redis.conf + + -- Chris Lamb Sat, 18 Jun 2016 20:13:44 +0100 + redis (2:3.2.0-3) unstable; urgency=medium * Skip logging tests as not all architectures support it yet. diff -Nru redis-3.2.0/debian/redis.conf redis-3.2.1/debian/redis.conf --- redis-3.2.0/debian/redis.conf 2016-05-16 09:28:54.000000000 +0000 +++ redis-3.2.1/debian/redis.conf 2016-06-18 19:13:47.000000000 +0000 @@ -117,8 +117,9 @@ # Note that to close the connection the double of the time is needed. # On other kernels the period depends on the kernel configuration. # -# A reasonable value for this option is 60 seconds. -tcp-keepalive 0 +# A reasonable value for this option is 300 seconds, which is the new +# Redis default starting with Redis 3.2.1. +tcp-keepalive 300 ################################# GENERAL ##################################### diff -Nru redis-3.2.0/deps/geohash-int/geohash_helper.c redis-3.2.1/deps/geohash-int/geohash_helper.c --- redis-3.2.0/deps/geohash-int/geohash_helper.c 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/deps/geohash-int/geohash_helper.c 2016-06-17 13:15:21.000000000 +0000 @@ -72,7 +72,7 @@ /* Frame to valid range. */ if (step < 1) step = 1; - if (step > 26) step = 25; + if (step > 26) step = 26; return step; } @@ -89,6 +89,8 @@ lonr = deg_rad(longitude); latr = deg_rad(latitude); + if (radius_meters > EARTH_RADIUS_IN_METERS) + radius_meters = EARTH_RADIUS_IN_METERS; double distance = radius_meters / EARTH_RADIUS_IN_METERS; double min_latitude = latr - distance; double max_latitude = latr + distance; diff -Nru redis-3.2.0/deps/Makefile redis-3.2.1/deps/Makefile --- redis-3.2.0/deps/Makefile 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/deps/Makefile 2016-06-17 13:15:21.000000000 +0000 @@ -78,7 +78,7 @@ jemalloc: .make-prerequisites @printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR) - cd jemalloc && ./configure --with-jemalloc-prefix=je_ --enable-cc-silence CFLAGS="$(JEMALLOC_CFLAGS)" LDFLAGS="$(JEMALLOC_LDFLAGS)" + cd jemalloc && ./configure --with-lg-quantum=3 --with-jemalloc-prefix=je_ --enable-cc-silence CFLAGS="$(JEMALLOC_CFLAGS)" LDFLAGS="$(JEMALLOC_LDFLAGS)" cd jemalloc && $(MAKE) CFLAGS="$(JEMALLOC_CFLAGS)" LDFLAGS="$(JEMALLOC_LDFLAGS)" lib/libjemalloc.a .PHONY: jemalloc diff -Nru redis-3.2.0/redis.conf redis-3.2.1/redis.conf --- redis-3.2.0/redis.conf 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/redis.conf 2016-06-17 13:15:21.000000000 +0000 @@ -117,8 +117,9 @@ # Note that to close the connection the double of the time is needed. # On other kernels the period depends on the kernel configuration. # -# A reasonable value for this option is 60 seconds. -tcp-keepalive 0 +# A reasonable value for this option is 300 seconds, which is the new +# Redis default starting with Redis 3.2.1. +tcp-keepalive 300 ################################# GENERAL ##################################### @@ -146,7 +147,7 @@ # # Creating a pid file is best effort: if Redis is not able to create it # nothing bad happens, the server will start and run normally. -pidfile /var/run/redis.pid +pidfile /var/run/redis_6379.pid # Specify the server verbosity level. # This can be one of: diff -Nru redis-3.2.0/src/ae_select.c redis-3.2.1/src/ae_select.c --- redis-3.2.0/src/ae_select.c 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/src/ae_select.c 2016-06-17 13:15:21.000000000 +0000 @@ -29,6 +29,7 @@ */ +#include #include typedef struct aeApiState { diff -Nru redis-3.2.0/src/bitops.c redis-3.2.1/src/bitops.c --- redis-3.2.0/src/bitops.c 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/src/bitops.c 2016-06-17 13:15:21.000000000 +0000 @@ -215,12 +215,7 @@ } void setSignedBitfield(unsigned char *p, uint64_t offset, uint64_t bits, int64_t value) { - uint64_t uv; - - if (value >= 0) - uv = value; - else - uv = UINT64_MAX + value + 1; + uint64_t uv = value; /* Casting will add UINT64_MAX + 1 if v is negative. */ setUnsignedBitfield(p,offset,bits,uv); } @@ -239,9 +234,21 @@ } int64_t getSignedBitfield(unsigned char *p, uint64_t offset, uint64_t bits) { - int64_t value = getUnsignedBitfield(p,offset,bits); + int64_t value; + union {uint64_t u; int64_t i;} conv; + + /* Converting from unsigned to signed is undefined when the value does + * not fit, however here we assume two's complement and the original value + * was obtained from signed -> unsigned conversion, so we'll find the + * most significant bit set if the original value was negative. + * + * Note that two's complement is mandatory for exact-width types + * according to the C99 standard. */ + conv.u = getUnsignedBitfield(p,offset,bits); + value = conv.i; + /* If the top significant bit is 1, propagate it to all the - * higher bits for two complement representation of signed + * higher bits for two's complement representation of signed * integers. */ if (value & ((uint64_t)1 << (bits-1))) value |= ((uint64_t)-1) << bits; @@ -299,7 +306,7 @@ handle_wrap: { - uint64_t mask = ((int64_t)-1) << bits; + uint64_t mask = ((uint64_t)-1) << bits; uint64_t res = value+incr; res &= ~mask; @@ -342,7 +349,7 @@ handle_wrap: { - uint64_t mask = ((int64_t)-1) << bits; + uint64_t mask = ((uint64_t)-1) << bits; uint64_t msb = (uint64_t)1 << (bits-1); uint64_t a = value, b = incr, c; c = a+b; /* Perform addition as unsigned so that's defined. */ @@ -476,6 +483,37 @@ return o; } +/* Return a pointer to the string object content, and stores its length + * in 'len'. The user is required to pass (likely stack allocated) buffer + * 'llbuf' of at least LONG_STR_SIZE bytes. Such a buffer is used in the case + * the object is integer encoded in order to provide the representation + * without usign heap allocation. + * + * The function returns the pointer to the object array of bytes representing + * the string it contains, that may be a pointer to 'llbuf' or to the + * internal object representation. As a side effect 'len' is filled with + * the length of such buffer. + * + * If the source object is NULL the function is guaranteed to return NULL + * and set 'len' to 0. */ +unsigned char *getObjectReadOnlyString(robj *o, long *len, char *llbuf) { + serverAssert(o->type == OBJ_STRING); + unsigned char *p = NULL; + + /* Set the 'p' pointer to the string, that can be just a stack allocated + * array if our string was integer encoded. */ + if (o && o->encoding == OBJ_ENCODING_INT) { + p = (unsigned char*) llbuf; + if (len) *len = ll2string(llbuf,LONG_STR_SIZE,(long)o->ptr); + } else if (o) { + p = (unsigned char*) o->ptr; + if (len) *len = sdslen(o->ptr); + } else { + if (len) *len = 0; + } + return p; +} + /* SETBIT key offset bitvalue */ void setbitCommand(client *c) { robj *o; @@ -721,21 +759,12 @@ robj *o; long start, end, strlen; unsigned char *p; - char llbuf[32]; + char llbuf[LONG_STR_SIZE]; /* Lookup, check for type, and return 0 for non existing keys. */ if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL || checkType(c,o,OBJ_STRING)) return; - - /* Set the 'p' pointer to the string, that can be just a stack allocated - * array if our string was integer encoded. */ - if (o->encoding == OBJ_ENCODING_INT) { - p = (unsigned char*) llbuf; - strlen = ll2string(llbuf,sizeof(llbuf),(long)o->ptr); - } else { - p = (unsigned char*) o->ptr; - strlen = sdslen(o->ptr); - } + p = getObjectReadOnlyString(o,&strlen,llbuf); /* Parse start/end range if any. */ if (c->argc == 4) { @@ -744,6 +773,10 @@ if (getLongFromObjectOrReply(c,c->argv[3],&end,NULL) != C_OK) return; /* Convert negative indexes */ + if (start < 0 && end < 0 && start > end) { + addReply(c,shared.czero); + return; + } if (start < 0) start = strlen+start; if (end < 0) end = strlen+end; if (start < 0) start = 0; @@ -775,7 +808,7 @@ robj *o; long bit, start, end, strlen; unsigned char *p; - char llbuf[32]; + char llbuf[LONG_STR_SIZE]; int end_given = 0; /* Parse the bit argument to understand what we are looking for, set @@ -795,16 +828,7 @@ return; } if (checkType(c,o,OBJ_STRING)) return; - - /* Set the 'p' pointer to the string, that can be just a stack allocated - * array if our string was integer encoded. */ - if (o->encoding == OBJ_ENCODING_INT) { - p = (unsigned char*) llbuf; - strlen = ll2string(llbuf,sizeof(llbuf),(long)o->ptr); - } else { - p = (unsigned char*) o->ptr; - strlen = sdslen(o->ptr); - } + p = getObjectReadOnlyString(o,&strlen,llbuf); /* Parse start/end range if any. */ if (c->argc == 4 || c->argc == 5) { @@ -882,6 +906,8 @@ int j, numops = 0, changes = 0; struct bitfieldOp *ops = NULL; /* Array of ops to execute at end. */ int owtype = BFOVERFLOW_WRAP; /* Overflow type. */ + int readonly = 1; + long higest_write_offset = 0; for (j = 2; j < c->argc; j++) { int remargs = c->argc-j-1; /* Remaining args other than current. */ @@ -929,8 +955,10 @@ return; } - /* INCRBY and SET require another argument. */ if (opcode != BITFIELDOP_GET) { + readonly = 0; + higest_write_offset = bitoffset + bits - 1; + /* INCRBY and SET require another argument. */ if (getLongLongFromObjectOrReply(c,c->argv[j+3],&i64,NULL) != C_OK){ zfree(ops); return; @@ -950,6 +978,18 @@ j += 3 - (opcode == BITFIELDOP_GET); } + if (readonly) { + /* Lookup for read is ok if key doesn't exit, but errors + * if it's not a string. */ + o = lookupKeyRead(c->db,c->argv[1]); + if (o != NULL && checkType(c,o,OBJ_STRING)) return; + } else { + /* Lookup by making room up to the farest bit reached by + * this operation. */ + if ((o = lookupStringForBitCommand(c, + higest_write_offset)) == NULL) return; + } + addReplyMultiBulkLen(c,numops); /* Actually process the operations. */ @@ -964,11 +1004,6 @@ * for simplicity. SET return value is the previous value so * we need fetch & store as well. */ - /* Lookup by making room up to the farest bit reached by - * this operation. */ - if ((o = lookupStringForBitCommand(c, - thisop->offset + (thisop->bits-1))) == NULL) return; - /* We need two different but very similar code paths for signed * and unsigned operations, since the set of functions to get/set * the integers and the used variables types are different. */ @@ -1035,20 +1070,23 @@ changes++; } else { /* GET */ - o = lookupKeyRead(c->db,c->argv[1]); - size_t olen = (o == NULL) ? 0 : sdslen(o->ptr); unsigned char buf[9]; + long strlen = 0; + unsigned char *src = NULL; + char llbuf[LONG_STR_SIZE]; + + if (o != NULL) + src = getObjectReadOnlyString(o,&strlen,llbuf); /* For GET we use a trick: before executing the operation * copy up to 9 bytes to a local buffer, so that we can easily * execute up to 64 bit operations that are at actual string * object boundaries. */ memset(buf,0,9); - unsigned char *src = o ? o->ptr : NULL; int i; size_t byte = thisop->offset >> 3; for (i = 0; i < 9; i++) { - if (src == NULL || i+byte >= olen) break; + if (src == NULL || i+byte >= (size_t)strlen) break; buf[i] = src[i+byte]; } diff -Nru redis-3.2.0/src/cluster.c redis-3.2.1/src/cluster.c --- redis-3.2.0/src/cluster.c 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/src/cluster.c 2016-06-17 13:15:21.000000000 +0000 @@ -4437,7 +4437,7 @@ /* Verify RDB version */ rdbver = (footer[1] << 8) | footer[0]; - if (rdbver != RDB_VERSION) return C_ERR; + if (rdbver > RDB_VERSION) return C_ERR; /* Verify CRC64 */ crc = crc64(0,p,len-8); diff -Nru redis-3.2.0/src/config.c redis-3.2.1/src/config.c --- redis-3.2.0/src/config.c 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/src/config.c 2016-06-17 13:15:21.000000000 +0000 @@ -682,7 +682,7 @@ #define config_set_numerical_field(_name,_var,min,max) \ } else if (!strcasecmp(c->argv[2]->ptr,_name)) { \ - if (getLongLongFromObject(o,&ll) == C_ERR || ll < 0) goto badfmt; \ + if (getLongLongFromObject(o,&ll) == C_ERR) goto badfmt; \ if (min != LLONG_MIN && ll < min) goto badfmt; \ if (max != LLONG_MAX && ll > max) goto badfmt; \ _var = ll; @@ -902,9 +902,9 @@ } config_set_numerical_field( "hash-max-ziplist-value",server.hash_max_ziplist_value,0,LLONG_MAX) { } config_set_numerical_field( - "list-max-ziplist-size",server.list_max_ziplist_size,0,LLONG_MAX) { + "list-max-ziplist-size",server.list_max_ziplist_size,INT_MIN,INT_MAX) { } config_set_numerical_field( - "list-compress-depth",server.list_compress_depth,0,LLONG_MAX) { + "list-compress-depth",server.list_compress_depth,0,INT_MAX) { } config_set_numerical_field( "set-max-intset-entries",server.set_max_intset_entries,0,LLONG_MAX) { } config_set_numerical_field( diff -Nru redis-3.2.0/src/db.c redis-3.2.1/src/db.c --- redis-3.2.0/src/db.c 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/src/db.c 2016-06-17 13:15:21.000000000 +0000 @@ -41,7 +41,10 @@ * C-level DB API *----------------------------------------------------------------------------*/ -robj *lookupKey(redisDb *db, robj *key) { +/* Low level key lookup API, not actually called directly from commands + * implementations that should instead rely on lookupKeyRead(), + * lookupKeyWrite() and lookupKeyReadWithFlags(). */ +robj *lookupKey(redisDb *db, robj *key, int flags) { dictEntry *de = dictFind(db->dict,key->ptr); if (de) { robj *val = dictGetVal(de); @@ -49,15 +52,40 @@ /* Update the access time for the ageing algorithm. * 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) + if (server.rdb_child_pid == -1 && + server.aof_child_pid == -1 && + !(flags & LOOKUP_NOTOUCH)) + { val->lru = LRU_CLOCK(); + } return val; } else { return NULL; } } -robj *lookupKeyRead(redisDb *db, robj *key) { +/* Lookup a key for read operations, or return NULL if the key is not found + * in the specified DB. + * + * As a side effect of calling this function: + * 1. A key gets expired if it reached it's TTL. + * 2. The key last access time is updated. + * 3. The global keys hits/misses stats are updated (reported in INFO). + * + * This API should not be used when we write to the key after obtaining + * the object linked to the key, but only for read only operations. + * + * Flags change the behavior of this command: + * + * LOOKUP_NONE (or zero): no special flags are passed. + * LOOKUP_NOTOUCH: don't alter the last access time of the key. + * + * Note: this function also returns NULL is the key is logically expired + * but still existing, in case this is a slave, since this API is called only + * for read operations. Even if the key expiry is master-driven, we can + * correctly report a key is expired on slaves even if the master is lagging + * expiring our key via DELs in the replication link. */ +robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) { robj *val; if (expireIfNeeded(db,key) == 1) { @@ -86,7 +114,7 @@ return NULL; } } - val = lookupKey(db,key); + val = lookupKey(db,key,flags); if (val == NULL) server.stat_keyspace_misses++; else @@ -94,9 +122,20 @@ return val; } +/* Like lookupKeyReadWithFlags(), but does not use any flag, which is the + * common case. */ +robj *lookupKeyRead(redisDb *db, robj *key) { + return lookupKeyReadWithFlags(db,key,LOOKUP_NONE); +} + +/* Lookup a key for write operations, and as a side effect, if needed, expires + * the key if its TTL is reached. + * + * Returns the linked value object if the key exists or NULL if the key + * does not exist in the specified DB. */ robj *lookupKeyWrite(redisDb *db, robj *key) { expireIfNeeded(db,key); - return lookupKey(db,key); + return lookupKey(db,key,LOOKUP_NONE); } robj *lookupKeyReadOrReply(client *c, robj *key, robj *reply) { @@ -645,7 +684,7 @@ robj *o; char *type; - o = lookupKeyRead(c->db,c->argv[1]); + o = lookupKeyReadWithFlags(c->db,c->argv[1],LOOKUP_NOTOUCH); if (o == NULL) { type = "none"; } else { @@ -967,7 +1006,7 @@ long long expire, ttl = -1; /* If the key does not exist at all, return -2 */ - if (lookupKeyRead(c->db,c->argv[1]) == NULL) { + if (lookupKeyReadWithFlags(c->db,c->argv[1],LOOKUP_NOTOUCH) == NULL) { addReplyLongLong(c,-2); return; } @@ -1009,6 +1048,14 @@ } } +/* TOUCH key1 [key2 key3 ... keyN] */ +void touchCommand(client *c) { + int touched = 0; + for (int j = 1; j < c->argc; j++) + if (lookupKeyRead(c->db,c->argv[j]) != NULL) touched++; + addReplyLongLong(c,touched); +} + /* ----------------------------------------------------------------------------- * API to get key arguments from commands * ---------------------------------------------------------------------------*/ diff -Nru redis-3.2.0/src/geo.c redis-3.2.1/src/geo.c --- redis-3.2.0/src/geo.c 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/src/geo.c 2016-06-17 13:15:21.000000000 +0000 @@ -156,9 +156,13 @@ return -1; } + if (distance < 0) { + addReplyError(c,"radius cannot be negative"); + return -1; + } + double to_meters = extractUnitOrReply(c,argv[1]); if (to_meters < 0) { - addReplyError(c,"radius cannot be negative"); return -1; } diff -Nru redis-3.2.0/src/help.h redis-3.2.1/src/help.h --- redis-3.2.0/src/help.h 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/src/help.h 2016-06-17 13:15:21.000000000 +0000 @@ -1,4 +1,4 @@ -/* Automatically generated by generate-command-help.rb, do not edit. */ +/* Automatically generated by utils/generate-command-help.rb, do not edit. */ #ifndef __REDIS_HELP_H #define __REDIS_HELP_H @@ -52,6 +52,11 @@ "Count set bits in a string", 1, "2.6.0" }, + { "BITFIELD", + "key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL]", + "Perform arbitrary bitfield integer operations on strings", + 1, + "3.2.0" }, { "BITOP", "operation destkey key [key ...]", "Perform bitwise operations between strings", @@ -83,7 +88,7 @@ 9, "2.6.9" }, { "CLIENT KILL", - "[ip:port] [ID client-id] [TYPE normal|slave|pubsub] [ADDR ip:port] [SKIPME yes/no]", + "[ip:port] [ID client-id] [TYPE normal|master|slave|pubsub] [ADDR ip:port] [SKIPME yes/no]", "Kill the connection of a client", 9, "2.4.0" }, @@ -97,6 +102,11 @@ "Stop processing commands from clients for some time", 9, "2.9.50" }, + { "CLIENT REPLY", + "ON|OFF|SKIP", + "Instruct the server whether to reply to commands", + 9, + "3.2" }, { "CLIENT SETNAME", "connection-name", "Set the current connection name", @@ -179,7 +189,7 @@ "3.0.0" }, { "CLUSTER SETSLOT", "slot IMPORTING|MIGRATING|STABLE|NODE [node-id]", - "Bind an hash slot to a specific node", + "Bind a hash slot to a specific node", 12, "3.0.0" }, { "CLUSTER SLAVES", @@ -321,32 +331,32 @@ "key longitude latitude member [longitude latitude member ...]", "Add one or more geospatial items in the geospatial index represented using a sorted set", 13, - "" }, + "3.2.0" }, { "GEODIST", "key member1 member2 [unit]", "Returns the distance between two members of a geospatial index", 13, - "" }, + "3.2.0" }, { "GEOHASH", "key member [member ...]", "Returns members of a geospatial index as standard geohash strings", 13, - "" }, + "3.2.0" }, { "GEOPOS", "key member [member ...]", "Returns longitude and latitude of members of a geospatial index", 13, - "" }, + "3.2.0" }, { "GEORADIUS", - "key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]", + "key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]", "Query a sorted set representing a geospatial index to fetch members matching a given maximum distance from a point", 13, - "" }, + "3.2.0" }, { "GEORADIUSBYMEMBER", - "key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]", + "key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]", "Query a sorted set representing a geospatial index to fetch members matching a given maximum distance from a member", 13, - "" }, + "3.2.0" }, { "GET", "key", "Get the value of a key", @@ -528,7 +538,7 @@ 1, "1.0.0" }, { "MIGRATE", - "host port key destination-db timeout [COPY] [REPLACE]", + "host port key|"" destination-db timeout [COPY] [REPLACE] [KEYS key]", "Atomically transfer a key from a Redis instance to another one.", 0, "2.6.0" }, @@ -593,7 +603,7 @@ 11, "2.8.9" }, { "PING", - "-", + "[message]", "Ping the server", 8, "1.0.0" }, @@ -707,6 +717,11 @@ "Get the number of members in a set", 3, "1.0.0" }, + { "SCRIPT DEBUG", + "YES|SYNC|NO", + "Set the debug mode for executed scripts.", + 10, + "3.2.0" }, { "SCRIPT EXISTS", "script [script ...]", "Check existence of scripts in the script cache.", @@ -768,7 +783,7 @@ 1, "2.2.0" }, { "SHUTDOWN", - "[NOSAVE] [SAVE]", + "[NOSAVE|SAVE]", "Synchronously save the dataset to disk and then shut down the server", 9, "1.0.0" }, diff -Nru redis-3.2.0/src/networking.c redis-3.2.1/src/networking.c --- redis-3.2.0/src/networking.c 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/src/networking.c 2016-06-17 13:15:21.000000000 +0000 @@ -1632,7 +1632,7 @@ pauseClients(duration); addReply(c,shared.ok); } else { - addReplyError(c, "Syntax error, try CLIENT (LIST | KILL ip:port | GETNAME | SETNAME connection-name)"); + addReplyError(c, "Syntax error, try CLIENT (LIST | KILL | GETNAME | SETNAME | PAUSE | REPLY)"); } } diff -Nru redis-3.2.0/src/quicklist.h redis-3.2.1/src/quicklist.h --- redis-3.2.0/src/quicklist.h 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/src/quicklist.h 2016-06-17 13:15:21.000000000 +0000 @@ -92,8 +92,8 @@ quicklistNode *node; unsigned char *zi; unsigned char *value; - unsigned int sz; long long longval; + unsigned int sz; int offset; } quicklistEntry; diff -Nru redis-3.2.0/src/redis-cli.c redis-3.2.1/src/redis-cli.c --- redis-3.2.0/src/redis-cli.c 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/src/redis-cli.c 2016-06-17 13:15:21.000000000 +0000 @@ -130,6 +130,7 @@ static void slaveMode(void); char *redisGitSHA1(void); char *redisGitDirty(void); +static int cliConnect(int force); /*------------------------------------------------------------------------------ * Utility functions @@ -238,11 +239,11 @@ helpEntry tmp; helpEntriesLen = len = commandslen+groupslen; - helpEntries = malloc(sizeof(helpEntry)*len); + helpEntries = zmalloc(sizeof(helpEntry)*len); for (i = 0; i < groupslen; i++) { tmp.argc = 1; - tmp.argv = malloc(sizeof(sds)); + tmp.argv = zmalloc(sizeof(sds)); tmp.argv[0] = sdscatprintf(sdsempty(),"@%s",commandGroups[i]); tmp.full = tmp.argv[0]; tmp.type = CLI_HELP_GROUP; @@ -259,6 +260,61 @@ } } +/* cliInitHelp() setups the helpEntries array with the command and group + * names from the help.h file. However the Redis instance we are connecting + * to may support more commands, so this function integrates the previous + * entries with additional entries obtained using the COMMAND command + * available in recent versions of Redis. */ +static void cliIntegrateHelp(void) { + if (cliConnect(0) == REDIS_ERR) return; + + redisReply *reply = redisCommand(context, "COMMAND"); + if(reply == NULL || reply->type != REDIS_REPLY_ARRAY) return; + + /* Scan the array reported by COMMAND and fill only the entries that + * don't already match what we have. */ + for (size_t j = 0; j < reply->elements; j++) { + redisReply *entry = reply->element[j]; + char *cmdname = entry->element[0]->str; + int i; + + for (i = 0; i < helpEntriesLen; i++) { + helpEntry *he = helpEntries+i; + if (!strcasecmp(he->argv[0],cmdname)) + break; + } + if (i != helpEntriesLen) continue; + + helpEntriesLen++; + helpEntries = zrealloc(helpEntries,sizeof(helpEntry)*helpEntriesLen); + helpEntry *new = helpEntries+(helpEntriesLen-1); + + new->argc = 1; + new->argv = zmalloc(sizeof(sds)); + new->argv[0] = sdsnew(cmdname); + new->full = new->argv[0]; + new->type = CLI_HELP_COMMAND; + sdstoupper(new->argv[0]); + + struct commandHelp *ch = zmalloc(sizeof(*ch)); + ch->name = new->argv[0]; + ch->params = sdsempty(); + int args = llabs(entry->element[1]->integer); + if (entry->element[3]->integer == 1) { + ch->params = sdscat(ch->params,"key "); + args--; + } + while(args--) ch->params = sdscat(ch->params,"arg "); + if (entry->element[1]->integer < 0) + ch->params = sdscat(ch->params,"...options..."); + ch->summary = "Help not available"; + ch->group = 0; + ch->since = "not known"; + new->org = ch; + } + freeReplyObject(reply); +} + /* Output command help to stdout. */ static void cliOutputCommandHelp(struct commandHelp *help, int group) { printf("\r\n \x1b[1m%s\x1b[0m \x1b[90m%s\x1b[0m\r\n", help->name, help->params); @@ -828,7 +884,7 @@ } /* Setup argument length */ - argvlen = malloc(argc*sizeof(size_t)); + argvlen = zmalloc(argc*sizeof(size_t)); for (j = 0; j < argc; j++) argvlen[j] = sdslen(argv[j]); @@ -851,12 +907,12 @@ printf("Entering slave output mode... (press Ctrl-C to quit)\n"); slaveMode(); config.slave_mode = 0; - free(argvlen); + zfree(argvlen); return REDIS_ERR; /* Error = slaveMode lost connection to master */ } if (cliReadReply(output_raw) != REDIS_OK) { - free(argvlen); + zfree(argvlen); return REDIS_ERR; } else { /* Store database number when SELECT was successfully executed. */ @@ -871,7 +927,7 @@ fflush(stdout); /* Make it grep friendly */ } - free(argvlen); + zfree(argvlen); return REDIS_OK; } @@ -1235,7 +1291,7 @@ if (argv == NULL) { printf("Invalid argument(s)\n"); - free(line); + linenoiseFree(line); continue; } else if (argc > 0) { if (strcasecmp(argv[0],"quit") == 0 || @@ -1294,7 +1350,7 @@ sdsfreesplitres(argv,argc); } /* linenoise() returns malloc-ed lines like readline() */ - free(line); + linenoiseFree(line); } exit(0); } @@ -2159,7 +2215,7 @@ n1 = strchr(p,'\r'); n2 = strchr(p,','); if (n2 && n2 < n1) n1 = n2; - result = malloc(sizeof(char)*(n1-p)+1); + result = zmalloc(sizeof(char)*(n1-p)+1); memcpy(result,p,(n1-p)); result[n1-p] = '\0'; return result; @@ -2173,7 +2229,7 @@ if (!value) return LONG_MIN; l = strtol(value,NULL,10); - free(value); + zfree(value); return l; } @@ -2535,12 +2591,16 @@ else config.output = OUTPUT_STANDARD; config.mb_delim = sdsnew("\n"); - cliInitHelp(); firstarg = parseOptions(argc,argv); argc -= firstarg; argv += firstarg; + /* Initialize the help and, if possible, use the COMMAND command in order + * to retrieve missing entries. */ + cliInitHelp(); + cliIntegrateHelp(); + /* Latency mode */ if (config.latency_mode) { if (cliConnect(0) == REDIS_ERR) exit(1); diff -Nru redis-3.2.0/src/scripting.c redis-3.2.1/src/scripting.c --- redis-3.2.0/src/scripting.c 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/src/scripting.c 2016-06-17 13:15:21.000000000 +0000 @@ -839,6 +839,8 @@ void luaRemoveUnsupportedFunctions(lua_State *lua) { lua_pushnil(lua); lua_setglobal(lua,"loadfile"); + lua_pushnil(lua); + lua_setglobal(lua,"dofile"); } /* This function installs metamethods in the global table _G that prevent diff -Nru redis-3.2.0/src/sds.c redis-3.2.1/src/sds.c --- redis-3.2.0/src/sds.c 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/src/sds.c 2016-06-17 13:15:21.000000000 +0000 @@ -55,13 +55,13 @@ } static inline char sdsReqType(size_t string_size) { - if (string_size < 32) + if (string_size < 1<<5) return SDS_TYPE_5; - if (string_size < 0xff) + if (string_size < 1<<8) return SDS_TYPE_8; - if (string_size < 0xffff) + if (string_size < 1<<16) return SDS_TYPE_16; - if (string_size < 0xffffffff) + if (string_size < 1ll<<32) return SDS_TYPE_32; return SDS_TYPE_64; } diff -Nru redis-3.2.0/src/sentinel.c redis-3.2.1/src/sentinel.c --- redis-3.2.0/src/sentinel.c 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/src/sentinel.c 2016-06-17 13:15:21.000000000 +0000 @@ -1910,6 +1910,7 @@ link->cc->errstr); instanceLinkCloseConnection(link,link->cc); } else { + link->pending_commands = 0; link->cc_conn_time = mstime(); link->cc->data = link; redisAeAttach(server.el,link->cc); @@ -3874,11 +3875,11 @@ return (*sa)->slave_priority - (*sb)->slave_priority; /* If priority is the same, select the slave with greater replication - * offset (processed more data frmo the master). */ + * offset (processed more data from the master). */ if ((*sa)->slave_repl_offset > (*sb)->slave_repl_offset) { return -1; /* a < b */ } else if ((*sa)->slave_repl_offset < (*sb)->slave_repl_offset) { - return 1; /* b > a */ + return 1; /* a > b */ } /* If the replication offset is the same select the slave with that has @@ -3996,7 +3997,7 @@ /* We can't send the command to the promoted slave if it is now * disconnected. Retry again and again with this state until the timeout * is reached, then abort the failover. */ - if (ri->link->disconnected) { + if (ri->promoted_slave->link->disconnected) { if (mstime() - ri->failover_state_change_time > ri->failover_timeout) { sentinelEvent(LL_WARNING,"-failover-abort-slave-timeout",ri,"%@"); sentinelAbortFailover(ri); diff -Nru redis-3.2.0/src/server.c redis-3.2.1/src/server.c --- redis-3.2.0/src/server.c 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/src/server.c 2016-06-17 13:15:21.000000000 +0000 @@ -163,7 +163,7 @@ {"smove",smoveCommand,4,"wF",0,NULL,1,2,1,0,0}, {"sismember",sismemberCommand,3,"rF",0,NULL,1,1,1,0,0}, {"scard",scardCommand,2,"rF",0,NULL,1,1,1,0,0}, - {"spop",spopCommand,-2,"wRsF",0,NULL,1,1,1,0,0}, + {"spop",spopCommand,-2,"wRF",0,NULL,1,1,1,0,0}, {"srandmember",srandmemberCommand,-2,"rR",0,NULL,1,1,1,0,0}, {"sinter",sinterCommand,-2,"rS",0,NULL,1,-1,1,0,0}, {"sinterstore",sinterstoreCommand,-3,"wm",0,NULL,1,-1,1,0,0}, @@ -248,6 +248,7 @@ {"info",infoCommand,-1,"lt",0,NULL,0,0,0,0,0}, {"monitor",monitorCommand,1,"as",0,NULL,0,0,0,0,0}, {"ttl",ttlCommand,2,"rF",0,NULL,1,1,1,0,0}, + {"touch",touchCommand,-2,"rF",0,NULL,1,1,1,0,0}, {"pttl",pttlCommand,2,"rF",0,NULL,1,1,1,0,0}, {"persist",persistCommand,2,"wF",0,NULL,1,1,1,0,0}, {"slaveof",slaveofCommand,3,"ast",0,NULL,0,0,0,0,0}, @@ -663,7 +664,7 @@ size = dictSlots(dict); used = dictSize(dict); - return (size && used && size > DICT_HT_INITIAL_SIZE && + return (size > DICT_HT_INITIAL_SIZE && (used*100/size < HASHTABLE_MIN_FILL)); } diff -Nru redis-3.2.0/src/server.h redis-3.2.1/src/server.h --- redis-3.2.0/src/server.h 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/src/server.h 2016-06-17 13:15:21.000000000 +0000 @@ -157,7 +157,7 @@ #define PROTO_REPLY_CHUNK_BYTES (16*1024) /* 16k output buffer */ #define PROTO_INLINE_MAX_SIZE (1024*64) /* Max size of inline reads */ #define PROTO_MBULK_BIG_ARG (1024*32) -#define LONG_STR_SIZE 21 /* Bytes needed for long -> str */ +#define LONG_STR_SIZE 21 /* Bytes needed for long -> str + '\0' */ #define AOF_AUTOSYNC_BYTES (1024*1024*32) /* fdatasync every 32MB */ /* When configuring the server eventloop, we setup it so that the total number @@ -467,7 +467,7 @@ /* 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. */ + * precomputed value, otherwise we need to resort to a system call. */ #define LRU_CLOCK() ((1000/server.hz <= LRU_CLOCK_RESOLUTION) ? server.lruclock : getLRUClock()) /* Macro used to initialize a Redis object allocated on the stack. @@ -1320,7 +1320,6 @@ void usage(void); void updateDictResizePolicy(void); int htNeedsResize(dict *dict); -void oom(const char *msg); void populateCommandTable(void); void resetCommandTableStats(void); void adjustOpenFilesLimit(void); @@ -1395,11 +1394,14 @@ int expireIfNeeded(redisDb *db, robj *key); long long getExpire(redisDb *db, robj *key); void setExpire(redisDb *db, robj *key, long long when); -robj *lookupKey(redisDb *db, robj *key); +robj *lookupKey(redisDb *db, robj *key, int flags); robj *lookupKeyRead(redisDb *db, robj *key); robj *lookupKeyWrite(redisDb *db, robj *key); robj *lookupKeyReadOrReply(client *c, robj *key, robj *reply); robj *lookupKeyWriteOrReply(client *c, robj *key, robj *reply); +robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags); +#define LOOKUP_NONE 0 +#define LOOKUP_NOTOUCH (1<<0) void dbAdd(redisDb *db, robj *key, robj *val); void dbOverwrite(redisDb *db, robj *key, robj *val); void setKey(redisDb *db, robj *key, robj *val); @@ -1542,6 +1544,7 @@ void pexpireatCommand(client *c); void getsetCommand(client *c); void ttlCommand(client *c); +void touchCommand(client *c); void pttlCommand(client *c); void persistCommand(client *c); void slaveofCommand(client *c); diff -Nru redis-3.2.0/src/t_set.c redis-3.2.1/src/t_set.c --- redis-3.2.0/src/t_set.c 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/src/t_set.c 2016-06-17 13:15:21.000000000 +0000 @@ -359,9 +359,6 @@ dbDelete(c->db,c->argv[1]); notifyKeyspaceEvent(NOTIFY_GENERIC,"del",c->argv[1],c->db->id); } - signalModifiedKey(c->db,c->argv[1]); - signalModifiedKey(c->db,c->argv[2]); - server.dirty++; /* Create the destination set when it doesn't exist */ if (!dstset) { @@ -369,6 +366,10 @@ dbAdd(c->db,c->argv[2],dstset); } + signalModifiedKey(c->db,c->argv[1]); + signalModifiedKey(c->db,c->argv[2]); + server.dirty++; + /* An extra key has changed when ele was successfully added to dstset */ if (setTypeAdd(dstset,ele)) { server.dirty++; @@ -554,6 +555,8 @@ * the alsoPropagate() API. */ decrRefCount(propargv[0]); preventCommandPropagation(c); + signalModifiedKey(c->db,c->argv[1]); + server.dirty++; } void spopCommand(client *c) { diff -Nru redis-3.2.0/src/t_string.c redis-3.2.1/src/t_string.c --- redis-3.2.0/src/t_string.c 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/src/t_string.c 2016-06-17 13:15:21.000000000 +0000 @@ -263,6 +263,10 @@ } /* Convert negative indexes */ + if (start < 0 && end < 0 && start > end) { + addReply(c,shared.emptybulk); + return; + } if (start < 0) start = strlen+start; if (end < 0) end = strlen+end; if (start < 0) start = 0; diff -Nru redis-3.2.0/src/t_zset.c redis-3.2.1/src/t_zset.c --- redis-3.2.0/src/t_zset.c 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/src/t_zset.c 2016-06-17 13:15:21.000000000 +0000 @@ -2148,16 +2148,13 @@ serverPanic("Unknown operator"); } - if (dbDelete(c->db,dstkey)) { - signalModifiedKey(c->db,dstkey); + if (dbDelete(c->db,dstkey)) touched = 1; - server.dirty++; - } if (dstzset->zsl->length) { zsetConvertToZiplistIfNeeded(dstobj,maxelelen); dbAdd(c->db,dstkey,dstobj); addReplyLongLong(c,zsetLength(dstobj)); - if (!touched) signalModifiedKey(c->db,dstkey); + signalModifiedKey(c->db,dstkey); notifyKeyspaceEvent(NOTIFY_ZSET, (op == SET_OP_UNION) ? "zunionstore" : "zinterstore", dstkey,c->db->id); @@ -2165,8 +2162,11 @@ } else { decrRefCount(dstobj); addReply(c,shared.czero); - if (touched) + if (touched) { + signalModifiedKey(c->db,dstkey); notifyKeyspaceEvent(NOTIFY_GENERIC,"del",dstkey,c->db->id); + server.dirty++; + } } zfree(src); } diff -Nru redis-3.2.0/src/version.h redis-3.2.1/src/version.h --- redis-3.2.0/src/version.h 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/src/version.h 2016-06-17 13:15:21.000000000 +0000 @@ -1 +1 @@ -#define REDIS_VERSION "3.2.0" +#define REDIS_VERSION "3.2.1" diff -Nru redis-3.2.0/tests/test_helper.tcl redis-3.2.1/tests/test_helper.tcl --- redis-3.2.0/tests/test_helper.tcl 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/tests/test_helper.tcl 2016-06-17 13:15:21.000000000 +0000 @@ -46,10 +46,12 @@ unit/scripting unit/maxmemory unit/introspection + unit/introspection-2 unit/limits unit/obuf-limits unit/bitops unit/bitfield + unit/geo unit/memefficiency unit/hyperloglog } diff -Nru redis-3.2.0/tests/unit/bitfield.tcl redis-3.2.1/tests/unit/bitfield.tcl --- redis-3.2.0/tests/unit/bitfield.tcl 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/tests/unit/bitfield.tcl 2016-06-17 13:15:21.000000000 +0000 @@ -184,4 +184,9 @@ } } } + + test {BITFIELD regression for #3221} { + r set bits 1 + r bitfield bits get u1 0 + } {0} } diff -Nru redis-3.2.0/tests/unit/bitops.tcl redis-3.2.1/tests/unit/bitops.tcl --- redis-3.2.0/tests/unit/bitops.tcl 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/tests/unit/bitops.tcl 2016-06-17 13:15:21.000000000 +0000 @@ -43,6 +43,16 @@ r bitcount no-key } 0 + test {BITCOUNT returns 0 with out of range indexes} { + r set str "xxxx" + r bitcount str 4 10 + } 0 + + test {BITCOUNT returns 0 with negative indexes where start > end} { + r set str "xxxx" + r bitcount str -6 -7 + } 0 + catch {unset num} foreach vec [list "" "\xaa" "\x00\x00\xff" "foobar" "123"] { incr num diff -Nru redis-3.2.0/tests/unit/introspection-2.tcl redis-3.2.1/tests/unit/introspection-2.tcl --- redis-3.2.0/tests/unit/introspection-2.tcl 1970-01-01 00:00:00.000000000 +0000 +++ redis-3.2.1/tests/unit/introspection-2.tcl 2016-06-17 13:15:21.000000000 +0000 @@ -0,0 +1,23 @@ +start_server {tags {"introspection"}} { + test {TTL and TYPYE do not alter the last access time of a key} { + r set foo bar + after 3000 + r ttl foo + r type foo + assert {[r object idletime foo] >= 2} + } + + test {TOUCH alters the last access time of a key} { + r set foo bar + after 3000 + r touch foo + assert {[r object idletime foo] < 2} + } + + test {TOUCH returns the number of existing keys specified} { + r flushdb + r set key1 1 + r set key2 2 + r touch key0 key1 key2 key3 + } 2 +} diff -Nru redis-3.2.0/tests/unit/scripting.tcl redis-3.2.1/tests/unit/scripting.tcl --- redis-3.2.0/tests/unit/scripting.tcl 2016-05-06 07:11:36.000000000 +0000 +++ redis-3.2.1/tests/unit/scripting.tcl 2016-06-17 13:15:21.000000000 +0000 @@ -142,7 +142,7 @@ test {EVAL - Scripts can't run certain commands} { set e {} - catch {r eval {return redis.pcall('spop','x')} 0} e + catch {r eval {return redis.pcall('blpop','x',0)} 0} e set e } {*not allowed*}