-
Notifications
You must be signed in to change notification settings - Fork 156
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
513 additions
and
257 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package common | ||
|
||
import ( | ||
redigoCluster "github.com/vinllen/redis-go-cluster" | ||
redigo "github.com/garyburd/redigo/redis" | ||
) | ||
|
||
const( | ||
RecvChanSize = 4096 | ||
) | ||
|
||
/* implement redigo.Conn(https://github.com/garyburd/redigo) | ||
* Embed redis-go-cluster(https://github.com/chasex/redis-go-cluster) | ||
* The reason I create this struct is that redis-go-cluster isn't fulfill redigo.Conn | ||
* interface. So I implement "Err", "Send", "Flush" and "Receive" interfaces. | ||
*/ | ||
type ClusterConn struct { | ||
client *redigoCluster.Cluster | ||
recvChan chan reply | ||
batcher *redigoCluster.Batch | ||
} | ||
|
||
type reply struct { | ||
answer interface{} | ||
err error | ||
} | ||
|
||
func NewClusterConn(clusterClient *redigoCluster.Cluster, recvChanSize int) redigo.Conn { | ||
if recvChanSize == 0 { | ||
recvChanSize = RecvChanSize | ||
} | ||
|
||
return &ClusterConn{ | ||
client: clusterClient, | ||
recvChan: make(chan reply, recvChanSize), | ||
} | ||
} | ||
|
||
func (cc *ClusterConn) Close() error { | ||
cc.client.Close() | ||
return nil | ||
} | ||
|
||
func (cc *ClusterConn) Err() error { | ||
return nil | ||
} | ||
|
||
func (cc *ClusterConn) Do(commandName string, args ...interface{}) (reply interface{}, err error) { | ||
return cc.client.Do(commandName, args...) | ||
} | ||
|
||
// just add into batcher | ||
func (cc *ClusterConn) Send(commandName string, args ...interface{}) error { | ||
if cc.batcher == nil { | ||
cc.batcher = cc.client.NewBatch() | ||
} | ||
return cc.batcher.Put(commandName, args...) | ||
} | ||
|
||
// send batcher and put the return into recvChan | ||
func (cc *ClusterConn) Flush() error { | ||
ret, err := cc.client.RunBatch(cc.batcher) | ||
defer func() { | ||
cc.batcher = nil // reset batcher | ||
}() | ||
|
||
if err != nil { | ||
cc.recvChan <- reply{ | ||
answer: nil, | ||
err: err, | ||
} | ||
|
||
return err | ||
} | ||
|
||
// for redis-go-cluster driver, "Receive" function returns all the replies once flushed. | ||
// However, this action is different with redigo driver that "Receive" only returns 1 | ||
// reply each time. | ||
|
||
retLength := len(ret) | ||
availableSize := cap(cc.recvChan) - len(cc.recvChan) | ||
if availableSize < retLength { | ||
Logger.Warnf("available channel size[%v] less than current returned batch size[%v]", availableSize, retLength) | ||
} | ||
// Logger.Debugf("cluster flush batch with size[%v], return replies size[%v]", cc.batcher.GetBatchSize(), retLength) | ||
|
||
for _, ele := range ret { | ||
cc.recvChan <- reply{ | ||
answer: ele, | ||
err: err, | ||
} | ||
} | ||
|
||
return err | ||
} | ||
|
||
// read recvChan | ||
func (cc *ClusterConn) Receive() (reply interface{}, err error) { | ||
ret := <- cc.recvChan | ||
return ret.answer, ret.err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,30 @@ | ||
package conf | ||
|
||
var Opts struct { | ||
SourceAddr string `short:"s" long:"source" value-name:"SOURCE" description:"Set host:port of source redis."` | ||
SourcePassword string `short:"p" long:"sourcepassword" value-name:"Password" description:"Set source redis password"` | ||
SourceAuthType string `long:"sourceauthtype" value-name:"AUTH-TYPE" default:"auth" description:"useless for opensource redis, valid value:auth/adminauth" ` | ||
SourceDBType int `long:"sourcedbtype" default:"0" description:"0: db, 1: aliyun proxy, 2: tencent proxy"` | ||
TargetAddr string `short:"t" long:"target" value-name:"TARGET" description:"Set host:port of target redis."` | ||
TargetPassword string `short:"a" long:"targetpassword" value-name:"Password" description:"Set target redis password"` | ||
TargetAuthType string `long:"targetauthtype" value-name:"AUTH-TYPE" default:"auth" description:"useless for opensource redis, valid value:auth/adminauth" ` | ||
// TargetDBType int `long:"targetdbtype" default:"1" description:"1: db, 2: aliyun proxy 3: tencent proxy"` | ||
ResultDBFile string `short:"d" long:"db" value-name:"Sqlite3-DB-FILE" default:"result.db" description:"sqlite3 db file for store result. If exist, it will be removed and a new file is created."` | ||
CompareTimes string `long:"comparetimes" value-name:"COUNT" default:"3" description:"Total compare count, at least 1. In the first round, all keys will be compared. The subsequent rounds of the comparison will be done on the previous results."` | ||
CompareMode int `short:"m" long:"comparemode" default:"2" description:"compare mode, 1: compare full value, 2: only compare value length, 3: only compare keys outline, 4: compare full value, but only compare value length when meets big key"` | ||
Id string `long:"id" default:"unknown" description:"used in metric, run id"` | ||
JobId string `long:"jobid" default:"unknown" description:"used in metric, job id"` | ||
TaskId string `long:"taskid" default:"unknown" description:"used in metric, task id"` | ||
Qps int `short:"q" long:"qps" default:"15000" description:"max batch qps limit: e.g., if qps is 10, full-check fetches 10 * $batch keys every second"` | ||
Interval int `long:"interval" value-name:"Second" default:"5" description:"The time interval for each round of comparison(Second)"` | ||
BatchCount string `long:"batchcount" value-name:"COUNT" default:"256" description:"the count of key/field per batch compare, valid value [1, 10000]"` | ||
Parallel int `long:"parallel" value-name:"COUNT" default:"5" description:"concurrent goroutine number for comparison, valid value [1, 100]"` | ||
LogFile string `long:"log" value-name:"FILE" description:"log file, if not specified, log is put to console"` | ||
ResultFile string `long:"result" value-name:"FILE" description:"store all diff result, format is 'db\tdiff-type\tkey\tfield'"` | ||
MetricPrint bool `long:"metric" value-name:"BOOL" description:"print metric in log"` | ||
BigKeyThreshold int64 `long:"bigkeythreshold" value-name:"COUNT" default:"16384"` | ||
FilterList string `short:"f" long:"filterlist" value-name:"FILTER" default:"" description:"if the filter list isn't empty, all elements in list will be synced. The input should be split by '|'. The end of the string is followed by a * to indicate a prefix match, otherwise it is a full match. e.g.: 'abc*|efg|m*' matches 'abc', 'abc1', 'efg', 'm', 'mxyz', but 'efgh', 'p' aren't'"` | ||
Version bool `short:"v" long:"version"` | ||
SourceAddr string `short:"s" long:"source" value-name:"SOURCE" description:"Set host:port of source redis. If db type is cluster, split by semicolon(;'), e.g., 10.1.1.1:1000;10.2.2.2:2000;10.3.3.3:3000. Only need to give a role in the master or slave."` | ||
SourcePassword string `short:"p" long:"sourcepassword" value-name:"Password" description:"Set source redis password"` | ||
SourceAuthType string `long:"sourceauthtype" value-name:"AUTH-TYPE" default:"auth" description:"useless for opensource redis, valid value:auth/adminauth" ` | ||
SourceDBType int `long:"sourcedbtype" default:"0" description:"0: db, 1: cluster 2: aliyun proxy, 3: tencent proxy"` | ||
SourceDBFilterList string `long:"sourcedbfilterlist" default:"-1" description:"db white list that need to be compared, -1 means fetch all, \"0;5;15\" means fetch db 0, 5, and 15"` | ||
TargetAddr string `short:"t" long:"target" value-name:"TARGET" description:"Set host:port of target redis. If db type is cluster, split by semicolon(;'), e.g., 10.1.1.1:1000;10.2.2.2:2000;10.3.3.3:3000. Only need to give a role in the master or slave."` | ||
TargetPassword string `short:"a" long:"targetpassword" value-name:"Password" description:"Set target redis password"` | ||
TargetAuthType string `long:"targetauthtype" value-name:"AUTH-TYPE" default:"auth" description:"useless for opensource redis, valid value:auth/adminauth" ` | ||
TargetDBType int `long:"targetdbtype" default:"0" description:"0: db, 1: cluster 2: aliyun proxy 3: tencent proxy"` | ||
TargetDBFilterList string `long:"targetdbfilterlist" default:"-1" description:"db white list that need to be compared, -1 means fetch all, \"0;5;15\" means fetch db 0, 5, and 15"` | ||
ResultDBFile string `short:"d" long:"db" value-name:"Sqlite3-DB-FILE" default:"result.db" description:"sqlite3 db file for store result. If exist, it will be removed and a new file is created."` | ||
CompareTimes string `long:"comparetimes" value-name:"COUNT" default:"3" description:"Total compare count, at least 1. In the first round, all keys will be compared. The subsequent rounds of the comparison will be done on the previous results."` | ||
CompareMode int `short:"m" long:"comparemode" default:"2" description:"compare mode, 1: compare full value, 2: only compare value length, 3: only compare keys outline, 4: compare full value, but only compare value length when meets big key"` | ||
Id string `long:"id" default:"unknown" description:"used in metric, run id"` | ||
JobId string `long:"jobid" default:"unknown" description:"used in metric, job id"` | ||
TaskId string `long:"taskid" default:"unknown" description:"used in metric, task id"` | ||
Qps int `short:"q" long:"qps" default:"15000" description:"max batch qps limit: e.g., if qps is 10, full-check fetches 10 * $batch keys every second"` | ||
Interval int `long:"interval" value-name:"Second" default:"5" description:"The time interval for each round of comparison(Second)"` | ||
BatchCount string `long:"batchcount" value-name:"COUNT" default:"256" description:"the count of key/field per batch compare, valid value [1, 10000]"` | ||
Parallel int `long:"parallel" value-name:"COUNT" default:"5" description:"concurrent goroutine number for comparison, valid value [1, 100]"` | ||
LogFile string `long:"log" value-name:"FILE" description:"log file, if not specified, log is put to console"` | ||
ResultFile string `long:"result" value-name:"FILE" description:"store all diff result, format is 'db\tdiff-type\tkey\tfield'"` | ||
MetricPrint bool `long:"metric" value-name:"BOOL" description:"print metric in log"` | ||
BigKeyThreshold int64 `long:"bigkeythreshold" value-name:"COUNT" default:"16384"` | ||
FilterList string `short:"f" long:"filterlist" value-name:"FILTER" default:"" description:"if the filter list isn't empty, all elements in list will be synced. The input should be split by '|'. The end of the string is followed by a * to indicate a prefix match, otherwise it is a full match. e.g.: 'abc*|efg|m*' matches 'abc', 'abc1', 'efg', 'm', 'mxyz', but 'efgh', 'p' aren't'"` | ||
Version bool `short:"v" long:"version"` | ||
} |
Oops, something went wrong.