func (c *conn) ping() error { deadline := time.Now().Add(time.Second * 5) if err := c.nc.SetDeadline(deadline); err != nil { return errors.Trace(err) } if _, err := c.w.WriteString("*1\r\n$4\r\nping\r\n"); err != nil { return errors.Trace(err) } if err := c.w.Flush(); err != nil { return errors.Trace(err) } var rsp string for !strings.HasSuffix(rsp, "\r\n") { b := []byte{0} if _, err := c.r.Read(b); err != nil { return errors.Trace(err) } if len(rsp) == 0 && b[0] == '\n' { continue } rsp += string(b) } rsp = rsp[:len(rsp)-2] if strings.ToLower(rsp) != "+pong" { return errors.Errorf("invalid response of command ping: %s", rsp) } else { return nil } }
func (e *Encoder) EncodeObject(db uint32, key []byte, expireat uint64, obj interface{}) error { o, ok := obj.(objectEncoder) if !ok { return errors.Errorf("unsupported object type") } if e.db == -1 || uint32(e.db) != db { e.db = int64(db) if err := e.enc.EncodeDatabase(int(db)); err != nil { return errors.Trace(err) } } if expireat != 0 { if err := e.enc.EncodeExpiry(expireat); err != nil { return errors.Trace(err) } } if err := o.encodeType(e.enc); err != nil { return err } if err := e.enc.EncodeString(key); err != nil { return errors.Trace(err) } if err := o.encodeValue(e.enc); err != nil { return err } return nil }
func loadRpdbRow(r rpdbReader, db uint32, key []byte) (rpdbRow, error) { metaKey := EncodeMetaKey(db, key) p, err := r.getRowValue(metaKey) if err != nil || p == nil { return nil, err } if len(p) == 0 { return nil, errors.Trace(ErrObjectCode) } var o rpdbRow var code = ObjectCode(p[0]) switch code { default: return nil, errors.Trace(ErrObjectCode) case StringCode: o = new(stringRow) case HashCode: o = new(hashRow) case ListCode: o = new(listRow) case ZSetCode: o = new(zsetRow) case SetCode: o = new(setRow) } o.lazyInit(&rpdbRowHelper{ code: code, metaKey: metaKey, dataKeyPrefix: EncodeDataKeyPrefix(db, key), }) return o, o.ParseMetaValue(p) }
func (e *encoder) encodeText(s string) error { if _, err := e.w.WriteString(s); err != nil { return errors.Trace(err) } if _, err := e.w.WriteString("\r\n"); err != nil { return errors.Trace(err) } return nil }
func (o Set) encodeValue(enc *rdb.Encoder) error { if err := enc.EncodeLength(uint32(len(o))); err != nil { return errors.Trace(err) } for _, e := range o { if err := enc.EncodeString(e); err != nil { return errors.Trace(err) } } return nil }
func (d *decoder) decodeText() (string, error) { b, err := d.r.ReadBytes('\n') if err != nil { return "", errors.Trace(err) } if n := len(b) - 2; n < 0 || b[n] != '\r' { return "", errors.Trace(ErrBadRespCRLFEnd) } else { return string(b[:n]), nil } }
func (p *fileBuffer) writeSome(b []byte) (int, error) { if p.f == nil { return 0, errors.Trace(ErrClosedBacklog) } maxlen, offset := woffset(len(b), p.size, p.wpos) if maxlen == 0 { return 0, nil } n, err := p.f.WriteAt(b[:maxlen], int64(offset)) p.wpos += uint64(n) return n, errors.Trace(err) }
func (p *memBuffer) readSomeAt(b []byte, rpos uint64) (int, error) { if p.b == nil { return 0, errors.Trace(ErrClosedBacklog) } if rpos > p.wpos || rpos+p.size < p.wpos { return 0, errors.Trace(ErrInvalidOffset) } maxlen, offset := roffset(len(b), p.size, rpos, p.wpos) if maxlen == 0 { return 0, nil } n := copy(b, p.b[offset:offset+maxlen]) return n, nil }
func (db *RocksDB) Clear() error { if db.rkdb != nil { db.rkdb.Close() db.rkdb = nil db.opts.SetCreateIfMissing(true) db.opts.SetErrorIfExists(true) if err := gorocks.DestroyDatabase(db.path, db.opts); err != nil { return errors.Trace(err) } else if db.rkdb, err = gorocks.Open(db.path, db.opts); err != nil { return errors.Trace(err) } } return nil }
func (p *fileBuffer) readSomeAt(b []byte, rpos uint64) (int, error) { if p.f == nil { return 0, errors.Trace(ErrClosedBacklog) } if rpos > p.wpos || rpos+p.size < p.wpos { return 0, errors.Trace(ErrInvalidOffset) } maxlen, offset := roffset(len(b), p.size, rpos, p.wpos) if maxlen == 0 { return 0, nil } n, err := p.f.ReadAt(b[:maxlen], int64(offset)) return n, errors.Trace(err) }
func Serve(config *Config, bl *rpdb.Rpdb) error { h := &Handler{ config: config, master: make(chan *conn, 0), signal: make(chan int, 0), } defer func() { close(h.signal) }() l, err := net.Listen("tcp", config.Listen) if err != nil { return errors.Trace(err) } defer l.Close() if h.htable, err = redis.NewHandlerTable(h); err != nil { return err } else { go h.daemonSyncMaster() } log.Infof("open listen address '%s' and start service", l.Addr()) for { if nc, err := l.Accept(); err != nil { return errors.Trace(err) } else { h.counters.clientsAccepted.Add(1) go func() { h.counters.clients.Add(1) defer h.counters.clients.Sub(1) c := newConn(nc, bl, h.config.ConnTimeout) defer c.Close() log.Infof("new connection: %s", c.summ) if err := c.serve(h); err != nil { if errors.Equal(err, io.EOF) { log.Infof("connection lost: %s [io.EOF]", c.summ) } else { log.InfoErrorf(err, "connection lost: %s", c.summ) } } else { log.Infof("connection exit: %s", c.summ) } }() } } }
func decodeRawBytes(r *BufReader, err error, refs ...interface{}) error { if err != nil { return err } if len(refs) == 0 { if r.Len() != 0 { return errors.Trace(ErrNotMatched) } return nil } for _, i := range refs { switch x := i.(type) { case byte: if v, err := r.ReadByte(); err != nil { return err } else if v != x { return errors.Errorf("read byte %d, expect %d", v, x) } case ObjectCode: if v, err := r.ReadByte(); err != nil { return err } else if v != byte(x) { return errors.Errorf("read code [%s], expect [%s]", ObjectCode(v), x) } case *[]byte: p, err := r.ReadVarbytes() if err != nil { return err } *x = p case *uint32: v, err := r.ReadUvarint() if err != nil { return err } *x = uint32(v) case *uint64: v, err := r.ReadUvarint() if err != nil { return err } *x = v case *int64: v, err := r.ReadVarint() if err != nil { return err } *x = v case *float64: v, err := r.ReadFloat64() if err != nil { return err } *x = v default: log.Panicf("unsupported type in row value: %+v", x) } } return nil }
func (e *encoder) encodeBulkBytes(b []byte) error { if b == nil { return e.encodeInt(-1) } else { if err := e.encodeInt(int64(len(b))); err != nil { return err } if _, err := e.w.Write(b); err != nil { return errors.Trace(err) } if _, err := e.w.WriteString("\r\n"); err != nil { return errors.Trace(err) } return nil } }
func DecodeDump(p []byte) (interface{}, error) { d := &decoder{} if err := rdb.DecodeDump(p, 0, nil, 0, d); err != nil { return nil, errors.Trace(err) } return d.obj, d.err }
func ParseFloat(i interface{}) (float64, error) { var s string switch x := Num64(i).(type) { case int64: return float64(x), nil case uint64: return float64(x), nil case float64: switch { case math.IsNaN(x): return 0, errors.New("float is NaN") case math.IsInf(x, 0): return 0, errors.New("float is Inf") } return float64(x), nil case string: s = x case []byte: s = string(x) default: s = fmt.Sprint(x) } f, err := strconv.ParseFloat(s, 64) return f, errors.Trace(err) }
func ParseUint(i interface{}) (uint64, error) { var s string switch x := Num64(i).(type) { case int64: if x < 0 { return 0, errors.New("integer overflow") } return uint64(x), nil case uint64: return uint64(x), nil case float64: switch { case math.IsNaN(x): return 0, errors.New("float is NaN") case math.IsInf(x, 0): return 0, errors.New("float is Inf") case math.Abs(x-float64(uint64(x))) > 1e-9: return 0, errors.New("float to uint64") } return uint64(x), nil case string: s = x case []byte: s = string(x) default: s = fmt.Sprint(x) } u, err := strconv.ParseUint(s, 10, 64) return u, errors.Trace(err) }
// SLAVEOF host port func (h *Handler) SlaveOf(arg0 interface{}, args [][]byte) (redis.Resp, error) { if len(args) != 2 { return toRespErrorf("len(args) = %d, expect = 2", len(args)) } s, err := session(arg0, args) if err != nil { return toRespError(err) } addr := fmt.Sprintf("%s:%s", string(args[0]), string(args[1])) log.Infof("set slave of %s", addr) var c *conn if strings.ToLower(addr) != "no:one" { if nc, err := net.DialTimeout("tcp", addr, time.Second); err != nil { return toRespError(errors.Trace(err)) } else { c = newConn(nc, s.Rpdb(), 0) if err := c.ping(); err != nil { c.Close() return toRespError(err) } } } select { case <-h.signal: if c != nil { c.Close() } return toRespErrorf("sync master has been closed") case h.master <- c: return redis.NewString("OK"), nil } }
func ParseFloat64(i interface{}) (float64, error) { if v, ok := Num64(i); ok { switch x := v.(type) { case int64: return float64(x), nil case uint64: return float64(x), nil case float64: switch { case math.IsNaN(x): return 0, errors.Errorf("parse nan float64") case math.IsInf(x, 0): return 0, errors.Errorf("parse inf float64") } return float64(x), nil default: return 0, errors.Errorf("parse float64 from unknown num64") } } else { var s string switch x := i.(type) { case nil: return 0, errors.Errorf("parse float64 from nil") case string: s = x case []byte: s = string(x) default: return 0, errors.Errorf("parse float64 from <%s>", reflect.TypeOf(i)) } f, err := strconv.ParseFloat(s, 64) return f, errors.Trace(err) } }
func (b *Rpdb) restore(bt *store.Batch, db uint32, key []byte, expireat uint64, obj interface{}) error { _, err := b.deleteIfExists(bt, db, key) if err != nil { return err } if !IsExpired(expireat) { var o rpdbRow switch obj.(type) { default: return errors.Trace(ErrObjectValue) case rdb.String: o = newStringRow(db, key) case rdb.Hash: o = newHashRow(db, key) case rdb.List: o = newListRow(db, key) case rdb.ZSet: o = newZSetRow(db, key) case rdb.Set: o = newSetRow(db, key) } return o.storeObject(b, bt, expireat, obj) } log.Debugf("restore an expired object, db = %d, key = %v, expireat = %d", db, key, expireat) return nil }
func openSyncConn(target string, passwd string) (net.Conn, <-chan int64) { c := openNetConn(target, passwd) if _, err := c.Write(redis.MustEncodeToBytes(redis.NewCommand("sync"))); err != nil { log.PanicError(errors.Trace(err), "write sync command failed") } return c, waitRdbDump(c) }
func (d *decoder) decodeType() (respType, error) { if b, err := d.r.ReadByte(); err != nil { return 0, errors.Trace(err) } else { return respType(b), nil } }
func authPassword(c net.Conn, passwd string) { if passwd == "" { return } _, err := c.Write(redis.MustEncodeToBytes(redis.NewCommand("auth", passwd))) if err != nil { log.PanicError(errors.Trace(err), "write auth command failed") } var b = make([]byte, 5) if _, err := io.ReadFull(c, b); err != nil { log.PanicError(errors.Trace(err), "read auth response failed") } if strings.ToUpper(string(b)) != "+OK\r\n" { log.Panic("auth failed") } }
func (db *LevelDB) init(path string, conf *Config, create, repair bool) error { if conf == nil { conf = NewDefaultConfig() } opts := levigo.NewOptions() if create { opts.SetCreateIfMissing(true) opts.SetErrorIfExists(true) } else { opts.SetCreateIfMissing(false) opts.SetErrorIfExists(false) } opts.SetCompression(levigo.SnappyCompression) opts.SetBlockSize(conf.BlockSize) opts.SetWriteBufferSize(conf.WriteBufferSize) opts.SetMaxOpenFiles(conf.MaxOpenFiles) cache := levigo.NewLRUCache(conf.CacheSize) opts.SetCache(cache) bloom := levigo.NewBloomFilter(conf.BloomFilterSize) opts.SetFilterPolicy(bloom) db.path = path db.opts = opts db.ropt = levigo.NewReadOptions() db.wopt = levigo.NewWriteOptions() db.cache = cache db.bloom = bloom if create { if err := os.MkdirAll(db.path, 0700); err != nil { return errors.Trace(err) } } else if repair { if err := levigo.RepairDatabase(db.path, db.opts); err != nil { return errors.Trace(err) } } var err error if db.lvdb, err = levigo.Open(db.path, db.opts); err != nil { return errors.Trace(err) } return nil }
func (b *Rpdb) acquire() error { b.mu.Lock() if b.db != nil { return nil } b.mu.Unlock() return errors.Trace(ErrClosed) }
func (p *fileBuffer) close() error { if f := p.f; f != nil { p.f = nil defer f.Close() return errors.Trace(f.Truncate(0)) } return nil }
func (s *RpdbSnapshot) acquire() error { s.mu.Lock() if s.sp != nil { return nil } s.mu.Unlock() return errors.Trace(ErrSnapClosed) }
func (it *Iterator) Error() error { if it.err == nil { if err := it.iter.GetError(); err != nil { it.err = errors.Trace(err) } } return it.err }
func (w *BufWriter) WriteVarbytes(p []byte) error { if n := uint64(len(p)); n > maxVarbytesLen { return errors.Trace(ErrVarbytesLen) } else if err := w.WriteUvarint(n); err != nil { return err } _, err := ioutils.WriteFull(w.w, p) return err }
func (c *conn) encodeResp(resp redis.Resp, timeout time.Duration) error { if err := c.sock.SetWriteDeadline(time.Now().Add(timeout)); err != nil { return err } if err := redis.Encode(c.w, resp); err != nil { return err } return errors.Trace(c.w.Flush()) }
func Parse(s string) (int64, error) { if !BytesizeRegexp.MatchString(s) { return 0, errors.Trace(ErrBadBytesize) } subs := BytesizeRegexp.FindStringSubmatch(s) if len(subs) != 3 { return 0, errors.Trace(ErrBadBytesize) } size := int64(0) switch strings.ToUpper(string(subs[2])) { case "B", "": size = 1 case "KB", "K": size = KB case "MB", "M": size = MB case "GB", "G": size = GB case "TB", "T": size = TB case "PB", "P": size = PB default: return 0, errors.Trace(ErrBadBytesizeUnit) } text := subs[1] if digitsRegexp.MatchString(text) { n, err := strconv.ParseInt(text, 10, 64) if err != nil { return 0, errors.Trace(ErrBadBytesize) } size *= n } else { n, err := strconv.ParseFloat(text, 64) if err != nil { return 0, errors.Trace(ErrBadBytesize) } size = int64(float64(size) * n) } return size, nil }