You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

114 lines
2.3 KiB

  1. // Copyright 2013 Gary Burd
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License"): you may
  4. // not use this file except in compliance with the License. You may obtain
  5. // a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  11. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12. // License for the specific language governing permissions and limitations
  13. // under the License.
  14. package redis_test
  15. import (
  16. "fmt"
  17. "github.com/garyburd/redigo/redis"
  18. )
  19. // zpop pops a value from the ZSET key using WATCH/MULTI/EXEC commands.
  20. func zpop(c redis.Conn, key string) (result string, err error) {
  21. defer func() {
  22. // Return connection to normal state on error.
  23. if err != nil {
  24. c.Do("DISCARD")
  25. }
  26. }()
  27. // Loop until transaction is successful.
  28. for {
  29. if _, err := c.Do("WATCH", key); err != nil {
  30. return "", err
  31. }
  32. members, err := redis.Strings(c.Do("ZRANGE", key, 0, 0))
  33. if err != nil {
  34. return "", err
  35. }
  36. if len(members) != 1 {
  37. return "", redis.ErrNil
  38. }
  39. c.Send("MULTI")
  40. c.Send("ZREM", key, members[0])
  41. queued, err := c.Do("EXEC")
  42. if err != nil {
  43. return "", err
  44. }
  45. if queued != nil {
  46. result = members[0]
  47. break
  48. }
  49. }
  50. return result, nil
  51. }
  52. // zpopScript pops a value from a ZSET.
  53. var zpopScript = redis.NewScript(1, `
  54. local r = redis.call('ZRANGE', KEYS[1], 0, 0)
  55. if r ~= nil then
  56. r = r[1]
  57. redis.call('ZREM', KEYS[1], r)
  58. end
  59. return r
  60. `)
  61. // This example implements ZPOP as described at
  62. // http://redis.io/topics/transactions using WATCH/MULTI/EXEC and scripting.
  63. func Example_zpop() {
  64. c, err := dial()
  65. if err != nil {
  66. fmt.Println(err)
  67. return
  68. }
  69. defer c.Close()
  70. // Add test data using a pipeline.
  71. for i, member := range []string{"red", "blue", "green"} {
  72. c.Send("ZADD", "zset", i, member)
  73. }
  74. if _, err := c.Do(""); err != nil {
  75. fmt.Println(err)
  76. return
  77. }
  78. // Pop using WATCH/MULTI/EXEC
  79. v, err := zpop(c, "zset")
  80. if err != nil {
  81. fmt.Println(err)
  82. return
  83. }
  84. fmt.Println(v)
  85. // Pop using a script.
  86. v, err = redis.String(zpopScript.Do(c, "zset"))
  87. if err != nil {
  88. fmt.Println(err)
  89. return
  90. }
  91. fmt.Println(v)
  92. // Output:
  93. // red
  94. // blue
  95. }