riak-client 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/README.markdown +55 -12
  3. data/RELEASE_NOTES.md +20 -1
  4. data/lib/riak.rb +1 -0
  5. data/lib/riak/client.rb +2 -1
  6. data/lib/riak/client/beefcake/crdt/counter_loader.rb +18 -0
  7. data/lib/riak/client/beefcake/crdt/map_loader.rb +64 -0
  8. data/lib/riak/client/beefcake/crdt/set_loader.rb +18 -0
  9. data/lib/riak/client/beefcake/crdt_loader.rb +16 -59
  10. data/lib/riak/client/beefcake/crdt_operator.rb +2 -1
  11. data/lib/riak/client/instrumentation.rb +19 -0
  12. data/lib/riak/crdt/base.rb +16 -0
  13. data/lib/riak/errors/backend_creation.rb +9 -0
  14. data/lib/riak/instrumentation.rb +6 -0
  15. data/lib/riak/version.rb +1 -1
  16. data/riak-client.gemspec +3 -2
  17. data/spec/integration/riak/counters_spec.rb +1 -1
  18. data/spec/integration/riak/crdt_spec.rb +68 -23
  19. data/spec/integration/riak/protobuffs_backends_spec.rb +1 -1
  20. data/spec/integration/riak/threading_spec.rb +4 -4
  21. data/spec/integration/yokozuna/index_spec.rb +5 -5
  22. data/spec/integration/yokozuna/queries_spec.rb +15 -16
  23. data/spec/integration/yokozuna/schema_spec.rb +2 -2
  24. data/spec/riak/beefcake_protobuffs_backend/crdt_operator_spec.rb +8 -8
  25. data/spec/riak/beefcake_protobuffs_backend/object_methods_spec.rb +1 -1
  26. data/spec/riak/beefcake_protobuffs_backend_spec.rb +8 -8
  27. data/spec/riak/bucket_spec.rb +38 -38
  28. data/spec/riak/client_spec.rb +26 -27
  29. data/spec/riak/core_ext/to_param_spec.rb +2 -2
  30. data/spec/riak/counter_spec.rb +11 -11
  31. data/spec/riak/crdt/counter_spec.rb +4 -2
  32. data/spec/riak/crdt/inner_counter_spec.rb +1 -1
  33. data/spec/riak/crdt/inner_flag_spec.rb +4 -4
  34. data/spec/riak/crdt/inner_map_spec.rb +3 -3
  35. data/spec/riak/crdt/inner_register_spec.rb +5 -5
  36. data/spec/riak/crdt/inner_set_spec.rb +1 -1
  37. data/spec/riak/crdt/map_spec.rb +2 -2
  38. data/spec/riak/crdt/set_spec.rb +4 -2
  39. data/spec/riak/crdt/shared_examples.rb +15 -15
  40. data/spec/riak/crdt/typed_collection_spec.rb +16 -22
  41. data/spec/riak/escape_spec.rb +10 -10
  42. data/spec/riak/feature_detection_spec.rb +1 -1
  43. data/spec/riak/index_collection_spec.rb +7 -4
  44. data/spec/riak/instrumentation_spec.rb +124 -0
  45. data/spec/riak/link_spec.rb +12 -12
  46. data/spec/riak/list_buckets_spec.rb +2 -2
  47. data/spec/riak/map_reduce/filter_builder_spec.rb +5 -5
  48. data/spec/riak/map_reduce/phase_spec.rb +20 -20
  49. data/spec/riak/map_reduce_spec.rb +50 -50
  50. data/spec/riak/multiget_spec.rb +5 -5
  51. data/spec/riak/node_spec.rb +3 -3
  52. data/spec/riak/robject_spec.rb +46 -45
  53. data/spec/riak/search_spec.rb +11 -11
  54. data/spec/riak/secondary_index_spec.rb +9 -9
  55. data/spec/riak/stamp_spec.rb +5 -5
  56. data/spec/riak/walk_spec_spec.rb +30 -30
  57. data/spec/spec_helper.rb +6 -0
  58. data/spec/support/certs/ca.crt +19 -20
  59. data/spec/support/certs/client.crl +13 -0
  60. data/spec/support/certs/client.crt +68 -69
  61. data/spec/support/certs/client.csr +18 -0
  62. data/spec/support/certs/client.key +25 -25
  63. data/spec/support/certs/server.crl +11 -11
  64. data/spec/support/certs/server.crt +68 -69
  65. data/spec/support/certs/server.key +25 -25
  66. data/spec/support/unified_backend_examples.rb +33 -33
  67. metadata +31 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ad40ac9eb63589a4a5ec590cec005f72da1d5865
