redis-shake工具
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

84 lines
2.5 KiB

package writer
import (
"bytes"
"github.com/alibaba/RedisShake/internal/client"
"github.com/alibaba/RedisShake/internal/client/proto"
"github.com/alibaba/RedisShake/internal/config"
"github.com/alibaba/RedisShake/internal/entry"
"github.com/alibaba/RedisShake/internal/log"
"github.com/alibaba/RedisShake/internal/statistics"
"strconv"
"sync/atomic"
"time"
)
type redisWriter struct {
client *client.Redis
DbId int
cmdBuffer *bytes.Buffer
chWaitReply chan *entry.Entry
UpdateUnansweredBytesCount uint64 // have sent in bytes
}
2 years ago
func NewRedisWriter(address string, username string, password string, isTls bool) Writer {
rw := new(redisWriter)
2 years ago
rw.client = client.NewRedisClient(address, username, password, isTls)
log.Infof("redisWriter connected to redis successful. address=[%s]", address)
rw.cmdBuffer = new(bytes.Buffer)
rw.chWaitReply = make(chan *entry.Entry, config.Config.Advanced.PipelineCountLimit)
go rw.flushInterval()
return rw
}
func (w *redisWriter) Write(e *entry.Entry) {
// switch db if we need
if w.DbId != e.DbId {
w.switchDbTo(e.DbId)
}
// send
w.cmdBuffer.Reset()
client.EncodeArgv(e.Argv, w.cmdBuffer)
e.EncodedSize = uint64(w.cmdBuffer.Len())
for e.EncodedSize+atomic.LoadUint64(&w.UpdateUnansweredBytesCount) > config.Config.Advanced.TargetRedisClientMaxQuerybufLen {
time.Sleep(1 * time.Nanosecond)
}
w.chWaitReply <- e
atomic.AddUint64(&w.UpdateUnansweredBytesCount, e.EncodedSize)
w.client.SendBytes(w.cmdBuffer.Bytes())
}
func (w *redisWriter) switchDbTo(newDbId int) {
w.client.Send("select", strconv.Itoa(newDbId))
w.DbId = newDbId
}
func (w *redisWriter) flushInterval() {
for {
select {
case e := <-w.chWaitReply:
reply, err := w.client.Receive()
if err == proto.Nil {
log.Warnf("redisWriter receive nil reply. argv=%v", e.Argv)
} else if err != nil {
if err.Error() == "BUSYKEY Target key name already exists." {
if config.Config.Advanced.RDBRestoreCommandBehavior == "skip" {
log.Warnf("redisWriter received BUSYKEY reply. argv=%v", e.Argv)
} else if config.Config.Advanced.RDBRestoreCommandBehavior == "panic" {
log.Panicf("redisWriter received BUSYKEY reply. argv=%v", e.Argv)
}
} else {
log.Panicf("redisWriter received error. error=[%v], argv=%v, slots=%v, reply=[%v]", err, e.Argv, e.Slots, reply)
}
}
atomic.AddUint64(&w.UpdateUnansweredBytesCount, ^(e.EncodedSize - 1))
statistics.UpdateEntryId(e.Id)
statistics.UpdateAOFAppliedOffset(e.Offset)
statistics.UpdateUnansweredBytesCount(atomic.LoadUint64(&w.UpdateUnansweredBytesCount))
}
}
}