gorsuch-redis 3.0.0.rc1

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 (87) hide show
  1. data/.gitignore +10 -0
  2. data/.yardopts +3 -0
  3. data/CHANGELOG.md +113 -0
  4. data/LICENSE +20 -0
  5. data/README.md +214 -0
  6. data/Rakefile +260 -0
  7. data/TODO.md +4 -0
  8. data/benchmarking/logging.rb +62 -0
  9. data/benchmarking/pipeline.rb +51 -0
  10. data/benchmarking/speed.rb +21 -0
  11. data/benchmarking/suite.rb +24 -0
  12. data/benchmarking/thread_safety.rb +38 -0
  13. data/benchmarking/worker.rb +71 -0
  14. data/examples/basic.rb +15 -0
  15. data/examples/dist_redis.rb +43 -0
  16. data/examples/incr-decr.rb +17 -0
  17. data/examples/list.rb +26 -0
  18. data/examples/pubsub.rb +31 -0
  19. data/examples/sets.rb +36 -0
  20. data/examples/unicorn/config.ru +3 -0
  21. data/examples/unicorn/unicorn.rb +20 -0
  22. data/lib/redis/client.rb +303 -0
  23. data/lib/redis/connection/command_helper.rb +44 -0
  24. data/lib/redis/connection/hiredis.rb +52 -0
  25. data/lib/redis/connection/registry.rb +12 -0
  26. data/lib/redis/connection/ruby.rb +136 -0
  27. data/lib/redis/connection/synchrony.rb +131 -0
  28. data/lib/redis/connection.rb +9 -0
  29. data/lib/redis/distributed.rb +696 -0
  30. data/lib/redis/errors.rb +38 -0
  31. data/lib/redis/hash_ring.rb +131 -0
  32. data/lib/redis/pipeline.rb +106 -0
  33. data/lib/redis/subscribe.rb +79 -0
  34. data/lib/redis/version.rb +3 -0
  35. data/lib/redis.rb +1724 -0
  36. data/redis.gemspec +43 -0
  37. data/test/command_map_test.rb +29 -0
  38. data/test/commands_on_hashes_test.rb +20 -0
  39. data/test/commands_on_lists_test.rb +60 -0
  40. data/test/commands_on_sets_test.rb +76 -0
  41. data/test/commands_on_sorted_sets_test.rb +108 -0
  42. data/test/commands_on_strings_test.rb +80 -0
  43. data/test/commands_on_value_types_test.rb +87 -0
  44. data/test/connection_handling_test.rb +204 -0
  45. data/test/db/.gitignore +1 -0
  46. data/test/distributed_blocking_commands_test.rb +53 -0
  47. data/test/distributed_commands_on_hashes_test.rb +11 -0
  48. data/test/distributed_commands_on_lists_test.rb +23 -0
  49. data/test/distributed_commands_on_sets_test.rb +84 -0
  50. data/test/distributed_commands_on_sorted_sets_test.rb +19 -0
  51. data/test/distributed_commands_on_strings_test.rb +49 -0
  52. data/test/distributed_commands_on_value_types_test.rb +72 -0
  53. data/test/distributed_commands_requiring_clustering_test.rb +148 -0
  54. data/test/distributed_connection_handling_test.rb +24 -0
  55. data/test/distributed_internals_test.rb +27 -0
  56. data/test/distributed_key_tags_test.rb +52 -0
  57. data/test/distributed_persistence_control_commands_test.rb +23 -0
  58. data/test/distributed_publish_subscribe_test.rb +100 -0
  59. data/test/distributed_remote_server_control_commands_test.rb +42 -0
  60. data/test/distributed_sorting_test.rb +21 -0
  61. data/test/distributed_test.rb +59 -0
  62. data/test/distributed_transactions_test.rb +33 -0
  63. data/test/encoding_test.rb +15 -0
  64. data/test/error_replies_test.rb +53 -0
  65. data/test/helper.rb +155 -0
  66. data/test/helper_test.rb +8 -0
  67. data/test/internals_test.rb +152 -0
  68. data/test/lint/hashes.rb +140 -0
  69. data/test/lint/internals.rb +36 -0
  70. data/test/lint/lists.rb +107 -0
  71. data/test/lint/sets.rb +90 -0
  72. data/test/lint/sorted_sets.rb +196 -0
  73. data/test/lint/strings.rb +133 -0
  74. data/test/lint/value_types.rb +81 -0
  75. data/test/persistence_control_commands_test.rb +21 -0
  76. data/test/pipelining_commands_test.rb +186 -0
  77. data/test/publish_subscribe_test.rb +158 -0
  78. data/test/redis_mock.rb +89 -0
  79. data/test/remote_server_control_commands_test.rb +88 -0
  80. data/test/sorting_test.rb +43 -0
  81. data/test/synchrony_driver.rb +57 -0
  82. data/test/test.conf +9 -0
  83. data/test/thread_safety_test.rb +30 -0
  84. data/test/transactions_test.rb +173 -0
  85. data/test/unknown_commands_test.rb +13 -0
  86. data/test/url_param_test.rb +59 -0
  87. metadata +236 -0
