riak-client-noenc 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (200) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.gitignore +42 -0
  4. data/.rspec +1 -0
  5. data/Gemfile +17 -0
  6. data/Guardfile +20 -0
  7. data/LICENSE.md +16 -0
  8. data/README.markdown +640 -0
  9. data/RELEASE_NOTES.md +392 -0
  10. data/Rakefile +119 -0
  11. data/lib/riak.rb +22 -0
  12. data/lib/riak/bucket.rb +297 -0
  13. data/lib/riak/bucket_properties.rb +74 -0
  14. data/lib/riak/bucket_type.rb +77 -0
  15. data/lib/riak/bucket_typed/bucket.rb +121 -0
  16. data/lib/riak/client.rb +433 -0
  17. data/lib/riak/client/beefcake/bucket_properties_operator.rb +178 -0
  18. data/lib/riak/client/beefcake/crdt/counter_loader.rb +18 -0
  19. data/lib/riak/client/beefcake/crdt/map_loader.rb +64 -0
  20. data/lib/riak/client/beefcake/crdt/set_loader.rb +18 -0
  21. data/lib/riak/client/beefcake/crdt_loader.rb +84 -0
  22. data/lib/riak/client/beefcake/crdt_operator.rb +223 -0
  23. data/lib/riak/client/beefcake/footer +4 -0
  24. data/lib/riak/client/beefcake/header +6 -0
  25. data/lib/riak/client/beefcake/message_codes.rb +89 -0
  26. data/lib/riak/client/beefcake/message_overlay.rb +87 -0
  27. data/lib/riak/client/beefcake/messages.rb +772 -0
  28. data/lib/riak/client/beefcake/object_methods.rb +112 -0
  29. data/lib/riak/client/beefcake/protocol.rb +105 -0
  30. data/lib/riak/client/beefcake/socket.rb +260 -0
  31. data/lib/riak/client/beefcake_protobuffs_backend.rb +538 -0
  32. data/lib/riak/client/decaying.rb +36 -0
  33. data/lib/riak/client/feature_detection.rb +120 -0
  34. data/lib/riak/client/instrumentation.rb +19 -0
  35. data/lib/riak/client/node.rb +49 -0
  36. data/lib/riak/client/protobuffs_backend.rb +143 -0
  37. data/lib/riak/client/search.rb +27 -0
  38. data/lib/riak/client/yokozuna.rb +52 -0
  39. data/lib/riak/conflict.rb +13 -0
  40. data/lib/riak/core_ext.rb +7 -0
  41. data/lib/riak/core_ext/blank.rb +53 -0
  42. data/lib/riak/core_ext/deep_dup.rb +13 -0
  43. data/lib/riak/core_ext/extract_options.rb +7 -0
  44. data/lib/riak/core_ext/json.rb +15 -0
  45. data/lib/riak/core_ext/slice.rb +18 -0
  46. data/lib/riak/core_ext/stringify_keys.rb +10 -0
  47. data/lib/riak/core_ext/symbolize_keys.rb +10 -0
  48. data/lib/riak/core_ext/to_param.rb +31 -0
  49. data/lib/riak/counter.rb +101 -0
  50. data/lib/riak/crdt.rb +21 -0
  51. data/lib/riak/crdt/base.rb +183 -0
  52. data/lib/riak/crdt/batch_counter.rb +19 -0
  53. data/lib/riak/crdt/batch_map.rb +41 -0
  54. data/lib/riak/crdt/counter.rb +82 -0
  55. data/lib/riak/crdt/inner_counter.rb +81 -0
  56. data/lib/riak/crdt/inner_flag.rb +42 -0
  57. data/lib/riak/crdt/inner_map.rb +75 -0
  58. data/lib/riak/crdt/inner_register.rb +26 -0
  59. data/lib/riak/crdt/inner_set.rb +102 -0
  60. data/lib/riak/crdt/map.rb +121 -0
  61. data/lib/riak/crdt/operation.rb +19 -0
  62. data/lib/riak/crdt/set.rb +166 -0
  63. data/lib/riak/crdt/typed_collection.rb +181 -0
  64. data/lib/riak/encoding.rb +6 -0
  65. data/lib/riak/errors/backend_creation.rb +9 -0
  66. data/lib/riak/errors/base.rb +9 -0
  67. data/lib/riak/errors/connection_error.rb +50 -0
  68. data/lib/riak/errors/crdt_error.rb +38 -0
  69. data/lib/riak/errors/failed_request.rb +58 -0
  70. data/lib/riak/errors/protobuffs_error.rb +11 -0
  71. data/lib/riak/errors/search_error.rb +35 -0
  72. data/lib/riak/i18n.rb +7 -0
  73. data/lib/riak/index_collection.rb +71 -0
  74. data/lib/riak/instrumentation.rb +6 -0
  75. data/lib/riak/json.rb +52 -0
  76. data/lib/riak/link.rb +96 -0
  77. data/lib/riak/list_buckets.rb +28 -0
  78. data/lib/riak/locale/en.yml +107 -0
  79. data/lib/riak/locale/fr.yml +51 -0
  80. data/lib/riak/map_reduce.rb +295 -0
  81. data/lib/riak/map_reduce/filter_builder.rb +103 -0
  82. data/lib/riak/map_reduce/phase.rb +98 -0
  83. data/lib/riak/map_reduce/results.rb +49 -0
  84. data/lib/riak/map_reduce_error.rb +7 -0
  85. data/lib/riak/multiget.rb +122 -0
  86. data/lib/riak/preflist_item.rb +7 -0
  87. data/lib/riak/rcontent.rb +173 -0
  88. data/lib/riak/robject.rb +222 -0
  89. data/lib/riak/search.rb +11 -0
  90. data/lib/riak/search/index.rb +87 -0
  91. data/lib/riak/search/query.rb +141 -0
  92. data/lib/riak/search/result_collection.rb +144 -0
  93. data/lib/riak/search/result_document.rb +129 -0
  94. data/lib/riak/search/schema.rb +65 -0
  95. data/lib/riak/secondary_index.rb +81 -0
  96. data/lib/riak/serializers.rb +73 -0
  97. data/lib/riak/stamp.rb +77 -0
  98. data/lib/riak/util/escape.rb +80 -0
  99. data/lib/riak/util/tcp_socket_extensions.rb +58 -0
  100. data/lib/riak/util/translation.rb +18 -0
  101. data/lib/riak/version.rb +3 -0
  102. data/lib/riak/walk_spec.rb +145 -0
  103. data/spec/failover/failover.rb +59 -0
  104. data/spec/fixtures/bitcask.txt +25 -0
  105. data/spec/fixtures/cat.jpg +0 -0
  106. data/spec/fixtures/multipart-basic-conflict.txt +15 -0
  107. data/spec/fixtures/multipart-blank.txt +7 -0
  108. data/spec/fixtures/multipart-mapreduce.txt +10 -0
  109. data/spec/fixtures/multipart-with-body.txt +16 -0
  110. data/spec/fixtures/multipart-with-marked-tombstones.txt +17 -0
  111. data/spec/fixtures/multipart-with-unmarked-tombstone.txt +16 -0
  112. data/spec/fixtures/server.cert.crt +15 -0
  113. data/spec/fixtures/server.cert.key +15 -0
  114. data/spec/fixtures/test.pem +1 -0
  115. data/spec/fixtures/yz_schema_template.xml +18 -0
  116. data/spec/integration/riak/bucket_types_spec.rb +270 -0
  117. data/spec/integration/riak/conflict_resolution_spec.rb +96 -0
  118. data/spec/integration/riak/counters_spec.rb +36 -0
  119. data/spec/integration/riak/crdt/configuration_spec.rb +37 -0
  120. data/spec/integration/riak/crdt_search_spec.rb +176 -0
  121. data/spec/integration/riak/crdt_spec.rb +250 -0
  122. data/spec/integration/riak/crdt_validation/map_spec.rb +63 -0
  123. data/spec/integration/riak/crdt_validation/set_spec.rb +122 -0
  124. data/spec/integration/riak/preflist_spec.rb +31 -0
  125. data/spec/integration/riak/properties_spec.rb +69 -0
  126. data/spec/integration/riak/protobuffs/interrupted_request_spec.rb +33 -0
  127. data/spec/integration/riak/protobuffs_backends_spec.rb +40 -0
  128. data/spec/integration/riak/search_spec.rb +104 -0
  129. data/spec/integration/riak/secondary_index_spec.rb +72 -0
  130. data/spec/integration/riak/security_spec.rb +100 -0
  131. data/spec/integration/riak/threading_spec.rb +150 -0
  132. data/spec/integration/yokozuna/index_spec.rb +61 -0
  133. data/spec/integration/yokozuna/queries_spec.rb +115 -0
  134. data/spec/integration/yokozuna/schema_spec.rb +49 -0
  135. data/spec/riak/beefcake_protobuffs_backend/bucket_properties_operator_spec.rb +247 -0
  136. data/spec/riak/beefcake_protobuffs_backend/crdt_operator_spec.rb +222 -0
  137. data/spec/riak/beefcake_protobuffs_backend/object_methods_spec.rb +23 -0
  138. data/spec/riak/beefcake_protobuffs_backend/protocol_spec.rb +189 -0
  139. data/spec/riak/beefcake_protobuffs_backend_spec.rb +162 -0
  140. data/spec/riak/bucket_properties_spec.rb +135 -0
  141. data/spec/riak/bucket_spec.rb +275 -0
  142. data/spec/riak/bucket_type_spec.rb +50 -0
  143. data/spec/riak/bucket_typed/bucket_spec.rb +62 -0
  144. data/spec/riak/client_spec.rb +246 -0
  145. data/spec/riak/core_ext/to_param_spec.rb +15 -0
  146. data/spec/riak/counter_spec.rb +122 -0
  147. data/spec/riak/crdt/counter_spec.rb +55 -0
  148. data/spec/riak/crdt/inner_counter_spec.rb +21 -0
  149. data/spec/riak/crdt/inner_flag_spec.rb +39 -0
  150. data/spec/riak/crdt/inner_map_spec.rb +47 -0
  151. data/spec/riak/crdt/inner_register_spec.rb +40 -0
  152. data/spec/riak/crdt/inner_set_spec.rb +33 -0
  153. data/spec/riak/crdt/map_spec.rb +78 -0
  154. data/spec/riak/crdt/set_spec.rb +61 -0
  155. data/spec/riak/crdt/shared_examples.rb +74 -0
  156. data/spec/riak/crdt/typed_collection_spec.rb +225 -0
  157. data/spec/riak/escape_spec.rb +72 -0
  158. data/spec/riak/feature_detection_spec.rb +77 -0
  159. data/spec/riak/index_collection_spec.rb +53 -0
  160. data/spec/riak/instrumentation_spec.rb +124 -0
  161. data/spec/riak/link_spec.rb +85 -0
  162. data/spec/riak/list_buckets_spec.rb +41 -0
  163. data/spec/riak/map_reduce/filter_builder_spec.rb +32 -0
  164. data/spec/riak/map_reduce/phase_spec.rb +142 -0
  165. data/spec/riak/map_reduce_spec.rb +434 -0
  166. data/spec/riak/multiget_spec.rb +81 -0
  167. data/spec/riak/node_spec.rb +26 -0
  168. data/spec/riak/robject_spec.rb +496 -0
  169. data/spec/riak/search/index_spec.rb +72 -0
  170. data/spec/riak/search/query_spec.rb +88 -0
  171. data/spec/riak/search/result_collection_spec.rb +89 -0
  172. data/spec/riak/search/result_document_spec.rb +106 -0
  173. data/spec/riak/search/schema_spec.rb +63 -0
  174. data/spec/riak/search_spec.rb +107 -0
  175. data/spec/riak/secondary_index_spec.rb +225 -0
  176. data/spec/riak/serializers_spec.rb +121 -0
  177. data/spec/riak/stamp_spec.rb +54 -0
  178. data/spec/riak/walk_spec_spec.rb +203 -0
  179. data/spec/spec_helper.rb +66 -0
  180. data/spec/support/certs/README.md +13 -0
  181. data/spec/support/certs/ca.crt +21 -0
  182. data/spec/support/certs/client.crl +13 -0
  183. data/spec/support/certs/client.crt +94 -0
  184. data/spec/support/certs/client.csr +18 -0
  185. data/spec/support/certs/client.key +27 -0
  186. data/spec/support/certs/empty_ca.crt +21 -0
  187. data/spec/support/certs/server.crl +13 -0
  188. data/spec/support/certs/server.crt +94 -0
  189. data/spec/support/certs/server.key +27 -0
  190. data/spec/support/crdt_search_config.rb +112 -0
  191. data/spec/support/crdt_search_fixtures.rb +42 -0
  192. data/spec/support/integration_setup.rb +10 -0
  193. data/spec/support/search_config.rb +83 -0
  194. data/spec/support/search_corpus_setup.rb +39 -0
  195. data/spec/support/test_client.rb +46 -0
  196. data/spec/support/test_client.yml.example +10 -0
  197. data/spec/support/unified_backend_examples.rb +380 -0
  198. data/spec/support/version_filter.rb +12 -0
  199. data/spec/support/wait_until.rb +20 -0
  200. metadata +511 -0
