Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1cb6effdc8 | ||
|
|
13e8e53806 | ||
|
|
c9ab43ef7c | ||
|
|
bf50875353 | ||
|
|
8774228cc5 | ||
|
|
ab900303b8 | ||
|
|
7fcca9baef | ||
|
|
41963fe676 | ||
|
|
97d50344c4 | ||
|
|
e39849808c | ||
|
|
84a4f20278 | ||
|
|
5aa2525006 | ||
|
|
7018d27dfe | ||
|
|
d557144ebb | ||
|
|
a309388dff | ||
|
|
55442262e1 | ||
|
|
e3641c8dee | ||
|
|
9ce105add5 | ||
|
|
e084a394a6 | ||
|
|
61c78a5215 | ||
|
|
d067e3342f | ||
|
|
2b0f03e4f2 | ||
|
|
ad949f2329 | ||
|
|
351663bd7b | ||
|
|
d70ac1d105 | ||
|
|
8da9a167e0 | ||
|
|
13546adcb9 | ||
|
|
373facf81c | ||
|
|
29e3ff9bec | ||
|
|
5116130d42 | ||
|
|
3b46cf97de | ||
|
|
f59b4b93d9 | ||
|
|
dd80fedf6f | ||
|
|
697d3abeff | ||
|
|
c9c04b11b9 | ||
|
|
d3b4992450 | ||
|
|
6a33952b8a | ||
|
|
bacb04f89f | ||
|
|
b83f9fea81 | ||
|
|
10dbb5cd33 | ||
|
|
db8a945cbb | ||
|
|
7178cac031 | ||
|
|
33fad43c0f | ||
|
|
af12f8ec3c | ||
|
|
3876d985a8 | ||
|
|
153f2f00ea | ||
|
|
ca532c94ef | ||
|
|
a73503530e | ||
|
|
b917e3fdb3 | ||
|
|
1177cf6395 | ||
|
|
874804da0c | ||
|
|
273cd7ff51 | ||
|
|
389b9f5945 | ||
|
|
1370a88887 | ||
|
|
68aab8e811 | ||
|
|
788e892534 | ||
|
|
77de5c2b71 | ||
|
|
f20f3ead1b | ||
|
|
8c22086c34 | ||
|
|
92958df3b1 | ||
|
|
0ee28ae40c | ||
|
|
289fadb2d0 | ||
|
|
f4f7d2c37f | ||
|
|
f61d6f0c4a | ||
|
|
473640790f | ||
|
|
9ada818b86 | ||
|
|
381651fac0 |
+390
@@ -10,6 +10,385 @@ 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 3.2.11 Released Thu Sep 21 15:47:53 CEST 2017
|
||||
================================================================================
|
||||
|
||||
Upgrade urgency HIGH: Potentially critical bugs fixed.
|
||||
|
||||
AOF flush on SHUTDOWN did not cared to really write the AOF buffers
|
||||
(not in the kernel but in the Redis process memory) to disk before exiting.
|
||||
Calling SHUTDOWN during traffic resulted into not every operation to be
|
||||
persisted on disk.
|
||||
|
||||
Oran Agra (and also Buğra Gedik) in commit 8651e5d5:
|
||||
Flush append only buffers before existing.
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
================================================================================
|
||||
Redis 3.2.10 Released Fri Jul 28 17:49:07 CEST 2017
|
||||
================================================================================
|
||||
|
||||
Upgrade urgency MODERATE: This release contains a number of fixes that are not
|
||||
critical in the general case, but quite important
|
||||
in certain use cases. Upgrading is suggested but not
|
||||
mandatory.
|
||||
|
||||
Dear Redis users,
|
||||
|
||||
while 4.0.1 is already out, this is a maintenance release of Redis 3.2.
|
||||
It fixes several bugs, the most interesting ones are the following:
|
||||
|
||||
1. INFO server.stat_net_output_bytes field was computed in a wrong way, now
|
||||
the output is correct.
|
||||
2. SET with EX/PX options are now propagated correctly in the AOF, using
|
||||
the absolute times.
|
||||
3. CLIENT PAUSE was fixed to prevent eviction of keys, so that master and
|
||||
slave continue to be consistent for the time the pause is active.
|
||||
4. GEORADIUS(BYMEMBER)_RO variants for read-only operations added.
|
||||
5. HyperLogLog sanity detection fixed in an edge case.
|
||||
6. Redis Cluster crash due to mis-handling of hidden node flags fixed.
|
||||
|
||||
If you think you may be affected by the above problems, upgrading is a
|
||||
good idea.
|
||||
|
||||
Have a nice day,
|
||||
Salvatore
|
||||
|
||||
Full history of commits in this release:
|
||||
|
||||
Jan-Erik Rediger in commit bf508753:
|
||||
Check that the whole first argument is a number
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
WuYunlong in commit 8774228c:
|
||||
fix rewrite config: auto-aof-rewrite-min-size
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
Byron Grobe in commit ab900303:
|
||||
Fixed issue #1996 (Missing '-' in help message for redis-benchmark)
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
Jan-Erik Rediger in commit 7fcca9ba:
|
||||
Don't use extended Regexp Syntax
|
||||
1 file changed, 6 insertions(+), 6 deletions(-)
|
||||
|
||||
Leon Chen in commit 41963fe6:
|
||||
fix return wrong value of clusterDelNodeSlots
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
Leon Chen in commit 97d50344:
|
||||
fix mismatch argument
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
liangsijian in commit e3984980:
|
||||
Fix lua ldb command log
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
antirez in commit 84a4f202:
|
||||
Make representClusterNodeFlags() more robust.
|
||||
1 file changed, 17 insertions(+), 16 deletions(-)
|
||||
|
||||
antirez in commit 5aa25250:
|
||||
Fix isHLLObjectOrReply() to handle integer encoded strings.
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
antirez in commit 7018d27d:
|
||||
Fix abort typo in Lua debugger help screen.
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
antirez in commit d557144e:
|
||||
Added GEORADIUS(BYMEMBER)_RO variants for read-only operations.
|
||||
3 files changed, 32 insertions(+), 11 deletions(-)
|
||||
|
||||
Suraj Narkhede in commit a309388d:
|
||||
Fix following issues in blocking commands: 1. brpop last key index, thus checking all keys for slots. 2. Memory leak in clusterRedirectBlockedClientIfNeeded. 3. Remove while loop in clusterRedirectBlockedClientIfNeeded.
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
Suraj Narkhede in commit 55442262:
|
||||
Fix brpop command table entry and redirect blocked clients.
|
||||
2 files changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
antirez in commit e3641c8d:
|
||||
Fix PERSIST expired key resuscitation issue #4048.
|
||||
1 file changed, 4 insertions(+), 7 deletions(-)
|
||||
|
||||
Antonio Mallia in commit 9ce105ad:
|
||||
Removed duplicate 'sys/socket.h' include
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
Zachary Marquez in commit e084a394:
|
||||
Prevent expirations and evictions while paused
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
antirez in commit 61c78a52:
|
||||
Collect fork() timing info only if fork succeeded.
|
||||
1 file changed, 4 insertions(+), 3 deletions(-)
|
||||
|
||||
antirez in commit d067e334:
|
||||
Aesthetic changes to #4068 PR to conform to Redis coding standard.
|
||||
1 file changed, 6 insertions(+), 7 deletions(-)
|
||||
|
||||
xuzhou in commit 2b0f03e4:
|
||||
Optimize set command with ex/px when updating aof.
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
antirez in commit ad949f23:
|
||||
redis-benchmark: add -t hset target.
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
xuzhou in commit 351663bd:
|
||||
Fix set with ex/px option when propagated to aof
|
||||
4 files changed, 36 insertions(+), 1 deletion(-)
|
||||
|
||||
minghang.zmh in commit d70ac1d1:
|
||||
fix server.stat_net_output_bytes calc bug
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
xuchengxuan in commit 8da9a167:
|
||||
Fixed comments of slowlog duration
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
cbgbt in commit 13546adc:
|
||||
cli: Only print elapsed time on OUTPUT_STANDARD
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
Aric Huang in commit 373facf8:
|
||||
(fix) Update create-cluster README
|
||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
Salvatore Sanfilippo in commit 29e3ff9b:
|
||||
Merge pull request #3926 from QuChen88/3.2
|
||||
|
||||
================================================================================
|
||||
Redis 3.2.9 Released Mon May 17 17:35:38 CEST 2017
|
||||
================================================================================
|
||||
|
||||
Upgrade urgency LOW: A few rarely harmful bugs were fixed.
|
||||
|
||||
This release just fixes bugs that are unlikely to cause serious problems
|
||||
so there is no need to update ASAP. Please, see the list of commits
|
||||
for the details on the bugs fixed and credits:
|
||||
|
||||
antirez in commit 3b46cf97:
|
||||
redis-cli --bigkeys: show error when TYPE fails.
|
||||
1 file changed, 7 insertions(+), 2 deletions(-)
|
||||
|
||||
antirez in commit f59b4b93:
|
||||
Fix preprocessor if/else chain broken in order to fix #3927.
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
antirez in commit dd80fedf:
|
||||
Fix zmalloc_get_memory_size() ifdefs to actually use the else branch.
|
||||
1 file changed, 2 deletions(-)
|
||||
|
||||
antirez in commit 697d3abe:
|
||||
Set lua-time-limit default value at safe place.
|
||||
2 files changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
antirez in commit c9c04b11:
|
||||
Fix #3848 by closing the descriptor on error.
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
张文康 in commit d3b49924:
|
||||
update block->free after some diff data are written to the child process
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
antirez in commit 6a33952b:
|
||||
Test: fix, hopefully, false PSYNC failure like in issue #2715.
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
John.Koepi in commit b83f9fea:
|
||||
fix #2883, #2857 pipe fds leak when fork() failed on bg aof rw
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
antirez in commit 10dbb5cd:
|
||||
Don't leak file descriptor on syncWithMaster().
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
================================================================================
|
||||
Redis 3.2.8 Released Sun Feb 12 16:11:18 CET 2017
|
||||
================================================================================
|
||||
|
||||
Upgrade urgency CRITICAL: This release reverts back the Jemalloc upgrade
|
||||
that is believed to potentially cause a server
|
||||
deadlock. A MIGRATE crash is also fixed.
|
||||
|
||||
Two important bug fixes, the first of one is critical:
|
||||
|
||||
1. Apparently Jemalloc 4.4.0 may contain a deadlock under particular
|
||||
conditions. See https://github.com/antirez/redis/issues/3799.
|
||||
We reverted back to the previously used Jemalloc versions and plan
|
||||
to upgrade Jemalloc again after having more info about the
|
||||
cause of the bug.
|
||||
|
||||
2. MIGRATE could crash the server after a socket error. See for reference:
|
||||
https://github.com/antirez/redis/issues/3796.
|
||||
|
||||
List of commits:
|
||||
|
||||
antirez in commit 7178cac:
|
||||
Revert "Jemalloc updated to 4.4.0."
|
||||
150 files changed, 6330 insertions(+), 17245 deletions(-)
|
||||
|
||||
antirez in commit 33fad43:
|
||||
Fix MIGRATE closing of cached socket on error.
|
||||
1 file changed, 23 insertions(+), 6 deletions(-)
|
||||
|
||||
================================================================================
|
||||
Redis 3.2.7 Released Tue Jan 31 16:21:41 CET 2017
|
||||
================================================================================
|
||||
|
||||
Upgrade urgency HIGH: This release fixes important security and correctness
|
||||
issues. It is especially important to upgrade for Redis
|
||||
Cluster users and for users running Redis in their laptop
|
||||
since a cross-scripting attack is fixed in this release.
|
||||
|
||||
Main bugs fixes and improvements in this release:
|
||||
|
||||
1. MIGRATE could incorrectly move keys between Redis Cluster nodes by turning
|
||||
keys with an expire set into persisting keys. This bug was introduced with
|
||||
the multiple-keys migration recently. It is now fixed. Only applies to
|
||||
Redis Cluster users that use the resharding features of Redis Cluster.
|
||||
|
||||
2. As Redis 4.0 beta and the unstable branch already did (for some months at
|
||||
this point), Redis 3.2.7 also aliases the Host: and POST commands to QUIT
|
||||
avoiding to process the remaining pipeline if there are pending commands.
|
||||
This is a security protection against a "Cross Scripting" attack, that
|
||||
usually involves trying to feed Redis with HTTP in order to execute commands.
|
||||
Example: a developer is running a local copy of Redis for development
|
||||
purposes. She also runs a web browser in the same computer. The web browser
|
||||
could send an HTTP request to http://127.0.0.1:6379 in order to access the
|
||||
Redis instance, since a specially crafted HTTP requesta may also be partially
|
||||
valid Redis protocol. However if POST and Host: break the connection, this
|
||||
problem should be avoided. IMPORTANT: It is important to realize that it
|
||||
is not impossible that another way will be found to talk with a localhost
|
||||
Redis using a Cross Protocol attack not involving sending POST or Host: so
|
||||
this is only a layer of protection but not a definitive fix for this class
|
||||
of issues.
|
||||
|
||||
3. A ziplist bug that could cause data corruption, could crash the server and
|
||||
MAY ALSO HAVE SECURITY IMPLICATIONS was fixed. The bug looks complex to
|
||||
exploit, but attacks always get worse, never better (cit). The bug is very
|
||||
very hard to catch in practice, it required manual analysis of the ziplist
|
||||
code in order to be found. However it is also possible that rarely it
|
||||
happened in the wild. Upgrading is required if you use LINSERT and other
|
||||
in-the-middle list manipulation commands.
|
||||
|
||||
4. We upgraded to Jemalloc 4.4.0 since the version we used to ship with Redis
|
||||
was an early 4.0 release of Jemalloc. This version may have several
|
||||
improvements including the ability to better reclaim/use the memory of
|
||||
system.
|
||||
|
||||
The following is the list of commits:
|
||||
|
||||
antirez in commit 3876d98:
|
||||
Ziplist: insertion bug under particular conditions fixed.
|
||||
1 file changed, 9 insertions(+), 1 deletion(-)
|
||||
|
||||
antirez in commit 153f2f0:
|
||||
Jemalloc updated to 4.4.0.
|
||||
150 files changed, 17271 insertions(+), 6356 deletions(-)
|
||||
|
||||
miter in commit ca532c9:
|
||||
Change switch statment to if statment
|
||||
1 file changed, 2 insertions(+), 4 deletions(-)
|
||||
|
||||
oranagra in commit a735035:
|
||||
fix rare assertion in DEBUG DIGEST
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
Itamar Haber in commit b917e3f:
|
||||
Verify pairs are provided after subcommands
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
antirez in commit 1177cf6:
|
||||
Avoid geo.c warning in initialization.
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
antirez in commit 874804d:
|
||||
Security: Cross Protocol Scripting protection.
|
||||
3 files changed, 27 insertions(+), 2 deletions(-)
|
||||
|
||||
antirez in commit 273cd7f:
|
||||
Ziplist: remove static from functions, they prevent good crash reports.
|
||||
1 file changed, 14 insertions(+), 14 deletions(-)
|
||||
|
||||
Jan-Erik Rediger in commit 389b9f5:
|
||||
Initialize help only in repl mode
|
||||
1 file changed, 5 insertions(+), 5 deletions(-)
|
||||
|
||||
Yossi Gottlieb in commit 1370a88:
|
||||
Fix redis-cli rare crash.
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
antirez in commit 68aab8e:
|
||||
MIGRATE: Remove upfront ttl initialization.
|
||||
1 file changed, 3 insertions(+), 4 deletions(-)
|
||||
|
||||
Jan-Erik Rediger in commit 788e892:
|
||||
Reset the ttl for additional keys
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
================================================================================
|
||||
Redis 3.2.6 Released Tue Dec 06 09:33:29 CET 2016
|
||||
================================================================================
|
||||
|
||||
Upgrade urgency MODERATE: GEORADIUS, BITFIELD and Redis Cluster minor fixes.
|
||||
|
||||
This release mainly fixes three bugs:
|
||||
|
||||
1. A bug with BITFIELD that may cause the bitmap corruption when setting offsets
|
||||
larger than the current string size.
|
||||
|
||||
2. A GEORADIUS bug that may happen when using very large radius lengths, in
|
||||
the range of 10000km or alike, due to wrong bounding box calculation.
|
||||
|
||||
3. A bug with Redis Cluster which crashes when reading a nodes configuration
|
||||
file with zero bytes at the end, which sometimes happens with certain ext4
|
||||
configurations after a system crash.
|
||||
|
||||
The following is the list of commits:
|
||||
|
||||
antirez in commit f20f3ea:
|
||||
Geo: improve fuzz test.
|
||||
1 file changed, 11 insertions(+), 3 deletions(-)
|
||||
|
||||
antirez in commit 8c22086:
|
||||
Geo: fix computation of bounding box.
|
||||
2 files changed, 33 insertions(+), 27 deletions(-)
|
||||
|
||||
antirez in commit 92958df:
|
||||
Cluster: handle zero bytes at the end of nodes.conf.
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
antirez in commit 0ee28ae:
|
||||
Test: regression test for #3564 added.
|
||||
1 file changed, 9 insertions(+)
|
||||
|
||||
sunhe in commit 289fadb:
|
||||
bitops.c/bitfieldCommand: update higest_write_offset with check
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
jybaek in commit f4f7d2c:
|
||||
Add missing fclose()
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
================================================================================
|
||||
Redis 3.2.5 Released Wed Oct 26 09:16:40 CEST 2016
|
||||
================================================================================
|
||||
|
||||
Upgrade urgency LOW: This release only fixes a compilation issue due to the
|
||||
missing -ldl at linking time.
|
||||
|
||||
zach shipko in commit 4736407:
|
||||
BSDs don't have -ldl
|
||||
1 file changed, 15 insertions(+), 5 deletions(-)
|
||||
|
||||
antirez in commit 9ada818:
|
||||
Fix modules compilation when libc malloc is used.
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
================================================================================
|
||||
Redis 3.2.4 Released Mon Sep 26 08:58:21 CEST 2016
|
||||
================================================================================
|
||||
@@ -26,14 +405,25 @@ which is documented clearly here:
|
||||
|
||||
Thanks to Cory Duplantis of Cisco Talos for reporting the issue.
|
||||
|
||||
IMPACT:
|
||||
|
||||
The gist is that using CONFIG SET calls (or by manipulating redis.conf)
|
||||
an attacker is able to compromise certain fields of the "server" global
|
||||
structure, including the aof filename pointer, that could be made pointing
|
||||
to something else. In turn the AOF name is used in different contexts such
|
||||
as logging, rename(2) and open(2) syscalls, leading to potential problems.
|
||||
|
||||
Please note that since having access to CONFIG SET also means to be able
|
||||
to change the AOF filename (and many other things) directly, this issue
|
||||
actual real world impact is quite small, so I would not panik: if you
|
||||
have CONFIG SET level of access, you can do more and more easily.
|
||||
|
||||
AFFECTED VERSIONS:
|
||||
|
||||
All Redis 3.2.x versions are affected.
|
||||
|
||||
OTHER CHANGES IN THIS RELEASE:
|
||||
|
||||
This release also includes other things:
|
||||
|
||||
* TCP binding bug fixed when only certain addresses were available for
|
||||
|
||||
Vendored
+9
-26
@@ -80,35 +80,18 @@ uint8_t geohashEstimateStepsByRadius(double range_meters, double lat) {
|
||||
return step;
|
||||
}
|
||||
|
||||
int geohashBitsComparator(const GeoHashBits *a, const GeoHashBits *b) {
|
||||
/* If step not equal, compare on step. Else, compare on bits. */
|
||||
return a->step != b->step ? a->step - b->step : a->bits - b->bits;
|
||||
}
|
||||
|
||||
/* Return the bounding box of the search area centered at latitude,longitude
|
||||
* having a radius of radius_meter. bounds[0] - bounds[2] is the minimum
|
||||
* and maxium longitude, while bounds[1] - bounds[3] is the minimum and
|
||||
* maximum latitude. */
|
||||
int geohashBoundingBox(double longitude, double latitude, double radius_meters,
|
||||
double *bounds) {
|
||||
if (!bounds) return 0;
|
||||
|
||||
double lonr, latr;
|
||||
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;
|
||||
|
||||
/* Note: we're being lazy and not accounting for coordinates near poles */
|
||||
double min_longitude, max_longitude;
|
||||
double difference_longitude = asin(sin(distance) / cos(latr));
|
||||
min_longitude = lonr - difference_longitude;
|
||||
max_longitude = lonr + difference_longitude;
|
||||
|
||||
bounds[0] = rad_deg(min_longitude);
|
||||
bounds[1] = rad_deg(min_latitude);
|
||||
bounds[2] = rad_deg(max_longitude);
|
||||
bounds[3] = rad_deg(max_latitude);
|
||||
bounds[0] = longitude - rad_deg(radius_meters/EARTH_RADIUS_IN_METERS/cos(deg_rad(latitude)));
|
||||
bounds[2] = longitude + rad_deg(radius_meters/EARTH_RADIUS_IN_METERS/cos(deg_rad(latitude)));
|
||||
bounds[1] = latitude - rad_deg(radius_meters/EARTH_RADIUS_IN_METERS);
|
||||
bounds[3] = latitude + rad_deg(radius_meters/EARTH_RADIUS_IN_METERS);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -161,7 +144,7 @@ GeoHashRadius geohashGetAreasByRadius(double longitude, double latitude, double
|
||||
< radius_meters) decrease_step = 1;
|
||||
}
|
||||
|
||||
if (decrease_step) {
|
||||
if (steps > 1 && decrease_step) {
|
||||
steps--;
|
||||
geohashEncode(&long_range,&lat_range,longitude,latitude,steps,&hash);
|
||||
geohashNeighbors(&hash,&neighbors);
|
||||
|
||||
+15
-5
@@ -65,17 +65,27 @@ ifeq ($(uname_S),SunOS)
|
||||
FINAL_LIBS+= -ldl -lnsl -lsocket -lresolv -lpthread -lrt
|
||||
else
|
||||
ifeq ($(uname_S),Darwin)
|
||||
# Darwin (nothing to do)
|
||||
# Darwin
|
||||
FINAL_LIBS+= -ldl
|
||||
else
|
||||
ifeq ($(uname_S),AIX)
|
||||
# AIX
|
||||
FINAL_LDFLAGS+= -Wl,-bexpall
|
||||
FINAL_LIBS+= -pthread -lcrypt -lbsd
|
||||
|
||||
FINAL_LIBS+=-ldl -pthread -lcrypt -lbsd
|
||||
else
|
||||
ifeq ($(uname_S),OpenBSD)
|
||||
# OpenBSD
|
||||
FINAL_LIBS+= -lpthread
|
||||
else
|
||||
ifeq ($(uname_S),FreeBSD)
|
||||
# FreeBSD
|
||||
FINAL_LIBS+= -lpthread
|
||||
else
|
||||
# All the other OSes (notably Linux)
|
||||
FINAL_LDFLAGS+= -rdynamic
|
||||
FINAL_LIBS+= -pthread
|
||||
FINAL_LIBS+=-ldl -pthread
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
@@ -95,7 +105,7 @@ endif
|
||||
ifeq ($(MALLOC),jemalloc)
|
||||
DEPENDENCY_TARGETS+= jemalloc
|
||||
FINAL_CFLAGS+= -DUSE_JEMALLOC -I../deps/jemalloc/include
|
||||
FINAL_LIBS+= ../deps/jemalloc/lib/libjemalloc.a -ldl
|
||||
FINAL_LIBS+= ../deps/jemalloc/lib/libjemalloc.a
|
||||
endif
|
||||
|
||||
REDIS_CC=$(QUIET_CC)$(CC) $(FINAL_CFLAGS)
|
||||
|
||||
+2
-1
@@ -462,7 +462,7 @@ static int anetV6Only(char *err, int s) {
|
||||
|
||||
static int _anetTcpServer(char *err, int port, char *bindaddr, int af, int backlog)
|
||||
{
|
||||
int s, rv;
|
||||
int s = -1, rv;
|
||||
char _port[6]; /* strlen("65535") */
|
||||
struct addrinfo hints, *servinfo, *p;
|
||||
|
||||
@@ -491,6 +491,7 @@ static int _anetTcpServer(char *err, int port, char *bindaddr, int af, int backl
|
||||
}
|
||||
|
||||
error:
|
||||
if (s != -1) close(s);
|
||||
s = ANET_ERR;
|
||||
end:
|
||||
freeaddrinfo(servinfo);
|
||||
|
||||
@@ -115,6 +115,7 @@ void aofChildWriteDiffData(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
if (nwritten <= 0) return;
|
||||
memmove(block->buf,block->buf+nwritten,block->used-nwritten);
|
||||
block->used -= nwritten;
|
||||
block->free += nwritten;
|
||||
}
|
||||
if (block->used == 0) listDelNode(server.aof_rewrite_buf_blocks,ln);
|
||||
}
|
||||
@@ -535,6 +536,22 @@ void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int a
|
||||
buf = catAppendOnlyGenericCommand(buf,3,tmpargv);
|
||||
decrRefCount(tmpargv[0]);
|
||||
buf = catAppendOnlyExpireAtCommand(buf,cmd,argv[1],argv[2]);
|
||||
} else if (cmd->proc == setCommand && argc > 3) {
|
||||
int i;
|
||||
robj *exarg = NULL, *pxarg = NULL;
|
||||
/* Translate SET [EX seconds][PX milliseconds] to SET and PEXPIREAT */
|
||||
buf = catAppendOnlyGenericCommand(buf,3,argv);
|
||||
for (i = 3; i < argc; i ++) {
|
||||
if (!strcasecmp(argv[i]->ptr, "ex")) exarg = argv[i+1];
|
||||
if (!strcasecmp(argv[i]->ptr, "px")) pxarg = argv[i+1];
|
||||
}
|
||||
serverAssert(!(exarg && pxarg));
|
||||
if (exarg)
|
||||
buf = catAppendOnlyExpireAtCommand(buf,server.expireCommand,argv[1],
|
||||
exarg);
|
||||
if (pxarg)
|
||||
buf = catAppendOnlyExpireAtCommand(buf,server.pexpireCommand,argv[1],
|
||||
pxarg);
|
||||
} else {
|
||||
/* All the other commands don't need translation or need the
|
||||
* same translation already operated in the command vector
|
||||
@@ -1295,6 +1312,7 @@ int rewriteAppendOnlyFileBackground(void) {
|
||||
serverLog(LL_WARNING,
|
||||
"Can't rewrite append only file in background: fork: %s",
|
||||
strerror(errno));
|
||||
aofClosePipes();
|
||||
return C_ERR;
|
||||
}
|
||||
serverLog(LL_NOTICE,
|
||||
|
||||
+3
-2
@@ -907,7 +907,7 @@ void bitfieldCommand(client *c) {
|
||||
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;
|
||||
size_t higest_write_offset = 0;
|
||||
|
||||
for (j = 2; j < c->argc; j++) {
|
||||
int remargs = c->argc-j-1; /* Remaining args other than current. */
|
||||
@@ -957,7 +957,8 @@ void bitfieldCommand(client *c) {
|
||||
|
||||
if (opcode != BITFIELDOP_GET) {
|
||||
readonly = 0;
|
||||
higest_write_offset = bitoffset + bits - 1;
|
||||
if (higest_write_offset < bitoffset + bits - 1)
|
||||
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);
|
||||
|
||||
+51
-30
@@ -37,7 +37,6 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <math.h>
|
||||
@@ -129,7 +128,7 @@ int clusterLoadConfig(char *filename) {
|
||||
/* Skip blank lines, they can be created either by users manually
|
||||
* editing nodes.conf or by the config writing process if stopped
|
||||
* before the truncate() call. */
|
||||
if (line[0] == '\n') continue;
|
||||
if (line[0] == '\n' || line[0] == '\0') continue;
|
||||
|
||||
/* Split the line into arguments for processing. */
|
||||
argv = sdssplitargs(line,&argc);
|
||||
@@ -1300,13 +1299,15 @@ void clusterProcessGossipSection(clusterMsg *hdr, clusterLink *link) {
|
||||
clusterNode *node;
|
||||
sds ci;
|
||||
|
||||
ci = representClusterNodeFlags(sdsempty(), flags);
|
||||
serverLog(LL_DEBUG,"GOSSIP %.40s %s:%d %s",
|
||||
g->nodename,
|
||||
g->ip,
|
||||
ntohs(g->port),
|
||||
ci);
|
||||
sdsfree(ci);
|
||||
if (server.verbosity == LL_DEBUG) {
|
||||
ci = representClusterNodeFlags(sdsempty(), flags);
|
||||
serverLog(LL_DEBUG,"GOSSIP %.40s %s:%d %s",
|
||||
g->nodename,
|
||||
g->ip,
|
||||
ntohs(g->port),
|
||||
ci);
|
||||
sdsfree(ci);
|
||||
}
|
||||
|
||||
/* Update our state accordingly to the gossip sections */
|
||||
node = clusterLookupNode(g->nodename);
|
||||
@@ -3440,8 +3441,10 @@ int clusterDelNodeSlots(clusterNode *node) {
|
||||
int deleted = 0, j;
|
||||
|
||||
for (j = 0; j < CLUSTER_SLOTS; j++) {
|
||||
if (clusterNodeGetSlotBit(node,j)) clusterDelSlot(j);
|
||||
deleted++;
|
||||
if (clusterNodeGetSlotBit(node,j)) {
|
||||
clusterDelSlot(j);
|
||||
deleted++;
|
||||
}
|
||||
}
|
||||
return deleted;
|
||||
}
|
||||
@@ -3675,15 +3678,14 @@ static struct redisNodeFlags redisNodeFlagsTable[] = {
|
||||
/* Concatenate the comma separated list of node flags to the given SDS
|
||||
* string 'ci'. */
|
||||
sds representClusterNodeFlags(sds ci, uint16_t flags) {
|
||||
if (flags == 0) {
|
||||
ci = sdscat(ci,"noflags,");
|
||||
} else {
|
||||
int i, size = sizeof(redisNodeFlagsTable)/sizeof(struct redisNodeFlags);
|
||||
for (i = 0; i < size; i++) {
|
||||
struct redisNodeFlags *nodeflag = redisNodeFlagsTable + i;
|
||||
if (flags & nodeflag->flag) ci = sdscat(ci, nodeflag->name);
|
||||
}
|
||||
size_t orig_len = sdslen(ci);
|
||||
int i, size = sizeof(redisNodeFlagsTable)/sizeof(struct redisNodeFlags);
|
||||
for (i = 0; i < size; i++) {
|
||||
struct redisNodeFlags *nodeflag = redisNodeFlagsTable + i;
|
||||
if (flags & nodeflag->flag) ci = sdscat(ci, nodeflag->name);
|
||||
}
|
||||
/* If no flag was added, add the "noflags" special flag. */
|
||||
if (sdslen(ci) == orig_len) ci = sdscat(ci,"noflags,");
|
||||
sdsIncrLen(ci,-1); /* Remove trailing comma. */
|
||||
return ci;
|
||||
}
|
||||
@@ -4007,7 +4009,7 @@ void clusterCommand(client *c) {
|
||||
}
|
||||
if ((n = clusterLookupNode(c->argv[4]->ptr)) == NULL) {
|
||||
addReplyErrorFormat(c,"I don't know about node %s",
|
||||
(char*)c->argv[3]->ptr);
|
||||
(char*)c->argv[4]->ptr);
|
||||
return;
|
||||
}
|
||||
server.cluster->importing_slots_from[slot] = n;
|
||||
@@ -4652,13 +4654,13 @@ void migrateCommand(client *c) {
|
||||
int copy, replace, j;
|
||||
long timeout;
|
||||
long dbid;
|
||||
long long ttl, expireat;
|
||||
robj **ov = NULL; /* Objects to migrate. */
|
||||
robj **kv = NULL; /* Key names. */
|
||||
robj **newargv = NULL; /* Used to rewrite the command as DEL ... keys ... */
|
||||
rio cmd, payload;
|
||||
int may_retry = 1;
|
||||
int write_error = 0;
|
||||
int argv_rewritten = 0;
|
||||
|
||||
/* To support the KEYS option we need the following additional state. */
|
||||
int first_key = 3; /* Argument index of the first key. */
|
||||
@@ -4667,7 +4669,6 @@ void migrateCommand(client *c) {
|
||||
/* Initialization */
|
||||
copy = 0;
|
||||
replace = 0;
|
||||
ttl = 0;
|
||||
|
||||
/* Parse additional options */
|
||||
for (j = 6; j < c->argc; j++) {
|
||||
@@ -4743,7 +4744,9 @@ try_again:
|
||||
|
||||
/* Create RESTORE payload and generate the protocol to call the command. */
|
||||
for (j = 0; j < num_keys; j++) {
|
||||
expireat = getExpire(c->db,kv[j]);
|
||||
long long ttl = 0;
|
||||
long long expireat = getExpire(c->db,kv[j]);
|
||||
|
||||
if (expireat != -1) {
|
||||
ttl = expireat-mstime();
|
||||
if (ttl < 1) ttl = 1;
|
||||
@@ -4841,12 +4844,20 @@ try_again:
|
||||
goto socket_err; /* A retry is guaranteed because of tested conditions.*/
|
||||
}
|
||||
|
||||
/* On socket errors, close the migration socket now that we still have
|
||||
* the original host/port in the ARGV. Later the original command may be
|
||||
* rewritten to DEL and will be too later. */
|
||||
if (socket_error) migrateCloseSocket(c->argv[1],c->argv[2]);
|
||||
|
||||
if (!copy) {
|
||||
/* Translate MIGRATE as DEL for replication/AOF. */
|
||||
/* Translate MIGRATE as DEL for replication/AOF. Note that we do
|
||||
* this only for the keys for which we received an acknowledgement
|
||||
* from the receiving Redis server, by using the del_idx index. */
|
||||
if (del_idx > 1) {
|
||||
newargv[0] = createStringObject("DEL",3);
|
||||
/* Note that the following call takes ownership of newargv. */
|
||||
replaceClientCommandVector(c,del_idx,newargv);
|
||||
argv_rewritten = 1;
|
||||
} else {
|
||||
/* No key transfer acknowledged, no need to rewrite as DEL. */
|
||||
zfree(newargv);
|
||||
@@ -4855,8 +4866,8 @@ try_again:
|
||||
}
|
||||
|
||||
/* If we are here and a socket error happened, we don't want to retry.
|
||||
* Just signal the problem to the client, but only do it if we don't
|
||||
* already queued a different error reported by the destination server. */
|
||||
* Just signal the problem to the client, but only do it if we did not
|
||||
* already queue a different error reported by the destination server. */
|
||||
if (!error_from_target && socket_error) {
|
||||
may_retry = 0;
|
||||
goto socket_err;
|
||||
@@ -4864,7 +4875,11 @@ try_again:
|
||||
|
||||
if (!error_from_target) {
|
||||
/* Success! Update the last_dbid in migrateCachedSocket, so that we can
|
||||
* avoid SELECT the next time if the target DB is the same. Reply +OK. */
|
||||
* avoid SELECT the next time if the target DB is the same. Reply +OK.
|
||||
*
|
||||
* Note: If we reached this point, even if socket_error is true
|
||||
* still the SELECT command succeeded (otherwise the code jumps to
|
||||
* socket_err label. */
|
||||
cs->last_dbid = dbid;
|
||||
addReply(c,shared.ok);
|
||||
} else {
|
||||
@@ -4874,7 +4889,6 @@ try_again:
|
||||
|
||||
sdsfree(cmd.io.buffer.ptr);
|
||||
zfree(ov); zfree(kv); zfree(newargv);
|
||||
if (socket_error) migrateCloseSocket(c->argv[1],c->argv[2]);
|
||||
return;
|
||||
|
||||
/* On socket errors we try to close the cached socket and try again.
|
||||
@@ -4884,7 +4898,12 @@ socket_err:
|
||||
/* Cleanup we want to perform in both the retry and no retry case.
|
||||
* Note: Closing the migrate socket will also force SELECT next time. */
|
||||
sdsfree(cmd.io.buffer.ptr);
|
||||
migrateCloseSocket(c->argv[1],c->argv[2]);
|
||||
|
||||
/* If the command was rewritten as DEL and there was a socket error,
|
||||
* we already closed the socket earlier. While migrateCloseSocket()
|
||||
* is idempotent, the host/port arguments are now gone, so don't do it
|
||||
* again. */
|
||||
if (!argv_rewritten) migrateCloseSocket(c->argv[1],c->argv[2]);
|
||||
zfree(newargv);
|
||||
newargv = NULL; /* This will get reallocated on retry. */
|
||||
|
||||
@@ -5187,8 +5206,9 @@ int clusterRedirectBlockedClientIfNeeded(client *c) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* All keys must belong to the same slot, so check first key only. */
|
||||
di = dictGetIterator(c->bpop.keys);
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
if ((de = dictNext(di)) != NULL) {
|
||||
robj *key = dictGetKey(de);
|
||||
int slot = keyHashSlot((char*)key->ptr, sdslen(key->ptr));
|
||||
clusterNode *node = server.cluster->slots[slot];
|
||||
@@ -5206,6 +5226,7 @@ int clusterRedirectBlockedClientIfNeeded(client *c) {
|
||||
clusterRedirectClient(c,node,slot,
|
||||
CLUSTER_REDIR_MOVED);
|
||||
}
|
||||
dictReleaseIterator(di);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -910,8 +910,6 @@ void configSetCommand(client *c) {
|
||||
"timeout",server.maxidletime,0,LONG_MAX) {
|
||||
} config_set_numerical_field(
|
||||
"auto-aof-rewrite-percentage",server.aof_rewrite_perc,0,LLONG_MAX){
|
||||
} config_set_numerical_field(
|
||||
"auto-aof-rewrite-min-size",server.aof_rewrite_min_size,0,LLONG_MAX) {
|
||||
} config_set_numerical_field(
|
||||
"hash-max-ziplist-entries",server.hash_max_ziplist_entries,0,LLONG_MAX) {
|
||||
} config_set_numerical_field(
|
||||
@@ -986,6 +984,8 @@ void configSetCommand(client *c) {
|
||||
}
|
||||
} config_set_memory_field("repl-backlog-size",ll) {
|
||||
resizeReplicationBacklog(ll);
|
||||
} config_set_memory_field("auto-aof-rewrite-min-size",ll) {
|
||||
server.aof_rewrite_min_size = ll;
|
||||
|
||||
/* Enumeration fields.
|
||||
* config_set_enum_field(name,var,enum_var) */
|
||||
|
||||
@@ -90,7 +90,7 @@ robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
|
||||
|
||||
if (expireIfNeeded(db,key) == 1) {
|
||||
/* Key expired. If we are in the context of a master, expireIfNeeded()
|
||||
* returns 0 only when the key does not exist at all, so it's save
|
||||
* returns 0 only when the key does not exist at all, so it's safe
|
||||
* to return NULL ASAP. */
|
||||
if (server.masterhost == NULL) return NULL;
|
||||
|
||||
@@ -1033,18 +1033,15 @@ void pttlCommand(client *c) {
|
||||
}
|
||||
|
||||
void persistCommand(client *c) {
|
||||
dictEntry *de;
|
||||
|
||||
de = dictFind(c->db->dict,c->argv[1]->ptr);
|
||||
if (de == NULL) {
|
||||
addReply(c,shared.czero);
|
||||
} else {
|
||||
if (lookupKeyWrite(c->db,c->argv[1])) {
|
||||
if (removeExpire(c->db,c->argv[1])) {
|
||||
addReply(c,shared.cone);
|
||||
server.dirty++;
|
||||
} else {
|
||||
addReply(c,shared.czero);
|
||||
}
|
||||
} else {
|
||||
addReply(c,shared.czero);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1234,6 +1231,44 @@ int *migrateGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkey
|
||||
return keys;
|
||||
}
|
||||
|
||||
/* Helper function to extract keys from following commands:
|
||||
* GEORADIUS key x y radius unit [WITHDIST] [WITHHASH] [WITHCOORD] [ASC|DESC]
|
||||
* [COUNT count] [STORE key] [STOREDIST key]
|
||||
* GEORADIUSBYMEMBER key member radius unit ... options ... */
|
||||
int *georadiusGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys) {
|
||||
int i, num, *keys;
|
||||
UNUSED(cmd);
|
||||
|
||||
/* Check for the presence of the stored key in the command */
|
||||
int stored_key = -1;
|
||||
for (i = 5; i < argc; i++) {
|
||||
char *arg = argv[i]->ptr;
|
||||
/* For the case when user specifies both "store" and "storedist" options, the
|
||||
* second key specified would override the first key. This behavior is kept
|
||||
* the same as in georadiusCommand method.
|
||||
*/
|
||||
if ((!strcasecmp(arg, "store") || !strcasecmp(arg, "storedist")) && ((i+1) < argc)) {
|
||||
stored_key = i+1;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
num = 1 + (stored_key == -1 ? 0 : 1);
|
||||
|
||||
/* Keys in the command come from two places:
|
||||
* argv[1] = key,
|
||||
* argv[5...n] = stored key if present
|
||||
*/
|
||||
keys = zmalloc(sizeof(int) * num);
|
||||
|
||||
/* Add all key positions to keys[] */
|
||||
keys[0] = 1;
|
||||
if(num > 1) {
|
||||
keys[1] = stored_key;
|
||||
}
|
||||
*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. */
|
||||
|
||||
+1
-1
@@ -126,7 +126,7 @@ void computeDatasetDigest(unsigned char *final) {
|
||||
redisDb *db = server.db+j;
|
||||
|
||||
if (dictSize(db->dict) == 0) continue;
|
||||
di = dictGetIterator(db->dict);
|
||||
di = dictGetSafeIterator(db->dict);
|
||||
|
||||
/* hash the DB id, so the same dataset moved in a different
|
||||
* DB will lead to a different digest */
|
||||
|
||||
@@ -328,6 +328,7 @@ int membersOfGeoHashBox(robj *zobj, GeoHashBits hash, geoArray *ga, double lon,
|
||||
int membersOfAllNeighbors(robj *zobj, GeoHashRadius n, double lon, double lat, double radius, geoArray *ga) {
|
||||
GeoHashBits neighbors[9];
|
||||
unsigned int i, count = 0, last_processed = 0;
|
||||
int debugmsg = 0;
|
||||
|
||||
neighbors[0] = n.hash;
|
||||
neighbors[1] = n.neighbors.north;
|
||||
@@ -342,8 +343,26 @@ int membersOfAllNeighbors(robj *zobj, GeoHashRadius n, double lon, double lat, d
|
||||
/* For each neighbor (*and* our own hashbox), get all the matching
|
||||
* members and add them to the potential result list. */
|
||||
for (i = 0; i < sizeof(neighbors) / sizeof(*neighbors); i++) {
|
||||
if (HASHISZERO(neighbors[i]))
|
||||
if (HASHISZERO(neighbors[i])) {
|
||||
if (debugmsg) D("neighbors[%d] is zero",i);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Debugging info. */
|
||||
if (debugmsg) {
|
||||
GeoHashRange long_range, lat_range;
|
||||
geohashGetCoordRange(&long_range,&lat_range);
|
||||
GeoHashArea myarea = {{0,0},{0,0},{0,0}};
|
||||
geohashDecode(long_range, lat_range, neighbors[i], &myarea);
|
||||
|
||||
/* Dump center square. */
|
||||
D("neighbors[%d]:\n",i);
|
||||
D("area.longitude.min: %f\n", myarea.longitude.min);
|
||||
D("area.longitude.max: %f\n", myarea.longitude.max);
|
||||
D("area.latitude.min: %f\n", myarea.latitude.min);
|
||||
D("area.latitude.max: %f\n", myarea.latitude.max);
|
||||
D("\n");
|
||||
}
|
||||
|
||||
/* When a huge Radius (in the 5000 km range or more) is used,
|
||||
* adjacent neighbors can be the same, leading to duplicated
|
||||
@@ -352,7 +371,11 @@ int membersOfAllNeighbors(robj *zobj, GeoHashRadius n, double lon, double lat, d
|
||||
if (last_processed &&
|
||||
neighbors[i].bits == neighbors[last_processed].bits &&
|
||||
neighbors[i].step == neighbors[last_processed].step)
|
||||
{
|
||||
if (debugmsg)
|
||||
D("Skipping processing of %d, same as previous\n",i);
|
||||
continue;
|
||||
}
|
||||
count += membersOfGeoHashBox(zobj, neighbors[i], ga, lon, lat, radius);
|
||||
last_processed = i;
|
||||
}
|
||||
@@ -431,13 +454,14 @@ void geoaddCommand(client *c) {
|
||||
#define SORT_ASC 1
|
||||
#define SORT_DESC 2
|
||||
|
||||
#define RADIUS_COORDS 1
|
||||
#define RADIUS_MEMBER 2
|
||||
#define RADIUS_COORDS (1<<0) /* Search around coordinates. */
|
||||
#define RADIUS_MEMBER (1<<1) /* Search around member. */
|
||||
#define RADIUS_NOSTORE (1<<2) /* Do not acceot STORE/STOREDIST option. */
|
||||
|
||||
/* GEORADIUS key x y radius unit [WITHDIST] [WITHHASH] [WITHCOORD] [ASC|DESC]
|
||||
* [COUNT count] [STORE key] [STOREDIST key]
|
||||
* GEORADIUSBYMEMBER key member radius unit ... options ... */
|
||||
void georadiusGeneric(client *c, int type) {
|
||||
void georadiusGeneric(client *c, int flags) {
|
||||
robj *key = c->argv[1];
|
||||
robj *storekey = NULL;
|
||||
int storedist = 0; /* 0 for STORE, 1 for STOREDIST. */
|
||||
@@ -452,11 +476,11 @@ void georadiusGeneric(client *c, int type) {
|
||||
/* Find long/lat to use for radius search based on inquiry type */
|
||||
int base_args;
|
||||
double xy[2] = { 0 };
|
||||
if (type == RADIUS_COORDS) {
|
||||
if (flags & RADIUS_COORDS) {
|
||||
base_args = 6;
|
||||
if (extractLongLatOrReply(c, c->argv + 2, xy) == C_ERR)
|
||||
return;
|
||||
} else if (type == RADIUS_MEMBER) {
|
||||
} else if (flags & RADIUS_MEMBER) {
|
||||
base_args = 5;
|
||||
robj *member = c->argv[2];
|
||||
if (longLatFromMember(zobj, member, xy) == C_ERR) {
|
||||
@@ -464,7 +488,7 @@ void georadiusGeneric(client *c, int type) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
addReplyError(c, "unknown georadius search type");
|
||||
addReplyError(c, "Unknown georadius search type");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -501,11 +525,17 @@ void georadiusGeneric(client *c, int type) {
|
||||
return;
|
||||
}
|
||||
i++;
|
||||
} else if (!strcasecmp(arg, "store") && (i+1) < remaining) {
|
||||
} else if (!strcasecmp(arg, "store") &&
|
||||
(i+1) < remaining &&
|
||||
!(flags & RADIUS_NOSTORE))
|
||||
{
|
||||
storekey = c->argv[base_args+i+1];
|
||||
storedist = 0;
|
||||
i++;
|
||||
} else if (!strcasecmp(arg, "storedist") && (i+1) < remaining) {
|
||||
} else if (!strcasecmp(arg, "storedist") &&
|
||||
(i+1) < remaining &&
|
||||
!(flags & RADIUS_NOSTORE))
|
||||
{
|
||||
storekey = c->argv[base_args+i+1];
|
||||
storedist = 1;
|
||||
i++;
|
||||
@@ -653,10 +683,20 @@ void georadiusCommand(client *c) {
|
||||
}
|
||||
|
||||
/* GEORADIUSBYMEMBER wrapper function. */
|
||||
void georadiusByMemberCommand(client *c) {
|
||||
void georadiusbymemberCommand(client *c) {
|
||||
georadiusGeneric(c, RADIUS_MEMBER);
|
||||
}
|
||||
|
||||
/* GEORADIUS_RO wrapper function. */
|
||||
void georadiusroCommand(client *c) {
|
||||
georadiusGeneric(c, RADIUS_COORDS|RADIUS_NOSTORE);
|
||||
}
|
||||
|
||||
/* GEORADIUSBYMEMBER_RO wrapper function. */
|
||||
void georadiusbymemberroCommand(client *c) {
|
||||
georadiusGeneric(c, RADIUS_MEMBER|RADIUS_NOSTORE);
|
||||
}
|
||||
|
||||
/* GEOHASH key ele1 ele2 ... eleN
|
||||
*
|
||||
* Returns an array with an 11 characters geohash representation of the
|
||||
|
||||
@@ -1128,6 +1128,7 @@ int isHLLObjectOrReply(client *c, robj *o) {
|
||||
if (checkType(c,o,OBJ_STRING))
|
||||
return C_ERR; /* Error already sent. */
|
||||
|
||||
if (!sdsEncodedObject(o)) goto invalid;
|
||||
if (stringObjectLen(o) < sizeof(*hdr)) goto invalid;
|
||||
hdr = o->ptr;
|
||||
|
||||
|
||||
+25
-3
@@ -949,11 +949,11 @@ int writeToClient(int fd, client *c, int handler_installed) {
|
||||
*
|
||||
* However if we are over the maxmemory limit we ignore that and
|
||||
* just deliver as much data as it is possible to deliver. */
|
||||
server.stat_net_output_bytes += totwritten;
|
||||
if (totwritten > NET_MAX_WRITES_PER_EVENT &&
|
||||
(server.maxmemory == 0 ||
|
||||
zmalloc_used_memory() < server.maxmemory)) break;
|
||||
}
|
||||
server.stat_net_output_bytes += totwritten;
|
||||
if (nwritten == -1) {
|
||||
if (errno == EAGAIN) {
|
||||
nwritten = 0;
|
||||
@@ -1269,8 +1269,10 @@ void processInputBuffer(client *c) {
|
||||
|
||||
/* CLIENT_CLOSE_AFTER_REPLY closes the connection once the reply is
|
||||
* written to the client. Make sure to not let the reply grow after
|
||||
* this flag has been set (i.e. don't process more commands). */
|
||||
if (c->flags & CLIENT_CLOSE_AFTER_REPLY) break;
|
||||
* this flag has been set (i.e. don't process more commands).
|
||||
*
|
||||
* The same applies for clients we want to terminate ASAP. */
|
||||
if (c->flags & (CLIENT_CLOSE_AFTER_REPLY|CLIENT_CLOSE_ASAP)) break;
|
||||
|
||||
/* Determine request type when unknown. */
|
||||
if (!c->reqtype) {
|
||||
@@ -1637,6 +1639,26 @@ void clientCommand(client *c) {
|
||||
}
|
||||
}
|
||||
|
||||
/* This callback is bound to POST and "Host:" command names. Those are not
|
||||
* really commands, but are used in security attacks in order to talk to
|
||||
* Redis instances via HTTP, with a technique called "cross protocol scripting"
|
||||
* which exploits the fact that services like Redis will discard invalid
|
||||
* HTTP headers and will process what follows.
|
||||
*
|
||||
* As a protection against this attack, Redis will terminate the connection
|
||||
* when a POST or "Host:" header is seen, and will log the event from
|
||||
* time to time (to avoid creating a DOS as a result of too many logs). */
|
||||
void securityWarningCommand(client *c) {
|
||||
static time_t logged_time;
|
||||
time_t now = time(NULL);
|
||||
|
||||
if (labs(now-logged_time) > 60) {
|
||||
serverLog(LL_WARNING,"Possible SECURITY ATTACK detected. It looks like somebody is sending POST or Host: commands to Redis. This is likely due to an attacker attempting to use Cross Protocol Scripting to compromise your Redis instance. Connection aborted.");
|
||||
logged_time = now;
|
||||
}
|
||||
freeClientAsync(c);
|
||||
}
|
||||
|
||||
/* Rewrite the command vector of the client. All the new objects ref count
|
||||
* is incremented. The old command vector is freed, and the old objects
|
||||
* ref count is decremented. */
|
||||
|
||||
+2
-4
@@ -241,11 +241,9 @@ void freeStringObject(robj *o) {
|
||||
}
|
||||
|
||||
void freeListObject(robj *o) {
|
||||
switch (o->encoding) {
|
||||
case OBJ_ENCODING_QUICKLIST:
|
||||
if (o->encoding == OBJ_ENCODING_QUICKLIST) {
|
||||
quicklistRelease(o->ptr);
|
||||
break;
|
||||
default:
|
||||
} else {
|
||||
serverPanic("Unknown list encoding type");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1690,9 +1690,6 @@ int rdbSaveToSlavesSockets(void) {
|
||||
exitFromChild((retval == C_OK) ? 0 : 1);
|
||||
} else {
|
||||
/* Parent */
|
||||
server.stat_fork_time = ustime()-start;
|
||||
server.stat_fork_rate = (double) zmalloc_used_memory() * 1000000 / server.stat_fork_time / (1024*1024*1024); /* GB per second. */
|
||||
latencyAddSampleIfNeeded("fork",server.stat_fork_time/1000);
|
||||
if (childpid == -1) {
|
||||
serverLog(LL_WARNING,"Can't save in background: fork: %s",
|
||||
strerror(errno));
|
||||
@@ -1715,6 +1712,10 @@ int rdbSaveToSlavesSockets(void) {
|
||||
close(pipefds[0]);
|
||||
close(pipefds[1]);
|
||||
} else {
|
||||
server.stat_fork_time = ustime()-start;
|
||||
server.stat_fork_rate = (double) zmalloc_used_memory() * 1000000 / server.stat_fork_time / (1024*1024*1024); /* GB per second. */
|
||||
latencyAddSampleIfNeeded("fork",server.stat_fork_time/1000);
|
||||
|
||||
serverLog(LL_NOTICE,"Background RDB transfer started by pid %d",
|
||||
childpid);
|
||||
server.rdb_save_time_start = time(NULL);
|
||||
|
||||
@@ -573,7 +573,7 @@ usage:
|
||||
" -c <clients> Number of parallel connections (default 50)\n"
|
||||
" -n <requests> Total number of requests (default 100000)\n"
|
||||
" -d <size> Data size of SET/GET value in bytes (default 2)\n"
|
||||
" -dbnum <db> SELECT the specified db number (default 0)\n"
|
||||
" --dbnum <db> SELECT the specified db number (default 0)\n"
|
||||
" -k <boolean> 1=keep alive 0=reconnect (default 1)\n"
|
||||
" -r <keyspacelen> Use random keys for SET/GET/INCR, random values for SADD\n"
|
||||
" Using this option the benchmark will expand the string __rand_int__\n"
|
||||
@@ -779,6 +779,13 @@ int main(int argc, const char **argv) {
|
||||
free(cmd);
|
||||
}
|
||||
|
||||
if (test_is_selected("hset")) {
|
||||
len = redisFormatCommand(&cmd,
|
||||
"HSET myset:__rand_int__ element:__rand_int__ %s",data);
|
||||
benchmark("HSET",cmd,len);
|
||||
free(cmd);
|
||||
}
|
||||
|
||||
if (test_is_selected("spop")) {
|
||||
len = redisFormatCommand(&cmd,"SPOP myset");
|
||||
benchmark("SPOP",cmd,len);
|
||||
|
||||
+23
-10
@@ -275,6 +275,10 @@ static void cliIntegrateHelp(void) {
|
||||
* don't already match what we have. */
|
||||
for (size_t j = 0; j < reply->elements; j++) {
|
||||
redisReply *entry = reply->element[j];
|
||||
if (entry->type != REDIS_REPLY_ARRAY || entry->elements < 4 ||
|
||||
entry->element[0]->type != REDIS_REPLY_STRING ||
|
||||
entry->element[1]->type != REDIS_REPLY_INTEGER ||
|
||||
entry->element[3]->type != REDIS_REPLY_INTEGER) return;
|
||||
char *cmdname = entry->element[0]->str;
|
||||
int i;
|
||||
|
||||
@@ -1255,6 +1259,7 @@ void cliLoadPreferences(void) {
|
||||
if (argc > 0) cliSetPreferences(argv,argc,0);
|
||||
sdsfreesplitres(argv,argc);
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
sdsfree(rcfile);
|
||||
}
|
||||
@@ -1266,6 +1271,11 @@ static void repl(void) {
|
||||
int argc;
|
||||
sds *argv;
|
||||
|
||||
/* Initialize the help and, if possible, use the COMMAND command in order
|
||||
* to retrieve missing entries. */
|
||||
cliInitHelp();
|
||||
cliIntegrateHelp();
|
||||
|
||||
config.interactive = 1;
|
||||
linenoiseSetMultiLine(1);
|
||||
linenoiseSetCompletionCallback(completionCallback);
|
||||
@@ -1320,9 +1330,10 @@ static void repl(void) {
|
||||
} else {
|
||||
long long start_time = mstime(), elapsed;
|
||||
int repeat, skipargs = 0;
|
||||
char *endptr;
|
||||
|
||||
repeat = atoi(argv[0]);
|
||||
if (argc > 1 && repeat) {
|
||||
repeat = strtol(argv[0], &endptr, 10);
|
||||
if (argc > 1 && *endptr == '\0' && repeat) {
|
||||
skipargs = 1;
|
||||
} else {
|
||||
repeat = 1;
|
||||
@@ -1341,7 +1352,9 @@ static void repl(void) {
|
||||
}
|
||||
|
||||
elapsed = mstime()-start_time;
|
||||
if (elapsed >= 500) {
|
||||
if (elapsed >= 500 &&
|
||||
config.output == OUTPUT_STANDARD)
|
||||
{
|
||||
printf("(%.2fs)\n",(double)elapsed/1000);
|
||||
}
|
||||
}
|
||||
@@ -2012,8 +2025,13 @@ static void getKeyTypes(redisReply *keys, int *types) {
|
||||
keys->element[i]->str, context->err, context->errstr);
|
||||
exit(1);
|
||||
} else if(reply->type != REDIS_REPLY_STATUS) {
|
||||
fprintf(stderr, "Invalid reply type (%d) for TYPE on key '%s'!\n",
|
||||
reply->type, keys->element[i]->str);
|
||||
if(reply->type == REDIS_REPLY_ERROR) {
|
||||
fprintf(stderr, "TYPE returned an error: %s\n", reply->str);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Invalid reply type (%d) for TYPE on key '%s'!\n",
|
||||
reply->type, keys->element[i]->str);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -2596,11 +2614,6 @@ int main(int argc, char **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);
|
||||
|
||||
+2
-1
@@ -1385,7 +1385,7 @@ int slaveTryPartialResynchronization(int fd, int read_reply) {
|
||||
|
||||
void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
char tmpfile[256], *err = NULL;
|
||||
int dfd, maxtries = 5;
|
||||
int dfd = -1, maxtries = 5;
|
||||
int sockerr = 0, psync_result;
|
||||
socklen_t errlen = sizeof(sockerr);
|
||||
UNUSED(el);
|
||||
@@ -1640,6 +1640,7 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
|
||||
error:
|
||||
aeDeleteFileEvent(server.el,fd,AE_READABLE|AE_WRITABLE);
|
||||
if (dfd != -1) close(dfd);
|
||||
close(fd);
|
||||
server.repl_transfer_s = -1;
|
||||
server.repl_state = REPL_STATE_CONNECT;
|
||||
|
||||
+2
-2
@@ -443,6 +443,7 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
|
||||
if (j == 10) {
|
||||
cmdlog = sdscatprintf(cmdlog," ... (%d more)",
|
||||
c->argc-j-1);
|
||||
break;
|
||||
} else {
|
||||
cmdlog = sdscatlen(cmdlog," ",1);
|
||||
cmdlog = sdscatsds(cmdlog,c->argv[j]->ptr);
|
||||
@@ -900,7 +901,6 @@ void scriptingInit(int setup) {
|
||||
server.lua_caller = NULL;
|
||||
server.lua_timedout = 0;
|
||||
server.lua_always_replicate_commands = 0; /* Only DEBUG can change it.*/
|
||||
server.lua_time_limit = LUA_SCRIPT_TIME_LIMIT;
|
||||
ldbInit();
|
||||
}
|
||||
|
||||
@@ -2272,7 +2272,7 @@ ldbLog(sdsnew("[e]eval <code> Execute some Lua code (in a different callfr
|
||||
ldbLog(sdsnew("[r]edis <cmd> Execute a Redis command."));
|
||||
ldbLog(sdsnew("[m]axlen [len] Trim logged Redis replies and Lua var dumps to len."));
|
||||
ldbLog(sdsnew(" Specifying zero as <len> means unlimited."));
|
||||
ldbLog(sdsnew("[a]abort Stop the execution of the script. In sync"));
|
||||
ldbLog(sdsnew("[a]bort Stop the execution of the script. In sync"));
|
||||
ldbLog(sdsnew(" mode dataset changes will be retained."));
|
||||
ldbLog(sdsnew(""));
|
||||
ldbLog(sdsnew("Debugger functions you can call from Lua scripts:"));
|
||||
|
||||
+22
-4
@@ -148,7 +148,7 @@ struct redisCommand redisCommandTable[] = {
|
||||
{"linsert",linsertCommand,5,"wm",0,NULL,1,1,1,0,0},
|
||||
{"rpop",rpopCommand,2,"wF",0,NULL,1,1,1,0,0},
|
||||
{"lpop",lpopCommand,2,"wF",0,NULL,1,1,1,0,0},
|
||||
{"brpop",brpopCommand,-3,"ws",0,NULL,1,1,1,0,0},
|
||||
{"brpop",brpopCommand,-3,"ws",0,NULL,1,-2,1,0,0},
|
||||
{"brpoplpush",brpoplpushCommand,4,"wms",0,NULL,1,2,1,0,0},
|
||||
{"blpop",blpopCommand,-3,"ws",0,NULL,1,-2,1,0,0},
|
||||
{"llen",llenCommand,2,"rF",0,NULL,1,1,1,0,0},
|
||||
@@ -284,8 +284,10 @@ struct redisCommand redisCommandTable[] = {
|
||||
{"wait",waitCommand,3,"s",0,NULL,0,0,0,0,0},
|
||||
{"command",commandCommand,0,"lt",0,NULL,0,0,0,0,0},
|
||||
{"geoadd",geoaddCommand,-5,"wm",0,NULL,1,1,1,0,0},
|
||||
{"georadius",georadiusCommand,-6,"w",0,NULL,1,1,1,0,0},
|
||||
{"georadiusbymember",georadiusByMemberCommand,-5,"w",0,NULL,1,1,1,0,0},
|
||||
{"georadius",georadiusCommand,-6,"w",0,georadiusGetKeys,1,1,1,0,0},
|
||||
{"georadius_ro",georadiusroCommand,-6,"r",0,georadiusGetKeys,1,1,1,0,0},
|
||||
{"georadiusbymember",georadiusbymemberCommand,-5,"w",0,georadiusGetKeys,1,1,1,0,0},
|
||||
{"georadiusbymember_ro",georadiusbymemberroCommand,-5,"r",0,georadiusGetKeys,1,1,1,0,0},
|
||||
{"geohash",geohashCommand,-2,"r",0,NULL,1,1,1,0,0},
|
||||
{"geopos",geoposCommand,-2,"r",0,NULL,1,1,1,0,0},
|
||||
{"geodist",geodistCommand,-4,"r",0,NULL,1,1,1,0,0},
|
||||
@@ -294,6 +296,8 @@ struct redisCommand redisCommandTable[] = {
|
||||
{"pfcount",pfcountCommand,-2,"r",0,NULL,1,-1,1,0,0},
|
||||
{"pfmerge",pfmergeCommand,-2,"wm",0,NULL,1,-1,1,0,0},
|
||||
{"pfdebug",pfdebugCommand,-3,"w",0,NULL,0,0,0,0,0},
|
||||
{"post",securityWarningCommand,-1,"lt",0,NULL,0,0,0,0,0},
|
||||
{"host:",securityWarningCommand,-1,"lt",0,NULL,0,0,0,0,0},
|
||||
{"latency",latencyCommand,-2,"aslt",0,NULL,0,0,0,0,0}
|
||||
};
|
||||
|
||||
@@ -775,6 +779,11 @@ void activeExpireCycle(int type) {
|
||||
int dbs_per_call = CRON_DBS_PER_CALL;
|
||||
long long start = ustime(), timelimit;
|
||||
|
||||
/* When clients are paused the dataset should be static not just from the
|
||||
* POV of clients not being able to write, but also from the POV of
|
||||
* expires and evictions of keys not being performed. */
|
||||
if (clientsArePaused()) return;
|
||||
|
||||
if (type == ACTIVE_EXPIRE_CYCLE_FAST) {
|
||||
/* Don't start a fast cycle if the previous cycle did not exited
|
||||
* for time limt. Also don't repeat a fast cycle for the same period
|
||||
@@ -1531,6 +1540,7 @@ void initServerConfig(void) {
|
||||
server.migrate_cached_sockets = dictCreate(&migrateCacheDictType,NULL);
|
||||
server.next_client_id = 1; /* Client IDs, start from 1 .*/
|
||||
server.loading_process_events_interval_bytes = (1024*1024*2);
|
||||
server.lua_time_limit = LUA_SCRIPT_TIME_LIMIT;
|
||||
|
||||
server.lruclock = getLRUClock();
|
||||
resetServerSaveParams();
|
||||
@@ -1590,6 +1600,8 @@ void initServerConfig(void) {
|
||||
server.rpopCommand = lookupCommandByCString("rpop");
|
||||
server.sremCommand = lookupCommandByCString("srem");
|
||||
server.execCommand = lookupCommandByCString("exec");
|
||||
server.expireCommand = lookupCommandByCString("expire");
|
||||
server.pexpireCommand = lookupCommandByCString("pexpire");
|
||||
|
||||
/* Slow log */
|
||||
server.slowlog_log_slower_than = CONFIG_DEFAULT_SLOWLOG_LOG_SLOWER_THAN;
|
||||
@@ -2583,8 +2595,9 @@ int prepareForShutdown(int flags) {
|
||||
"There is a child rewriting the AOF. Killing it!");
|
||||
kill(server.aof_child_pid,SIGUSR1);
|
||||
}
|
||||
/* Append only file: fsync() the AOF and exit */
|
||||
/* Append only file: flush buffers and fsync() the AOF at exit */
|
||||
serverLog(LL_NOTICE,"Calling fsync() on the AOF file.");
|
||||
flushAppendOnlyFile(1);
|
||||
aof_fsync(server.aof_fd);
|
||||
}
|
||||
|
||||
@@ -3459,6 +3472,11 @@ int freeMemoryIfNeeded(void) {
|
||||
int slaves = listLength(server.slaves);
|
||||
mstime_t latency, eviction_latency;
|
||||
|
||||
/* When clients are paused the dataset should be static not just from the
|
||||
* POV of clients not being able to write, but also from the POV of
|
||||
* expires and evictions of keys not being performed. */
|
||||
if (clientsArePaused()) return C_OK;
|
||||
|
||||
/* Remove the size of slaves output buffers and AOF buffer from the
|
||||
* count of used memory. */
|
||||
mem_used = zmalloc_used_memory();
|
||||
|
||||
+7
-2
@@ -752,7 +752,8 @@ struct redisServer {
|
||||
off_t loading_process_events_interval_bytes;
|
||||
/* Fast pointers to often looked up command */
|
||||
struct redisCommand *delCommand, *multiCommand, *lpushCommand, *lpopCommand,
|
||||
*rpopCommand, *sremCommand, *execCommand;
|
||||
*rpopCommand, *sremCommand, *execCommand, *expireCommand,
|
||||
*pexpireCommand;
|
||||
/* Fields used only for stats */
|
||||
time_t stat_starttime; /* Server start time */
|
||||
long long stat_numcommands; /* Number of processed commands */
|
||||
@@ -1435,6 +1436,7 @@ int *zunionInterGetKeys(struct redisCommand *cmd,robj **argv, int argc, int *num
|
||||
int *evalGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys);
|
||||
int *sortGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys);
|
||||
int *migrateGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys);
|
||||
int *georadiusGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys);
|
||||
|
||||
/* Cluster */
|
||||
void clusterInit(void);
|
||||
@@ -1633,8 +1635,10 @@ void replconfCommand(client *c);
|
||||
void waitCommand(client *c);
|
||||
void geoencodeCommand(client *c);
|
||||
void geodecodeCommand(client *c);
|
||||
void georadiusByMemberCommand(client *c);
|
||||
void georadiusbymemberCommand(client *c);
|
||||
void georadiusbymemberroCommand(client *c);
|
||||
void georadiusCommand(client *c);
|
||||
void georadiusroCommand(client *c);
|
||||
void geoaddCommand(client *c);
|
||||
void geohashCommand(client *c);
|
||||
void geoposCommand(client *c);
|
||||
@@ -1645,6 +1649,7 @@ void pfcountCommand(client *c);
|
||||
void pfmergeCommand(client *c);
|
||||
void pfdebugCommand(client *c);
|
||||
void latencyCommand(client *c);
|
||||
void securityWarningCommand(client *c);
|
||||
|
||||
#if defined(__GNUC__)
|
||||
void *calloc(size_t count, size_t size) __attribute__ ((deprecated));
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ typedef struct slowlogEntry {
|
||||
robj **argv;
|
||||
int argc;
|
||||
long long id; /* Unique entry identifier. */
|
||||
long long duration; /* Time spent by the query, in nanoseconds. */
|
||||
long long duration; /* Time spent by the query, in microseconds. */
|
||||
time_t time; /* Unix time at which the query was executed. */
|
||||
} slowlogEntry;
|
||||
|
||||
|
||||
+1
-1
@@ -1247,7 +1247,7 @@ void zaddGenericCommand(client *c, int flags) {
|
||||
/* After the options, we expect to have an even number of args, since
|
||||
* we expect any number of score-element pairs. */
|
||||
elements = c->argc-scoreidx;
|
||||
if (elements % 2) {
|
||||
if (elements % 2 || !elements) {
|
||||
addReply(c,shared.syntaxerr);
|
||||
return;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
#define REDIS_VERSION "3.2.4"
|
||||
#define REDIS_VERSION "3.2.11"
|
||||
|
||||
+23
-15
@@ -180,7 +180,7 @@ typedef struct zlentry {
|
||||
void ziplistRepr(unsigned char *zl);
|
||||
|
||||
/* Return bytes needed to store integer encoded by 'encoding' */
|
||||
static unsigned int zipIntSize(unsigned char encoding) {
|
||||
unsigned int zipIntSize(unsigned char encoding) {
|
||||
switch(encoding) {
|
||||
case ZIP_INT_8B: return 1;
|
||||
case ZIP_INT_16B: return 2;
|
||||
@@ -195,7 +195,7 @@ static unsigned int zipIntSize(unsigned char encoding) {
|
||||
|
||||
/* Encode the length 'rawlen' writing it in 'p'. If p is NULL it just returns
|
||||
* the amount of bytes required to encode such a length. */
|
||||
static unsigned int zipEncodeLength(unsigned char *p, unsigned char encoding, unsigned int rawlen) {
|
||||
unsigned int zipEncodeLength(unsigned char *p, unsigned char encoding, unsigned int rawlen) {
|
||||
unsigned char len = 1, buf[5];
|
||||
|
||||
if (ZIP_IS_STR(encoding)) {
|
||||
@@ -259,7 +259,7 @@ static unsigned int zipEncodeLength(unsigned char *p, unsigned char encoding, un
|
||||
|
||||
/* Encode the length of the previous entry and write it to "p". Return the
|
||||
* number of bytes needed to encode this length if "p" is NULL. */
|
||||
static unsigned int zipPrevEncodeLength(unsigned char *p, unsigned int len) {
|
||||
unsigned int zipPrevEncodeLength(unsigned char *p, unsigned int len) {
|
||||
if (p == NULL) {
|
||||
return (len < ZIP_BIGLEN) ? 1 : sizeof(len)+1;
|
||||
} else {
|
||||
@@ -277,7 +277,7 @@ static unsigned int zipPrevEncodeLength(unsigned char *p, unsigned int len) {
|
||||
|
||||
/* Encode the length of the previous entry and write it to "p". This only
|
||||
* uses the larger encoding (required in __ziplistCascadeUpdate). */
|
||||
static void zipPrevEncodeLengthForceLarge(unsigned char *p, unsigned int len) {
|
||||
void zipPrevEncodeLengthForceLarge(unsigned char *p, unsigned int len) {
|
||||
if (p == NULL) return;
|
||||
p[0] = ZIP_BIGLEN;
|
||||
memcpy(p+1,&len,sizeof(len));
|
||||
@@ -309,14 +309,14 @@ static void zipPrevEncodeLengthForceLarge(unsigned char *p, unsigned int len) {
|
||||
|
||||
/* Return the difference in number of bytes needed to store the length of the
|
||||
* previous element 'len', in the entry pointed to by 'p'. */
|
||||
static int zipPrevLenByteDiff(unsigned char *p, unsigned int len) {
|
||||
int zipPrevLenByteDiff(unsigned char *p, unsigned int len) {
|
||||
unsigned int prevlensize;
|
||||
ZIP_DECODE_PREVLENSIZE(p, prevlensize);
|
||||
return zipPrevEncodeLength(NULL, len) - prevlensize;
|
||||
}
|
||||
|
||||
/* Return the total number of bytes used by the entry pointed to by 'p'. */
|
||||
static unsigned int zipRawEntryLength(unsigned char *p) {
|
||||
unsigned int zipRawEntryLength(unsigned char *p) {
|
||||
unsigned int prevlensize, encoding, lensize, len;
|
||||
ZIP_DECODE_PREVLENSIZE(p, prevlensize);
|
||||
ZIP_DECODE_LENGTH(p + prevlensize, encoding, lensize, len);
|
||||
@@ -325,7 +325,7 @@ static unsigned int zipRawEntryLength(unsigned char *p) {
|
||||
|
||||
/* Check if string pointed to by 'entry' can be encoded as an integer.
|
||||
* Stores the integer value in 'v' and its encoding in 'encoding'. */
|
||||
static int zipTryEncoding(unsigned char *entry, unsigned int entrylen, long long *v, unsigned char *encoding) {
|
||||
int zipTryEncoding(unsigned char *entry, unsigned int entrylen, long long *v, unsigned char *encoding) {
|
||||
long long value;
|
||||
|
||||
if (entrylen >= 32 || entrylen == 0) return 0;
|
||||
@@ -352,7 +352,7 @@ static int zipTryEncoding(unsigned char *entry, unsigned int entrylen, long long
|
||||
}
|
||||
|
||||
/* Store integer 'value' at 'p', encoded as 'encoding' */
|
||||
static void zipSaveInteger(unsigned char *p, int64_t value, unsigned char encoding) {
|
||||
void zipSaveInteger(unsigned char *p, int64_t value, unsigned char encoding) {
|
||||
int16_t i16;
|
||||
int32_t i32;
|
||||
int64_t i64;
|
||||
@@ -382,7 +382,7 @@ static void zipSaveInteger(unsigned char *p, int64_t value, unsigned char encodi
|
||||
}
|
||||
|
||||
/* Read integer encoded as 'encoding' from 'p' */
|
||||
static int64_t zipLoadInteger(unsigned char *p, unsigned char encoding) {
|
||||
int64_t zipLoadInteger(unsigned char *p, unsigned char encoding) {
|
||||
int16_t i16;
|
||||
int32_t i32;
|
||||
int64_t i64, ret = 0;
|
||||
@@ -414,7 +414,7 @@ static int64_t zipLoadInteger(unsigned char *p, unsigned char encoding) {
|
||||
}
|
||||
|
||||
/* Return a struct with all information about an entry. */
|
||||
static void zipEntry(unsigned char *p, zlentry *e) {
|
||||
void zipEntry(unsigned char *p, zlentry *e) {
|
||||
|
||||
ZIP_DECODE_PREVLEN(p, e->prevrawlensize, e->prevrawlen);
|
||||
ZIP_DECODE_LENGTH(p + e->prevrawlensize, e->encoding, e->lensize, e->len);
|
||||
@@ -434,7 +434,7 @@ unsigned char *ziplistNew(void) {
|
||||
}
|
||||
|
||||
/* Resize the ziplist. */
|
||||
static unsigned char *ziplistResize(unsigned char *zl, unsigned int len) {
|
||||
unsigned char *ziplistResize(unsigned char *zl, unsigned int len) {
|
||||
zl = zrealloc(zl,len);
|
||||
ZIPLIST_BYTES(zl) = intrev32ifbe(len);
|
||||
zl[len-1] = ZIP_END;
|
||||
@@ -461,7 +461,7 @@ static unsigned char *ziplistResize(unsigned char *zl, unsigned int len) {
|
||||
*
|
||||
* The pointer "p" points to the first entry that does NOT need to be
|
||||
* updated, i.e. consecutive fields MAY need an update. */
|
||||
static unsigned char *__ziplistCascadeUpdate(unsigned char *zl, unsigned char *p) {
|
||||
unsigned char *__ziplistCascadeUpdate(unsigned char *zl, unsigned char *p) {
|
||||
size_t curlen = intrev32ifbe(ZIPLIST_BYTES(zl)), rawlen, rawlensize;
|
||||
size_t offset, noffset, extra;
|
||||
unsigned char *np;
|
||||
@@ -523,7 +523,7 @@ static unsigned char *__ziplistCascadeUpdate(unsigned char *zl, unsigned char *p
|
||||
}
|
||||
|
||||
/* Delete "num" entries, starting at "p". Returns pointer to the ziplist. */
|
||||
static unsigned char *__ziplistDelete(unsigned char *zl, unsigned char *p, unsigned int num) {
|
||||
unsigned char *__ziplistDelete(unsigned char *zl, unsigned char *p, unsigned int num) {
|
||||
unsigned int i, totlen, deleted = 0;
|
||||
size_t offset;
|
||||
int nextdiff = 0;
|
||||
@@ -583,7 +583,7 @@ static unsigned char *__ziplistDelete(unsigned char *zl, unsigned char *p, unsig
|
||||
}
|
||||
|
||||
/* Insert item at "p". */
|
||||
static unsigned char *__ziplistInsert(unsigned char *zl, unsigned char *p, unsigned char *s, unsigned int slen) {
|
||||
unsigned char *__ziplistInsert(unsigned char *zl, unsigned char *p, unsigned char *s, unsigned int slen) {
|
||||
size_t curlen = intrev32ifbe(ZIPLIST_BYTES(zl)), reqlen;
|
||||
unsigned int prevlensize, prevlen = 0;
|
||||
size_t offset;
|
||||
@@ -621,7 +621,12 @@ static unsigned char *__ziplistInsert(unsigned char *zl, unsigned char *p, unsig
|
||||
/* When the insert position is not equal to the tail, we need to
|
||||
* make sure that the next entry can hold this entry's length in
|
||||
* its prevlen field. */
|
||||
int forcelarge = 0;
|
||||
nextdiff = (p[0] != ZIP_END) ? zipPrevLenByteDiff(p,reqlen) : 0;
|
||||
if (nextdiff == -4 && reqlen < 4) {
|
||||
nextdiff = 0;
|
||||
forcelarge = 1;
|
||||
}
|
||||
|
||||
/* Store offset because a realloc may change the address of zl. */
|
||||
offset = p-zl;
|
||||
@@ -634,7 +639,10 @@ static unsigned char *__ziplistInsert(unsigned char *zl, unsigned char *p, unsig
|
||||
memmove(p+reqlen,p-nextdiff,curlen-offset-1+nextdiff);
|
||||
|
||||
/* Encode this entry's raw length in the next entry. */
|
||||
zipPrevEncodeLength(p+reqlen,reqlen);
|
||||
if (forcelarge)
|
||||
zipPrevEncodeLengthForceLarge(p+reqlen,reqlen);
|
||||
else
|
||||
zipPrevEncodeLength(p+reqlen,reqlen);
|
||||
|
||||
/* Update offset for tail */
|
||||
ZIPLIST_TAIL_OFFSET(zl) =
|
||||
|
||||
+3
-2
@@ -413,8 +413,9 @@ size_t zmalloc_get_memory_size(void) {
|
||||
if (sysctl(mib, 2, &size, &len, NULL, 0) == 0)
|
||||
return (size_t)size;
|
||||
return 0L; /* Failed? */
|
||||
#endif /* sysctl and sysconf variants */
|
||||
|
||||
#else
|
||||
return 0L; /* Unknown method to get the data. */
|
||||
#endif
|
||||
#else
|
||||
return 0L; /* Unknown OS. */
|
||||
#endif
|
||||
|
||||
@@ -110,7 +110,7 @@ foreach diskless {no yes} {
|
||||
test_psync {no reconnection, just sync} 6 1000000 3600 0 {
|
||||
} $diskless 0
|
||||
|
||||
test_psync {ok psync} 6 1000000 3600 0 {
|
||||
test_psync {ok psync} 6 100000000 3600 0 {
|
||||
assert {[s -1 sync_partial_ok] > 0}
|
||||
} $diskless 1
|
||||
|
||||
|
||||
@@ -189,4 +189,13 @@ start_server {tags {"bitops"}} {
|
||||
r set bits 1
|
||||
r bitfield bits get u1 0
|
||||
} {0}
|
||||
|
||||
test {BITFIELD regression for #3564} {
|
||||
for {set j 0} {$j < 10} {incr j} {
|
||||
r del mystring
|
||||
set res [r BITFIELD mystring SET i8 0 10 SET i8 64 10 INCRBY i8 10 99900]
|
||||
assert {$res eq {0 0 60}}
|
||||
}
|
||||
r del mystring
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,4 +204,19 @@ start_server {tags {"expire"}} {
|
||||
catch {r expire foo ""} e
|
||||
set e
|
||||
} {*not an integer*}
|
||||
|
||||
test {SET - use EX/PX option, TTL should not be reseted after loadaof} {
|
||||
r config set appendonly yes
|
||||
r set foo bar EX 100
|
||||
after 2000
|
||||
r debug loadaof
|
||||
set ttl [r ttl foo]
|
||||
assert {$ttl <= 98 && $ttl > 90}
|
||||
|
||||
r set foo bar PX 100000
|
||||
after 2000
|
||||
r debug loadaof
|
||||
set ttl [r ttl foo]
|
||||
assert {$ttl <= 98 && $ttl > 90}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-3
@@ -221,18 +221,26 @@ start_server {tags {"geo"}} {
|
||||
}
|
||||
|
||||
test {GEOADD + GEORANGE randomized test} {
|
||||
set attempt 20
|
||||
set attempt 30
|
||||
while {[incr attempt -1]} {
|
||||
set rv [lindex $regression_vectors $rv_idx]
|
||||
incr rv_idx
|
||||
|
||||
unset -nocomplain debuginfo
|
||||
set srand_seed [randomInt 1000000]
|
||||
set srand_seed [clock milliseconds]
|
||||
if {$rv ne {}} {set srand_seed [lindex $rv 0]}
|
||||
lappend debuginfo "srand_seed is $srand_seed"
|
||||
expr {srand($srand_seed)} ; # If you need a reproducible run
|
||||
r del mypoints
|
||||
set radius_km [expr {[randomInt 200]+10}]
|
||||
|
||||
if {[randomInt 10] == 0} {
|
||||
# From time to time use very big radiuses
|
||||
set radius_km [expr {[randomInt 50000]+10}]
|
||||
} else {
|
||||
# Normally use a few - ~200km radiuses to stress
|
||||
# test the code the most in edge cases.
|
||||
set radius_km [expr {[randomInt 200]+10}]
|
||||
}
|
||||
if {$rv ne {}} {set radius_km [lindex $rv 1]}
|
||||
set radius_m [expr {$radius_km*1000}]
|
||||
geo_random_point search_lon search_lat
|
||||
|
||||
@@ -2,7 +2,7 @@ Create-custer is a small script used to easily start a big number of Redis
|
||||
instances configured to run in cluster mode. Its main goal is to allow manual
|
||||
testing in a condition which is not easy to replicate with the Redis cluster
|
||||
unit tests, for example when a lot of instances are needed in order to trigger
|
||||
a give bug.
|
||||
a given bug.
|
||||
|
||||
The tool can also be used just to easily create a number of instances in a
|
||||
Redis Cluster in order to experiment a bit with the system.
|
||||
@@ -10,7 +10,7 @@ Redis Cluster in order to experiment a bit with the system.
|
||||
USAGE
|
||||
---
|
||||
|
||||
To create a cluster, follow this steps:
|
||||
To create a cluster, follow these steps:
|
||||
|
||||
1. Edit create-cluster and change the start / end port, depending on the
|
||||
number of instances you want to create.
|
||||
@@ -21,7 +21,7 @@ an actual Redis cluster will be created.
|
||||
|
||||
In order to stop a cluster:
|
||||
|
||||
1. Use "./craete-cluster stop" to stop all the instances. After you stopped the instances you can use "./create-cluster start" to restart them if you change ideas.
|
||||
2. Use "./create-cluster clean" to remove all the AOF / log files to restat with a clean environment.
|
||||
1. Use "./create-cluster stop" to stop all the instances. After you stopped the instances you can use "./create-cluster start" to restart them if you change your mind.
|
||||
2. Use "./create-cluster clean" to remove all the AOF / log files to restart with a clean environment.
|
||||
|
||||
Use the command "./create-cluster help" to get the full list of features.
|
||||
|
||||
@@ -135,13 +135,13 @@ fi
|
||||
echo "## Generated by install_server.sh ##" > $TMP_FILE
|
||||
|
||||
read -r SED_EXPR <<-EOF
|
||||
s#^port [0-9]{4}\$#port ${REDIS_PORT}#; \
|
||||
s#^logfile .+\$#logfile ${REDIS_LOG_FILE}#; \
|
||||
s#^dir .+\$#dir ${REDIS_DATA_DIR}#; \
|
||||
s#^pidfile .+\$#pidfile ${PIDFILE}#; \
|
||||
s#^daemonize no\$#daemonize yes#;
|
||||
s#^port .\+#port ${REDIS_PORT}#; \
|
||||
s#^logfile .\+#logfile ${REDIS_LOG_FILE}#; \
|
||||
s#^dir .\+#dir ${REDIS_DATA_DIR}#; \
|
||||
s#^pidfile .\+#pidfile ${PIDFILE}#; \
|
||||
s#^daemonize no#daemonize yes#;
|
||||
EOF
|
||||
sed -r "$SED_EXPR" $DEFAULT_CONFIG >> $TMP_FILE
|
||||
sed "$SED_EXPR" $DEFAULT_CONFIG >> $TMP_FILE
|
||||
|
||||
#cat $TPL_FILE | while read line; do eval "echo \"$line\"" >> $TMP_FILE; done
|
||||
cp $TMP_FILE $REDIS_CONFIG_FILE || die "Could not write redis config file $REDIS_CONFIG_FILE"
|
||||
|
||||
Reference in New Issue
Block a user