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,538 @@
1
+ require 'base64'
2
+ require 'riak/json'
3
+ require 'riak/client'
4
+ require 'riak/errors/failed_request'
5
+ require 'riak/client/protobuffs_backend'
6
+
7
+ module Riak
8
+ class Client
9
+ class BeefcakeProtobuffsBackend < ProtobuffsBackend
10
+ def self.configured?
11
+ begin
12
+ require 'beefcake'
13
+ require 'riak/client/beefcake/messages'
14
+ require 'riak/client/beefcake/message_overlay'
15
+ require 'riak/client/beefcake/object_methods'
16
+ require 'riak/client/beefcake/bucket_properties_operator'
17
+ require 'riak/client/beefcake/crdt_operator'
18
+ require 'riak/client/beefcake/crdt_loader'
19
+ require 'riak/client/beefcake/protocol'
20
+ require 'riak/client/beefcake/socket'
21
+ true
22
+ rescue LoadError, NameError => e
23
+ # put exception into a variable for debugging
24
+ false
25
+ end
26
+ end
27
+
28
+ def protocol
29
+ p = Protocol.new socket
30
+ in_request = false
31
+ result = nil
32
+ begin
33
+ in_request = true
34
+ result = yield p
35
+ in_request = false
36
+ ensure
37
+ reset_socket if in_request
38
+ end
39
+ return result
40
+ end
41
+
42
+ def new_socket
43
+ BeefcakeSocket.new @node.host, @node.pb_port, authentication: client.authentication
44
+ end
45
+
46
+ def ping
47
+ protocol do |p|
48
+ p.write :PingReq
49
+ p.expect :PingResp
50
+ end
51
+ end
52
+
53
+ def get_client_id
54
+ protocol do |p|
55
+ p.write :GetClientIdReq
56
+ p.expect(:GetClientIdResp, RpbGetClientIdResp).client_id
57
+ end
58
+ end
59
+
60
+ def server_info
61
+ resp = protocol do |p|
62
+ p.write :GetServerInfoReq
63
+ p.expect(:GetServerInfoResp, RpbGetServerInfoResp)
64
+ end
65
+
66
+ { node: resp.node, server_version: resp.server_version }
67
+ end
68
+
69
+ def set_client_id(id)
70
+ value = case id
71
+ when Integer
72
+ [id].pack("N")
73
+ else
74
+ id.to_s
75
+ end
76
+ req = RpbSetClientIdReq.new(:client_id => value)
77
+ protocol do |p|
78
+ p.write :SetClientIdReq, req
79
+ p.expect :SetClientIdResp
80
+ end
81
+ return true
82
+ end
83
+
84
+ def fetch_object(bucket, key, options = {})
85
+ options = prune_unsupported_options(:GetReq, normalize_quorums(options))
86
+ bucket = Bucket === bucket ? bucket.name : bucket
87
+ req = RpbGetReq.new(options.merge(:bucket => maybe_encode(bucket), :key => maybe_encode(key)))
88
+
89
+ resp = protocol do |p|
90
+ p.write :GetReq, req
91
+ p.expect :GetResp, RpbGetResp, empty_body_acceptable: true
92
+ end
93
+
94
+ if :empty == resp
95
+ raise Riak::ProtobuffsFailedRequest.new(:not_found, t('not_found'))
96
+ end
97
+
98
+ template = RObject.new(client.bucket(bucket), key)
99
+ load_object(resp, template)
100
+ end
101
+
102
+ def reload_object(robject, options = {})
103
+ options = normalize_quorums(options)
104
+ options[:bucket] = maybe_encode(robject.bucket.name)
105
+ options[:type] = maybe_encode(robject.bucket.type.name) if robject.bucket.needs_type?
106
+ options[:key] = maybe_encode(robject.key)
107
+ options[:if_modified] = maybe_encode Base64.decode64(robject.vclock) if robject.vclock
108
+ req = RpbGetReq.new(prune_unsupported_options(:GetReq, options))
109
+
110
+ resp = protocol do |p|
111
+ p.write :GetReq, req
112
+ p.expect :GetResp, RpbGetResp, empty_body_acceptable: true
113
+ end
114
+
115
+ if :empty == resp
116
+ raise Riak::ProtobuffsFailedRequest.new(:not_found, t('not_found'))
117
+ end
118
+
119
+ load_object(resp, robject)
120
+ end
121
+
122
+ def store_object(robject, options = {})
123
+ options[:return_body] ||= options[:returnbody]
124
+ options = normalize_quorums(options)
125
+ if robject.prevent_stale_writes
126
+ unless pb_conditionals?
127
+ other = fetch_object(robject.bucket, robject.key)
128
+ raise Riak::ProtobuffsFailedRequest.new(:stale_object, t("stale_write_prevented")) unless other.vclock == robject.vclock
129
+ end
130
+ if robject.vclock
131
+ options[:if_not_modified] = true
132
+ else
133
+ options[:if_none_match] = true
134
+ end
135
+ end
136
+ req = dump_object(robject, prune_unsupported_options(:PutReq, options))
137
+
138
+ resp = protocol do |p|
139
+ p.write(:PutReq, req)
140
+ p.expect :PutResp, RpbPutResp, empty_body_acceptable: true
141
+ end
142
+
143
+ return true if :empty == resp
144
+
145
+ load_object resp, robject
146
+ end
147
+
148
+ def delete_object(bucket, key, options = {})
149
+ if bucket.is_a? Bucket
150
+ options[:type] = bucket.type.name if bucket.needs_type?
151
+ bucket = bucket.name
152
+ end
153
+ options = normalize_quorums(options)
154
+ options[:bucket] = maybe_encode(bucket)
155
+ options[:key] = maybe_encode(key)
156
+ options[:vclock] = Base64.decode64(options[:vclock]) if options[:vclock]
157
+ req = RpbDelReq.new(prune_unsupported_options(:DelReq, options))
158
+
159
+ protocol do |p|
160
+ p.write :DelReq, req
161
+ p.expect :DelResp
162
+ end
163
+
164
+ return true
165
+ end
166
+
167
+ def get_preflist(bucket, key, type = nil, options = {})
168
+ if type.nil? && bucket.is_a?(Riak::BucketTyped::Bucket)
169
+ type = bucket.type.name
170
+ end
171
+ bucket = bucket.name if bucket.is_a? Bucket
172
+ type = type.name if type.is_a? BucketType
173
+
174
+ message = RpbGetBucketKeyPreflistReq.new(
175
+ bucket: bucket,
176
+ key: key,
177
+ type: type
178
+ )
179
+
180
+ resp = protocol do |p|
181
+ p.write :GetBucketKeyPreflistReq, message
182
+ p.expect :GetBucketKeyPreflistResp, RpbGetBucketKeyPreflistResp
183
+ end
184
+
185
+ resp.preflist
186
+ end
187
+
188
+ def get_counter(bucket, key, options = {})
189
+ bucket = bucket.name if bucket.is_a? Bucket
190
+
191
+ options = normalize_quorums(options)
192
+ options[:bucket] = bucket
193
+ options[:key] = key
194
+
195
+ request = RpbCounterGetReq.new options
196
+
197
+ resp = protocol do |p|
198
+ p.write :CounterGetReq, request
199
+ p.expect :CounterGetResp, RpbCounterGetResp, empty_body_acceptable: true
200
+ end
201
+
202
+ if :empty == resp
203
+ return 0
204
+ end
205
+
206
+ return resp.value || 0
207
+ end
208
+
209
+ def post_counter(bucket, key, amount, options = {})
210
+ bucket = bucket.name if bucket.is_a? Bucket
211
+
212
+ options = normalize_quorums(options)
213
+ options[:bucket] = bucket
214
+ options[:key] = key
215
+ # TODO: raise if amount doesn't fit in sint64
216
+ options[:amount] = amount
217
+ options[:returnvalue] = options[:returnvalue] || options[:return_value]
218
+
219
+ request = RpbCounterUpdateReq.new options
220
+
221
+ resp = protocol do |p|
222
+ p.write :CounterUpdateReq, request
223
+ p.expect :CounterUpdateResp, RpbCounterUpdateResp, empty_body_acceptable: true
224
+ end
225
+
226
+ return nil if :empty == resp
227
+
228
+ return resp.value
229
+ end
230
+
231
+ def get_bucket_props(bucket, options = { })
232
+ bucket_properties_operator.get bucket, options
233
+ end
234
+
235
+ def set_bucket_props(bucket, props, type = nil)
236
+ bucket_properties_operator.put bucket, props, type: type
237
+ end
238
+
239
+ def reset_bucket_props(bucket, options)
240
+ bucket = bucket.name if Bucket === bucket
241
+ req = RpbResetBucketReq.new(bucket: maybe_encode(bucket),
242
+ type: options[:type])
243
+
244
+ protocol do |p|
245
+ p.write :ResetBucketReq, req
246
+ p.expect :ResetBucketResp
247
+ end
248
+ end
249
+
250
+ def get_bucket_type_props(bucket_type)
251
+ bucket_type = bucket_type.name if bucket_type.is_a? BucketType
252
+ req = RpbGetBucketTypeReq.new type: bucket_type
253
+
254
+ resp = protocol do |p|
255
+ p.write :GetBucketTypeReq, req
256
+ p.expect(:GetBucketResp, RpbGetBucketResp)
257
+ end
258
+
259
+ resp.props.to_hash
260
+ end
261
+
262
+ def list_keys(bucket, options = {}, &block)
263
+ bucket = bucket.name if Bucket === bucket
264
+ req = RpbListKeysReq.new(options.merge(:bucket => maybe_encode(bucket)))
265
+
266
+ keys = []
267
+
268
+ protocol do |p|
269
+ p.write :ListKeysReq, req
270
+
271
+ while msg = p.expect(:ListKeysResp, RpbListKeysResp)
272
+ break if msg.done
273
+ if block_given?
274
+ yield msg.keys
275
+ else
276
+ keys += msg.keys
277
+ end
278
+ end
279
+ end
280
+
281
+ return keys unless block_given?
282
+
283
+ return true
284
+ end
285
+
286
+ # override the simple list_buckets
287
+ def list_buckets(options = {}, &blk)
288
+ if block_given?
289
+ return streaming_list_buckets options, &blk
290
+ end
291
+
292
+ raise t("streaming_bucket_list_without_block") if options[:stream]
293
+
294
+ request = RpbListBucketsReq.new options
295
+
296
+ resp = protocol do |p|
297
+ p.write :ListBucketsReq, request
298
+
299
+ p.expect :ListBucketsResp, RpbListBucketsResp, empty_body_acceptable: true
300
+ end
301
+
302
+ return [] if :empty == resp
303
+
304
+ resp.buckets
305
+ end
306
+
307
+ def mapred(mr, &block)
308
+ raise MapReduceError.new(t("empty_map_reduce_query")) if mr.query.empty? && !mapred_phaseless?
309
+ req = RpbMapRedReq.new(:request => mr.to_json, :content_type => "application/json")
310
+
311
+ results = MapReduce::Results.new(mr)
312
+
313
+ protocol do |p|
314
+ p.write :MapRedReq, req
315
+ while msg = p.expect(:MapRedResp, RpbMapRedResp)
316
+ break if msg.done
317
+ if block_given?
318
+ yield msg.phase, JSON.parse(msg.response)
319
+ else
320
+ results.add msg.phase, JSON.parse(msg.response)
321
+ end
322
+ end
323
+ end
324
+
325
+ block_given? || results.report
326
+ end
327
+
328
+ def get_index(bucket, index, query, query_options = {}, &block)
329
+ return super unless pb_indexes?
330
+ bucket = bucket.name if Bucket === bucket
331
+ if Range === query
332
+ options = {
333
+ :qtype => RpbIndexReq::IndexQueryType::RANGE,
334
+ :range_min => query.begin.to_s,
335
+ :range_max => query.end.to_s
336
+ }
337
+ else
338
+ options = {
339
+ :qtype => RpbIndexReq::IndexQueryType::EQ,
340
+ :key => query.to_s
341
+ }
342
+ end
343
+
344
+ options.merge!(:bucket => bucket, :index => index.to_s)
345
+ options.merge!(query_options)
346
+ options[:stream] = block_given?
347
+
348
+ req = RpbIndexReq.new(options)
349
+
350
+ protocol do |p|
351
+ p.write :IndexReq, req
352
+ decode_index_response(p, &block)
353
+ end
354
+ end
355
+
356
+ def search(index, query, options = {})
357
+ return super unless pb_search?
358
+ options = options.symbolize_keys
359
+ options[:op] = options.delete(:'q.op') if options[:'q.op']
360
+ req = RpbSearchQueryReq.new(options.merge(:index => index || 'search', :q => query))
361
+
362
+ resp = protocol do |p|
363
+ p.write :SearchQueryReq, req
364
+ p.expect :SearchQueryResp, RpbSearchQueryResp
365
+ end
366
+
367
+ resp.docs = [] if resp.docs.nil?
368
+
369
+ ret = { 'max_score' => resp.max_score, 'num_found' => resp.num_found }
370
+ ret['docs'] = resp.docs.map { |d| decode_doc d }
371
+
372
+ return ret
373
+ end
374
+
375
+ def create_search_index(name, schema = nil, n_val = nil, timeout = nil)
376
+ index = RpbYokozunaIndex.new(name: name, schema: schema, n_val: n_val)
377
+ req = RpbYokozunaIndexPutReq.new(index: index, timeout: timeout)
378
+
379
+ protocol do |p|
380
+ p.write :YokozunaIndexPutReq, req
381
+ p.expect :PutResp
382
+ end
383
+ end
384
+
385
+ def get_search_index(name)
386
+ req = RpbYokozunaIndexGetReq.new(:name => name)
387
+ begin
388
+ resp = protocol do |p|
389
+ p.write :YokozunaIndexGetReq, req
390
+ p.expect :YokozunaIndexGetResp, RpbYokozunaIndexGetResp, empty_body_acceptable: true
391
+ end
392
+ rescue ProtobuffsErrorResponse => e
393
+ if e.code == 0 && e.original_message =~ /notfound/
394
+ raise Riak::ProtobuffsFailedRequest.new(:not_found, t('not_found'))
395
+ end
396
+
397
+ raise e
398
+ end
399
+
400
+ resp
401
+ end
402
+
403
+ def delete_search_index(name)
404
+ req = RpbYokozunaIndexDeleteReq.new(:name => name)
405
+ protocol do |p|
406
+ p.write :YokozunaIndexDeleteReq, req
407
+ p.expect :DelResp
408
+ end
409
+ true
410
+ end
411
+
412
+ def create_search_schema(name, content)
413
+ schema = RpbYokozunaSchema.new(:name => name, :content => content)
414
+ req = RpbYokozunaSchemaPutReq.new(:schema => schema)
415
+
416
+ protocol do |p|
417
+ p.write :YokozunaSchemaPutReq, req
418
+ p.expect :PutResp
419
+ end
420
+ true
421
+ end
422
+
423
+ def get_search_schema(name)
424
+ req = RpbYokozunaSchemaGetReq.new(:name => name)
425
+
426
+ begin
427
+ resp = protocol do |p|
428
+ p.write :YokozunaSchemaGetReq, req
429
+ p.expect :YokozunaSchemaGetResp, RpbYokozunaSchemaGetResp
430
+ end
431
+ rescue ProtobuffsErrorResponse => e
432
+ if e.code == 0 && e.original_message =~ /notfound/
433
+ raise Riak::ProtobuffsFailedRequest.new(:not_found, t('not_found'))
434
+ end
435
+
436
+ raise e
437
+ end
438
+
439
+ resp.schema ? resp.schema : resp
440
+ end
441
+
442
+ def write_protobuff(code, message)
443
+ encoded = message.encode
444
+ header = [encoded.length+1, MESSAGE_CODES.index(code)].pack("NC")
445
+ socket.write(header + encoded)
446
+ end
447
+
448
+ private
449
+ def decode_response(*args)
450
+ header = socket.read(5)
451
+ raise ProtobuffsFailedHeader.new if header.nil?
452
+ msglen, msgcode = header.unpack("NC")
453
+ if msglen == 1
454
+ case MESSAGE_CODES[msgcode]
455
+ when :ListBucketsResp,
456
+ :IndexResp
457
+ []
458
+ when :GetResp,
459
+ :YokozunaSchemaGetResp
460
+ raise Riak::ProtobuffsFailedRequest.new(:not_found, t('not_found'))
461
+ when :CounterGetResp,
462
+ :CounterUpdateResp
463
+ 0
464
+ else
465
+ false
466
+ end
467
+ else
468
+ message = socket.read(msglen-1)
469
+ case MESSAGE_CODES[msgcode]
470
+ when :ErrorResp
471
+ res = RpbErrorResp.decode(message)
472
+ raise Riak::ProtobuffsFailedRequest.new(res.errcode, res.errmsg)
473
+ end
474
+ end
475
+ rescue SystemCallError, SocketError => e
476
+ reset_socket
477
+ raise
478
+ end
479
+
480
+ def streaming_list_buckets(options = {})
481
+ request = RpbListBucketsReq.new(options.merge(stream: true))
482
+ write_protobuff :ListBucketsReq, request
483
+ loop do
484
+ header = socket.read 5
485
+ raise SocketError, "Unexpected EOF on PBC socket" if header.nil?
486
+ len, code = header.unpack 'NC'
487
+ if MESSAGE_CODES[code] != :ListBucketsResp
488
+ raise SocketError, "Unexpected non-ListBucketsResp during streaming list buckets"
489
+ end
490
+
491
+ message = socket.read(len - 1)
492
+ section = RpbListBucketsResp.decode message
493
+ yield section.buckets
494
+
495
+ return if section.done
496
+ end
497
+ end
498
+
499
+ def decode_index_response(p)
500
+ loop do
501
+ resp = p.expect :IndexResp, RpbIndexResp, empty_body_acceptable: true
502
+
503
+ if :empty == resp
504
+ return if block_given?
505
+ return IndexCollection.new_from_protobuf(RpbIndexResp.decode(''))
506
+ end
507
+
508
+ if !block_given?
509
+ return IndexCollection.new_from_protobuf(resp)
510
+ end
511
+
512
+ content = resp.keys || resp.results || []
513
+ yield content
514
+
515
+ return if resp.done
516
+ end
517
+ rescue ProtobuffsErrorResponse => err
518
+ if match = err.message.match(/indexes_not_supported,(\w+)/)
519
+ old_err = err
520
+ err = ProtobuffsFailedRequest.new(:indexes_not_supported,
521
+ t('index.wrong_backend', backend: match[1])
522
+ )
523
+ end
524
+
525
+ raise err
526
+ end
527
+
528
+ def decode_doc(doc)
529
+ Hash[doc.fields.map {|p| [ force_utf8(p.key), force_utf8(p.value) ] }]
530
+ end
531
+
532
+ def force_utf8(str)
533
+ # Search returns strings that should always be valid UTF-8
534
+ ObjectMethods::ENCODING ? str.force_encoding('UTF-8') : str
535
+ end
536
+ end
537
+ end
538
+ end