riak-client 2.4.0 → 2.4.1
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.
- 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
|