// SETNX key value func (b *Rpdb) SetNX(db uint32, args ...interface{}) (int64, error) { if len(args) != 2 { return 0, errArguments("len(args) = %d, expect = 2", len(args)) } var key, value []byte for i, ref := range []interface{}{&key, &value} { if err := parseArgument(args[i], ref); err != nil { return 0, errArguments("parse args[%d] failed, %s", i, err) } } if err := b.acquire(); err != nil { return 0, err } defer b.release() o, err := b.loadRpdbRow(db, key, true) if err != nil || o != nil { return 0, err } else { o := newStringRow(db, key) o.Value = value bt := store.NewBatch() bt.Set(o.DataKey(), o.DataValue()) bt.Set(o.MetaKey(), o.MetaValue()) fw := &Forward{DB: db, Op: "Set", Args: args} return 1, b.commit(bt, fw) } }
// PERSIST key func (b *Rpdb) Persist(db uint32, args ...interface{}) (int64, error) { if len(args) != 1 { return 0, errArguments("len(args) = %d, expect = 1", len(args)) } var key []byte for i, ref := range []interface{}{&key} { if err := parseArgument(args[i], ref); err != nil { return 0, errArguments("parse args[%d] failed, %s", i, err) } } if err := b.acquire(); err != nil { return 0, err } defer b.release() o, err := b.loadRpdbRow(db, key, true) if err != nil || o == nil { return 0, err } if o.GetExpireAt() == 0 { return 0, nil } fw := &Forward{DB: db, Op: "Persist", Args: args} bt := store.NewBatch() o.SetExpireAt(0) bt.Set(o.MetaKey(), o.MetaValue()) return 1, b.commit(bt, fw) }
func (b *Rpdb) incrFloat(db uint32, key []byte, delta float64) (float64, error) { o, err := b.loadStringRow(db, key, true) if err != nil { return 0, err } bt := store.NewBatch() if o != nil { _, err := o.LoadDataValue(b) if err != nil { return 0, err } v, err := ParseFloat(o.Value) if err != nil { return 0, err } delta += v } else { o = newStringRow(db, key) bt.Set(o.MetaKey(), o.MetaValue()) } o.Value = FormatFloat(delta) bt.Set(o.DataKey(), o.DataValue()) fw := &Forward{DB: db, Op: "IncrByFloat", Args: []interface{}{key, delta}} return delta, b.commit(bt, fw) }
// SETBIT key offset value func (b *Rpdb) SetBit(db uint32, args ...interface{}) (int64, error) { if len(args) != 3 { return 0, errArguments("len(args) = %d, expect = 3", len(args)) } var key []byte var offset, value uint64 for i, ref := range []interface{}{&key, &offset, &value} { if err := parseArgument(args[i], ref); err != nil { return 0, errArguments("parse args[%d] failed, %s", i, err) } } if offset > maxVarbytesLen { return 0, errArguments("offset = %d", offset) } var bit bool = value != 0 if err := b.acquire(); err != nil { return 0, err } defer b.release() o, err := b.loadStringRow(db, key, true) if err != nil { return 0, err } bt := store.NewBatch() if o != nil { _, err := o.LoadDataValue(b) if err != nil { return 0, err } } else { o = newStringRow(db, key) bt.Set(o.MetaKey(), o.MetaValue()) } ipos := offset / 8 if n := int(ipos) + 1; n > len(o.Value) { o.Value = append(o.Value, make([]byte, n-len(o.Value))...) } mask := byte(1 << (offset % 8)) orig := o.Value[ipos] & mask if bit { o.Value[ipos] |= mask } else { o.Value[ipos] &= ^mask } bt.Set(o.DataKey(), o.DataValue()) var n int64 = 0 if orig != 0 { n = 1 } fw := &Forward{DB: db, Op: "SetBit", Args: args} return n, b.commit(bt, fw) }
// SLOTSRESTORE key ttlms value [key ttlms value ...] func (b *Rpdb) SlotsRestore(db uint32, args ...interface{}) error { if len(args) == 0 || len(args)%3 != 0 { return errArguments("len(args) = %d, expect != 0 && mod 3 = 0", len(args)) } objs := make([]*rdb.ObjEntry, len(args)/3) for i := 0; i < len(objs); i++ { var key, value []byte var ttlms int64 for j, ref := range []interface{}{&key, &ttlms, &value} { if err := parseArgument(args[i*3+j], ref); err != nil { return errArguments("parse args[%d] failed, %s", i*3+j, err) } } expireat := uint64(0) if ttlms != 0 { if v, ok := TTLmsToExpireAt(ttlms); ok && v > 0 { expireat = v } else { return errArguments("parse args[%d] ttlms = %d", i*3+1, ttlms) } } obj, err := rdb.DecodeDump(value) if err != nil { return errArguments("decode args[%d] failed, %s", i*3+2, err) } objs[i] = &rdb.ObjEntry{ DB: db, Key: key, ExpireAt: expireat, Value: obj, } } if err := b.acquire(); err != nil { return err } defer b.release() ms := &markSet{} bt := store.NewBatch() for i := len(objs) - 1; i >= 0; i-- { e := objs[i] if ms.Has(e.Key) { log.Debugf("[%d] restore batch, db = %d, key = %v, ignore", i, e.DB, e.Key) continue } else { log.Debugf("[%d] restore batch, db = %d, key = %v", i, e.DB, e.Key) } if err := b.restore(bt, e.DB, e.Key, e.ExpireAt, e.Value); err != nil { log.DebugErrorf(err, "restore object failed, db = %d, key = %v", e.DB, e.Key) return err } ms.Set(e.Key) } fw := &Forward{DB: db, Op: "SlotsRestore", Args: args} return b.commit(bt, fw) }
// HMSET key field value [field value ...] func (b *Rpdb) HMSet(db uint32, args ...interface{}) error { if len(args) == 1 || len(args)%2 != 1 { return errArguments("len(args) = %d, expect != 1 && mod 2 = 1", len(args)) } var key []byte var eles = make([]*rdb.HashElement, len(args)/2) if err := parseArgument(args[0], &key); err != nil { return errArguments("parse args[%d] failed, %s", 0, err) } for i := 0; i < len(eles); i++ { e := &rdb.HashElement{} if err := parseArgument(args[i*2+1], &e.Field); err != nil { return errArguments("parse args[%d] failed, %s", i*2+1, err) } if err := parseArgument(args[i*2+2], &e.Value); err != nil { return errArguments("parse args[%d] failed, %s", i*2+2, err) } eles[i] = e } if err := b.acquire(); err != nil { return err } defer b.release() o, err := b.loadHashRow(db, key, true) if err != nil { return err } if o == nil { o = newHashRow(db, key) } ms := &markSet{} bt := store.NewBatch() for _, e := range eles { o.Field, o.Value = e.Field, e.Value exists, err := o.TestDataValue(b) if err != nil { return err } if !exists { ms.Set(o.Field) } bt.Set(o.DataKey(), o.DataValue()) } n := ms.Len() if n != 0 { o.Size += n bt.Set(o.MetaKey(), o.MetaValue()) } fw := &Forward{DB: db, Op: "HMSet", Args: args} return b.commit(bt, fw) }
// SREM key member [member ...] func (b *Rpdb) SRem(db uint32, args ...interface{}) (int64, error) { if len(args) < 2 { return 0, errArguments("len(args) = %d, expect >= 2", len(args)) } var key []byte var members = make([][]byte, len(args)-1) if err := parseArgument(args[0], &key); err != nil { return 0, errArguments("parse args[%d] failed, %s", 0, err) } for i := 0; i < len(members); i++ { if err := parseArgument(args[i+1], &members[i]); err != nil { return 0, errArguments("parse args[%d] failed, %s", i+1, err) } } if err := b.acquire(); err != nil { return 0, err } defer b.release() o, err := b.loadSetRow(db, key, true) if err != nil || o == nil { return 0, err } ms := &markSet{} bt := store.NewBatch() for _, o.Member = range members { if !ms.Has(o.Member) { exists, err := o.TestDataValue(b) if err != nil { return 0, err } if exists { bt.Del(o.DataKey()) ms.Set(o.Member) } } } n := ms.Len() if n != 0 { if o.Size -= n; o.Size > 0 { bt.Set(o.MetaKey(), o.MetaValue()) } else { bt.Del(o.MetaKey()) } } fw := &Forward{DB: db, Op: "SRem", Args: args} return n, b.commit(bt, fw) }
// HINCRBYFLOAT key field delta func (b *Rpdb) HIncrByFloat(db uint32, args ...interface{}) (float64, error) { if len(args) != 3 { return 0, errArguments("len(args) = %d, expect = 2", len(args)) } var key, field []byte var delta float64 for i, ref := range []interface{}{&key, &field, &delta} { if err := parseArgument(args[i], ref); err != nil { return 0, errArguments("parse args[%d] failed, %s", i, err) } } if err := b.acquire(); err != nil { return 0, err } defer b.release() o, err := b.loadHashRow(db, key, true) if err != nil { return 0, err } var exists bool = false if o != nil { o.Field = field exists, err = o.LoadDataValue(b) if err != nil { return 0, err } } else { o = newHashRow(db, key) o.Field = field } bt := store.NewBatch() if exists { v, err := ParseFloat(o.Value) if err != nil { return 0, err } delta += v } else { o.Size++ bt.Set(o.MetaKey(), o.MetaValue()) } o.Value = FormatFloat(delta) bt.Set(o.DataKey(), o.DataValue()) fw := &Forward{DB: db, Op: "HIncrByFloat", Args: args} return delta, b.commit(bt, fw) }
// HSET key field value func (b *Rpdb) HSet(db uint32, args ...interface{}) (int64, error) { if len(args) != 3 { return 0, errArguments("len(args) = %d, expect = 2", len(args)) } var key, field, value []byte for i, ref := range []interface{}{&key, &field, &value} { if err := parseArgument(args[i], ref); err != nil { return 0, errArguments("parse args[%d] failed, %s", i, err) } } if err := b.acquire(); err != nil { return 0, err } defer b.release() o, err := b.loadHashRow(db, key, true) if err != nil { return 0, err } var exists bool = false if o != nil { o.Field = field exists, err = o.TestDataValue(b) if err != nil { return 0, err } } else { o = newHashRow(db, key) o.Field = field } var n int64 bt := store.NewBatch() if exists { n, o.Value = 0, value bt.Set(o.DataKey(), o.DataValue()) } else { o.Size++ n, o.Value = 1, value bt.Set(o.DataKey(), o.DataValue()) bt.Set(o.MetaKey(), o.MetaValue()) } fw := &Forward{DB: db, Op: "HSet", Args: args} return n, b.commit(bt, fw) }
func (b *Rpdb) loadRpdbRow(db uint32, key []byte, deleteIfExpired bool) (rpdbRow, error) { o, err := loadRpdbRow(b, db, key) if err != nil || o == nil { return nil, err } if deleteIfExpired && o.IsExpired() { bt := store.NewBatch() if err := o.deleteObject(b, bt); err != nil { return nil, err } fw := &Forward{DB: db, Op: "Del", Args: []interface{}{key}} return nil, b.commit(bt, fw) } return o, nil }
// LTRIM key beg end func (b *Rpdb) LTrim(db uint32, args ...interface{}) error { if len(args) != 3 { return errArguments("len(args) = %d, expect = 2", len(args)) } var key []byte var beg, end int64 for i, ref := range []interface{}{&key, &beg, &end} { if err := parseArgument(args[i], ref); err != nil { return errArguments("parse args[%d] failed, %s", i, err) } } if err := b.acquire(); err != nil { return err } defer b.release() o, err := b.loadListRow(db, key, true) if err != nil || o == nil { return err } beg = maxIntValue(adjustIndex(beg, o.Lindex, o.Rindex), o.Lindex) end = minIntValue(adjustIndex(end, o.Lindex, o.Rindex), o.Rindex-1) if beg == o.Lindex && end == o.Rindex-1 { return nil } bt := store.NewBatch() if beg <= end { for o.Index = o.Lindex; o.Index < beg; o.Index++ { bt.Del(o.DataKey()) } for o.Index = o.Rindex - 1; o.Index > end; o.Index-- { bt.Del(o.DataKey()) } o.Lindex, o.Rindex = beg, end+1 bt.Set(o.MetaKey(), o.MetaValue()) } else { for o.Index = o.Lindex; o.Index < o.Rindex; o.Index++ { bt.Del(o.DataKey()) } bt.Del(o.MetaKey()) } fw := &Forward{DB: db, Op: "LTrim", Args: args} return b.commit(bt, fw) }
// ZINCRBY key delta member func (b *Rpdb) ZIncrBy(db uint32, args ...interface{}) (float64, error) { if len(args) != 3 { return 0, errArguments("len(args) = %d, expect = 2", len(args)) } var key, member []byte var delta float64 for i, ref := range []interface{}{&key, &delta, &member} { if err := parseArgument(args[i], ref); err != nil { return 0, errArguments("parse args[%d] failed, %s", i, err) } } if err := b.acquire(); err != nil { return 0, err } defer b.release() o, err := b.loadZSetRow(db, key, true) if err != nil { return 0, err } var exists bool = false if o != nil { o.Member = member exists, err = o.LoadDataValue(b) if err != nil { return 0, err } } else { o = newZSetRow(db, key) o.Member = member } bt := store.NewBatch() if exists { delta += o.Score } else { o.Size++ bt.Set(o.MetaKey(), o.MetaValue()) } o.Score = delta bt.Set(o.DataKey(), o.DataValue()) fw := &Forward{DB: db, Op: "ZIncrBy", Args: args} return delta, b.commit(bt, fw) }
func (b *Rpdb) migrate(addr string, timeout time.Duration, db uint32, keys ...[]byte) (int64, error) { var rows []rpdbRow var bins []*rdb.BinEntry for i, key := range keys { o, bin, err := loadBinEntry(b, db, key) if err != nil { return 0, err } if o == nil { log.Debugf("[%d] missing, db = %d, key = %v", i, db, key) continue } rows = append(rows, o) if bin != nil { log.Debugf("[%d] migrate, db = %d, key = %v, expireat = %d", i, db, key, o.GetExpireAt()) bins = append(bins, bin) } else { log.Debugf("[%d] expired, db = %d, key = %v, expireat = %d", i, db, key, o.GetExpireAt()) } } if len(bins) != 0 { if err := doMigrate(addr, timeout, db, bins); err != nil { return 0, err } } if len(rows) == 0 { return 0, nil } bt := store.NewBatch() for _, o := range rows { if err := o.deleteObject(b, bt); err != nil { return 0, err } } fw := &Forward{DB: db, Op: "Del"} for _, key := range keys { fw.Args = append(fw.Args, key) } return int64(len(rows)), b.commit(bt, fw) }
// SETEX key seconds value func (b *Rpdb) SetEX(db uint32, args ...interface{}) error { if len(args) != 3 { return errArguments("len(args) = %d, expect = 3", len(args)) } var key, value []byte var ttls int64 for i, ref := range []interface{}{&key, &ttls, &value} { if err := parseArgument(args[i], ref); err != nil { return errArguments("parse args[%d] failed, %s", i, err) } } if ttls == 0 { return errArguments("invalid ttls = %d", ttls) } expireat := uint64(0) if v, ok := TTLsToExpireAt(ttls); ok && v > 0 { expireat = v } else { return errArguments("invalid ttls = %d", ttls) } if err := b.acquire(); err != nil { return err } defer b.release() bt := store.NewBatch() _, err := b.deleteIfExists(bt, db, key) if err != nil { return err } if !IsExpired(expireat) { o := newStringRow(db, key) o.ExpireAt, o.Value = expireat, value bt.Set(o.DataKey(), o.DataValue()) bt.Set(o.MetaKey(), o.MetaValue()) fw := &Forward{DB: db, Op: "SetEX", Args: args} return b.commit(bt, fw) } else { fw := &Forward{DB: db, Op: "Del", Args: []interface{}{key}} return b.commit(bt, fw) } }
// SETRANGE key offset value func (b *Rpdb) SetRange(db uint32, args ...interface{}) (int64, error) { if len(args) != 3 { return 0, errArguments("len(args) = %d, expect = 3", len(args)) } var key, value []byte var offset uint64 for i, ref := range []interface{}{&key, &offset, &value} { if err := parseArgument(args[i], ref); err != nil { return 0, errArguments("parse args[%d] failed, %s", i, err) } } if offset > maxVarbytesLen { return 0, errArguments("offset = %d", offset) } if err := b.acquire(); err != nil { return 0, err } defer b.release() o, err := b.loadStringRow(db, key, true) if err != nil { return 0, err } bt := store.NewBatch() if o != nil { _, err := o.LoadDataValue(b) if err != nil { return 0, err } } else { o = newStringRow(db, key) bt.Set(o.MetaKey(), o.MetaValue()) } if n := int(offset) + len(value); n > len(o.Value) { o.Value = append(o.Value, make([]byte, n-len(o.Value))...) } copy(o.Value[offset:], value) bt.Set(o.DataKey(), o.DataValue()) fw := &Forward{DB: db, Op: "SetRange", Args: args} return int64(len(o.Value)), b.commit(bt, fw) }
func (b *Rpdb) setExpireAt(db uint32, key []byte, expireat uint64) (int64, error) { o, err := b.loadRpdbRow(db, key, true) if err != nil || o == nil { return 0, err } bt := store.NewBatch() if !IsExpired(expireat) { o.SetExpireAt(expireat) bt.Set(o.MetaKey(), o.MetaValue()) fw := &Forward{DB: db, Op: "PExpireAt", Args: []interface{}{key, expireat}} return 1, b.commit(bt, fw) } else { _, err := b.deleteIfExists(bt, db, key) if err != nil { return 0, err } fw := &Forward{DB: db, Op: "Del", Args: []interface{}{key}} return 1, b.commit(bt, fw) } }
// GETSET key value func (b *Rpdb) GetSet(db uint32, args ...interface{}) ([]byte, error) { if len(args) != 2 { return nil, errArguments("len(args) = %d, expect = 2", len(args)) } var key, value []byte for i, ref := range []interface{}{&key, &value} { if err := parseArgument(args[i], ref); err != nil { return nil, errArguments("parse args[%d] failed, %s", i, err) } } if err := b.acquire(); err != nil { return nil, err } defer b.release() o, err := b.loadStringRow(db, key, true) if err != nil { return nil, err } bt := store.NewBatch() if o != nil { _, err := o.LoadDataValue(b) if err != nil { return nil, err } if o.ExpireAt != 0 { o.ExpireAt = 0 bt.Set(o.MetaKey(), o.MetaValue()) } } else { o = newStringRow(db, key) bt.Set(o.MetaKey(), o.MetaValue()) } o.Value, value = value, o.Value bt.Set(o.DataKey(), o.DataValue()) fw := &Forward{DB: db, Op: "Set", Args: args} return value, b.commit(bt, fw) }
// DEL key [key ...] func (b *Rpdb) Del(db uint32, args ...interface{}) (int64, error) { if len(args) == 0 { return 0, errArguments("len(args) = %d, expect != 0", len(args)) } keys := make([][]byte, len(args)) for i := 0; i < len(keys); i++ { if err := parseArgument(args[i], &keys[i]); err != nil { return 0, errArguments("parse args[%d] failed, %s", err) } } if err := b.acquire(); err != nil { return 0, err } defer b.release() for _, key := range keys { _, err := b.loadRpdbRow(db, key, true) if err != nil { return 0, err } } ms := &markSet{} bt := store.NewBatch() for _, key := range keys { if !ms.Has(key) { exists, err := b.deleteIfExists(bt, db, key) if err != nil { return 0, err } if exists { ms.Set(key) } } } fw := &Forward{DB: db, Op: "Del", Args: args} return ms.Len(), b.commit(bt, fw) }
// MSETNX key value [key value ...] func (b *Rpdb) MSetNX(db uint32, args ...interface{}) (int64, error) { if len(args) == 0 || len(args)%2 != 0 { return 0, errArguments("len(args) = %d, expect != 0 && mod 2 = 0", len(args)) } pairs := make([][]byte, len(args)) for i := 0; i < len(args); i++ { if err := parseArgument(args[i], &pairs[i]); err != nil { return 0, errArguments("parse args[%d] failed, %s", i, err) } } if err := b.acquire(); err != nil { return 0, err } defer b.release() for i := 0; i < len(pairs); i += 2 { o, err := b.loadRpdbRow(db, pairs[i], true) if err != nil || o != nil { return 0, err } } ms := &markSet{} bt := store.NewBatch() for i := len(pairs)/2 - 1; i >= 0; i-- { key, value := pairs[i*2], pairs[i*2+1] if !ms.Has(key) { o := newStringRow(db, key) o.Value = value bt.Set(o.DataKey(), o.DataValue()) bt.Set(o.MetaKey(), o.MetaValue()) ms.Set(key) } } fw := &Forward{DB: db, Op: "MSet", Args: args} return 1, b.commit(bt, fw) }
// RESTORE key ttlms value func (b *Rpdb) Restore(db uint32, args ...interface{}) error { if len(args) != 3 { return errArguments("len(args) = %d, expect = 3", len(args)) } var key, value []byte var ttlms int64 for i, ref := range []interface{}{&key, &ttlms, &value} { if err := parseArgument(args[i], ref); err != nil { return errArguments("parse args[%d] failed, %s", i, err) } } expireat := uint64(0) if ttlms != 0 { if v, ok := TTLmsToExpireAt(ttlms); ok && v > 0 { expireat = v } else { return errArguments("parse ttlms = %d", ttlms) } } obj, err := rdb.DecodeDump(value) if err != nil { return err } if err := b.acquire(); err != nil { return err } defer b.release() fw := &Forward{DB: db, Op: "Restore", Args: args} bt := store.NewBatch() if err := b.restore(bt, db, key, expireat, obj); err != nil { return err } return b.commit(bt, fw) }
// SPOP key func (b *Rpdb) SPop(db uint32, args ...interface{}) ([]byte, error) { if len(args) != 1 { return nil, errArguments("len(args) = %d, expect = 1", len(args)) } var key []byte for i, ref := range []interface{}{&key} { if err := parseArgument(args[i], ref); err != nil { return nil, errArguments("parse args[%d] failed, %s", i, err) } } if err := b.acquire(); err != nil { return nil, err } defer b.release() o, err := b.loadSetRow(db, key, true) if err != nil || o == nil { return nil, err } members, err := o.getMembers(b, 1) if err != nil || len(members) == 0 { return nil, err } o.Member = members[0] bt := store.NewBatch() bt.Del(o.DataKey()) if o.Size--; o.Size > 0 { bt.Set(o.MetaKey(), o.MetaValue()) } else { bt.Del(o.MetaKey()) } fw := &Forward{DB: db, Op: "SRem", Args: []interface{}{key, members[0]}} return o.Member, b.commit(bt, fw) }
// LSET key index value func (b *Rpdb) LSet(db uint32, args ...interface{}) error { if len(args) != 3 { return errArguments("len(args) = %d, expect = 2", len(args)) } var key, value []byte var index int64 for i, ref := range []interface{}{&key, &index, &value} { if err := parseArgument(args[i], ref); err != nil { return errArguments("parse args[%d] failed, %s", i, err) } } if err := b.acquire(); err != nil { return err } defer b.release() o, err := b.loadListRow(db, key, true) if err != nil { return err } if o == nil { return errors.Trace(ErrNoSuchList) } o.Index = adjustIndex(index, o.Lindex, o.Rindex) if o.Index >= o.Lindex && o.Index < o.Rindex { o.Value = value bt := store.NewBatch() bt.Set(o.DataKey(), o.DataValue()) fw := &Forward{DB: db, Op: "LSet", Args: args} return b.commit(bt, fw) } else { return errors.Trace(ErrOutOfRange) } }
// RPOP key func (b *Rpdb) RPop(db uint32, args ...interface{}) ([]byte, error) { if len(args) != 1 { return nil, errArguments("len(args) = %d, expect = 1", len(args)) } var key []byte for i, ref := range []interface{}{&key} { if err := parseArgument(args[i], ref); err != nil { return nil, errArguments("parse args[%d] failed, %s", i, err) } } if err := b.acquire(); err != nil { return nil, err } defer b.release() o, err := b.loadListRow(db, key, true) if err != nil || o == nil { return nil, err } o.Index = o.Rindex - 1 if _, err := o.LoadDataValue(b); err != nil { return nil, err } else { bt := store.NewBatch() bt.Del(o.DataKey()) if o.Rindex--; o.Lindex < o.Rindex { bt.Set(o.MetaKey(), o.MetaValue()) } else { bt.Del(o.MetaKey()) } fw := &Forward{DB: db, Op: "RPop", Args: args} return o.Value, b.commit(bt, fw) } }
func (b *Rpdb) rpush(db uint32, key []byte, create bool, values ...[]byte) (int64, error) { o, err := b.loadListRow(db, key, true) if err != nil { return 0, err } if o == nil { if !create { return 0, nil } o = newListRow(db, key) } fw := &Forward{DB: db, Op: "RPush", Args: []interface{}{key}} bt := store.NewBatch() for _, value := range values { o.Index, o.Value = o.Rindex, value o.Rindex++ bt.Set(o.DataKey(), o.DataValue()) fw.Args = append(fw.Args, value) } bt.Set(o.MetaKey(), o.MetaValue()) return o.Rindex - o.Lindex, b.commit(bt, fw) }