cassandra-driver 1.0.0.beta.2-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 +7 -0
- data/.yardopts +4 -0
- data/README.md +125 -0
- data/lib/cassandra/auth/providers/password.rb +73 -0
- data/lib/cassandra/auth/providers.rb +16 -0
- data/lib/cassandra/auth.rb +97 -0
- data/lib/cassandra/client/batch.rb +212 -0
- data/lib/cassandra/client/client.rb +591 -0
- data/lib/cassandra/client/column_metadata.rb +54 -0
- data/lib/cassandra/client/connection_manager.rb +72 -0
- data/lib/cassandra/client/connector.rb +277 -0
- data/lib/cassandra/client/execute_options_decoder.rb +59 -0
- data/lib/cassandra/client/null_logger.rb +37 -0
- data/lib/cassandra/client/peer_discovery.rb +50 -0
- data/lib/cassandra/client/prepared_statement.rb +314 -0
- data/lib/cassandra/client/query_result.rb +230 -0
- data/lib/cassandra/client/request_runner.rb +71 -0
- data/lib/cassandra/client/result_metadata.rb +48 -0
- data/lib/cassandra/client/void_result.rb +78 -0
- data/lib/cassandra/client.rb +144 -0
- data/lib/cassandra/cluster/client.rb +768 -0
- data/lib/cassandra/cluster/connector.rb +244 -0
- data/lib/cassandra/cluster/control_connection.rb +425 -0
- data/lib/cassandra/cluster/metadata.rb +124 -0
- data/lib/cassandra/cluster/options.rb +42 -0
- data/lib/cassandra/cluster/registry.rb +198 -0
- data/lib/cassandra/cluster/schema/partitioners/murmur3.rb +47 -0
- data/lib/cassandra/cluster/schema/partitioners/ordered.rb +37 -0
- data/lib/cassandra/cluster/schema/partitioners/random.rb +37 -0
- data/lib/cassandra/cluster/schema/partitioners.rb +21 -0
- data/lib/cassandra/cluster/schema/replication_strategies/network_topology.rb +92 -0
- data/lib/cassandra/cluster/schema/replication_strategies/none.rb +39 -0
- data/lib/cassandra/cluster/schema/replication_strategies/simple.rb +44 -0
- data/lib/cassandra/cluster/schema/replication_strategies.rb +21 -0
- data/lib/cassandra/cluster/schema/type_parser.rb +138 -0
- data/lib/cassandra/cluster/schema.rb +340 -0
- data/lib/cassandra/cluster.rb +215 -0
- data/lib/cassandra/column.rb +92 -0
- data/lib/cassandra/compression/compressors/lz4.rb +72 -0
- data/lib/cassandra/compression/compressors/snappy.rb +66 -0
- data/lib/cassandra/compression.rb +66 -0
- data/lib/cassandra/driver.rb +111 -0
- data/lib/cassandra/errors.rb +79 -0
- data/lib/cassandra/execution/info.rb +51 -0
- data/lib/cassandra/execution/options.rb +80 -0
- data/lib/cassandra/execution/trace.rb +152 -0
- data/lib/cassandra/future.rb +675 -0
- data/lib/cassandra/host.rb +79 -0
- data/lib/cassandra/keyspace.rb +133 -0
- data/lib/cassandra/listener.rb +87 -0
- data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +149 -0
- data/lib/cassandra/load_balancing/policies/round_robin.rb +132 -0
- data/lib/cassandra/load_balancing/policies/token_aware.rb +119 -0
- data/lib/cassandra/load_balancing/policies/white_list.rb +90 -0
- data/lib/cassandra/load_balancing/policies.rb +19 -0
- data/lib/cassandra/load_balancing.rb +113 -0
- data/lib/cassandra/protocol/cql_byte_buffer.rb +307 -0
- data/lib/cassandra/protocol/cql_protocol_handler.rb +323 -0
- data/lib/cassandra/protocol/frame_decoder.rb +128 -0
- data/lib/cassandra/protocol/frame_encoder.rb +48 -0
- data/lib/cassandra/protocol/request.rb +38 -0
- data/lib/cassandra/protocol/requests/auth_response_request.rb +47 -0
- data/lib/cassandra/protocol/requests/batch_request.rb +76 -0
- data/lib/cassandra/protocol/requests/credentials_request.rb +47 -0
- data/lib/cassandra/protocol/requests/execute_request.rb +103 -0
- data/lib/cassandra/protocol/requests/options_request.rb +39 -0
- data/lib/cassandra/protocol/requests/prepare_request.rb +50 -0
- data/lib/cassandra/protocol/requests/query_request.rb +153 -0
- data/lib/cassandra/protocol/requests/register_request.rb +38 -0
- data/lib/cassandra/protocol/requests/startup_request.rb +49 -0
- data/lib/cassandra/protocol/requests/void_query_request.rb +24 -0
- data/lib/cassandra/protocol/response.rb +38 -0
- data/lib/cassandra/protocol/responses/auth_challenge_response.rb +41 -0
- data/lib/cassandra/protocol/responses/auth_success_response.rb +41 -0
- data/lib/cassandra/protocol/responses/authenticate_response.rb +41 -0
- data/lib/cassandra/protocol/responses/detailed_error_response.rb +60 -0
- data/lib/cassandra/protocol/responses/error_response.rb +50 -0
- data/lib/cassandra/protocol/responses/event_response.rb +39 -0
- data/lib/cassandra/protocol/responses/prepared_result_response.rb +64 -0
- data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +43 -0
- data/lib/cassandra/protocol/responses/ready_response.rb +44 -0
- data/lib/cassandra/protocol/responses/result_response.rb +48 -0
- data/lib/cassandra/protocol/responses/rows_result_response.rb +139 -0
- data/lib/cassandra/protocol/responses/schema_change_event_response.rb +60 -0
- data/lib/cassandra/protocol/responses/schema_change_result_response.rb +57 -0
- data/lib/cassandra/protocol/responses/set_keyspace_result_response.rb +42 -0
- data/lib/cassandra/protocol/responses/status_change_event_response.rb +44 -0
- data/lib/cassandra/protocol/responses/supported_response.rb +41 -0
- data/lib/cassandra/protocol/responses/topology_change_event_response.rb +34 -0
- data/lib/cassandra/protocol/responses/void_result_response.rb +39 -0
- data/lib/cassandra/protocol/type_converter.rb +384 -0
- data/lib/cassandra/protocol.rb +93 -0
- data/lib/cassandra/reconnection/policies/constant.rb +48 -0
- data/lib/cassandra/reconnection/policies/exponential.rb +79 -0
- data/lib/cassandra/reconnection/policies.rb +20 -0
- data/lib/cassandra/reconnection.rb +49 -0
- data/lib/cassandra/result.rb +215 -0
- data/lib/cassandra/retry/policies/default.rb +47 -0
- data/lib/cassandra/retry/policies/downgrading_consistency.rb +71 -0
- data/lib/cassandra/retry/policies/fallthrough.rb +39 -0
- data/lib/cassandra/retry/policies.rb +21 -0
- data/lib/cassandra/retry.rb +142 -0
- data/lib/cassandra/session.rb +202 -0
- data/lib/cassandra/statement.rb +22 -0
- data/lib/cassandra/statements/batch.rb +95 -0
- data/lib/cassandra/statements/bound.rb +48 -0
- data/lib/cassandra/statements/prepared.rb +81 -0
- data/lib/cassandra/statements/simple.rb +58 -0
- data/lib/cassandra/statements/void.rb +33 -0
- data/lib/cassandra/statements.rb +23 -0
- data/lib/cassandra/table.rb +299 -0
- data/lib/cassandra/time_uuid.rb +142 -0
- data/lib/cassandra/util.rb +167 -0
- data/lib/cassandra/uuid.rb +104 -0
- data/lib/cassandra/version.rb +21 -0
- data/lib/cassandra.rb +428 -0
- data/lib/cassandra_murmur3.jar +0 -0
- metadata +211 -0
|
@@ -0,0 +1,79 @@
|
|
|
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
|
+
class Host
|
|
21
|
+
# @return [IPAddr] host ip
|
|
22
|
+
attr_reader :ip
|
|
23
|
+
# @note Host id can be `nil` before cluster has connected.
|
|
24
|
+
# @return [Cassandra::Uuid, nil] host id.
|
|
25
|
+
attr_reader :id
|
|
26
|
+
# @note Host datacenter can be `nil` before cluster has connected.
|
|
27
|
+
# @return [String, nil] host datacenter
|
|
28
|
+
attr_reader :datacenter
|
|
29
|
+
# @note Host rack can be `nil` before cluster has connected.
|
|
30
|
+
# @return [String, nil] host rack
|
|
31
|
+
attr_reader :rack
|
|
32
|
+
# @note Host's cassandra version can be `nil` before cluster has connected.
|
|
33
|
+
# @return [String, nil] version of cassandra that a host is running
|
|
34
|
+
attr_reader :release_version
|
|
35
|
+
# @note Host tokens will be empty before cluster has connected.
|
|
36
|
+
# @return [Array<String>] a list of tokens owned by this host
|
|
37
|
+
attr_reader :tokens
|
|
38
|
+
# @return [Symbol] host status. Must be `:up` or `:down`
|
|
39
|
+
attr_reader :status
|
|
40
|
+
|
|
41
|
+
# @private
|
|
42
|
+
def initialize(ip, id = nil, rack = nil, datacenter = nil, release_version = nil, tokens = EMPTY_LIST, status = :up)
|
|
43
|
+
@ip = ip
|
|
44
|
+
@id = id
|
|
45
|
+
@rack = rack
|
|
46
|
+
@datacenter = datacenter
|
|
47
|
+
@release_version = release_version
|
|
48
|
+
@tokens = tokens
|
|
49
|
+
@status = status
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# @return [Boolean] whether this host's status is `:up`
|
|
53
|
+
def up?
|
|
54
|
+
@status == :up
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# @return [Boolean] whether this host's status is `:down`
|
|
58
|
+
def down?
|
|
59
|
+
@status == :down
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# @private
|
|
63
|
+
def hash
|
|
64
|
+
@hash ||= @ip.hash
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# @param other [Cassandra::Host] a host to compare
|
|
68
|
+
# @return [Boolean] whether this host has the same ip as the other
|
|
69
|
+
def eql?(other)
|
|
70
|
+
other.eql?(@ip)
|
|
71
|
+
end
|
|
72
|
+
alias :== :eql?
|
|
73
|
+
|
|
74
|
+
# @return [String] a CLI-friendly host representation
|
|
75
|
+
def inspect
|
|
76
|
+
"#<#{self.class.name}:0x#{self.object_id.to_s(16)} @ip=#{@ip}>"
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,133 @@
|
|
|
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
|
+
# Represents a cassandra keyspace
|
|
21
|
+
# @see Cassandra::Cluster#each_keyspace
|
|
22
|
+
# @see Cassandra::Cluster#keyspace
|
|
23
|
+
class Keyspace
|
|
24
|
+
# @private
|
|
25
|
+
class Replication
|
|
26
|
+
attr_reader :klass, :options
|
|
27
|
+
|
|
28
|
+
def initialize(klass, options)
|
|
29
|
+
@klass = klass
|
|
30
|
+
@options = options
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def to_cql
|
|
34
|
+
replication = {'class' => @klass}
|
|
35
|
+
replication.merge!(@options)
|
|
36
|
+
|
|
37
|
+
Util.encode_hash(replication)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def eql?(other)
|
|
41
|
+
other.is_a?(Replication) &&
|
|
42
|
+
@klass == other.klass &&
|
|
43
|
+
@options == other.options
|
|
44
|
+
end
|
|
45
|
+
alias :== :eql?
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @return [String] this keyspace name
|
|
49
|
+
attr_reader :name
|
|
50
|
+
# @private
|
|
51
|
+
attr_reader :replication
|
|
52
|
+
|
|
53
|
+
# @private
|
|
54
|
+
def initialize(name, durable_writes, replication, tables)
|
|
55
|
+
@name = name
|
|
56
|
+
@durable_writes = durable_writes
|
|
57
|
+
@replication = replication
|
|
58
|
+
@tables = tables
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @return [Boolean] whether durables writes are enabled for this keyspace
|
|
62
|
+
def durable_writes?
|
|
63
|
+
@durable_writes
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# @return [Boolean] whether this keyspace has a table with the given name
|
|
67
|
+
# @param name [String] table name
|
|
68
|
+
def has_table?(name)
|
|
69
|
+
@tables.has_key?(name)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# @return [Cassandra::Table, nil] a table or nil
|
|
73
|
+
# @param name [String] table name
|
|
74
|
+
def table(name)
|
|
75
|
+
@tables[name]
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Yield or enumerate each table defined in this keyspace
|
|
79
|
+
# @overload each_table
|
|
80
|
+
# @yieldparam table [Cassandra::Table] current table
|
|
81
|
+
# @return [Cassandra::Keyspace] self
|
|
82
|
+
# @overload each_table
|
|
83
|
+
# @return [Array<Cassandra::Table>] a list of tables
|
|
84
|
+
def each_table(&block)
|
|
85
|
+
if block_given?
|
|
86
|
+
@tables.each_value(&block)
|
|
87
|
+
self
|
|
88
|
+
else
|
|
89
|
+
@tables.values
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
alias :tables :each_table
|
|
93
|
+
|
|
94
|
+
# @return [String] a cql representation of this table
|
|
95
|
+
def to_cql
|
|
96
|
+
"CREATE KEYSPACE #{Util.escape_name(@name)} WITH REPLICATION = #{@replication.to_cql} AND DURABLE_WRITES = #{@durable_writes};"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# @return [Boolean] whether this keyspace is equal to the other
|
|
100
|
+
def eql?(other)
|
|
101
|
+
other.is_a?(Keyspace) &&
|
|
102
|
+
@name == other.name &&
|
|
103
|
+
@durable_writes == other.durable_writes &&
|
|
104
|
+
@replication == other.replication &&
|
|
105
|
+
@tables == other.raw_tables
|
|
106
|
+
end
|
|
107
|
+
alias :== :eql?
|
|
108
|
+
|
|
109
|
+
# @private
|
|
110
|
+
def update_table(table)
|
|
111
|
+
tables = @tables.dup
|
|
112
|
+
tables[table.name] = table
|
|
113
|
+
Keyspace.new(@name, @durable_writes, @replication, tables)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# @private
|
|
117
|
+
def create_partition_key(table, values)
|
|
118
|
+
table = @tables[table]
|
|
119
|
+
table && table.create_partition_key(values)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# @private
|
|
123
|
+
attr_reader :durable_writes
|
|
124
|
+
protected :durable_writes
|
|
125
|
+
|
|
126
|
+
protected
|
|
127
|
+
|
|
128
|
+
# @private
|
|
129
|
+
def raw_tables
|
|
130
|
+
@tables
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
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
|
+
# Cassandra state listener.
|
|
21
|
+
#
|
|
22
|
+
# @abstract Actual state listener implementations don't need to inherit from
|
|
23
|
+
# this class as long as they conform to its interface. This class exists
|
|
24
|
+
# solely for documentation purposes
|
|
25
|
+
#
|
|
26
|
+
# @see Cassandra::Cluster#register
|
|
27
|
+
class Listener
|
|
28
|
+
# This method is called whenever a host is considered to be up, whether
|
|
29
|
+
# by Cassandra's gossip exchange or when the driver has successfully
|
|
30
|
+
# established a connection to it.
|
|
31
|
+
#
|
|
32
|
+
# @param host [Cassandra::Host] a host instance
|
|
33
|
+
# @return [void]
|
|
34
|
+
def host_up(host)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# This method is called whenever a host is considered to be down, whether
|
|
38
|
+
# by Cassandra's gossip exchange or when the driver failed to establish
|
|
39
|
+
# any connections to it.
|
|
40
|
+
#
|
|
41
|
+
# @param host [Cassandra::Host] a host instance
|
|
42
|
+
# @return [void]
|
|
43
|
+
def host_down(host)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# This method is called whenever a host is discovered by the driver,
|
|
47
|
+
# whether because it is a completely new node or if its
|
|
48
|
+
# {Cassandra::Host#datacenter} or {Cassandra::Host#rack} have changed.
|
|
49
|
+
#
|
|
50
|
+
# @param host [Cassandra::Host] a host instance
|
|
51
|
+
# @return [void]
|
|
52
|
+
def host_found(host)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# This method is called whenever a host leaves the cluster, whether
|
|
56
|
+
# because it is completely gone or if its {Cassandra::Host#datacenter} or
|
|
57
|
+
# {Cassandra::Host#rack} have changed.
|
|
58
|
+
#
|
|
59
|
+
# @param host [Cassandra::Host] a host instance
|
|
60
|
+
# @return [void]
|
|
61
|
+
def host_lost(host)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# This method is called whenever a new keyspace is created.
|
|
65
|
+
#
|
|
66
|
+
# @param keyspace [Cassandra::Keyspace] a keyspace instance
|
|
67
|
+
# @return [void]
|
|
68
|
+
def keyspace_created(keyspace)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# This method is called whenever an existing keyspace is changed. This
|
|
72
|
+
# happens when a new table is created or an existing table is dropped or
|
|
73
|
+
# altered.
|
|
74
|
+
#
|
|
75
|
+
# @param keyspace [Cassandra::Keyspace] a keyspace instance
|
|
76
|
+
# @return [void]
|
|
77
|
+
def keyspace_changed(keyspace)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# This method is called whenever an existing keyspace is dropped.
|
|
81
|
+
#
|
|
82
|
+
# @param keyspace [Cassandra::Keyspace] a keyspace instance
|
|
83
|
+
# @return [void]
|
|
84
|
+
def keyspace_dropped(keyspace)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,149 @@
|
|
|
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 LoadBalancing
|
|
21
|
+
module Policies
|
|
22
|
+
class DCAwareRoundRobin < Policy
|
|
23
|
+
# @private
|
|
24
|
+
class Plan
|
|
25
|
+
def initialize(local, remote, index)
|
|
26
|
+
@local = local
|
|
27
|
+
@remote = remote
|
|
28
|
+
@index = index
|
|
29
|
+
|
|
30
|
+
@local_remaining = @local_total = local.size
|
|
31
|
+
@remote_remaining = @remote_total = remote.size
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def has_next?
|
|
35
|
+
@local_remaining > 0 || @remote_remaining > 0
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def next
|
|
39
|
+
if @local_remaining > 0
|
|
40
|
+
@local_remaining -= 1
|
|
41
|
+
i = (@index % @local_total)
|
|
42
|
+
@index += 1
|
|
43
|
+
|
|
44
|
+
return @local[i]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
if @remote_remaining > 0
|
|
48
|
+
@remote_remaining -= 1
|
|
49
|
+
i = (@index % @remote_total)
|
|
50
|
+
@index += 1
|
|
51
|
+
|
|
52
|
+
return @remote[i]
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
include MonitorMixin
|
|
58
|
+
|
|
59
|
+
def initialize(datacenter, max_remote_hosts_to_use = nil, use_remote_hosts_for_local_consistency = false)
|
|
60
|
+
datacenter = String(datacenter)
|
|
61
|
+
max_remote_hosts_to_use = max_remote_hosts_to_use && Integer(max_remote_hosts_to_use)
|
|
62
|
+
|
|
63
|
+
raise ::ArgumentError, "datacenter cannot be nil" if datacenter.nil?
|
|
64
|
+
raise ::ArgumentError, "max_remote_hosts_to_use must be nil or >= 0" if max_remote_hosts_to_use && max_remote_hosts_to_use < 0
|
|
65
|
+
|
|
66
|
+
@datacenter = datacenter
|
|
67
|
+
@max_remote = max_remote_hosts_to_use
|
|
68
|
+
@local = ::Array.new
|
|
69
|
+
@remote = ::Array.new
|
|
70
|
+
@position = 0
|
|
71
|
+
|
|
72
|
+
@use_remote = !!use_remote_hosts_for_local_consistency
|
|
73
|
+
|
|
74
|
+
mon_initialize
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def host_up(host)
|
|
78
|
+
if host.datacenter.nil? || host.datacenter == @datacenter
|
|
79
|
+
synchronize { @local = @local.dup.push(host) }
|
|
80
|
+
else
|
|
81
|
+
if @max_remote.nil? || @remote.size < @max_remote
|
|
82
|
+
synchronize { @remote = @remote.dup.push(host) }
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
self
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def host_down(host)
|
|
90
|
+
if host.datacenter.nil? || host.datacenter == @datacenter
|
|
91
|
+
synchronize do
|
|
92
|
+
@local = @local.dup
|
|
93
|
+
@local.delete(host)
|
|
94
|
+
end
|
|
95
|
+
else
|
|
96
|
+
synchronize do
|
|
97
|
+
@remote = @remote.dup
|
|
98
|
+
@remote.delete(host)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
self
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def host_found(host)
|
|
106
|
+
self
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def host_lost(host)
|
|
110
|
+
self
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def distance(host)
|
|
114
|
+
if host.datacenter.nil? || host.datacenter == @datacenter
|
|
115
|
+
@local.include?(host) ? :local : :ignore
|
|
116
|
+
else
|
|
117
|
+
@remote.include?(host) ? :remote : :ignore
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def plan(keyspace, statement, options)
|
|
122
|
+
local = @local
|
|
123
|
+
|
|
124
|
+
if LOCAL_CONSISTENCIES.include?(options.consistency) && !@use_remote
|
|
125
|
+
remote = EMPTY_ARRAY
|
|
126
|
+
else
|
|
127
|
+
remote = @remote
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
position = @position
|
|
131
|
+
total = local.size + remote.size
|
|
132
|
+
|
|
133
|
+
return EMPTY_PLAN if total == 0
|
|
134
|
+
|
|
135
|
+
@position = (@position + 1) % total
|
|
136
|
+
|
|
137
|
+
Plan.new(local, remote, position)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
private
|
|
141
|
+
|
|
142
|
+
# @private
|
|
143
|
+
LOCAL_CONSISTENCIES = [:local_quorum, :local_one].freeze
|
|
144
|
+
# @private
|
|
145
|
+
EMPTY_ARRAY = [].freeze
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
@@ -0,0 +1,132 @@
|
|
|
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 LoadBalancing
|
|
21
|
+
module Policies
|
|
22
|
+
class RoundRobin < Policy
|
|
23
|
+
# @private
|
|
24
|
+
class Plan
|
|
25
|
+
def initialize(hosts, index)
|
|
26
|
+
@hosts = hosts
|
|
27
|
+
@index = index
|
|
28
|
+
|
|
29
|
+
@total = @remaining = hosts.size
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def has_next?
|
|
33
|
+
@remaining > 0
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def next
|
|
37
|
+
return if @remaining == 0
|
|
38
|
+
|
|
39
|
+
@remaining -= 1
|
|
40
|
+
index, @index = @index, (@index + 1) % @total
|
|
41
|
+
|
|
42
|
+
@hosts[index]
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
include MonitorMixin
|
|
47
|
+
|
|
48
|
+
def initialize
|
|
49
|
+
@hosts = ::Array.new
|
|
50
|
+
@position = 0
|
|
51
|
+
|
|
52
|
+
mon_initialize
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Adds this host to rotation
|
|
56
|
+
#
|
|
57
|
+
# @param host [Cassandra::Host] a host instance
|
|
58
|
+
# @return [Cassandra::LoadBalancing::Policies::RoundRobin] self
|
|
59
|
+
# @see Cassandra::Listener#host_up
|
|
60
|
+
def host_up(host)
|
|
61
|
+
synchronize { @hosts = @hosts.dup.push(host) }
|
|
62
|
+
|
|
63
|
+
self
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Removes this host from rotation
|
|
67
|
+
#
|
|
68
|
+
# @param host [Cassandra::Host] a host instance
|
|
69
|
+
# @return [Cassandra::LoadBalancing::Policies::RoundRobin] self
|
|
70
|
+
# @see Cassandra::Listener#host_down
|
|
71
|
+
def host_down(host)
|
|
72
|
+
synchronize do
|
|
73
|
+
@hosts = @hosts.dup
|
|
74
|
+
@hosts.delete(host)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
self
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Noop
|
|
81
|
+
#
|
|
82
|
+
# @param host [Cassandra::Host] a host instance
|
|
83
|
+
# @return [Cassandra::LoadBalancing::Policies::RoundRobin] self
|
|
84
|
+
# @see Cassandra::Listener#host_found
|
|
85
|
+
def host_found(host)
|
|
86
|
+
self
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Noop
|
|
90
|
+
#
|
|
91
|
+
# @param host [Cassandra::Host] a host instance
|
|
92
|
+
# @return [Cassandra::LoadBalancing::Policies::RoundRobin] self
|
|
93
|
+
# @see Cassandra::Listener#host_lost
|
|
94
|
+
def host_lost(host)
|
|
95
|
+
self
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Returns distance to host. All hosts in rotation are considered
|
|
99
|
+
# `:local`, all other hosts - `:ignore`.
|
|
100
|
+
#
|
|
101
|
+
# @param host [Cassandra::Host] a host instance
|
|
102
|
+
# @return [Symbol] `:local` for all hosts in rotation and `:ignore` for
|
|
103
|
+
# all other hosts.
|
|
104
|
+
# @see Cassandra::LoadBalancing::Policy#distance
|
|
105
|
+
def distance(host)
|
|
106
|
+
@hosts.include?(host) ? :local : :ignore
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Returns a load balancing plan that rotates hosts by 1 each time a
|
|
110
|
+
# plan is requested.
|
|
111
|
+
#
|
|
112
|
+
# @param keyspace [String] current keyspace of the {Cassandra::Session}
|
|
113
|
+
# @param statement [Cassandra::Statement] actual statement to be
|
|
114
|
+
# executed
|
|
115
|
+
# @param options [Cassandra::Execution::Options] execution options to
|
|
116
|
+
# be used
|
|
117
|
+
# @return [Cassandra::LoadBalancing::Plan] a rotated load balancing plan
|
|
118
|
+
# @see Cassandra::LoadBalancing::Policy#plan
|
|
119
|
+
def plan(keyspace, statement, options)
|
|
120
|
+
hosts = @hosts
|
|
121
|
+
position = @position
|
|
122
|
+
total = hosts.size
|
|
123
|
+
return EMPTY_PLAN if total == 0
|
|
124
|
+
|
|
125
|
+
@position = (position + 1) % total
|
|
126
|
+
|
|
127
|
+
Plan.new(hosts, position)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
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 LoadBalancing
|
|
21
|
+
module Policies
|
|
22
|
+
class TokenAware < Policy
|
|
23
|
+
# @private
|
|
24
|
+
class Plan
|
|
25
|
+
def initialize(hosts, policy, keyspace, statement, options)
|
|
26
|
+
@hosts = hosts
|
|
27
|
+
@policy = policy
|
|
28
|
+
@keyspace = keyspace
|
|
29
|
+
@statement = statement
|
|
30
|
+
@options = options
|
|
31
|
+
@seen = ::Hash.new
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def has_next?
|
|
35
|
+
until @hosts.empty?
|
|
36
|
+
host = @hosts.shift
|
|
37
|
+
|
|
38
|
+
if @policy.distance(host) == :local
|
|
39
|
+
@seen[host] = true
|
|
40
|
+
@next = host
|
|
41
|
+
break
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
return true if @next
|
|
46
|
+
|
|
47
|
+
@plan ||= @policy.plan(@keyspace, @statement, @options)
|
|
48
|
+
|
|
49
|
+
while @plan.has_next?
|
|
50
|
+
host = @plan.next
|
|
51
|
+
|
|
52
|
+
unless @seen[host]
|
|
53
|
+
@next = host
|
|
54
|
+
return true
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
false
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def next
|
|
62
|
+
host = @next
|
|
63
|
+
@next = nil
|
|
64
|
+
host
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
extend Forwardable
|
|
69
|
+
|
|
70
|
+
# @!method distance(host)
|
|
71
|
+
# Delegates to wrapped policy
|
|
72
|
+
# @see Cassandra::LoadBalancing::Policy#distance
|
|
73
|
+
#
|
|
74
|
+
# @!method host_found(host)
|
|
75
|
+
# Delegates to wrapped policy
|
|
76
|
+
# @see Cassandra::LoadBalancing::Policy#host_found
|
|
77
|
+
#
|
|
78
|
+
# @!method host_up(host)
|
|
79
|
+
# Delegates to wrapped policy
|
|
80
|
+
# @see Cassandra::LoadBalancing::Policy#host_up
|
|
81
|
+
#
|
|
82
|
+
# @!method host_down(host)
|
|
83
|
+
# Delegates to wrapped policy
|
|
84
|
+
# @see Cassandra::LoadBalancing::Policy#host_down
|
|
85
|
+
#
|
|
86
|
+
# @!method host_lost(host)
|
|
87
|
+
# Delegates to wrapped policy
|
|
88
|
+
# @see Cassandra::LoadBalancing::Policy#host_lost
|
|
89
|
+
def_delegators :@policy, :distance, :host_found, :host_up, :host_down, :host_lost
|
|
90
|
+
|
|
91
|
+
# @param wrapped_policy [Cassandra::LoadBalancing::Policy] actual policy to filter
|
|
92
|
+
def initialize(wrapped_policy)
|
|
93
|
+
methods = [:host_up, :host_down, :host_found, :host_lost, :distance, :plan]
|
|
94
|
+
|
|
95
|
+
unless methods.all? {|method| wrapped_policy.respond_to?(method)}
|
|
96
|
+
raise ::ArgumentError, "supplied policy must be a Cassandra::LoadBalancing::Policy, #{wrapped_policy.inspect} given"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
@policy = wrapped_policy
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def setup(cluster)
|
|
103
|
+
@cluster = cluster
|
|
104
|
+
@policy.setup(cluster)
|
|
105
|
+
nil
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def plan(keyspace, statement, options)
|
|
109
|
+
return @policy.plan(keyspace, statement, options) unless @cluster
|
|
110
|
+
|
|
111
|
+
replicas = @cluster.find_replicas(keyspace, statement)
|
|
112
|
+
return @policy.plan(keyspace, statement, options) if replicas.empty?
|
|
113
|
+
|
|
114
|
+
Plan.new(replicas.dup, @policy, keyspace, statement, options)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|