riak-client 2.4.1 → 2.5.0

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