cassandra-driver 1.0.0.rc.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +8 -8
  2. data/README.md +45 -10
  3. data/lib/cassandra.rb +82 -82
  4. data/lib/cassandra/cluster.rb +3 -0
  5. data/lib/cassandra/cluster/client.rb +17 -5
  6. data/lib/cassandra/{client/connection_manager.rb → cluster/connection_pool.rb} +3 -3
  7. data/lib/cassandra/cluster/connector.rb +101 -30
  8. data/lib/cassandra/cluster/control_connection.rb +6 -7
  9. data/lib/cassandra/{client/null_logger.rb → cluster/failed_connection.rb} +12 -14
  10. data/lib/cassandra/cluster/options.rb +8 -0
  11. data/lib/cassandra/column.rb +5 -0
  12. data/lib/cassandra/driver.rb +3 -3
  13. data/lib/cassandra/errors.rb +5 -5
  14. data/lib/cassandra/execution/options.rb +13 -6
  15. data/lib/cassandra/execution/trace.rb +4 -4
  16. data/lib/cassandra/future.rb +4 -0
  17. data/lib/cassandra/keyspace.rb +5 -0
  18. data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +7 -2
  19. data/lib/cassandra/load_balancing/policies/token_aware.rb +1 -3
  20. data/lib/cassandra/load_balancing/policies/white_list.rb +3 -6
  21. data/lib/cassandra/null_logger.rb +35 -0
  22. data/lib/cassandra/protocol/cql_protocol_handler.rb +4 -0
  23. data/lib/cassandra/protocol/requests/query_request.rb +1 -11
  24. data/lib/cassandra/result.rb +4 -6
  25. data/lib/cassandra/session.rb +3 -0
  26. data/lib/cassandra/statements/prepared.rb +5 -1
  27. data/lib/cassandra/table.rb +5 -0
  28. data/lib/cassandra/util.rb +130 -0
  29. data/lib/cassandra/version.rb +1 -1
  30. metadata +9 -20
  31. data/lib/cassandra/client.rb +0 -144
  32. data/lib/cassandra/client/batch.rb +0 -212
  33. data/lib/cassandra/client/client.rb +0 -591
  34. data/lib/cassandra/client/column_metadata.rb +0 -54
  35. data/lib/cassandra/client/connector.rb +0 -273
  36. data/lib/cassandra/client/execute_options_decoder.rb +0 -59
  37. data/lib/cassandra/client/peer_discovery.rb +0 -50
  38. data/lib/cassandra/client/prepared_statement.rb +0 -314
  39. data/lib/cassandra/client/query_result.rb +0 -230
  40. data/lib/cassandra/client/request_runner.rb +0 -70
  41. data/lib/cassandra/client/result_metadata.rb +0 -48
  42. data/lib/cassandra/client/void_result.rb +0 -78
