func (cmd *cmdSync) SyncCommand(reader *bufio.Reader, target, passwd string) { c := openNetConn(target, passwd) defer c.Close() cr := openRedisConn(target, passwd) defer cr.Close() writer := bufio.NewWriterSize(stats.NewCountWriter(c, &cmd.wbytes), WriterBufferSize) defer flushWriter(writer) go func() { p := make([]byte, ReaderBufferSize) for { iocopy(c, ioutil.Discard, p, len(p)) } }() go func() { var bypass bool = false for { resp := redis.MustDecode(reader) if scmd, args, err := redis.ParseArgs(resp); err != nil { log.PanicError(err, "parse command arguments failed") } else if scmd != "ping" { if scmd == "select" { if len(args) != 1 { log.Panicf("select command len(args) = %d", len(args)) } s := string(args[0]) n, err := parseInt(s, MinDB, MaxDB) if err != nil { log.PanicErrorf(err, "parse db = %s failed", s) } bypass = !acceptDB(uint32(n)) } if bypass || (len(args) > 0 && !acceptKey(args[0])) { cmd.nbypass.Incr() continue } if skipKey(args[0]) { log.Warnf("skip key: %s", args[0]) cmd.ignore.Incr() continue } if aggregateKey(args[0]) && ((scmd == "lpush") || (scmd == "LPUSH")) { log.Infof("Aggregate Key %s", args[0]) for i := 1; i < len(args); i++ { _, err := cr.Do(aggregateCmd, aggregateTarget, args[i]) if err != nil { log.Warnf("SyncAggregate err at: %s %s", args[0], args[i]) //log.PanicError(err, "sync aggregate error") } } } // set 2 sorted set in sync command if set2sortedKey(args[0]) { switch scmd { default: log.Panicf("set2sorted operate %s on key %s err", scmd, args[0]) case "sadd": for i := 1; i < len(args); i++ { _, err := cr.Do("zadd", args[0], 1, args[i]) if err != nil { log.PanicErrorf(err, "set2sorted zadd %s 1 %s", args[0], args[i]) } } case "srem": for i := 1; i < len(args); i++ { _, err := cr.Do("zrem", args[0], args[i]) if err != nil { log.PanicErrorf(err, "set2sorted zrem %s %s", args[0], args[i]) } } case "del": _, err := cr.Do("del", args[0]) if err != nil { log.PanicErrorf(err, "set2sorted del %s", args[0]) } } continue } if sorted2setKey(args[0]) { switch scmd { default: log.Panicf("sorted2set operate %s on key %s err", scmd, args[0]) case "zadd": for i := 1; i < len(args); i++ { if string(args[i]) != "1" { _, err := cr.Do("sadd", args[0], args[i]) if err != nil { log.PanicErrorf(err, "sorted2set sadd %s %s", args[0], args[i]) } } else { continue } } case "zrem": for i := 1; i < len(args); i++ { _, err := cr.Do("srem", args[0], args[i]) if err != nil { log.PanicErrorf(err, "sorted2set srem %s %s", args[0], args[i]) } } case "del": _, err := cr.Do("del", args[0]) if err != nil { log.PanicErrorf(err, "sorted2set del %s", args[0]) } } continue } // Some commands like MSET may have multi keys, but we only use // first for filter } cmd.forward.Incr() redis.MustEncode(writer, resp) flushWriter(writer) } }() for lstat := cmd.Stat(); ; { time.Sleep(time.Second) nstat := cmd.Stat() var b bytes.Buffer fmt.Fprintf(&b, "sync: ") fmt.Fprintf(&b, " +forward=%-6d", nstat.forward-lstat.forward) fmt.Fprintf(&b, " +nbypass=%-6d", nstat.nbypass-lstat.nbypass) fmt.Fprintf(&b, " +nbytes=%d", nstat.wbytes-lstat.wbytes) log.Info(b.String()) lstat = nstat } }
func (cmd *cmdRestore) RestoreCommand(reader *bufio.Reader, target, passwd string) { c := openNetConn(target, passwd) defer c.Close() writer := bufio.NewWriterSize(c, WriterBufferSize) defer flushWriter(writer) go func() { p := make([]byte, ReaderBufferSize) for { iocopy(c, ioutil.Discard, p, len(p)) } }() go func() { var bypass bool = false for { resp := redis.MustDecode(reader) if scmd, args, err := redis.ParseArgs(resp); err != nil { log.PanicError(err, "parse command arguments failed") } else if scmd != "ping" { if scmd == "select" { if len(args) != 1 { log.Panicf("select command len(args) = %d", len(args)) } s := string(args[0]) n, err := parseInt(s, MinDB, MaxDB) if err != nil { log.PanicErrorf(err, "parse db = %s failed", s) } bypass = !acceptDB(uint32(n)) } if skipKey(args[0]) { log.Warnf("skip key: %s", args[0]) cmd.ignore.Incr() continue } if bypass || (len(args) > 0 && !acceptKey(args[0])) { cmd.nbypass.Incr() continue } // added for aggregating list or set if aggregateKey(args[0]) { cr := openRedisConn(target, passwd) defer cr.Close() for i := 1; i < len(args); i++ { _, err := cr.Do(aggregateCmd, aggregateTarget, args[i]) if err != nil { log.PanicError(err, "restore aggregate error") } } } } cmd.forward.Incr() redis.MustEncode(writer, resp) flushWriter(writer) } }() for lstat := cmd.Stat(); ; { time.Sleep(time.Second) nstat := cmd.Stat() var b bytes.Buffer fmt.Fprintf(&b, "restore: ") fmt.Fprintf(&b, " +forward=%-6d", nstat.forward-lstat.forward) fmt.Fprintf(&b, " +nbypass=%-6d", nstat.nbypass-lstat.nbypass) log.Info(b.String()) lstat = nstat } }