finsync_redis 3.3.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 (121) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.travis/Gemfile +11 -0
  4. data/.travis.yml +89 -0
  5. data/.yardopts +3 -0
  6. data/CHANGELOG.md +373 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE +20 -0
  9. data/README.md +410 -0
  10. data/Rakefile +87 -0
  11. data/benchmarking/logging.rb +71 -0
  12. data/benchmarking/pipeline.rb +51 -0
  13. data/benchmarking/speed.rb +21 -0
  14. data/benchmarking/suite.rb +24 -0
  15. data/benchmarking/worker.rb +71 -0
  16. data/examples/basic.rb +15 -0
  17. data/examples/consistency.rb +114 -0
  18. data/examples/dist_redis.rb +43 -0
  19. data/examples/incr-decr.rb +17 -0
  20. data/examples/list.rb +26 -0
  21. data/examples/pubsub.rb +37 -0
  22. data/examples/sentinel/sentinel.conf +9 -0
  23. data/examples/sentinel/start +49 -0
  24. data/examples/sentinel.rb +41 -0
  25. data/examples/sets.rb +36 -0
  26. data/examples/unicorn/config.ru +3 -0
  27. data/examples/unicorn/unicorn.rb +20 -0
  28. data/lib/redis/client.rb +590 -0
  29. data/lib/redis/connection/command_helper.rb +44 -0
  30. data/lib/redis/connection/hiredis.rb +66 -0
  31. data/lib/redis/connection/registry.rb +12 -0
  32. data/lib/redis/connection/ruby.rb +429 -0
  33. data/lib/redis/connection/synchrony.rb +133 -0
  34. data/lib/redis/connection.rb +9 -0
  35. data/lib/redis/distributed.rb +873 -0
  36. data/lib/redis/errors.rb +40 -0
  37. data/lib/redis/hash_ring.rb +132 -0
  38. data/lib/redis/pipeline.rb +141 -0
  39. data/lib/redis/subscribe.rb +91 -0
  40. data/lib/redis/version.rb +3 -0
  41. data/lib/redis.rb +2788 -0
  42. data/redis.gemspec +44 -0
  43. data/test/bitpos_test.rb +69 -0
  44. data/test/blocking_commands_test.rb +42 -0
  45. data/test/client_test.rb +59 -0
  46. data/test/command_map_test.rb +30 -0
  47. data/test/commands_on_hashes_test.rb +21 -0
  48. data/test/commands_on_hyper_log_log_test.rb +21 -0
  49. data/test/commands_on_lists_test.rb +20 -0
  50. data/test/commands_on_sets_test.rb +77 -0
  51. data/test/commands_on_sorted_sets_test.rb +137 -0
  52. data/test/commands_on_strings_test.rb +101 -0
  53. data/test/commands_on_value_types_test.rb +133 -0
  54. data/test/connection_handling_test.rb +277 -0
  55. data/test/connection_test.rb +57 -0
  56. data/test/db/.gitkeep +0 -0
  57. data/test/distributed_blocking_commands_test.rb +46 -0
  58. data/test/distributed_commands_on_hashes_test.rb +10 -0
  59. data/test/distributed_commands_on_hyper_log_log_test.rb +33 -0
  60. data/test/distributed_commands_on_lists_test.rb +22 -0
  61. data/test/distributed_commands_on_sets_test.rb +83 -0
  62. data/test/distributed_commands_on_sorted_sets_test.rb +18 -0
  63. data/test/distributed_commands_on_strings_test.rb +59 -0
  64. data/test/distributed_commands_on_value_types_test.rb +95 -0
  65. data/test/distributed_commands_requiring_clustering_test.rb +164 -0
  66. data/test/distributed_connection_handling_test.rb +23 -0
  67. data/test/distributed_internals_test.rb +79 -0
  68. data/test/distributed_key_tags_test.rb +52 -0
  69. data/test/distributed_persistence_control_commands_test.rb +26 -0
  70. data/test/distributed_publish_subscribe_test.rb +92 -0
  71. data/test/distributed_remote_server_control_commands_test.rb +66 -0
  72. data/test/distributed_scripting_test.rb +102 -0
  73. data/test/distributed_sorting_test.rb +20 -0
  74. data/test/distributed_test.rb +58 -0
  75. data/test/distributed_transactions_test.rb +32 -0
  76. data/test/encoding_test.rb +18 -0
  77. data/test/error_replies_test.rb +59 -0
  78. data/test/fork_safety_test.rb +65 -0
  79. data/test/helper.rb +232 -0
  80. data/test/helper_test.rb +24 -0
  81. data/test/internals_test.rb +417 -0
  82. data/test/lint/blocking_commands.rb +150 -0
  83. data/test/lint/hashes.rb +162 -0
  84. data/test/lint/hyper_log_log.rb +60 -0
  85. data/test/lint/lists.rb +143 -0
  86. data/test/lint/sets.rb +140 -0
  87. data/test/lint/sorted_sets.rb +316 -0
  88. data/test/lint/strings.rb +260 -0
  89. data/test/lint/value_types.rb +122 -0
  90. data/test/persistence_control_commands_test.rb +26 -0
  91. data/test/pipelining_commands_test.rb +242 -0
  92. data/test/publish_subscribe_test.rb +282 -0
  93. data/test/remote_server_control_commands_test.rb +118 -0
  94. data/test/scanning_test.rb +413 -0
  95. data/test/scripting_test.rb +78 -0
  96. data/test/sentinel_command_test.rb +80 -0
  97. data/test/sentinel_test.rb +255 -0
  98. data/test/sorting_test.rb +59 -0
  99. data/test/ssl_test.rb +73 -0
  100. data/test/support/connection/hiredis.rb +1 -0
  101. data/test/support/connection/ruby.rb +1 -0
  102. data/test/support/connection/synchrony.rb +17 -0
  103. data/test/support/redis_mock.rb +130 -0
  104. data/test/support/ssl/gen_certs.sh +31 -0
  105. data/test/support/ssl/trusted-ca.crt +25 -0
  106. data/test/support/ssl/trusted-ca.key +27 -0
  107. data/test/support/ssl/trusted-cert.crt +81 -0
  108. data/test/support/ssl/trusted-cert.key +28 -0
  109. data/test/support/ssl/untrusted-ca.crt +26 -0
  110. data/test/support/ssl/untrusted-ca.key +27 -0
  111. data/test/support/ssl/untrusted-cert.crt +82 -0
  112. data/test/support/ssl/untrusted-cert.key +28 -0
  113. data/test/support/wire/synchrony.rb +24 -0
  114. data/test/support/wire/thread.rb +5 -0
  115. data/test/synchrony_driver.rb +88 -0
  116. data/test/test.conf.erb +9 -0
  117. data/test/thread_safety_test.rb +62 -0
  118. data/test/transactions_test.rb +264 -0
  119. data/test/unknown_commands_test.rb +14 -0
  120. data/test/url_param_test.rb +138 -0
  121. metadata +202 -0
