redis 3.3.3 → 5.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +280 -12
  3. data/README.md +141 -147
  4. data/lib/redis/client.rb +77 -539
  5. data/lib/redis/commands/bitmaps.rb +66 -0
  6. data/lib/redis/commands/cluster.rb +28 -0
  7. data/lib/redis/commands/connection.rb +53 -0
  8. data/lib/redis/commands/geo.rb +84 -0
  9. data/lib/redis/commands/hashes.rb +254 -0
  10. data/lib/redis/commands/hyper_log_log.rb +37 -0
  11. data/lib/redis/commands/keys.rb +437 -0
  12. data/lib/redis/commands/lists.rb +285 -0
  13. data/lib/redis/commands/pubsub.rb +54 -0
  14. data/lib/redis/commands/scripting.rb +114 -0
  15. data/lib/redis/commands/server.rb +188 -0
  16. data/lib/redis/commands/sets.rb +214 -0
  17. data/lib/redis/commands/sorted_sets.rb +818 -0
  18. data/lib/redis/commands/streams.rb +384 -0
  19. data/lib/redis/commands/strings.rb +314 -0
  20. data/lib/redis/commands/transactions.rb +115 -0
  21. data/lib/redis/commands.rb +235 -0
  22. data/lib/redis/distributed.rb +300 -108
  23. data/lib/redis/errors.rb +22 -1
  24. data/lib/redis/hash_ring.rb +36 -79
  25. data/lib/redis/pipeline.rb +69 -83
  26. data/lib/redis/subscribe.rb +26 -19
  27. data/lib/redis/version.rb +3 -1
  28. data/lib/redis.rb +113 -2685
  29. metadata +40 -218
  30. data/.gitignore +0 -16
  31. data/.travis/Gemfile +0 -11
  32. data/.travis.yml +0 -89
  33. data/.yardopts +0 -3
  34. data/Gemfile +0 -4
  35. data/Rakefile +0 -87
  36. data/benchmarking/logging.rb +0 -71
  37. data/benchmarking/pipeline.rb +0 -51
  38. data/benchmarking/speed.rb +0 -21
  39. data/benchmarking/suite.rb +0 -24
  40. data/benchmarking/worker.rb +0 -71
  41. data/examples/basic.rb +0 -15
  42. data/examples/consistency.rb +0 -114
  43. data/examples/dist_redis.rb +0 -43
  44. data/examples/incr-decr.rb +0 -17
  45. data/examples/list.rb +0 -26
  46. data/examples/pubsub.rb +0 -37
  47. data/examples/sentinel/sentinel.conf +0 -9
  48. data/examples/sentinel/start +0 -49
  49. data/examples/sentinel.rb +0 -41
  50. data/examples/sets.rb +0 -36
  51. data/examples/unicorn/config.ru +0 -3
  52. data/examples/unicorn/unicorn.rb +0 -20
  53. data/lib/redis/connection/command_helper.rb +0 -44
  54. data/lib/redis/connection/hiredis.rb +0 -66
  55. data/lib/redis/connection/registry.rb +0 -12
  56. data/lib/redis/connection/ruby.rb +0 -429
  57. data/lib/redis/connection/synchrony.rb +0 -133
  58. data/lib/redis/connection.rb +0 -9
  59. data/redis.gemspec +0 -44
  60. data/test/bitpos_test.rb +0 -69
  61. data/test/blocking_commands_test.rb +0 -42
  62. data/test/client_test.rb +0 -59
  63. data/test/command_map_test.rb +0 -30
  64. data/test/commands_on_hashes_test.rb +0 -21
  65. data/test/commands_on_hyper_log_log_test.rb +0 -21
  66. data/test/commands_on_lists_test.rb +0 -20
  67. data/test/commands_on_sets_test.rb +0 -77
  68. data/test/commands_on_sorted_sets_test.rb +0 -137
  69. data/test/commands_on_strings_test.rb +0 -101
  70. data/test/commands_on_value_types_test.rb +0 -133
  71. data/test/connection_handling_test.rb +0 -277
  72. data/test/db/.gitkeep +0 -0
  73. data/test/distributed_blocking_commands_test.rb +0 -46
  74. data/test/distributed_commands_on_hashes_test.rb +0 -10
  75. data/test/distributed_commands_on_hyper_log_log_test.rb +0 -33
  76. data/test/distributed_commands_on_lists_test.rb +0 -22
  77. data/test/distributed_commands_on_sets_test.rb +0 -83
  78. data/test/distributed_commands_on_sorted_sets_test.rb +0 -18
  79. data/test/distributed_commands_on_strings_test.rb +0 -59
  80. data/test/distributed_commands_on_value_types_test.rb +0 -95
  81. data/test/distributed_commands_requiring_clustering_test.rb +0 -164
  82. data/test/distributed_connection_handling_test.rb +0 -23
  83. data/test/distributed_internals_test.rb +0 -79
  84. data/test/distributed_key_tags_test.rb +0 -52
  85. data/test/distributed_persistence_control_commands_test.rb +0 -26
  86. data/test/distributed_publish_subscribe_test.rb +0 -92
  87. data/test/distributed_remote_server_control_commands_test.rb +0 -66
  88. data/test/distributed_scripting_test.rb +0 -102
  89. data/test/distributed_sorting_test.rb +0 -20
  90. data/test/distributed_test.rb +0 -58
  91. data/test/distributed_transactions_test.rb +0 -32
  92. data/test/encoding_test.rb +0 -18
  93. data/test/error_replies_test.rb +0 -59
  94. data/test/fork_safety_test.rb +0 -65
  95. data/test/helper.rb +0 -232
  96. data/test/helper_test.rb +0 -24
  97. data/test/internals_test.rb +0 -457
  98. data/test/lint/blocking_commands.rb +0 -150
  99. data/test/lint/hashes.rb +0 -162
  100. data/test/lint/hyper_log_log.rb +0 -60
  101. data/test/lint/lists.rb +0 -143
  102. data/test/lint/sets.rb +0 -140
  103. data/test/lint/sorted_sets.rb +0 -316
  104. data/test/lint/strings.rb +0 -260
  105. data/test/lint/value_types.rb +0 -122
  106. data/test/persistence_control_commands_test.rb +0 -26
  107. data/test/pipelining_commands_test.rb +0 -242
  108. data/test/publish_subscribe_test.rb +0 -282
  109. data/test/remote_server_control_commands_test.rb +0 -118
  110. data/test/scanning_test.rb +0 -413
  111. data/test/scripting_test.rb +0 -78
  112. data/test/sentinel_command_test.rb +0 -80
  113. data/test/sentinel_test.rb +0 -255
  114. data/test/sorting_test.rb +0 -59
  115. data/test/ssl_test.rb +0 -73
  116. data/test/support/connection/hiredis.rb +0 -1
  117. data/test/support/connection/ruby.rb +0 -1
  118. data/test/support/connection/synchrony.rb +0 -17
  119. data/test/support/redis_mock.rb +0 -130
  120. data/test/support/ssl/gen_certs.sh +0 -31
  121. data/test/support/ssl/trusted-ca.crt +0 -25
  122. data/test/support/ssl/trusted-ca.key +0 -27
  123. data/test/support/ssl/trusted-cert.crt +0 -81
  124. data/test/support/ssl/trusted-cert.key +0 -28
  125. data/test/support/ssl/untrusted-ca.crt +0 -26
  126. data/test/support/ssl/untrusted-ca.key +0 -27
  127. data/test/support/ssl/untrusted-cert.crt +0 -82
  128. data/test/support/ssl/untrusted-cert.key +0 -28
  129. data/test/support/wire/synchrony.rb +0 -24
  130. data/test/support/wire/thread.rb +0 -5
  131. data/test/synchrony_driver.rb +0 -88
  132. data/test/test.conf.erb +0 -9
  133. data/test/thread_safety_test.rb +0 -62
  134. data/test/transactions_test.rb +0 -264
  135. data/test/unknown_commands_test.rb +0 -14
  136. data/test/url_param_test.rb +0 -138
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Redis
4
+ module Commands
5
+ module Transactions
6
+ # Mark the start of a transaction block.
7
+ #
8
+ # @example With a block
9
+ # redis.multi do |multi|
10
+ # multi.set("key", "value")
11
+ # multi.incr("counter")
12
+ # end # => ["OK", 6]
13
+ #
14
+ # @yield [multi] the commands that are called inside this block are cached
15
+ # and written to the server upon returning from it
16
+ # @yieldparam [Redis] multi `self`
17
+ #
18
+ # @return [Array<...>]
19
+ # - an array with replies
20
+ #
21
+ # @see #watch
22
+ # @see #unwatch
23
+ def multi
24
+ synchronize do |client|
25
+ client.multi do |raw_transaction|
26
+ yield MultiConnection.new(raw_transaction)
27
+ end
28
+ end
29
+ end
30
+
31
+ # Watch the given keys to determine execution of the MULTI/EXEC block.
32
+ #
33
+ # Using a block is optional, but is necessary for thread-safety.
34
+ #
35
+ # An `#unwatch` is automatically issued if an exception is raised within the
36
+ # block that is a subclass of StandardError and is not a ConnectionError.
37
+ #
38
+ # @example With a block
39
+ # redis.watch("key") do
40
+ # if redis.get("key") == "some value"
41
+ # redis.multi do |multi|
42
+ # multi.set("key", "other value")
43
+ # multi.incr("counter")
44
+ # end
45
+ # else
46
+ # redis.unwatch
47
+ # end
48
+ # end
49
+ # # => ["OK", 6]
50
+ #
51
+ # @example Without a block
52
+ # redis.watch("key")
53
+ # # => "OK"
54
+ #
55
+ # @param [String, Array<String>] keys one or more keys to watch
56
+ # @return [Object] if using a block, returns the return value of the block
57
+ # @return [String] if not using a block, returns `OK`
58
+ #
59
+ # @see #unwatch
60
+ # @see #multi
61
+ def watch(*keys)
62
+ synchronize do |client|
63
+ res = client.call_v([:watch] + keys)
64
+
65
+ if block_given?
66
+ begin
67
+ yield(self)
68
+ rescue ConnectionError
69
+ raise
70
+ rescue StandardError
71
+ unwatch
72
+ raise
73
+ end
74
+ else
75
+ res
76
+ end
77
+ end
78
+ end
79
+
80
+ # Forget about all watched keys.
81
+ #
82
+ # @return [String] `OK`
83
+ #
84
+ # @see #watch
85
+ # @see #multi
86
+ def unwatch
87
+ send_command([:unwatch])
88
+ end
89
+
90
+ # Execute all commands issued after MULTI.
91
+ #
92
+ # Only call this method when `#multi` was called **without** a block.
93
+ #
94
+ # @return [nil, Array<...>]
95
+ # - when commands were not executed, `nil`
96
+ # - when commands were executed, an array with their replies
97
+ #
98
+ # @see #multi
99
+ # @see #discard
100
+ def exec
101
+ send_command([:exec])
102
+ end
103
+
104
+ # Discard all commands issued after MULTI.
105
+ #
106
+ # @return [String] `"OK"`
107
+ #
108
+ # @see #multi
109
+ # @see #exec
110
+ def discard
111
+ send_command([:discard])
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,235 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "redis/commands/bitmaps"
4
+ require "redis/commands/cluster"
5
+ require "redis/commands/connection"
6
+ require "redis/commands/geo"
7
+ require "redis/commands/hashes"
8
+ require "redis/commands/hyper_log_log"
9
+ require "redis/commands/keys"
10
+ require "redis/commands/lists"
11
+ require "redis/commands/pubsub"
12
+ require "redis/commands/scripting"
13
+ require "redis/commands/server"
14
+ require "redis/commands/sets"
15
+ require "redis/commands/sorted_sets"
16
+ require "redis/commands/streams"
17
+ require "redis/commands/strings"
18
+ require "redis/commands/transactions"
19
+
20
+ class Redis
21
+ module Commands
22
+ include Bitmaps
23
+ include Cluster
24
+ include Connection
25
+ include Geo
26
+ include Hashes
27
+ include HyperLogLog
28
+ include Keys
29
+ include Lists
30
+ include Pubsub
31
+ include Scripting
32
+ include Server
33
+ include Sets
34
+ include SortedSets
35
+ include Streams
36
+ include Strings
37
+ include Transactions
38
+
39
+ # Commands returning 1 for true and 0 for false may be executed in a pipeline
40
+ # where the method call will return nil. Propagate the nil instead of falsely
41
+ # returning false.
42
+ Boolify = lambda { |value|
43
+ value != 0 unless value.nil?
44
+ }
45
+
46
+ BoolifySet = lambda { |value|
47
+ case value
48
+ when "OK"
49
+ true
50
+ when nil
51
+ false
52
+ else
53
+ value
54
+ end
55
+ }
56
+
57
+ Hashify = lambda { |value|
58
+ if value.respond_to?(:each_slice)
59
+ value.each_slice(2).to_h
60
+ else
61
+ value
62
+ end
63
+ }
64
+
65
+ Pairify = lambda { |value|
66
+ if value.respond_to?(:each_slice)
67
+ value.each_slice(2).to_a
68
+ else
69
+ value
70
+ end
71
+ }
72
+
73
+ Floatify = lambda { |value|
74
+ case value
75
+ when "inf"
76
+ Float::INFINITY
77
+ when "-inf"
78
+ -Float::INFINITY
79
+ when String
80
+ Float(value)
81
+ else
82
+ value
83
+ end
84
+ }
85
+
86
+ FloatifyPairs = lambda { |value|
87
+ return value unless value.respond_to?(:each_slice)
88
+
89
+ value.each_slice(2).map do |member, score|
90
+ [member, Floatify.call(score)]
91
+ end
92
+ }
93
+
94
+ HashifyInfo = lambda { |reply|
95
+ lines = reply.split("\r\n").grep_v(/^(#|$)/)
96
+ lines.map! { |line| line.split(':', 2) }
97
+ lines.compact!
98
+ lines.to_h
99
+ }
100
+
101
+ HashifyStreams = lambda { |reply|
102
+ case reply
103
+ when nil
104
+ {}
105
+ else
106
+ reply.map { |key, entries| [key, HashifyStreamEntries.call(entries)] }.to_h
107
+ end
108
+ }
109
+
110
+ EMPTY_STREAM_RESPONSE = [nil].freeze
111
+ private_constant :EMPTY_STREAM_RESPONSE
112
+
113
+ HashifyStreamEntries = lambda { |reply|
114
+ reply.compact.map do |entry_id, values|
115
+ [entry_id, values&.each_slice(2)&.to_h]
116
+ end
117
+ }
118
+
119
+ HashifyStreamAutoclaim = lambda { |reply|
120
+ {
121
+ 'next' => reply[0],
122
+ 'entries' => reply[1].map { |entry| [entry[0], entry[1].each_slice(2).to_h] }
123
+ }
124
+ }
125
+
126
+ HashifyStreamAutoclaimJustId = lambda { |reply|
127
+ {
128
+ 'next' => reply[0],
129
+ 'entries' => reply[1]
130
+ }
131
+ }
132
+
133
+ HashifyStreamPendings = lambda { |reply|
134
+ {
135
+ 'size' => reply[0],
136
+ 'min_entry_id' => reply[1],
137
+ 'max_entry_id' => reply[2],
138
+ 'consumers' => reply[3].nil? ? {} : reply[3].to_h
139
+ }
140
+ }
141
+
142
+ HashifyStreamPendingDetails = lambda { |reply|
143
+ reply.map do |arr|
144
+ {
145
+ 'entry_id' => arr[0],
146
+ 'consumer' => arr[1],
147
+ 'elapsed' => arr[2],
148
+ 'count' => arr[3]
149
+ }
150
+ end
151
+ }
152
+
153
+ HashifyClusterNodeInfo = lambda { |str|
154
+ arr = str.split(' ')
155
+ {
156
+ 'node_id' => arr[0],
157
+ 'ip_port' => arr[1],
158
+ 'flags' => arr[2].split(','),
159
+ 'master_node_id' => arr[3],
160
+ 'ping_sent' => arr[4],
161
+ 'pong_recv' => arr[5],
162
+ 'config_epoch' => arr[6],
163
+ 'link_state' => arr[7],
164
+ 'slots' => arr[8].nil? ? nil : Range.new(*arr[8].split('-'))
165
+ }
166
+ }
167
+
168
+ HashifyClusterSlots = lambda { |reply|
169
+ reply.map do |arr|
170
+ first_slot, last_slot = arr[0..1]
171
+ master = { 'ip' => arr[2][0], 'port' => arr[2][1], 'node_id' => arr[2][2] }
172
+ replicas = arr[3..-1].map { |r| { 'ip' => r[0], 'port' => r[1], 'node_id' => r[2] } }
173
+ {
174
+ 'start_slot' => first_slot,
175
+ 'end_slot' => last_slot,
176
+ 'master' => master,
177
+ 'replicas' => replicas
178
+ }
179
+ end
180
+ }
181
+
182
+ HashifyClusterNodes = lambda { |reply|
183
+ reply.split(/[\r\n]+/).map { |str| HashifyClusterNodeInfo.call(str) }
184
+ }
185
+
186
+ HashifyClusterSlaves = lambda { |reply|
187
+ reply.map { |str| HashifyClusterNodeInfo.call(str) }
188
+ }
189
+
190
+ Noop = ->(reply) { reply }
191
+
192
+ # Sends a command to Redis and returns its reply.
193
+ #
194
+ # Replies are converted to Ruby objects according to the RESP protocol, so
195
+ # you can expect a Ruby array, integer or nil when Redis sends one. Higher
196
+ # level transformations, such as converting an array of pairs into a Ruby
197
+ # hash, are up to consumers.
198
+ #
199
+ # Redis error replies are raised as Ruby exceptions.
200
+ def call(*command)
201
+ send_command(command)
202
+ end
203
+
204
+ # Interact with the sentinel command (masters, master, slaves, failover)
205
+ #
206
+ # @param [String] subcommand e.g. `masters`, `master`, `slaves`
207
+ # @param [Array<String>] args depends on subcommand
208
+ # @return [Array<String>, Hash<String, String>, String] depends on subcommand
209
+ def sentinel(subcommand, *args)
210
+ subcommand = subcommand.to_s.downcase
211
+ send_command([:sentinel, subcommand] + args) do |reply|
212
+ case subcommand
213
+ when "get-master-addr-by-name"
214
+ reply
215
+ else
216
+ if reply.is_a?(Array)
217
+ if reply[0].is_a?(Array)
218
+ reply.map(&Hashify)
219
+ else
220
+ Hashify.call(reply)
221
+ end
222
+ else
223
+ reply
224
+ end
225
+ end
226
+ end
227
+ end
228
+
229
+ private
230
+
231
+ def method_missing(*command) # rubocop:disable Style/MissingRespondToMissing
232
+ send_command(command)
233
+ end
234
+ end
235
+ end