@@ -0,0 +1,121 @@
1
+ require 'riak/bucket'
2
+ require 'riak/bucket_type'
3
+
4
+ module Riak
5
+
6
+ # Container module for subclasses of objects with bucket type data attached.
7
+ # Currently only used for {BucketTyped::Bucket}.
8
+ module BucketTyped
9
+
10
+ # A bucket that has a {BucketType} attached to it. Normally created using
11
+ # the {BucketType#bucket} method. Inherits most of its behavior from the
12
+ # {Riak::Bucket} class.
13
+ class Bucket < Riak::Bucket
14
+
15
+ # @return [BucketType] the bucket type used with this bucket
16
+ attr_reader :type
17
+
18
+ # Create a bucket-typed bucket manually.
19
+ # @param [Client] client the {Riak::Client} for this bucket
20
+ # @param [String] name the name of this bucket
21
+ # @param [BucketType,String] type the bucket type of this bucket
22
+ def initialize(client, name, type)
23
+ if type.is_a? String
24
+ type = client.bucket_type type
25
+ elsif !(type.is_a? BucketType)
26
+ raise ArgumentError, t('argument_error.bucket_type', bucket_type: type)
27
+ end
28
+
29
+ @type = type
30
+
31
+ super client, name
32
+ end
33
+
34
+ # Retrieve an object from within the bucket type and bucket.
35
+ # @param [String] key the key of the object to retrieve
36
+ # @param [Hash] options query parameters for the request
37
+ # @option options [Fixnum] :r - the read quorum for the request - how many nodes should concur on the read
38
+ # @return [Riak::RObject] the object
39
+ # @raise [FailedRequest] if the object is not found or some other error occurs
40
+ def get(key, options = { })
41
+ object = super key, o(options)
42
+ object.bucket = self
43
+ return object
44
+ end
45
+ alias :[] :get
46
+
47
+ # Deletes a key from the bucket
48
+ # @param [String] key the key to delete
49
+ # @param [Hash] options quorum options
50
+ # @option options [Fixnum] :rw - the read/write quorum for the
51
+ # delete
52
+ # @option options [String] :vclock - the vector clock of the
53
+ # object being deleted
54
+ def delete(key, options = { })
55
+ super key, o(options)
56
+ end
57
+
58
+ # Retrieves a list of keys in this bucket.
59
+ # If a block is given, keys will be streamed through
60
+ # the block (useful for large buckets). When streaming,
61
+ # results of the operation will not be returned to the caller.
62
+ # @yield [Array<String>] a list of keys from the current chunk
63
+ # @return [Array<String>] Keys in this bucket
64
+ # @note This operation has serious performance implications and
65
+ # should not be used in production applications.
66
+ def keys(options = { }, &block)
67
+ super o(options), &block
68
+ end
69
+
70
+ # @return [String] a friendly representation of this bucket-typed bucket
71
+ def inspect
72
+ "#<Riak::BucketTyped::Bucket {#{ type.name }/#{ name }}>"
73
+ end
74
+
75
+ def props=(new_props)
76
+ raise ArgumentError, t('hash_type', hash: new_props.inspect) unless new_props.is_a? Hash
77
+ complete_props = props.merge new_props
78
+ @client.set_bucket_props(self, complete_props, self.type.name)
79
+ end
80
+
81
+ def props
82
+ @props ||= @client.get_bucket_props(self, type: self.type.name)
83
+ end
84
+
85
+ def clear_props
86
+ @props = nil
87
+ @client.clear_bucket_props(self, type: self.type.name)
88
+ end
89
+
90
+ # Pretty prints the bucket for `pp` or `pry`.
91
+ def pretty_print(pp)
92
+ pp.object_group self do
93
+ pp.breakable
94
+ pp.text "bucket_type="
95
+ type.pretty_print(pp)
96
+ pp.breakable
97
+ pp.text "name=#{name}"
98
+ end
99
+ end
100
+
101
+ # Does this {BucketTyped::Bucket} have a non-default bucket type?
102
+ # @return [Boolean] true if this bucket has a non-default type.
103
+ def needs_type?
104
+ return true unless type.default?
105
+ return false
106
+ end
107
+
108
+ def ==(other)
109
+ return false unless self.class == other.class
110
+ return false unless self.type == other.type
111
+ super
112
+ end
113
+
114
+ private
115
+ # merge in the type name with options
116
+ def o(options)
117
+ { type: type.name }.merge options
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,433 @@
1
+ require 'tempfile'
2
+ require 'delegate'
3
+ require 'innertube'
4
+ require 'riak'
5
+ require 'riak/util/translation'
6
+ require 'riak/util/escape'
7
+ require 'riak/errors/failed_request'
8
+ require 'riak/errors/protobuffs_error'
9
+ require 'riak/errors/backend_creation'
10
+ require 'riak/client/decaying'
11
+ require 'riak/client/node'
12
+ require 'riak/client/search'
13
+ require 'riak/client/yokozuna'
14
+ require 'riak/client/protobuffs_backend'
15
+ require 'riak/preflist_item'
16
+ require 'riak/client/beefcake_protobuffs_backend'
17
+ require 'riak/bucket'
18
+ require 'riak/bucket_properties'
19
+ require 'riak/bucket_type'
20
+ require 'riak/multiget'
21
+ require 'riak/secondary_index'
22
+ require 'riak/search'
23
+ require 'riak/stamp'
24
+ require 'riak/list_buckets'
25
+
26
+ module Riak
27
+ # A client connection to Riak.
28
+ class Client
29
+ include Util::Translation
30
+ include Util::Escape
31
+
32
+ # When using integer client IDs, the exclusive upper-bound of valid values.
33
+ MAX_CLIENT_ID = 4294967296
34
+
35
+ # Regexp for validating hostnames, lifted from uri.rb in Ruby 1.8.6
36
+ HOST_REGEX = /^(?:(?:(?:[a-zA-Z\d](?:[-a-zA-Z\d]*[a-zA-Z\d])?)\.)*(?:[a-zA-Z](?:[-a-zA-Z\d]*[a-zA-Z\d])?)\.?|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|\[(?:(?:[a-fA-F\d]{1,4}:)*(?:[a-fA-F\d]{1,4}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|(?:(?:[a-fA-F\d]{1,4}:)*[a-fA-F\d]{1,4})?::(?:(?:[a-fA-F\d]{1,4}:)*(?:[a-fA-F\d]{1,4}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}))?)\])$/n
37
+
38
+ # Valid constructor options.
39
+ VALID_OPTIONS = [:nodes, :client_id, :protobuffs_backend, :authentication] | Node::VALID_OPTIONS
40
+
41
+ # Network errors.
42
+ NETWORK_ERRORS = [
43
+ EOFError,
44
+ Errno::ECONNABORTED,
45
+ Errno::ECONNREFUSED,
46
+ Errno::ECONNRESET,
47
+ Errno::ENETDOWN,
48
+ Errno::ENETRESET,
49
+ Errno::ENETUNREACH,
50
+ SocketError,
51
+ SystemCallError,
52
+ Riak::ProtobuffsFailedHeader,
53
+ ]
54
+
55
+ Pool = ::Innertube::Pool
56
+
57
+ # @return [Array] The set of Nodes this client can communicate with.
58
+ attr_accessor :nodes
59
+
60
+ # @return [String] The internal client ID used by Riak to route responses
61
+ attr_reader :client_id
62
+
63
+ # @return [Symbol] The Protocol Buffers backend/client to use
64
+ attr_accessor :protobuffs_backend
65
+
66
+ # @return [Client::Pool] A pool of protobuffs connections
67
+ attr_reader :protobuffs_pool
68
+
69
+ # @return [Integer] The number of threads for multiget requests
70
+ attr_reader :multiget_threads
71
+
72
+ # @return [Hash] The authentication information this client will use.
73
+ attr_reader :authentication
74
+
75
+ # Creates a client connection to Riak
76
+ # @param [Hash] options configuration options for the client
77
+ # @option options [Array] :nodes A list of nodes this client connects to.
78
+ # Each element of the list is a hash which is passed to Node.new, e.g.
79
+ # `{host: '127.0.0.1', pb_port: 1234, ...}`.
80
+ # If no nodes are given, a single node is constructed from the remaining
81
+ # options given to Client.new.
82
+ # @option options [String] :host ('127.0.0.1') The host or IP address for the Riak endpoint
83
+ # @option options [Fixnum] :pb_port (8087) The port of the Riak Protocol Buffers endpoint
84
+ # @option options [Fixnum, String] :client_id (rand(MAX_CLIENT_ID)) The internal client ID used by Riak to route responses
85
+ # @option options [String, Symbol] :protobuffs_backend (:Beefcake) which Protocol Buffers backend to use
86
+ # @raise [ArgumentError] raised if any invalid options are given
87
+ def initialize(options = {})
88
+ if options.include? :port
89
+ warn(t('deprecated.port', :backtrace => caller[0..2].join("\n ")))
90
+ end
91
+
92
+ unless (evil = options.keys - VALID_OPTIONS).empty?
93
+ raise ArgumentError, "#{evil.inspect} are not valid options for Client.new"
94
+ end
95
+
96
+ @nodes = (options[:nodes] || []).map do |n|
97
+ Client::Node.new self, n
98
+ end
99
+ if @nodes.empty? or options[:host] or options[:pb_port]
100
+ @nodes |= [Client::Node.new(self, options)]
101
+ end
102
+
103
+ @protobuffs_pool = Pool.new(
104
+ method(:new_protobuffs_backend),
105
+ lambda { |b| b.teardown }
106
+ )
107
+
108
+
109
+ self.protobuffs_backend = options[:protobuffs_backend] || :Beefcake
110
+ self.client_id = options[:client_id] if options[:client_id]
111
+ self.multiget_threads = options[:multiget_threads]
112
+ @authentication = options[:authentication] && options[:authentication].symbolize_keys
113
+ end
114
+
115
+ # Is security enabled?
116
+ # @return [Boolean] whether or not a secure connection is being used
117
+ def security?
118
+ !!authentication
119
+ end
120
+
121
+ # Retrieves a bucket from Riak.
122
+ # @param [String] name the bucket to retrieve
123
+ # @param [Hash] options options for retrieving the bucket
124
+ # @option options [Boolean] :props (false) whether to retreive the bucket properties
125
+ # @return [Bucket] the requested bucket
126
+ def bucket(name, options = {})
127
+ raise ArgumentError, t('zero_length_bucket') if name == ''
128
+ unless (options.keys - [:props]).empty?
129
+ raise ArgumentError, "invalid options"
130
+ end
131
+ @bucket_cache ||= {}
132
+ (@bucket_cache[name] ||= Bucket.new(self, name)).tap do |b|
133
+ b.props if options[:props]
134
+ end
135
+ end
136
+ alias :[] :bucket
137
+
138
+ def bucket_type(name)
139
+ BucketType.new self, name
140
+ end
141
+
142
+ # Lists buckets which have keys stored in them.
143
+ # @note This is an expensive operation and should be used only
144
+ # in development.
145
+ # @return [Array<Bucket>] a list of buckets
146
+ def buckets(options = {}, &block)
147
+ warn(t('list_buckets', :backtrace => caller.join("\n "))) unless Riak.disable_list_keys_warnings
148
+
149
+ return ListBuckets.new self, options, block if block_given?
150
+
151
+ backend do |b|
152
+ b.list_buckets(options).map {|name| Bucket.new(self, name) }
153
+ end
154
+ end
155
+ alias :list_buckets :buckets
156
+
157
+ # Choose a node from a set.
158
+ def choose_node(nodes = self.nodes)
159
+ # Prefer nodes which have gone a reasonable time without errors.
160
+ s = nodes.select do |node|
161
+ node.error_rate.value < 0.1
162
+ end
163
+
164
+ if s.empty?
165
+ # Fall back to minimally broken node.
166
+ nodes.min_by do |node|
167
+ node.error_rate.value
168
+ end
169
+ else
170
+ s[rand(s.size)]
171
+ end
172
+ end
173
+
174
+ # Set the number of threads to use for multiget operations.
175
+ # If set to nil, defaults to twice the number of nodes.
176
+ # @param [Integer] count The number of threads to use.
177
+ # @raise [ArgumentError] when a non-nil, non-positive-Integer count is given
178
+ def multiget_threads=(count)
179
+ if count.nil?
180
+ @multiget_threads = nodes.length * 2
181
+ return
182
+ end
183
+
184
+ if count.is_a?(Integer) && count > 0
185
+ @multiget_threads = count
186
+ return
187
+ end
188
+
189
+ raise ArgumentError, t("invalid_multiget_thread_count")
190
+ end
191
+
192
+ # Set the client ID for this client. Must be a string or Fixnum value 0 =<
193
+ # value < MAX_CLIENT_ID.
194
+ # @param [String, Fixnum] value The internal client ID used by Riak to route responses
195
+ # @raise [ArgumentError] when an invalid client ID is given
196
+ # @return [String] the assigned client ID
197
+ def client_id=(value)
198
+ value = case value
199
+ when 0...MAX_CLIENT_ID, String
200
+ value
201
+ else
202
+ raise ArgumentError, t("invalid_client_id", :max_id => MAX_CLIENT_ID)
203
+ end
204
+
205
+ # Change all existing backend client IDs.
206
+ @protobuffs_pool.each do |pb|
207
+ pb.set_client_id value if pb.respond_to?(:set_client_id)
208
+ end
209
+ @client_id = value
210
+ end
211
+
212
+ def client_id
213
+ @client_id ||= backend do |b|
214
+ if b.respond_to?(:get_client_id)
215
+ b.get_client_id
216
+ else
217
+ make_client_id
218
+ end
219
+ end
220
+ end
221
+
222
+ # Delete an object. See Bucket#delete
223
+ def delete_object(bucket, key, options = {})
224
+ backend do |b|
225
+ b.delete_object(bucket, key, options)
226
+ end
227
+ end
228
+
229
+ # Bucket properties. See Bucket#props
230
+ def get_bucket_props(bucket, options = { })
231
+ backend do |b|
232
+ b.get_bucket_props bucket, options
233
+ end
234
+ end
235
+
236
+ # Queries a secondary index on a bucket. See Bucket#get_index
237
+ def get_index(bucket, index, query, options = {})
238
+ backend do |b|
239
+ b.get_index bucket, index, query, options
240
+ end
241
+ end
242
+
243
+ # Retrieves a preflist for the given bucket, key, and type; useful for
244
+ # figuring out where in the cluster an object is stored.
245
+ # @param [Bucket, String] bucket the Bucket or name of the bucket
246
+ # @param [String] key the key
247
+ # @param [BucketType, String] type the bucket type or name of the bucket
248
+ # type
249
+ # @return [Array<PreflistItem>] an array of preflist entries
250
+ def get_preflist(bucket, key, type = nil, options = { })
251
+ backend do |b|
252
+ b.get_preflist bucket, key, type, options
253
+ end
254
+ end
255
+
256
+ # Get multiple objects in parallel.
257
+ def get_many(pairs)
258
+ Multiget.get_all self, pairs
259
+ end
260
+
261
+ # Get an object. See Bucket#get
262
+ def get_object(bucket, key, options = {})
263
+ raise ArgumentError, t("zero_length_key") if key == ''
264
+ backend do |b|
265
+ b.fetch_object(bucket, key, options)
266
+ end
267
+ end
268
+
269
+ # @return [String] A representation suitable for IRB and debugging output.
270
+ def inspect
271
+ "#<Riak::Client #{nodes.inspect}>"
272
+ end
273
+
274
+ # Retrieves a list of keys in the given bucket. See Bucket#keys
275
+ def list_keys(bucket, options = {}, &block)
276
+ if block_given?
277
+ backend do |b|
278
+ b.list_keys bucket, options, &block
279
+ end
280
+ else
281
+ backend do |b|
282
+ b.list_keys bucket, options
283
+ end
284
+ end
285
+ end
286
+
287
+ # Executes a mapreduce request. See MapReduce#run
288
+ def mapred(mr, &block)
289
+ backend do |b|
290
+ b.mapred(mr, &block)
291
+ end
292
+ end
293
+
294
+ # Creates a new protocol buffers backend.
295
+ # @return [ProtobuffsBackend] the Protocol Buffers backend for
296
+ # a given node.
297
+ def new_protobuffs_backend
298
+ klass = self.class.const_get("#{@protobuffs_backend}ProtobuffsBackend")
299
+ if klass.configured?
300
+ node = choose_node(
301
+ @nodes.select do |n|
302
+ n.protobuffs?
303
+ end
304
+ )
305
+
306
+ klass.new(self, node)
307
+ else
308
+ raise BackendCreationError.new @protobuffs_backend
309
+ end
310
+ end
311
+
312
+ # @return [Node] An arbitrary Node.
313
+ def node
314
+ nodes[rand nodes.size]
315
+ end
316
+
317
+ # Pings the Riak cluster to check for liveness.
318
+ # @return [true,false] whether the Riak cluster is alive and reachable
319
+ def ping
320
+ backend do |b|
321
+ b.ping
322
+ end
323
+ end
324
+
325
+ # Yields a protocol buffers backend.
326
+ def protobuffs(&block)
327
+ recover_from @protobuffs_pool, &block
328
+ end
329
+ alias :backend :protobuffs
330
+
331
+ # Sets the desired Protocol Buffers backend
332
+ def protobuffs_backend=(value)
333
+ # Shutdown any connections using the old backend
334
+ @protobuffs_backend = value
335
+ @protobuffs_pool.clear
336
+ @protobuffs_backend
337
+ end
338
+
339
+ # Takes a pool. Acquires a backend from the pool and yields it with
340
+ # node-specific error recovery.
341
+ def recover_from(pool)
342
+ skip_nodes = []
343
+ take_opts = {}
344
+ tries = 3
345
+
346
+ begin
347
+ # Only select nodes which we haven't used before.
348
+ unless skip_nodes.empty?
349
+ take_opts[:filter] = lambda do |backend|
350
+ not skip_nodes.include? backend.node
351
+ end
352
+ end
353
+
354
+ # Acquire a backend
355
+ pool.take(take_opts) do |backend|
356
+ begin
357
+ yield backend
358
+ rescue *NETWORK_ERRORS => e
359
+ # Network error.
360
+ tries -= 1
361
+
362
+ # Notify the node that a request against it failed.
363
+ backend.node.error_rate << 1
364
+
365
+ # Skip this node next time.
366
+ skip_nodes << backend.node
367
+
368
+ # And delete this connection.
369
+ raise Pool::BadResource, e
370
+ end
371
+ end
372
+ rescue Pool::BadResource => e
373
+ retry if tries > 0
374
+ raise e.message
375
+ end
376
+ end
377
+
378
+ # Reloads the object from Riak.
379
+ def reload_object(object, options = {})
380
+ backend do |b|
381
+ b.reload_object(object, options)
382
+ end
383
+ end
384
+
385
+ # Sets the properties on a bucket. See Bucket#props=
386
+ def set_bucket_props(bucket, properties, type = nil)
387
+ backend do |b|
388
+ b.set_bucket_props(bucket, properties, type)
389
+ end
390
+ end
391
+
392
+ # Clears the properties on a bucket. See Bucket#clear_props
393
+ def clear_bucket_props(bucket, options = { })
394
+ backend do |b|
395
+ b.reset_bucket_props(bucket, options)
396
+ end
397
+ end
398
+
399
+ # Exposes a {Stamp} object for use in generating unique
400
+ # identifiers.
401
+ # @return [Stamp] an ID generator
402
+ # @see Stamp#next
403
+ def stamp
404
+ @stamp ||= Riak::Stamp.new(self)
405
+ end
406
+
407
+
408
+ # Stores an object in Riak.
409
+ def store_object(object, options = {})
410
+ params = {:returnbody => true}.merge(options)
411
+ backend do |b|
412
+ b.store_object(object, params)
413
+ end
414
+ end
415
+
416
+ private
417
+ def make_client_id
418
+ rand(MAX_CLIENT_ID)
419
+ end
420
+
421
+ def ssl_enable
422
+ @nodes.each do |n|
423
+ n.ssl_enable
424
+ end
425
+ end
426
+
427
+ def ssl_disable
428
+ @nodes.each do |n|
429
+ n.ssl_disable
430
+ end
431
+ end
432
+ end
433
+ end