Unverified Commit 68ceb466 authored by chendianqiang's avatar chendianqiang Committed by GitHub
Browse files

Merge pull request #1 from antirez/unstable

update
parents 3d5e2c62 1c95c075
...@@ -193,7 +193,7 @@ void sortCommand(client *c) { ...@@ -193,7 +193,7 @@ void sortCommand(client *c) {
long limit_start = 0, limit_count = -1, start, end; long limit_start = 0, limit_count = -1, start, end;
int j, dontsort = 0, vectorlen; int j, dontsort = 0, vectorlen;
int getop = 0; /* GET operation counter */ int getop = 0; /* GET operation counter */
int int_convertion_error = 0; int int_conversion_error = 0;
int syntax_error = 0; int syntax_error = 0;
robj *sortval, *sortby = NULL, *storekey = NULL; robj *sortval, *sortby = NULL, *storekey = NULL;
redisSortObject *vector; /* Resulting vector to sort */ redisSortObject *vector; /* Resulting vector to sort */
...@@ -447,7 +447,7 @@ void sortCommand(client *c) { ...@@ -447,7 +447,7 @@ void sortCommand(client *c) {
serverAssertWithInfo(c,sortval,j == vectorlen); serverAssertWithInfo(c,sortval,j == vectorlen);
/* Now it's time to load the right scores in the sorting vector */ /* Now it's time to load the right scores in the sorting vector */
if (dontsort == 0) { if (!dontsort) {
for (j = 0; j < vectorlen; j++) { for (j = 0; j < vectorlen; j++) {
robj *byval; robj *byval;
if (sortby) { if (sortby) {
...@@ -469,7 +469,7 @@ void sortCommand(client *c) { ...@@ -469,7 +469,7 @@ void sortCommand(client *c) {
if (eptr[0] != '\0' || errno == ERANGE || if (eptr[0] != '\0' || errno == ERANGE ||
isnan(vector[j].u.score)) isnan(vector[j].u.score))
{ {
int_convertion_error = 1; int_conversion_error = 1;
} }
} else if (byval->encoding == OBJ_ENCODING_INT) { } else if (byval->encoding == OBJ_ENCODING_INT) {
/* Don't need to decode the object if it's /* Don't need to decode the object if it's
...@@ -487,9 +487,7 @@ void sortCommand(client *c) { ...@@ -487,9 +487,7 @@ void sortCommand(client *c) {
decrRefCount(byval); decrRefCount(byval);
} }
} }
}
if (dontsort == 0) {
server.sort_desc = desc; server.sort_desc = desc;
server.sort_alpha = alpha; server.sort_alpha = alpha;
server.sort_bypattern = sortby ? 1 : 0; server.sort_bypattern = sortby ? 1 : 0;
...@@ -503,7 +501,7 @@ void sortCommand(client *c) { ...@@ -503,7 +501,7 @@ void sortCommand(client *c) {
/* Send command output to the output buffer, performing the specified /* Send command output to the output buffer, performing the specified
* GET/DEL/INCR/DECR operations if any. */ * GET/DEL/INCR/DECR operations if any. */
outputlen = getop ? getop*(end-start+1) : end-start+1; outputlen = getop ? getop*(end-start+1) : end-start+1;
if (int_convertion_error) { if (int_conversion_error) {
addReplyError(c,"One or more scores can't be converted into double"); addReplyError(c,"One or more scores can't be converted into double");
} else if (storekey == NULL) { } else if (storekey == NULL) {
/* STORE option not specified, sent the sorting result to client */ /* STORE option not specified, sent the sorting result to client */
......
...@@ -108,5 +108,6 @@ streamConsumer *streamLookupConsumer(streamCG *cg, sds name, int create); ...@@ -108,5 +108,6 @@ streamConsumer *streamLookupConsumer(streamCG *cg, sds name, int create);
streamCG *streamCreateCG(stream *s, char *name, size_t namelen, streamID *id); streamCG *streamCreateCG(stream *s, char *name, size_t namelen, streamID *id);
streamNACK *streamCreateNACK(streamConsumer *consumer); streamNACK *streamCreateNACK(streamConsumer *consumer);
void streamDecodeID(void *buf, streamID *id); void streamDecodeID(void *buf, streamID *id);
int streamCompareID(streamID *a, streamID *b);
#endif #endif
This diff is collapsed.
...@@ -361,7 +361,7 @@ void incrDecrCommand(client *c, long long incr) { ...@@ -361,7 +361,7 @@ void incrDecrCommand(client *c, long long incr) {
new = o; new = o;
o->ptr = (void*)((long)value); o->ptr = (void*)((long)value);
} else { } else {
new = createStringObjectFromLongLong(value); new = createStringObjectFromLongLongForValue(value);
if (o) { if (o) {
dbOverwrite(c->db,c->argv[1],new); dbOverwrite(c->db,c->argv[1],new);
} else { } else {
......
...@@ -507,7 +507,7 @@ static int zslParseRange(robj *min, robj *max, zrangespec *spec) { ...@@ -507,7 +507,7 @@ static int zslParseRange(robj *min, robj *max, zrangespec *spec) {
* + means the max string possible * + means the max string possible
* *
* If the string is valid the *dest pointer is set to the redis object * If the string is valid the *dest pointer is set to the redis object
* that will be used for the comparision, and ex will be set to 0 or 1 * that will be used for the comparison, and ex will be set to 0 or 1
* respectively if the item is exclusive or inclusive. C_OK will be * respectively if the item is exclusive or inclusive. C_OK will be
* returned. * returned.
* *
...@@ -1100,8 +1100,8 @@ unsigned char *zzlDeleteRangeByRank(unsigned char *zl, unsigned int start, unsig ...@@ -1100,8 +1100,8 @@ unsigned char *zzlDeleteRangeByRank(unsigned char *zl, unsigned int start, unsig
* Common sorted set API * Common sorted set API
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
unsigned int zsetLength(const robj *zobj) { unsigned long zsetLength(const robj *zobj) {
int length = -1; unsigned long length = 0;
if (zobj->encoding == OBJ_ENCODING_ZIPLIST) { if (zobj->encoding == OBJ_ENCODING_ZIPLIST) {
length = zzlLength(zobj->ptr); length = zzlLength(zobj->ptr);
} else if (zobj->encoding == OBJ_ENCODING_SKIPLIST) { } else if (zobj->encoding == OBJ_ENCODING_SKIPLIST) {
...@@ -1878,7 +1878,7 @@ void zuiClearIterator(zsetopsrc *op) { ...@@ -1878,7 +1878,7 @@ void zuiClearIterator(zsetopsrc *op) {
} }
} }
int zuiLength(zsetopsrc *op) { unsigned long zuiLength(zsetopsrc *op) {
if (op->subject == NULL) if (op->subject == NULL)
return 0; return 0;
...@@ -2085,7 +2085,11 @@ int zuiFind(zsetopsrc *op, zsetopval *val, double *score) { ...@@ -2085,7 +2085,11 @@ int zuiFind(zsetopsrc *op, zsetopval *val, double *score) {
} }
int zuiCompareByCardinality(const void *s1, const void *s2) { int zuiCompareByCardinality(const void *s1, const void *s2) {
return zuiLength((zsetopsrc*)s1) - zuiLength((zsetopsrc*)s2); unsigned long first = zuiLength((zsetopsrc*)s1);
unsigned long second = zuiLength((zsetopsrc*)s2);
if (first > second) return 1;
if (first < second) return -1;
return 0;
} }
#define REDIS_AGGR_SUM 1 #define REDIS_AGGR_SUM 1
...@@ -2129,7 +2133,7 @@ void zunionInterGenericCommand(client *c, robj *dstkey, int op) { ...@@ -2129,7 +2133,7 @@ void zunionInterGenericCommand(client *c, robj *dstkey, int op) {
zsetopsrc *src; zsetopsrc *src;
zsetopval zval; zsetopval zval;
sds tmp; sds tmp;
unsigned int maxelelen = 0; size_t maxelelen = 0;
robj *dstobj; robj *dstobj;
zset *dstzset; zset *dstzset;
zskiplistNode *znode; zskiplistNode *znode;
...@@ -2363,8 +2367,8 @@ void zrangeGenericCommand(client *c, int reverse) { ...@@ -2363,8 +2367,8 @@ void zrangeGenericCommand(client *c, int reverse) {
int withscores = 0; int withscores = 0;
long start; long start;
long end; long end;
int llen; long llen;
int rangelen; long rangelen;
if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != C_OK) || if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != C_OK) ||
(getLongFromObjectOrReply(c, c->argv[3], &end, NULL) != C_OK)) return; (getLongFromObjectOrReply(c, c->argv[3], &end, NULL) != C_OK)) return;
...@@ -2671,7 +2675,7 @@ void zcountCommand(client *c) { ...@@ -2671,7 +2675,7 @@ void zcountCommand(client *c) {
robj *key = c->argv[1]; robj *key = c->argv[1];
robj *zobj; robj *zobj;
zrangespec range; zrangespec range;
int count = 0; unsigned long count = 0;
/* Parse the range arguments */ /* Parse the range arguments */
if (zslParseRange(c->argv[2],c->argv[3],&range) != C_OK) { if (zslParseRange(c->argv[2],c->argv[3],&range) != C_OK) {
...@@ -2748,7 +2752,7 @@ void zlexcountCommand(client *c) { ...@@ -2748,7 +2752,7 @@ void zlexcountCommand(client *c) {
robj *key = c->argv[1]; robj *key = c->argv[1];
robj *zobj; robj *zobj;
zlexrangespec range; zlexrangespec range;
int count = 0; unsigned long count = 0;
/* Parse the range arguments */ /* Parse the range arguments */
if (zslParseLexRange(c->argv[2],c->argv[3],&range) != C_OK) { if (zslParseLexRange(c->argv[2],c->argv[3],&range) != C_OK) {
...@@ -3163,8 +3167,8 @@ void genericZpopCommand(client *c, robj **keyv, int keyc, int where, int emitkey ...@@ -3163,8 +3167,8 @@ void genericZpopCommand(client *c, robj **keyv, int keyc, int where, int emitkey
signalModifiedKey(c->db,key); signalModifiedKey(c->db,key);
} }
addReplyDouble(c,score);
addReplyBulkCBuffer(c,ele,sdslen(ele)); addReplyBulkCBuffer(c,ele,sdslen(ele));
addReplyDouble(c,score);
sdsfree(ele); sdsfree(ele);
arraylen += 2; arraylen += 2;
...@@ -3216,9 +3220,9 @@ void blockingGenericZpopCommand(client *c, int where) { ...@@ -3216,9 +3220,9 @@ void blockingGenericZpopCommand(client *c, int where) {
return; return;
} else { } else {
if (zsetLength(o) != 0) { if (zsetLength(o) != 0) {
/* Non empty zset, this is like a normal Z[REV]POP. */ /* Non empty zset, this is like a normal ZPOP[MIN|MAX]. */
genericZpopCommand(c,&c->argv[j],1,where,1,NULL); genericZpopCommand(c,&c->argv[j],1,where,1,NULL);
/* Replicate it as an Z[REV]POP instead of BZ[REV]POP. */ /* Replicate it as an ZPOP[MIN|MAX] instead of BZPOP[MIN|MAX]. */
rewriteClientCommandVector(c,2, rewriteClientCommandVector(c,2,
where == ZSET_MAX ? shared.zpopmax : shared.zpopmin, where == ZSET_MAX ? shared.zpopmax : shared.zpopmin,
c->argv[j]); c->argv[j]);
......
...@@ -451,7 +451,7 @@ int string2ld(const char *s, size_t slen, long double *dp) { ...@@ -451,7 +451,7 @@ int string2ld(const char *s, size_t slen, long double *dp) {
/* Convert a double to a string representation. Returns the number of bytes /* Convert a double to a string representation. Returns the number of bytes
* required. The representation should always be parsable by strtod(3). * required. The representation should always be parsable by strtod(3).
* This function does not support human-friendly formatting like ld2string * This function does not support human-friendly formatting like ld2string
* does. It is intented mainly to be used inside t_zset.c when writing scores * does. It is intended mainly to be used inside t_zset.c when writing scores
* into a ziplist representing a sorted set. */ * into a ziplist representing a sorted set. */
int d2string(char *buf, size_t len, double value) { int d2string(char *buf, size_t len, double value) {
if (isnan(value)) { if (isnan(value)) {
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
* traversal. * traversal.
* *
* <uint16_t zllen> is the number of entries. When there are more than * <uint16_t zllen> is the number of entries. When there are more than
* 2^16-2 entires, this value is set to 2^16-1 and we need to traverse the * 2^16-2 entries, this value is set to 2^16-1 and we need to traverse the
* entire list to know how many items it holds. * entire list to know how many items it holds.
* *
* <uint8_t zlend> is a special entry representing the end of the ziplist. * <uint8_t zlend> is a special entry representing the end of the ziplist.
...@@ -256,7 +256,7 @@ ...@@ -256,7 +256,7 @@
#define ZIPLIST_ENTRY_END(zl) ((zl)+intrev32ifbe(ZIPLIST_BYTES(zl))-1) #define ZIPLIST_ENTRY_END(zl) ((zl)+intrev32ifbe(ZIPLIST_BYTES(zl))-1)
/* Increment the number of items field in the ziplist header. Note that this /* Increment the number of items field in the ziplist header. Note that this
* macro should never overflow the unsigned 16 bit integer, since entires are * macro should never overflow the unsigned 16 bit integer, since entries are
* always pushed one at a time. When UINT16_MAX is reached we want the count * always pushed one at a time. When UINT16_MAX is reached we want the count
* to stay there to signal that a full scan is needed to get the number of * to stay there to signal that a full scan is needed to get the number of
* items inside the ziplist. */ * items inside the ziplist. */
...@@ -269,7 +269,7 @@ ...@@ -269,7 +269,7 @@
* Note that this is not how the data is actually encoded, is just what we * Note that this is not how the data is actually encoded, is just what we
* get filled by a function in order to operate more easily. */ * get filled by a function in order to operate more easily. */
typedef struct zlentry { typedef struct zlentry {
unsigned int prevrawlensize; /* Bytes used to encode the previos entry len*/ unsigned int prevrawlensize; /* Bytes used to encode the previous entry len*/
unsigned int prevrawlen; /* Previous entry len. */ unsigned int prevrawlen; /* Previous entry len. */
unsigned int lensize; /* Bytes used to encode this entry type/len. unsigned int lensize; /* Bytes used to encode this entry type/len.
For example strings have a 1, 2 or 5 bytes For example strings have a 1, 2 or 5 bytes
...@@ -431,7 +431,7 @@ unsigned int zipStorePrevEntryLength(unsigned char *p, unsigned int len) { ...@@ -431,7 +431,7 @@ unsigned int zipStorePrevEntryLength(unsigned char *p, unsigned int len) {
/* Return the length of the previous element, and the number of bytes that /* Return the length of the previous element, and the number of bytes that
* are used in order to encode the previous element length. * are used in order to encode the previous element length.
* 'ptr' must point to the prevlen prefix of an entry (that encodes the * 'ptr' must point to the prevlen prefix of an entry (that encodes the
* length of the previos entry in order to navigate the elements backward). * length of the previous entry in order to navigate the elements backward).
* The length of the previous entry is stored in 'prevlen', the number of * The length of the previous entry is stored in 'prevlen', the number of
* bytes needed to encode the previous entry length are stored in * bytes needed to encode the previous entry length are stored in
* 'prevlensize'. */ * 'prevlensize'. */
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h>
/* This function provide us access to the original libc free(). This is useful /* This function provide us access to the original libc free(). This is useful
* for instance to free results obtained by backtrace_symbols(). We need * for instance to free results obtained by backtrace_symbols(). We need
...@@ -164,7 +165,7 @@ void *zrealloc(void *ptr, size_t size) { ...@@ -164,7 +165,7 @@ void *zrealloc(void *ptr, size_t size) {
*((size_t*)newptr) = size; *((size_t*)newptr) = size;
update_zmalloc_stat_free(oldsize); update_zmalloc_stat_free(oldsize);
update_zmalloc_stat_alloc(size); update_zmalloc_stat_alloc(size+PREFIX_SIZE);
return (char*)newptr+PREFIX_SIZE; return (char*)newptr+PREFIX_SIZE;
#endif #endif
} }
...@@ -181,6 +182,9 @@ size_t zmalloc_size(void *ptr) { ...@@ -181,6 +182,9 @@ size_t zmalloc_size(void *ptr) {
if (size&(sizeof(long)-1)) size += sizeof(long)-(size&(sizeof(long)-1)); if (size&(sizeof(long)-1)) size += sizeof(long)-(size&(sizeof(long)-1));
return size+PREFIX_SIZE; return size+PREFIX_SIZE;
} }
size_t zmalloc_usable(void *ptr) {
return zmalloc_usable(ptr)-PREFIX_SIZE;
}
#endif #endif
void zfree(void *ptr) { void zfree(void *ptr) {
...@@ -379,7 +383,7 @@ size_t zmalloc_get_private_dirty(long pid) { ...@@ -379,7 +383,7 @@ size_t zmalloc_get_private_dirty(long pid) {
} }
/* Returns the size of physical memory (RAM) in bytes. /* Returns the size of physical memory (RAM) in bytes.
* It looks ugly, but this is the cleanest way to achive cross platform results. * It looks ugly, but this is the cleanest way to achieve cross platform results.
* Cleaned up from: * Cleaned up from:
* *
* http://nadeausoftware.com/articles/2012/09/c_c_tip_how_get_physical_memory_size_system * http://nadeausoftware.com/articles/2012/09/c_c_tip_how_get_physical_memory_size_system
...@@ -418,7 +422,7 @@ size_t zmalloc_get_memory_size(void) { ...@@ -418,7 +422,7 @@ size_t zmalloc_get_memory_size(void) {
mib[0] = CTL_HW; mib[0] = CTL_HW;
#if defined(HW_REALMEM) #if defined(HW_REALMEM)
mib[1] = HW_REALMEM; /* FreeBSD. ----------------- */ mib[1] = HW_REALMEM; /* FreeBSD. ----------------- */
#elif defined(HW_PYSMEM) #elif defined(HW_PHYSMEM)
mib[1] = HW_PHYSMEM; /* Others. ------------------ */ mib[1] = HW_PHYSMEM; /* Others. ------------------ */
#endif #endif
unsigned int size = 0; /* 32-bit */ unsigned int size = 0; /* 32-bit */
......
...@@ -63,6 +63,11 @@ ...@@ -63,6 +63,11 @@
#ifndef ZMALLOC_LIB #ifndef ZMALLOC_LIB
#define ZMALLOC_LIB "libc" #define ZMALLOC_LIB "libc"
#ifdef __GLIBC__
#include <malloc.h>
#define HAVE_MALLOC_SIZE 1
#define zmalloc_size(p) malloc_usable_size(p)
#endif
#endif #endif
/* We can enable the Redis defrag capabilities only if we are using Jemalloc /* We can enable the Redis defrag capabilities only if we are using Jemalloc
...@@ -93,6 +98,9 @@ void *zmalloc_no_tcache(size_t size); ...@@ -93,6 +98,9 @@ void *zmalloc_no_tcache(size_t size);
#ifndef HAVE_MALLOC_SIZE #ifndef HAVE_MALLOC_SIZE
size_t zmalloc_size(void *ptr); size_t zmalloc_size(void *ptr);
size_t zmalloc_usable(void *ptr);
#else
#define zmalloc_usable(p) zmalloc_size(p)
#endif #endif
#endif /* __ZMALLOC_H */ #endif /* __ZMALLOC_H */
...@@ -92,3 +92,80 @@ test "Node #10 should eventually replicate node #5" { ...@@ -92,3 +92,80 @@ test "Node #10 should eventually replicate node #5" {
fail "#10 didn't became slave of #5" fail "#10 didn't became slave of #5"
} }
} }
source "../tests/includes/init-tests.tcl"
# Create a cluster with 3 master and 15 slaves, so that we have 5
# slaves for eatch master.
test "Create a 3 nodes cluster" {
create_cluster 3 15
}
test "Cluster is up" {
assert_cluster_state ok
}
test "The first master has actually 5 slaves" {
assert {[llength [lindex [R 0 role] 2]] == 5}
}
test {Slaves of #0 are instance #3, #6, #9, #12 and #15 as expected} {
set port0 [get_instance_attrib redis 0 port]
assert {[lindex [R 3 role] 2] == $port0}
assert {[lindex [R 6 role] 2] == $port0}
assert {[lindex [R 9 role] 2] == $port0}
assert {[lindex [R 12 role] 2] == $port0}
assert {[lindex [R 15 role] 2] == $port0}
}
test {Instance #3, #6, #9, #12 and #15 synced with the master} {
wait_for_condition 1000 50 {
[RI 3 master_link_status] eq {up} &&
[RI 6 master_link_status] eq {up} &&
[RI 9 master_link_status] eq {up} &&
[RI 12 master_link_status] eq {up} &&
[RI 15 master_link_status] eq {up}
} else {
fail "Instance #3 or #6 or #9 or #12 or #15 master link status is not up"
}
}
proc master_detected {instances} {
foreach instance [dict keys $instances] {
if {[RI $instance role] eq {master}} {
return true
}
}
return false
}
test "New Master down consecutively" {
set instances [dict create 0 1 3 1 6 1 9 1 12 1 15 1]
set loops [expr {[dict size $instances]-1}]
for {set i 0} {$i < $loops} {incr i} {
set master_id -1
foreach instance [dict keys $instances] {
if {[RI $instance role] eq {master}} {
set master_id $instance
break;
}
}
if {$master_id eq -1} {
fail "no master detected, #loop $i"
}
set instances [dict remove $instances $master_id]
kill_instance redis $master_id
wait_for_condition 1000 50 {
[master_detected $instances]
} else {
failover "No failover detected when master $master_id fails"
}
assert_cluster_state ok
}
}
...@@ -39,6 +39,25 @@ start_server [list overrides [list "dir" $server_path]] { ...@@ -39,6 +39,25 @@ start_server [list overrides [list "dir" $server_path]] {
} {0000000000000000000000000000000000000000} } {0000000000000000000000000000000000000000}
} }
start_server [list overrides [list "dir" $server_path]] {
test {Test RDB stream encoding} {
for {set j 0} {$j < 1000} {incr j} {
if {rand() < 0.9} {
r xadd stream * foo $j
} else {
r xadd stream * bar $j
}
}
r xgroup create stream mygroup 0
r xreadgroup GROUP mygroup Alice COUNT 1 STREAMS stream >
set digest [r debug digest]
r debug reload
set newdigest [r debug digest]
assert {$digest eq $newdigest}
r del stream
}
}
# Helper function to start a server and kill it, just to check the error # Helper function to start a server and kill it, just to check the error
# logged. # logged.
set defaults {} set defaults {}
......
...@@ -11,7 +11,7 @@ proc stop_bg_complex_data {handle} { ...@@ -11,7 +11,7 @@ proc stop_bg_complex_data {handle} {
# partial resyncs attempts, all this while flooding the master with # partial resyncs attempts, all this while flooding the master with
# write queries. # write queries.
# #
# You can specifiy backlog size, ttl, delay before reconnection, test duration # You can specify backlog size, ttl, delay before reconnection, test duration
# in seconds, and an additional condition to verify at the end. # in seconds, and an additional condition to verify at the end.
# #
# If reconnect is > 0, the test actually try to break the connection and # If reconnect is > 0, the test actually try to break the connection and
......
...@@ -66,3 +66,13 @@ test "SDOWN is triggered by misconfigured instance repling with errors" { ...@@ -66,3 +66,13 @@ test "SDOWN is triggered by misconfigured instance repling with errors" {
R 0 bgsave R 0 bgsave
ensure_master_up ensure_master_up
} }
# We use this test setup to also test command renaming, as a side
# effect of the master going down if we send PONG instead of PING
test "SDOWN is triggered if we rename PING to PONG" {
ensure_master_up
S 4 SENTINEL SET mymaster rename-command PING PONG
ensure_master_down
S 4 SENTINEL SET mymaster rename-command PING PING
ensure_master_up
}
...@@ -276,6 +276,12 @@ proc start_server {options {code undefined}} { ...@@ -276,6 +276,12 @@ proc start_server {options {code undefined}} {
error_and_quit $config_file $line error_and_quit $config_file $line
} }
if {$::wait_server} {
set msg "server started PID: [dict get $srv "pid"]. press any key to continue..."
puts $msg
read stdin 1
}
while 1 { while 1 {
# check that the server actually started and is ready for connections # check that the server actually started and is ready for connections
if {[exec grep -i "Ready to accept" | wc -l < $stdout] > 0} { if {[exec grep -i "Ready to accept" | wc -l < $stdout] > 0} {
......
...@@ -375,3 +375,19 @@ proc start_write_load {host port seconds} { ...@@ -375,3 +375,19 @@ proc start_write_load {host port seconds} {
proc stop_write_load {handle} { proc stop_write_load {handle} {
catch {exec /bin/kill -9 $handle} catch {exec /bin/kill -9 $handle}
} }
proc K { x y } { set x }
# Shuffle a list. From Tcl wiki. Originally from Steve Cohen that improved
# other versions. Code should be under public domain.
proc lshuffle {list} {
set n [llength $list]
while {$n>0} {
set j [expr {int(rand()*$n)}]
lappend slist [lindex $list $j]
incr n -1
set temp [lindex $list $n]
set list [lreplace [K $list [set list {}]] $j $j $temp]
}
return $slist
}
...@@ -61,6 +61,7 @@ set ::all_tests { ...@@ -61,6 +61,7 @@ set ::all_tests {
unit/hyperloglog unit/hyperloglog
unit/lazyfree unit/lazyfree
unit/wait unit/wait
unit/pendingquerybuf
} }
# Index to the next test to run in the ::all_tests list. # Index to the next test to run in the ::all_tests list.
set ::next_test 0 set ::next_test 0
...@@ -82,6 +83,8 @@ set ::force_failure 0 ...@@ -82,6 +83,8 @@ set ::force_failure 0
set ::timeout 600; # 10 minutes without progresses will quit the test. set ::timeout 600; # 10 minutes without progresses will quit the test.
set ::last_progress [clock seconds] set ::last_progress [clock seconds]
set ::active_servers {} ; # Pids of active Redis instances. set ::active_servers {} ; # Pids of active Redis instances.
set ::dont_clean 0
set ::wait_server 0
# Set to 1 when we are running in client mode. The Redis test uses a # Set to 1 when we are running in client mode. The Redis test uses a
# server-client model to run tests simultaneously. The server instance # server-client model to run tests simultaneously. The server instance
...@@ -175,6 +178,9 @@ proc s {args} { ...@@ -175,6 +178,9 @@ proc s {args} {
} }
proc cleanup {} { proc cleanup {} {
if {$::dont_clean} {
return
}
if {!$::quiet} {puts -nonewline "Cleanup: may take some time... "} if {!$::quiet} {puts -nonewline "Cleanup: may take some time... "}
flush stdout flush stdout
catch {exec rm -rf {*}[glob tests/tmp/redis.conf.*]} catch {exec rm -rf {*}[glob tests/tmp/redis.conf.*]}
...@@ -224,6 +230,7 @@ proc test_server_cron {} { ...@@ -224,6 +230,7 @@ proc test_server_cron {} {
if {$elapsed > $::timeout} { if {$elapsed > $::timeout} {
set err "\[[colorstr red TIMEOUT]\]: clients state report follows." set err "\[[colorstr red TIMEOUT]\]: clients state report follows."
puts $err puts $err
lappend ::failed_tests $err
show_clients_state show_clients_state
kill_clients kill_clients
force_kill_all_servers force_kill_all_servers
...@@ -410,6 +417,8 @@ proc print_help_screen {} { ...@@ -410,6 +417,8 @@ proc print_help_screen {} {
"--clients <num> Number of test clients (default 16)." "--clients <num> Number of test clients (default 16)."
"--timeout <sec> Test timeout in seconds (default 10 min)." "--timeout <sec> Test timeout in seconds (default 10 min)."
"--force-failure Force the execution of a test that always fails." "--force-failure Force the execution of a test that always fails."
"--dont-clean don't delete redis log files after the run"
"--wait-server wait after server is started (so that you can attach a debugger)"
"--help Print this help screen." "--help Print this help screen."
} "\n"] } "\n"]
} }
...@@ -463,6 +472,10 @@ for {set j 0} {$j < [llength $argv]} {incr j} { ...@@ -463,6 +472,10 @@ for {set j 0} {$j < [llength $argv]} {incr j} {
} elseif {$opt eq {--clients}} { } elseif {$opt eq {--clients}} {
set ::numclients $arg set ::numclients $arg
incr j incr j
} elseif {$opt eq {--dont-clean}} {
set ::dont_clean 1
} elseif {$opt eq {--wait-server}} {
set ::wait_server 1
} elseif {$opt eq {--timeout}} { } elseif {$opt eq {--timeout}} {
set ::timeout $arg set ::timeout $arg
incr j incr j
......
This diff is collapsed.
...@@ -121,7 +121,7 @@ start_server {tags {"expire"}} { ...@@ -121,7 +121,7 @@ start_server {tags {"expire"}} {
list $a $b list $a $b
} {somevalue {}} } {somevalue {}}
test {TTL returns tiem to live in seconds} { test {TTL returns time to live in seconds} {
r del x r del x
r setex x 10 somevalue r setex x 10 somevalue
set ttl [r ttl x] set ttl [r ttl x]
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment