cassandra-driver 1.0.0.beta.1 → 1.0.0.beta.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +20 -12
- data/ext/cassandra_murmur3/cassandra_murmur3.c +178 -0
- data/ext/cassandra_murmur3/extconf.rb +2 -0
- data/lib/cassandra.rb +132 -24
- data/lib/cassandra/auth.rb +5 -5
- data/lib/cassandra/client/connector.rb +11 -6
- data/lib/cassandra/cluster.rb +47 -23
- data/lib/cassandra/cluster/client.rb +5 -4
- data/lib/cassandra/cluster/connector.rb +17 -4
- data/lib/cassandra/cluster/control_connection.rb +21 -16
- data/lib/cassandra/cluster/metadata.rb +124 -0
- data/lib/cassandra/cluster/options.rb +5 -3
- data/lib/cassandra/cluster/registry.rb +26 -9
- data/lib/cassandra/cluster/schema.rb +23 -4
- data/lib/cassandra/cluster/schema/partitioners.rb +21 -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/replication_strategies.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/type_parser.rb +1 -1
- data/lib/cassandra/compression.rb +1 -1
- data/lib/cassandra/driver.rb +29 -4
- data/lib/cassandra/execution/options.rb +3 -0
- data/lib/cassandra/host.rb +9 -5
- data/lib/cassandra/keyspace.rb +17 -4
- data/lib/cassandra/listener.rb +3 -3
- data/lib/cassandra/load_balancing.rb +12 -11
- data/lib/cassandra/load_balancing/policies.rb +2 -1
- data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +1 -1
- data/lib/cassandra/load_balancing/policies/round_robin.rb +37 -0
- data/lib/cassandra/load_balancing/policies/token_aware.rb +119 -0
- data/lib/cassandra/protocol/cql_protocol_handler.rb +2 -2
- data/lib/cassandra/reconnection.rb +5 -5
- data/lib/cassandra/retry.rb +3 -3
- data/lib/cassandra/session.rb +7 -0
- data/lib/cassandra/statements/bound.rb +4 -2
- data/lib/cassandra/statements/prepared.rb +28 -6
- data/lib/cassandra/table.rb +49 -4
- data/lib/cassandra/time_uuid.rb +1 -0
- data/lib/cassandra/util.rb +0 -2
- data/lib/cassandra/version.rb +1 -1
- metadata +50 -45
@@ -21,16 +21,18 @@ module Cassandra
|
|
21
21
|
# @private
|
22
22
|
class Options
|
23
23
|
attr_reader :credentials, :auth_provider, :compressor, :port,
|
24
|
-
:
|
24
|
+
:connect_timeout, :ssl, :connections_per_local_node,
|
25
|
+
:connections_per_remote_node
|
25
26
|
attr_accessor :protocol_version
|
26
27
|
|
27
|
-
def initialize(protocol_version, credentials, auth_provider, compressor, port,
|
28
|
+
def initialize(protocol_version, credentials, auth_provider, compressor, port, connect_timeout, ssl, connections_per_local_node, connections_per_remote_node)
|
28
29
|
@protocol_version = protocol_version
|
29
30
|
@credentials = credentials
|
30
31
|
@auth_provider = auth_provider
|
31
32
|
@compressor = compressor
|
32
33
|
@port = port
|
33
|
-
@
|
34
|
+
@connect_timeout = connect_timeout
|
35
|
+
@ssl = ssl
|
34
36
|
|
35
37
|
@connections_per_local_node = connections_per_local_node
|
36
38
|
@connections_per_remote_node = connections_per_remote_node
|
@@ -45,7 +45,12 @@ module Cassandra
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def each_host(&block)
|
48
|
-
|
48
|
+
if block_given?
|
49
|
+
@hosts.each_value(&block)
|
50
|
+
self
|
51
|
+
else
|
52
|
+
@hosts.values
|
53
|
+
end
|
49
54
|
end
|
50
55
|
alias :hosts :each_host
|
51
56
|
|
@@ -81,7 +86,11 @@ module Cassandra
|
|
81
86
|
notify_found(host)
|
82
87
|
end
|
83
88
|
|
84
|
-
synchronize
|
89
|
+
synchronize do
|
90
|
+
hosts = @hosts.dup
|
91
|
+
hosts[ip] = host
|
92
|
+
@hosts = hosts
|
93
|
+
end
|
85
94
|
|
86
95
|
self
|
87
96
|
end
|
@@ -94,7 +103,11 @@ module Cassandra
|
|
94
103
|
|
95
104
|
host = toggle_down(host)
|
96
105
|
|
97
|
-
synchronize
|
106
|
+
synchronize do
|
107
|
+
hosts = @hosts.dup
|
108
|
+
hosts[ip] = host
|
109
|
+
@hosts = hosts
|
110
|
+
end
|
98
111
|
|
99
112
|
self
|
100
113
|
end
|
@@ -107,7 +120,11 @@ module Cassandra
|
|
107
120
|
|
108
121
|
host = toggle_up(host)
|
109
122
|
|
110
|
-
synchronize
|
123
|
+
synchronize do
|
124
|
+
hosts = @hosts.dup
|
125
|
+
hosts[ip] = host
|
126
|
+
@hosts = hosts
|
127
|
+
end
|
111
128
|
|
112
129
|
self
|
113
130
|
end
|
@@ -126,17 +143,17 @@ module Cassandra
|
|
126
143
|
|
127
144
|
notify_lost(host)
|
128
145
|
|
129
|
-
|
146
|
+
host
|
130
147
|
end
|
131
148
|
|
132
149
|
private
|
133
150
|
|
134
151
|
def create_host(ip, data)
|
135
|
-
Host.new(ip, data['host_id'], data['rack'], data['data_center'], data['release_version'], :up)
|
152
|
+
Host.new(ip, data['host_id'], data['rack'], data['data_center'], data['release_version'], data['tokens'].freeze, :up)
|
136
153
|
end
|
137
154
|
|
138
155
|
def toggle_up(host)
|
139
|
-
host = Host.new(host.ip, host.id, host.rack, host.datacenter, host.release_version, :up)
|
156
|
+
host = Host.new(host.ip, host.id, host.rack, host.datacenter, host.release_version, host.tokens, :up)
|
140
157
|
@logger.debug("Host #{host.ip} is up")
|
141
158
|
@listeners.each do |listener|
|
142
159
|
listener.host_up(host) rescue nil
|
@@ -145,7 +162,7 @@ module Cassandra
|
|
145
162
|
end
|
146
163
|
|
147
164
|
def toggle_down(host)
|
148
|
-
host = Host.new(host.ip, host.id, host.rack, host.datacenter, host.release_version, :down)
|
165
|
+
host = Host.new(host.ip, host.id, host.rack, host.datacenter, host.release_version, host.tokens, :down)
|
149
166
|
@logger.debug("Host #{host.ip} is down")
|
150
167
|
@listeners.each do |listener|
|
151
168
|
listener.host_down(host) rescue nil
|
@@ -156,7 +173,7 @@ module Cassandra
|
|
156
173
|
def notify_lost(host)
|
157
174
|
if host.up?
|
158
175
|
@logger.debug("Host #{host.ip} is down and lost")
|
159
|
-
host = Host.new(host.ip, host.id, host.rack, host.datacenter, host.release_version, :down)
|
176
|
+
host = Host.new(host.ip, host.id, host.rack, host.datacenter, host.release_version, host.tokens, :down)
|
160
177
|
@listeners.each do |listener|
|
161
178
|
listener.host_down(host) rescue nil
|
162
179
|
listener.host_lost(host) rescue nil
|
@@ -30,6 +30,11 @@ module Cassandra
|
|
30
30
|
mon_initialize
|
31
31
|
end
|
32
32
|
|
33
|
+
def create_partition_key(keyspace, table, values)
|
34
|
+
keyspace = @keyspaces[keyspace]
|
35
|
+
keyspace && keyspace.create_partition_key(table, values)
|
36
|
+
end
|
37
|
+
|
33
38
|
def add_listener(listener)
|
34
39
|
synchronize do
|
35
40
|
@listeners = @listeners.dup.add(listener)
|
@@ -90,7 +95,9 @@ module Cassandra
|
|
90
95
|
created = !@keyspaces.include?(keyspace_name)
|
91
96
|
|
92
97
|
synchronize do
|
93
|
-
|
98
|
+
keyspaces = @keyspaces.dup
|
99
|
+
keyspaces[keyspace_name] = keyspace
|
100
|
+
@keyspaces = keyspaces
|
94
101
|
end
|
95
102
|
|
96
103
|
if created
|
@@ -127,7 +134,9 @@ module Cassandra
|
|
127
134
|
keyspace = keyspace.update_table(table)
|
128
135
|
|
129
136
|
synchronize do
|
130
|
-
|
137
|
+
keyspaces = @keyspaces.dup
|
138
|
+
keyspaces[keyspace_name] = keyspace
|
139
|
+
@keyspaces = keyspaces
|
131
140
|
end
|
132
141
|
|
133
142
|
keyspace_updated(keyspace)
|
@@ -144,7 +153,12 @@ module Cassandra
|
|
144
153
|
end
|
145
154
|
|
146
155
|
def each_keyspace(&block)
|
147
|
-
|
156
|
+
if block_given?
|
157
|
+
@keyspaces.each_value(&block)
|
158
|
+
self
|
159
|
+
else
|
160
|
+
@keyspaces.values
|
161
|
+
end
|
148
162
|
end
|
149
163
|
alias :keyspaces :each_keyspace
|
150
164
|
|
@@ -235,7 +249,8 @@ module Cassandra
|
|
235
249
|
end
|
236
250
|
|
237
251
|
if is_dense
|
238
|
-
value_alias = table['value_alias']
|
252
|
+
value_alias = table['value_alias']
|
253
|
+
value_alias = 'value' if value_alias.nil? || value_alias.empty?
|
239
254
|
type, order = @type_parser.parse(table['default_validator']).results.first
|
240
255
|
other_columns << Column.new(value_alias, type, order)
|
241
256
|
end
|
@@ -245,6 +260,8 @@ module Cassandra
|
|
245
260
|
end
|
246
261
|
else
|
247
262
|
columns.each do |name, row|
|
263
|
+
next if row['column_name'].empty?
|
264
|
+
|
248
265
|
column = create_column(row)
|
249
266
|
type = row['type']
|
250
267
|
index = row['component_index'] || 0
|
@@ -318,4 +335,6 @@ module Cassandra
|
|
318
335
|
end
|
319
336
|
end
|
320
337
|
|
338
|
+
require 'cassandra/cluster/schema/partitioners'
|
339
|
+
require 'cassandra/cluster/schema/replication_strategies'
|
321
340
|
require 'cassandra/cluster/schema/type_parser'
|
@@ -0,0 +1,21 @@
|
|
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
|
+
require 'cassandra/cluster/schema/partitioners/ordered'
|
20
|
+
require 'cassandra/cluster/schema/partitioners/random'
|
21
|
+
require 'cassandra/cluster/schema/partitioners/murmur3'
|
@@ -0,0 +1,47 @@
|
|
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 Cluster
|
21
|
+
class Schema
|
22
|
+
# @private
|
23
|
+
module Partitioners
|
24
|
+
# @private
|
25
|
+
class Murmur3
|
26
|
+
def create_token(partition_key)
|
27
|
+
token = Cassandra::Murmur3.hash(partition_key)
|
28
|
+
token = LONG_MAX if token == LONG_MIN
|
29
|
+
|
30
|
+
token
|
31
|
+
end
|
32
|
+
|
33
|
+
def parse_token(token_string)
|
34
|
+
token_string.to_i
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
# @private
|
40
|
+
LONG_MIN = -2 ** 63
|
41
|
+
# @private
|
42
|
+
LONG_MAX = 2 ** 63 - 1
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,37 @@
|
|
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 Cluster
|
21
|
+
class Schema
|
22
|
+
# @private
|
23
|
+
module Partitioners
|
24
|
+
# @private
|
25
|
+
class Ordered
|
26
|
+
def create_token(partition_key)
|
27
|
+
partition_key
|
28
|
+
end
|
29
|
+
|
30
|
+
def parse_token(token_string)
|
31
|
+
token_string
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,37 @@
|
|
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 Cluster
|
21
|
+
class Schema
|
22
|
+
# @private
|
23
|
+
module Partitioners
|
24
|
+
# @private
|
25
|
+
class Random
|
26
|
+
def create_token(partition_key)
|
27
|
+
Digest::MD5.hexdigest(partition_key).to_i(16)
|
28
|
+
end
|
29
|
+
|
30
|
+
def parse_token(token_string)
|
31
|
+
token_string.to_i
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,21 @@
|
|
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
|
+
require 'cassandra/cluster/schema/replication_strategies/simple'
|
20
|
+
require 'cassandra/cluster/schema/replication_strategies/network_topology'
|
21
|
+
require 'cassandra/cluster/schema/replication_strategies/none'
|
@@ -0,0 +1,92 @@
|
|
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 Cluster
|
21
|
+
class Schema
|
22
|
+
# @private
|
23
|
+
module ReplicationStrategies
|
24
|
+
# @private
|
25
|
+
class NetworkTopology
|
26
|
+
def replication_map(token_hosts, token_ring, replication_options)
|
27
|
+
size = token_ring.size
|
28
|
+
racks = ::Hash.new
|
29
|
+
token_hosts.each_value do |host|
|
30
|
+
racks[host.datacenter] ||= ::Set.new
|
31
|
+
racks[host.datacenter].add(host.rack)
|
32
|
+
end
|
33
|
+
|
34
|
+
replication_map = ::Hash.new
|
35
|
+
|
36
|
+
token_ring.each_with_index do |token, i|
|
37
|
+
all_replicas = ::Hash.new
|
38
|
+
visited = ::Hash.new
|
39
|
+
skipped_datacenter_hosts = ::Hash.new
|
40
|
+
replicas = ::Set.new
|
41
|
+
|
42
|
+
size.times do |j|
|
43
|
+
break if all_replicas.size == racks.size && !all_replicas.any? {|(datacenter, r)| r.size < Integer(replication_options[datacenter])}
|
44
|
+
|
45
|
+
host = token_hosts[token_ring[(i + j) % size]]
|
46
|
+
datacenter = host.datacenter
|
47
|
+
next if datacenter.nil?
|
48
|
+
|
49
|
+
factor = replication_options[datacenter]
|
50
|
+
next unless factor
|
51
|
+
|
52
|
+
factor = Integer(factor) rescue next
|
53
|
+
|
54
|
+
replicas_in_datacenter = all_replicas[datacenter] ||= ::Set.new
|
55
|
+
next if replicas_in_datacenter.size >= factor
|
56
|
+
|
57
|
+
rack = host.rack
|
58
|
+
visited_racks = visited[datacenter] ||= ::Set.new
|
59
|
+
|
60
|
+
if rack.nil? || visited_racks.size == racks[datacenter].size
|
61
|
+
replicas << host
|
62
|
+
replicas_in_datacenter << host
|
63
|
+
else
|
64
|
+
if visited_racks.include?(rack)
|
65
|
+
skipped_hosts = skipped_datacenter_hosts[datacenter] ||= ::Set.new
|
66
|
+
skipped_hosts << host
|
67
|
+
else
|
68
|
+
replicas << host
|
69
|
+
replicas_in_datacenter << host
|
70
|
+
visited_racks << rack
|
71
|
+
|
72
|
+
if visited_racks.size == racks[datacenter].size && (skipped_hosts = skipped_datacenter_hosts[datacenter]) && replicas_in_datacenter.size < factor
|
73
|
+
skipped_hosts.each do |skipped_host|
|
74
|
+
replicas << skipped_host
|
75
|
+
replicas_in_datacenter << skipped_host
|
76
|
+
break if replicas_in_datacenter.size >= factor
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
replication_map[token] = replicas.to_a.freeze
|
84
|
+
end
|
85
|
+
|
86
|
+
replication_map
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|