riak-client 1.4.5 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (180) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/Gemfile +0 -1
  4. data/{LICENSE → LICENSE.md} +0 -0
  5. data/README.markdown +211 -66
  6. data/RELEASE_NOTES.md +22 -47
  7. data/Rakefile +45 -0
  8. data/lib/riak.rb +1 -1
  9. data/lib/riak/bucket.rb +2 -2
  10. data/lib/riak/client.rb +22 -195
  11. data/lib/riak/client/beefcake/crdt_loader.rb +127 -0
  12. data/lib/riak/client/beefcake/crdt_operator.rb +222 -0
  13. data/lib/riak/client/beefcake/footer +4 -0
  14. data/lib/riak/client/beefcake/header +6 -0
  15. data/lib/riak/client/beefcake/message_codes.rb +29 -0
  16. data/lib/riak/client/beefcake/message_overlay.rb +61 -0
  17. data/lib/riak/client/beefcake/messages.rb +733 -371
  18. data/lib/riak/client/beefcake/object_methods.rb +1 -1
  19. data/lib/riak/client/beefcake/protocol.rb +105 -0
  20. data/lib/riak/client/beefcake/socket.rb +243 -0
  21. data/lib/riak/client/beefcake_protobuffs_backend.rb +262 -122
  22. data/lib/riak/client/node.rb +4 -75
  23. data/lib/riak/client/protobuffs_backend.rb +6 -14
  24. data/lib/riak/client/search.rb +0 -64
  25. data/lib/riak/client/yokozuna.rb +52 -0
  26. data/lib/riak/counter.rb +1 -1
  27. data/lib/riak/crdt.rb +21 -0
  28. data/lib/riak/crdt/base.rb +97 -0
  29. data/lib/riak/crdt/batch_counter.rb +19 -0
  30. data/lib/riak/crdt/batch_map.rb +41 -0
  31. data/lib/riak/crdt/counter.rb +71 -0
  32. data/lib/riak/crdt/inner_counter.rb +74 -0
  33. data/lib/riak/crdt/inner_flag.rb +42 -0
  34. data/lib/riak/crdt/inner_map.rb +53 -0
  35. data/lib/riak/crdt/inner_register.rb +26 -0
  36. data/lib/riak/crdt/inner_set.rb +95 -0
  37. data/lib/riak/crdt/map.rb +88 -0
  38. data/lib/riak/crdt/operation.rb +19 -0
  39. data/lib/riak/crdt/set.rb +156 -0
  40. data/lib/riak/crdt/typed_collection.rb +131 -0
  41. data/lib/riak/errors/base.rb +9 -0
  42. data/lib/riak/errors/connection_error.rb +44 -0
  43. data/lib/riak/errors/crdt_error.rb +18 -0
  44. data/lib/riak/errors/failed_request.rb +56 -0
  45. data/lib/riak/errors/protobuffs_error.rb +11 -0
  46. data/lib/riak/i18n.rb +2 -0
  47. data/lib/riak/json.rb +1 -1
  48. data/lib/riak/locale/en.yml +26 -1
  49. data/lib/riak/locale/fr.yml +0 -1
  50. data/lib/riak/map_reduce.rb +1 -1
  51. data/lib/riak/map_reduce/results.rb +1 -1
  52. data/lib/riak/multiget.rb +1 -2
  53. data/lib/riak/rcontent.rb +8 -3
  54. data/lib/riak/robject.rb +2 -8
  55. data/lib/riak/secondary_index.rb +4 -4
  56. data/lib/riak/serializers.rb +1 -1
  57. data/lib/riak/util/escape.rb +3 -5
  58. data/lib/riak/version.rb +1 -1
  59. data/lib/riak/walk_spec.rb +7 -3
  60. data/riak-client.gemspec +10 -8
  61. data/spec/fixtures/bitcask.txt +25 -0
  62. data/spec/integration/riak/bucket_types_spec.rb +61 -0
  63. data/spec/integration/riak/counters_spec.rb +17 -32
  64. data/spec/integration/riak/crdt_spec.rb +181 -0
  65. data/spec/integration/riak/crdt_validation/map_spec.rb +63 -0
  66. data/spec/integration/riak/crdt_validation/set_spec.rb +122 -0
  67. data/spec/integration/riak/protobuffs_backends_spec.rb +9 -26
  68. data/spec/integration/riak/security_spec.rb +94 -0
  69. data/spec/integration/riak/threading_spec.rb +24 -67
  70. data/spec/integration/yokozuna/index_spec.rb +61 -0
  71. data/spec/integration/yokozuna/queries_spec.rb +116 -0
  72. data/spec/integration/yokozuna/schema_spec.rb +49 -0
  73. data/spec/riak/beefcake_protobuffs_backend/crdt_operator_spec.rb +222 -0
  74. data/spec/riak/beefcake_protobuffs_backend/object_methods_spec.rb +4 -4
  75. data/spec/riak/beefcake_protobuffs_backend/protocol_spec.rb +189 -0
  76. data/spec/riak/beefcake_protobuffs_backend/socket_spec.rb +151 -0
  77. data/spec/riak/beefcake_protobuffs_backend_spec.rb +68 -106
  78. data/spec/riak/bucket_spec.rb +81 -77
  79. data/spec/riak/client_spec.rb +43 -340
  80. data/spec/riak/core_ext/to_param_spec.rb +2 -2
  81. data/spec/riak/counter_spec.rb +20 -20
  82. data/spec/riak/crdt/counter_spec.rb +52 -0
  83. data/spec/riak/crdt/inner_counter_spec.rb +21 -0
  84. data/spec/riak/crdt/inner_flag_spec.rb +39 -0
  85. data/spec/riak/crdt/inner_map_spec.rb +47 -0
  86. data/spec/riak/crdt/inner_register_spec.rb +40 -0
  87. data/spec/riak/crdt/inner_set_spec.rb +33 -0
  88. data/spec/riak/crdt/map_spec.rb +77 -0
  89. data/spec/riak/crdt/set_spec.rb +58 -0
  90. data/spec/riak/crdt/shared_examples.rb +74 -0
  91. data/spec/riak/crdt/typed_collection_spec.rb +231 -0
  92. data/spec/riak/escape_spec.rb +33 -37
  93. data/spec/riak/feature_detection_spec.rb +45 -45
  94. data/spec/riak/index_collection_spec.rb +12 -12
  95. data/spec/riak/link_spec.rb +34 -34
  96. data/spec/riak/list_buckets_spec.rb +7 -7
  97. data/spec/riak/map_reduce/filter_builder_spec.rb +6 -6
  98. data/spec/riak/map_reduce/phase_spec.rb +35 -35
  99. data/spec/riak/map_reduce_spec.rb +89 -87
  100. data/spec/riak/multiget_spec.rb +20 -15
  101. data/spec/riak/node_spec.rb +5 -152
  102. data/spec/riak/robject_spec.rb +95 -108
  103. data/spec/riak/search_spec.rb +17 -139
  104. data/spec/riak/secondary_index_spec.rb +49 -49
  105. data/spec/riak/serializers_spec.rb +9 -9
  106. data/spec/riak/stamp_spec.rb +9 -9
  107. data/spec/riak/walk_spec_spec.rb +46 -46
  108. data/spec/spec_helper.rb +14 -22
  109. data/spec/support/certs/README.md +13 -0
  110. data/spec/support/certs/ca.crt +22 -0
  111. data/spec/support/certs/client.crt +95 -0
  112. data/spec/support/certs/client.key +27 -0
  113. data/spec/support/certs/empty_ca.crt +21 -0
  114. data/spec/support/certs/server.crl +13 -0
  115. data/spec/support/certs/server.crt +95 -0
  116. data/spec/support/certs/server.key +27 -0
  117. data/spec/support/integration_setup.rb +1 -1
  118. data/spec/support/search_corpus_setup.rb +29 -8
  119. data/spec/support/test_client.rb +46 -0
  120. data/spec/support/test_client.yml.example +10 -0
  121. data/spec/support/unified_backend_examples.rb +104 -83
  122. data/spec/support/version_filter.rb +2 -2
  123. data/spec/support/wait_until.rb +14 -0
  124. metadata +134 -132
  125. data/erl_src/riak_kv_test014_backend.beam +0 -0
  126. data/erl_src/riak_kv_test014_backend.erl +0 -189
  127. data/erl_src/riak_kv_test_backend.beam +0 -0
  128. data/erl_src/riak_kv_test_backend.erl +0 -731
  129. data/erl_src/riak_search_test_backend.beam +0 -0
  130. data/erl_src/riak_search_test_backend.erl +0 -175
  131. data/lib/riak/client/excon_backend.rb +0 -172
  132. data/lib/riak/client/http_backend.rb +0 -413
  133. data/lib/riak/client/http_backend/bucket_streamer.rb +0 -15
  134. data/lib/riak/client/http_backend/chunked_json_streamer.rb +0 -42
  135. data/lib/riak/client/http_backend/configuration.rb +0 -227
  136. data/lib/riak/client/http_backend/key_streamer.rb +0 -15
  137. data/lib/riak/client/http_backend/object_methods.rb +0 -114
  138. data/lib/riak/client/http_backend/request_headers.rb +0 -34
  139. data/lib/riak/client/http_backend/transport_methods.rb +0 -201
  140. data/lib/riak/client/instrumentation.rb +0 -25
  141. data/lib/riak/client/net_http_backend.rb +0 -82
  142. data/lib/riak/cluster.rb +0 -151
  143. data/lib/riak/failed_request.rb +0 -81
  144. data/lib/riak/instrumentation.rb +0 -6
  145. data/lib/riak/node.rb +0 -40
  146. data/lib/riak/node/configuration.rb +0 -304
  147. data/lib/riak/node/console.rb +0 -133
  148. data/lib/riak/node/control.rb +0 -207
  149. data/lib/riak/node/defaults.rb +0 -85
  150. data/lib/riak/node/generation.rb +0 -127
  151. data/lib/riak/node/log.rb +0 -34
  152. data/lib/riak/node/version.rb +0 -29
  153. data/lib/riak/search.rb +0 -3
  154. data/lib/riak/test_server.rb +0 -89
  155. data/lib/riak/util/headers.rb +0 -32
  156. data/lib/riak/util/multipart.rb +0 -52
  157. data/lib/riak/util/multipart/stream_parser.rb +0 -62
  158. data/spec/fixtures/munchausen.txt +0 -1033
  159. data/spec/integration/riak/cluster_spec.rb +0 -88
  160. data/spec/integration/riak/http_backends_spec.rb +0 -180
  161. data/spec/integration/riak/node_spec.rb +0 -170
  162. data/spec/integration/riak/test_server_spec.rb +0 -57
  163. data/spec/riak/excon_backend_spec.rb +0 -102
  164. data/spec/riak/headers_spec.rb +0 -21
  165. data/spec/riak/http_backend/configuration_spec.rb +0 -273
  166. data/spec/riak/http_backend/object_methods_spec.rb +0 -243
  167. data/spec/riak/http_backend/transport_methods_spec.rb +0 -97
  168. data/spec/riak/http_backend_spec.rb +0 -367
  169. data/spec/riak/instrumentation_spec.rb +0 -167
  170. data/spec/riak/multipart_spec.rb +0 -23
  171. data/spec/riak/net_http_backend_spec.rb +0 -15
  172. data/spec/riak/stream_parser_spec.rb +0 -53
  173. data/spec/support/drb_mock_server.rb +0 -39
  174. data/spec/support/http_backend_implementation_examples.rb +0 -253
  175. data/spec/support/mock_server.rb +0 -81
  176. data/spec/support/mocks.rb +0 -4
  177. data/spec/support/riak_test.rb +0 -77
  178. data/spec/support/sometimes.rb +0 -46
  179. data/spec/support/test_server.rb +0 -61
  180. data/spec/support/test_server.yml.example +0 -14
