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 }