2014-05-29 11:07:14 +04:00
|
|
|
package ledis
|
|
|
|
|
|
|
|
import (
|
2014-09-17 13:54:04 +04:00
|
|
|
"bytes"
|
2014-05-29 11:07:14 +04:00
|
|
|
"encoding/binary"
|
2014-06-04 10:42:02 +04:00
|
|
|
"errors"
|
2014-09-17 13:54:04 +04:00
|
|
|
"io"
|
2014-07-11 09:28:34 +04:00
|
|
|
"strconv"
|
2014-06-04 10:42:02 +04:00
|
|
|
)
|
|
|
|
|
2014-09-17 13:54:04 +04:00
|
|
|
const (
|
|
|
|
kTypeDeleteEvent uint8 = 0
|
|
|
|
kTypePutEvent uint8 = 1
|
|
|
|
)
|
|
|
|
|
2014-06-04 10:42:02 +04:00
|
|
|
var (
|
2014-09-17 13:54:04 +04:00
|
|
|
errInvalidPutEvent = errors.New("invalid put event")
|
|
|
|
errInvalidDeleteEvent = errors.New("invalid delete event")
|
|
|
|
errInvalidEvent = errors.New("invalid event")
|
2014-05-29 11:07:14 +04:00
|
|
|
)
|
|
|
|
|
2014-09-17 13:54:04 +04:00
|
|
|
type eventBatch struct {
|
|
|
|
bytes.Buffer
|
2014-05-29 11:07:14 +04:00
|
|
|
}
|
|
|
|
|
2014-09-17 13:54:04 +04:00
|
|
|
type event struct {
|
|
|
|
key []byte
|
|
|
|
value []byte //value = nil for delete event
|
2014-06-04 10:42:02 +04:00
|
|
|
}
|
|
|
|
|
2014-09-17 13:54:04 +04:00
|
|
|
func (b *eventBatch) Put(key []byte, value []byte) {
|
|
|
|
l := uint32(len(key) + len(value) + 1 + 2)
|
|
|
|
binary.Write(b, binary.BigEndian, l)
|
|
|
|
b.WriteByte(kTypePutEvent)
|
|
|
|
keyLen := uint16(len(key))
|
|
|
|
binary.Write(b, binary.BigEndian, keyLen)
|
|
|
|
b.Write(key)
|
|
|
|
b.Write(value)
|
2014-05-29 11:07:14 +04:00
|
|
|
}
|
|
|
|
|
2014-09-17 13:54:04 +04:00
|
|
|
func (b *eventBatch) Delete(key []byte) {
|
|
|
|
l := uint32(len(key) + 1)
|
|
|
|
binary.Write(b, binary.BigEndian, l)
|
|
|
|
b.WriteByte(kTypeDeleteEvent)
|
|
|
|
b.Write(key)
|
2014-06-04 10:42:02 +04:00
|
|
|
}
|
|
|
|
|
2014-09-17 13:54:04 +04:00
|
|
|
func decodeEventBatch(data []byte) (ev []event, err error) {
|
|
|
|
ev = make([]event, 0, 16)
|
|
|
|
for {
|
|
|
|
if len(data) == 0 {
|
|
|
|
return ev, nil
|
|
|
|
}
|
2014-07-11 09:28:34 +04:00
|
|
|
|
2014-09-17 13:54:04 +04:00
|
|
|
if len(data) < 4 {
|
|
|
|
return nil, io.ErrUnexpectedEOF
|
|
|
|
}
|
2014-07-11 09:28:34 +04:00
|
|
|
|
2014-09-17 13:54:04 +04:00
|
|
|
l := binary.BigEndian.Uint32(data)
|
|
|
|
data = data[4:]
|
|
|
|
if uint32(len(data)) < l {
|
|
|
|
return nil, io.ErrUnexpectedEOF
|
|
|
|
}
|
2014-07-11 09:28:34 +04:00
|
|
|
|
2014-09-17 13:54:04 +04:00
|
|
|
var e event
|
|
|
|
if err := decodeEvent(&e, data[0:l]); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
ev = append(ev, e)
|
|
|
|
data = data[l:]
|
2014-07-11 09:28:34 +04:00
|
|
|
}
|
2014-09-17 13:54:04 +04:00
|
|
|
}
|
2014-07-11 09:28:34 +04:00
|
|
|
|
2014-09-17 13:54:04 +04:00
|
|
|
func decodeEvent(e *event, b []byte) error {
|
|
|
|
if len(b) == 0 {
|
|
|
|
return errInvalidEvent
|
2014-07-11 09:28:34 +04:00
|
|
|
}
|
|
|
|
|
2014-09-17 13:54:04 +04:00
|
|
|
switch b[0] {
|
|
|
|
case kTypePutEvent:
|
|
|
|
if len(b[1:]) < 2 {
|
|
|
|
return errInvalidPutEvent
|
|
|
|
}
|
2014-07-11 09:28:34 +04:00
|
|
|
|
2014-09-17 13:54:04 +04:00
|
|
|
keyLen := binary.BigEndian.Uint16(b[1:3])
|
|
|
|
b = b[3:]
|
|
|
|
if len(b) < int(keyLen) {
|
|
|
|
return errInvalidPutEvent
|
|
|
|
}
|
|
|
|
|
|
|
|
e.key = b[0:keyLen]
|
|
|
|
e.value = b[keyLen:]
|
|
|
|
case kTypeDeleteEvent:
|
|
|
|
e.value = nil
|
|
|
|
e.key = b[1:]
|
|
|
|
default:
|
|
|
|
return errInvalidEvent
|
2014-07-11 09:28:34 +04:00
|
|
|
}
|
|
|
|
|
2014-09-17 13:54:04 +04:00
|
|
|
return nil
|
2014-07-11 09:28:34 +04:00
|
|
|
}
|
|
|
|
|
2014-09-17 13:54:04 +04:00
|
|
|
func formatEventKey(buf []byte, k []byte) ([]byte, error) {
|
2014-07-11 09:28:34 +04:00
|
|
|
if len(k) < 2 {
|
2014-09-17 13:54:04 +04:00
|
|
|
return nil, errInvalidEvent
|
2014-07-11 09:28:34 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
buf = append(buf, fmt.Sprintf("DB:%2d ", k[0])...)
|
|
|
|
buf = append(buf, fmt.Sprintf("%s ", TypeName[k[1]])...)
|
|
|
|
|
|
|
|
db := new(DB)
|
|
|
|
db.index = k[0]
|
|
|
|
|
|
|
|
//to do format at respective place
|
|
|
|
|
|
|
|
switch k[1] {
|
|
|
|
case KVType:
|
|
|
|
if key, err := db.decodeKVKey(k); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
buf = strconv.AppendQuote(buf, String(key))
|
|
|
|
}
|
|
|
|
case HashType:
|
|
|
|
if key, field, err := db.hDecodeHashKey(k); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
buf = strconv.AppendQuote(buf, String(key))
|
|
|
|
buf = append(buf, ' ')
|
|
|
|
buf = strconv.AppendQuote(buf, String(field))
|
|
|
|
}
|
|
|
|
case HSizeType:
|
|
|
|
if key, err := db.hDecodeSizeKey(k); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
buf = strconv.AppendQuote(buf, String(key))
|
|
|
|
}
|
|
|
|
case ListType:
|
|
|
|
if key, seq, err := db.lDecodeListKey(k); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
buf = strconv.AppendQuote(buf, String(key))
|
|
|
|
buf = append(buf, ' ')
|
|
|
|
buf = strconv.AppendInt(buf, int64(seq), 10)
|
|
|
|
}
|
|
|
|
case LMetaType:
|
|
|
|
if key, err := db.lDecodeMetaKey(k); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
buf = strconv.AppendQuote(buf, String(key))
|
|
|
|
}
|
|
|
|
case ZSetType:
|
|
|
|
if key, m, err := db.zDecodeSetKey(k); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
buf = strconv.AppendQuote(buf, String(key))
|
|
|
|
buf = append(buf, ' ')
|
|
|
|
buf = strconv.AppendQuote(buf, String(m))
|
|
|
|
}
|
|
|
|
case ZSizeType:
|
|
|
|
if key, err := db.zDecodeSizeKey(k); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
buf = strconv.AppendQuote(buf, String(key))
|
|
|
|
}
|
|
|
|
case ZScoreType:
|
|
|
|
if key, m, score, err := db.zDecodeScoreKey(k); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
buf = strconv.AppendQuote(buf, String(key))
|
|
|
|
buf = append(buf, ' ')
|
|
|
|
buf = strconv.AppendQuote(buf, String(m))
|
|
|
|
buf = append(buf, ' ')
|
|
|
|
buf = strconv.AppendInt(buf, score, 10)
|
|
|
|
}
|
|
|
|
case BitType:
|
|
|
|
if key, seq, err := db.bDecodeBinKey(k); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
buf = strconv.AppendQuote(buf, String(key))
|
|
|
|
buf = append(buf, ' ')
|
|
|
|
buf = strconv.AppendUint(buf, uint64(seq), 10)
|
|
|
|
}
|
|
|
|
case BitMetaType:
|
|
|
|
if key, err := db.bDecodeMetaKey(k); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
buf = strconv.AppendQuote(buf, String(key))
|
|
|
|
}
|
2014-08-25 10:18:23 +04:00
|
|
|
case SetType:
|
|
|
|
if key, member, err := db.sDecodeSetKey(k); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
buf = strconv.AppendQuote(buf, String(key))
|
|
|
|
buf = append(buf, ' ')
|
|
|
|
buf = strconv.AppendQuote(buf, String(member))
|
|
|
|
}
|
|
|
|
case SSizeType:
|
|
|
|
if key, err := db.sDecodeSizeKey(k); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
buf = strconv.AppendQuote(buf, String(key))
|
|
|
|
}
|
2014-07-11 09:28:34 +04:00
|
|
|
case ExpTimeType:
|
|
|
|
if tp, key, t, err := db.expDecodeTimeKey(k); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
buf = append(buf, TypeName[tp]...)
|
|
|
|
buf = append(buf, ' ')
|
|
|
|
buf = strconv.AppendQuote(buf, String(key))
|
|
|
|
buf = append(buf, ' ')
|
|
|
|
buf = strconv.AppendInt(buf, t, 10)
|
|
|
|
}
|
|
|
|
case ExpMetaType:
|
|
|
|
if tp, key, err := db.expDecodeMetaKey(k); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
buf = append(buf, TypeName[tp]...)
|
|
|
|
buf = append(buf, ' ')
|
|
|
|
buf = strconv.AppendQuote(buf, String(key))
|
|
|
|
}
|
|
|
|
default:
|
2014-09-17 13:54:04 +04:00
|
|
|
return nil, errInvalidEvent
|
2014-07-11 09:28:34 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return buf, nil
|
|
|
|
}
|