@@ -1,81 +0,0 @@
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
@@ -1,6 +0,0 @@
1
- begin
2
- require 'instrumentable'
3
- require 'riak/client/instrumentation'
4
- rescue LoadError => e
5
- # Go quietly into the night...(?)
6
- end
@@ -1,40 +0,0 @@
1
- require 'fileutils'
2
-
3
- require 'riak/util/translation'
4
- require 'riak/node/defaults'
5
- require 'riak/node/configuration'
6
- require 'riak/node/generation'
7
- require 'riak/node/control'
8
- require 'riak/node/version'
9
- require 'riak/node/log'
10
-
11
- module Riak
12
- # A Node encapsulates the generation and management of standalone
13
- # Riak nodes. It is used by the {TestServer} to start and manage an
14
- # in-memory node for supporting integration test suites.
15
- class Node
16
- include Util::Translation
17
-
18
- # Creates a new Riak node. Unlike {#new}, this will also generate
19
- # the node if it does not exist on disk. Equivalent to {::new}
20
- # followed by {#create}.
21
- # @see #new
22
- def self.create(configuration={})
23
- new(configuration).tap do |node|
24
- node.create
25
- end
26
- end
27
-
28
- # Creates the template for a Riak node. To generate the node after
29
- # initialization, use {#create}.
30
- def initialize(configuration={})
31
- set_defaults
32
- configure configuration
33
- end
34
-
35
- protected
36
- def debug(msg)
37
- $stderr.puts msg if ENV["DEBUG_RIAK_NODE"]
38
- end
39
- end
40
- end
@@ -1,304 +0,0 @@
1
- require 'pathname'
2
- require 'yaml'
3
-
4
- module Riak
5
- class Node
6
-
7
- # do not copy these directories to the test node
8
- NODE_DIR_SKIP_LIST = [:data, :pipe]
9
-
10
- # The directories (and accessor methods) that will be created
11
- # under the generated node.
12
- NODE_DIRECTORIES = [:bin, :etc, :log, :data, :pipe]
13
-
14
- # Makes accessor methods for all the node directories that
15
- # return Pathname objects.
16
- NODE_DIRECTORIES.each do |dir|
17
- class_eval %Q{
18
- def #{dir}
19
- root + '#{dir}/'
20
- end
21
- }
22
- end
23
-
24
- # @return [Hash] the contents of the Erlang environment, which will
25
- # be created into the app.config file.
26
- attr_reader :env
27
-
28
- # @return [Hash] the command-line switches for the Erlang virtual
29
- # machine, which will be created into the vm.args file
30
- attr_reader :vm
31
-
32
- # @return [Hash] the configuration that was passed to the Node
33
- # when initialized
34
- attr_reader :configuration
35
-
36
- # @return [Array<Pathname>] where user Erlang code will be loaded from
37
- def erlang_sources
38
- env[:riak_kv][:add_paths].map {|p| Pathname.new(p) }
39
- end
40
-
41
- # @return [Pathname] where user Javascript code will be loaded from
42
- def javascript_source
43
- Pathname.new(env[:riak_kv][:js_source_dir])
44
- end
45
-
46
- # @return [Fixnum] the size of the ring, i.e. number of partitions
47
- def ring_size
48
- env[:riak_core][:ring_creation_size]
49
- end
50
-
51
- # @return [Fixnum] The port used for handing off data to other nodes.
52
- def handoff_port
53
- env[:riak_core][:handoff_port]
54
- end
55
-
56
- # @return [Fixnum] The port to which the HTTP API is connected.
57
- def http_port
58
- # We'll only support 0.14 and later, which uses http rather than web_ip/web_port
59
- env[:riak_core][:http][0][1]
60
- end
61
-
62
- def pb_config_section
63
- return :riak_kv if version < '1.4.0'
64
- return :riak_api
65
- end
66
-
67
- # @return [Fixnum] the port to which the Protocol Buffers API is connected.
68
- def pb_port
69
- env[pb_config_section][:pb_port]
70
- end
71
-
72
- # @return [String] the interface to which the HTTP API is connected
73
- def http_ip
74
- env[:riak_core][:http][0][0]
75
- end
76
-
77
- # @return [String] the interface to which the Protocol Buffers API is connected
78
- def pb_ip
79
- env[pb_config_section][:pb_ip]
80
- end
81
-
82
- # @return [Symbol] the storage backend for Riak Search.
83
- def search_backend
84
- env[:riak_search][:search_backend]
85
- end
86
-
87
- # @return [Symbol] the storage backend for Riak KV.
88
- def kv_backend
89
- env[:riak_kv][:storage_backend]
90
- end
91
-
92
- # @return [String] the name of the Riak node as seen by distributed Erlang
93
- # communication. AKA "-name" in vm.args.
94
- def name
95
- vm['-name']
96
- end
97
-
98
- # @return [String] the cookie/shared secret used for connecting
99
- # a cluster
100
- def cookie
101
- vm['-setcookie']
102
- end
103
-
104
- # The source of the Riak installation from where the {Node} will
105
- # be generated.
106
- # @return [Pathname] the source Riak installation
107
- attr_reader :source
108
-
109
- # The root directory of the {Node}, where all files are placed
110
- # after generation.
111
- # @return [Pathname] the root directory of the node
112
- attr_reader :root
113
-
114
- def env_script
115
- @env_script ||= root + 'lib' + 'env.sh'
116
- end
117
-
118
- # The script for starting, stopping and pinging the Node.
119
- # @return [Pathname] the path to the control script
120
- def control_script
121
- @control_script ||= root + 'bin' + control_script_name
122
- end
123
-
124
- # The name of the 'riak' control script.
125
- def control_script_name
126
- @control_script_name ||= 'riak'
127
- end
128
-
129
- # The script for controlling non-lifecycle features of Riak like
130
- # joining, leaving, status, ringready, etc.
131
- # @return [Pathname] the path to the administrative script
132
- def admin_script
133
- @admin_script ||= root + 'bin' + "#{control_script_name}-admin"
134
- end
135
-
136
- # The "manifest" file where the node configuration will be
137
- # written.
138
- # @return [Pathname] the path to the manifest
139
- def manifest
140
- root + '.node.yml'
141
- end
142
-
143
- protected
144
- # Populates the proper node configuration from the input config.
145
- def configure(hash)
146
- raise ArgumentError, t('source_and_root_required') unless hash[:source] && hash[:root]
147
- @configuration = hash
148
- configure_paths
149
- configure_manifest
150
- configure_settings
151
- configure_logging
152
- configure_data
153
- configure_ports(hash[:interface], hash[:min_port])
154
- configure_name(hash[:interface])
155
- end
156
-
157
- # Reads the manifest if it exists, overrides the passed configuration.
158
- def configure_manifest
159
- @configuration = YAML.load_file(manifest.to_s) if exist?
160
- end
161
-
162
- # Sets the data directories for the various on-disk backends and
163
- # the ring state.
164
- def configure_data
165
- [:bitcask, :eleveldb, :merge_index].each {|k| env[k] ||= {} }
166
- env[:bitcask][:data_root] ||= (data + 'bitcask').expand_path.to_s
167
- env[:eleveldb][:data_root] ||= (data + 'leveldb').expand_path.to_s
168
- env[:merge_index][:data_root] ||= (data + 'merge_index').expand_path.to_s
169
- env[:riak_core][:slide_private_dir] ||= (data + 'slide-data').expand_path.to_s
170
- env[:riak_core][:ring_state_dir] ||= (data + 'ring').expand_path.to_s
171
-
172
- NODE_DIRECTORIES.each do |dir|
173
- env[:riak_core][:"platform_#{dir}_dir"] ||= send(dir).to_s
174
- end
175
- end
176
-
177
- # Sets directories and handlers for logging.
178
- def configure_logging
179
- if env[:lager]
180
- env[:lager][:handlers] = {
181
- :lager_console_backend => :info,
182
- :lager_file_backend => [
183
- Tuple[(log + "error.log").expand_path.to_s, :error],
184
- Tuple[(log + "console.log").expand_path.to_s, :info]
185
- ]
186
- }
187
- env[:lager][:crash_log] = (log + "crash.log").to_s
188
- else
189
- # TODO: Need a better way to detect this, the defaults point
190
- # to 1.0-style configs. Maybe there should be some kind of
191
- # detection routine.
192
- # Use sasl error logger for 0.14.
193
- env[:riak_err] ||= {
194
- :term_max_size => 65536,
195
- :fmt_max_bytes => 65536
196
- }
197
- env[:sasl] = {
198
- :sasl_error_logger => Tuple[:file, (log + "sasl-error.log").expand_path.to_s],
199
- :errlog_type => :error,
200
- :error_logger_mf_dir => (log + "sasl").expand_path.to_s,
201
- :error_logger_mf_maxbytes => 10485760,
202
- :error_logger_mf_maxfiles => 5
203
- }
204
- end
205
- vm['-env ERL_CRASH_DUMP'] = (log + 'erl_crash.dump').to_s
206
- end
207
-
208
- # Sets the node name and cookie for distributed Erlang.
209
- def configure_name(interface)
210
- interface ||= "127.0.0.1"
211
- vm["-name"] ||= configuration[:name] || "riak#{rand(1000000).to_s}@#{interface}"
212
- vm["-setcookie"] ||= configuration[:cookie] || "#{rand(100000).to_s}_#{rand(1000000).to_s}"
213
- end
214
-
215
- # Merges input configuration with the defaults.
216
- def configure_settings
217
- @env = deep_merge(env.dup, configuration[:env]) if configuration[:env]
218
- @vm = vm.merge(configuration[:vm]) if configuration[:vm]
219
- end
220
-
221
- # Sets the source directory and root directory of the generated node.
222
- def configure_paths
223
- @source = Pathname.new(configuration[:source]).expand_path
224
- @root = Pathname.new(configuration[:root]).expand_path
225
- # Systems like Homebrew and Stow symlink the scripts into $PATH,
226
- # but RUNNER_BASE_DIR is not relative to the symlink.
227
- if (@source + control_script_name).symlink?
228
- @source = (@source + control_script_name).realpath.parent
229
- end
230
- end
231
-
232
- # Sets ports and interfaces for http, protocol buffers, and handoff.
233
- def configure_ports(interface, min_port)
234
- interface ||= "127.0.0.1"
235
- min_port ||= 8080
236
- unless env[:riak_core][:http]
237
- env[:riak_core][:http] = [Tuple[interface, min_port]]
238
- min_port += 1
239
- end
240
- env[:riak_core][:http] = env[:riak_core][:http].map {|pair| Tuple[*pair] }
241
- env[pb_config_section][:pb_ip] = interface unless env[pb_config_section][:pb_ip]
242
- unless env[pb_config_section][:pb_port]
243
- env[pb_config_section][:pb_port] = min_port
244
- min_port += 1
245
- end
246
- unless env[:riak_core][:handoff_port]
247
- env[:riak_core][:handoff_port] = min_port
248
- min_port += 1
249
- end
250
- end
251
-
252
- # Implements a deep-merge of two {Hash} instances.
253
- # @param [Hash] source the original hash
254
- # @param [Hash] target the new hash
255
- # @return [Hash] a {Hash} whose {Hash} values have also been merged
256
- def deep_merge(source, target)
257
- source.merge(target) do |key, old_val, new_val|
258
- if Hash === old_val && Hash === new_val
259
- deep_merge(old_val, new_val)
260
- else
261
- new_val
262
- end
263
- end
264
- end
265
-
266
- # This class lets us specify that some settings should be emitted
267
- # as Erlang tuples, even though the first element is not
268
- # necessarily a Symbol.
269
- class Tuple < Array; end
270
-
271
- # Recursively converts a {Hash} into an Erlang configuration
272
- # string that is appropriate for the app.config file.
273
- # @param [Hash] hash a collection of configuration values
274
- # @param [Fixnum] depth the current nesting level of
275
- # generation/indentation
276
- # @return [String] Erlang proplists in a String for use in
277
- # app.config
278
- def to_erlang_config(hash, depth = 1)
279
- padding = ' ' * depth
280
- parent_padding = ' ' * (depth-1)
281
- values = hash.map do |k,v|
282
- "{#{k}, #{value_to_erlang(v, depth)}}"
283
- end.join(",\n#{padding}")
284
- "[\n#{padding}#{values}\n#{parent_padding}]"
285
- end
286
-
287
- # Converts a value to an Erlang term. Mutually recursive with
288
- # {#to_erlang_config}.
289
- def value_to_erlang(v, depth=1)
290
- case v
291
- when Hash
292
- to_erlang_config(v, depth+1)
293
- when String
294
- "\"#{v}\""
295
- when Tuple
296
- "{" << v.map {|i| value_to_erlang(i, depth+1) }.join(", ") << "}"
297
- when Array
298
- "[" << v.map {|i| value_to_erlang(i, depth+1) }.join(", ") << "]"
299
- else
300
- v.to_s
301
- end
302
- end
303
- end
304
- end
@@ -1,133 +0,0 @@
1
- require 'expect'
2
- require 'pathname'
3
- require 'riak/util/translation'
4
-
5
- if ENV['DEBUG_RIAK_CONSOLE']
6
- $expect_verbose = true
7
- end
8
-
9
- module Riak
10
- class Node
11
- # Eases working with the Erlang console when attached to the Riak
12
- # node.
13
- class Console
14
- include Util::Translation
15
-
16
- # @return [String] the name of the connected node
17
- attr_accessor :nodename
18
-
19
- # Opens a {Console} by connecting to the node.
20
- # @return [Console] the opened console
21
- def self.open(node)
22
- new node.pipe, node.name
23
- end
24
-
25
- # Creates a {Console} from the IO pipes connected to the node.
26
- # @param [String,Pathname] pipedir path to the pipes opened by
27
- # run_erl
28
- # @param [String] nodename the name of the node the Console will
29
- # be attached to
30
- def initialize(pipedir, nodename)
31
- @nodename = nodename
32
- @mutex = Mutex.new
33
- @prompt = /\(#{Regexp.escape(nodename)}\)\d+>\s*/
34
- pipedir = Pathname(pipedir)
35
- pipedir.children.each do |path|
36
- if path.pipe?
37
- if path.fnmatch("*.r") # Read pipe
38
- # debug "Found read pipe: #{path}"
39
- @rfile ||= path
40
- elsif path.fnmatch("*.w") # Write pipe
41
- # debug "Found write pipe: #{path}"
42
- @wfile ||= path
43
- end
44
- else
45
- debug "Non-pipe found! #{path}"
46
- end
47
- end
48
- raise ArgumentError, t('no_pipes', :path => pipedir.to_s) if [@rfile, @wfile].any? {|p| p.nil? }
49
-
50
- begin
51
- debug "Opening write pipe."
52
- @w = open_write_pipe
53
- @w.sync = true
54
- read_ready = false
55
- # Using threads, we get around JRuby's blocking-open
56
- # behavior. The main thread pumps the write pipe full of
57
- # data so that run_erl will start echoing it into the read
58
- # pipe once we have started the open. On non-JVM rubies,
59
- # O_NONBLOCK works and we proceed as expected.
60
- Thread.new do
61
- debug "Opening read pipe."
62
- @r = open_read_pipe
63
- read_ready = true
64
- end
65
- Thread.pass
66
- @w.print "\n" until read_ready
67
- command "ok."
68
- debug "Initialized console: #{@r.inspect} #{@w.inspect}"
69
- rescue => e
70
- debug e.message
71
- close
72
- raise t('no_pipes', :path => pipedir.to_s) + "[ #{e.message} ]"
73
- end
74
- end
75
-
76
- # Sends an Erlang command to the console
77
- # @param [String] cmd an Erlang expression to send to the node
78
- def command(cmd)
79
- @mutex.synchronize do
80
- begin
81
- debug "Sending command #{cmd.inspect}"
82
- @w.print "#{cmd}\n"
83
- wait_for_erlang_prompt
84
- rescue SystemCallError
85
- close
86
- end
87
- end
88
- end
89
-
90
- # Detects whether the console connection is still open, that is,
91
- # if the node hasn't disconnected from the other side of the
92
- # pipe.
93
- def open?
94
- (@r && !@r.closed?) && (@w && !@w.closed?)
95
- end
96
-
97
- # Scans the output of the console until an Erlang shell prompt
98
- # is found. Called by {#command} to ensure that the submitted
99
- # command succeeds.
100
- def wait_for_erlang_prompt
101
- wait_for @prompt
102
- end
103
-
104
- # Scans the output of the console for the given pattern.
105
- # @param [String, Regexp] pattern the pattern to scan for
106
- def wait_for(pattern)
107
- debug "Scanning for #{pattern.inspect}"
108
- @r.expect(pattern)
109
- end
110
-
111
- # Closes the console by detaching from the pipes.
112
- def close
113
- @r.close if @r && !@r.closed?
114
- @w.close if @w && !@w.closed?
115
- freeze
116
- end
117
-
118
- protected
119
-
120
- def debug(msg)
121
- $stderr.puts msg if ENV["DEBUG_RIAK_CONSOLE"]
122
- end
123
-
124
- def open_write_pipe
125
- @wfile.open(File::WRONLY|File::NONBLOCK)
126
- end
127
-
128
- def open_read_pipe
129
- @rfile.open(File::RDONLY|File::NONBLOCK)
130
- end
131
- end
132
- end
133
- end