better-riak-client 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. data/LICENSE +16 -0
  2. data/README.markdown +198 -0
  3. data/RELEASE_NOTES.md +211 -0
  4. data/better-riak-client.gemspec +61 -0
  5. data/erl_src/riak_kv_test014_backend.beam +0 -0
  6. data/erl_src/riak_kv_test014_backend.erl +189 -0
  7. data/erl_src/riak_kv_test_backend.beam +0 -0
  8. data/erl_src/riak_kv_test_backend.erl +697 -0
  9. data/erl_src/riak_search_test_backend.beam +0 -0
  10. data/erl_src/riak_search_test_backend.erl +175 -0
  11. data/lib/riak/bucket.rb +221 -0
  12. data/lib/riak/client/beefcake/messages.rb +213 -0
  13. data/lib/riak/client/beefcake/object_methods.rb +111 -0
  14. data/lib/riak/client/beefcake_protobuffs_backend.rb +226 -0
  15. data/lib/riak/client/decaying.rb +36 -0
  16. data/lib/riak/client/excon_backend.rb +162 -0
  17. data/lib/riak/client/feature_detection.rb +88 -0
  18. data/lib/riak/client/http_backend/configuration.rb +211 -0
  19. data/lib/riak/client/http_backend/key_streamer.rb +43 -0
  20. data/lib/riak/client/http_backend/object_methods.rb +106 -0
  21. data/lib/riak/client/http_backend/request_headers.rb +34 -0
  22. data/lib/riak/client/http_backend/transport_methods.rb +201 -0
  23. data/lib/riak/client/http_backend.rb +340 -0
  24. data/lib/riak/client/net_http_backend.rb +82 -0
  25. data/lib/riak/client/node.rb +115 -0
  26. data/lib/riak/client/protobuffs_backend.rb +173 -0
  27. data/lib/riak/client/search.rb +91 -0
  28. data/lib/riak/client.rb +540 -0
  29. data/lib/riak/cluster.rb +151 -0
  30. data/lib/riak/core_ext/blank.rb +53 -0
  31. data/lib/riak/core_ext/deep_dup.rb +13 -0
  32. data/lib/riak/core_ext/extract_options.rb +7 -0
  33. data/lib/riak/core_ext/json.rb +15 -0
  34. data/lib/riak/core_ext/slice.rb +18 -0
  35. data/lib/riak/core_ext/stringify_keys.rb +10 -0
  36. data/lib/riak/core_ext/symbolize_keys.rb +10 -0
  37. data/lib/riak/core_ext/to_param.rb +31 -0
  38. data/lib/riak/core_ext.rb +7 -0
  39. data/lib/riak/encoding.rb +6 -0
  40. data/lib/riak/failed_request.rb +81 -0
  41. data/lib/riak/i18n.rb +5 -0
  42. data/lib/riak/json.rb +52 -0
  43. data/lib/riak/link.rb +94 -0
  44. data/lib/riak/locale/en.yml +53 -0
  45. data/lib/riak/locale/fr.yml +52 -0
  46. data/lib/riak/map_reduce/filter_builder.rb +103 -0
  47. data/lib/riak/map_reduce/phase.rb +98 -0
  48. data/lib/riak/map_reduce.rb +225 -0
  49. data/lib/riak/map_reduce_error.rb +7 -0
  50. data/lib/riak/node/configuration.rb +293 -0
  51. data/lib/riak/node/console.rb +133 -0
  52. data/lib/riak/node/control.rb +207 -0
  53. data/lib/riak/node/defaults.rb +83 -0
  54. data/lib/riak/node/generation.rb +106 -0
  55. data/lib/riak/node/log.rb +34 -0
  56. data/lib/riak/node/version.rb +43 -0
  57. data/lib/riak/node.rb +38 -0
  58. data/lib/riak/robject.rb +318 -0
  59. data/lib/riak/search.rb +3 -0
  60. data/lib/riak/serializers.rb +74 -0
  61. data/lib/riak/stamp.rb +77 -0
  62. data/lib/riak/test_server.rb +89 -0
  63. data/lib/riak/util/escape.rb +76 -0
  64. data/lib/riak/util/headers.rb +53 -0
  65. data/lib/riak/util/multipart/stream_parser.rb +62 -0
  66. data/lib/riak/util/multipart.rb +52 -0
  67. data/lib/riak/util/tcp_socket_extensions.rb +58 -0
  68. data/lib/riak/util/translation.rb +19 -0
  69. data/lib/riak/version.rb +3 -0
  70. data/lib/riak/walk_spec.rb +105 -0
  71. data/lib/riak.rb +21 -0
  72. metadata +348 -0
