Esempio n. 1
0
File: sync.go Progetto: vebin/reborn
func (h *Handler) doSyncFromMater(c *conn, counter *atomic2.Int64) error {
	c.authenticated = true

	lastACKTime := time.Now()
	for {
		readTotalSize := counter.Get()

		if _, err := c.handleRequest(h); err != nil {
			return errors.Trace(err)
		}

		if h.syncOffset.Get() != -1 {
			h.syncOffset.Add(counter.Get() - readTotalSize)

			n := time.Now()
			if n.Sub(lastACKTime) > time.Second {
				lastACKTime = n
				// this command has no reply
				if err := c.sendCommand("REPLCONF", "ACK", h.syncOffset.Get()); err != nil {
					log.Errorf("send REPLCONF ACK %d err - %s", h.syncOffset.Get(), err)
				}
			}
		}
	}

	return nil
}
Esempio n. 2
0
func (cmd *cmdDump) DumpRDBFile(reader *bufio.Reader, writer *bufio.Writer, nsize int64) {
	var nread atomic2.Int64
	wait := make(chan struct{})
	go func() {
		defer close(wait)
		p := make([]byte, WriterBufferSize)
		for nsize != nread.Get() {
			cnt := iocopy(reader, writer, p, int(nsize-nread.Get()))
			nread.Add(int64(cnt))
		}
		flushWriter(writer)
	}()

	for done := false; !done; {
		select {
		case <-wait:
			done = true
		case <-time.After(time.Second):
		}
		n := nread.Get()
		p := 100 * n / nsize
		log.Infof("total = %d - %12d [%3d%%]\n", nsize, n, p)
	}
	log.Info("dump: rdb done")
}
Esempio n. 3
0
func (s *testRedisRdbSuite) TestEncodeRdb(c *gocheck.C) {
	objs := make([]struct {
		db       uint32
		expireat uint64
		key      []byte
		obj      interface{}
		typ      string
	}, 128)
	var b bytes.Buffer
	enc := NewEncoder(&b)
	c.Assert(enc.EncodeHeader(), gocheck.IsNil)

	for i := 0; i < len(objs); i++ {
		db := uint32(i + 32)
		expireat := uint64(i)
		key := []byte(strconv.Itoa(i))
		var obj interface{}
		var typ string
		switch i % 5 {
		case 0:
			sss := strconv.Itoa(i)
			obj = sss
			typ = "string"
			c.Assert(enc.EncodeObject(db, key, expireat, s.toString(sss)), gocheck.IsNil)
		case 1:
			list := []string{}
			for j := 0; j < 32; j++ {
				list = append(list, fmt.Sprintf("l%d_%d", i, rand.Int()))
			}
			obj = list
			typ = "list"
			c.Assert(enc.EncodeObject(db, key, expireat, s.toList(list...)), gocheck.IsNil)
		case 2:
			hash := make(map[string]string)
			for j := 0; j < 32; j++ {
				hash[strconv.Itoa(j)] = fmt.Sprintf("h%d_%d", i, rand.Int())
			}
			obj = hash
			typ = "hash"
			c.Assert(enc.EncodeObject(db, key, expireat, s.toHash(hash)), gocheck.IsNil)
		case 3:
			zset := make(map[string]float64)
			for j := 0; j < 32; j++ {
				zset[strconv.Itoa(j)] = rand.Float64()
			}
			obj = zset
			typ = "zset"
			c.Assert(enc.EncodeObject(db, key, expireat, s.toZSet(zset)), gocheck.IsNil)
		case 4:
			set := []string{}
			for j := 0; j < 32; j++ {
				set = append(set, fmt.Sprintf("s%d_%d", i, rand.Int()))
			}
			obj = set
			typ = "set"
			c.Assert(enc.EncodeObject(db, key, expireat, s.toSet(set...)), gocheck.IsNil)
		}

		objs[i].db = db
		objs[i].expireat = expireat
		objs[i].key = key
		objs[i].obj = obj
		objs[i].typ = typ
	}

	c.Assert(enc.EncodeFooter(), gocheck.IsNil)

	rdb := b.Bytes()
	var cc atomic2.Int64
	l := NewLoader(ioutils.NewCountReader(bytes.NewReader(rdb), &cc))
	c.Assert(l.Header(), gocheck.IsNil)

	var i int = 0
	for {
		e, err := l.NextBinEntry()
		c.Assert(err, gocheck.IsNil)
		if e == nil {
			break
		}

		c.Assert(objs[i].db, gocheck.Equals, e.DB)
		c.Assert(objs[i].expireat, gocheck.Equals, e.ExpireAt)
		c.Assert(objs[i].key, gocheck.DeepEquals, e.Key)

		o, err := DecodeDump(e.Value)
		c.Assert(err, gocheck.IsNil)

		switch objs[i].typ {
		case "string":
			s.checkString(c, o, objs[i].obj.(string))
		case "list":
			s.checkList(c, o, objs[i].obj.([]string))
		case "hash":
			s.checkHash(c, o, objs[i].obj.(map[string]string))
		case "zset":
			s.checkZSet(c, o, objs[i].obj.(map[string]float64))
		case "set":
			s.checkSet(c, o, objs[i].obj.([]string))
		}
		i++
	}

	c.Assert(i, gocheck.Equals, len(objs))
	c.Assert(l.Footer(), gocheck.IsNil)
	c.Assert(cc.Get(), gocheck.DeepEquals, int64(len(rdb)))
}
Esempio n. 4
0
func (cmd *cmdRestore) RestoreCommand(reader *bufio.Reader, slave string, nsize int64) {
	var forward, nbypass atomic2.Int64
	c := openNetConn(slave)
	defer c.Close()

	writer := bufio.NewWriterSize(c, WriterBufferSize)
	defer flushWriter(writer)

	discard := bufio.NewReaderSize(c, ReaderBufferSize)

	go func() {
		var bypass bool = false
		for {
			resp := redis.MustDecode(reader)
			if cmd, args, err := redis.ParseArgs(resp); err != nil {
				log.PanicError(err, "parse command arguments failed")
			} else if cmd != "ping" {
				if cmd == "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 {
					nbypass.Incr()
					continue
				}
			}
			redis.MustEncode(writer, resp)
			flushWriter(writer)
			forward.Incr()
			redis.MustDecode(discard)
		}
	}()

	for {
		lastForward := forward.Get()
		lastByPass := nbypass.Get()
		time.Sleep(time.Second)
		log.Infof("restore: +forward=%-6d  +bypass=%-6d\n", forward.Get()-lastForward, nbypass.Get()-lastByPass)
	}
}
Esempio n. 5
0
func (cmd *cmdSync) SyncCommand(reader *bufio.Reader, slave string) {
	var forward, nbypass atomic2.Int64
	c := openNetConn(slave)
	defer c.Close()

	writer := bufio.NewWriterSize(c, WriterBufferSize)
	defer flushWriter(writer)

	go func() {
		p := make([]byte, ReaderBufferSize)
		for {
			cnt := iocopy(c, ioutil.Discard, p, len(p))
			cmd.nrecv.Add(int64(cnt))
		}
	}()

	var mu sync.Mutex
	go func() {
		for {
			time.Sleep(time.Second)
			mu.Lock()
			flushWriter(writer)
			mu.Unlock()
		}
	}()

	go func() {
		var bypass bool = false
		for {
			resp := redis.MustDecode(reader)
			if cmd, args, err := redis.ParseArgs(resp); err != nil {
				log.PanicError(err, "parse command arguments failed")
			} else if cmd != "ping" {
				if cmd == "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 {
					nbypass.Incr()
					continue
				}
			}
			mu.Lock()
			redis.MustEncode(writer, resp)
			mu.Unlock()
			forward.Incr()
		}
	}()

	for {
		lastForward := forward.Get()
		lastByPass := nbypass.Get()
		lastRead := cmd.nread.Get()
		lastRecv := cmd.nrecv.Get()
		time.Sleep(time.Second)
		log.Infof("sync: +forward=%-6d  +bypass=%-6d  +read=%-9d  +recv=%-9d\n", forward.Get()-lastForward, nbypass.Get()-lastByPass, cmd.nread.Get()-lastRead, cmd.nrecv.Get()-lastRecv)
	}
}
Esempio n. 6
0
File: sync.go Progetto: vebin/reborn
func (h *Handler) doSyncRDB(c *conn, size int64) error {
	defer h.counters.syncRdbRemains.Set(0)
	h.counters.syncRdbRemains.Set(size)

	r := ioutils.NewCountReader(c.r, nil)
	l := rdb.NewLoader(r)
	if err := l.Header(); err != nil {
		return err
	}

	ncpu := runtime.GOMAXPROCS(0)
	errs := make(chan error, ncpu)

	var lock sync.Mutex
	var flag atomic2.Int64
	loadNextEntry := func() (*rdb.BinEntry, error) {
		lock.Lock()
		defer lock.Unlock()
		if flag.Get() != 0 {
			return nil, nil
		}
		entry, err := l.NextBinEntry()
		if err != nil || entry == nil {
			flag.Set(1)
			return nil, err
		}
		return entry, nil
	}

	for i := 0; i < ncpu; i++ {
		go func() {
			defer flag.Set(1)
			for {
				entry, err := loadNextEntry()
				if err != nil || entry == nil {
					errs <- err
					return
				}
				db, key, value := entry.DB, entry.Key, entry.Value
				ttlms := int64(0)
				if entry.ExpireAt != 0 {
					if v, ok := store.ExpireAtToTTLms(int64(entry.ExpireAt)); ok && v > 0 {
						ttlms = v
					} else {
						ttlms = 1
					}
				}
				if err := c.Store().SlotsRestore(db, [][]byte{key, store.FormatInt(ttlms), value}); err != nil {
					errs <- err
					return
				}
			}
		}()
	}

	for {
		select {
		case <-time.After(time.Second):
			h.counters.syncRdbRemains.Set(size - r.Count())
		case err := <-errs:
			for i := 1; i < cap(errs); i++ {
				e := <-errs
				if err == nil && e != nil {
					err = e
				}
			}
			if err != nil {
				return err
			}
			return l.Footer()
		}
	}
}
Esempio n. 7
0
func TestEncodeRdb(t *testing.T) {
	objs := make([]struct {
		db       uint32
		expireat uint64
		key      []byte
		obj      interface{}
		typ      string
	}, 128)
	var b bytes.Buffer
	enc := NewEncoder(&b)
	assert.ErrorIsNil(t, enc.EncodeHeader())
	for i := 0; i < len(objs); i++ {
		db := uint32(i + 32)
		expireat := uint64(i)
		key := []byte(strconv.Itoa(i))
		var obj interface{}
		var typ string
		switch i % 5 {
		case 0:
			s := strconv.Itoa(i)
			obj = s
			typ = "string"
			assert.ErrorIsNil(t, enc.EncodeObject(db, key, expireat, toString(s)))
		case 1:
			list := []string{}
			for j := 0; j < 32; j++ {
				list = append(list, fmt.Sprintf("l%d_%d", i, rand.Int()))
			}
			obj = list
			typ = "list"
			assert.ErrorIsNil(t, enc.EncodeObject(db, key, expireat, toList(list...)))
		case 2:
			hash := make(map[string]string)
			for j := 0; j < 32; j++ {
				hash[strconv.Itoa(j)] = fmt.Sprintf("h%d_%d", i, rand.Int())
			}
			obj = hash
			typ = "hash"
			assert.ErrorIsNil(t, enc.EncodeObject(db, key, expireat, toHash(hash)))
		case 3:
			zset := make(map[string]float64)
			for j := 0; j < 32; j++ {
				zset[strconv.Itoa(j)] = rand.Float64()
			}
			obj = zset
			typ = "zset"
			assert.ErrorIsNil(t, enc.EncodeObject(db, key, expireat, toZSet(zset)))
		case 4:
			set := []string{}
			for j := 0; j < 32; j++ {
				set = append(set, fmt.Sprintf("s%d_%d", i, rand.Int()))
			}
			obj = set
			typ = "set"
			assert.ErrorIsNil(t, enc.EncodeObject(db, key, expireat, toSet(set...)))
		}
		objs[i].db = db
		objs[i].expireat = expireat
		objs[i].key = key
		objs[i].obj = obj
		objs[i].typ = typ
	}
	assert.ErrorIsNil(t, enc.EncodeFooter())
	rdb := b.Bytes()
	var c atomic2.Int64
	l := NewLoader(ioutils.NewCountReader(bytes.NewReader(rdb), &c))
	assert.ErrorIsNil(t, l.Header())
	var i int = 0
	for {
		e, err := l.NextBinEntry()
		assert.ErrorIsNil(t, err)
		if e == nil {
			break
		}
		assert.Must(t, objs[i].db == e.DB)
		assert.Must(t, objs[i].expireat == e.ExpireAt)
		assert.Must(t, bytes.Equal(objs[i].key, e.Key))
		o, err := DecodeDump(e.Value)
		assert.ErrorIsNil(t, err)
		switch objs[i].typ {
		case "string":
			checkString(t, o, objs[i].obj.(string))
		case "list":
			checkList(t, o, objs[i].obj.([]string))
		case "hash":
			checkHash(t, o, objs[i].obj.(map[string]string))
		case "zset":
			checkZSet(t, o, objs[i].obj.(map[string]float64))
		case "set":
			checkSet(t, o, objs[i].obj.([]string))
		}
		i++
	}
	assert.Must(t, i == len(objs))
	assert.ErrorIsNil(t, l.Footer())
	assert.Must(t, c.Get() == int64(len(rdb)))
}