riak-client 2.4.0 → 2.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -2
- data/README.md +9 -2
- data/RELNOTES.md +71 -68
- data/lib/riak/bucket.rb +3 -6
- data/lib/riak/bucket_type.rb +4 -2
- data/lib/riak/client/beefcake/socket.rb +7 -3
- data/lib/riak/crdt/map.rb +0 -1
- data/lib/riak/crdt/set.rb +4 -1
- data/lib/riak/crdt/typed_collection.rb +9 -5
- data/lib/riak/util/string.rb +31 -0
- data/lib/riak/version.rb +1 -1
- data/riak-client.gemspec +9 -8
- data/spec/integration/riak/encodings/crdt_spec.rb +24 -4
- data/spec/integration/riak/protobuffs/timeouts_spec.rb +147 -143
- data/spec/riak/util/gzip_spec.rb +14 -2
- data/spec/support/test_client.rb +8 -2
- metadata +49 -36
data/lib/riak/crdt/map.rb
CHANGED
data/lib/riak/crdt/set.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'riak/util/string'
|
2
|
+
|
1
3
|
module Riak
|
2
4
|
module Crdt
|
3
5
|
|
@@ -6,6 +8,7 @@ module Riak
|
|
6
8
|
# Uses the Ruby standard library `::Set` frequently, so the full class names will
|
7
9
|
# be used frequently.
|
8
10
|
class Set < Base
|
11
|
+
include Util::String
|
9
12
|
|
10
13
|
# Create a set instance. The bucket type is determined by the first of
|
11
14
|
# these sources:
|
@@ -73,7 +76,7 @@ module Riak
|
|
73
76
|
# @param [String] candidate string to check for inclusion in this structure
|
74
77
|
# @return [Boolean] if the structure includes
|
75
78
|
def include?(candidate)
|
76
|
-
members.
|
79
|
+
members.any? { |m| equal_bytes?(m, candidate) }
|
77
80
|
end
|
78
81
|
|
79
82
|
# Add a {String} to the {Riak::Crdt::Set}
|
@@ -74,7 +74,7 @@ module Riak
|
|
74
74
|
# @param [String] key the key to get the value for
|
75
75
|
# @return the value for the given key
|
76
76
|
def [](key)
|
77
|
-
key = normalize_key
|
77
|
+
key = normalize_key(key)
|
78
78
|
if include? key
|
79
79
|
candidate = @contents[key]
|
80
80
|
return candidate unless candidate.respond_to? :parent
|
@@ -97,7 +97,7 @@ module Riak
|
|
97
97
|
# @param [Boolean, String, Integer] value the value to set at the key,
|
98
98
|
# or in the case of counters, the amount to increment
|
99
99
|
def []=(key, value)
|
100
|
-
key = normalize_key
|
100
|
+
key = normalize_key(key)
|
101
101
|
|
102
102
|
operation = @type.update value
|
103
103
|
operation.name = key
|
@@ -112,11 +112,15 @@ module Riak
|
|
112
112
|
|
113
113
|
alias_method :increment, :[]=
|
114
114
|
|
115
|
+
def length
|
116
|
+
@contents.length
|
117
|
+
end
|
118
|
+
|
115
119
|
# Remove the entry from the map.
|
116
120
|
#
|
117
121
|
# @param [String] key the key to remove from the map
|
118
122
|
def delete(key)
|
119
|
-
key = normalize_key
|
123
|
+
key = normalize_key(key)
|
120
124
|
operation = @type.delete
|
121
125
|
operation.name = key
|
122
126
|
|
@@ -127,7 +131,7 @@ module Riak
|
|
127
131
|
|
128
132
|
# @api private
|
129
133
|
def operate(key, inner_operation)
|
130
|
-
key = normalize_key
|
134
|
+
key = normalize_key(key)
|
131
135
|
|
132
136
|
inner_operation.name = key
|
133
137
|
|
@@ -152,7 +156,7 @@ module Riak
|
|
152
156
|
private
|
153
157
|
|
154
158
|
def normalize_key(unnormalized_key)
|
155
|
-
unnormalized_key.to_s
|
159
|
+
unnormalized_key.to_s.dup.force_encoding('binary')
|
156
160
|
end
|
157
161
|
|
158
162
|
def initialize_nil?
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Riak
|
2
|
+
module Util
|
3
|
+
# Methods comparing strings
|
4
|
+
module String
|
5
|
+
def equal_bytes?(a, b)
|
6
|
+
return true if a.nil? && b.nil?
|
7
|
+
|
8
|
+
return false unless a.respond_to?(:bytesize)
|
9
|
+
return false unless b.respond_to?(:bytesize)
|
10
|
+
return false unless a.bytesize == b.bytesize
|
11
|
+
|
12
|
+
return false unless a.respond_to?(:bytes)
|
13
|
+
return false unless b.respond_to?(:bytes)
|
14
|
+
|
15
|
+
b1 = a.bytes.to_a
|
16
|
+
b2 = b.bytes.to_a
|
17
|
+
i = 0
|
18
|
+
loop do
|
19
|
+
c1 = b1[i]
|
20
|
+
c2 = b2[i]
|
21
|
+
return false unless c1 == c2
|
22
|
+
i += 1
|
23
|
+
break if i > b1.length
|
24
|
+
end
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
module_function :equal_bytes?
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/riak/version.rb
CHANGED
data/riak-client.gemspec
CHANGED
@@ -15,19 +15,20 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.required_ruby_version = '>= 1.9.3'
|
16
16
|
|
17
17
|
# Deps
|
18
|
-
gem.add_development_dependency '
|
19
|
-
gem.add_development_dependency '
|
20
|
-
gem.add_development_dependency 'yard', '~> 0.8'
|
18
|
+
gem.add_development_dependency 'activesupport', '~> 4.2'
|
19
|
+
gem.add_development_dependency 'instrumentable', '~> 1.1'
|
21
20
|
gem.add_development_dependency 'kramdown', '~> 1.4'
|
21
|
+
gem.add_development_dependency 'rake', '~> 10.1'
|
22
|
+
gem.add_development_dependency 'rspec', '~> 3.0'
|
23
|
+
gem.add_development_dependency 'rubocop', '~> 0.40.0'
|
22
24
|
gem.add_development_dependency 'simplecov', '~> 0.10'
|
23
|
-
gem.add_development_dependency '
|
24
|
-
gem.add_development_dependency 'rubocop', '~> 0.40'
|
25
|
+
gem.add_development_dependency 'yard', '~> 0.8'
|
25
26
|
|
26
|
-
gem.add_runtime_dependency 'i18n', '~> 0.6'
|
27
27
|
gem.add_runtime_dependency 'beefcake', '~> 1.1'
|
28
|
-
gem.add_runtime_dependency 'multi_json', '~> 1.0'
|
29
|
-
gem.add_runtime_dependency 'innertube', '~> 1.0'
|
30
28
|
gem.add_runtime_dependency 'cert_validator', '~> 0.0.1'
|
29
|
+
gem.add_runtime_dependency 'i18n', '~> 0.6'
|
30
|
+
gem.add_runtime_dependency 'innertube', '~> 1.0'
|
31
|
+
gem.add_runtime_dependency 'multi_json', '~> 1.0'
|
31
32
|
|
32
33
|
# Files
|
33
34
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
require 'spec_helper'
|
3
3
|
require 'riak'
|
4
|
+
require 'riak/util/string'
|
4
5
|
|
5
6
|
describe 'Encoding and CRDTs', integration: true, search_config: true do
|
6
7
|
shared_examples 'CRDTs with weird names' do
|
@@ -16,6 +17,7 @@ describe 'Encoding and CRDTs', integration: true, search_config: true do
|
|
16
17
|
|
17
18
|
it 'creates counters' do
|
18
19
|
counter = nil
|
20
|
+
|
19
21
|
expect{ counter = Riak::Crdt::Counter.new counter_bucket, random_string }.
|
20
22
|
to_not raise_error
|
21
23
|
|
@@ -24,44 +26,61 @@ describe 'Encoding and CRDTs', integration: true, search_config: true do
|
|
24
26
|
expect(value = counter.value).to be_a Numeric
|
25
27
|
|
26
28
|
expect{ counter.increment }.to_not raise_error
|
29
|
+
|
27
30
|
expect(counter.value).to eq value + 1
|
28
31
|
end
|
29
32
|
|
30
33
|
it 'updates registers in maps' do
|
31
34
|
map = nil
|
35
|
+
|
36
|
+
expect(random_string.encoding.name).to eq expected_encoding
|
37
|
+
|
32
38
|
expect{ map = Riak::Crdt::Map.new map_bucket, random_string }.
|
33
39
|
to_not raise_error
|
34
40
|
|
35
41
|
expect(map).to be_a Riak::Crdt::Map
|
36
42
|
|
37
43
|
expect(map.registers[random_string]).to be_nil
|
44
|
+
|
38
45
|
expect{ map.registers[random_string] = random_string }.
|
39
46
|
to_not raise_error
|
40
47
|
|
41
|
-
expect(map.registers
|
48
|
+
expect(map.registers.length).to eq 1
|
49
|
+
|
50
|
+
expect(map.registers[random_string]).to_not be_nil
|
51
|
+
|
52
|
+
expect(Riak::Util::String.equal_bytes?(map.registers[random_string], random_string)).to be
|
53
|
+
|
54
|
+
expect(random_string.encoding.name).to eq expected_encoding
|
42
55
|
end
|
43
56
|
|
44
57
|
it 'updates sets' do
|
45
58
|
set = nil
|
59
|
+
|
60
|
+
expect(random_string.encoding.name).to eq expected_encoding
|
61
|
+
|
46
62
|
expect{ set = Riak::Crdt::Set.new set_bucket, random_string }.
|
47
63
|
to_not raise_error
|
48
64
|
|
49
65
|
expect(set).to be_a Riak::Crdt::Set
|
50
66
|
|
51
|
-
expect(set.
|
67
|
+
expect(set.include?(random_string)).to_not be
|
52
68
|
|
53
69
|
set.add random_string
|
54
70
|
|
55
|
-
expect(set.
|
71
|
+
expect(set.include?(random_string)).to be
|
56
72
|
|
57
73
|
set.remove random_string
|
58
74
|
|
59
|
-
expect(set.
|
75
|
+
expect(set.include?(random_string)).to_not be
|
76
|
+
|
77
|
+
expect(random_string.encoding.name).to eq expected_encoding
|
60
78
|
end
|
61
79
|
end
|
62
80
|
|
63
81
|
describe 'with utf-8 strings' do
|
64
82
|
let(:string){ "\xF0\x9F\x9A\xB4こんにちはสวัสดี" }
|
83
|
+
let(:expected_encoding){ 'UTF-8' }
|
65
84
|
let(:random_string){ string + random_key }
|
66
85
|
|
67
86
|
include_examples 'CRDTs with weird names'
|
@@ -69,6 +88,7 @@ describe 'Encoding and CRDTs', integration: true, search_config: true do
|
|
69
88
|
|
70
89
|
describe 'with binary strings' do
|
71
90
|
let(:string){ "\xff\xff".force_encoding('binary') }
|
91
|
+
let(:expected_encoding){ 'ASCII-8BIT' }
|
72
92
|
let(:random_string){ string + random_key }
|
73
93
|
|
74
94
|
include_examples 'CRDTs with weird names'
|
@@ -5,170 +5,174 @@ require 'riak/client/beefcake/messages'
|
|
5
5
|
require 'riak/client/beefcake/protocol'
|
6
6
|
|
7
7
|
describe 'Protocol Buffers', test_client: true, integration: true do
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
it 'raises error on read timeout' do
|
24
|
-
ok_to_continue = false
|
25
|
-
quitting = false
|
26
|
-
port = 0
|
8
|
+
if RUBY_VERSION >= '2.0.0'
|
9
|
+
describe 'timeouts' do
|
10
|
+
it 'raises error on connect timeout' do
|
11
|
+
# unroutable TEST-NET (https://tools.ietf.org/html/rfc5737)
|
12
|
+
config = {}
|
13
|
+
config[:host] = '192.0.2.0'
|
14
|
+
config[:pb_port] = 65535
|
15
|
+
|
16
|
+
config[:connect_timeout] = 0.0001
|
17
|
+
client = Riak::Client.new(config)
|
18
|
+
|
19
|
+
expect do
|
20
|
+
client.ping
|
21
|
+
end.to raise_error RuntimeError, /timed out/
|
22
|
+
end
|
27
23
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
port =
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
24
|
+
it 'raises error on read timeout' do
|
25
|
+
ok_to_continue = false
|
26
|
+
quitting = false
|
27
|
+
port = 0
|
28
|
+
|
29
|
+
server = nil
|
30
|
+
thr = Thread.new do
|
31
|
+
server = TCPServer.new port
|
32
|
+
port = server.addr[1]
|
33
|
+
ok_to_continue = true
|
34
|
+
loop do
|
35
|
+
begin
|
36
|
+
Thread.start(server.accept) do |s|
|
37
|
+
loop do
|
38
|
+
p = Riak::Client::BeefcakeProtobuffsBackend::Protocol.new s
|
39
|
+
begin
|
40
|
+
msgname, _body = p.receive
|
41
|
+
rescue IOError
|
42
|
+
break if quitting
|
43
|
+
raise
|
44
|
+
end
|
45
|
+
case msgname
|
46
|
+
when :PingReq
|
47
|
+
sleep 0.5
|
48
|
+
p.write :PingResp
|
49
|
+
else
|
50
|
+
$stderr.puts("unknown msgname: #{msgname}")
|
51
|
+
end
|
50
52
|
end
|
51
53
|
end
|
54
|
+
rescue IOError
|
55
|
+
break if quitting
|
56
|
+
raise
|
52
57
|
end
|
53
|
-
rescue IOError
|
54
|
-
break if quitting
|
55
|
-
raise
|
56
58
|
end
|
57
59
|
end
|
58
|
-
end
|
59
60
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
end
|
64
|
-
ok_to_continue = false
|
65
|
-
|
66
|
-
config = {}
|
67
|
-
config[:pb_port] = port
|
68
|
-
config[:client_id] = port
|
69
|
-
config[:read_timeout] = 0.0001
|
70
|
-
client = Riak::Client.new(config)
|
71
|
-
|
72
|
-
max_ping_attempts = 16
|
73
|
-
ping_count = 0
|
74
|
-
loop do
|
75
|
-
begin
|
76
|
-
client.ping
|
77
|
-
ping_count += 1
|
78
|
-
break if ping_count > max_ping_attempts
|
79
|
-
rescue RuntimeError => e
|
80
|
-
break if e.message =~ /timed out/
|
61
|
+
loop do
|
62
|
+
break if ok_to_continue
|
63
|
+
sleep 0.1
|
81
64
|
end
|
82
|
-
|
83
|
-
end
|
84
|
-
|
85
|
-
quitting = true
|
86
|
-
server.close
|
87
|
-
thr.join
|
65
|
+
ok_to_continue = false
|
88
66
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
quitting = false
|
95
|
-
port = 0
|
67
|
+
config = {}
|
68
|
+
config[:pb_port] = port
|
69
|
+
config[:client_id] = port
|
70
|
+
config[:read_timeout] = 0.0001
|
71
|
+
client = Riak::Client.new(config)
|
96
72
|
|
97
|
-
|
98
|
-
|
99
|
-
server = TCPServer.new port
|
100
|
-
port = server.addr[1]
|
101
|
-
ok_to_continue = true
|
73
|
+
max_ping_attempts = 16
|
74
|
+
ping_count = 0
|
102
75
|
loop do
|
103
76
|
begin
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
77
|
+
client.ping
|
78
|
+
ping_count += 1
|
79
|
+
break if ping_count > max_ping_attempts
|
80
|
+
rescue RuntimeError => e
|
81
|
+
break if e.message =~ /timed out/
|
82
|
+
end
|
83
|
+
sleep 0.5
|
84
|
+
end
|
85
|
+
|
86
|
+
quitting = true
|
87
|
+
server.close
|
88
|
+
thr.join
|
89
|
+
|
90
|
+
expect(ping_count).to be < max_ping_attempts
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'raises error on write timeout' do
|
94
|
+
ok_to_continue = false
|
95
|
+
quitting = false
|
96
|
+
port = 0
|
97
|
+
|
98
|
+
server = nil
|
99
|
+
thr = Thread.new do
|
100
|
+
server = TCPServer.new port
|
101
|
+
port = server.addr[1]
|
102
|
+
ok_to_continue = true
|
103
|
+
loop do
|
104
|
+
begin
|
105
|
+
Thread.start(server.accept) do |s|
|
106
|
+
loop do
|
107
|
+
p = Riak::Client::BeefcakeProtobuffsBackend::Protocol.new s
|
108
|
+
begin
|
109
|
+
msgname, _body = p.receive
|
110
|
+
rescue IOError
|
111
|
+
break if quitting
|
112
|
+
raise
|
113
|
+
end
|
114
|
+
case msgname
|
115
|
+
when :PingReq
|
116
|
+
p.write :PingResp
|
117
|
+
when :GetServerInfoReq
|
118
|
+
r = Riak::Client::BeefcakeProtobuffsBackend::RpbGetServerInfoResp.new
|
119
|
+
r.node = 'dev1@127.0.0.1'.force_encoding('BINARY')
|
120
|
+
r.server_version = '2.1.4'.force_encoding('BINARY')
|
121
|
+
p.write :GetServerInfoResp, r
|
122
|
+
when :PutReq
|
123
|
+
r = Riak::Client::BeefcakeProtobuffsBackend::RpbPutResp.new
|
124
|
+
p.write :PutResp, r
|
125
|
+
else
|
126
|
+
$stderr.puts("unknown msgname: #{msgname}")
|
127
|
+
end
|
126
128
|
end
|
127
129
|
end
|
130
|
+
rescue IOError
|
131
|
+
break if quitting
|
132
|
+
raise
|
128
133
|
end
|
129
|
-
rescue IOError
|
130
|
-
break if quitting
|
131
|
-
raise
|
132
134
|
end
|
133
135
|
end
|
134
|
-
end
|
135
136
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
end
|
140
|
-
ok_to_continue = false
|
141
|
-
|
142
|
-
config = {}
|
143
|
-
config[:pb_port] = port
|
144
|
-
config[:client_id] = port
|
145
|
-
config[:write_timeout] = 0.0001
|
146
|
-
client = Riak::Client.new(config)
|
147
|
-
|
148
|
-
bucket = client.bucket('timeouts')
|
149
|
-
|
150
|
-
max_store_attempts = 16
|
151
|
-
store_count = 0
|
152
|
-
loop do
|
153
|
-
begin
|
154
|
-
obj = bucket.new "obj-#{store_count}"
|
155
|
-
# write enough data to grow beyond socket buffer capacity
|
156
|
-
obj.data = SecureRandom.urlsafe_base64(10_000_000)
|
157
|
-
obj.content_type = 'text/plain'
|
158
|
-
obj.store
|
159
|
-
store_count += 1
|
160
|
-
break if store_count > max_store_attempts
|
161
|
-
rescue RuntimeError => e
|
162
|
-
break if e.message =~ /timed out/
|
137
|
+
loop do
|
138
|
+
break if ok_to_continue
|
139
|
+
sleep 0.1
|
163
140
|
end
|
164
|
-
|
165
|
-
end
|
141
|
+
ok_to_continue = false
|
166
142
|
|
167
|
-
|
168
|
-
|
169
|
-
|
143
|
+
config = {}
|
144
|
+
config[:pb_port] = port
|
145
|
+
config[:client_id] = port
|
146
|
+
config[:write_timeout] = 0.0001
|
147
|
+
client = Riak::Client.new(config)
|
170
148
|
|
171
|
-
|
149
|
+
bucket = client.bucket('timeouts')
|
150
|
+
|
151
|
+
max_store_attempts = 16
|
152
|
+
store_count = 0
|
153
|
+
loop do
|
154
|
+
begin
|
155
|
+
obj = bucket.new "obj-#{store_count}"
|
156
|
+
# write enough data to grow beyond socket buffer capacity
|
157
|
+
obj.data = SecureRandom.urlsafe_base64(10_000_000)
|
158
|
+
obj.content_type = 'text/plain'
|
159
|
+
obj.store
|
160
|
+
store_count += 1
|
161
|
+
break if store_count > max_store_attempts
|
162
|
+
rescue RuntimeError => e
|
163
|
+
break if e.message =~ /timed out/
|
164
|
+
end
|
165
|
+
sleep 0.5
|
166
|
+
end
|
167
|
+
|
168
|
+
quitting = true
|
169
|
+
server.close
|
170
|
+
thr.join
|
171
|
+
|
172
|
+
expect(store_count).to be < max_store_attempts
|
173
|
+
end
|
172
174
|
end
|
175
|
+
else
|
176
|
+
skip 'not supported in this version of Ruby'
|
173
177
|
end
|
174
178
|
end
|