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 zrangebyscore(args [][]byte, flag zrangeFlag, wb *levigo.WriteBatch) interface{} { // use a snapshot for this read so that the zcard is consistent snapshot := DB.NewSnapshot() opts := levigo.NewReadOptions() opts.SetSnapshot(snapshot) defer opts.Close() defer DB.ReleaseSnapshot(snapshot) mk := metaKey(args[0]) card, err := zcard(mk, opts) if err != nil { return err } var minExclusive, maxExclusive bool if args[1][0] == '(' { minExclusive = true args[1] = args[1][1:] } if args[2][0] == '(' { maxExclusive = true args[2] = args[2][1:] } min, err := bconv.ParseFloat(args[1], 64) max, err2 := bconv.ParseFloat(args[2], 64) if err != nil || err2 != nil { return fmt.Errorf("min or max is not a float") } if flag == zrangeReverse { min, max = max, min minExclusive, maxExclusive = maxExclusive, minExclusive } if card == 0 || min > max { if flag <= zrangeReverse { return []interface{}{} } else { return 0 } } // shortcut for zcount of -Inf to +Inf if flag == zrangeCount && math.IsInf(min, -1) && math.IsInf(max, 1) { return card } var withscores bool var offset, total int64 = 0, -1 if flag <= zrangeReverse && len(args) > 3 { if len(args) == 4 || len(args) == 7 { if EqualIgnoreCase(args[3], []byte("withscores")) { withscores = true } } else if len(args) != 6 { return SyntaxError } if len(args) >= 6 { if EqualIgnoreCase(args[len(args)-3], []byte("limit")) { offset, err = bconv.ParseInt(args[len(args)-2], 10, 64) total, err2 = bconv.ParseInt(args[len(args)-1], 10, 64) if err != nil || err2 != nil { return InvalidIntError } if offset < 0 || total < 1 { return []interface{}{} } } else { return SyntaxError } } } it := DB.NewIterator(opts) defer it.Close() var deleted, count uint32 var deleteKey *KeyBuffer if flag == zrangeDelete { deleteKey = NewKeyBuffer(ZSetKey, args[0], 0) } res := []interface{}{} iterKey := NewKeyBuffer(ZScoreKey, args[0], 8) if flag != zrangeReverse { setZScoreKeyScore(iterKey, min) } else { setZScoreKeyScore(iterKey, max) iterKey.ReverseIterKey() } it.Seek(iterKey.Key()) for i := int64(0); it.Valid(); i++ { if flag == zrangeReverse { it.Prev() } if i >= offset { if total > -1 && i-offset >= total { break } k := it.Key() if !iterKey.IsPrefixOf(k) { break } score, member := parseZScoreKey(it.Key(), len(args[0])) if (!minExclusive && score < min) || (minExclusive && score <= min) { if flag != zrangeReverse { it.Next() } continue } if (!maxExclusive && score > max) || (maxExclusive && score >= max) { break } if flag <= zrangeReverse { res = append(res, member) if withscores { res = append(res, ftoa(score)) } } if flag == zrangeDelete { deleteKey.SetSuffix(member) wb.Delete(k) wb.Delete(deleteKey.Key()) deleted++ } if flag == zrangeCount { count++ } } if flag != zrangeReverse { it.Next() } } if flag == zrangeDelete && deleted == card { wb.Delete(mk) } else if deleted > 0 { setZcard(mk, card-deleted, wb) } if flag == zrangeDelete { return deleted } if flag == zrangeCount { return count } return res }
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 }