@@ -0,0 +1,72 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path("./helper", File.dirname(__FILE__))
4
+ require "redis/distributed"
5
+
6
+ setup do
7
+ log = StringIO.new
8
+ init(Redis::Distributed.new(NODES, :logger => ::Logger.new(log)))
9
+ end
10
+
11
+ load "./test/lint/value_types.rb"
12
+
13
+ test "DEL" do |r|
14
+ r.set "foo", "s1"
15
+ r.set "bar", "s2"
16
+ r.set "baz", "s3"
17
+
18
+ assert ["bar", "baz", "foo"] == r.keys("*").sort
19
+
20
+ assert 1 == r.del("foo")
21
+
22
+ assert ["bar", "baz"] == r.keys("*").sort
23
+
24
+ assert 2 == r.del("bar", "baz")
25
+
26
+ assert [] == r.keys("*").sort
27
+ end
28
+
29
+ test "RANDOMKEY" do |r|
30
+ assert_raise Redis::Distributed::CannotDistribute do
31
+ r.randomkey
32
+ end
33
+ end
34
+
35
+ test "RENAME" do |r|
36
+ assert_raise Redis::Distributed::CannotDistribute do
37
+ r.set("foo", "s1")
38
+ r.rename "foo", "bar"
39
+ end
40
+
41
+ assert "s1" == r.get("foo")
42
+ assert nil == r.get("bar")
43
+ end
44
+
45
+ test "RENAMENX" do |r|
46
+ assert_raise Redis::Distributed::CannotDistribute do
47
+ r.set("foo", "s1")
48
+ r.rename "foo", "bar"
49
+ end
50
+
51
+ assert "s1" == r.get("foo")
52
+ assert nil == r.get("bar")
53
+ end
54
+
55
+ test "DBSIZE" do |r|
56
+ assert [0] == r.dbsize
57
+
58
+ r.set("foo", "s1")
59
+
60
+ assert [1] == r.dbsize
61
+ end
62
+
63
+ test "FLUSHDB" do |r|
64
+ r.set("foo", "s1")
65
+ r.set("bar", "s2")
66
+
67
+ assert [2] == r.dbsize
68
+
69
+ r.flushdb
70
+
71
+ assert [0] == r.dbsize
72
+ end
@@ -0,0 +1,148 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path("./helper", File.dirname(__FILE__))
4
+ require "redis/distributed"
5
+
6
+ setup do
7
+ log = StringIO.new
8
+ init Redis::Distributed.new(NODES, :logger => ::Logger.new(log))
9
+ end
10
+
11
+ test "RENAME" do |r|
12
+ r.set("{qux}foo", "s1")
13
+ r.rename "{qux}foo", "{qux}bar"
14
+
15
+ assert "s1" == r.get("{qux}bar")
16
+ assert nil == r.get("{qux}foo")
17
+ end
18
+
19
+ test "RENAMENX" do |r|
20
+ r.set("{qux}foo", "s1")
21
+ r.set("{qux}bar", "s2")
22
+
23
+ assert false == r.renamenx("{qux}foo", "{qux}bar")
24
+
25
+ assert "s1" == r.get("{qux}foo")
26
+ assert "s2" == r.get("{qux}bar")
27
+ end
28
+
29
+ test "BRPOPLPUSH" do |r|
30
+ r.rpush "{qux}foo", "s1"
31
+ r.rpush "{qux}foo", "s2"
32
+
33
+ assert_equal "s2", r.brpoplpush("{qux}foo", "{qux}bar", 1)
34
+ assert_equal ["s2"], r.lrange("{qux}bar", 0, -1)
35
+ end
36
+
37
+ test "RPOPLPUSH" do |r|
38
+ r.rpush "{qux}foo", "s1"
39
+ r.rpush "{qux}foo", "s2"
40
+
41
+ assert "s2" == r.rpoplpush("{qux}foo", "{qux}bar")
42
+ assert ["s2"] == r.lrange("{qux}bar", 0, -1)
43
+ assert "s1" == r.rpoplpush("{qux}foo", "{qux}bar")
44
+ assert ["s1", "s2"] == r.lrange("{qux}bar", 0, -1)
45
+ end
46
+
47
+ test "SMOVE" do |r|
48
+ r.sadd "{qux}foo", "s1"
49
+ r.sadd "{qux}bar", "s2"
50
+
51
+ assert r.smove("{qux}foo", "{qux}bar", "s1")
52
+ assert r.sismember("{qux}bar", "s1")
53
+ end
54
+
55
+ test "SINTER" do |r|
56
+ r.sadd "{qux}foo", "s1"
57
+ r.sadd "{qux}foo", "s2"
58
+ r.sadd "{qux}bar", "s2"
59
+
60
+ assert ["s2"] == r.sinter("{qux}foo", "{qux}bar")
61
+ end
62
+
63
+ test "SINTERSTORE" do |r|
64
+ r.sadd "{qux}foo", "s1"
65
+ r.sadd "{qux}foo", "s2"
66
+ r.sadd "{qux}bar", "s2"
67
+
68
+ r.sinterstore("{qux}baz", "{qux}foo", "{qux}bar")
69
+
70
+ assert ["s2"] == r.smembers("{qux}baz")
71
+ end
72
+
73
+ test "SUNION" do |r|
74
+ r.sadd "{qux}foo", "s1"
75
+ r.sadd "{qux}foo", "s2"
76
+ r.sadd "{qux}bar", "s2"
77
+ r.sadd "{qux}bar", "s3"
78
+
79
+ assert ["s1", "s2", "s3"] == r.sunion("{qux}foo", "{qux}bar").sort
80
+ end
81
+
82
+ test "SUNIONSTORE" do |r|
83
+ r.sadd "{qux}foo", "s1"
84
+ r.sadd "{qux}foo", "s2"
85
+ r.sadd "{qux}bar", "s2"
86
+ r.sadd "{qux}bar", "s3"
87
+
88
+ r.sunionstore("{qux}baz", "{qux}foo", "{qux}bar")
89
+
90
+ assert ["s1", "s2", "s3"] == r.smembers("{qux}baz").sort
91
+ end
92
+
93
+ test "SDIFF" do |r|
94
+ r.sadd "{qux}foo", "s1"
95
+ r.sadd "{qux}foo", "s2"
96
+ r.sadd "{qux}bar", "s2"
97
+ r.sadd "{qux}bar", "s3"
98
+
99
+ assert ["s1"] == r.sdiff("{qux}foo", "{qux}bar")
100
+ assert ["s3"] == r.sdiff("{qux}bar", "{qux}foo")
101
+ end
102
+
103
+ test "SDIFFSTORE" do |r|
104
+ r.sadd "{qux}foo", "s1"
105
+ r.sadd "{qux}foo", "s2"
106
+ r.sadd "{qux}bar", "s2"
107
+ r.sadd "{qux}bar", "s3"
108
+
109
+ r.sdiffstore("{qux}baz", "{qux}foo", "{qux}bar")
110
+
111
+ assert ["s1"] == r.smembers("{qux}baz")
112
+ end
113
+
114
+ test "SORT" do |r|
115
+ r.set("{qux}foo:1", "s1")
116
+ r.set("{qux}foo:2", "s2")
117
+
118
+ r.rpush("{qux}bar", "1")
119
+ r.rpush("{qux}bar", "2")
120
+
121
+ assert ["s1"] == r.sort("{qux}bar", :get => "{qux}foo:*", :limit => [0, 1])
122
+ assert ["s2"] == r.sort("{qux}bar", :get => "{qux}foo:*", :limit => [0, 1], :order => "desc alpha")
123
+ end
124
+
125
+ test "SORT with an array of GETs" do |r|
126
+ r.set("{qux}foo:1:a", "s1a")
127
+ r.set("{qux}foo:1:b", "s1b")
128
+
129
+ r.set("{qux}foo:2:a", "s2a")
130
+ r.set("{qux}foo:2:b", "s2b")
131
+
132
+ r.rpush("{qux}bar", "1")
133
+ r.rpush("{qux}bar", "2")
134
+
135
+ assert ["s1a", "s1b"] == r.sort("{qux}bar", :get => ["{qux}foo:*:a", "{qux}foo:*:b"], :limit => [0, 1])
136
+ assert ["s2a", "s2b"] == r.sort("{qux}bar", :get => ["{qux}foo:*:a", "{qux}foo:*:b"], :limit => [0, 1], :order => "desc alpha")
137
+ end
138
+
139
+ test "SORT with STORE" do |r|
140
+ r.set("{qux}foo:1", "s1")
141
+ r.set("{qux}foo:2", "s2")
142
+
143
+ r.rpush("{qux}bar", "1")
144
+ r.rpush("{qux}bar", "2")
145
+
146
+ r.sort("{qux}bar", :get => "{qux}foo:*", :store => "{qux}baz")
147
+ assert ["s1", "s2"] == r.lrange("{qux}baz", 0, -1)
148
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path("./helper", File.dirname(__FILE__))
4
+ require "redis/distributed"
5
+
6
+ setup do
7
+ log = StringIO.new
8
+ init Redis::Distributed.new(NODES, :logger => ::Logger.new(log))
9
+ end
10
+
11
+ test "PING" do |r|
12
+ assert ["PONG"] == r.ping
13
+ end
14
+
15
+ test "SELECT" do |r|
16
+ r.set "foo", "bar"
17
+
18
+ r.select 14
19
+ assert nil == r.get("foo")
20
+
21
+ r.select 15
22
+
23
+ assert "bar" == r.get("foo")
24
+ end
@@ -0,0 +1,27 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path("./helper", File.dirname(__FILE__))
4
+ require File.expand_path("./redis_mock", File.dirname(__FILE__))
5
+
6
+ include RedisMock::Helper
7
+
8
+ require "redis/distributed"
9
+
10
+ setup do
11
+ log = StringIO.new
12
+ [init(Redis::Distributed.new(NODES, :logger => ::Logger.new(log))), log]
13
+ end
14
+
15
+ $TEST_PIPELINING = false
16
+
17
+ load File.expand_path("./lint/internals.rb", File.dirname(__FILE__))
18
+
19
+ test "provides a meaningful inspect" do |r, _|
20
+ nodes = ["redis://localhost:6379/15", *NODES]
21
+ @r = Redis::Distributed.new nodes
22
+
23
+ node_info = nodes.map do |node|
24
+ "#{node} (Redis v#{@r.info.first["redis_version"]})"
25
+ end
26
+ assert "#<Redis client v#{Redis::VERSION} connected to #{node_info.join(', ')}>" == @r.inspect
27
+ end
@@ -0,0 +1,52 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path("./helper", File.dirname(__FILE__))
4
+ require "redis/distributed"
5
+
6
+ setup do
7
+ log = StringIO.new
8
+ init Redis::Distributed.new(NODES, :logger => ::Logger.new(log))
9
+ end
10
+
11
+ test "hashes consistently" do
12
+ r1 = Redis::Distributed.new ["redis://localhost:6379/15", *NODES]
13
+ r2 = Redis::Distributed.new ["redis://localhost:6379/15", *NODES]
14
+ r3 = Redis::Distributed.new ["redis://localhost:6379/15", *NODES]
15
+
16
+ assert r1.node_for("foo").id == r2.node_for("foo").id
17
+ assert r1.node_for("foo").id == r3.node_for("foo").id
18
+ end
19
+
20
+ test "allows clustering of keys" do |r|
21
+ r = Redis::Distributed.new(NODES)
22
+ r.add_node("redis://localhost:6379/14")
23
+ r.flushdb
24
+
25
+ 100.times do |i|
26
+ r.set "{foo}users:#{i}", i
27
+ end
28
+
29
+ assert [0, 100] == r.nodes.map { |node| node.keys.size }
30
+ end
31
+
32
+ test "distributes keys if no clustering is used" do |r|
33
+ r.add_node("redis://localhost:6379/14")
34
+ r.flushdb
35
+
36
+ r.set "users:1", 1
37
+ r.set "users:4", 4
38
+
39
+ assert [1, 1] == r.nodes.map { |node| node.keys.size }
40
+ end
41
+
42
+ test "allows passing a custom tag extractor" do |r|
43
+ r = Redis::Distributed.new(NODES, :tag => /^(.+?):/)
44
+ r.add_node("redis://localhost:6379/14")
45
+ r.flushdb
46
+
47
+ 100.times do |i|
48
+ r.set "foo:users:#{i}", i
49
+ end
50
+
51
+ assert [0, 100] == r.nodes.map { |node| node.keys.size }
52
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path("./helper", File.dirname(__FILE__))
4
+ require "redis/distributed"
5
+
6
+ setup do
7
+ log = StringIO.new
8
+ init Redis::Distributed.new(NODES, :logger => ::Logger.new(log))
9
+ end
10
+
11
+ test "SAVE and BGSAVE" do |r|
12
+ assert_nothing_raised do
13
+ r.save
14
+ end
15
+
16
+ assert_nothing_raised do
17
+ r.bgsave
18
+ end
19
+ end
20
+
21
+ test "LASTSAVE" do |r|
22
+ assert r.lastsave.all? { |t| Time.at(t) <= Time.now }
23
+ end
@@ -0,0 +1,100 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path("./helper", File.dirname(__FILE__))
4
+ require "redis/distributed"
5
+
6
+ setup do
7
+ log = StringIO.new
8
+ init Redis::Distributed.new(NODES, :logger => ::Logger.new(log))
9
+ end
10
+
11
+ test "SUBSCRIBE and UNSUBSCRIBE" do |r|
12
+ assert_raise Redis::Distributed::CannotDistribute do
13
+ r.subscribe("foo", "bar") { }
14
+ end
15
+
16
+ assert_raise Redis::Distributed::CannotDistribute do
17
+ r.subscribe("{qux}foo", "bar") { }
18
+ end
19
+ end
20
+
21
+ test "SUBSCRIBE and UNSUBSCRIBE with tags" do |r|
22
+ listening = false
23
+
24
+ wire = Wire.new do
25
+ r.subscribe("foo") do |on|
26
+ on.subscribe do |channel, total|
27
+ @subscribed = true
28
+ @t1 = total
29
+ end
30
+
31
+ on.message do |channel, message|
32
+ if message == "s1"
33
+ r.unsubscribe
34
+ @message = message
35
+ end
36
+ end
37
+
38
+ on.unsubscribe do |channel, total|
39
+ @unsubscribed = true
40
+ @t2 = total
41
+ end
42
+
43
+ listening = true
44
+ end
45
+ end
46
+
47
+ Wire.pass while !listening
48
+
49
+ Redis::Distributed.new(NODES).publish("foo", "s1")
50
+
51
+ wire.join
52
+
53
+ assert @subscribed
54
+ assert 1 == @t1
55
+ assert @unsubscribed
56
+ assert 0 == @t2
57
+ assert "s1" == @message
58
+ end
59
+
60
+ test "SUBSCRIBE within SUBSCRIBE" do |r|
61
+ listening = false
62
+ @channels = []
63
+
64
+ wire = Wire.new do
65
+ r.subscribe("foo") do |on|
66
+ on.subscribe do |channel, total|
67
+ @channels << channel
68
+
69
+ r.subscribe("bar") if channel == "foo"
70
+ r.unsubscribe if channel == "bar"
71
+ end
72
+
73
+ listening = true
74
+ end
75
+ end
76
+
77
+ Wire.pass while !listening
78
+
79
+ Redis::Distributed.new(NODES).publish("foo", "s1")
80
+
81
+ wire.join
82
+
83
+ assert ["foo", "bar"] == @channels
84
+ end
85
+
86
+ test "other commands within a SUBSCRIBE" do |r|
87
+ assert_raise Redis::CommandError do
88
+ r.subscribe("foo") do |on|
89
+ on.subscribe do |channel, total|
90
+ r.set("bar", "s2")
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ test "SUBSCRIBE without a block" do |r|
97
+ assert_raise LocalJumpError do
98
+ r.subscribe("foo")
99
+ end
100
+ end