riak-client 1.2.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/Gemfile +1 -7
- data/README.markdown +66 -0
- data/RELEASE_NOTES.md +27 -0
- data/lib/riak/bucket.rb +24 -5
- data/lib/riak/client.rb +42 -7
- data/lib/riak/client/beefcake/message_codes.rb +56 -0
- data/lib/riak/client/beefcake/messages.rb +190 -18
- data/lib/riak/client/beefcake_protobuffs_backend.rb +143 -10
- data/lib/riak/client/feature_detection.rb +26 -1
- data/lib/riak/client/http_backend.rb +58 -9
- data/lib/riak/client/http_backend/bucket_streamer.rb +15 -0
- data/lib/riak/client/http_backend/chunked_json_streamer.rb +42 -0
- data/lib/riak/client/http_backend/configuration.rb +17 -1
- data/lib/riak/client/http_backend/key_streamer.rb +4 -32
- data/lib/riak/client/protobuffs_backend.rb +12 -34
- data/lib/riak/counter.rb +101 -0
- data/lib/riak/index_collection.rb +71 -0
- data/lib/riak/list_buckets.rb +28 -0
- data/lib/riak/locale/en.yml +14 -0
- data/lib/riak/multiget.rb +123 -0
- data/lib/riak/node.rb +2 -0
- data/lib/riak/node/configuration.rb +32 -21
- data/lib/riak/node/defaults.rb +2 -0
- data/lib/riak/node/generation.rb +19 -7
- data/lib/riak/node/version.rb +2 -16
- data/lib/riak/robject.rb +1 -0
- data/lib/riak/secondary_index.rb +67 -0
- data/lib/riak/version.rb +1 -1
- data/riak-client.gemspec +3 -2
- data/spec/integration/riak/counters_spec.rb +51 -0
- data/spec/integration/riak/http_backends_spec.rb +24 -14
- data/spec/integration/riak/node_spec.rb +6 -28
- data/spec/riak/beefcake_protobuffs_backend_spec.rb +84 -0
- data/spec/riak/bucket_spec.rb +55 -5
- data/spec/riak/client_spec.rb +34 -0
- data/spec/riak/counter_spec.rb +122 -0
- data/spec/riak/index_collection_spec.rb +50 -0
- data/spec/riak/list_buckets_spec.rb +41 -0
- data/spec/riak/multiget_spec.rb +76 -0
- data/spec/riak/robject_spec.rb +4 -1
- data/spec/riak/secondary_index_spec.rb +225 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/support/sometimes.rb +2 -2
- data/spec/support/unified_backend_examples.rb +4 -0
- metadata +41 -47
@@ -1,40 +1,12 @@
|
|
1
|
-
require 'riak/
|
2
|
-
require 'riak/json'
|
1
|
+
require 'riak/client/http_backend/chunked_json_streamer'
|
3
2
|
|
4
3
|
module Riak
|
5
4
|
class Client
|
6
5
|
class HTTPBackend
|
7
6
|
# @private
|
8
|
-
class KeyStreamer
|
9
|
-
|
10
|
-
|
11
|
-
def initialize(block)
|
12
|
-
@buffer = ""
|
13
|
-
@block = block
|
14
|
-
end
|
15
|
-
|
16
|
-
def accept(chunk)
|
17
|
-
@buffer << chunk
|
18
|
-
consume
|
19
|
-
end
|
20
|
-
|
21
|
-
def to_proc
|
22
|
-
method(:accept).to_proc
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
def consume
|
27
|
-
while @buffer =~ /\}\{/
|
28
|
-
stream($~.pre_match + '}')
|
29
|
-
@buffer = '{' + $~.post_match
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def stream(str)
|
34
|
-
obj = JSON.parse(str) rescue nil
|
35
|
-
if obj && obj['keys']
|
36
|
-
@block.call obj['keys'].map(&method(:maybe_unescape))
|
37
|
-
end
|
7
|
+
class KeyStreamer < ChunkedJsonStreamer
|
8
|
+
def get_values(obj)
|
9
|
+
obj['keys']
|
38
10
|
end
|
39
11
|
end
|
40
12
|
end
|
@@ -4,6 +4,7 @@ require 'base64'
|
|
4
4
|
require 'digest/sha1'
|
5
5
|
require 'riak/util/translation'
|
6
6
|
require 'riak/client/feature_detection'
|
7
|
+
require 'riak/client/beefcake/message_codes'
|
7
8
|
|
8
9
|
module Riak
|
9
10
|
class Client
|
@@ -12,38 +13,7 @@ module Riak
|
|
12
13
|
include Util::Escape
|
13
14
|
include FeatureDetection
|
14
15
|
|
15
|
-
|
16
|
-
MESSAGE_CODES = %W[
|
17
|
-
ErrorResp
|
18
|
-
PingReq
|
19
|
-
PingResp
|
20
|
-
GetClientIdReq
|
21
|
-
GetClientIdResp
|
22
|
-
SetClientIdReq
|
23
|
-
SetClientIdResp
|
24
|
-
GetServerInfoReq
|
25
|
-
GetServerInfoResp
|
26
|
-
GetReq
|
27
|
-
GetResp
|
28
|
-
PutReq
|
29
|
-
PutResp
|
30
|
-
DelReq
|
31
|
-
DelResp
|
32
|
-
ListBucketsReq
|
33
|
-
ListBucketsResp
|
34
|
-
ListKeysReq
|
35
|
-
ListKeysResp
|
36
|
-
GetBucketReq
|
37
|
-
GetBucketResp
|
38
|
-
SetBucketReq
|
39
|
-
SetBucketResp
|
40
|
-
MapRedReq
|
41
|
-
MapRedResp
|
42
|
-
IndexReq
|
43
|
-
IndexResp
|
44
|
-
SearchQueryReq
|
45
|
-
SearchQueryResp
|
46
|
-
].map {|s| s.intern }.freeze
|
16
|
+
MESSAGE_CODES = BeefcakeMessageCodes
|
47
17
|
|
48
18
|
def self.simple(method, code)
|
49
19
|
define_method method do
|
@@ -62,7 +32,6 @@ module Riak
|
|
62
32
|
simple :ping, :PingReq
|
63
33
|
simple :get_client_id, :GetClientIdReq
|
64
34
|
simple :server_info, :GetServerInfoReq
|
65
|
-
simple :list_buckets, :ListBucketsReq
|
66
35
|
|
67
36
|
# Performs a secondary-index query via emulation through MapReduce.
|
68
37
|
# @param [String, Bucket] bucket the bucket to query
|
@@ -144,6 +113,9 @@ module Riak
|
|
144
113
|
unless quorum_controls?
|
145
114
|
[:notfound_ok, :basic_quorum, :pr, :pw].each {|k| options.delete k }
|
146
115
|
end
|
116
|
+
unless key_object_bucket_timeouts?
|
117
|
+
options.delete :timeout
|
118
|
+
end
|
147
119
|
unless pb_head?
|
148
120
|
[:head, :return_head].each {|k| options.delete k }
|
149
121
|
end
|
@@ -160,7 +132,9 @@ module Riak
|
|
160
132
|
def normalize_quorums(options={})
|
161
133
|
options.dup.tap do |o|
|
162
134
|
[:r, :pr, :w, :pw, :dw, :rw].each do |k|
|
163
|
-
o[k] = normalize_quorum_value(o[k]) if o[k]
|
135
|
+
next o[k] = normalize_quorum_value(o[k]) if o[k]
|
136
|
+
s = k.to_s
|
137
|
+
o[k] = o[s] = denormalize_quorum_value(o[s]) if o[s]
|
164
138
|
end
|
165
139
|
end
|
166
140
|
end
|
@@ -168,6 +142,10 @@ module Riak
|
|
168
142
|
def normalize_quorum_value(q)
|
169
143
|
QUORUMS[q.to_s] || q.to_i
|
170
144
|
end
|
145
|
+
|
146
|
+
def denormalize_quorum_value(q)
|
147
|
+
QUORUMS.invert[q] || q.to_i
|
148
|
+
end
|
171
149
|
end
|
172
150
|
end
|
173
151
|
end
|
data/lib/riak/counter.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'riak/failed_request'
|
2
|
+
|
3
|
+
module Riak
|
4
|
+
|
5
|
+
# A distributed counter that supports incrementing by positive and negative
|
6
|
+
# integers.
|
7
|
+
class Counter
|
8
|
+
include Util::Translation
|
9
|
+
attr_accessor :bucket
|
10
|
+
attr_accessor :key
|
11
|
+
attr_accessor :client
|
12
|
+
|
13
|
+
# Create a Riak counter.
|
14
|
+
# @param [Bucket] bucket the {Riak::Bucket} for this counter
|
15
|
+
# @param [String] key the name of the counter
|
16
|
+
def initialize(bucket, key)
|
17
|
+
raise ArgumentError, t("bucket_type", bucket: bucket.inspect) unless bucket.is_a? Bucket
|
18
|
+
raise ArgumentError, t("string_type", string: key.inspect) unless key.is_a? String
|
19
|
+
@bucket, @key = bucket, key
|
20
|
+
@client = bucket.client
|
21
|
+
|
22
|
+
validate_bucket
|
23
|
+
end
|
24
|
+
|
25
|
+
# Retrieve the current value of the counter.
|
26
|
+
# @param [Hash] options
|
27
|
+
# @option options [Fixnum,String] :r ("quorum") read quorum (numeric or
|
28
|
+
# symbolic)
|
29
|
+
def value(options={})
|
30
|
+
backend do |backend|
|
31
|
+
backend.get_counter bucket, key, options
|
32
|
+
end
|
33
|
+
end
|
34
|
+
alias :to_i :value
|
35
|
+
|
36
|
+
# Increment the counter and return its new value.
|
37
|
+
# @param amount [Integer] the amount to increment the counter by.
|
38
|
+
def increment_and_return(amount=1)
|
39
|
+
increment amount, return_value: true
|
40
|
+
end
|
41
|
+
|
42
|
+
# Decrement the counter and return its new value.
|
43
|
+
# @param amount [Integer] the amount to decrement the counter by. Negative
|
44
|
+
# values increment the counter.
|
45
|
+
def decrement_and_return(amount=1)
|
46
|
+
increment_and_return -amount
|
47
|
+
end
|
48
|
+
|
49
|
+
# Increment the counter.
|
50
|
+
# @param amount [Integer] the amount to increment the counter by
|
51
|
+
# @param [Hash] options
|
52
|
+
# @option options [Boolean] :return_value whether to return the new counter
|
53
|
+
# value. Default false.
|
54
|
+
# @option options [Fixnum,String] :r ("quorum") read quorum (numeric or
|
55
|
+
# symbolic)
|
56
|
+
# @option options [Fixnum] :w the "w" parameter (Write quorum)
|
57
|
+
# @option options [Fixnum] :dw the "dw" parameter (Durable-write quorum)
|
58
|
+
def increment(amount=1, options={})
|
59
|
+
validate_amount amount
|
60
|
+
|
61
|
+
backend do |backend|
|
62
|
+
backend.post_counter bucket, key, amount, options
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Decrement the counter.
|
67
|
+
# @param amount [Integer] the amount to decrement the counter by. Negative
|
68
|
+
# values increment the counter.
|
69
|
+
# @param [Hash] options
|
70
|
+
# @option options [Boolean] :return_value whether to return the new counter
|
71
|
+
# value. Default false.
|
72
|
+
# @option options [Fixnum,String] :r ("quorum") read quorum (numeric or
|
73
|
+
# symbolic)
|
74
|
+
# @option options [Fixnum] :w the "w" parameter (Write quorum)
|
75
|
+
# @option options [Fixnum] :dw the "dw" parameter (Durable-write quorum)
|
76
|
+
def decrement(amount=1, options={})
|
77
|
+
increment(-amount, options)
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
def validate_bucket
|
82
|
+
raise ArgumentError, t("counter.bucket_needs_allow_mult") unless bucket.allow_mult
|
83
|
+
end
|
84
|
+
|
85
|
+
def validate_amount(amount)
|
86
|
+
raise ArgumentError, t("counter.increment_by_integer") unless amount.is_a? Integer
|
87
|
+
end
|
88
|
+
|
89
|
+
def backend(&blk)
|
90
|
+
begin
|
91
|
+
return client.backend &blk
|
92
|
+
rescue Riak::FailedRequest => e
|
93
|
+
raise QuorumError.new e if e.message =~ /unsatisfied/
|
94
|
+
raise e
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class QuorumError < Riak::FailedRequest
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Riak
|
2
|
+
|
3
|
+
# IndexCollection provides extra tools for managing index matches returned by
|
4
|
+
# a Secondary Index query. In Riak 1.4, these queries can be paginaged, and
|
5
|
+
# match keys up with the index values they matched against.
|
6
|
+
class IndexCollection < Array
|
7
|
+
|
8
|
+
# @return [String] The continuation used to retrieve the next page of a
|
9
|
+
# paginated query.
|
10
|
+
attr_accessor :continuation
|
11
|
+
|
12
|
+
# @return [Hash<Integer/String, String>] A hash of index keys (String or
|
13
|
+
# Integer, depending on whether the query was a binary or integer) to
|
14
|
+
# arrays of keys.
|
15
|
+
attr_accessor :with_terms
|
16
|
+
|
17
|
+
def self.new_from_json(json)
|
18
|
+
parsed = JSON.parse json
|
19
|
+
fresh = nil
|
20
|
+
if parsed['keys']
|
21
|
+
fresh = new parsed['keys']
|
22
|
+
elsif parsed['results']
|
23
|
+
fresh_terms = load_json_terms(parsed)
|
24
|
+
fresh = new fresh_terms.values.flatten
|
25
|
+
fresh.with_terms = fresh_terms
|
26
|
+
else
|
27
|
+
fresh = new []
|
28
|
+
end
|
29
|
+
fresh.continuation = parsed['continuation']
|
30
|
+
|
31
|
+
fresh
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.new_from_protobuf(message)
|
35
|
+
fresh = nil
|
36
|
+
if message.keys
|
37
|
+
fresh = new message.keys
|
38
|
+
elsif message.results
|
39
|
+
fresh_terms = load_pb_terms(message)
|
40
|
+
fresh = new fresh_terms.values.flatten
|
41
|
+
fresh.with_terms = fresh_terms
|
42
|
+
else
|
43
|
+
fresh = new
|
44
|
+
end
|
45
|
+
fresh.continuation = message.continuation
|
46
|
+
|
47
|
+
fresh
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
def self.load_json_terms(parsed)
|
52
|
+
fresh_terms = Hash.new{Array.new}
|
53
|
+
parsed['results'].each do |r|
|
54
|
+
k = r.keys.first
|
55
|
+
v = r[k]
|
56
|
+
fresh_terms[k] += [v]
|
57
|
+
end
|
58
|
+
|
59
|
+
fresh_terms
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.load_pb_terms(message)
|
63
|
+
fresh_terms = Hash.new{Array.new}
|
64
|
+
message.results.each do |r|
|
65
|
+
fresh_terms[r.key] += [r.value]
|
66
|
+
end
|
67
|
+
|
68
|
+
fresh_terms
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Riak
|
2
|
+
class ListBuckets
|
3
|
+
def initialize(client, options, block)
|
4
|
+
@client = client
|
5
|
+
@block = block
|
6
|
+
@options = options
|
7
|
+
perform_request
|
8
|
+
end
|
9
|
+
|
10
|
+
def perform_request
|
11
|
+
@client.backend do |be|
|
12
|
+
be.list_buckets @options, &wrapped_block
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def wrapped_block
|
19
|
+
proc do |bucket_names|
|
20
|
+
next if bucket_names.nil?
|
21
|
+
bucket_names.each do |bucket_name|
|
22
|
+
bucket = @client.bucket bucket_name
|
23
|
+
@block.call bucket
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/riak/locale/en.yml
CHANGED
@@ -2,9 +2,13 @@ en:
|
|
2
2
|
riak:
|
3
3
|
backwards_clock: "System clock moved backwards, ID generation will fail for %{delay} more milliseconds."
|
4
4
|
bucket_link_conversion: "Can't convert a bucket link to a walk spec"
|
5
|
+
bucket_type: "invalid argument %{bucket} is not a Riak::Bucket"
|
5
6
|
client_type: "invalid argument %{client} is not a Riak::Client"
|
6
7
|
conflict_resolver_invalid: "The given resolver (%{resolver}) did not respond to :call"
|
7
8
|
content_type_undefined: "content_type is not defined!"
|
9
|
+
counter:
|
10
|
+
bucket_needs_allow_mult: "Counters require allow_mult to be enabled on their bucket."
|
11
|
+
increment_by_integer: "Counters can only be incremented or decremented by integers."
|
8
12
|
deprecated:
|
9
13
|
port: "DEPRECATION: Riak::Client#port has been deprecated, use #http_port or #pb_port for the appropriate protocol.\n%{backtrace}"
|
10
14
|
search: "DEPRECATION: Riak Search features are included in the main client, you no longer need to require 'riak/search'.\n%{backtrace}"
|
@@ -18,10 +22,17 @@ en:
|
|
18
22
|
http_failed_request: "Expected %{expected} from Riak but received %{code}. %{body}"
|
19
23
|
hostname_invalid: "host must be a valid hostname"
|
20
24
|
protocol_invalid: "'%{invalid}' is not a valid protocol, valid values are %{valid}"
|
25
|
+
index:
|
26
|
+
no_next_page: "The returned search did not have a continuation available."
|
27
|
+
pagination_not_available: "The Riak server does not support secondary index pagination."
|
28
|
+
return_terms_not_available: "The Riak server does not support return_terms."
|
29
|
+
streaming_not_available: "The Riak server does not support streaming."
|
30
|
+
include_terms_is_wrong: "include_terms isn't a valid option; return_terms is."
|
21
31
|
invalid_basic_auth: "basic auth must be set using 'user:pass'"
|
22
32
|
invalid_client_id: "Invalid client ID, must be a string or between 0 and %{max_id}"
|
23
33
|
invalid_io_object: "Invalid IO-like object assigned to RObject#data. It should be assigned to raw_data instead."
|
24
34
|
invalid_function_value: "invalid value for function: %{value}"
|
35
|
+
invalid_multiget_thread_count: "Invalid multiget thread count, must be nil or a positive integer."
|
25
36
|
invalid_options: "Invalid configuration options given."
|
26
37
|
invalid_phase_type: "type must be :map, :reduce, or :link"
|
27
38
|
invalid_ssl_verify_mode: "%{invalid} is not a valid :verify_mode option for SSL. Valid options are 'peer' and 'none'."
|
@@ -48,7 +59,10 @@ en:
|
|
48
59
|
source_and_root_required: "Riak::Node configuration must include :source and :root keys."
|
49
60
|
stale_write_prevented: "Stale write prevented by client."
|
50
61
|
stored_function_invalid: "function must have :bucket and :key when a hash"
|
62
|
+
streaming_bucket_list_without_block: "Streaming bucket list was requested but no block was given."
|
51
63
|
string_type: "invalid_argument %{string} is not a String"
|
52
64
|
too_few_arguments: "too few arguments: %{params}"
|
53
65
|
walk_spec_invalid_unless_link: "WalkSpec is only valid for a function when the type is :link"
|
54
66
|
wrong_argument_count_walk_spec: "wrong number of arguments (one Hash or bucket,tag,keep required)"
|
67
|
+
zero_length_bucket: "bucket name cannot be a String of zero length"
|
68
|
+
zero_length_key: "key cannot be a String of zero length"
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'riak/client'
|
2
|
+
require 'riak/bucket'
|
3
|
+
require 'riak/cluster'
|
4
|
+
|
5
|
+
module Riak
|
6
|
+
# Coordinates a parallel fetch operation for multiple values.
|
7
|
+
class Multiget
|
8
|
+
include Util::Translation
|
9
|
+
|
10
|
+
# @return [Riak::Client] the associated client
|
11
|
+
attr_reader :client
|
12
|
+
|
13
|
+
# @return [Array<Bucket, String>] fetch_list an {Array} of {Bucket} and {String} keys to fetch
|
14
|
+
attr_reader :fetch_list
|
15
|
+
|
16
|
+
# @return [Hash<fetch_list_entry, RObject] result_hash a {Hash} of {Bucket} and {String} key pairs to {RObject} instances
|
17
|
+
attr_accessor :result_hash
|
18
|
+
|
19
|
+
# @return [Boolean] finished if the fetch operation has completed
|
20
|
+
attr_reader :finished
|
21
|
+
|
22
|
+
# @return [Integer] The number of threads to use
|
23
|
+
attr_accessor :thread_count
|
24
|
+
|
25
|
+
# Perform a Riak Multiget operation.
|
26
|
+
# @param [Client] client the {Riak::Client} that will perform the multiget
|
27
|
+
# @param [Array<Bucket, String>] fetch_list an {Array} of {Bucket} and {String} keys to fetch
|
28
|
+
# @return [Hash<fetch_list_entry, RObject] result_hash a {Hash} of {Bucket} and {String} key pairs to {Robject} instances
|
29
|
+
def self.get_all(client, fetch_list)
|
30
|
+
multi = new client, fetch_list
|
31
|
+
multi.fetch
|
32
|
+
multi.results
|
33
|
+
end
|
34
|
+
|
35
|
+
# Create a Riak Multiget operation.
|
36
|
+
# @param [Client] client the {Riak::Client} that will perform the multiget
|
37
|
+
# @param [Array<Bucket, String>] fetch_list an {Array} of {Bucket} and {String} keys to fetch
|
38
|
+
def initialize(client, fetch_list)
|
39
|
+
raise ArgumentError, t('client_type', :client => client.inspect) unless client.is_a? Riak::Client
|
40
|
+
raise ArgumentError, t('array_type', :array => fetch_list.inspect) unless fetch_list.is_a? Array
|
41
|
+
|
42
|
+
validate_fetch_list fetch_list
|
43
|
+
@client, @fetch_list = client, fetch_list.uniq
|
44
|
+
self.result_hash = Hash.new
|
45
|
+
@finished = false
|
46
|
+
self.thread_count = client.multiget_threads
|
47
|
+
end
|
48
|
+
|
49
|
+
# Starts the parallelized fetch operation
|
50
|
+
# @raise [ArgumentError] when a non-positive-Integer count is given
|
51
|
+
def fetch
|
52
|
+
queue = fetch_list.dup
|
53
|
+
queue_mutex = Mutex.new
|
54
|
+
result_mutex = Mutex.new
|
55
|
+
|
56
|
+
unless thread_count.is_a?(Integer) && thread_count > 0
|
57
|
+
raise ArgumentError, t("invalid_multiget_thread_count")
|
58
|
+
end
|
59
|
+
|
60
|
+
@threads = 1.upto(thread_count).map do |_node|
|
61
|
+
Thread.new do
|
62
|
+
loop do
|
63
|
+
pair = queue_mutex.synchronize do
|
64
|
+
queue.shift
|
65
|
+
end
|
66
|
+
|
67
|
+
break if pair.nil?
|
68
|
+
|
69
|
+
found = attempt_fetch(*pair)
|
70
|
+
result_mutex.synchronize do
|
71
|
+
result_hash[pair] = found
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def results
|
79
|
+
wait_for_finish
|
80
|
+
result_hash
|
81
|
+
end
|
82
|
+
|
83
|
+
def finished?
|
84
|
+
set_finished_for_thread_liveness
|
85
|
+
finished
|
86
|
+
end
|
87
|
+
|
88
|
+
def wait_for_finish
|
89
|
+
return if finished?
|
90
|
+
@threads.each {|t| t.join }
|
91
|
+
@finished = true
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def attempt_fetch(bucket, key)
|
97
|
+
bucket[key]
|
98
|
+
rescue Riak::FailedRequest => e
|
99
|
+
raise e unless e.not_found?
|
100
|
+
nil
|
101
|
+
end
|
102
|
+
|
103
|
+
def set_finished_for_thread_liveness
|
104
|
+
return if @finished # already done
|
105
|
+
|
106
|
+
all_dead = @threads.none? {|t| t.alive? }
|
107
|
+
return unless all_dead # still working
|
108
|
+
|
109
|
+
@finished = true
|
110
|
+
return
|
111
|
+
end
|
112
|
+
|
113
|
+
def validate_fetch_list(fetch_list)
|
114
|
+
return unless erroneous = fetch_list.detect do |e|
|
115
|
+
bucket, key = e
|
116
|
+
next true unless bucket.is_a? Bucket
|
117
|
+
next true unless key.is_a? String
|
118
|
+
end
|
119
|
+
|
120
|
+
raise ArgumentError, t('fetch_list_type', :problem => erroneous)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|