riak-client 2.4.1 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.document +5 -5
- data/.gitignore +3 -0
- data/Gemfile +17 -17
- data/Guardfile +20 -20
- data/LICENSE.md +16 -16
- data/RELNOTES.md +4 -0
- data/Rakefile +6 -1
- data/lib/riak/client/beefcake/crdt/counter_loader.rb +18 -18
- data/lib/riak/client/beefcake/crdt/hyper_log_log_loader.rb +18 -0
- data/lib/riak/client/beefcake/crdt/map_loader.rb +64 -64
- data/lib/riak/client/beefcake/crdt_loader.rb +4 -1
- data/lib/riak/client/beefcake/crdt_operator.rb +13 -0
- data/lib/riak/client/beefcake/footer +4 -4
- data/lib/riak/client/beefcake/header +6 -6
- data/lib/riak/client/beefcake/messages.rb +67 -10
- data/lib/riak/client/decaying.rb +36 -36
- data/lib/riak/client/feature_detection.rb +120 -120
- data/lib/riak/client/instrumentation.rb +19 -19
- data/lib/riak/client/node.rb +49 -49
- data/lib/riak/client/search.rb +27 -27
- data/lib/riak/conflict.rb +13 -13
- data/lib/riak/core_ext.rb +7 -7
- data/lib/riak/core_ext/blank.rb +53 -53
- data/lib/riak/core_ext/extract_options.rb +7 -7
- data/lib/riak/core_ext/json.rb +15 -15
- data/lib/riak/core_ext/slice.rb +18 -18
- data/lib/riak/core_ext/stringify_keys.rb +10 -10
- data/lib/riak/core_ext/symbolize_keys.rb +10 -10
- data/lib/riak/core_ext/to_param.rb +31 -31
- data/lib/riak/crdt.rb +23 -21
- data/lib/riak/crdt/base.rb +1 -1
- data/lib/riak/crdt/hyper_log_log.rb +97 -0
- data/lib/riak/crdt/operation.rb +19 -19
- data/lib/riak/encoding.rb +6 -6
- data/lib/riak/errors/backend_creation.rb +9 -9
- data/lib/riak/errors/connection_error.rb +50 -50
- data/lib/riak/errors/protobuffs_error.rb +11 -11
- data/lib/riak/i18n.rb +7 -7
- data/lib/riak/instrumentation.rb +6 -6
- data/lib/riak/json.rb +52 -52
- data/lib/riak/list_buckets.rb +28 -28
- data/lib/riak/locale/en.yml +1 -0
- data/lib/riak/locale/fr.yml +51 -51
- data/lib/riak/map_reduce/results.rb +49 -49
- data/lib/riak/map_reduce_error.rb +7 -7
- data/lib/riak/multiget.rb +122 -122
- data/lib/riak/robject.rb +17 -1
- data/lib/riak/search/result_document.rb +9 -0
- data/lib/riak/stamp.rb +77 -77
- data/lib/riak/tombstone.rb +13 -0
- data/lib/riak/util/tcp_socket_extensions.rb +58 -58
- data/lib/riak/version.rb +1 -1
- data/spec/failover/failover.rb +59 -59
- data/spec/fixtures/bitcask.txt +25 -25
- data/spec/fixtures/multipart-basic-conflict.txt +15 -15
- data/spec/fixtures/multipart-blank.txt +7 -7
- data/spec/fixtures/multipart-mapreduce.txt +10 -10
- data/spec/fixtures/multipart-with-body.txt +16 -16
- data/spec/fixtures/multipart-with-marked-tombstones.txt +17 -17
- data/spec/fixtures/multipart-with-unmarked-tombstone.txt +16 -16
- data/spec/fixtures/server.cert.crt +15 -15
- data/spec/fixtures/server.cert.key +15 -15
- data/spec/fixtures/test.pem +1 -1
- data/spec/integration/riak/bucket_types_spec.rb +38 -0
- data/spec/integration/riak/crdt/configuration_spec.rb +4 -3
- data/spec/integration/riak/crdt_spec.rb +70 -0
- data/spec/integration/riak/encodings/crdt_spec.rb +29 -3
- data/spec/integration/riak/encodings/yz_spec.rb +2 -1
- data/spec/integration/riak/preflist_spec.rb +15 -3
- data/spec/integration/riak/protobuffs/timeouts_spec.rb +1 -1
- data/spec/integration/riak/security_spec.rb +11 -6
- data/spec/integration/riak/threading_spec.rb +154 -150
- data/spec/integration/yokozuna/index_spec.rb +61 -61
- data/spec/integration/yokozuna/queries_spec.rb +1 -1
- data/spec/integration/yokozuna/schema_spec.rb +49 -49
- data/spec/riak/beefcake_protobuffs_backend/crdt_operator_spec.rb +22 -0
- data/spec/riak/core_ext/to_param_spec.rb +15 -15
- data/spec/riak/crdt/hyper_log_log_spec.rb +56 -0
- data/spec/riak/crdt/inner_counter_spec.rb +21 -21
- data/spec/riak/crdt/inner_set_spec.rb +33 -33
- data/spec/riak/crdt/set_spec.rb +61 -61
- data/spec/riak/crdt/shared_examples.rb +14 -0
- data/spec/riak/escape_spec.rb +72 -72
- data/spec/riak/feature_detection_spec.rb +77 -77
- data/spec/riak/index_collection_spec.rb +53 -53
- data/spec/riak/instrumentation_spec.rb +124 -124
- data/spec/riak/link_spec.rb +85 -85
- data/spec/riak/list_buckets_spec.rb +41 -41
- data/spec/riak/node_spec.rb +26 -26
- data/spec/riak/robject_spec.rb +45 -0
- data/spec/support/certs/README.md +12 -12
- data/spec/support/certs/ca.crt +21 -21
- data/spec/support/certs/client.crl +13 -13
- data/spec/support/certs/client.crt +94 -94
- data/spec/support/certs/client.csr +18 -18
- data/spec/support/certs/client.key +27 -27
- data/spec/support/certs/empty_ca.crt +21 -21
- data/spec/support/certs/server.crl +13 -13
- data/spec/support/certs/server.crt +94 -94
- data/spec/support/certs/server.key +27 -27
- data/spec/support/crdt_search_fixtures.rb +1 -1
- data/spec/support/integration_setup.rb +10 -10
- data/spec/support/test_client.rb +1 -1
- data/spec/support/test_client.yml.example +10 -10
- metadata +10 -3
data/lib/riak/robject.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'forwardable'
|
2
2
|
require 'riak/rcontent'
|
3
3
|
require 'riak/conflict'
|
4
|
+
require 'riak/tombstone'
|
4
5
|
require 'riak/util/translation'
|
5
6
|
require 'riak/util/escape'
|
6
7
|
require 'riak/bucket'
|
@@ -141,6 +142,7 @@ module Riak
|
|
141
142
|
# @raise [Conflict] if the object has siblings
|
142
143
|
def store(options = {})
|
143
144
|
fail Conflict, self if conflict?
|
145
|
+
fail Tombstone, self if tombstone?
|
144
146
|
raise ArgumentError, t('content_type_undefined') unless content_type.present?
|
145
147
|
raise ArgumentError, t('zero_length_key') if key == ''
|
146
148
|
# NB: key can be nil to indicate that Riak should generate one
|
@@ -188,12 +190,26 @@ module Riak
|
|
188
190
|
# @raise [Conflict] when multiple siblings are present
|
189
191
|
def content
|
190
192
|
raise Conflict, self if conflict?
|
193
|
+
raise Tombstone, self if tombstone?
|
191
194
|
@siblings.first
|
192
195
|
end
|
193
196
|
|
194
197
|
# @return [true,false] Whether this object has conflicting sibling objects (divergent vclocks)
|
195
198
|
def conflict?
|
196
|
-
@siblings.size
|
199
|
+
@siblings.size > 1
|
200
|
+
end
|
201
|
+
|
202
|
+
# @return [true,false] Whether this object is a Riak tombstone (has no RContents, but contains a vclock)
|
203
|
+
def tombstone?
|
204
|
+
@siblings.empty? && !@vclock.nil?
|
205
|
+
end
|
206
|
+
|
207
|
+
# Will "revive" a tombstone object by giving it a new content.
|
208
|
+
# If the object is not a tombstone, will just return self.
|
209
|
+
# @return [Riak::RObject] self
|
210
|
+
def revive
|
211
|
+
@siblings = [ RContent.new(self) ] if tombstone?
|
212
|
+
self
|
197
213
|
end
|
198
214
|
|
199
215
|
# @return [String] A representation suitable for IRB and debugging output
|
@@ -92,6 +92,15 @@ module Riak::Search
|
|
92
92
|
return crdt if check_type_class Riak::Crdt::Set
|
93
93
|
end
|
94
94
|
|
95
|
+
# If the result document describes a set, return it.
|
96
|
+
#
|
97
|
+
# @return [Riak::Crdt::HyperLogLog]
|
98
|
+
# @raise [Riak::CrdtError::NotACrdt] if the result is not a CRDT
|
99
|
+
# @raise [Riak::CrdtError::UnexpectedDataType] if the CRDT is not a hyper_log_log
|
100
|
+
def hyper_log_log
|
101
|
+
return crdt if check_type_class Riak::Crdt::HyperLogLog
|
102
|
+
end
|
103
|
+
|
95
104
|
# Provides access to other parts of the result document without
|
96
105
|
# materializing them. Useful when querying non-default fields.
|
97
106
|
#
|
data/lib/riak/stamp.rb
CHANGED
@@ -1,77 +1,77 @@
|
|
1
|
-
require 'riak/client'
|
2
|
-
require 'riak/util/translation'
|
3
|
-
require 'thread'
|
4
|
-
|
5
|
-
module Riak
|
6
|
-
# Implements a client-side form of monotonically-increasing k-sorted
|
7
|
-
# unique identifiers. These are useful for key generation if your
|
8
|
-
# data is time-sequential and needs to be sorted by key, perhaps in
|
9
|
-
# Riak Search. Inspired by Twitter's Snowflake project.
|
10
|
-
class Stamp
|
11
|
-
attr_reader :client
|
12
|
-
|
13
|
-
CLIENT_ID_MASK = (1 << 10) - 1
|
14
|
-
SEQUENCE_MASK = (1 << 12) - 1
|
15
|
-
TIMESTAMP_MASK = (1 << 41) - 1
|
16
|
-
SEQUENCE_SHIFT = 10
|
17
|
-
TIMESTAMP_SHIFT = 22
|
18
|
-
|
19
|
-
# @param [Client] client a {Riak::Client} which will be used for
|
20
|
-
# the "worker ID" component of the stamp.
|
21
|
-
# @see Client#stamp
|
22
|
-
def initialize(client)
|
23
|
-
@client = client
|
24
|
-
@mutex = Mutex.new
|
25
|
-
@timestamp = time_gen
|
26
|
-
@sequence = 0
|
27
|
-
end
|
28
|
-
|
29
|
-
# Generates a k-sorted unique ID for use as a key or other
|
30
|
-
# disambiguation purposes.
|
31
|
-
def next
|
32
|
-
@mutex.synchronize do
|
33
|
-
now = time_gen
|
34
|
-
if @timestamp == now
|
35
|
-
@sequence = (@sequence + 1) & SEQUENCE_MASK
|
36
|
-
now = wait_for_next_ms(@timestamp) if @sequence == 0
|
37
|
-
else
|
38
|
-
@sequence = 0
|
39
|
-
end
|
40
|
-
|
41
|
-
raise BackwardsClockError.new(@timestamp - now) if now < @timestamp
|
42
|
-
|
43
|
-
@timestamp = now
|
44
|
-
@timestamp << TIMESTAMP_SHIFT | @sequence << SEQUENCE_SHIFT | client_id
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
private
|
49
|
-
def client_id
|
50
|
-
case id = @client.client_id
|
51
|
-
when Integer
|
52
|
-
id & CLIENT_ID_MASK
|
53
|
-
else
|
54
|
-
id.hash & CLIENT_ID_MASK
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def time_gen
|
59
|
-
(Time.now.to_f * 1000).floor & TIMESTAMP_MASK
|
60
|
-
end
|
61
|
-
|
62
|
-
def wait_for_next_ms(start)
|
63
|
-
now = time_gen
|
64
|
-
now = time_gen while now <= start
|
65
|
-
now
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
# Raised when calling {Stamp#next} and NTP or some other external
|
70
|
-
# event has moved the system clock backwards.
|
71
|
-
class BackwardsClockError < StandardError
|
72
|
-
include Util::Translation
|
73
|
-
def initialize(delay)
|
74
|
-
super t('backwards_clock', :delay => delay)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
1
|
+
require 'riak/client'
|
2
|
+
require 'riak/util/translation'
|
3
|
+
require 'thread'
|
4
|
+
|
5
|
+
module Riak
|
6
|
+
# Implements a client-side form of monotonically-increasing k-sorted
|
7
|
+
# unique identifiers. These are useful for key generation if your
|
8
|
+
# data is time-sequential and needs to be sorted by key, perhaps in
|
9
|
+
# Riak Search. Inspired by Twitter's Snowflake project.
|
10
|
+
class Stamp
|
11
|
+
attr_reader :client
|
12
|
+
|
13
|
+
CLIENT_ID_MASK = (1 << 10) - 1
|
14
|
+
SEQUENCE_MASK = (1 << 12) - 1
|
15
|
+
TIMESTAMP_MASK = (1 << 41) - 1
|
16
|
+
SEQUENCE_SHIFT = 10
|
17
|
+
TIMESTAMP_SHIFT = 22
|
18
|
+
|
19
|
+
# @param [Client] client a {Riak::Client} which will be used for
|
20
|
+
# the "worker ID" component of the stamp.
|
21
|
+
# @see Client#stamp
|
22
|
+
def initialize(client)
|
23
|
+
@client = client
|
24
|
+
@mutex = Mutex.new
|
25
|
+
@timestamp = time_gen
|
26
|
+
@sequence = 0
|
27
|
+
end
|
28
|
+
|
29
|
+
# Generates a k-sorted unique ID for use as a key or other
|
30
|
+
# disambiguation purposes.
|
31
|
+
def next
|
32
|
+
@mutex.synchronize do
|
33
|
+
now = time_gen
|
34
|
+
if @timestamp == now
|
35
|
+
@sequence = (@sequence + 1) & SEQUENCE_MASK
|
36
|
+
now = wait_for_next_ms(@timestamp) if @sequence == 0
|
37
|
+
else
|
38
|
+
@sequence = 0
|
39
|
+
end
|
40
|
+
|
41
|
+
raise BackwardsClockError.new(@timestamp - now) if now < @timestamp
|
42
|
+
|
43
|
+
@timestamp = now
|
44
|
+
@timestamp << TIMESTAMP_SHIFT | @sequence << SEQUENCE_SHIFT | client_id
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
def client_id
|
50
|
+
case id = @client.client_id
|
51
|
+
when Integer
|
52
|
+
id & CLIENT_ID_MASK
|
53
|
+
else
|
54
|
+
id.hash & CLIENT_ID_MASK
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def time_gen
|
59
|
+
(Time.now.to_f * 1000).floor & TIMESTAMP_MASK
|
60
|
+
end
|
61
|
+
|
62
|
+
def wait_for_next_ms(start)
|
63
|
+
now = time_gen
|
64
|
+
now = time_gen while now <= start
|
65
|
+
now
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Raised when calling {Stamp#next} and NTP or some other external
|
70
|
+
# event has moved the system clock backwards.
|
71
|
+
class BackwardsClockError < StandardError
|
72
|
+
include Util::Translation
|
73
|
+
def initialize(delay)
|
74
|
+
super t('backwards_clock', :delay => delay)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'riak/util/translation'
|
2
|
+
|
3
|
+
module Riak
|
4
|
+
# Raised when a tombstone object (i.e. has vclock, but no rcontent values) is
|
5
|
+
# stored or manipulated as if it had a single value.
|
6
|
+
class Tombstone < StandardError
|
7
|
+
include Util::Translation
|
8
|
+
|
9
|
+
def initialize(robject)
|
10
|
+
super t('tombstone_object', :robject => robject.inspect)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -1,58 +1,58 @@
|
|
1
|
-
require 'time'
|
2
|
-
require 'timeout'
|
3
|
-
require 'socket'
|
4
|
-
|
5
|
-
# Borrowed from Webrat and Selenium client, watches for TCP port
|
6
|
-
# liveness of the spawned server.
|
7
|
-
# @private
|
8
|
-
class TCPSocket
|
9
|
-
def self.wait_for_service(options)
|
10
|
-
verbose_wait until listening_service?(options)
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.wait_for_service_termination(options)
|
14
|
-
verbose_wait while listening_service?(options)
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.listening_service?(options)
|
18
|
-
Timeout::timeout(options[:timeout] || 20) do
|
19
|
-
begin
|
20
|
-
socket = TCPSocket.new(options[:host], options[:port])
|
21
|
-
socket.close unless socket.nil?
|
22
|
-
true
|
23
|
-
rescue Errno::ECONNREFUSED,
|
24
|
-
Errno::EBADF # Windows
|
25
|
-
false
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.verbose_wait
|
31
|
-
# Removed the puts call so as not to clutter up test output.
|
32
|
-
sleep 2
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.wait_for_service_with_timeout(options)
|
36
|
-
start_time = Time.now
|
37
|
-
|
38
|
-
until listening_service?(options)
|
39
|
-
verbose_wait
|
40
|
-
|
41
|
-
if options[:timeout] && (Time.now > start_time + options[:timeout])
|
42
|
-
raise SocketError.new("Socket did not open within #{options[:timeout]} seconds")
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def self.wait_for_service_termination_with_timeout(options)
|
48
|
-
start_time = Time.now
|
49
|
-
|
50
|
-
while listening_service?(options)
|
51
|
-
verbose_wait
|
52
|
-
|
53
|
-
if options[:timeout] && (Time.now > start_time + options[:timeout])
|
54
|
-
raise SocketError.new("Socket did not terminate within #{options[:timeout]} seconds")
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
1
|
+
require 'time'
|
2
|
+
require 'timeout'
|
3
|
+
require 'socket'
|
4
|
+
|
5
|
+
# Borrowed from Webrat and Selenium client, watches for TCP port
|
6
|
+
# liveness of the spawned server.
|
7
|
+
# @private
|
8
|
+
class TCPSocket
|
9
|
+
def self.wait_for_service(options)
|
10
|
+
verbose_wait until listening_service?(options)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.wait_for_service_termination(options)
|
14
|
+
verbose_wait while listening_service?(options)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.listening_service?(options)
|
18
|
+
Timeout::timeout(options[:timeout] || 20) do
|
19
|
+
begin
|
20
|
+
socket = TCPSocket.new(options[:host], options[:port])
|
21
|
+
socket.close unless socket.nil?
|
22
|
+
true
|
23
|
+
rescue Errno::ECONNREFUSED,
|
24
|
+
Errno::EBADF # Windows
|
25
|
+
false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.verbose_wait
|
31
|
+
# Removed the puts call so as not to clutter up test output.
|
32
|
+
sleep 2
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.wait_for_service_with_timeout(options)
|
36
|
+
start_time = Time.now
|
37
|
+
|
38
|
+
until listening_service?(options)
|
39
|
+
verbose_wait
|
40
|
+
|
41
|
+
if options[:timeout] && (Time.now > start_time + options[:timeout])
|
42
|
+
raise SocketError.new("Socket did not open within #{options[:timeout]} seconds")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.wait_for_service_termination_with_timeout(options)
|
48
|
+
start_time = Time.now
|
49
|
+
|
50
|
+
while listening_service?(options)
|
51
|
+
verbose_wait
|
52
|
+
|
53
|
+
if options[:timeout] && (Time.now > start_time + options[:timeout])
|
54
|
+
raise SocketError.new("Socket did not terminate within #{options[:timeout]} seconds")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/riak/version.rb
CHANGED
data/spec/failover/failover.rb
CHANGED
@@ -1,59 +1,59 @@
|
|
1
|
-
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../../lib')
|
2
|
-
require 'riak'
|
3
|
-
|
4
|
-
# This is not a formal spec yet. It's designed to be run agains a local dev
|
5
|
-
# cluster while you bring nodes up and down.
|
6
|
-
[
|
7
|
-
{:protocol => 'pbc', :protobuffs_backend => :Beefcake},
|
8
|
-
{:protocol => 'http', :http_backend => :NetHTTP},
|
9
|
-
{:protocol => 'http', :http_backend => :Excon}
|
10
|
-
].each do |opts|
|
11
|
-
@client = Riak::Client.new(
|
12
|
-
{
|
13
|
-
:nodes => (1..3).map { |i|
|
14
|
-
{
|
15
|
-
:http_port => 8090 + i,
|
16
|
-
:pb_port => 8080 + i
|
17
|
-
}
|
18
|
-
}
|
19
|
-
}.merge(opts)
|
20
|
-
)
|
21
|
-
|
22
|
-
errors = []
|
23
|
-
p opts
|
24
|
-
|
25
|
-
n = 10
|
26
|
-
c = 1000
|
27
|
-
|
28
|
-
(0...n).map do |t|
|
29
|
-
Thread.new do
|
30
|
-
# Generate a stream of put reqs. Put a . for each success, an X for
|
31
|
-
# each failure.
|
32
|
-
c.times do |i|
|
33
|
-
begin
|
34
|
-
o = @client['test'].new("#{t}:#{i}")
|
35
|
-
o.content_type = 'text/plain'
|
36
|
-
o.data = i.to_s
|
37
|
-
o.store
|
38
|
-
o2 = @client['test'].get("#{t}:#{i}")
|
39
|
-
o2.data == i.to_s or raise "wrong data"
|
40
|
-
print '.'
|
41
|
-
rescue => e
|
42
|
-
print 'X'
|
43
|
-
errors << e
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end.each do |thread|
|
48
|
-
thread.join
|
49
|
-
end
|
50
|
-
|
51
|
-
# Put errors
|
52
|
-
puts
|
53
|
-
errors.each do |e|
|
54
|
-
puts e.inspect
|
55
|
-
puts e.backtrace.map { |x| " #{x}" }.join("\n")
|
56
|
-
end
|
57
|
-
|
58
|
-
puts "\n\n"
|
59
|
-
end
|
1
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../../lib')
|
2
|
+
require 'riak'
|
3
|
+
|
4
|
+
# This is not a formal spec yet. It's designed to be run agains a local dev
|
5
|
+
# cluster while you bring nodes up and down.
|
6
|
+
[
|
7
|
+
{:protocol => 'pbc', :protobuffs_backend => :Beefcake},
|
8
|
+
{:protocol => 'http', :http_backend => :NetHTTP},
|
9
|
+
{:protocol => 'http', :http_backend => :Excon}
|
10
|
+
].each do |opts|
|
11
|
+
@client = Riak::Client.new(
|
12
|
+
{
|
13
|
+
:nodes => (1..3).map { |i|
|
14
|
+
{
|
15
|
+
:http_port => 8090 + i,
|
16
|
+
:pb_port => 8080 + i
|
17
|
+
}
|
18
|
+
}
|
19
|
+
}.merge(opts)
|
20
|
+
)
|
21
|
+
|
22
|
+
errors = []
|
23
|
+
p opts
|
24
|
+
|
25
|
+
n = 10
|
26
|
+
c = 1000
|
27
|
+
|
28
|
+
(0...n).map do |t|
|
29
|
+
Thread.new do
|
30
|
+
# Generate a stream of put reqs. Put a . for each success, an X for
|
31
|
+
# each failure.
|
32
|
+
c.times do |i|
|
33
|
+
begin
|
34
|
+
o = @client['test'].new("#{t}:#{i}")
|
35
|
+
o.content_type = 'text/plain'
|
36
|
+
o.data = i.to_s
|
37
|
+
o.store
|
38
|
+
o2 = @client['test'].get("#{t}:#{i}")
|
39
|
+
o2.data == i.to_s or raise "wrong data"
|
40
|
+
print '.'
|
41
|
+
rescue => e
|
42
|
+
print 'X'
|
43
|
+
errors << e
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end.each do |thread|
|
48
|
+
thread.join
|
49
|
+
end
|
50
|
+
|
51
|
+
# Put errors
|
52
|
+
puts
|
53
|
+
errors.each do |e|
|
54
|
+
puts e.inspect
|
55
|
+
puts e.backtrace.map { |x| " #{x}" }.join("\n")
|
56
|
+
end
|
57
|
+
|
58
|
+
puts "\n\n"
|
59
|
+
end
|