func getbit(v resp.CommandArgs, ex *CommandExtras) error { ex.DB.RLock() defer ex.DB.RUnlock() exists, tipe, _ := ex.DB.Has(v[0]) if !exists { return resp.ZeroInteger.WriteTo(ex.Buffer) } if tipe != storage.String { return resp.NewError(ErrWrongType).WriteTo(ex.Buffer) } val := ex.DB.GetString(v[0]) offset, err := strconv.Atoi(string(v[1])) if err != nil { return resp.NewError(ErrNotValidInt).WriteTo(ex.Buffer) } if offset >= 8*len(val) { return resp.ZeroInteger.WriteTo(ex.Buffer) } byten := offset / 8 pos := offset % 8 k := val[byten] >> uint32(7-pos) & 0x01 return resp.Integer(k).WriteTo(ex.Buffer) }
func setrange(v resp.CommandArgs, ex *CommandExtras) error { i64, err := strconv.ParseInt(string(v[1]), 10, 32) if err != nil { return resp.NewError(ErrNotValidInt).WriteTo(ex.Buffer) } offset := int(i64) if offset < 0 { return resp.NewError(ErrOffsetOutRange).WriteTo(ex.Buffer) } if offset+len(v[2]) > 536870912 { // 512M is the limit length return resp.NewError(ErrStringExccedLimit).WriteTo(ex.Buffer) } ex.DB.Lock() defer ex.DB.Unlock() exists, tipe, expireAt := ex.DB.Has(v[0]) if exists && tipe != storage.String { return resp.NewError(ErrWrongType).WriteTo(ex.Buffer) } val := []byte("") if exists { val = ex.DB.GetString(v[0]) } if len(val) < offset+len(v[2]) { val = append(val, make([]byte, len(v[2])+offset-len(val))...) } copy(val[offset:], v[2]) ex.DB.PutString(v[0], val, expireAt) return resp.Integer(len(val)).WriteTo(ex.Buffer) }
func hdel(v resp.CommandArgs, ex *CommandExtras) error { if len(v) < 2 { return resp.NewError(ErrFmtWrongNumberArgument, "hdel").WriteTo(ex.Buffer) } ex.DB.Lock() defer ex.DB.Unlock() keyExists, tipe, _ := ex.DB.Has(v[0]) if !keyExists { return resp.ZeroInteger.WriteTo(ex.Buffer) } if keyExists && tipe != storage.Hash { return resp.NewError(ErrWrongType).WriteTo(ex.Buffer) } fields := [][]byte{} for _, field := range v[1:] { fields = append(fields, []byte(field)) } hash := ex.DB.GetHashFields(v[0], fields) count := 0 for _, value := range hash { if value != nil { count++ } } ex.DB.DeleteHashFields(v[0], fields) return resp.Integer(count).WriteTo(ex.Buffer) }
func hincrby(v resp.CommandArgs, ex *CommandExtras) error { by, err := strconv.ParseInt(v[2].String(), 10, 64) if err != nil { return resp.NewError(ErrNotValidInt).WriteTo(ex.Buffer) } ex.DB.Lock() defer ex.DB.Unlock() keyExists, tipe, expireAt := ex.DB.Has(v[0]) if keyExists && tipe != storage.Hash { return resp.NewError(ErrWrongType).WriteTo(ex.Buffer) } hash := ex.DB.GetHashFields(v[0], [][]byte{v[1]}) newVal := int64(0) if hash[string(v[1])] == nil { newVal += by } else { i, err := strconv.ParseInt(string(hash[string(v[1])]), 10, 64) if err != nil { return resp.NewError(ErrNotValidInt).WriteTo(ex.Buffer) } newVal = i + by } hash[string(v[1])] = []byte(strconv.FormatInt(newVal, 10)) ex.DB.PutHash(v[0], hash, expireAt) return resp.Integer(newVal).WriteTo(ex.Buffer) }
func del(v resp.CommandArgs, ex *CommandExtras) error { if len(v) == 0 { return resp.NewError(ErrFmtWrongNumberArgument, "del").WriteTo(ex.Buffer) } ex.DB.Lock() defer ex.DB.Unlock() count := 0 for _, key := range v { exists, tipe, _ := ex.DB.Has(key) if !exists { continue } switch tipe { case storage.String: ex.DB.DeleteString(key) case storage.Hash: ex.DB.DeleteHash(key) } count++ } return resp.Integer(count).WriteTo(ex.Buffer) }
func bitcount(v resp.CommandArgs, ex *CommandExtras) error { if len(v) == 0 { return resp.NewError(ErrFmtWrongNumberArgument, "bitcount").WriteTo(ex.Buffer) } ex.DB.RLock() defer ex.DB.RUnlock() exists, tipe, _ := ex.DB.Has(v[0]) if !exists { return resp.ZeroInteger.WriteTo(ex.Buffer) } if tipe != storage.String { return resp.NewError(ErrWrongType).WriteTo(ex.Buffer) } if len(v) != 1 && len(v) != 3 { return resp.NewError(ErrFmtSyntax).WriteTo(ex.Buffer) } val := ex.DB.GetString(v[0]) start := 0 end := len(val) var err error if len(v) == 3 { start, err = strconv.Atoi(string(v[1])) if err != nil { return resp.NewError(ErrNotValidInt).WriteTo(ex.Buffer) } end, err = strconv.Atoi(string(v[2])) if err != nil { return resp.NewError(ErrNotValidInt).WriteTo(ex.Buffer) } start, end = calcRange(start, end, len(val)) } if end <= start { return resp.ZeroInteger.WriteTo(ex.Buffer) } sum := 0 for _, b := range val[start:end] { sum += countSetBits[b] } return resp.Integer(sum).WriteTo(ex.Buffer) }
func setbit(v resp.CommandArgs, ex *CommandExtras) error { i64, err := strconv.ParseInt(string(v[1]), 10, 32) if err != nil { return resp.NewError(ErrNotValidInt).WriteTo(ex.Buffer) } offset := uint32(i64) pos := offset % 8 byten := offset / 8 if int(byten)+1 > STRLIMIT { return resp.NewError(ErrStringExccedLimit).WriteTo(ex.Buffer) } bit, err := strconv.Atoi(string(v[2])) if err != nil || bit != 0 && bit != 1 { return resp.NewError(ErrBitValueInvalid).WriteTo(ex.Buffer) } ex.DB.Lock() defer ex.DB.Unlock() exists, tipe, expireAt := ex.DB.Has(v[0]) if exists && tipe != storage.String { return resp.NewError(ErrWrongType).WriteTo(ex.Buffer) } val := []byte("") if exists { val = ex.DB.GetString(v[0]) } if uint32(len(val)) < byten+1 { val = append(val, make([]byte, int(byten)+1-len(val))...) } k := val[byten] >> uint32(7-pos) & 0x01 switch bit { case 0: clear := byte(^(0x01 << (7 - pos))) val[byten] = val[byten] & clear case 1: set := byte(0x01 << (7 - pos)) val[byten] = val[byten] | set } ex.DB.PutString(v[0], val, expireAt) return resp.Integer(k).WriteTo(ex.Buffer) }
func strlen(v resp.CommandArgs, ex *CommandExtras) error { ex.DB.RLock() defer ex.DB.RUnlock() exists, tipe, _ := ex.DB.Has(v[0]) if !exists { return resp.ZeroInteger.WriteTo(ex.Buffer) } if tipe != storage.String { return resp.NewError(ErrWrongType).WriteTo(ex.Buffer) } val := ex.DB.GetString(v[0]) return resp.Integer(len(val)).WriteTo(ex.Buffer) }
func hstrlen(v resp.CommandArgs, ex *CommandExtras) error { ex.DB.RLock() defer ex.DB.RUnlock() keyExists, tipe, _ := ex.DB.Has(v[0]) if !keyExists { return resp.ZeroInteger.WriteTo(ex.Buffer) } if keyExists && tipe != storage.Hash { return resp.NewError(ErrWrongType).WriteTo(ex.Buffer) } hash := ex.DB.GetHashFields(v[0], [][]byte{v[1]}) return resp.Integer(len(hash[string(v[1])])).WriteTo(ex.Buffer) }
func hlen(v resp.CommandArgs, ex *CommandExtras) error { ex.DB.RLock() defer ex.DB.RUnlock() keyExists, tipe, _ := ex.DB.Has(v[0]) if !keyExists { return resp.ZeroInteger.WriteTo(ex.Buffer) } if keyExists && tipe != storage.Hash { return resp.NewError(ErrWrongType).WriteTo(ex.Buffer) } fields := ex.DB.GetHashFieldNames(v[0]) return resp.Integer(len(fields)).WriteTo(ex.Buffer) }
func exists(v resp.CommandArgs, ex *CommandExtras) error { if len(v) == 0 { return resp.NewError(ErrFmtWrongNumberArgument, "exists").WriteTo(ex.Buffer) } ex.DB.RLock() defer ex.DB.RUnlock() count := 0 for _, key := range v { exists, _, _ := ex.DB.Has(key) if !exists { continue } count++ } return resp.Integer(count).WriteTo(ex.Buffer) }
// use appendx for append command, because append is a key word of golang func appendx(v resp.CommandArgs, ex *CommandExtras) error { ex.DB.Lock() defer ex.DB.Unlock() exists, tipe, expireAt := ex.DB.Has(v[0]) if exists && tipe != storage.String { return resp.NewError(ErrWrongType).WriteTo(ex.Buffer) } val := []byte("") if exists { val = ex.DB.GetString(v[0]) } if len(val)+len(v[1]) > STRLIMIT { return resp.NewError(ErrStringExccedLimit).WriteTo(ex.Buffer) } val = append(val, v[1]...) ex.DB.PutString(v[0], val, expireAt) return resp.Integer(len(val)).WriteTo(ex.Buffer) }
func incrdecrHelper(v resp.CommandArgs, ex *CommandExtras, by int64) error { ex.DB.Lock() defer ex.DB.Unlock() exists, tipe, expireAt := ex.DB.Has(v[0]) if exists && tipe != storage.String { return resp.NewError(ErrWrongType).WriteTo(ex.Buffer) } newVal := int64(0) if !exists { newVal += by } else { val := ex.DB.GetString(v[0]) i, err := strconv.ParseInt(string(val), 10, 64) if err != nil { return resp.NewError(ErrNotValidInt).WriteTo(ex.Buffer) } newVal = i + by } ex.DB.PutString(v[0], []byte(strconv.FormatInt(newVal, 10)), expireAt) return resp.Integer(newVal).WriteTo(ex.Buffer) }
func bitpos(v resp.CommandArgs, ex *CommandExtras) error { if len(v) < 2 { return resp.NewError(ErrFmtWrongNumberArgument, "bitpos").WriteTo(ex.Buffer) } arg, err := strconv.Atoi(string(v[1])) if err != nil || arg != 0 && arg != 1 { return resp.NewError(ErrShouldBe0or1).WriteTo(ex.Buffer) } set := arg == 1 // set bit pos clear := arg == 0 // clear bit pos ex.DB.RLock() defer ex.DB.RUnlock() exists, tipe, _ := ex.DB.Has(v[0]) if exists && tipe != storage.String { return resp.NewError(ErrWrongType).WriteTo(ex.Buffer) } // This is the same behavior as offical redis. Not sure why // not check the len(v) when key is missing if !exists && set { return resp.NegativeOneInteger.WriteTo(ex.Buffer) } if !exists && clear { return resp.ZeroInteger.WriteTo(ex.Buffer) } // Seam that: check the len(v) only when the key exists if len(v) > 4 { return resp.NewError(ErrFmtSyntax).WriteTo(ex.Buffer) } val := ex.DB.GetString(v[0]) // Get the range. start := 0 end := len(val) if len(v) >= 3 { start, err = strconv.Atoi(string(v[2])) if err != nil { return resp.NewError(ErrNotValidInt).WriteTo(ex.Buffer) } } if len(v) == 4 { end, err = strconv.Atoi(string(v[3])) if err != nil { return resp.NewError(ErrNotValidInt).WriteTo(ex.Buffer) } } start, end = calcRange(start, end, len(val)) if end <= start { return resp.NegativeOneInteger.WriteTo(ex.Buffer) } // Get the postion in the range pos := 0 found := false for _, b := range val[start:end] { if clear && posFirstClear[b] != 8 { found = true pos += posFirstClear[b] break } if set && posFirstSet[b] != -1 { found = true pos += posFirstSet[b] break } pos += 8 // not found, pos += 1*byte } if found { return resp.Integer(8*start + pos).WriteTo(ex.Buffer) } // From http://redis.io/commands/bitpos // If we look for set bits (the bit argument is 1) and the string is // empty or composed of just zero bytes, -1 is returned. if !found && set { return resp.NegativeOneInteger.WriteTo(ex.Buffer) } // If we look for clear bits (the bit argument is 0) and the string only // contains bit set to 1, the function returns the first bit not part of // the string on the right. So if the string is three bytes set to the // value 0xff the command BITPOS key 0 will return 24, since up to bit 23 // all the bits are 1. // Basically, the function considers the right of the string as padded with // zeros if you look for clear bits and specify no range or the start argument // only. if !found && clear && len(v) < 4 { //len(v) < 4: no range 'end' specified return resp.Integer(8 * end).WriteTo(ex.Buffer) } // However, this behavior changes if you are looking for clear bits and // specify a range with both start and end. If no clear bit is found in // the specified range, the function returns -1 as the user specified a // clear range and there are no 0 bits in that range. if !found && clear && len(v) == 4 { return resp.NegativeOneInteger.WriteTo(ex.Buffer) } return resp.NegativeOneInteger.WriteTo(ex.Buffer) // Should NEVER called }
func bitop(v resp.CommandArgs, ex *CommandExtras) error { if len(v) < 3 { return resp.NewError(ErrFmtWrongNumberArgument, "bitop").WriteTo(ex.Buffer) } ex.DB.Lock() defer ex.DB.Unlock() op := strings.ToLower(string(v[0])) switch op { case "not": if len(v) > 3 { return resp.NewError(ErrBitOPNotError).WriteTo(ex.Buffer) } exists, tipe, _ := ex.DB.Has(v[2]) if !exists { return resp.ZeroInteger.WriteTo(ex.Buffer) } if exists && tipe != storage.String { return resp.NewError(ErrWrongType).WriteTo(ex.Buffer) } val := ex.DB.GetString(v[2]) destValue := make([]byte, len(val)) for i, b := range val { destValue[i] = ^b } ex.DB.PutString(v[1], destValue, nil) return resp.Integer(len(destValue)).WriteTo(ex.Buffer) case "or", "and", "xor": var destValue []byte = nil for _, b := range v[2:] { exists, tipe, _ := ex.DB.Has(b) if exists && tipe != storage.String { return resp.NewError(ErrWrongType).WriteTo(ex.Buffer) } val := ex.DB.GetString(b) if exists && len(destValue) < len(val) { if len(destValue) == 0 { // loop first step destValue = append(destValue, val...) continue } else { destValue = append(destValue, make([]byte, len(val)-len(destValue))...) } } for i, _ := range destValue { s := byte(0) if exists && i < len(val) { s = val[i] } switch op { case "or": destValue[i] |= s case "and": destValue[i] &= s case "xor": destValue[i] ^= s } } } ex.DB.PutString(v[1], destValue, nil) return resp.Integer(len(destValue)).WriteTo(ex.Buffer) default: return resp.NewError(ErrSyntax).WriteTo(ex.Buffer) } }