@@ -1,54 +0,0 @@
1
- # encoding: utf-8
2
-
3
- #--
4
- # Copyright 2013-2014 DataStax, Inc.
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #++
18
-
19
- module Cassandra
20
- module Client
21
- # Represents metadata about a column in a query result set or prepared
22
- # statement. Apart from the keyspace, table and column names there's also
23
- # the type as a symbol (e.g. `:varchar`, `:int`, `:date`).
24
- class ColumnMetadata
25
- attr_reader :keyspace, :table, :column_name, :type
26
-
27
- # @private
28
- def initialize(*args)
29
- @keyspace, @table, @column_name, @type = args
30
- end
31
-
32
- # @private
33
- def to_ary
34
- [@keyspace, @table, @column_name, @type]
35
- end
36
-
37
- def eql?(other)
38
- self.keyspace == other.keyspace && self.table == other.table && self.column_name == other.column_name && self.type == other.type
39
- end
40
- alias_method :==, :eql?
41
-
42
- def hash
43
- @h ||= begin
44
- h = 0
45
- h = ((h & 33554431) * 31) ^ @keyspace.hash
46
- h = ((h & 33554431) * 31) ^ @table.hash
47
- h = ((h & 33554431) * 31) ^ @column_name.hash
48
- h = ((h & 33554431) * 31) ^ @type.hash
49
- h
50
- end
51
- end
52
- end
53
- end
54
- end
@@ -1,273 +0,0 @@
1
- # encoding: utf-8
2
-
3
- #--
4
- # Copyright 2013-2014 DataStax, Inc.
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #++
18
-
19
- module Cassandra
20
- module Client
21
- # @private
22
- class ClusterConnector
23
- def initialize(sequence, logger)
24
- @sequence = sequence
25
- @logger = logger
26
- end
27
-
28
- def connect_all(hosts, connections_per_node)
29
- connections = hosts.flat_map do |host|
30
- Array.new(connections_per_node) do
31
- f = @sequence.connect(host)
32
- f.on_value { |connection| register_logging(connection) }
33
- f.recover do |error|
34
- @logger.warn('Failed connecting to node at %s: %s' % [host, error.message])
35
- FailedConnection.new(error, host)
36
- end
37
- end
38
- end
39
- Ione::Future.all(*connections).map do |connections|
40
- connected_connections = connections.select(&:connected?)
41
- if connected_connections.empty?
42
- error = connections.first.error
43
- raise(error, error.message, error.backtrace)
44
- end
45
- connected_connections
46
- end
47
- end
48
-
49
- private
50
-
51
- def register_logging(connection)
52
- args = [connection[:host_id], connection.host, connection.port, connection[:data_center]]
53
- @logger.info('Connected to node %s at %s:%d in data center %s' % args)
54
- connection.on_closed do |cause|
55
- message = 'Connection to node %s at %s:%d in data center %s closed' % args
56
- if cause
57
- message << (' unexpectedly: %s' % cause.message)
58
- @logger.warn(message)
59
- else
60
- @logger.info(message)
61
- end
62
- end
63
- end
64
- end
65
-
66
- # @private
67
- class Connector
68
- def initialize(steps)
69
- @steps = steps.dup
70
- end
71
-
72
- def connect(host)
73
- pending_connection = PendingConnection.new(host)
74
- seed = Ione::Future.resolved(pending_connection)
75
- f = @steps.reduce(seed) do |chain, step|
76
- chain.flat_map do |pending_connection|
77
- step.run(pending_connection)
78
- end
79
- end
80
- f.map do |pending_connection|
81
- pending_connection.connection
82
- end
83
- end
84
- end
85
-
86
- # @private
87
- class ConnectStep
88
- def initialize(io_reactor, protocol_handler_factory, port, connection_options, logger)
89
- @io_reactor = io_reactor
90
- @protocol_handler_factory = protocol_handler_factory
91
- @port = port
92
- @connection_options = connection_options
93
- @logger = logger
94
- end
95
-
96
- def run(pending_connection)
97
- @io_reactor.connect(pending_connection.host, @port, @connection_options, &@protocol_handler_factory).map do |connection|
98
- pending_connection.with_connection(connection)
99
- end
100
- end
101
- end
102
-
103
- # @private
104
- class CacheOptionsStep
105
- def initialize(timeout = nil)
106
- @timeout = timeout
107
- end
108
-
109
- def run(pending_connection)
110
- f = pending_connection.execute(Protocol::OptionsRequest.new, @timeout)
111
- f.on_value do |supported_options|
112
- pending_connection[:cql_version] = supported_options['CQL_VERSION']
113
- pending_connection[:compression] = supported_options['COMPRESSION']
114
- end
115
-
116
- f.map(pending_connection)
117
- end
118
- end
119
-
120
- # @private
121
- class InitializeStep
122
- def initialize(compressor, logger)
123
- @compressor = compressor
124
- @logger = logger
125
- end
126
-
127
- def run(pending_connection)
128
- compression = @compressor && @compressor.algorithm
129
- supported_algorithms = pending_connection[:compression]
130
- if compression && !supported_algorithms.include?(compression)
131
- @logger.info("Compression with #{compression.inspect} is not supported by host at #{pending_connection.host}, supported algorithms are #{supported_algorithms.inspect}")
132
- compression = nil
133
- end
134
- supported_cql_versions = pending_connection[:cql_version]
135
- cql_version = (supported_cql_versions && !supported_cql_versions.empty?) ? supported_cql_versions.first : '3.1.0'
136
-
137
- f = pending_connection.execute(Protocol::StartupRequest.new(cql_version, compression))
138
- f.map do |startup_response|
139
- if startup_response.is_a?(AuthenticationRequired)
140
- pending_connection.with_authentication_class(startup_response.authentication_class)
141
- else
142
- pending_connection
143
- end
144
- end
145
- end
146
- end
147
-
148
- # @private
149
- class SaslAuthenticationStep
150
- def initialize(auth_provider)
151
- @auth_provider = auth_provider
152
- end
153
-
154
- def run(pending_connection)
155
- if pending_connection.authentication_class
156
- begin
157
- authenticator = @auth_provider && @auth_provider.create_authenticator(pending_connection.authentication_class)
158
- if authenticator
159
- token = authenticator.initial_response
160
- challenge_cycle(pending_connection, authenticator, token)
161
- elsif @auth_provider
162
- Ione::Future.failed(Errors::AuthenticationError.new('Auth provider does not support the required authentication class "%s" and/or protocol version %d' % [pending_connection.authentication_class, @protocol_version]))
163
- else
164
- Ione::Future.failed(Errors::AuthenticationError.new('Server requested authentication, but client was not configured to authenticate'))
165
- end
166
- rescue => e
167
- Ione::Future.failed(Errors::AuthenticationError.new('Auth provider error (%s: %s)' % [e.class.name, e.message]))
168
- end
169
- else
170
- Ione::Future.resolved(pending_connection)
171
- end
172
- end
173
-
174
- def challenge_cycle(pending_connection, authenticator, response_token)
175
- request = Protocol::AuthResponseRequest.new(response_token)
176
- f = pending_connection.execute(request) { |raw_response| raw_response }
177
- f.flat_map do |response|
178
- case response
179
- when Protocol::AuthChallengeResponse
180
- token = authenticator.challenge_response(response.token)
181
- challenge_cycle(pending_connection, authenticator, token)
182
- when Protocol::AuthSuccessResponse
183
- authenticator.authentication_successful(response.token) rescue nil
184
- Ione::Future.resolved(pending_connection)
185
- else
186
- Ione::Future.resolved(pending_connection)
187
- end
188
- end
189
- end
190
- end
191
-
192
- # @private
193
- class CredentialsAuthenticationStep
194
- def initialize(credentials)
195
- @credentials = credentials
196
- end
197
-
198
- def run(pending_connection)
199
- if pending_connection.authentication_class
200
- if @credentials
201
- request = Protocol::CredentialsRequest.new(@credentials)
202
- pending_connection.execute(request).map(pending_connection)
203
- else
204
- Ione::Future.failed(Errors::AuthenticationError.new('Server requested authentication, but client was not configured to authenticate'))
205
- end
206
- else
207
- Ione::Future.resolved(pending_connection)
208
- end
209
- end
210
- end
211
-
212
- # @private
213
- class CachePropertiesStep
214
- def run(pending_connection)
215
- request = Protocol::QueryRequest.new('SELECT data_center, host_id FROM system.local', nil, nil, :one)
216
- f = pending_connection.execute(request)
217
- f.on_value do |result|
218
- unless result.empty?
219
- pending_connection[:host_id] = result.first['host_id']
220
- pending_connection[:data_center] = result.first['data_center']
221
- end
222
- end
223
- f.map(pending_connection)
224
- end
225
- end
226
-
227
- # @private
228
- class PendingConnection
229
- attr_reader :host, :connection, :authentication_class
230
-
231
- def initialize(host, connection=nil, authentication_class=nil)
232
- @host = host
233
- @connection = connection
234
- @authentication_class = authentication_class
235
- @request_runner = RequestRunner.new
236
- end
237
-
238
- def with_connection(connection)
239
- self.class.new(host, connection, @authentication_class)
240
- end
241
-
242
- def with_authentication_class(authentication_class)
243
- self.class.new(host, @connection, authentication_class)
244
- end
245
-
246
- def [](key)
247
- @connection[key]
248
- end
249
-
250
- def []=(key, value)
251
- @connection[key] = value
252
- end
253
-
254
- def execute(request, timeout = nil, &block)
255
- @request_runner.execute(@connection, request, timeout, nil, &block)
256
- end
257
- end
258
-
259
- # @private
260
- class FailedConnection
261
- attr_reader :error, :host
262
-
263
- def initialize(error, host)
264
- @error = error
265
- @host = host
266
- end
267
-
268
- def connected?
269
- false
270
- end
271
- end
272
- end
273
- end
@@ -1,59 +0,0 @@
1
- # encoding: utf-8
2
-
3
- #--
4
- # Copyright 2013-2014 DataStax, Inc.
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #++
18
-
19
- module Cassandra
20
- module Client
21
- # @private
22
- class ExecuteOptionsDecoder
23
- def initialize(default_consistency)
24
- @default_consistency = default_consistency
25
- @default_options = {:consistency => @default_consistency}.freeze
26
- end
27
-
28
- def decode_options(*args)
29
- if args.empty?
30
- @default_options
31
- elsif args.size == 1
32
- decode_one(args.first)
33
- else
34
- args.each_with_object({}) do |options_or_consistency, result|
35
- result.merge!(decode_one(options_or_consistency))
36
- end
37
- end
38
- end
39
-
40
- private
41
-
42
- def decode_one(options_or_consistency)
43
- return @default_options unless options_or_consistency
44
- case options_or_consistency
45
- when Symbol
46
- {:consistency => options_or_consistency}
47
- when Hash
48
- if options_or_consistency.include?(:consistency)
49
- options_or_consistency
50
- else
51
- options = options_or_consistency.dup
52
- options[:consistency] = @default_consistency
53
- options
54
- end
55
- end
56
- end
57
- end
58
- end
59
- end
@@ -1,50 +0,0 @@
1
- # encoding: utf-8
2
-
3
- #--
4
- # Copyright 2013-2014 DataStax, Inc.
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #++
18
-
19
- module Cassandra
20
- module Client
21
- # @private
22
- class PeerDiscovery
23
- def initialize(seed_connections)
24
- @seed_connections = seed_connections
25
- @connection = seed_connections.sample
26
- @request_runner = RequestRunner.new
27
- end
28
-
29
- def new_hosts
30
- request = Protocol::QueryRequest.new('SELECT peer, data_center, host_id, rpc_address FROM system.peers', nil, nil, :one)
31
- response = @request_runner.execute(@connection, request)
32
- response.map do |result|
33
- result.each_with_object([]) do |row, new_peers|
34
- if include?(row['host_id'], row['data_center'])
35
- rpc_address = row['rpc_address'].to_s
36
- rpc_address = row['peer'].to_s if rpc_address == '0.0.0.0'
37
- new_peers << rpc_address
38
- end
39
- end
40
- end
41
- end
42
-
43
- private
44
-
45
- def include?(host_id, dc)
46
- @seed_connections.any? { |c| c[:data_center] == dc } && @seed_connections.none? { |c| c[:host_id] == host_id }
47
- end
48
- end
49
- end
50
- end
@@ -1,314 +0,0 @@
1
- # encoding: utf-8
2
-
3
- #--
4
- # Copyright 2013-2014 DataStax, Inc.
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #++
18
-
19
- module Cassandra
20
- module Client
21
- # A prepared statement are CQL queries that have been sent to the server
22
- # to be precompiled, so that when executed only their ID and not the whole
23
- # CQL string need to be sent. They support bound values, or placeholders
24
- # for values.
25
- #
26
- # Using a prepared statement for any query that you execute more than once
27
- # is highly recommended. Besides the benefit of having less network overhead,
28
- # and less processing overhead on the server side, they don't require you
29
- # to build CQL strings and escape special characters, or format non-character
30
- # data such as UUIDs, different numeric types, or collections, in the
31
- # correct way.
32
- #
33
- # You should only prepare a statement once and reuse the prepared statement
34
- # object every time you want to execute that particular query. The statement
35
- # object will make sure that it is prepared on all connections, and will
36
- # (lazily, but transparently) make sure it is prepared on any new connections.
37
- #
38
- # It is an anti-pattern to prepare the same query over and over again. It is
39
- # bad for performance, since every preparation requires a roundtrip to all
40
- # connected servers, and because of some bookeeping that is done to support
41
- # automatic preparation on new connections, it will lead to unnecessary
42
- # extra memory usage. There is no performance benefit in creating multiple
43
- # prepared statement objects for the same query.
44
- #
45
- # Prepared statement objects are completely thread safe and can be shared
46
- # across all threads in your application.
47
- #
48
- # @see Cassandra::Client::Client#prepare
49
- class PreparedStatement
50
- # Metadata describing the bound values
51
- #
52
- # @return [ResultMetadata]
53
- attr_reader :metadata
54
-
55
- # Metadata about the result (i.e. rows) that is returned when executing
56
- # this prepared statement.
57
- #
58
- # @return [ResultMetadata]
59
- attr_reader :result_metadata
60
-
61
- # Execute the prepared statement with a list of values to be bound to the
62
- # statements parameters.
63
- #
64
- # The number of arguments must equal the number of bound parameters. You
65
- # can also specify options as the last argument, or a symbol as a shortcut
66
- # for just specifying the consistency.
67
- #
68
- # Because you can specify options, or not, there is an edge case where if
69
- # the last parameter of your prepared statement is a map, and you forget
70
- # to specify a value for your map, the options will end up being sent to
71
- # Cassandra. Most other cases when you specify the wrong number of
72
- # arguments should result in an `ArgumentError` or `TypeError` being
73
- # raised.
74
- #
75
- # @example Preparing and executing an `INSERT` statement
76
- # statement = client.prepare(%(INSERT INTO metrics (id, time, value) VALUES (?, NOW(), ?)))
77
- # statement.execute(1234, 23432)
78
- # statement.execute(2345, 34543, tracing: true)
79
- # statement.execute(3456, 45654, consistency: :one)
80
- #
81
- # @example Preparing and executing a `SELECT` statement
82
- # statement = client.prepare(%(SELECT * FROM metrics WHERE id = ? AND time > ?))
83
- # result = statement.execute(1234, Time.now - 3600)
84
- # result.each do |row|
85
- # p row
86
- # end
87
- #
88
- # @param args [Array] the values for the bound parameters, and an optional
89
- # hash of options as last argument – see {Cassandra::Client::Client#execute}
90
- # for details on which options are available.
91
- # @raise [ArgumentError] raised when number of argument does not match
92
- # the number of parameters needed to be bound to the statement.
93
- # @raise [Cassandra::Errors::ClientError] raised when the client is not connected
94
- # @raise [Cassandra::Errors::IoError] raised when there is an IO error, for example
95
- # if the server suddenly closes the connection
96
- # @raise [Cassandra::Errors::QueryError] raised when there is an error on the server side
97
- # @return [nil, Cassandra::Client::QueryResult, Cassandra::Client::VoidResult] Some
98
- # queries have no result and return `nil`, but `SELECT` statements
99
- # return an `Enumerable` of rows (see {Cassandra::Client::QueryResult}), and
100
- # `INSERT` and `UPDATE` return a similar type
101
- # (see {Cassandra::Client::VoidResult}).
102
- def execute(*args)
103
- end
104
-
105
- # Yields a batch when called with a block. The batch is automatically
106
- # executed at the end of the block and the result is returned.
107
- #
108
- # Returns a batch when called wihtout a block. The batch will remember
109
- # the options given and merge these with any additional options given
110
- # when {Cassandra::Client::PreparedStatementBatch#execute} is called.
111
- #
112
- # The batch yielded or returned by this method is not identical to the
113
- # regular batch objects yielded or returned by {Cassandra::Client::Client#batch}.
114
- # These prepared statement batch objects can be used only to add multiple
115
- # executions of the same prepared statement.
116
- #
117
- # Please note that the batch object returned by this method _is not thread
118
- # safe_.
119
- #
120
- # The type parameter can be ommitted and the options can then be given
121
- # as first parameter.
122
- #
123
- # @example Executing a prepared statement in a batch
124
- # statement = client.prepare(%(INSERT INTO metrics (id, time, value) VALUES (?, NOW(), ?)))
125
- # statement.batch do |batch|
126
- # batch.add(1234, 23423)
127
- # batch.add(2346, 13)
128
- # batch.add(2342, 2367)
129
- # batch.add(4562, 1231)
130
- # end
131
- #
132
- # @see Cassandra::Client::PreparedStatementBatch
133
- # @see Cassandra::Client::Client#batch
134
- # @param [Symbol] type the type of batch, must be one of `:logged`,
135
- # `:unlogged` and `:counter`. The precise meaning of these is defined
136
- # in the CQL specification.
137
- # @yieldparam [Cassandra::Client::PreparedStatementBatch] batch the batch
138
- # @return [Cassandra::Client::VoidResult, Cassandra::Client::Batch] when no block is
139
- # given the batch is returned, when a block is given the result of
140
- # executing the batch is returned (see {Cassandra::Client::Batch#execute}).
141
- def batch(type=:logged, options={})
142
- end
143
- end
144
-
145
- # @private
146
- class AsynchronousPreparedStatement < PreparedStatement
147
- # @private
148
- def initialize(cql, execute_options_decoder, connection_manager, logger)
149
- @cql = cql
150
- @execute_options_decoder = execute_options_decoder
151
- @connection_manager = connection_manager
152
- @logger = logger
153
- @request_runner = RequestRunner.new
154
- end
155
-
156
- def self.prepare(cql, execute_options_decoder, connection_manager, logger)
157
- statement = new(cql, execute_options_decoder, connection_manager, logger)
158
- futures = connection_manager.map do |connection|
159
- statement.prepare(connection)
160
- end
161
- Ione::Future.all(*futures).map(statement)
162
- rescue => e
163
- Ione::Future.failed(e)
164
- end
165
-
166
- def execute(*args)
167
- connection = @connection_manager.random_connection
168
- if connection[self]
169
- run(args, connection)
170
- else
171
- prepare(connection).flat_map do
172
- run(args, connection)
173
- end
174
- end
175
- rescue => e
176
- Ione::Future.failed(e)
177
- end
178
-
179
- def batch(type=:logged, options=nil)
180
- if type.is_a?(Hash)
181
- options = type
182
- type = :logged
183
- end
184
- b = AsynchronousBatch.new(type, @execute_options_decoder, @connection_manager, options)
185
- pb = AsynchronousPreparedStatementBatch.new(self, b)
186
- if block_given?
187
- yield pb
188
- pb.execute
189
- else
190
- pb
191
- end
192
- end
193
-
194
- # @private
195
- def prepare(connection)
196
- prepare_request = Protocol::PrepareRequest.new(@cql)
197
- f = @request_runner.execute(connection, prepare_request) do |response|
198
- connection[self] = response.id
199
- unless @raw_metadata
200
- # NOTE: this is not thread safe, but the worst that could happen
201
- # is that we assign the same data multiple times
202
- @raw_metadata = response.metadata
203
- @metadata = ResultMetadata.new(@raw_metadata)
204
- @raw_result_metadata = response.result_metadata
205
- if @raw_result_metadata
206
- @result_metadata = ResultMetadata.new(@raw_result_metadata)
207
- end
208
- end
209
- hex_id = response.id.each_byte.map { |x| x.to_s(16).rjust(2, '0') }.join('')
210
- @logger.debug('Statement %s prepared on node %s (%s:%d)' % [hex_id, connection[:host_id].to_s, connection.host, connection.port])
211
- end
212
- f.map(self)
213
- end
214
-
215
- # @private
216
- def prepared?(connection)
217
- !!connection[self]
218
- end
219
-
220
- # @private
221
- def add_to_batch(batch, connection, bound_args)
222
- statement_id = connection[self]
223
- unless statement_id
224
- raise ::ArgumentError, "Statement was not prepared"
225
- end
226
- unless bound_args.size == @raw_metadata.size
227
- raise ::ArgumentError, "Expected #{@raw_metadata.size} arguments, got #{bound_args.size}"
228
- end
229
- batch.add_prepared(statement_id, @raw_metadata, bound_args)
230
- end
231
-
232
- private
233
-
234
- def run(args, connection)
235
- bound_args = args.shift(@raw_metadata.size)
236
- unless bound_args.size == @raw_metadata.size && args.size <= 1
237
- raise ::ArgumentError, "Expected #{@raw_metadata.size} arguments, got #{bound_args.size}"
238
- end
239
- options = @execute_options_decoder.decode_options(args.last)
240
- statement_id = connection[self]
241
- request_metadata = @raw_result_metadata.nil?
242
- request = Protocol::ExecuteRequest.new(statement_id, @raw_metadata, bound_args, request_metadata, options[:consistency], options[:serial_consistency], options[:page_size], options[:paging_state], options[:trace])
243
- f = @request_runner.execute(connection, request, options[:timeout], @raw_result_metadata)
244
- if options.include?(:page_size)
245
- f = f.map { |result| AsynchronousPreparedPagedQueryResult.new(self, request, result, options) }
246
- end
247
- f
248
- end
249
- end
250
-
251
- # @private
252
- class SynchronousPreparedStatement < PreparedStatement
253
- include SynchronousBacktrace
254
-
255
- def initialize(async_statement)
256
- @async_statement = async_statement
257
- @metadata = async_statement.metadata
258
- @result_metadata = async_statement.result_metadata
259
- end
260
-
261
- def execute(*args)
262
- synchronous_backtrace do
263
- result = @async_statement.execute(*args).value
264
- result = SynchronousPagedQueryResult.new(result) if result.is_a?(PagedQueryResult)
265
- result
266
- end
267
- end
268
-
269
- def batch(type=:logged, options=nil, &block)
270
- if block_given?
271
- synchronous_backtrace { @async_statement.batch(type, options, &block).value }
272
- else
273
- SynchronousPreparedStatementBatch.new(@async_statement.batch(type, options))
274
- end
275
- end
276
-
277
- def pipeline
278
- pl = Pipeline.new(@async_statement)
279
- yield pl
280
- synchronous_backtrace { pl.value }
281
- end
282
-
283
- def async
284
- @async_statement
285
- end
286
-
287
- # @private
288
- def prepared?(connection)
289
- @async_statement.prepared?(connection)
290
- end
291
-
292
- # @private
293
- def add_to_batch(batch, connection, bound_arguments)
294
- @async_statement.add_to_batch(batch, connection, bound_arguments)
295
- end
296
- end
297
-
298
- # @private
299
- class Pipeline
300
- def initialize(async_statement)
301
- @async_statement = async_statement
302
- @futures = []
303
- end
304
-
305
- def execute(*args)
306
- @futures << @async_statement.execute(*args)
307
- end
308
-
309
- def value
310
- Ione::Future.all(*@futures).value
311
- end
312
- end
313
- end
314
- end