func Sadd(args [][]byte, wb *levigo.WriteBatch) interface{} { var newMembers uint32 key := NewKeyBuffer(SetKey, args[0], len(args[1])) mk := metaKey(args[0]) card, err := scard(mk, nil) if err != nil { return err } for _, member := range args[1:] { key.SetSuffix(member) if card > 0 { res, err := DB.Get(DefaultReadOptions, key.Key()) if err != nil { return err } if res != nil { continue } } wb.Put(key.Key(), []byte{}) newMembers++ } if newMembers > 0 { setCard(mk, card+newMembers, wb) } return newMembers }
func lpush(args [][]byte, left bool, create bool, wb *levigo.WriteBatch) (interface{}, error) { mk := metaKey(args[0]) l, err := llen(mk, nil) if err != nil { return nil, err } if create || l.length > 0 { key := NewKeyBuffer(ListKey, args[0], 8) for _, value := range args[1:] { l.length++ var seq int64 if left { seq = l.left l.left-- } else { seq = l.right l.right++ } // To sort negative ints in order before positive, we subtract math.MinInt64 // which wraps the numbers around and sorts correctly binary.BigEndian.PutUint64(key.SuffixForRead(8), uint64(seq-math.MinInt64)) wb.Put(key.Key(), value) } setLlen(mk, l, wb) } return l.length, nil }
func Hincrbyfloat(args [][]byte, wb *levigo.WriteBatch) interface{} { mk := metaKey(args[0]) length, err := hlen(mk, nil) if err != nil { return err } key := NewKeyBufferWithSuffix(HashKey, args[0], args[1]).Key() res, err := DB.Get(DefaultReadOptions, key) if err != nil { return err } var current float64 if res != nil { current, err = bconv.ParseFloat(res, 64) if err != nil { return fmt.Errorf("hash value is not a valid float") } } increment, err := bconv.ParseFloat(args[2], 64) if err != nil { return fmt.Errorf("value is not a valid float") } result := strconv.AppendFloat(nil, current+increment, 'f', -1, 64) wb.Put(key, result) // if is a new key, increment the hash length if res == nil { setHlen(mk, length+1, wb) } return result }
func Hincrby(args [][]byte, wb *levigo.WriteBatch) interface{} { mk := metaKey(args[0]) length, err := hlen(mk, nil) if err != nil { return err } key := NewKeyBufferWithSuffix(HashKey, args[0], args[1]).Key() res, err := DB.Get(DefaultReadOptions, key) if err != nil { return err } var current int64 if res != nil { current, err = bconv.ParseInt(res, 10, 64) if err != nil { return InvalidIntError } } increment, err := bconv.ParseInt(args[2], 10, 64) if err != nil { return InvalidIntError } result := strconv.AppendInt(nil, current+increment, 10) wb.Put(key, result) // if is a new key, increment the hash length if res == nil { setHlen(mk, length+1, wb) } return result }
func Hmset(args [][]byte, wb *levigo.WriteBatch) interface{} { if (len(args)-1)%2 != 0 { return fmt.Errorf("wrong number of arguments for 'hmset' command") } mk := metaKey(args[0]) length, err := hlen(mk, nil) if err != nil { return err } var added uint32 key := NewKeyBuffer(HashKey, args[0], len(args[1])) for i := 1; i < len(args); i += 2 { key.SetSuffix(args[i]) var res []byte if length > 0 { res, err = DB.Get(DefaultReadOptions, key.Key()) if err != nil { return err } } if res == nil { added++ } wb.Put(key.Key(), args[i+1]) } if added > 0 { setHlen(mk, length+added, wb) } return ReplyOK }
func setLlen(key []byte, l *listDetails, wb *levigo.WriteBatch) { data := make([]byte, 22) data[0] = ListLengthValue binary.BigEndian.PutUint32(data[1:], l.length) data[5] = l.flags binary.BigEndian.PutUint64(data[6:], uint64(l.left)) binary.BigEndian.PutUint64(data[14:], uint64(l.right)) wb.Put(key, data) }
func AddIndex(index [2]string, key []byte, indexDb *levigo.DB, wb *levigo.WriteBatch) error { searchKey := []byte(index[0] + "~" + index[1]) keys, err := indexDb.Get(LReadOptions, searchKey) if err != nil { return err } keys = appendDataKey(keys, key) wb.Put(searchKey, keys) return nil }
func combineSet(keys [][]byte, op int, wb *levigo.WriteBatch) interface{} { var count uint32 res := []interface{}{} members := make(chan *iterSetMember) var storeKey *KeyBuffer var mk []byte if wb != nil { mk = metaKey(keys[0]) _, err := delKey(mk, wb) if err != nil { return err } storeKey = NewKeyBuffer(SetKey, keys[0], 0) keys = keys[1:] } go multiSetIter(keys, members, op != setUnion) combine: for m := range members { switch op { case setInter: for _, k := range m.exists { if !k { continue combine } } case setDiff: for i, k := range m.exists { if i == 0 && !k || i > 0 && k { continue combine } } } if wb != nil { storeKey.SetSuffix(m.member) wb.Put(storeKey.Key(), []byte{}) count++ } else { res = append(res, m.member) } } if wb != nil { if count > 0 { setCard(mk, count, wb) } return count } return res }
// TODO: refactor with above. func RemoveIndex(index [2]string, key []byte, indexDb *levigo.DB, wb *levigo.WriteBatch) error { searchKey := []byte(index[0] + "~" + index[1]) keys, err := indexDb.Get(LReadOptions, searchKey) if err != nil { return err } keys = removeDataKey(keys, key) if len(keys) > 0 { wb.Put(searchKey, keys) } else { wb.Delete(searchKey) } return nil }
func set(k []byte, v []byte, wb *levigo.WriteBatch) error { mk := metaKey(k) res, err := DB.Get(DefaultReadOptions, mk) if err != nil { return err } // If there is a non-string key here, let's delete it first if len(res) > 0 && res[0] != StringLengthValue { del(k, res[0], wb) } setStringLen(mk, len(v), wb) wb.Put(stringKey(k), v) return nil }
func hset(args [][]byte, overwrite bool, wb *levigo.WriteBatch) interface{} { mk := metaKey(args[0]) length, err := hlen(mk, nil) if err != nil { return err } var res []byte key := NewKeyBufferWithSuffix(HashKey, args[0], args[1]).Key() if length > 0 { res, err = DB.Get(DefaultReadOptions, key) if err != nil { return err } } if overwrite || res == nil { wb.Put(key, args[2]) } if res == nil { setHlen(mk, length+1, wb) return 1 } return 0 }
func setCard(key []byte, card uint32, wb *levigo.WriteBatch) { data := make([]byte, 5) data[0] = SetCardValue binary.BigEndian.PutUint32(data[1:], card) wb.Put(key, data) }
func zadd(args [][]byte, wb *levigo.WriteBatch, incr bool) interface{} { var newMembers uint32 var score float64 scoreBytes := make([]byte, 8) setKey := NewKeyBuffer(ZSetKey, args[0], len(args[2])) scoreKey := NewKeyBuffer(ZScoreKey, args[0], 8+len(args[2])) mk := metaKey(args[0]) card, err := zcard(mk, nil) if err != nil { return err } // Iterate through each of the score/member pairs for i := 1; i < len(args); i += 2 { var err error score, err = bconv.ParseFloat(args[i], 64) if err != nil { return fmt.Errorf("'%s' is not a valid float", string(args[1])) } // Check if the member exists setKey.SetSuffix(args[i+1]) var res []byte if card > 0 { res, err = DB.Get(DefaultReadOptions, setKey.Key()) if err != nil { return err } } // set the score key with 8 empty bytes before the member for the score setZScoreKeyMember(scoreKey, args[i+1]) if res != nil { // We got a score from the db, so the member already exists if len(res) != 8 { return InvalidDataError } actualScore := math.Float64frombits(binary.BigEndian.Uint64(res)) if incr { // this is a ZINCRBY, so increment the score score += actualScore } if score == actualScore { // Member already exists with the same score, do nothing continue } // Delete score key for member setZScoreKeyScore(scoreKey, actualScore) wb.Delete(scoreKey.Key()) } else { // No score found, we're adding a new member newMembers++ } // Store the set and score keys binary.BigEndian.PutUint64(scoreBytes, math.Float64bits(score)) setZScoreKeyScore(scoreKey, score) wb.Put(setKey.Key(), scoreBytes) wb.Put(scoreKey.Key(), []byte{}) // The score key is only used for sorting, the value is empty } // Update the set metadata with the new cardinality if newMembers > 0 { setZcard(mk, card+newMembers, wb) } if incr { // This is a ZINCRBY, return the new score return ftoa(score) } return newMembers }
func combineZset(args [][]byte, op int, wb *levigo.WriteBatch) interface{} { var count uint32 res := []interface{}{} members := make(chan *iterZsetMember) var setKey, scoreKey *KeyBuffer scoreBytes := make([]byte, 8) mk := metaKey(args[0]) if wb != nil { _, err := delKey(mk, wb) if err != nil { return err } setKey = NewKeyBuffer(ZSetKey, args[0], 0) scoreKey = NewKeyBuffer(ZScoreKey, args[0], 0) } numKeys, err := bconv.Atoi(args[1]) if err != nil { return InvalidIntError } aggregate := zsetAggSum weights := make([]float64, numKeys) scores := make([]float64, 0, numKeys) for i := 0; i < numKeys; i++ { weights[i] = 1 } argOffset := 2 + numKeys if len(args) > argOffset { if len(args) > argOffset+numKeys { if EqualIgnoreCase(args[argOffset], []byte("weights")) { argOffset += numKeys + 1 for i, w := range args[numKeys+3 : argOffset] { weights[i], err = bconv.ParseFloat(w, 64) if err != nil { return fmt.Errorf("weight value is not a float") } } } else { return SyntaxError } } if len(args) > argOffset { if len(args) == argOffset+2 && EqualIgnoreCase(args[argOffset], []byte("aggregate")) { agg := bytes.ToLower(args[argOffset+1]) switch { case bytes.Equal(agg, []byte("sum")): aggregate = zsetAggSum case bytes.Equal(agg, []byte("min")): aggregate = zsetAggMin case bytes.Equal(agg, []byte("max")): aggregate = zsetAggMax default: return SyntaxError } } else { return SyntaxError } } } go multiZsetIter(args[2:numKeys+2], members, op != zsetUnion) combine: for m := range members { if op == zsetInter { for _, k := range m.exists { if !k { continue combine } } } scores = scores[:0] for i, k := range m.exists { if k { scores = append(scores, m.scores[i]) } } var score float64 for i, s := range scores { scores[i] = s * weights[i] } switch aggregate { case zsetAggSum: for _, s := range scores { score += s } case zsetAggMin: sort.Float64s(scores) score = scores[0] case zsetAggMax: sort.Float64s(scores) score = scores[len(scores)-1] } if wb != nil { setKey.SetSuffix(m.member) binary.BigEndian.PutUint64(scoreBytes, math.Float64bits(score)) setZScoreKeyMember(scoreKey, m.member) setZScoreKeyScore(scoreKey, score) wb.Put(setKey.Key(), scoreBytes) wb.Put(scoreKey.Key(), []byte{}) count++ } else { res = append(res, m.member, ftoa(score)) } } if wb != nil { if count > 0 { setZcard(mk, count, wb) } return count } return res }
func setHlen(key []byte, length uint32, wb *levigo.WriteBatch) { data := make([]byte, 5) data[0] = HashLengthValue binary.BigEndian.PutUint32(data[1:], length) wb.Put(key, data) }
func setStringLen(key []byte, length int, wb *levigo.WriteBatch) { meta := make([]byte, 5) meta[0] = StringLengthValue binary.BigEndian.PutUint32(meta[1:], uint32(length)) wb.Put(key, meta) }