redis 3.3.3 → 5.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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