cassandra-driver 1.0.0.rc.1-java → 1.1.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +58 -18
- data/lib/cassandra.rb +132 -93
- data/lib/cassandra/auth.rb +3 -3
- data/lib/cassandra/cluster.rb +65 -39
- data/lib/cassandra/cluster/client.rb +67 -28
- data/lib/cassandra/{client/connection_manager.rb → cluster/connection_pool.rb} +9 -3
- data/lib/cassandra/cluster/connector.rb +101 -30
- data/lib/cassandra/cluster/control_connection.rb +160 -96
- data/lib/cassandra/{client/null_logger.rb → cluster/failed_connection.rb} +12 -14
- data/lib/cassandra/cluster/options.rb +26 -11
- data/lib/cassandra/cluster/schema.rb +22 -1
- data/lib/cassandra/column.rb +5 -0
- data/lib/cassandra/driver.rb +46 -12
- data/lib/cassandra/errors.rb +5 -5
- data/lib/cassandra/execution/options.rb +42 -8
- data/lib/cassandra/execution/trace.rb +4 -4
- data/lib/cassandra/executors.rb +111 -0
- data/lib/cassandra/future.rb +88 -64
- data/lib/cassandra/keyspace.rb +12 -0
- data/lib/cassandra/load_balancing.rb +10 -0
- data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +10 -5
- data/lib/cassandra/load_balancing/policies/round_robin.rb +7 -5
- data/lib/cassandra/load_balancing/policies/token_aware.rb +31 -10
- data/lib/cassandra/load_balancing/policies/white_list.rb +4 -7
- data/lib/cassandra/null_logger.rb +35 -0
- data/lib/cassandra/protocol/cql_protocol_handler.rb +8 -1
- data/lib/cassandra/protocol/requests/query_request.rb +1 -11
- data/lib/cassandra/result.rb +34 -9
- data/lib/cassandra/session.rb +6 -0
- data/lib/cassandra/statements/prepared.rb +5 -1
- data/lib/cassandra/table.rb +5 -0
- data/lib/cassandra/util.rb +130 -0
- data/lib/cassandra/version.rb +1 -1
- metadata +40 -50
- data/lib/cassandra/client.rb +0 -144
- data/lib/cassandra/client/batch.rb +0 -212
- data/lib/cassandra/client/client.rb +0 -591
- data/lib/cassandra/client/column_metadata.rb +0 -54
- data/lib/cassandra/client/connector.rb +0 -273
- data/lib/cassandra/client/execute_options_decoder.rb +0 -59
- data/lib/cassandra/client/peer_discovery.rb +0 -50
- data/lib/cassandra/client/prepared_statement.rb +0 -314
- data/lib/cassandra/client/query_result.rb +0 -230
- data/lib/cassandra/client/request_runner.rb +0 -70
- data/lib/cassandra/client/result_metadata.rb +0 -48
- data/lib/cassandra/client/void_result.rb +0 -78
data/lib/cassandra/client.rb
DELETED
@@ -1,144 +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
|
-
# A CQL client manages connections to one or more Cassandra nodes and you use
|
21
|
-
# it run queries, insert and update data.
|
22
|
-
#
|
23
|
-
# Client instances are threadsafe.
|
24
|
-
#
|
25
|
-
# See {Cassandra::Client::Client} for the full client API, or {Cassandra::Client.connect}
|
26
|
-
# for the options available when connecting.
|
27
|
-
#
|
28
|
-
# @example Connecting and changing to a keyspace
|
29
|
-
# # create a client and connect to two Cassandra nodes
|
30
|
-
# client = Cassandra::Client.connect(hosts: %w[node01.cassandra.local node02.cassandra.local])
|
31
|
-
# # change to a keyspace
|
32
|
-
# client.use('stuff')
|
33
|
-
#
|
34
|
-
# @example Query for data
|
35
|
-
# rows = client.execute('SELECT * FROM things WHERE id = 2')
|
36
|
-
# rows.each do |row|
|
37
|
-
# p row
|
38
|
-
# end
|
39
|
-
#
|
40
|
-
# @example Inserting and updating data
|
41
|
-
# client.execute("INSERT INTO things (id, value) VALUES (4, 'foo')")
|
42
|
-
# client.execute("UPDATE things SET value = 'bar' WHERE id = 5")
|
43
|
-
#
|
44
|
-
# @example Prepared statements
|
45
|
-
# statement = client.prepare('INSERT INTO things (id, value) VALUES (?, ?)')
|
46
|
-
# statement.execute(9, 'qux')
|
47
|
-
# statement.execute(8, 'baz')
|
48
|
-
# @private
|
49
|
-
module Client
|
50
|
-
InvalidKeyspaceNameError = Class.new(Errors::ClientError)
|
51
|
-
|
52
|
-
# @private
|
53
|
-
module SynchronousBacktrace
|
54
|
-
def synchronous_backtrace
|
55
|
-
yield
|
56
|
-
rescue Error => e
|
57
|
-
new_backtrace = caller
|
58
|
-
if new_backtrace.first.include?(SYNCHRONOUS_BACKTRACE_METHOD_NAME)
|
59
|
-
new_backtrace = new_backtrace.drop(1)
|
60
|
-
end
|
61
|
-
e.set_backtrace(new_backtrace)
|
62
|
-
raise
|
63
|
-
end
|
64
|
-
|
65
|
-
private
|
66
|
-
|
67
|
-
SYNCHRONOUS_BACKTRACE_METHOD_NAME = 'synchronous_backtrace'
|
68
|
-
end
|
69
|
-
|
70
|
-
# Create a new client and connect to Cassandra.
|
71
|
-
#
|
72
|
-
# By default the client will connect to localhost port 9042, which can be
|
73
|
-
# overridden with the `:hosts` and `:port` options, respectively. Once
|
74
|
-
# connected to the hosts given in `:hosts` the rest of the nodes in the
|
75
|
-
# cluster will automatically be discovered and connected to.
|
76
|
-
#
|
77
|
-
# If you have a multi data center setup the client will connect to all nodes
|
78
|
-
# in the data centers where the nodes you pass to `:hosts` are located. So
|
79
|
-
# if you only want to connect to nodes in one data center, make sure that
|
80
|
-
# you only specify nodes in that data center in `:hosts`.
|
81
|
-
#
|
82
|
-
# The connection will succeed if at least one node is up and accepts the
|
83
|
-
# connection. Nodes that don't respond within the specified timeout, or
|
84
|
-
# where the connection initialization fails for some reason, are ignored.
|
85
|
-
#
|
86
|
-
# @param [Hash] options
|
87
|
-
# @option options [Array<String>] :hosts (['localhost']) One or more
|
88
|
-
# hostnames used as seed nodes when connecting. Duplicates will be removed.
|
89
|
-
# @option options [String] :port (9042) The port to connect to, this port
|
90
|
-
# will be used for all nodes. Because the `system.peers` table does not
|
91
|
-
# contain the port that the nodes are listening on, the port must be the
|
92
|
-
# same for all nodes.
|
93
|
-
# @option options [Integer] :connection_timeout (5) Max time to wait for a
|
94
|
-
# connection, in seconds.
|
95
|
-
# @option options [String] :keyspace The keyspace to change to immediately
|
96
|
-
# after all connections have been established, this is optional.
|
97
|
-
# @option options [Hash] :credentials When using Cassandra's built in
|
98
|
-
# authentication you can provide your username and password through this
|
99
|
-
# option. Example: `:credentials => {:username => 'cassandra', :password => 'cassandra'}`
|
100
|
-
# @option options [Object] :auth_provider When using custom authentication
|
101
|
-
# use this option to specify the auth provider that will handle the
|
102
|
-
# authentication negotiation. See {Cassandra::Client::AuthProvider} for more info.
|
103
|
-
# @option options [Integer] :connections_per_node (1) The number of
|
104
|
-
# connections to open to each node. Each connection can have 128
|
105
|
-
# concurrent requests, so unless you have a need for more than that (times
|
106
|
-
# the number of nodes in your cluster), leave this option at its default.
|
107
|
-
# @option options [Integer] :default_consistency (:quorum) The consistency
|
108
|
-
# to use unless otherwise specified. Consistency can also be specified on
|
109
|
-
# a per-request basis.
|
110
|
-
# @option options [Cassandra::Compression::Compressor] :compressor An object that
|
111
|
-
# can compress and decompress frames. By specifying this option frame
|
112
|
-
# compression will be enabled. If the server does not support compression
|
113
|
-
# or the specific compression algorithm specified by the compressor,
|
114
|
-
# compression will not be enabled and a warning will be logged.
|
115
|
-
# @option options [String] :cql_version Specifies which CQL version the
|
116
|
-
# server should expect.
|
117
|
-
# @option options [Integer] :logger If you want the client to log
|
118
|
-
# significant events pass an object implementing the standard Ruby logger
|
119
|
-
# interface (e.g. quacks like `Logger` from the standard library) with
|
120
|
-
# this option.
|
121
|
-
# @raise [Cassandra::Errors::IOError] when a connection couldn't be established
|
122
|
-
# to any node
|
123
|
-
# @raise [Cassandra::Errors::ExecutionError] when the specified keyspace does not exist
|
124
|
-
# or when the specifed CQL version is not supported.
|
125
|
-
# @return [Cassandra::Client::Client]
|
126
|
-
def self.connect(options={})
|
127
|
-
SynchronousClient.new(AsynchronousClient.new(options)).connect
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
require 'cassandra/client/connection_manager'
|
133
|
-
require 'cassandra/client/connector'
|
134
|
-
require 'cassandra/client/null_logger'
|
135
|
-
require 'cassandra/client/column_metadata'
|
136
|
-
require 'cassandra/client/result_metadata'
|
137
|
-
require 'cassandra/client/execute_options_decoder'
|
138
|
-
require 'cassandra/client/client'
|
139
|
-
require 'cassandra/client/prepared_statement'
|
140
|
-
require 'cassandra/client/batch'
|
141
|
-
require 'cassandra/client/query_result'
|
142
|
-
require 'cassandra/client/void_result'
|
143
|
-
require 'cassandra/client/request_runner'
|
144
|
-
require 'cassandra/client/peer_discovery'
|
@@ -1,212 +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
|
-
# Batches let you send multiple queries (`INSERT`, `UPDATE` and `DELETE`) in
|
22
|
-
# one go. This can lead to better performance, and depending on the options
|
23
|
-
# you specify can also give you different consistency guarantees.
|
24
|
-
#
|
25
|
-
# Batches can contain a mix of different queries and prepared statements.
|
26
|
-
#
|
27
|
-
# @see Cassandra::Client::Client#batch
|
28
|
-
class Batch
|
29
|
-
# @!method add(cql_or_prepared_statement, *bound_values)
|
30
|
-
#
|
31
|
-
# Add a query or a prepared statement to the batch.
|
32
|
-
#
|
33
|
-
# @example Adding a mix of statements to a batch
|
34
|
-
# batch.add(%(UPDATE people SET name = 'Miriam' WHERE id = 3435))
|
35
|
-
# batch.add(%(UPDATE people SET name = ? WHERE id = ?), 'Miriam', 3435)
|
36
|
-
# batch.add(prepared_statement, 'Miriam', 3435)
|
37
|
-
#
|
38
|
-
# @param [String, Cassandra::Client::PreparedStatement] cql_or_prepared_statement
|
39
|
-
# a CQL string or a prepared statement object (obtained through
|
40
|
-
# {Cassandra::Client::Client#prepare})
|
41
|
-
# @param [Array] bound_values a list of bound values -- only applies when
|
42
|
-
# adding prepared statements and when there are binding markers in the
|
43
|
-
# given CQL. If the last argument is a hash and it has the key
|
44
|
-
# `:type_hints` this will be passed as type hints to the request encoder
|
45
|
-
# (if the last argument is any other hash it will be assumed to be a
|
46
|
-
# bound value of type MAP). See {Cassandra::Client::Client#execute} for more
|
47
|
-
# info on type hints.
|
48
|
-
# @return [nil]
|
49
|
-
|
50
|
-
# @!method execute(options={})
|
51
|
-
#
|
52
|
-
# Execute the batch and return the result.
|
53
|
-
#
|
54
|
-
# @param [Hash] options an options hash or a symbol (as a shortcut for
|
55
|
-
# specifying the consistency), see {Cassandra::Client::Client#execute} for
|
56
|
-
# full details about how this value is interpreted.
|
57
|
-
# @raise [Cassandra::Errors::ExecutionError] raised when there is an error on the server side
|
58
|
-
# @raise [Cassandra::Errors::NotPreparedError] raised in the unlikely event that a
|
59
|
-
# prepared statement was not prepared on the chosen connection
|
60
|
-
# @return [Cassandra::Client::VoidResult] a batch always returns a void result
|
61
|
-
end
|
62
|
-
|
63
|
-
# A convenient wrapper that makes it easy to build batches of multiple
|
64
|
-
# executions of the same prepared statement.
|
65
|
-
#
|
66
|
-
# @see Cassandra::Client::PreparedStatement#batch
|
67
|
-
class PreparedStatementBatch
|
68
|
-
# @!method add(*bound_values)
|
69
|
-
#
|
70
|
-
# Add the statement to the batch with the specified bound values.
|
71
|
-
#
|
72
|
-
# @param [Array] bound_values the values to bind to the added statement,
|
73
|
-
# see {Cassandra::Client::PreparedStatement#execute}.
|
74
|
-
# @return [nil]
|
75
|
-
|
76
|
-
# @!method execute(options={})
|
77
|
-
#
|
78
|
-
# Execute the batch and return the result.
|
79
|
-
#
|
80
|
-
# @raise [Cassandra::Errors::ExecutionError] raised when there is an error on the server side
|
81
|
-
# @raise [Cassandra::Errors::NotPreparedError] raised in the unlikely event that a
|
82
|
-
# prepared statement was not prepared on the chosen connection
|
83
|
-
# @return [Cassandra::Client::VoidResult] a batch always returns a void result
|
84
|
-
end
|
85
|
-
|
86
|
-
# @private
|
87
|
-
class AsynchronousBatch < Batch
|
88
|
-
def initialize(type, execute_options_decoder, connection_manager, options=nil)
|
89
|
-
raise ::ArgumentError, "Unknown batch type: #{type}" unless BATCH_TYPES.include?(type)
|
90
|
-
@type = type
|
91
|
-
@execute_options_decoder = execute_options_decoder
|
92
|
-
@connection_manager = connection_manager
|
93
|
-
@options = options
|
94
|
-
@request_runner = RequestRunner.new
|
95
|
-
@parts = []
|
96
|
-
end
|
97
|
-
|
98
|
-
def add(*args)
|
99
|
-
@parts << args
|
100
|
-
nil
|
101
|
-
end
|
102
|
-
|
103
|
-
def execute(options=nil)
|
104
|
-
options = @execute_options_decoder.decode_options(@options, options)
|
105
|
-
connection = @connection_manager.random_connection
|
106
|
-
request = Protocol::BatchRequest.new(BATCH_TYPES[@type], options[:consistency], options[:trace])
|
107
|
-
unprepared_statements = nil
|
108
|
-
@parts.each do |part, *bound_args|
|
109
|
-
if part.is_a?(String) || part.prepared?(connection)
|
110
|
-
add_part(connection, request, part, bound_args)
|
111
|
-
else
|
112
|
-
unprepared_statements ||= []
|
113
|
-
unprepared_statements << [part, bound_args]
|
114
|
-
end
|
115
|
-
end
|
116
|
-
@parts = []
|
117
|
-
if unprepared_statements.nil?
|
118
|
-
@request_runner.execute(connection, request, options[:timeout])
|
119
|
-
else
|
120
|
-
fs = unprepared_statements.map do |statement, _|
|
121
|
-
if statement.respond_to?(:async)
|
122
|
-
statement.async.prepare(connection)
|
123
|
-
else
|
124
|
-
statement.prepare(connection)
|
125
|
-
end
|
126
|
-
end
|
127
|
-
Ione::Future.all(*fs).flat_map do
|
128
|
-
unprepared_statements.each do |statement, bound_args|
|
129
|
-
add_part(connection, request, statement, bound_args)
|
130
|
-
end
|
131
|
-
@request_runner.execute(connection, request, options[:timeout])
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
private
|
137
|
-
|
138
|
-
BATCH_TYPES = {
|
139
|
-
:logged => Protocol::BatchRequest::LOGGED_TYPE,
|
140
|
-
:unlogged => Protocol::BatchRequest::UNLOGGED_TYPE,
|
141
|
-
:counter => Protocol::BatchRequest::COUNTER_TYPE,
|
142
|
-
}.freeze
|
143
|
-
|
144
|
-
def add_part(connection, request, part, bound_args)
|
145
|
-
if part.is_a?(String)
|
146
|
-
type_hints = nil
|
147
|
-
if bound_args.last.is_a?(Hash) && bound_args.last.include?(:type_hints)
|
148
|
-
bound_args = bound_args.dup
|
149
|
-
type_hints = bound_args.pop[:type_hints]
|
150
|
-
end
|
151
|
-
request.add_query(part, bound_args, type_hints)
|
152
|
-
else
|
153
|
-
part.add_to_batch(request, connection, bound_args)
|
154
|
-
end
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
# @private
|
159
|
-
class SynchronousBatch < Batch
|
160
|
-
include SynchronousBacktrace
|
161
|
-
|
162
|
-
def initialize(asynchronous_batch)
|
163
|
-
@asynchronous_batch = asynchronous_batch
|
164
|
-
end
|
165
|
-
|
166
|
-
def async
|
167
|
-
@asynchronous_batch
|
168
|
-
end
|
169
|
-
|
170
|
-
def add(*args)
|
171
|
-
@asynchronous_batch.add(*args)
|
172
|
-
end
|
173
|
-
|
174
|
-
def execute(options=nil)
|
175
|
-
synchronous_backtrace { @asynchronous_batch.execute(options).value }
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
# @private
|
180
|
-
class AsynchronousPreparedStatementBatch < PreparedStatementBatch
|
181
|
-
def initialize(prepared_statement, batch)
|
182
|
-
@prepared_statement = prepared_statement
|
183
|
-
@batch = batch
|
184
|
-
end
|
185
|
-
|
186
|
-
def add(*args)
|
187
|
-
@batch.add(@prepared_statement, *args)
|
188
|
-
end
|
189
|
-
|
190
|
-
def execute(options=nil)
|
191
|
-
@batch.execute(options)
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
|
-
# @private
|
196
|
-
class SynchronousPreparedStatementBatch < PreparedStatementBatch
|
197
|
-
include SynchronousBacktrace
|
198
|
-
|
199
|
-
def initialize(asynchronous_batch)
|
200
|
-
@asynchronous_batch = asynchronous_batch
|
201
|
-
end
|
202
|
-
|
203
|
-
def add(*args)
|
204
|
-
@asynchronous_batch.add(*args)
|
205
|
-
end
|
206
|
-
|
207
|
-
def execute(options=nil)
|
208
|
-
synchronous_backtrace { @asynchronous_batch.execute(options).value }
|
209
|
-
end
|
210
|
-
end
|
211
|
-
end
|
212
|
-
end
|
@@ -1,591 +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 CQL client manages connections to one or more Cassandra nodes and you use
|
22
|
-
# it run queries, insert and update data, prepare statements and switch
|
23
|
-
# keyspaces.
|
24
|
-
#
|
25
|
-
# To get a reference to a client you call {Cassandra::Client.connect}. When you
|
26
|
-
# don't need the client anymore you can call {#close} to close all connections.
|
27
|
-
#
|
28
|
-
# Internally the client runs an IO reactor in a background thread. The reactor
|
29
|
-
# handles all IO and manages the connections to the Cassandra nodes. This
|
30
|
-
# makes it possible for the client to handle highly concurrent applications
|
31
|
-
# very efficiently.
|
32
|
-
#
|
33
|
-
# Client instances are threadsafe and you only need a single instance for in
|
34
|
-
# an application. Using multiple instances is more likely to lead to worse
|
35
|
-
# performance than better.
|
36
|
-
#
|
37
|
-
# Because the client opens sockets, and runs threads it cannot be used by
|
38
|
-
# the child created when forking a process. If your application forks (for
|
39
|
-
# example applications running in the Unicorn application server or Resque
|
40
|
-
# task queue) you _must_ connect after forking.
|
41
|
-
#
|
42
|
-
# @see Cassandra::Client.connect
|
43
|
-
class Client
|
44
|
-
# @!method close
|
45
|
-
#
|
46
|
-
# Disconnect from all nodes.
|
47
|
-
#
|
48
|
-
# @return [Cassandra::Client]
|
49
|
-
|
50
|
-
# @!method connected?
|
51
|
-
#
|
52
|
-
# Returns whether or not the client is connected.
|
53
|
-
#
|
54
|
-
# @return [true, false]
|
55
|
-
|
56
|
-
# @!method keyspace
|
57
|
-
#
|
58
|
-
# Returns the name of the current keyspace, or `nil` if no keyspace has been
|
59
|
-
# set yet.
|
60
|
-
#
|
61
|
-
# @return [String]
|
62
|
-
|
63
|
-
# @!method use(keyspace)
|
64
|
-
#
|
65
|
-
# Changes keyspace by sending a `USE` statement to all connections.
|
66
|
-
#
|
67
|
-
# The the second parameter is meant for internal use only.
|
68
|
-
#
|
69
|
-
# @param [String] keyspace
|
70
|
-
# @raise [Cassandra::Errors::ClientError] raised when the client is not connected
|
71
|
-
# @return [nil]
|
72
|
-
|
73
|
-
# @!method execute(cql, *values, options={})
|
74
|
-
#
|
75
|
-
# Execute a CQL statement, optionally passing bound values.
|
76
|
-
#
|
77
|
-
# When passing bound values the request encoder will have to guess what
|
78
|
-
# types to encode the values as. For most types this will be no problem,
|
79
|
-
# but for integers and floating point numbers the larger size will be
|
80
|
-
# chosen (e.g. `BIGINT` and `DOUBLE` and not `INT` and `FLOAT`). You can
|
81
|
-
# override the guessing with the `:type_hint` option. Don't use on-the-fly
|
82
|
-
# bound values when you will issue the request multiple times, prepared
|
83
|
-
# statements are almost always a better choice.
|
84
|
-
#
|
85
|
-
# _Please note that on-the-fly bound values are only supported by Cassandra
|
86
|
-
# 2.0 and above._
|
87
|
-
#
|
88
|
-
# @example A simple CQL query
|
89
|
-
# result = client.execute("SELECT * FROM users WHERE user_name = 'sue'")
|
90
|
-
# result.each do |row|
|
91
|
-
# p row
|
92
|
-
# end
|
93
|
-
#
|
94
|
-
# @example Using on-the-fly bound values
|
95
|
-
# client.execute('INSERT INTO users (user_name, full_name) VALUES (?, ?)', 'sue', 'Sue Smith')
|
96
|
-
#
|
97
|
-
# @example Using on-the-fly bound values with type hints
|
98
|
-
# client.execute('INSERT INTO users (user_name, age) VALUES (?, ?)', 'sue', 33, type_hints: [nil, :int])
|
99
|
-
#
|
100
|
-
# @example Specifying the consistency as a symbol
|
101
|
-
# client.execute("UPDATE users SET full_name = 'Sue S. Smith' WHERE user_name = 'sue'", consistency: :one)
|
102
|
-
#
|
103
|
-
# @example Specifying the consistency and other options
|
104
|
-
# client.execute("SELECT * FROM users", consistency: :all, timeout: 1.5)
|
105
|
-
#
|
106
|
-
# @example Loading a big result page by page
|
107
|
-
# result_page = client.execute("SELECT * FROM large_table WHERE id = 'partition_with_lots_of_data'", page_size: 100)
|
108
|
-
# while result_page
|
109
|
-
# result_page.each do |row|
|
110
|
-
# p row
|
111
|
-
# end
|
112
|
-
# result_page = result_page.next_page
|
113
|
-
# end
|
114
|
-
#
|
115
|
-
# @example Activating tracing for a query
|
116
|
-
# result = client.execute("SELECT * FROM users", tracing: true)
|
117
|
-
# p result.trace_id
|
118
|
-
#
|
119
|
-
# @param [String] cql
|
120
|
-
# @param [Array] values Values to bind to any binding markers in the
|
121
|
-
# query (i.e. "?" placeholders) -- using this feature is similar to
|
122
|
-
# using a prepared statement, but without the type checking. The client
|
123
|
-
# needs to guess which data types to encode the values as, and will err
|
124
|
-
# on the side of caution, using types like BIGINT instead of INT for
|
125
|
-
# integers, and DOUBLE instead of FLOAT for floating point numbers. It
|
126
|
-
# is not recommended to use this feature for anything but convenience,
|
127
|
-
# and the algorithm used to guess types is to be considered experimental.
|
128
|
-
# @param [Hash] options
|
129
|
-
# @option options [Symbol] :consistency (:quorum) The
|
130
|
-
# consistency to use for this query.
|
131
|
-
# @option options [Symbol] :serial_consistency (nil) The
|
132
|
-
# consistency to use for conditional updates (`:serial` or
|
133
|
-
# `:local_serial`), see the CQL documentation for the semantics of
|
134
|
-
# serial consistencies and conditional updates. The default is assumed
|
135
|
-
# to be `:serial` by the server if none is specified. Ignored for non-
|
136
|
-
# conditional queries.
|
137
|
-
# @option options [Integer] :timeout (nil) How long to wait
|
138
|
-
# for a response. If this timeout expires a {Cassandra::Errors::TimeoutError} will
|
139
|
-
# be raised.
|
140
|
-
# @option options [Boolean] :trace (false) Request tracing
|
141
|
-
# for this request. See {Cassandra::Client::QueryResult} and
|
142
|
-
# {Cassandra::Client::VoidResult} for how to retrieve the tracing data.
|
143
|
-
# @option options [Integer] :page_size (nil) Instead of
|
144
|
-
# returning all rows, return the response in pages of this size. The
|
145
|
-
# first result will contain the first page, to load subsequent pages
|
146
|
-
# use {Cassandra::Client::QueryResult#next_page}.
|
147
|
-
# @option options [Array] :type_hints (nil) When passing
|
148
|
-
# on-the-fly bound values the request encoder will have to guess what
|
149
|
-
# types to encode the values as. Using this option you can give it hints
|
150
|
-
# and avoid it guessing wrong. The hints must be an array that has the
|
151
|
-
# same number of arguments as the number of bound values, and each
|
152
|
-
# element should be the type of the corresponding value, or nil if you
|
153
|
-
# prefer the encoder to guess. The types should be provided as lower
|
154
|
-
# case symbols, e.g. `:int`, `:time_uuid`, etc.
|
155
|
-
# @raise [Cassandra::Errors::ClientError] raised when the client is not connected
|
156
|
-
# @raise [Cassandra::Errors::TimeoutError] raised when a timeout was specified and no
|
157
|
-
# response was received within the timeout.
|
158
|
-
# @raise [Cassandra::Errors::ExecutionError] raised when the CQL has syntax errors or for
|
159
|
-
# other situations when the server complains.
|
160
|
-
# @return [nil, Cassandra::Client::QueryResult, Cassandra::Client::VoidResult] Some
|
161
|
-
# queries have no result and return `nil`, but `SELECT` statements
|
162
|
-
# return an `Enumerable` of rows (see {Cassandra::Client::QueryResult}), and
|
163
|
-
# `INSERT` and `UPDATE` return a similar type
|
164
|
-
# (see {Cassandra::Client::VoidResult}).
|
165
|
-
|
166
|
-
# @!method prepare(cql)
|
167
|
-
#
|
168
|
-
# Returns a prepared statement that can be run over and over again with
|
169
|
-
# different bound values.
|
170
|
-
#
|
171
|
-
# @see Cassandra::Client::PreparedStatement
|
172
|
-
# @param [String] cql The CQL to prepare
|
173
|
-
# @raise [Cassandra::Errors::ClientError] raised when the client is not connected
|
174
|
-
# @raise [Cassandra::Errors::IoError] raised when there is an IO error, for example
|
175
|
-
# if the server suddenly closes the connection
|
176
|
-
# @raise [Cassandra::Errors::ExecutionError] raised when there is an error on the server
|
177
|
-
# side, for example when you specify a malformed CQL query
|
178
|
-
# @return [Cassandra::Client::PreparedStatement] an object encapsulating the
|
179
|
-
# prepared statement
|
180
|
-
|
181
|
-
# @!method batch(type=:logged, options={})
|
182
|
-
#
|
183
|
-
# Yields a batch when called with a block. The batch is automatically
|
184
|
-
# executed at the end of the block and the result is returned.
|
185
|
-
#
|
186
|
-
# Returns a batch when called wihtout a block. The batch will remember
|
187
|
-
# the options given and merge these with any additional options given
|
188
|
-
# when {Cassandra::Client::Batch#execute} is called.
|
189
|
-
#
|
190
|
-
# Please note that the batch object returned by this method _is not thread
|
191
|
-
# safe_.
|
192
|
-
#
|
193
|
-
# The type parameter can be ommitted and the options can then be given
|
194
|
-
# as first parameter.
|
195
|
-
#
|
196
|
-
# @example Executing queries in a batch
|
197
|
-
# client.batch do |batch|
|
198
|
-
# batch.add(%(INSERT INTO metrics (id, time, value) VALUES (1234, NOW(), 23423)))
|
199
|
-
# batch.add(%(INSERT INTO metrics (id, time, value) VALUES (2346, NOW(), 13)))
|
200
|
-
# batch.add(%(INSERT INTO metrics (id, time, value) VALUES (2342, NOW(), 2367)))
|
201
|
-
# batch.add(%(INSERT INTO metrics (id, time, value) VALUES (4562, NOW(), 1231)))
|
202
|
-
# end
|
203
|
-
#
|
204
|
-
# @example Using the returned batch object
|
205
|
-
# batch = client.batch(:counter, trace: true)
|
206
|
-
# batch.add('UPDATE counts SET value = value + ? WHERE id = ?', 4, 87654)
|
207
|
-
# batch.add('UPDATE counts SET value = value + ? WHERE id = ?', 3, 6572)
|
208
|
-
# result = batch.execute(timeout: 10)
|
209
|
-
# puts result.trace_id
|
210
|
-
#
|
211
|
-
# @example Providing type hints for on-the-fly bound values
|
212
|
-
# batch = client.batch
|
213
|
-
# batch.add('UPDATE counts SET value = value + ? WHERE id = ?', 4, type_hints: [:int])
|
214
|
-
# batch.execute
|
215
|
-
#
|
216
|
-
# @see Cassandra::Client::Batch
|
217
|
-
# @param [Symbol] type the type of batch, must be one of `:logged`,
|
218
|
-
# `:unlogged` and `:counter`. The precise meaning of these is defined
|
219
|
-
# in the CQL specification.
|
220
|
-
# @yieldparam [Cassandra::Client::Batch] batch the batch
|
221
|
-
# @return [Cassandra::Client::VoidResult, Cassandra::Client::Batch] when no block is
|
222
|
-
# given the batch is returned, when a block is given the result of
|
223
|
-
# executing the batch is returned (see {Cassandra::Client::Batch#execute}).
|
224
|
-
end
|
225
|
-
|
226
|
-
# @private
|
227
|
-
class AsynchronousClient < Client
|
228
|
-
def initialize(options={})
|
229
|
-
@compressor = options[:compressor]
|
230
|
-
@cql_version = options[:cql_version]
|
231
|
-
@logger = options[:logger] || NullLogger.new
|
232
|
-
@protocol_version = options[:protocol_version] || 2
|
233
|
-
@io_reactor = options[:io_reactor] || Ione::Io::IoReactor.new
|
234
|
-
@hosts = extract_hosts(options)
|
235
|
-
@initial_keyspace = options[:keyspace]
|
236
|
-
@connections_per_node = options[:connections_per_node] || 1
|
237
|
-
@lock = Mutex.new
|
238
|
-
@request_runner = RequestRunner.new
|
239
|
-
@connection_manager = ConnectionManager.new
|
240
|
-
@execute_options_decoder = ExecuteOptionsDecoder.new(options[:default_consistency] || DEFAULT_CONSISTENCY)
|
241
|
-
@port = options[:port] || DEFAULT_PORT
|
242
|
-
@connection_timeout = options[:connection_timeout] || DEFAULT_CONNECTION_TIMEOUT
|
243
|
-
@credentials = options[:credentials]
|
244
|
-
@auth_provider = options[:auth_provider] || @credentials && Auth::Providers::Password.new(*@credentials.values_at(:username, :password))
|
245
|
-
@connected = false
|
246
|
-
@connecting = false
|
247
|
-
@closing = false
|
248
|
-
end
|
249
|
-
|
250
|
-
def connect
|
251
|
-
@lock.synchronize do
|
252
|
-
raise Errors::ClientError, 'Cannot connect a closed client' if @closing || @closed
|
253
|
-
return @connected_future if can_execute?
|
254
|
-
@connecting = true
|
255
|
-
@connected_future = begin
|
256
|
-
f = @io_reactor.start
|
257
|
-
f = f.flat_map { connect_with_protocol_version_fallback }
|
258
|
-
f = f.flat_map { |connections| connect_to_all_peers(connections) }
|
259
|
-
f = f.flat_map do |connections|
|
260
|
-
@connection_manager.add_connections(connections)
|
261
|
-
register_event_listener(@connection_manager.random_connection)
|
262
|
-
end
|
263
|
-
f = f.flat_map { use_keyspace(@connection_manager.snapshot, @initial_keyspace) }
|
264
|
-
f.map(self)
|
265
|
-
end
|
266
|
-
end
|
267
|
-
@connected_future.on_complete(&method(:connected))
|
268
|
-
@connected_future
|
269
|
-
end
|
270
|
-
|
271
|
-
def close
|
272
|
-
@lock.synchronize do
|
273
|
-
return @closed_future if @closing
|
274
|
-
@closing = true
|
275
|
-
@closed_future = begin
|
276
|
-
if @connecting
|
277
|
-
f = @connected_future.recover
|
278
|
-
f = f.flat_map { @io_reactor.stop }
|
279
|
-
f = f.map(self)
|
280
|
-
f
|
281
|
-
else
|
282
|
-
f = @io_reactor.stop
|
283
|
-
f = f.map(self)
|
284
|
-
f
|
285
|
-
end
|
286
|
-
end
|
287
|
-
end
|
288
|
-
@closed_future.on_complete(&method(:closed))
|
289
|
-
@closed_future
|
290
|
-
end
|
291
|
-
|
292
|
-
def connected?
|
293
|
-
@connected
|
294
|
-
end
|
295
|
-
|
296
|
-
def keyspace
|
297
|
-
@connection_manager.random_connection.keyspace
|
298
|
-
end
|
299
|
-
|
300
|
-
def use(keyspace)
|
301
|
-
with_failure_handler do
|
302
|
-
connections = @connection_manager.reject { |c| c.keyspace == keyspace }
|
303
|
-
return Ione::Future.resolved if connections.empty?
|
304
|
-
use_keyspace(connections, keyspace).map(nil)
|
305
|
-
end
|
306
|
-
end
|
307
|
-
|
308
|
-
def execute(cql, *args)
|
309
|
-
with_failure_handler do
|
310
|
-
options_or_consistency = nil
|
311
|
-
if args.last.is_a?(Symbol) || args.last.is_a?(Hash)
|
312
|
-
options_or_consistency = args.pop
|
313
|
-
end
|
314
|
-
options = @execute_options_decoder.decode_options(options_or_consistency)
|
315
|
-
request = Protocol::QueryRequest.new(cql, args, options[:type_hints], options[:consistency], options[:serial_consistency], options[:page_size], options[:paging_state], options[:trace])
|
316
|
-
f = execute_request(request, options[:timeout])
|
317
|
-
if options.include?(:page_size)
|
318
|
-
f = f.map { |result| AsynchronousQueryPagedQueryResult.new(self, request, result, options) }
|
319
|
-
end
|
320
|
-
f
|
321
|
-
end
|
322
|
-
end
|
323
|
-
|
324
|
-
def prepare(cql)
|
325
|
-
with_failure_handler do
|
326
|
-
AsynchronousPreparedStatement.prepare(cql, @execute_options_decoder, @connection_manager, @logger)
|
327
|
-
end
|
328
|
-
end
|
329
|
-
|
330
|
-
def batch(type=:logged, options=nil)
|
331
|
-
if type.is_a?(Hash)
|
332
|
-
options = type
|
333
|
-
type = :logged
|
334
|
-
end
|
335
|
-
b = AsynchronousBatch.new(type, @execute_options_decoder, @connection_manager, options)
|
336
|
-
if block_given?
|
337
|
-
yield b
|
338
|
-
b.execute
|
339
|
-
else
|
340
|
-
b
|
341
|
-
end
|
342
|
-
end
|
343
|
-
|
344
|
-
private
|
345
|
-
|
346
|
-
DEFAULT_CQL_VERSIONS = {1 => '3.0.0'}
|
347
|
-
DEFAULT_CQL_VERSIONS.default = '3.1.0'
|
348
|
-
DEFAULT_CQL_VERSIONS.freeze
|
349
|
-
DEFAULT_CONSISTENCY = :quorum
|
350
|
-
DEFAULT_PORT = 9042
|
351
|
-
DEFAULT_CONNECTION_TIMEOUT = 10
|
352
|
-
MAX_RECONNECTION_ATTEMPTS = 5
|
353
|
-
|
354
|
-
def extract_hosts(options)
|
355
|
-
if options[:hosts] && options[:hosts].any?
|
356
|
-
options[:hosts].uniq
|
357
|
-
elsif options[:host]
|
358
|
-
options[:host].split(',').uniq
|
359
|
-
else
|
360
|
-
%w[localhost]
|
361
|
-
end
|
362
|
-
end
|
363
|
-
|
364
|
-
def create_cluster_connector
|
365
|
-
cql_version = @cql_version || DEFAULT_CQL_VERSIONS[@protocol_version]
|
366
|
-
authentication_step = @protocol_version == 1 ? CredentialsAuthenticationStep.new(@credentials) : SaslAuthenticationStep.new(@auth_provider)
|
367
|
-
protocol_handler_factory = lambda { |connection| Protocol::CqlProtocolHandler.new(connection, @io_reactor, @protocol_version, @compressor) }
|
368
|
-
ClusterConnector.new(
|
369
|
-
Connector.new([
|
370
|
-
ConnectStep.new(@io_reactor, protocol_handler_factory, @port, @connection_timeout, @logger),
|
371
|
-
CacheOptionsStep.new,
|
372
|
-
InitializeStep.new(@compressor, @logger),
|
373
|
-
authentication_step,
|
374
|
-
CachePropertiesStep.new,
|
375
|
-
]),
|
376
|
-
@logger
|
377
|
-
)
|
378
|
-
end
|
379
|
-
|
380
|
-
def connect_with_protocol_version_fallback
|
381
|
-
f = create_cluster_connector.connect_all(@hosts, @connections_per_node)
|
382
|
-
f.fallback do |error|
|
383
|
-
if error.is_a?(Errors::ProtocolError) && @protocol_version > 1
|
384
|
-
@logger.warn('Could not connect using protocol version %d (will try again with %d): %s' % [@protocol_version, @protocol_version - 1, error.message])
|
385
|
-
@protocol_version -= 1
|
386
|
-
connect_with_protocol_version_fallback
|
387
|
-
else
|
388
|
-
raise(error, error.message, error.backtrace)
|
389
|
-
end
|
390
|
-
end
|
391
|
-
end
|
392
|
-
|
393
|
-
def connect_to_all_peers(seed_connections, initial_keyspace=@initial_keyspace)
|
394
|
-
@logger.debug('Looking for additional nodes')
|
395
|
-
peer_discovery = PeerDiscovery.new(seed_connections)
|
396
|
-
peer_discovery.new_hosts.flat_map do |hosts|
|
397
|
-
if hosts.empty?
|
398
|
-
@logger.debug('No additional nodes found')
|
399
|
-
Ione::Future.resolved(seed_connections)
|
400
|
-
else
|
401
|
-
@logger.debug('%d additional nodes found' % hosts.size)
|
402
|
-
f = create_cluster_connector.connect_all(hosts, @connections_per_node)
|
403
|
-
f = f.map do |discovered_connections|
|
404
|
-
seed_connections + discovered_connections
|
405
|
-
end
|
406
|
-
f.recover(seed_connections)
|
407
|
-
end
|
408
|
-
end
|
409
|
-
end
|
410
|
-
|
411
|
-
def connected(f)
|
412
|
-
if f.resolved?
|
413
|
-
@lock.synchronize do
|
414
|
-
@connecting = false
|
415
|
-
@connected = true
|
416
|
-
end
|
417
|
-
@logger.info('Cluster connection complete')
|
418
|
-
else
|
419
|
-
@lock.synchronize do
|
420
|
-
@connecting = false
|
421
|
-
@connected = false
|
422
|
-
end
|
423
|
-
f.on_failure do |e|
|
424
|
-
@logger.error('Failed connecting to cluster: %s' % e.message)
|
425
|
-
end
|
426
|
-
close
|
427
|
-
end
|
428
|
-
end
|
429
|
-
|
430
|
-
def closed(f)
|
431
|
-
@lock.synchronize do
|
432
|
-
@closing = false
|
433
|
-
@closed = true
|
434
|
-
@connected = false
|
435
|
-
if f.resolved?
|
436
|
-
@logger.info('Cluster disconnect complete')
|
437
|
-
else
|
438
|
-
f.on_failure do |e|
|
439
|
-
@logger.error('Cluster disconnect failed: %s' % e.message)
|
440
|
-
end
|
441
|
-
end
|
442
|
-
end
|
443
|
-
end
|
444
|
-
|
445
|
-
def can_execute?
|
446
|
-
!@closing && (@connecting || (@connected && @connection_manager.connected?))
|
447
|
-
end
|
448
|
-
|
449
|
-
def with_failure_handler
|
450
|
-
return Ione::Future.failed(Errors::ClientError.new) unless can_execute?
|
451
|
-
yield
|
452
|
-
rescue => e
|
453
|
-
Ione::Future.failed(e)
|
454
|
-
end
|
455
|
-
|
456
|
-
def use_keyspace(connections, keyspace)
|
457
|
-
return Ione::Future.resolved(connections) unless keyspace
|
458
|
-
return Ione::Future.failed(InvalidKeyspaceNameError.new(%("#{keyspace}" is not a valid keyspace name))) unless keyspace =~ /^\w[\w\d_]*$|^"\w[\w\d_]*"$/
|
459
|
-
|
460
|
-
futures = connections.map do |connection|
|
461
|
-
request = Protocol::QueryRequest.new("USE #{keyspace}", nil, nil, :one)
|
462
|
-
@request_runner.execute(connection, request).map(connection)
|
463
|
-
end
|
464
|
-
Ione::Future.all(*futures)
|
465
|
-
end
|
466
|
-
|
467
|
-
def register_event_listener(connection)
|
468
|
-
register_request = Protocol::RegisterRequest.new(Protocol::TopologyChangeEventResponse::TYPE, Protocol::StatusChangeEventResponse::TYPE)
|
469
|
-
f = execute_request(register_request, nil, connection)
|
470
|
-
f.on_value do
|
471
|
-
connection.on_closed do
|
472
|
-
if connected?
|
473
|
-
begin
|
474
|
-
register_event_listener(@connection_manager.random_connection)
|
475
|
-
rescue Errors::IOError
|
476
|
-
# we had started closing down after the connection check
|
477
|
-
end
|
478
|
-
end
|
479
|
-
end
|
480
|
-
connection.on_event do |event|
|
481
|
-
if event.change == 'UP' || event.change == 'NEW_NODE'
|
482
|
-
@logger.debug('Received %s event' % event.change)
|
483
|
-
unless @looking_for_nodes
|
484
|
-
@looking_for_nodes = true
|
485
|
-
handle_topology_change.on_complete do |f|
|
486
|
-
@looking_for_nodes = false
|
487
|
-
end
|
488
|
-
end
|
489
|
-
end
|
490
|
-
end
|
491
|
-
end
|
492
|
-
f
|
493
|
-
end
|
494
|
-
|
495
|
-
def handle_topology_change(remaning_attempts=MAX_RECONNECTION_ATTEMPTS)
|
496
|
-
with_failure_handler do
|
497
|
-
seed_connections = @connection_manager.snapshot
|
498
|
-
f = connect_to_all_peers(seed_connections, keyspace)
|
499
|
-
f.flat_map do |all_connections|
|
500
|
-
new_connections = all_connections - seed_connections
|
501
|
-
if new_connections.size > 0
|
502
|
-
f = use_keyspace(new_connections, keyspace)
|
503
|
-
f.on_value do
|
504
|
-
@connection_manager.add_connections(new_connections)
|
505
|
-
end
|
506
|
-
f
|
507
|
-
elsif remaning_attempts > 0
|
508
|
-
timeout = 2**(MAX_RECONNECTION_ATTEMPTS - remaning_attempts)
|
509
|
-
@logger.debug('Scheduling new peer discovery in %ds' % timeout)
|
510
|
-
f = @io_reactor.schedule_timer(timeout)
|
511
|
-
f.flat_map do
|
512
|
-
handle_topology_change(remaning_attempts - 1)
|
513
|
-
end
|
514
|
-
else
|
515
|
-
@logger.warn('Giving up looking for additional nodes')
|
516
|
-
Ione::Future.resolved
|
517
|
-
end
|
518
|
-
end
|
519
|
-
end
|
520
|
-
end
|
521
|
-
|
522
|
-
def execute_request(request, timeout=nil, connection=nil)
|
523
|
-
f = @request_runner.execute(connection || @connection_manager.random_connection, request, timeout)
|
524
|
-
f.map do |result|
|
525
|
-
if result.is_a?(KeyspaceChanged)
|
526
|
-
use(result.keyspace)
|
527
|
-
nil
|
528
|
-
else
|
529
|
-
result
|
530
|
-
end
|
531
|
-
end
|
532
|
-
end
|
533
|
-
end
|
534
|
-
|
535
|
-
# @private
|
536
|
-
class SynchronousClient < Client
|
537
|
-
include SynchronousBacktrace
|
538
|
-
|
539
|
-
def initialize(async_client)
|
540
|
-
@async_client = async_client
|
541
|
-
end
|
542
|
-
|
543
|
-
def connect
|
544
|
-
synchronous_backtrace { @async_client.connect.value }
|
545
|
-
self
|
546
|
-
end
|
547
|
-
|
548
|
-
def close
|
549
|
-
synchronous_backtrace { @async_client.close.value }
|
550
|
-
self
|
551
|
-
end
|
552
|
-
|
553
|
-
def connected?
|
554
|
-
@async_client.connected?
|
555
|
-
end
|
556
|
-
|
557
|
-
def keyspace
|
558
|
-
@async_client.keyspace
|
559
|
-
end
|
560
|
-
|
561
|
-
def use(keyspace)
|
562
|
-
synchronous_backtrace { @async_client.use(keyspace).value }
|
563
|
-
end
|
564
|
-
|
565
|
-
def execute(cql, *args)
|
566
|
-
synchronous_backtrace do
|
567
|
-
result = @async_client.execute(cql, *args).value
|
568
|
-
result = SynchronousPagedQueryResult.new(result) if result.is_a?(PagedQueryResult)
|
569
|
-
result
|
570
|
-
end
|
571
|
-
end
|
572
|
-
|
573
|
-
def prepare(cql)
|
574
|
-
async_statement = synchronous_backtrace { @async_client.prepare(cql).value }
|
575
|
-
SynchronousPreparedStatement.new(async_statement)
|
576
|
-
end
|
577
|
-
|
578
|
-
def batch(type=:logged, options={}, &block)
|
579
|
-
if block_given?
|
580
|
-
synchronous_backtrace { @async_client.batch(type, options, &block).value }
|
581
|
-
else
|
582
|
-
SynchronousBatch.new(@async_client.batch(type, options))
|
583
|
-
end
|
584
|
-
end
|
585
|
-
|
586
|
-
def async
|
587
|
-
@async_client
|
588
|
-
end
|
589
|
-
end
|
590
|
-
end
|
591
|
-
end
|