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.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +20 -12
  3. data/ext/cassandra_murmur3/cassandra_murmur3.c +178 -0
  4. data/ext/cassandra_murmur3/extconf.rb +2 -0
  5. data/lib/cassandra.rb +132 -24
  6. data/lib/cassandra/auth.rb +5 -5
  7. data/lib/cassandra/client/connector.rb +11 -6
  8. data/lib/cassandra/cluster.rb +47 -23
  9. data/lib/cassandra/cluster/client.rb +5 -4
  10. data/lib/cassandra/cluster/connector.rb +17 -4
  11. data/lib/cassandra/cluster/control_connection.rb +21 -16
  12. data/lib/cassandra/cluster/metadata.rb +124 -0
  13. data/lib/cassandra/cluster/options.rb +5 -3
  14. data/lib/cassandra/cluster/registry.rb +26 -9
  15. data/lib/cassandra/cluster/schema.rb +23 -4
  16. data/lib/cassandra/cluster/schema/partitioners.rb +21 -0
  17. data/lib/cassandra/cluster/schema/partitioners/murmur3.rb +47 -0
  18. data/lib/cassandra/cluster/schema/partitioners/ordered.rb +37 -0
  19. data/lib/cassandra/cluster/schema/partitioners/random.rb +37 -0
  20. data/lib/cassandra/cluster/schema/replication_strategies.rb +21 -0
  21. data/lib/cassandra/cluster/schema/replication_strategies/network_topology.rb +92 -0
  22. data/lib/cassandra/cluster/schema/replication_strategies/none.rb +39 -0
  23. data/lib/cassandra/cluster/schema/replication_strategies/simple.rb +44 -0
  24. data/lib/cassandra/cluster/schema/type_parser.rb +1 -1
  25. data/lib/cassandra/compression.rb +1 -1
  26. data/lib/cassandra/driver.rb +29 -4
  27. data/lib/cassandra/execution/options.rb +3 -0
  28. data/lib/cassandra/host.rb +9 -5
  29. data/lib/cassandra/keyspace.rb +17 -4
  30. data/lib/cassandra/listener.rb +3 -3
  31. data/lib/cassandra/load_balancing.rb +12 -11
  32. data/lib/cassandra/load_balancing/policies.rb +2 -1
  33. data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +1 -1
  34. data/lib/cassandra/load_balancing/policies/round_robin.rb +37 -0
  35. data/lib/cassandra/load_balancing/policies/token_aware.rb +119 -0
  36. data/lib/cassandra/protocol/cql_protocol_handler.rb +2 -2
  37. data/lib/cassandra/reconnection.rb +5 -5
  38. data/lib/cassandra/retry.rb +3 -3
  39. data/lib/cassandra/session.rb +7 -0
  40. data/lib/cassandra/statements/bound.rb +4 -2
  41. data/lib/cassandra/statements/prepared.rb +28 -6
  42. data/lib/cassandra/table.rb +49 -4
  43. data/lib/cassandra/time_uuid.rb +1 -0
  44. data/lib/cassandra/util.rb +0 -2
  45. data/lib/cassandra/version.rb +1 -1
  46. 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
- :connection_timeout, :connections_per_local_node, :connections_per_remote_node
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, connection_timeout, connections_per_local_node, connections_per_remote_node)
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
- @connection_timeout = connection_timeout
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
- @hosts.values.each(&block)
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 { @hosts = @hosts.merge(ip => host) }
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 { @hosts = @hosts.merge(ip => host) }
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 { @hosts = @hosts.merge(ip => host) }
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
- self
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
- @keyspaces = @keyspaces.merge(keyspace_name => keyspace)
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
- @keyspaces = @keyspaces.merge(keyspace_name => keyspace)
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
- @keyspaces.values.each(&block)
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'] || 'value'
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