コード例 #1
0
ファイル: restore.go プロジェクト: left2right/redis-port
func (cmd *cmdRestore) RestoreRDBFile(reader *bufio.Reader, target, passwd string, nsize int64) {
	pipe := newRDBLoader(reader, &cmd.rbytes, args.parallel*32)
	wait := make(chan struct{})
	go func() {
		defer close(wait)
		group := make(chan int, args.parallel)
		for i := 0; i < cap(group); i++ {
			go func() {
				defer func() {
					group <- 0
				}()
				c := openRedisConn(target, passwd)
				defer c.Close()
				var lastdb uint32 = 0
				for e := range pipe {
					if !acceptDB(e.DB) || !acceptKey(e.Key) {
						cmd.ignore.Incr()
					} else if skipKey(e.Key) {
						log.Warnf("restore skip key: %s", e.Key)
						cmd.ignore.Incr()
					} else {
						cmd.nentry.Incr()
						if e.DB != lastdb {
							lastdb = e.DB
							selectDB(c, lastdb)
						}
						restoreRdbEntry(c, e)
					}
				}
			}()
		}
		for i := 0; i < cap(group); i++ {
			<-group
		}
	}()

	for done := false; !done; {
		select {
		case <-wait:
			done = true
		case <-time.After(time.Second):
		}
		stat := cmd.Stat()
		var b bytes.Buffer
		if nsize != 0 {
			fmt.Fprintf(&b, "total = %d - %12d [%3d%%]", nsize, stat.rbytes, 100*stat.rbytes/nsize)
		} else {
			fmt.Fprintf(&b, "total = %12d", stat.rbytes)
		}
		fmt.Fprintf(&b, "  entry=%-12d", stat.nentry)
		if stat.ignore != 0 {
			fmt.Fprintf(&b, "  ignore=%-12d", stat.ignore)
		}
		log.Info(b.String())
	}
	log.Info("restore: rdb done")
}
コード例 #2
0
ファイル: sync.go プロジェクト: left2right/redis-port
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
	}
}
コード例 #3
0
ファイル: utils.go プロジェクト: left2right/redis-port
func restoreRdbEntry(c redigo.Conn, e *rdb.BinEntry) {
	var ttlms uint64
	if e.ExpireAt != 0 {
		now := uint64(time.Now().Add(args.shift).UnixNano())
		now /= uint64(time.Millisecond)
		if now >= e.ExpireAt {
			ttlms = 1
		} else {
			ttlms = e.ExpireAt - now
		}
	}

	toText := func(p []byte) string {
		var b bytes.Buffer
		for _, c := range p {
			switch {
			case c >= '#' && c <= '~':
				b.WriteByte(c)
			default:
				b.WriteByte('.')
			}
		}
		return b.String()
	}

	if aggregateKey(e.Key) {
		log.Infof("Aggregate key %s", e.Key)
		o, err := rdb.DecodeDump(e.Value)
		if err != nil {
			log.PanicError(err, "decode failed")
		}
		switch obj := o.(type) {
		default:
			log.Panicf("unknown object %v", o)
		case rdb.List:
			for _, ele := range obj {
				_, err := c.Do(aggregateCmd, aggregateTarget, toText(ele))
				if err != nil {
					log.PanicError(err, "aggregate error")
				}
			}
		case rdb.Set:
			for _, ele := range obj {
				_, err := c.Do(aggregateCmd, aggregateTarget, toText(ele))
				if err != nil {
					log.PanicError(err, "aggregate error")
				}
			}
		}
	}

	if set2sortedKey(e.Key) {
		o, err := rdb.DecodeDump(e.Value)
		if err != nil {
			log.PanicError(err, "decode failed")
		}
		switch obj := o.(type) {
		default:
			log.Panicf("set2sorted key %s type is not set err", e.Key)
			log.Panicf("unknown object %v", o)
		case rdb.Set:
			for _, ele := range obj {
				_, err := c.Do("zadd", e.Key, 1, toText(ele))
				if err != nil {
					log.PanicErrorf(err, "set2sorted zadd %s 1 %s", e.Key, toText(ele))
				}
			}
		}
		return
	}

	if sorted2setKey(e.Key) {
		o, err := rdb.DecodeDump(e.Value)
		if err != nil {
			log.PanicError(err, "decode failed")
		}
		switch obj := o.(type) {
		default:
			log.Panicf("sorted2set key %s type is not sorted set err", e.Key)
		case rdb.ZSet:
			for _, ele := range obj {
				_, err := c.Do("sadd", e.Key, toText(ele.Member))
				if err != nil {
					log.PanicErrorf(err, "sorted2set sadd %s %s", e.Key, toText(ele.Member))
				}
			}
		}
		return
	}

	if (restoreCmd == "del") || (restoreCmd == "DEL") {
		_, err := redigo.String(c.Do(restoreCmd, e.Key))
		if err != nil {
			log.Warnf("delete key: '%s'", e.Key)
		}
	} else {
		s, err := redigo.String(c.Do(restoreCmd, e.Key, ttlms, e.Value))

		if err != nil {
			log.Warnf("restore error, when '%s' '%s'", restoreCmd, e.Key)
			//log.PanicError(err, "restore command error")
		}
		if s != "OK" {
			//log.Panicf("restore command response = '%s', should be 'OK'", s)
			log.Warnf("restore command response = '%s', should be 'OK'", s)
		}
	}
}
コード例 #4
0
ファイル: restore.go プロジェクト: left2right/redis-port
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
	}
}