4
- data.tar.gz: 728c720266417b1f07e0d2078b83deb49341e004
3
+ metadata.gz: ca7b5752fe722de4af5c0adceec72adf47c80241
4
+ data.tar.gz: 0a2b4e34fefb8b5c7a9ecef6fd06d8372616ba2c
5
5
  SHA512:
6
- metadata.gz: d74e7d77692280c40f0777b0c80dad5455592584e116f1ea12a9eeca2d53e14bd38b32cca201fafd15550767d305a13ae2127376c3fef4339204ed1d860f554f
7
- data.tar.gz: 8073b45333abf60fb4965afea5eaca555b44761abe08089295f742d1bcd937c0ee8027319f0c65f3d86e0caf57cc63ae5b538430fc161d500939c885650045b2
6
+ metadata.gz: 43600350e10122607eaca375a69225285a28403041e231d3bf527c04c90fedde75fc7136f7bd626d3ea448e0ecfd4deed10e8707e6a12605077662edb72a60f0
7
+ data.tar.gz: 1b3e910ec530a8d9e41a333b376918608aac4398be8b15af478978323e22f94cd407e008a43135c2f4bb12914e4e1ea998d88ac6acf19201242c3bd9eac6e0e9
@@ -50,7 +50,7 @@ client = Riak::Client.new(authentication: {
50
50
 
51
51
  # username, required
52
52
  user: 'zedo',
53
-
53
+
54
54
  # password for password-based authentication
55
55
  password: 'catnip',
56
56
 
@@ -97,7 +97,7 @@ new_one.store
97
97
  ## Bucket Types
98
98
 
99
99
  Riak 2 uses [bucket types](http://docs.basho.com/riak/latest/dev/advanced/bucket-types/) to
100
- enable groups of similar buckets to share properties, configuration, and to namespace values
100
+ enable groups of similar buckets to share properties, configuration, and to namespace values
101
101
  within those buckets. Bucket type support is integral to how CRDTs work.
102
102
 
103
103
  Many operations take `type` options to perform them with a specific bucket type.
@@ -133,9 +133,9 @@ results = Riak::MapReduce.new(client).
133
133
  link(:bucket => "albums").
134
134
  map("function(v){ return [JSON.parse(v.values[0].data).title]; }", :keep => true).run
135
135
 
136
- p results # => ["Please Please Me", "With The Beatles", "A Hard Day's Night",
136
+ p results # => ["Please Please Me", "With The Beatles", "A Hard Day's Night",
137
137
  # "Beatles For Sale", "Help!", "Rubber Soul",
138
- # "Revolver", "Sgt. Pepper's Lonely Hearts Club Band", "Magical Mystery Tour",
138
+ # "Revolver", "Sgt. Pepper's Lonely Hearts Club Band", "Magical Mystery Tour",
139
139
  # "The Beatles", "Yellow Submarine", "Abbey Road", "Let It Be"]
140
140
  ```
141
141
 
@@ -151,7 +151,7 @@ client = Riak::Client.new
151
151
  bucket = client.bucket 'pizzas'
152
152
 
153
153
  # Create an index and add it to a typed bucket. Setting the index on the bucket
154
- # may fail until the index creation has propagated.
154
+ # may fail until the index creation has propagated.
155
155
  client.create_search_index 'pizzas'
156
156
  client.set_bucket_props bucket, {search_index: 'pizzas'}, 'yokozuna'
157
157
 
@@ -172,7 +172,7 @@ result['docs'] # the list of indexed documents
172
172
 
173
173
  ## Secondary Index Examples
174
174
 
175
- Riak supports secondary indexes. Secondary indexing, or "2i," gives you the
175
+ Riak supports secondary indexes. Secondary indexing, or "2i," gives you the
176
176
  ability to tag objects with multiple queryable values at write time, and then
177
177
  query them later.
178
178
 
@@ -187,7 +187,7 @@ storage logic is in `lib/riak/rcontent.rb`.
187
187
  ```ruby
188
188
  object = bucket.get_or_new 'cobb.salad'
189
189
 
190
- # Indexes end with the "_bin" suffix to indicate they're binary or string
190
+ # Indexes end with the "_bin" suffix to indicate they're binary or string
191
191
  # indexes. They can have multiple values.
192
192
  object.indexes['ingredients_bin'] = %w{lettuce tomato bacon egg chives}
193
193
 
@@ -201,7 +201,7 @@ object.store
201
201
 
202
202
  ### Finding Objects
203
203
 
204
- Secondary index queries return a list of keys exactly matching a scalar or
204
+ Secondary index queries return a list of keys exactly matching a scalar or
205
205
  within a range.
206
206
 
207
207
  ```ruby
@@ -238,12 +238,12 @@ q2 = q.next_page
238
238
 
239
239
  ## Riak 2 Data Types
240
240
 
241
- Riak 2 features new distributed data structures: counters, sets, and maps
242
- (containing counters, flags, maps, registers, and sets). These are implemented
241
+ Riak 2 features new distributed data structures: counters, sets, and maps
242
+ (containing counters, flags, maps, registers, and sets). These are implemented
243
243
  by the Riak database as Convergent Replicated Data Types.
244
244
 
245
245
  Riak data type support requires bucket types to be configured to support each
246
- top-level data type. If you're just playing around, use the
246
+ top-level data type. If you're just playing around, use the
247
247
  [Riak Ruby Vagrant](https://github.com/basho-labs/riak-ruby-vagrant) setup to
248
248
  get started with the appropriate configuration and bucket types quickly.
249
249
 
@@ -438,6 +438,49 @@ ArgumentError: Counters can only be incremented or decremented by integers.
438
438
 
439
439
  That's about it. PN Counters in Riak are distributed, so each node will receive the proper increment/decrement operation. Enjoy using them.
440
440
 
441
+ ## Instrumentation
442
+
443
+ The Riak client has built-in event hooks for all major over-the-wire operations including:
444
+
445
+ * riak.list_buckets
446
+ * riak.list_keys
447
+ * riak.set_bucket_props
448
+ * riak.get_bucket_props
449
+ * riak.clear_bucket_props
450
+ * riak.get_index
451
+ * riak.store_object
452
+ * riak.get_object
453
+ * riak.reload_object
454
+ * riak.delete_object
455
+ * riak.map_reduce
456
+ * riak.ping
457
+
458
+ Events are propogated using [ActiveSupport::Notifications](http://api.rubyonrails.org/classes/ActiveSupport/Notifications.html), provided by the [Instrumentable](https://github.com/siyegen/instrumentable) gem.
459
+
460
+ ### Enabling
461
+
462
+ Instrumentation is opt-in. If `instrumentable` is not available, instrumentation will not be available. To turn on instrumentation, simply require the `instrumentable` gem in your app's Gemfile:
463
+
464
+ ```ruby
465
+ gem 'instrumentable', '~> 1.1.0'
466
+ ```
467
+
468
+ Then, to subscribe to events:
469
+
470
+ ```ruby
471
+ ActiveSupport::Notifications.subscribe(/^riak\.*/) do |name, start, finish, id, payload|
472
+ name # => String, name of the event (such as 'riak.get_object' from above)
473
+ start # => Time, when the instrumented block started execution
474
+ finish # => Time, when the instrumented block ended execution
475
+ id # => String, unique ID for this notification
476
+ payload # => Hash, the payload
477
+ end
478
+ ```
479
+
480
+ The payload for each event contains the following keys:
481
+
482
+ * `:client_id`: The client_id of the Riak client
483
+ * `:_method_args`: The array of method arguments for the instrumented method. For instance, for `riak.get_object`, this value would resemble `[<Riak::Bucket ...>, 'key', {}]`
441
484
 
442
485
  ## How to Contribute
443
486
 
@@ -480,5 +523,5 @@ Unless required by applicable law or agreed to in writing, software distributed
480
523
 
481
524
  ## Auxillary Licenses
482
525
 
483
- The included photo (spec/fixtures/cat.jpg) is Copyright &copy;2009 [Sean Cribbs](http://seancribbs.com/), and is licensed under the [Creative Commons Attribution Non-Commercial 3.0](http://creativecommons.org/licenses/by-nc/3.0) license.
526
+ The included photo (spec/fixtures/cat.jpg) is Copyright &copy;2009 [Sean Cribbs](http://seancribbs.com/), and is licensed under the [Creative Commons Attribution Non-Commercial 3.0](http://creativecommons.org/licenses/by-nc/3.0) license.
484
527
  !["Creative Commons"](http://i.creativecommons.org/l/by-nc/3.0/88x31.png)
@@ -1,6 +1,25 @@
1
1
  # Riak Ruby Client Release Notes
2
2
 
3
- ## 2.0.0 Release - TBD
3
+ ## 2.1.0 Release - 2014-10-03
4
+
5
+ Version 2.1.0 is a feature release.
6
+
7
+ New features:
8
+
9
+ * Instrumentation: if the `instrumentable` gem is loaded, the client exposes
10
+ several event hooks to `ActiveSupport::Notifications`. Read the README for
11
+ more information, and if you'd like other events to be instrumented, please
12
+ file GitHub issues. Instrumentation was developed by Ryan Daigle.
13
+ * CRDTs support the `returnbody` option, and use it by default. This means that
14
+ unless specified otherwise, CRDTs will update themselves on a write.
15
+
16
+ Small changes:
17
+
18
+ * UTF-8 support is now tested against.
19
+ * RSpec 3.1 is now supported, although RSpec 3.0 still works.
20
+ * Specs no longer use gratuitous "should"s.
21
+
22
+ ## 2.0.0 Release - 2014-09-05
4
23
 
5
24
  Version 2.0.0 is a major new version with many new features, API changes,
6
25
  and feature removals.
@@ -4,6 +4,7 @@ require 'riak/client'
4
4
  require 'riak/map_reduce'
5
5
  require 'riak/util/translation'
6
6
  require 'riak/crdt'
7
+ require 'riak/instrumentation'
7
8
 
8
9
  # The Riak module contains all aspects of the client interface to
9
10
  # Riak.
@@ -6,6 +6,7 @@ require 'riak/util/translation'
6
6
  require 'riak/util/escape'
7
7
  require 'riak/errors/failed_request'
8
8
  require 'riak/errors/protobuffs_error'
9
+ require 'riak/errors/backend_creation'
9
10
  require 'riak/client/decaying'
10
11
  require 'riak/client/node'
11
12
  require 'riak/client/search'
@@ -283,7 +284,7 @@ module Riak
283
284
 
284
285
  klass.new(self, node)
285
286
  else
286
- raise t('protobuffs_configuration', :backend => @protobuffs_backend)
287
+ raise BackendCreationError.new @protobuffs_backend
287
288
  end
288
289
  end
289
290
 
@@ -0,0 +1,18 @@
1
+ class Riak::Client::BeefcakeProtobuffsBackend
2
+ class CrdtLoader
3
+ class CounterLoader
4
+ def self.for_value(resp)
5
+ return nil unless resp.counter_value
6
+ new resp.counter_value
7
+ end
8
+
9
+ def initialize(counter_value)
10
+ @value = counter_value
11
+ end
12
+
13
+ def rubyfy
14
+ @value
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,64 @@
1
+ class Riak::Client::BeefcakeProtobuffsBackend
2
+ class CrdtLoader
3
+ class MapLoader
4
+ def self.for_value(resp)
5
+ return nil unless resp.map_value
6
+ new resp.map_value
7
+ end
8
+
9
+ def initialize(map_value)
10
+ @value = map_value
11
+ end
12
+
13
+ def rubyfy
14
+ accum = {
15
+ counters: {},
16
+ flags: {},
17
+ maps: {},
18
+ registers: {},
19
+ sets: {}
20
+ }
21
+
22
+ contents_loop @value, accum
23
+ end
24
+
25
+ private
26
+
27
+ def rubyfy_inner(accum, map_value)
28
+ destination = accum[:maps][map_value.field.name]
29
+ if destination.nil?
30
+ destination = accum[:maps][map_value.field.name] = {
31
+ counters: {},
32
+ flags: {},
33
+ maps: {},
34
+ registers: {},
35
+ sets: {}
36
+ }
37
+ end
38
+
39
+ contents_loop map_value.map_value, destination
40
+ end
41
+
42
+ def contents_loop(rolling_value, destination)
43
+ return destination if rolling_value.nil?
44
+
45
+ rolling_value.each do |inner|
46
+ case inner.field.type
47
+ when MapField::MapFieldType::COUNTER
48
+ destination[:counters][inner.field.name] = inner.counter_value
49
+ when MapField::MapFieldType::FLAG
50
+ destination[:flags][inner.field.name] = inner.flag_value
51
+ when MapField::MapFieldType::MAP
52
+ rubyfy_inner destination, inner
53
+ when MapField::MapFieldType::REGISTER
54
+ destination[:registers][inner.field.name] = inner.register_value
55
+ when MapField::MapFieldType::SET
56
+ destination[:sets][inner.field.name] = ::Set.new inner.set_value
57
+ end
58
+ end
59
+
60
+ return destination
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,18 @@
1
+ class Riak::Client::BeefcakeProtobuffsBackend
2
+ class CrdtLoader
3
+ class SetLoader
4
+ def self.for_value(resp)
5
+ return nil unless resp.set_value
6
+ new resp.set_value
7
+ end
8
+
9
+ def initialize(set_value)
10
+ @value = set_value
11
+ end
12
+
13
+ def rubyfy
14
+ ::Set.new @value
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,3 +1,7 @@
1
+ require 'riak/client/beefcake/crdt/counter_loader'
2
+ require 'riak/client/beefcake/crdt/map_loader'
3
+ require 'riak/client/beefcake/crdt/set_loader'
4
+
1
5
  module Riak
2
6
  class Client
3
7
  class BeefcakeProtobuffsBackend
@@ -8,7 +12,7 @@ module Riak
8
12
  def crdt_loader
9
13
  return CrdtLoader.new self
10
14
  end
11
-
15
+
12
16
  # Loads, and deserializes CRDTs from protobuffs into Ruby hashes,
13
17
  # sets, strings, and integers.
14
18
  # @api private
@@ -40,68 +44,21 @@ module Riak
40
44
  rubyfy response
41
45
  end
42
46
 
43
- private
44
- # Convert the protobuffs response into low-level Ruby objects.
45
- def rubyfy(response)
46
- return nil_rubyfy(response.type) if response.value.nil?
47
- case response.type
48
- when DtFetchResp::DataType::COUNTER
49
- response.value.counter_value
50
- when DtFetchResp::DataType::SET
51
- ::Set.new response.value.set_value
52
- when DtFetchResp::DataType::MAP
53
- rubyfy_map response.value.map_value
54
- end
55
- end
56
-
57
- # Convert a top-level map into a Ruby {Hash} of hashes.
58
- def rubyfy_map(map_value)
59
- accum = {
60
- counters: {},
61
- flags: {},
62
- maps: {},
63
- registers: {},
64
- sets: {}
65
- }
47
+ def get_loader_for_value(value)
48
+ return nil if value.nil?
66
49
 
67
- rubyfy_map_contents map_value, accum
50
+ [CounterLoader, MapLoader, SetLoader].map do |loader|
51
+ loader.for_value value
52
+ end.compact.first
68
53
  end
69
54
 
70
- # Convert a map inside another map into a Ruby {Hash}.
71
- def rubyfy_inner_map(accum, map_value)
72
- destination = accum[:maps][map_value.field.name]
73
- if destination.nil?
74
- destination = accum[:maps][map_value.field.name] = {
75
- counters: {},
76
- flags: {},
77
- maps: {},
78
- registers: {},
79
- sets: {}
80
- }
81
- end
82
-
83
- rubyfy_map_contents map_value.map_value, destination
84
- end
85
-
86
- # Load the contents of a map into Ruby hashes.
87
- def rubyfy_map_contents(map_value, destination)
88
- return destination if map_value.nil?
89
- map_value.each do |inner_mv|
90
- case inner_mv.field.type
91
- when MapField::MapFieldType::COUNTER
92
- destination[:counters][inner_mv.field.name] = inner_mv.counter_value
93
- when MapField::MapFieldType::FLAG
94
- destination[:flags][inner_mv.field.name] = inner_mv.flag_value
95
- when MapField::MapFieldType::MAP
96
- rubyfy_inner_map destination, inner_mv
97
- when MapField::MapFieldType::REGISTER
98
- destination[:registers][inner_mv.field.name] = inner_mv.register_value
99
- when MapField::MapFieldType::SET
100
- destination[:sets][inner_mv.field.name] = ::Set.new inner_mv.set_value
101
- end
102
- end
55
+ private
56
+ # Convert the protobuffs response into low-level Ruby objects.
57
+ def rubyfy(response)
58
+ loader = get_loader_for_value response.value
59
+ return nil_rubyfy(response.type) if loader.nil?
103
60
 
104
- return destination
61
+ return loader.rubyfy
105
62
  end
106
63
 
107
64
  # Sometimes a CRDT is empty, provide a sane default.
@@ -30,7 +30,8 @@ module Riak
30
30
  bucket: bucket,
31
31
  key: key,
32
32
  type: bucket_type,
33
- op: serialized
33
+ op: serialized,
34
+ return_body: true,
34
35
  }.merge options
35
36
  request = DtUpdateReq.new args
36
37
  begin
@@ -0,0 +1,19 @@
1
+ class Riak::Client
2
+ include Instrumentable
3
+
4
+ client_payload = {client_id: :client_id}
5
+
6
+ instrument_method :buckets, 'riak.list_buckets', client_payload
7
+ instrument_method :list_buckets, 'riak.list_buckets', client_payload
8
+ instrument_method :list_keys, 'riak.list_keys', client_payload
9
+ instrument_method :set_bucket_props, 'riak.set_bucket_props', client_payload
10
+ instrument_method :get_bucket_props, 'riak.get_bucket_props', client_payload
11
+ instrument_method :clear_bucket_props, 'riak.clear_bucket_props', client_payload
12
+ instrument_method :get_index, 'riak.get_index', client_payload
13
+ instrument_method :store_object, 'riak.store_object', client_payload
14
+ instrument_method :get_object, 'riak.get_object', client_payload
15
+ instrument_method :reload_object, 'riak.reload_object', client_payload
16
+ instrument_method :delete_object, 'riak.delete_object', client_payload
17
+ instrument_method :mapred, 'riak.map_reduce', client_payload
18
+ instrument_method :ping, 'riak.ping', client_payload
19
+ end
@@ -112,9 +112,25 @@ module Riak
112
112
 
113
113
  break if :empty == response
114
114
  @key = response.key if response.key
115
+ response
115
116
  end
116
117
 
117
118
  @dirty = true
119
+ vivify_returnbody(result)
120
+
121
+ return true
122
+ end
123
+
124
+ def vivify_returnbody(result)
125
+ loader do |l|
126
+ specific_loader = l.get_loader_for_value result
127
+
128
+ return false if specific_loader.nil?
129
+
130
+ vivify specific_loader.rubyfy
131
+ @context = result.context unless result.context.nil?
132
+ @dirty = false
133
+ end
118
134
  end
119
135
  end
120
136
  end