@@ -0,0 +1,151 @@
1
+ require 'pathname'
2
+ require 'riak/node'
3
+ require 'riak/util/translation'
4
+
5
+ module Riak
6
+ # Generates and controls a cluster of {Riak::Node} instances for use
7
+ # in development or testing on a single machine.
8
+ class Cluster
9
+ include Util::Translation
10
+ # @return [Array<Node>] the member Nodes of this cluster
11
+ attr_reader :nodes
12
+
13
+ # @return [Hash] the cluster configuration
14
+ attr_reader :configuration
15
+
16
+ # @return [Pathname] the root directory of the cluster
17
+ attr_reader :root
18
+
19
+ # Creates a {Cluster} of {Node}s.
20
+ # @param [Hash] config the configuration for the cluster
21
+ # @option config [Fixnum] :count the number of nodes to create
22
+ # @option config [String] :source path to the Riak bin/ directory.
23
+ # See {Node#source}.
24
+ # @option config [String] :root path to where the nodes will be
25
+ # generated.
26
+ # @option config [Fixnum] :min_port the base port number from
27
+ # which nodes will claim IP ports for HTTP, PB, handoff.
28
+ def initialize(config={})
29
+ raise ArgumentError, t('source_and_root_required') unless config[:source] && config[:root]
30
+ @configuration = config
31
+ @count = config.delete(:count) || 4
32
+ @min_port = config.delete(:min_port) || 9000
33
+ @root = Pathname.new(config.delete(:root))
34
+ @nodes = []
35
+ cookie = "#{rand(100000).to_s}_#{rand(1000000).to_s}"
36
+ @count.times do |i|
37
+ nodes << Riak::Node.new(config.merge(:min_port => @min_port + (i * 3),
38
+ :root => @root + (i+1).to_s,
39
+ :cookie => cookie))
40
+ end
41
+ end
42
+
43
+ # @return [true,false] whether the cluster has been created
44
+ def exist?
45
+ root.directory? && nodes.all? {|n| n.exist? }
46
+ end
47
+
48
+ # Generates all nodes in the cluster.
49
+ def create
50
+ unless exist?
51
+ root.mkpath unless root.exist?
52
+ nodes.each {|n| n.create }
53
+ end
54
+ end
55
+
56
+ # Removes all nodes in the cluster and the root, and freezes the
57
+ # object.
58
+ def destroy
59
+ nodes.each {|n| n.destroy }
60
+ root.rmtree if root.exist?
61
+ freeze
62
+ end
63
+
64
+ # Removes and recreates the cluster.
65
+ def recreate
66
+ stop unless stopped?
67
+ root.rmtree if root.exist?
68
+ create
69
+ end
70
+
71
+ # Drops all data from the cluster without destroying the nodes.
72
+ def drop
73
+ nodes.each {|n| n.drop }
74
+ end
75
+
76
+ # Starts all nodes in the cluster.
77
+ def start
78
+ nodes.each {|n| n.start }
79
+ end
80
+
81
+ # Stops all nodes in the cluster.
82
+ def stop
83
+ nodes.each {|n| n.stop }
84
+ end
85
+
86
+ # Restarts all nodes in the cluster (without exiting the Erlang
87
+ # runtime)
88
+ def restart
89
+ nodes.each {|n| n.restart }
90
+ end
91
+
92
+ # Reboots all nodes in the cluster
93
+ def reboot
94
+ nodes.each {|n| n.reboot }
95
+ end
96
+
97
+ # Forces the cluster nodes to restart/reload their JavaScript VMs,
98
+ # effectively reloading any user-provided code.
99
+ def js_reload
100
+ nodes.each {|n| n.js_reload }
101
+ end
102
+
103
+ # Attaches to the console on all nodes, returning a list of
104
+ # {Riak::Node::Console} objects.
105
+ # @return [Array<Riak::Node::Console>] consoles for all running
106
+ # nodes, with nil for nodes that aren't running or otherwise
107
+ # fail to connect
108
+ def attach
109
+ nodes.map do |n|
110
+ begin
111
+ n.attach
112
+ rescue ArgumentError, SystemCallError
113
+ nil
114
+ end
115
+ end
116
+ end
117
+
118
+ # Executes the given block on each node against the node's
119
+ # console. You could use this to send Erlang commands to all nodes
120
+ # in the cluster.
121
+ # @yield [console] A block of commands to be run against the
122
+ # console
123
+ # @yieldparam [Riak::Node::Console] console A console manager for
124
+ # sending commands to the current node in the iteration
125
+ def with_console(&block)
126
+ nodes.each do |n|
127
+ n.with_console(&block)
128
+ end
129
+ end
130
+
131
+ # Is the cluster started?
132
+ def started?
133
+ nodes.all? {|n| n.started? }
134
+ end
135
+
136
+ # Is the cluster stopped?
137
+ def stopped?
138
+ nodes.all? {|n| n.stopped? }
139
+ end
140
+
141
+ # Joins the nodes together into a cluster.
142
+ # @note This method relies on cluster membership changes present
143
+ # in the 1.0 series of Riak, and is NOT safe on 0.14 and
144
+ # earlier.
145
+ def join
146
+ claimant = nodes.first.name # Not really the claimant, just a
147
+ # node to join to
148
+ nodes[1..-1].each {|n| n.join(claimant) unless n.peers.include?(claimant) }
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,53 @@
1
+ require 'set'
2
+
3
+ unless Object.new.respond_to? :blank?
4
+ class Object
5
+ def blank?
6
+ false
7
+ end
8
+ end
9
+
10
+ class NilClass
11
+ def blank?
12
+ true
13
+ end
14
+ end
15
+
16
+ class FalseClass
17
+ def blank?
18
+ true
19
+ end
20
+ end
21
+
22
+ class TrueClass
23
+ def blank?
24
+ false
25
+ end
26
+ end
27
+
28
+ class Set
29
+ alias :blank? :empty?
30
+ end
31
+
32
+ class String
33
+ def blank?
34
+ self !~ /[^\s]/
35
+ end
36
+ end
37
+
38
+ class Array
39
+ alias :blank? :empty?
40
+ end
41
+
42
+ class Hash
43
+ alias :blank? :empty?
44
+ end
45
+ end
46
+
47
+ unless Object.new.respond_to? :present?
48
+ class Object
49
+ def present?
50
+ !blank?
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,13 @@
1
+ unless {}.respond_to?(:deep_dup)
2
+ class Hash
3
+ # Returns a deep copy of hash.
4
+ def deep_dup
5
+ duplicate = self.dup
6
+ duplicate.each_pair do |k,v|
7
+ tv = duplicate[k]
8
+ duplicate[k] = tv.is_a?(Hash) && v.is_a?(Hash) ? tv.deep_dup : v
9
+ end
10
+ duplicate
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ unless Array.new.respond_to? :extract_options!
2
+ class Array
3
+ def extract_options!
4
+ last.is_a?(::Hash) ? pop : {}
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,15 @@
1
+ unless Object.new.respond_to?(:to_json)
2
+ # @private
3
+ class Object
4
+ def to_json(*args)
5
+ Riak::JSON.encode(self)
6
+ end
7
+ end
8
+
9
+ # @private
10
+ class Symbol
11
+ def to_json(*args)
12
+ to_s.to_json(*args)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ unless {}.respond_to? :slice
2
+ class Hash
3
+ def slice(*keys)
4
+ allowed = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
5
+ hash = {}
6
+ allowed.each { |k| hash[k] = self[k] if has_key?(k) }
7
+ hash
8
+ end
9
+
10
+ def slice!(*keys)
11
+ keys = keys.map! { |key| convert_key(key) } if respond_to?(:convert_key)
12
+ omit = slice(*self.keys - keys)
13
+ hash = slice(*keys)
14
+ replace(hash)
15
+ omit
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,10 @@
1
+ unless {}.respond_to? :stringify_keys
2
+ class Hash
3
+ def stringify_keys
4
+ inject({}) do |hash, pair|
5
+ hash[pair[0].to_s] = pair[1]
6
+ hash
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ unless {}.respond_to? :symbolize_keys
2
+ class Hash
3
+ def symbolize_keys
4
+ inject({}) do |hash, pair|
5
+ hash[pair[0].to_sym] = pair[1]
6
+ hash
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,31 @@
1
+ unless Object.new.respond_to? :to_query and Object.new.respond_to? :to_param
2
+ class Object
3
+ def to_param
4
+ to_s
5
+ end
6
+
7
+ def to_query(key)
8
+ require 'cgi' unless defined?(CGI) && defined?(CGI::escape)
9
+ "#{CGI.escape(key.to_s)}=#{CGI.escape(to_param.to_s)}"
10
+ end
11
+ end
12
+
13
+ class Array
14
+ def to_param
15
+ map(&:to_param).join('/')
16
+ end
17
+
18
+ def to_query(key)
19
+ prefix = "#{key}[]"
20
+ collect { |value| value.to_query(prefix) }.join '&'
21
+ end
22
+ end
23
+
24
+ class Hash
25
+ def to_param(namespace = nil)
26
+ collect do |key, value|
27
+ value.to_query(namespace ? "#{namespace}[#{key}]" : key)
28
+ end.sort * '&'
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,7 @@
1
+ require 'riak/core_ext/blank'
2
+ require 'riak/core_ext/extract_options'
3
+ require 'riak/core_ext/slice'
4
+ require 'riak/core_ext/stringify_keys'
5
+ require 'riak/core_ext/symbolize_keys'
6
+ require 'riak/core_ext/to_param'
7
+ require 'riak/core_ext/deep_dup'
@@ -0,0 +1,6 @@
1
+ if defined? Encoding
2
+ Encoding.default_internal = "UTF-8" if Encoding.default_internal.nil? ||
3
+ !Encoding.default_internal.ascii_compatible?
4
+ else
5
+ $KCODE = "U"
6
+ end
@@ -0,0 +1,81 @@
1
+
2
+ require 'riak/util/translation'
3
+ require 'riak/json'
4
+
5
+ module Riak
6
+ # Exception raised when receiving an unexpected client response from
7
+ # Riak.
8
+ class FailedRequest < StandardError
9
+ include Util::Translation
10
+
11
+ def initialize(message)
12
+ super(message || t('failed_request'))
13
+ end
14
+ end
15
+
16
+ # Exception raised when the expected HTTP response code from Riak
17
+ # fails to match the actual response code.
18
+ class HTTPFailedRequest < FailedRequest
19
+ # @return [Symbol] the HTTP method, one of :head, :get, :post, :put, :delete
20
+ attr_reader :method
21
+ # @return [Fixnum] the expected response code
22
+ attr_reader :expected
23
+ # @return [Fixnum] the received response code
24
+ attr_reader :code
25
+ # @return [Hash] the response headers
26
+ attr_reader :headers
27
+ # @return [String] the response body, if present
28
+ attr_reader :body
29
+
30
+ def initialize(method, expected_code, received_code, headers, body)
31
+ @method, @expected, @code, @headers, @body = method, expected_code, received_code, headers, body
32
+ super t("http_failed_request", :expected => @expected.inspect, :code => @code, :body => @body)
33
+ end
34
+
35
+ def is_json?
36
+ headers['content-type'].include?('application/json')
37
+ end
38
+
39
+ # @return [true,false] whether the error represents a "not found" response
40
+ def not_found?
41
+ @code.to_i == 404
42
+ end
43
+
44
+ # @return [true,false] whether the error represents an internal
45
+ # server error
46
+ def server_error?
47
+ @code.to_i == 500
48
+ end
49
+ end
50
+
51
+ # Exception raised when receiving an unexpected Protocol Buffers response from Riak
52
+ class ProtobuffsFailedRequest < FailedRequest
53
+ def initialize(code, message)
54
+ super t('protobuffs_failed_request', :code => code, :body => message)
55
+ @original_message = message
56
+ @not_found = code == :not_found
57
+ @server_error = code == :server_error
58
+ end
59
+
60
+ # @return [true, false] whether the error response is in JSON
61
+ def is_json?
62
+ begin
63
+ JSON.parse(original_message)
64
+ true
65
+ rescue
66
+ false
67
+ end
68
+ end
69
+
70
+ # @return [true,false] whether the error represents a "not found" response
71
+ def not_found?
72
+ @not_found
73
+ end
74
+
75
+ # @return [true,false] whether the error represents an internal
76
+ # server error
77
+ def server_error?
78
+ @server_error
79
+ end
80
+ end
81
+ end
data/lib/riak/i18n.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'i18n'
2
+
3
+ Dir.glob(File.expand_path("../locale/*.yml", __FILE__)).each do |locale_file|
4
+ I18n.load_path << locale_file
5
+ end
data/lib/riak/json.rb ADDED
@@ -0,0 +1,52 @@
1
+ require 'multi_json'
2
+ if MultiJson.respond_to?(:adapter)
3
+ MultiJson.adapter
4
+ else
5
+ MultiJson.engine # Force loading of an engine
6
+ end
7
+ require 'riak/core_ext/json'
8
+
9
+ module Riak
10
+ class << self
11
+ # Options that will be passed to the JSON parser and encoder.
12
+ # Defaults to {:max_nesting => 20}
13
+ attr_accessor :json_options
14
+ end
15
+ self.json_options = {:max_nesting => 20}
16
+
17
+ # JSON module for internal use inside riak-client
18
+ module JSON
19
+ class << self
20
+ if MultiJson.respond_to?(:dump) # MultiJson 1.2 or later
21
+ # Parse a JSON string
22
+ # @param [String] str a JSON payload
23
+ # @return [Array,Hash] a Ruby object decoded from the JSON payload
24
+ def parse(str)
25
+ MultiJson.load(str, Riak.json_options)
26
+ end
27
+
28
+ # Generate a JSON string
29
+ # @param [Array, Hash] obj an object to JSON-encode
30
+ # @return [String] a JSON payload
31
+ def encode(obj)
32
+ MultiJson.dump(obj)
33
+ end
34
+ else
35
+ # Parse a JSON string
36
+ # @param [String] str a JSON payload
37
+ # @return [Array,Hash] a Ruby object decoded from the JSON payload
38
+ def parse(str)
39
+ MultiJson.decode(str, Riak.json_options)
40
+ end
41
+
42
+ # Generate a JSON string
43
+ # @param [Array, Hash] obj an object to JSON-encode
44
+ # @return [String] a JSON payload
45
+ def encode(obj)
46
+ MultiJson.encode(obj)
47
+ end
48
+ end
49
+ alias :dump :encode
50
+ end
51
+ end
52
+ end