data/README.md ADDED
@@ -0,0 +1,410 @@
1
+ # redis-rb [![Build Status][travis-image]][travis-link] [![Inline docs][inchpages-image]][inchpages-link]
2
+
3
+ [travis-image]: https://secure.travis-ci.org/redis/redis-rb.png?branch=master
4
+ [travis-link]: http://travis-ci.org/redis/redis-rb
5
+ [travis-home]: http://travis-ci.org/
6
+ [inchpages-image]: http://inch-ci.org/github/redis/redis-rb.png
7
+ [inchpages-link]: http://inch-ci.org/github/redis/redis-rb
8
+
9
+ A Ruby client library for [Redis][redis-home].
10
+
11
+ [redis-home]: http://redis.io
12
+
13
+ A Ruby client that tries to match Redis' API one-to-one, while still
14
+ providing an idiomatic interface. It features thread-safety, client-side
15
+ sharding, pipelining, and an obsession for performance.
16
+
17
+ ## Upgrading from 2.x to 3.0
18
+
19
+ Please refer to the [CHANGELOG][changelog-3.0.0] for a summary of the
20
+ most important changes, as well as a full list of changes.
21
+
22
+ [changelog-3.0.0]: https://github.com/redis/redis-rb/blob/master/CHANGELOG.md#300
23
+
24
+ ## Getting started
25
+
26
+ To install **redis-rb**, run the following command:
27
+
28
+ ```
29
+ gem install redis
30
+ ```
31
+
32
+ Or if you are using **bundler**, add
33
+
34
+ ```
35
+ gem 'redis', '~>3.2'
36
+ ```
37
+
38
+ to your `Gemfile`, and run `bundle install`
39
+
40
+ As of version 2.0 this client only targets Redis version 2.0 and higher.
41
+ You can use an older version of this client if you need to interface
42
+ with a Redis instance older than 2.0, but this is no longer supported.
43
+
44
+ You can connect to Redis by instantiating the `Redis` class:
45
+
46
+ ```ruby
47
+ require "redis"
48
+
49
+ redis = Redis.new
50
+ ```
51
+
52
+ This assumes Redis was started with a default configuration, and is
53
+ listening on `localhost`, port 6379. If you need to connect to a remote
54
+ server or a different port, try:
55
+
56
+ ```ruby
57
+ redis = Redis.new(:host => "10.0.1.1", :port => 6380, :db => 15)
58
+ ```
59
+
60
+ You can also specify connection options as a [`redis://` URL][redis-url]:
61
+
62
+ ```ruby
63
+ redis = Redis.new(:url => "redis://:p4ssw0rd@10.0.1.1:6380/15")
64
+ ```
65
+
66
+ [redis-url]: http://www.iana.org/assignments/uri-schemes/prov/redis
67
+
68
+ By default, the client will try to read the `REDIS_URL` environment variable
69
+ and use that as URL to connect to. The above statement is therefore equivalent
70
+ to setting this environment variable and calling `Redis.new` without arguments.
71
+
72
+ To connect to Redis listening on a Unix socket, try:
73
+
74
+ ```ruby
75
+ redis = Redis.new(:path => "/tmp/redis.sock")
76
+ ```
77
+
78
+ To connect to a password protected Redis instance, use:
79
+
80
+ ```ruby
81
+ redis = Redis.new(:password => "mysecret")
82
+ ```
83
+
84
+ The Redis class exports methods that are named identical to the commands
85
+ they execute. The arguments these methods accept are often identical to
86
+ the arguments specified on the [Redis website][redis-commands]. For
87
+ instance, the `SET` and `GET` commands can be called like this:
88
+
89
+ [redis-commands]: http://redis.io/commands
90
+
91
+ ```ruby
92
+ redis.set("mykey", "hello world")
93
+ # => "OK"
94
+
95
+ redis.get("mykey")
96
+ # => "hello world"
97
+ ```
98
+
99
+ All commands, their arguments and return values are documented, and
100
+ available on [rdoc.info][rdoc].
101
+
102
+ [rdoc]: http://rdoc.info/github/redis/redis-rb/
103
+
104
+ ## Sentinel support
105
+
106
+ The client is able to perform automatic failovers by using [Redis
107
+ Sentinel](http://redis.io/topics/sentinel). Make sure to run Redis 2.8+
108
+ if you want to use this feature.
109
+
110
+ To connect using Sentinel, use:
111
+
112
+ ```ruby
113
+ SENTINELS = [{:host => "127.0.0.1", :port => 26380},
114
+ {:host => "127.0.0.1", :port => 26381}]
115
+
116
+ redis = Redis.new(:url => "redis://mymaster", :sentinels => SENTINELS, :role => :master)
117
+ ```
118
+
119
+ * The master name identifies a group of Redis instances composed of a master
120
+ and one or more slaves (`mymaster` in the example).
121
+
122
+ * It is possible to optionally provide a role. The allowed roles are `master`
123
+ and `slave`. When the role is `slave`, the client will try to connect to a
124
+ random slave of the specified master. If a role is not specified, the client
125
+ will connect to the master.
126
+
127
+ * When using the Sentinel support you need to specify a list of sentinels to
128
+ connect to. The list does not need to enumerate all your Sentinel instances,
129
+ but a few so that if one is down the client will try the next one. The client
130
+ is able to remember the last Sentinel that was able to reply correctly and will
131
+ use it for the next requests.
132
+
133
+ ## Storing objects
134
+
135
+ Redis only stores strings as values. If you want to store an object, you
136
+ can use a serialization mechanism such as JSON:
137
+
138
+ ```ruby
139
+ require "json"
140
+
141
+ redis.set "foo", [1, 2, 3].to_json
142
+ # => OK
143
+
144
+ JSON.parse(redis.get("foo"))
145
+ # => [1, 2, 3]
146
+ ```
147
+
148
+ ## Pipelining
149
+
150
+ When multiple commands are executed sequentially, but are not dependent,
151
+ the calls can be *pipelined*. This means that the client doesn't wait
152
+ for reply of the first command before sending the next command. The
153
+ advantage is that multiple commands are sent at once, resulting in
154
+ faster overall execution.
155
+
156
+ The client can be instructed to pipeline commands by using the
157
+ `#pipelined` method. After the block is executed, the client sends all
158
+ commands to Redis and gathers their replies. These replies are returned
159
+ by the `#pipelined` method.
160
+
161
+ ```ruby
162
+ redis.pipelined do
163
+ redis.set "foo", "bar"
164
+ redis.incr "baz"
165
+ end
166
+ # => ["OK", 1]
167
+ ```
168
+
169
+ ### Executing commands atomically
170
+
171
+ You can use `MULTI/EXEC` to run a number of commands in an atomic
172
+ fashion. This is similar to executing a pipeline, but the commands are
173
+ preceded by a call to `MULTI`, and followed by a call to `EXEC`. Like
174
+ the regular pipeline, the replies to the commands are returned by the
175
+ `#multi` method.
176
+
177
+ ```ruby
178
+ redis.multi do
179
+ redis.set "foo", "bar"
180
+ redis.incr "baz"
181
+ end
182
+ # => ["OK", 1]
183
+ ```
184
+
185
+ ### Futures
186
+
187
+ Replies to commands in a pipeline can be accessed via the *futures* they
188
+ emit (since redis-rb 3.0). All calls inside a pipeline block return a
189
+ `Future` object, which responds to the `#value` method. When the
190
+ pipeline has successfully executed, all futures are assigned their
191
+ respective replies and can be used.
192
+
193
+ ```ruby
194
+ redis.pipelined do
195
+ @set = redis.set "foo", "bar"
196
+ @incr = redis.incr "baz"
197
+ end
198
+
199
+ @set.value
200
+ # => "OK"
201
+
202
+ @incr.value
203
+ # => 1
204
+ ```
205
+
206
+ ## Error Handling
207
+
208
+ In general, if something goes wrong you'll get an exception. For example, if
209
+ it can't connect to the server a `Redis::CannotConnectError` error will be raised.
210
+
211
+ ```ruby
212
+ begin
213
+ redis.ping
214
+ rescue Exception => e
215
+ e.inspect
216
+ # => #<Redis::CannotConnectError: Timed out connecting to Redis on 10.0.1.1:6380>
217
+
218
+ e.message
219
+ # => Timed out connecting to Redis on 10.0.1.1:6380
220
+ end
221
+ ```
222
+
223
+ See lib/redis/errors.rb for information about what exceptions are possible.
224
+
225
+ ## Timeouts
226
+
227
+ The client allows you to configure connect, read, and write timeouts.
228
+ Passing a single `timeout` option will set all three values:
229
+
230
+ ```ruby
231
+ Redis.new(:timeout => 1)
232
+ ```
233
+
234
+ But you can use specific values for each of them:
235
+
236
+ ```ruby
237
+ Redis.new(
238
+ :connect_timeout => 0.2,
239
+ :read_timeout => 1.0,
240
+ :write_timeout => 0.5
241
+ )
242
+ ```
243
+
244
+ All timeout values are specified in seconds.
245
+
246
+ When using pub/sub, you can subscribe to a channel using a timeout as well:
247
+
248
+ ```ruby
249
+ redis.subscribe_with_timeout(5, "news") do |on|
250
+ on.message do |channel, message|
251
+ # ...
252
+ end
253
+ end
254
+ ```
255
+
256
+ If no message is received after 5 seconds, the client will unsubscribe.
257
+
258
+
259
+ ## SSL/TLS Support
260
+
261
+ This library supports natively terminating client side SSL/TLS connections
262
+ when talking to Redis via a server-side proxy such as [stunnel], [hitch],
263
+ or [ghostunnel].
264
+
265
+ To enable SSL support, pass the `:ssl => :true` option when configuring the
266
+ Redis client, or pass in `:url => "rediss://..."` (like HTTPS for Redis).
267
+ You will also need to pass in an `:ssl_params => { ... }` hash used to
268
+ configure the `OpenSSL::SSL::SSLContext` object used for the connection:
269
+
270
+ ```ruby
271
+ redis = Redis.new(
272
+ :url => "rediss://:p4ssw0rd@10.0.1.1:6381/15",
273
+ :ssl_params => {
274
+ :ca_file => "/path/to/ca.crt"
275
+ }
276
+ )
277
+ ```
278
+
279
+ The options given to `:ssl_params` are passed directly to the
280
+ `OpenSSL::SSL::SSLContext#set_params` method and can be any valid attribute
281
+ of the SSL context. Please see the [OpenSSL::SSL::SSLContext documentation]
282
+ for all of the available attributes.
283
+
284
+ Here is an example of passing in params that can be used for SSL client
285
+ certificate authentication (a.k.a. mutual TLS):
286
+
287
+ ```ruby
288
+ redis = Redis.new(
289
+ :url => "rediss://:p4ssw0rd@10.0.1.1:6381/15",
290
+ :ssl_params => {
291
+ :ca_file => "/path/to/ca.crt",
292
+ :cert => OpenSSL::X509::Certificate.new(File.read("client.crt")),
293
+ :key => OpenSSL::PKey::RSA.new(File.read("client.key"))
294
+ }
295
+ )
296
+ ```
297
+
298
+ [stunnel]: https://www.stunnel.org/
299
+ [hitch]: https://hitch-tls.org/
300
+ [ghostunnel]: https://github.com/square/ghostunnel
301
+ [OpenSSL::SSL::SSLContext documentation]: http://ruby-doc.org/stdlib-2.3.0/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html
302
+
303
+ *NOTE:* SSL is only supported by the default "Ruby" driver
304
+
305
+
306
+ ## Expert-Mode Options
307
+
308
+ - `inherit_socket: true`: disable safety check that prevents a forked child
309
+ from sharing a socket with its parent; this is potentially useful in order to mitigate connection churn when:
310
+ - many short-lived forked children of one process need to talk
311
+ to redis, AND
312
+ - your own code prevents the parent process from using the redis
313
+ connection while a child is alive
314
+
315
+ Improper use of `inherit_socket` will result in corrupted and/or incorrect
316
+ responses.
317
+
318
+ ## Alternate drivers
319
+
320
+ By default, redis-rb uses Ruby's socket library to talk with Redis.
321
+ To use an alternative connection driver it should be specified as option
322
+ when instantiating the client object. These instructions are only valid
323
+ for **redis-rb 3.0**. For instructions on how to use alternate drivers from
324
+ **redis-rb 2.2**, please refer to an [older README][readme-2.2.2].
325
+
326
+ [readme-2.2.2]: https://github.com/redis/redis-rb/blob/v2.2.2/README.md
327
+
328
+ ### hiredis
329
+
330
+ The hiredis driver uses the connection facility of hiredis-rb. In turn,
331
+ hiredis-rb is a binding to the official hiredis client library. It
332
+ optimizes for speed, at the cost of portability. Because it is a C
333
+ extension, JRuby is not supported (by default).
334
+
335
+ It is best to use hiredis when you have large replies (for example:
336
+ `LRANGE`, `SMEMBERS`, `ZRANGE`, etc.) and/or use big pipelines.
337
+
338
+ In your Gemfile, include hiredis:
339
+
340
+ ```ruby
341
+ gem "redis", "~> 3.0.1"
342
+ gem "hiredis", "~> 0.4.5"
343
+ ```
344
+
345
+ When instantiating the client object, specify hiredis:
346
+
347
+ ```ruby
348
+ redis = Redis.new(:driver => :hiredis)
349
+ ```
350
+
351
+ ### synchrony
352
+
353
+ The synchrony driver adds support for [em-synchrony][em-synchrony].
354
+ This makes redis-rb work with EventMachine's asynchronous I/O, while not
355
+ changing the exposed API. The hiredis gem needs to be available as
356
+ well, because the synchrony driver uses hiredis for parsing the Redis
357
+ protocol.
358
+
359
+ [em-synchrony]: https://github.com/igrigorik/em-synchrony
360
+
361
+ In your Gemfile, include em-synchrony and hiredis:
362
+
363
+ ```ruby
364
+ gem "redis", "~> 3.0.1"
365
+ gem "hiredis", "~> 0.4.5"
366
+ gem "em-synchrony"
367
+ ```
368
+
369
+ When instantiating the client object, specify synchrony:
370
+
371
+ ```ruby
372
+ redis = Redis.new(:driver => :synchrony)
373
+ ```
374
+
375
+ ## Testing
376
+
377
+ This library is tested using [Travis][travis-home], where it is tested
378
+ against the following interpreters and drivers:
379
+
380
+ * MRI 1.8.7 (drivers: ruby, hiredis)
381
+ * MRI 1.9.3 (drivers: ruby, hiredis, synchrony)
382
+ * MRI 2.0 (drivers: ruby, hiredis, synchrony)
383
+ * MRI 2.1 (drivers: ruby, hiredis, synchrony)
384
+ * MRI 2.2 (drivers: ruby, hiredis, synchrony)
385
+ * MRI 2.3 (drivers: ruby, hiredis, synchrony)
386
+ * JRuby 1.7 (1.8 mode) (drivers: ruby)
387
+ * JRuby 1.7 (1.9 mode) (drivers: ruby)
388
+
389
+ ## Contributors
390
+
391
+ (ordered chronologically with more than 5 commits, see `git shortlog -sn` for
392
+ all contributors)
393
+
394
+ * Ezra Zygmuntowicz
395
+ * Taylor Weibley
396
+ * Matthew Clark
397
+ * Brian McKinney
398
+ * Luca Guidi
399
+ * Salvatore Sanfilippo
400
+ * Chris Wanstrath
401
+ * Damian Janowski
402
+ * Michel Martens
403
+ * Nick Quaranto
404
+ * Pieter Noordhuis
405
+ * Ilya Grigorik
406
+
407
+ ## Contributing
408
+
409
+ [Fork the project](https://github.com/redis/redis-rb) and send pull
410
+ requests. You can also ask for help at `#redis-rb` on Freenode.
data/Rakefile ADDED
@@ -0,0 +1,87 @@
1
+ require "rake/testtask"
2
+
3
+ ENV["REDIS_BRANCH"] ||= "unstable"
4
+
5
+ REDIS_DIR = File.expand_path(File.join("..", "test"), __FILE__)
6
+ REDIS_CNF = File.join(REDIS_DIR, "test.conf")
7
+ REDIS_CNF_TEMPLATE = File.join(REDIS_DIR, "test.conf.erb")
8
+ REDIS_PID = File.join(REDIS_DIR, "db", "redis.pid")
9
+ REDIS_LOG = File.join(REDIS_DIR, "db", "redis.log")
10
+ REDIS_SOCKET = File.join(REDIS_DIR, "db", "redis.sock")
11
+ BINARY = "tmp/redis-#{ENV["REDIS_BRANCH"]}/src/redis-server"
12
+
13
+ task :default => :run
14
+
15
+ desc "Run tests and manage server start/stop"
16
+ task :run => [:start, :test, :stop]
17
+
18
+ desc "Start the Redis server"
19
+ task :start => [BINARY, REDIS_CNF] do
20
+ sh "#{BINARY} --version"
21
+
22
+ redis_running = \
23
+ begin
24
+ File.exists?(REDIS_PID) && Process.kill(0, File.read(REDIS_PID).to_i)
25
+ rescue Errno::ESRCH
26
+ FileUtils.rm REDIS_PID
27
+ false
28
+ end
29
+
30
+ unless redis_running
31
+ unless system("#{BINARY} #{REDIS_CNF}")
32
+ abort "could not start redis-server"
33
+ end
34
+ end
35
+
36
+ at_exit do
37
+ Rake::Task["stop"].invoke
38
+ end
39
+ end
40
+
41
+ desc "Stop the Redis server"
42
+ task :stop do
43
+ if File.exists?(REDIS_PID)
44
+ Process.kill "INT", File.read(REDIS_PID).to_i
45
+ FileUtils.rm REDIS_PID
46
+ end
47
+ end
48
+
49
+ desc "Clean up testing artifacts"
50
+ task :clean do
51
+ FileUtils.rm_f(BINARY)
52
+ FileUtils.rm_f(REDIS_CNF)
53
+ end
54
+
55
+ file BINARY do
56
+ branch = ENV.fetch("REDIS_BRANCH")
57
+
58
+ sh <<-SH
59
+ mkdir -p tmp;
60
+ cd tmp;
61
+ rm -rf redis-#{branch};
62
+ wget https://github.com/antirez/redis/archive/#{branch}.tar.gz -O #{branch}.tar.gz;
63
+ tar xf #{branch}.tar.gz;
64
+ cd redis-#{branch};
65
+ make
66
+ SH
67
+ end
68
+
69
+ file REDIS_CNF => [REDIS_CNF_TEMPLATE, __FILE__] do |t|
70
+ require 'erb'
71
+
72
+ erb = t.prerequisites[0]
73
+ template = File.read(erb)
74
+
75
+ File.open(REDIS_CNF, 'w') do |file|
76
+ file.puts "\# This file was auto-generated at #{Time.now}",
77
+ "\# from (#{erb})",
78
+ "\#"
79
+ conf = ERB.new(template).result
80
+ file << conf
81
+ end
82
+ end
83
+
84
+ Rake::TestTask.new do |t|
85
+ t.options = "-v" if $VERBOSE
86
+ t.test_files = FileList["test/*_test.rb"]
87
+ end
@@ -0,0 +1,71 @@
1
+ # Run with
2
+ #
3
+ # $ ruby -Ilib benchmarking/logging.rb
4
+ #
5
+
6
+ begin
7
+ require "bench"
8
+ rescue LoadError
9
+ $stderr.puts "`gem install bench` and try again."
10
+ exit 1
11
+ end
12
+
13
+ require "redis"
14
+ require "logger"
15
+
16
+ def log(level, namespace = nil)
17
+ logger = (namespace || Kernel).const_get(:Logger).new("/dev/null")
18
+ logger.level = (namespace || Logger).const_get(level)
19
+ logger
20
+ end
21
+
22
+ def stress(redis)
23
+ redis.flushdb
24
+
25
+ n = (ARGV.shift || 2000).to_i
26
+
27
+ n.times do |i|
28
+ key = "foo:#{i}"
29
+ redis.set key, i
30
+ redis.get key
31
+ end
32
+ end
33
+
34
+ default = Redis.new
35
+
36
+ logging_redises = [
37
+ Redis.new(:logger => log(:DEBUG)),
38
+ Redis.new(:logger => log(:INFO)),
39
+ ]
40
+
41
+ begin
42
+ require "log4r"
43
+
44
+ logging_redises += [
45
+ Redis.new(:logger => log(:DEBUG, Log4r)),
46
+ Redis.new(:logger => log(:INFO, Log4r)),
47
+ ]
48
+ rescue LoadError
49
+ $stderr.puts "Log4r not installed. `gem install log4r` if you want to compare it against Ruby's Logger (spoiler: it's much faster)."
50
+ end
51
+
52
+ benchmark "Default options (no logger)" do
53
+ stress(default)
54
+ end
55
+
56
+ logging_redises.each do |redis|
57
+ logger = redis.client.logger
58
+
59
+ case logger
60
+ when Logger
61
+ level = Logger::SEV_LABEL[logger.level]
62
+ when Log4r::Logger
63
+ level = logger.levels[logger.level]
64
+ end
65
+
66
+ benchmark "#{logger.class} on #{level}" do
67
+ stress(redis)
68
+ end
69
+ end
70
+
71
+ run 10
@@ -0,0 +1,51 @@
1
+ require "benchmark"
2
+
3
+ $:.push File.join(File.dirname(__FILE__), 'lib')
4
+
5
+ require 'redis'
6
+
7
+ ITERATIONS = 10000
8
+
9
+ @r = Redis.new
10
+
11
+ Benchmark.bmbm do |benchmark|
12
+ benchmark.report("set") do
13
+ @r.flushdb
14
+
15
+ ITERATIONS.times do |i|
16
+ @r.set("foo#{i}", "Hello world!")
17
+ @r.get("foo#{i}")
18
+ end
19
+ end
20
+
21
+ benchmark.report("set (pipelined)") do
22
+ @r.flushdb
23
+
24
+ @r.pipelined do
25
+ ITERATIONS.times do |i|
26
+ @r.set("foo#{i}", "Hello world!")
27
+ @r.get("foo#{i}")
28
+ end
29
+ end
30
+ end
31
+
32
+ benchmark.report("lpush+ltrim") do
33
+ @r.flushdb
34
+
35
+ ITERATIONS.times do |i|
36
+ @r.lpush "lpush#{i}", i
37
+ @r.ltrim "ltrim#{i}", 0, 30
38
+ end
39
+ end
40
+
41
+ benchmark.report("lpush+ltrim (pipelined)") do
42
+ @r.flushdb
43
+
44
+ @r.pipelined do
45
+ ITERATIONS.times do |i|
46
+ @r.lpush "lpush#{i}", i
47
+ @r.ltrim "ltrim#{i}", 0, 30
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,21 @@
1
+ # Run with
2
+ #
3
+ # $ ruby -Ilib benchmarking/speed.rb
4
+ #
5
+
6
+ require "benchmark"
7
+ require "redis"
8
+
9
+ r = Redis.new
10
+ n = (ARGV.shift || 20000).to_i
11
+
12
+ elapsed = Benchmark.realtime do
13
+ # n sets, n gets
14
+ n.times do |i|
15
+ key = "foo#{i}"
16
+ r[key] = key * 10
17
+ r[key]
18
+ end
19
+ end
20
+
21
+ puts '%.2f Kops' % (2 * n / 1000 / elapsed)
@@ -0,0 +1,24 @@
1
+ require 'fileutils'
2
+
3
+ def run_in_background(command)
4
+ fork { system command }
5
+ end
6
+
7
+ def with_all_segments(&block)
8
+ 0.upto(9) do |segment_number|
9
+ block_size = 100000
10
+ start_index = segment_number * block_size
11
+ end_index = start_index + block_size - 1
12
+ block.call(start_index, end_index)
13
+ end
14
+ end
15
+
16
+ #with_all_segments do |start_index, end_index|
17
+ # puts "Initializing keys from #{start_index} to #{end_index}"
18
+ # system "ruby worker.rb initialize #{start_index} #{end_index} 0"
19
+ #end
20
+
21
+ with_all_segments do |start_index, end_index|
22
+ run_in_background "ruby worker.rb write #{start_index} #{end_index} 10"
23
+ run_in_background "ruby worker.rb read #{start_index} #{end_index} 1"
24
+ end