github.com/hdt3213/godis@v1.2.9/database/string.go (about)

     1  package database
     2  
     3  import (
     4  	"math/bits"
     5  	"strconv"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/hdt3213/godis/aof"
    10  	"github.com/hdt3213/godis/datastruct/bitmap"
    11  	"github.com/hdt3213/godis/interface/database"
    12  	"github.com/hdt3213/godis/interface/redis"
    13  	"github.com/hdt3213/godis/lib/utils"
    14  	"github.com/hdt3213/godis/redis/protocol"
    15  	"github.com/shopspring/decimal"
    16  )
    17  
    18  func (db *DB) getAsString(key string) ([]byte, protocol.ErrorReply) {
    19  	entity, ok := db.GetEntity(key)
    20  	if !ok {
    21  		return nil, nil
    22  	}
    23  	bytes, ok := entity.Data.([]byte)
    24  	if !ok {
    25  		return nil, &protocol.WrongTypeErrReply{}
    26  	}
    27  	return bytes, nil
    28  }
    29  
    30  // execGet returns string value bound to the given key
    31  func execGet(db *DB, args [][]byte) redis.Reply {
    32  	key := string(args[0])
    33  	bytes, err := db.getAsString(key)
    34  	if err != nil {
    35  		return err
    36  	}
    37  	if bytes == nil {
    38  		return &protocol.NullBulkReply{}
    39  	}
    40  	return protocol.MakeBulkReply(bytes)
    41  }
    42  
    43  const (
    44  	upsertPolicy = iota // default
    45  	insertPolicy        // set nx
    46  	updatePolicy        // set ex
    47  )
    48  
    49  const unlimitedTTL int64 = 0
    50  
    51  // execGetEX Get the value of key and optionally set its expiration
    52  func execGetEX(db *DB, args [][]byte) redis.Reply {
    53  	key := string(args[0])
    54  	bytes, err := db.getAsString(key)
    55  	ttl := unlimitedTTL
    56  	if err != nil {
    57  		return err
    58  	}
    59  	if bytes == nil {
    60  		return &protocol.NullBulkReply{}
    61  	}
    62  
    63  	for i := 1; i < len(args); i++ {
    64  		arg := strings.ToUpper(string(args[i]))
    65  		if arg == "EX" { // ttl in seconds
    66  			if ttl != unlimitedTTL {
    67  				// ttl has been set
    68  				return &protocol.SyntaxErrReply{}
    69  			}
    70  			if i+1 >= len(args) {
    71  				return &protocol.SyntaxErrReply{}
    72  			}
    73  			ttlArg, err := strconv.ParseInt(string(args[i+1]), 10, 64)
    74  			if err != nil {
    75  				return &protocol.SyntaxErrReply{}
    76  			}
    77  			if ttlArg <= 0 {
    78  				return protocol.MakeErrReply("ERR invalid expire time in getex")
    79  			}
    80  			ttl = ttlArg * 1000
    81  			i++ // skip next arg
    82  		} else if arg == "PX" { // ttl in milliseconds
    83  			if ttl != unlimitedTTL {
    84  				return &protocol.SyntaxErrReply{}
    85  			}
    86  			if i+1 >= len(args) {
    87  				return &protocol.SyntaxErrReply{}
    88  			}
    89  			ttlArg, err := strconv.ParseInt(string(args[i+1]), 10, 64)
    90  			if err != nil {
    91  				return &protocol.SyntaxErrReply{}
    92  			}
    93  			if ttlArg <= 0 {
    94  				return protocol.MakeErrReply("ERR invalid expire time in getex")
    95  			}
    96  			ttl = ttlArg
    97  			i++ // skip next arg
    98  		} else if arg == "PERSIST" {
    99  			if ttl != unlimitedTTL { // PERSIST Cannot be used with EX | PX
   100  				return &protocol.SyntaxErrReply{}
   101  			}
   102  			if i+1 > len(args) {
   103  				return &protocol.SyntaxErrReply{}
   104  			}
   105  			db.Persist(key)
   106  		}
   107  	}
   108  
   109  	if len(args) > 1 {
   110  		if ttl != unlimitedTTL { // EX | PX
   111  			expireTime := time.Now().Add(time.Duration(ttl) * time.Millisecond)
   112  			db.Expire(key, expireTime)
   113  			db.addAof(aof.MakeExpireCmd(key, expireTime).Args)
   114  		} else { // PERSIST
   115  			db.Persist(key) // override ttl
   116  			// we convert to persist command to write aof
   117  			db.addAof(utils.ToCmdLine3("persist", args[0]))
   118  		}
   119  	}
   120  	return protocol.MakeBulkReply(bytes)
   121  }
   122  
   123  // execSet sets string value and time to live to the given key
   124  func execSet(db *DB, args [][]byte) redis.Reply {
   125  	key := string(args[0])
   126  	value := args[1]
   127  	policy := upsertPolicy
   128  	ttl := unlimitedTTL
   129  
   130  	// parse options
   131  	if len(args) > 2 {
   132  		for i := 2; i < len(args); i++ {
   133  			arg := strings.ToUpper(string(args[i]))
   134  			if arg == "NX" { // insert
   135  				if policy == updatePolicy {
   136  					return &protocol.SyntaxErrReply{}
   137  				}
   138  				policy = insertPolicy
   139  			} else if arg == "XX" { // update policy
   140  				if policy == insertPolicy {
   141  					return &protocol.SyntaxErrReply{}
   142  				}
   143  				policy = updatePolicy
   144  			} else if arg == "EX" { // ttl in seconds
   145  				if ttl != unlimitedTTL {
   146  					// ttl has been set
   147  					return &protocol.SyntaxErrReply{}
   148  				}
   149  				if i+1 >= len(args) {
   150  					return &protocol.SyntaxErrReply{}
   151  				}
   152  				ttlArg, err := strconv.ParseInt(string(args[i+1]), 10, 64)
   153  				if err != nil {
   154  					return &protocol.SyntaxErrReply{}
   155  				}
   156  				if ttlArg <= 0 {
   157  					return protocol.MakeErrReply("ERR invalid expire time in set")
   158  				}
   159  				ttl = ttlArg * 1000
   160  				i++ // skip next arg
   161  			} else if arg == "PX" { // ttl in milliseconds
   162  				if ttl != unlimitedTTL {
   163  					return &protocol.SyntaxErrReply{}
   164  				}
   165  				if i+1 >= len(args) {
   166  					return &protocol.SyntaxErrReply{}
   167  				}
   168  				ttlArg, err := strconv.ParseInt(string(args[i+1]), 10, 64)
   169  				if err != nil {
   170  					return &protocol.SyntaxErrReply{}
   171  				}
   172  				if ttlArg <= 0 {
   173  					return protocol.MakeErrReply("ERR invalid expire time in set")
   174  				}
   175  				ttl = ttlArg
   176  				i++ // skip next arg
   177  			} else {
   178  				return &protocol.SyntaxErrReply{}
   179  			}
   180  		}
   181  	}
   182  
   183  	entity := &database.DataEntity{
   184  		Data: value,
   185  	}
   186  
   187  	var result int
   188  	switch policy {
   189  	case upsertPolicy:
   190  		db.PutEntity(key, entity)
   191  		result = 1
   192  	case insertPolicy:
   193  		result = db.PutIfAbsent(key, entity)
   194  	case updatePolicy:
   195  		result = db.PutIfExists(key, entity)
   196  	}
   197  	if result > 0 {
   198  		if ttl != unlimitedTTL {
   199  			expireTime := time.Now().Add(time.Duration(ttl) * time.Millisecond)
   200  			db.Expire(key, expireTime)
   201  			db.addAof(CmdLine{
   202  				[]byte("SET"),
   203  				args[0],
   204  				args[1],
   205  			})
   206  			db.addAof(aof.MakeExpireCmd(key, expireTime).Args)
   207  		} else {
   208  			db.Persist(key) // override ttl
   209  			db.addAof(utils.ToCmdLine3("set", args...))
   210  		}
   211  	}
   212  
   213  	if result > 0 {
   214  		return &protocol.OkReply{}
   215  	}
   216  	return &protocol.NullBulkReply{}
   217  }
   218  
   219  // execSetNX sets string if not exists
   220  func execSetNX(db *DB, args [][]byte) redis.Reply {
   221  	key := string(args[0])
   222  	value := args[1]
   223  	entity := &database.DataEntity{
   224  		Data: value,
   225  	}
   226  	result := db.PutIfAbsent(key, entity)
   227  	db.addAof(utils.ToCmdLine3("setnx", args...))
   228  	return protocol.MakeIntReply(int64(result))
   229  }
   230  
   231  // execSetEX sets string and its ttl
   232  func execSetEX(db *DB, args [][]byte) redis.Reply {
   233  	key := string(args[0])
   234  	value := args[2]
   235  
   236  	ttlArg, err := strconv.ParseInt(string(args[1]), 10, 64)
   237  	if err != nil {
   238  		return &protocol.SyntaxErrReply{}
   239  	}
   240  	if ttlArg <= 0 {
   241  		return protocol.MakeErrReply("ERR invalid expire time in setex")
   242  	}
   243  	ttl := ttlArg * 1000
   244  
   245  	entity := &database.DataEntity{
   246  		Data: value,
   247  	}
   248  
   249  	db.PutEntity(key, entity)
   250  	expireTime := time.Now().Add(time.Duration(ttl) * time.Millisecond)
   251  	db.Expire(key, expireTime)
   252  	db.addAof(utils.ToCmdLine3("setex", args...))
   253  	db.addAof(aof.MakeExpireCmd(key, expireTime).Args)
   254  	return &protocol.OkReply{}
   255  }
   256  
   257  // execPSetEX set a key's time to live in  milliseconds
   258  func execPSetEX(db *DB, args [][]byte) redis.Reply {
   259  	key := string(args[0])
   260  	value := args[2]
   261  
   262  	ttlArg, err := strconv.ParseInt(string(args[1]), 10, 64)
   263  	if err != nil {
   264  		return &protocol.SyntaxErrReply{}
   265  	}
   266  	if ttlArg <= 0 {
   267  		return protocol.MakeErrReply("ERR invalid expire time in setex")
   268  	}
   269  
   270  	entity := &database.DataEntity{
   271  		Data: value,
   272  	}
   273  
   274  	db.PutEntity(key, entity)
   275  	expireTime := time.Now().Add(time.Duration(ttlArg) * time.Millisecond)
   276  	db.Expire(key, expireTime)
   277  	db.addAof(utils.ToCmdLine3("setex", args...))
   278  	db.addAof(aof.MakeExpireCmd(key, expireTime).Args)
   279  
   280  	return &protocol.OkReply{}
   281  }
   282  
   283  func prepareMSet(args [][]byte) ([]string, []string) {
   284  	size := len(args) / 2
   285  	keys := make([]string, size)
   286  	for i := 0; i < size; i++ {
   287  		keys[i] = string(args[2*i])
   288  	}
   289  	return keys, nil
   290  }
   291  
   292  func undoMSet(db *DB, args [][]byte) []CmdLine {
   293  	writeKeys, _ := prepareMSet(args)
   294  	return rollbackGivenKeys(db, writeKeys...)
   295  }
   296  
   297  // execMSet sets multi key-value in database
   298  func execMSet(db *DB, args [][]byte) redis.Reply {
   299  	if len(args)%2 != 0 {
   300  		return protocol.MakeSyntaxErrReply()
   301  	}
   302  
   303  	size := len(args) / 2
   304  	keys := make([]string, size)
   305  	values := make([][]byte, size)
   306  	for i := 0; i < size; i++ {
   307  		keys[i] = string(args[2*i])
   308  		values[i] = args[2*i+1]
   309  	}
   310  
   311  	for i, key := range keys {
   312  		value := values[i]
   313  		db.PutEntity(key, &database.DataEntity{Data: value})
   314  	}
   315  	db.addAof(utils.ToCmdLine3("mset", args...))
   316  	return &protocol.OkReply{}
   317  }
   318  
   319  func prepareMGet(args [][]byte) ([]string, []string) {
   320  	keys := make([]string, len(args))
   321  	for i, v := range args {
   322  		keys[i] = string(v)
   323  	}
   324  	return nil, keys
   325  }
   326  
   327  // execMGet get multi key-value from database
   328  func execMGet(db *DB, args [][]byte) redis.Reply {
   329  	keys := make([]string, len(args))
   330  	for i, v := range args {
   331  		keys[i] = string(v)
   332  	}
   333  
   334  	result := make([][]byte, len(args))
   335  	for i, key := range keys {
   336  		bytes, err := db.getAsString(key)
   337  		if err != nil {
   338  			_, isWrongType := err.(*protocol.WrongTypeErrReply)
   339  			if isWrongType {
   340  				result[i] = nil
   341  				continue
   342  			} else {
   343  				return err
   344  			}
   345  		}
   346  		result[i] = bytes // nil or []byte
   347  	}
   348  
   349  	return protocol.MakeMultiBulkReply(result)
   350  }
   351  
   352  // execMSetNX sets multi key-value in database, only if none of the given keys exist
   353  func execMSetNX(db *DB, args [][]byte) redis.Reply {
   354  	// parse args
   355  	if len(args)%2 != 0 {
   356  		return protocol.MakeSyntaxErrReply()
   357  	}
   358  	size := len(args) / 2
   359  	values := make([][]byte, size)
   360  	keys := make([]string, size)
   361  	for i := 0; i < size; i++ {
   362  		keys[i] = string(args[2*i])
   363  		values[i] = args[2*i+1]
   364  	}
   365  
   366  	for _, key := range keys {
   367  		_, exists := db.GetEntity(key)
   368  		if exists {
   369  			return protocol.MakeIntReply(0)
   370  		}
   371  	}
   372  
   373  	for i, key := range keys {
   374  		value := values[i]
   375  		db.PutEntity(key, &database.DataEntity{Data: value})
   376  	}
   377  	db.addAof(utils.ToCmdLine3("msetnx", args...))
   378  	return protocol.MakeIntReply(1)
   379  }
   380  
   381  // execGetSet sets value of a string-type key and returns its old value
   382  func execGetSet(db *DB, args [][]byte) redis.Reply {
   383  	key := string(args[0])
   384  	value := args[1]
   385  
   386  	old, err := db.getAsString(key)
   387  	if err != nil {
   388  		return err
   389  	}
   390  
   391  	db.PutEntity(key, &database.DataEntity{Data: value})
   392  	db.Persist(key) // override ttl
   393  	db.addAof(utils.ToCmdLine3("set", args...))
   394  	if old == nil {
   395  		return new(protocol.NullBulkReply)
   396  	}
   397  	return protocol.MakeBulkReply(old)
   398  }
   399  
   400  // execGetDel Get the value of key and delete the key.
   401  func execGetDel(db *DB, args [][]byte) redis.Reply {
   402  	key := string(args[0])
   403  
   404  	old, err := db.getAsString(key)
   405  	if err != nil {
   406  		return err
   407  	}
   408  	if old == nil {
   409  		return new(protocol.NullBulkReply)
   410  	}
   411  	db.Remove(key)
   412  
   413  	// We convert to del command to write aof
   414  	db.addAof(utils.ToCmdLine3("del", args...))
   415  	return protocol.MakeBulkReply(old)
   416  }
   417  
   418  // execIncr increments the integer value of a key by one
   419  func execIncr(db *DB, args [][]byte) redis.Reply {
   420  	key := string(args[0])
   421  
   422  	bytes, err := db.getAsString(key)
   423  	if err != nil {
   424  		return err
   425  	}
   426  	if bytes != nil {
   427  		val, err := strconv.ParseInt(string(bytes), 10, 64)
   428  		if err != nil {
   429  			return protocol.MakeErrReply("ERR value is not an integer or out of range")
   430  		}
   431  		db.PutEntity(key, &database.DataEntity{
   432  			Data: []byte(strconv.FormatInt(val+1, 10)),
   433  		})
   434  		db.addAof(utils.ToCmdLine3("incr", args...))
   435  		return protocol.MakeIntReply(val + 1)
   436  	}
   437  	db.PutEntity(key, &database.DataEntity{
   438  		Data: []byte("1"),
   439  	})
   440  	db.addAof(utils.ToCmdLine3("incr", args...))
   441  	return protocol.MakeIntReply(1)
   442  }
   443  
   444  // execIncrBy increments the integer value of a key by given value
   445  func execIncrBy(db *DB, args [][]byte) redis.Reply {
   446  	key := string(args[0])
   447  	rawDelta := string(args[1])
   448  	delta, err := strconv.ParseInt(rawDelta, 10, 64)
   449  	if err != nil {
   450  		return protocol.MakeErrReply("ERR value is not an integer or out of range")
   451  	}
   452  
   453  	bytes, errReply := db.getAsString(key)
   454  	if errReply != nil {
   455  		return errReply
   456  	}
   457  	if bytes != nil {
   458  		// existed value
   459  		val, err := strconv.ParseInt(string(bytes), 10, 64)
   460  		if err != nil {
   461  			return protocol.MakeErrReply("ERR value is not an integer or out of range")
   462  		}
   463  		db.PutEntity(key, &database.DataEntity{
   464  			Data: []byte(strconv.FormatInt(val+delta, 10)),
   465  		})
   466  		db.addAof(utils.ToCmdLine3("incrby", args...))
   467  		return protocol.MakeIntReply(val + delta)
   468  	}
   469  	db.PutEntity(key, &database.DataEntity{
   470  		Data: args[1],
   471  	})
   472  	db.addAof(utils.ToCmdLine3("incrby", args...))
   473  	return protocol.MakeIntReply(delta)
   474  }
   475  
   476  // execIncrByFloat increments the float value of a key by given value
   477  func execIncrByFloat(db *DB, args [][]byte) redis.Reply {
   478  	key := string(args[0])
   479  	rawDelta := string(args[1])
   480  	delta, err := decimal.NewFromString(rawDelta)
   481  	if err != nil {
   482  		return protocol.MakeErrReply("ERR value is not a valid float")
   483  	}
   484  
   485  	bytes, errReply := db.getAsString(key)
   486  	if errReply != nil {
   487  		return errReply
   488  	}
   489  	if bytes != nil {
   490  		val, err := decimal.NewFromString(string(bytes))
   491  		if err != nil {
   492  			return protocol.MakeErrReply("ERR value is not a valid float")
   493  		}
   494  		resultBytes := []byte(val.Add(delta).String())
   495  		db.PutEntity(key, &database.DataEntity{
   496  			Data: resultBytes,
   497  		})
   498  		db.addAof(utils.ToCmdLine3("incrbyfloat", args...))
   499  		return protocol.MakeBulkReply(resultBytes)
   500  	}
   501  	db.PutEntity(key, &database.DataEntity{
   502  		Data: args[1],
   503  	})
   504  	db.addAof(utils.ToCmdLine3("incrbyfloat", args...))
   505  	return protocol.MakeBulkReply(args[1])
   506  }
   507  
   508  // execDecr decrements the integer value of a key by one
   509  func execDecr(db *DB, args [][]byte) redis.Reply {
   510  	key := string(args[0])
   511  
   512  	bytes, errReply := db.getAsString(key)
   513  	if errReply != nil {
   514  		return errReply
   515  	}
   516  	if bytes != nil {
   517  		val, err := strconv.ParseInt(string(bytes), 10, 64)
   518  		if err != nil {
   519  			return protocol.MakeErrReply("ERR value is not an integer or out of range")
   520  		}
   521  		db.PutEntity(key, &database.DataEntity{
   522  			Data: []byte(strconv.FormatInt(val-1, 10)),
   523  		})
   524  		db.addAof(utils.ToCmdLine3("decr", args...))
   525  		return protocol.MakeIntReply(val - 1)
   526  	}
   527  	entity := &database.DataEntity{
   528  		Data: []byte("-1"),
   529  	}
   530  	db.PutEntity(key, entity)
   531  	db.addAof(utils.ToCmdLine3("decr", args...))
   532  	return protocol.MakeIntReply(-1)
   533  }
   534  
   535  // execDecrBy decrements the integer value of a key by onedecrement
   536  func execDecrBy(db *DB, args [][]byte) redis.Reply {
   537  	key := string(args[0])
   538  	rawDelta := string(args[1])
   539  	delta, err := strconv.ParseInt(rawDelta, 10, 64)
   540  	if err != nil {
   541  		return protocol.MakeErrReply("ERR value is not an integer or out of range")
   542  	}
   543  
   544  	bytes, errReply := db.getAsString(key)
   545  	if errReply != nil {
   546  		return errReply
   547  	}
   548  	if bytes != nil {
   549  		val, err := strconv.ParseInt(string(bytes), 10, 64)
   550  		if err != nil {
   551  			return protocol.MakeErrReply("ERR value is not an integer or out of range")
   552  		}
   553  		db.PutEntity(key, &database.DataEntity{
   554  			Data: []byte(strconv.FormatInt(val-delta, 10)),
   555  		})
   556  		db.addAof(utils.ToCmdLine3("decrby", args...))
   557  		return protocol.MakeIntReply(val - delta)
   558  	}
   559  	valueStr := strconv.FormatInt(-delta, 10)
   560  	db.PutEntity(key, &database.DataEntity{
   561  		Data: []byte(valueStr),
   562  	})
   563  	db.addAof(utils.ToCmdLine3("decrby", args...))
   564  	return protocol.MakeIntReply(-delta)
   565  }
   566  
   567  // execStrLen returns len of string value bound to the given key
   568  func execStrLen(db *DB, args [][]byte) redis.Reply {
   569  	key := string(args[0])
   570  	bytes, err := db.getAsString(key)
   571  	if err != nil {
   572  		return err
   573  	}
   574  	if bytes == nil {
   575  		return protocol.MakeIntReply(0)
   576  	}
   577  	return protocol.MakeIntReply(int64(len(bytes)))
   578  }
   579  
   580  // execAppend sets string value to the given key
   581  func execAppend(db *DB, args [][]byte) redis.Reply {
   582  	key := string(args[0])
   583  	bytes, err := db.getAsString(key)
   584  	if err != nil {
   585  		return err
   586  	}
   587  	bytes = append(bytes, args[1]...)
   588  	db.PutEntity(key, &database.DataEntity{
   589  		Data: bytes,
   590  	})
   591  	db.addAof(utils.ToCmdLine3("append", args...))
   592  	return protocol.MakeIntReply(int64(len(bytes)))
   593  }
   594  
   595  // execSetRange overwrites part of the string stored at key, starting at the specified offset.
   596  // If the offset is larger than the current length of the string at key, the string is padded with zero-bytes.
   597  func execSetRange(db *DB, args [][]byte) redis.Reply {
   598  	key := string(args[0])
   599  	offset, errNative := strconv.ParseInt(string(args[1]), 10, 64)
   600  	if errNative != nil {
   601  		return protocol.MakeErrReply(errNative.Error())
   602  	}
   603  	value := args[2]
   604  	bytes, err := db.getAsString(key)
   605  	if err != nil {
   606  		return err
   607  	}
   608  	bytesLen := int64(len(bytes))
   609  	if bytesLen < offset {
   610  		diff := offset - bytesLen
   611  		diffArray := make([]byte, diff)
   612  		bytes = append(bytes, diffArray...)
   613  		bytesLen = int64(len(bytes))
   614  	}
   615  	for i := 0; i < len(value); i++ {
   616  		idx := offset + int64(i)
   617  		if idx >= bytesLen {
   618  			bytes = append(bytes, value[i])
   619  		} else {
   620  			bytes[idx] = value[i]
   621  		}
   622  	}
   623  	db.PutEntity(key, &database.DataEntity{
   624  		Data: bytes,
   625  	})
   626  	db.addAof(utils.ToCmdLine3("setRange", args...))
   627  	return protocol.MakeIntReply(int64(len(bytes)))
   628  }
   629  
   630  func execGetRange(db *DB, args [][]byte) redis.Reply {
   631  	key := string(args[0])
   632  	startIdx, err2 := strconv.ParseInt(string(args[1]), 10, 64)
   633  	if err2 != nil {
   634  		return protocol.MakeErrReply("ERR value is not an integer or out of range")
   635  	}
   636  	endIdx, err2 := strconv.ParseInt(string(args[2]), 10, 64)
   637  	if err2 != nil {
   638  		return protocol.MakeErrReply("ERR value is not an integer or out of range")
   639  	}
   640  
   641  	bs, err := db.getAsString(key)
   642  	if err != nil {
   643  		return err
   644  	}
   645  	if bs == nil {
   646  		return protocol.MakeNullBulkReply()
   647  	}
   648  	bytesLen := int64(len(bs))
   649  	beg, end := utils.ConvertRange(startIdx, endIdx, bytesLen)
   650  	if beg < 0 {
   651  		return protocol.MakeNullBulkReply()
   652  	}
   653  	return protocol.MakeBulkReply(bs[beg:end])
   654  }
   655  
   656  func execSetBit(db *DB, args [][]byte) redis.Reply {
   657  	key := string(args[0])
   658  	offset, err := strconv.ParseInt(string(args[1]), 10, 64)
   659  	if err != nil {
   660  		return protocol.MakeErrReply("ERR bit offset is not an integer or out of range")
   661  	}
   662  	valStr := string(args[2])
   663  	var v byte
   664  	if valStr == "1" {
   665  		v = 1
   666  	} else if valStr == "0" {
   667  		v = 0
   668  	} else {
   669  		return protocol.MakeErrReply("ERR bit is not an integer or out of range")
   670  	}
   671  	bs, errReply := db.getAsString(key)
   672  	if errReply != nil {
   673  		return errReply
   674  	}
   675  	bm := bitmap.FromBytes(bs)
   676  	former := bm.GetBit(offset)
   677  	bm.SetBit(offset, v)
   678  	db.PutEntity(key, &database.DataEntity{Data: bm.ToBytes()})
   679  	db.addAof(utils.ToCmdLine3("setBit", args...))
   680  	return protocol.MakeIntReply(int64(former))
   681  }
   682  
   683  func execGetBit(db *DB, args [][]byte) redis.Reply {
   684  	key := string(args[0])
   685  	offset, err := strconv.ParseInt(string(args[1]), 10, 64)
   686  	if err != nil {
   687  		return protocol.MakeErrReply("ERR bit offset is not an integer or out of range")
   688  	}
   689  	bs, errReply := db.getAsString(key)
   690  	if errReply != nil {
   691  		return errReply
   692  	}
   693  	if bs == nil {
   694  		return protocol.MakeIntReply(0)
   695  	}
   696  	bm := bitmap.FromBytes(bs)
   697  	return protocol.MakeIntReply(int64(bm.GetBit(offset)))
   698  }
   699  
   700  func execBitCount(db *DB, args [][]byte) redis.Reply {
   701  	key := string(args[0])
   702  	bs, err := db.getAsString(key)
   703  	if err != nil {
   704  		return err
   705  	}
   706  	if bs == nil {
   707  		return protocol.MakeIntReply(0)
   708  	}
   709  	byteMode := true
   710  	if len(args) > 3 {
   711  		mode := strings.ToLower(string(args[3]))
   712  		if mode == "bit" {
   713  			byteMode = false
   714  		} else if mode == "byte" {
   715  			byteMode = true
   716  		} else {
   717  			return protocol.MakeErrReply("ERR syntax error")
   718  		}
   719  	}
   720  	var size int64
   721  	bm := bitmap.FromBytes(bs)
   722  	if byteMode {
   723  		size = int64(len(*bm))
   724  	} else {
   725  		size = int64(bm.BitSize())
   726  	}
   727  	var beg, end int
   728  	if len(args) > 1 {
   729  		var err2 error
   730  		var startIdx, endIdx int64
   731  		startIdx, err2 = strconv.ParseInt(string(args[1]), 10, 64)
   732  		if err2 != nil {
   733  			return protocol.MakeErrReply("ERR value is not an integer or out of range")
   734  		}
   735  		endIdx, err2 = strconv.ParseInt(string(args[2]), 10, 64)
   736  		if err2 != nil {
   737  			return protocol.MakeErrReply("ERR value is not an integer or out of range")
   738  		}
   739  		beg, end = utils.ConvertRange(startIdx, endIdx, size)
   740  		if beg < 0 {
   741  			return protocol.MakeIntReply(0)
   742  		}
   743  	}
   744  	var count int64
   745  	if byteMode {
   746  		bm.ForEachByte(beg, end, func(offset int64, val byte) bool {
   747  			count += int64(bits.OnesCount8(val))
   748  			return true
   749  		})
   750  	} else {
   751  		bm.ForEachBit(int64(beg), int64(end), func(offset int64, val byte) bool {
   752  			if val > 0 {
   753  				count++
   754  			}
   755  			return true
   756  		})
   757  	}
   758  	return protocol.MakeIntReply(count)
   759  }
   760  
   761  func execBitPos(db *DB, args [][]byte) redis.Reply {
   762  	key := string(args[0])
   763  	bs, err := db.getAsString(key)
   764  	if err != nil {
   765  		return err
   766  	}
   767  	if bs == nil {
   768  		return protocol.MakeIntReply(-1)
   769  	}
   770  	valStr := string(args[1])
   771  	var v byte
   772  	if valStr == "1" {
   773  		v = 1
   774  	} else if valStr == "0" {
   775  		v = 0
   776  	} else {
   777  		return protocol.MakeErrReply("ERR bit is not an integer or out of range")
   778  	}
   779  	byteMode := true
   780  	if len(args) > 4 {
   781  		mode := strings.ToLower(string(args[4]))
   782  		if mode == "bit" {
   783  			byteMode = false
   784  		} else if mode == "byte" {
   785  			byteMode = true
   786  		} else {
   787  			return protocol.MakeErrReply("ERR syntax error")
   788  		}
   789  	}
   790  	var size int64
   791  	bm := bitmap.FromBytes(bs)
   792  	if byteMode {
   793  		size = int64(len(*bm))
   794  	} else {
   795  		size = int64(bm.BitSize())
   796  	}
   797  	var beg, end int
   798  	if len(args) > 2 {
   799  		var err2 error
   800  		var startIdx, endIdx int64
   801  		startIdx, err2 = strconv.ParseInt(string(args[2]), 10, 64)
   802  		if err2 != nil {
   803  			return protocol.MakeErrReply("ERR value is not an integer or out of range")
   804  		}
   805  		endIdx, err2 = strconv.ParseInt(string(args[3]), 10, 64)
   806  		if err2 != nil {
   807  			return protocol.MakeErrReply("ERR value is not an integer or out of range")
   808  		}
   809  		beg, end = utils.ConvertRange(startIdx, endIdx, size)
   810  		if beg < 0 {
   811  			return protocol.MakeIntReply(0)
   812  		}
   813  	}
   814  	if byteMode {
   815  		beg *= 8
   816  		end *= 8
   817  	}
   818  	var offset = int64(-1)
   819  	bm.ForEachBit(int64(beg), int64(end), func(o int64, val byte) bool {
   820  		if val == v {
   821  			offset = o
   822  			return false
   823  		}
   824  		return true
   825  	})
   826  	return protocol.MakeIntReply(offset)
   827  }
   828  
   829  // GetRandomKey Randomly return (do not delete) a key from the godis
   830  func getRandomKey(db *DB, args [][]byte) redis.Reply {
   831  	k := db.data.RandomKeys(1)
   832  	if len(k) == 0 {
   833  		return &protocol.NullBulkReply{}
   834  	}
   835  	var key []byte
   836  	return protocol.MakeBulkReply(strconv.AppendQuote(key, k[0]))
   837  }
   838  
   839  func init() {
   840  	registerCommand("Set", execSet, writeFirstKey, rollbackFirstKey, -3, flagWrite).
   841  		attachCommandExtra([]string{redisFlagWrite, redisFlagDenyOOM}, 1, 1, 1)
   842  	registerCommand("SetNx", execSetNX, writeFirstKey, rollbackFirstKey, 3, flagWrite).
   843  		attachCommandExtra([]string{redisFlagWrite, redisFlagDenyOOM, redisFlagFast}, 1, 1, 1)
   844  	registerCommand("SetEX", execSetEX, writeFirstKey, rollbackFirstKey, 4, flagWrite).
   845  		attachCommandExtra([]string{redisFlagWrite, redisFlagDenyOOM}, 1, 1, 1)
   846  	registerCommand("PSetEX", execPSetEX, writeFirstKey, rollbackFirstKey, 4, flagWrite).
   847  		attachCommandExtra([]string{redisFlagWrite, redisFlagDenyOOM}, 1, 1, 1)
   848  	registerCommand("MSet", execMSet, prepareMSet, undoMSet, -3, flagWrite).
   849  		attachCommandExtra([]string{redisFlagWrite, redisFlagDenyOOM}, 1, -1, 2)
   850  	registerCommand("MGet", execMGet, prepareMGet, nil, -2, flagReadOnly).
   851  		attachCommandExtra([]string{redisFlagReadonly, redisFlagFast}, 1, 1, 1)
   852  	registerCommand("MSetNX", execMSetNX, prepareMSet, undoMSet, -3, flagWrite).
   853  		attachCommandExtra([]string{redisFlagWrite, redisFlagDenyOOM}, 1, 1, 1)
   854  	registerCommand("Get", execGet, readFirstKey, nil, 2, flagReadOnly).
   855  		attachCommandExtra([]string{redisFlagReadonly, redisFlagFast}, 1, 1, 1)
   856  	registerCommand("GetEX", execGetEX, writeFirstKey, rollbackFirstKey, -2, flagReadOnly).
   857  		attachCommandExtra([]string{redisFlagReadonly, redisFlagFast}, 1, 1, 1)
   858  	registerCommand("GetSet", execGetSet, writeFirstKey, rollbackFirstKey, 3, flagWrite).
   859  		attachCommandExtra([]string{redisFlagWrite, redisFlagDenyOOM}, 1, 1, 1)
   860  	registerCommand("GetDel", execGetDel, writeFirstKey, rollbackFirstKey, 2, flagWrite).
   861  		attachCommandExtra([]string{redisFlagWrite, redisFlagDenyOOM}, 1, 1, 1)
   862  	registerCommand("Incr", execIncr, writeFirstKey, rollbackFirstKey, 2, flagWrite).
   863  		attachCommandExtra([]string{redisFlagWrite, redisFlagDenyOOM, redisFlagFast}, 1, 1, 1)
   864  	registerCommand("IncrBy", execIncrBy, writeFirstKey, rollbackFirstKey, 3, flagWrite).
   865  		attachCommandExtra([]string{redisFlagWrite, redisFlagDenyOOM}, 1, 1, 1)
   866  	registerCommand("IncrByFloat", execIncrByFloat, writeFirstKey, rollbackFirstKey, 3, flagWrite).attachCommandExtra([]string{redisFlagWrite, redisFlagDenyOOM}, 1, 1, 1)
   867  	registerCommand("Decr", execDecr, writeFirstKey, rollbackFirstKey, 2, flagWrite).
   868  		attachCommandExtra([]string{redisFlagWrite, redisFlagDenyOOM}, 1, 1, 1)
   869  	registerCommand("DecrBy", execDecrBy, writeFirstKey, rollbackFirstKey, 3, flagWrite).
   870  		attachCommandExtra([]string{redisFlagWrite, redisFlagDenyOOM}, 1, 1, 1)
   871  	registerCommand("StrLen", execStrLen, readFirstKey, nil, 2, flagReadOnly).
   872  		attachCommandExtra([]string{redisFlagReadonly, redisFlagFast}, 1, 1, 1)
   873  	registerCommand("Append", execAppend, writeFirstKey, rollbackFirstKey, 3, flagWrite).
   874  		attachCommandExtra([]string{redisFlagWrite, redisFlagDenyOOM}, 1, 1, 1)
   875  	registerCommand("SetRange", execSetRange, writeFirstKey, rollbackFirstKey, 4, flagWrite).
   876  		attachCommandExtra([]string{redisFlagWrite, redisFlagDenyOOM}, 1, 1, 1)
   877  	registerCommand("GetRange", execGetRange, readFirstKey, nil, 4, flagReadOnly).
   878  		attachCommandExtra([]string{redisFlagReadonly}, 1, 1, 1)
   879  	registerCommand("SetBit", execSetBit, writeFirstKey, rollbackFirstKey, 4, flagWrite).
   880  		attachCommandExtra([]string{redisFlagWrite, redisFlagDenyOOM}, 1, 1, 1)
   881  	registerCommand("GetBit", execGetBit, readFirstKey, nil, 3, flagReadOnly).
   882  		attachCommandExtra([]string{redisFlagReadonly, redisFlagFast}, 1, 1, 1)
   883  	registerCommand("BitCount", execBitCount, readFirstKey, nil, -2, flagReadOnly).
   884  		attachCommandExtra([]string{redisFlagReadonly}, 1, 1, 1)
   885  	registerCommand("BitPos", execBitPos, readFirstKey, nil, -3, flagReadOnly).
   886  		attachCommandExtra([]string{redisFlagReadonly}, 1, 1, 1)
   887  	registerCommand("Randomkey", getRandomKey, readAllKeys, nil, 1, flagReadOnly).
   888  		attachCommandExtra([]string{redisFlagReadonly, redisFlagRandom}, 1, 1, 1)
   889  }