cassandra-driver 1.0.0.beta.1 → 1.0.0.beta.2

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.
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
@@ -0,0 +1,39 @@
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 None
26
+ def replication_map(token_hosts, token_ring, replication_options)
27
+ replication_map = ::Hash.new
28
+
29
+ token_hosts.each do |token, host|
30
+ replication_map[token] = [host].freeze
31
+ end
32
+
33
+ replication_map
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,44 @@
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 Simple
26
+ def replication_map(token_hosts, token_ring, replication_options)
27
+ factor = Integer(replication_options['replication_factor'])
28
+ size = token_ring.size
29
+ factor = size if size < factor
30
+ replication_map = ::Hash.new
31
+
32
+ token_ring.each_with_index do |token, i|
33
+ replication_map[token] = factor.times.map do |j|
34
+ token_hosts[token_ring[(i + j) % size]]
35
+ end.freeze
36
+ end
37
+
38
+ replication_map
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -45,7 +45,7 @@ module Cassandra
45
45
  "org.apache.cassandra.db.marshal.MapType" => :map,
46
46
  "org.apache.cassandra.db.marshal.SetType" => :set,
47
47
  "org.apache.cassandra.db.marshal.ListType" => :list
48
- }
48
+ }.freeze
49
49
 
50
50
  def parse(string)
51
51
  create_result(parse_node(string))
@@ -18,7 +18,7 @@
18
18
 
19
19
  module Cassandra
20
20
  module Compression
21
- # @note Compressors given to {Cassandra.connect} as the `:compressor`
21
+ # @abstract Compressors given to {Cassandra.connect} as the `:compressor`
22
22
  # option don't need to be subclasses of this class, but need to implement
23
23
  # the same methods. This class exists only for documentation purposes.
24
24
  class Compressor
@@ -27,15 +27,38 @@ module Cassandra
27
27
  let(:io_reactor) { Io::IoReactor.new }
28
28
  let(:cluster_registry) { Cluster::Registry.new(logger) }
29
29
  let(:cluster_schema) { Cluster::Schema.new(schema_type_parser) }
30
+ let(:cluster_metadata) { Cluster::Metadata.new(
31
+ cluster_registry,
32
+ cluster_schema,
33
+ {
34
+ 'org.apache.cassandra.dht.Murmur3Partitioner' => murmur3_partitioner,
35
+ 'org.apache.cassandra.dht.ByteOrderedPartitioner' => ordered_partitioner,
36
+ 'org.apache.cassandra.dht.RandomPartitioner' => random_partitioner
37
+ }.freeze,
38
+ {
39
+ 'org.apache.cassandra.locator.SimpleStrategy' => simple_replication_strategy,
40
+ 'org.apache.cassandra.locator.NetworkTopologyStrategy' => network_topology_replication_strategy
41
+ }.freeze,
42
+ no_replication_strategy
43
+ )
44
+ }
30
45
  let(:futures_factory) { Future }
31
46
 
32
47
  let(:schema_type_parser) { Cluster::Schema::TypeParser.new }
33
48
 
49
+ let(:simple_replication_strategy) { Cluster::Schema::ReplicationStrategies::Simple.new }
50
+ let(:network_topology_replication_strategy) { Cluster::Schema::ReplicationStrategies::NetworkTopology.new }
51
+ let(:no_replication_strategy) { Cluster::Schema::ReplicationStrategies::None.new }
52
+
53
+ let(:murmur3_partitioner) { Cluster::Schema::Partitioners::Murmur3.new }
54
+ let(:ordered_partitioner) { Cluster::Schema::Partitioners::Ordered.new }
55
+ let(:random_partitioner) { Cluster::Schema::Partitioners::Random.new }
56
+
34
57
  let(:connector) { Cluster::Connector.new(logger, io_reactor, cluster_registry, connection_options) }
35
58
 
36
- let(:control_connection) { Cluster::ControlConnection.new(logger, io_reactor, cluster_registry, cluster_schema, load_balancing_policy, reconnection_policy, connector) }
59
+ let(:control_connection) { Cluster::ControlConnection.new(logger, io_reactor, cluster_registry, cluster_schema, cluster_metadata, load_balancing_policy, reconnection_policy, connector) }
37
60
 
38
- let(:cluster) { Cluster.new(logger, io_reactor, control_connection, cluster_registry, cluster_schema, execution_options, connection_options, load_balancing_policy, reconnection_policy, retry_policy, connector, futures_factory) }
61
+ let(:cluster) { Cluster.new(logger, io_reactor, control_connection, cluster_registry, cluster_schema, cluster_metadata, execution_options, connection_options, load_balancing_policy, reconnection_policy, retry_policy, connector, futures_factory) }
39
62
 
40
63
  let(:execution_options) do
41
64
  Execution::Options.new({
@@ -45,11 +68,12 @@ module Cassandra
45
68
  })
46
69
  end
47
70
 
48
- let(:connection_options) { Cluster::Options.new(protocol_version, credentials, auth_provider, compressor, port, connection_timeout, connections_per_local_node, connections_per_remote_node) }
71
+ let(:connection_options) { Cluster::Options.new(protocol_version, credentials, auth_provider, compressor, port, connect_timeout, ssl, connections_per_local_node, connections_per_remote_node) }
49
72
 
50
73
  let(:port) { 9042 }
51
74
  let(:protocol_version) { 2 }
52
- let(:connection_timeout) { 10 }
75
+ let(:connect_timeout) { 10 }
76
+ let(:ssl) { false }
53
77
  let(:logger) { Client::NullLogger.new }
54
78
  let(:compressor) { nil }
55
79
  let(:credentials) { nil }
@@ -72,6 +96,7 @@ module Cassandra
72
96
  end
73
97
 
74
98
  def connect(addresses)
99
+ load_balancing_policy.setup(cluster)
75
100
  cluster_registry.add_listener(load_balancing_policy)
76
101
  cluster_registry.add_listener(control_connection)
77
102
  listeners.each do |listener|
@@ -45,6 +45,9 @@ module Cassandra
45
45
  page_size = page_size && Integer(page_size)
46
46
  timeout = timeout && Integer(timeout)
47
47
 
48
+ raise ::ArgumentError, ":page_size must be greater than 0, #{page_size.inspect} given" if page_size && page_size <= 0
49
+ raise ::ArgumentError, ":timeout must be greater than 0, #{timeout.inspect} given" if timeout && timeout <= 0
50
+
48
51
  @consistency = consistency
49
52
  @page_size = page_size
50
53
  @trace = !!trace
@@ -20,28 +20,32 @@ module Cassandra
20
20
  class Host
21
21
  # @return [IPAddr] host ip
22
22
  attr_reader :ip
23
- # @note Host id can be `nil` before cluster connected.
23
+ # @note Host id can be `nil` before cluster has connected.
24
24
  # @return [Cassandra::Uuid, nil] host id.
25
25
  attr_reader :id
26
- # @note Host datacenter can be `nil` before cluster connected.
26
+ # @note Host datacenter can be `nil` before cluster has connected.
27
27
  # @return [String, nil] host datacenter
28
28
  attr_reader :datacenter
29
- # @note Host rack can be `nil` before cluster connected.
29
+ # @note Host rack can be `nil` before cluster has connected.
30
30
  # @return [String, nil] host rack
31
31
  attr_reader :rack
32
- # @note Host's cassandra version can be `nil` before cluster connected.
32
+ # @note Host's cassandra version can be `nil` before cluster has connected.
33
33
  # @return [String, nil] version of cassandra that a host is running
34
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
35
38
  # @return [Symbol] host status. Must be `:up` or `:down`
36
39
  attr_reader :status
37
40
 
38
41
  # @private
39
- def initialize(ip, id = nil, rack = nil, datacenter = nil, release_version = nil, status = :up)
42
+ def initialize(ip, id = nil, rack = nil, datacenter = nil, release_version = nil, tokens = EMPTY_LIST, status = :up)
40
43
  @ip = ip
41
44
  @id = id
42
45
  @rack = rack
43
46
  @datacenter = datacenter
44
47
  @release_version = release_version
48
+ @tokens = tokens
45
49
  @status = status
46
50
  end
47
51
 
@@ -78,11 +78,16 @@ module Cassandra
78
78
  # Yield or enumerate each table defined in this keyspace
79
79
  # @overload each_table
80
80
  # @yieldparam table [Cassandra::Table] current table
81
- # @return [Array<Cassandra::Table>] a list of tables
81
+ # @return [Cassandra::Keyspace] self
82
82
  # @overload each_table
83
- # @return [Enumerator<Cassandra::Table>] an enumerator
83
+ # @return [Array<Cassandra::Table>] a list of tables
84
84
  def each_table(&block)
85
- @tables.values.each(&block)
85
+ if block_given?
86
+ @tables.each_value(&block)
87
+ self
88
+ else
89
+ @tables.values
90
+ end
86
91
  end
87
92
  alias :tables :each_table
88
93
 
@@ -103,7 +108,15 @@ module Cassandra
103
108
 
104
109
  # @private
105
110
  def update_table(table)
106
- Keyspace.new(@name, @durable_writes, @replication, @tables.merge(table.name => 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)
107
120
  end
108
121
 
109
122
  # @private
@@ -19,9 +19,9 @@
19
19
  module Cassandra
20
20
  # Cassandra state listener.
21
21
  #
22
- # @note Actual state listener implementations don't need to inherit from this
23
- # class as long as they conform to its interface. This class exists solely
24
- # for documentation purposes
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
25
  #
26
26
  # @see Cassandra::Cluster#register
27
27
  class Listener
@@ -22,34 +22,36 @@ module Cassandra
22
22
  # {Cassandra::LoadBalancing::Policy#distance} must return
23
23
  DISTANCES = [:ignore, :local, :remote].freeze
24
24
 
25
- # @note Actual load balancing policies don't need to extend this class,
25
+ # @abstract Actual load balancing policies don't need to extend this class,
26
26
  # only implement its methods. This class exists for documentation
27
- # purposes only
27
+ # purposes only.
28
28
  class Policy
29
- # @abstract implementation should be provided by an actual policy
29
+ # Allows policy to initialize with the cluster instance. This method is
30
+ # called once before connecting to the cluster.
31
+ # @param cluster [Cassandra::Cluster] current cluster instance
32
+ # @return [void]
33
+ def setup(cluster)
34
+ end
35
+
30
36
  # @see Cassandra::Listener#host_up
31
37
  def host_up(host)
32
38
  end
33
39
 
34
- # @abstract implementation should be provided by an actual policy
35
40
  # @see Cassandra::Listener#host_down
36
41
  def host_down(host)
37
42
  end
38
43
 
39
- # @abstract implementation should be provided by an actual policy
40
44
  # @see Cassandra::Listener#host_found
41
45
  def host_found(host)
42
46
  end
43
47
 
44
- # @abstract implementation should be provided by an actual policy
45
48
  # @see Cassandra::Listener#host_lost
46
49
  def host_lost(host)
47
50
  end
48
51
 
49
- # Returns a distance that lets the driver to determine host many
50
- # connections (if any) to open to the host
52
+ # Returns a distance that determines how many connections (if any) the
53
+ # driver will open to the host.
51
54
  #
52
- # @abstract implementation should be provided by an actual policy
53
55
  # @param host [Cassandra::Host] a host instance
54
56
  # @return [Symbol] distance to host. Must be one of
55
57
  # {Cassandra::LoadBalancing::DISTANCES}
@@ -62,7 +64,6 @@ module Cassandra
62
64
  #
63
65
  # @note Hosts that should be ignored, must not be included in the Plan
64
66
  #
65
- # @abstract implementation should be provided by an actual policy
66
67
  # @param keyspace [String] current keyspace of the {Cassandra::Session}
67
68
  # @param statement [Cassandra::Statement] actual statement to be executed
68
69
  # @param options [Cassandra::Execution::Options] execution options to be used
@@ -80,7 +81,7 @@ module Cassandra
80
81
 
81
82
  # A load balancing plan is used to determine the order of hosts for running
82
83
  # queries, preparing statements and establishing connections.
83
- # @note Plans returned by {Cassandra::LoadBalancing::Policy}
84
+ # @abstract Plans returned by {Cassandra::LoadBalancing::Policy#plan}
84
85
  # implementations don't need to extend this class, only implement its
85
86
  # methods. This class exists for documentation purposes only.
86
87
  class Plan
@@ -13,6 +13,7 @@
13
13
  # limitations under the License.
14
14
  #++
15
15
 
16
- require 'cassandra/load_balancing/policies/round_robin'
17
16
  require 'cassandra/load_balancing/policies/dc_aware_round_robin'
17
+ require 'cassandra/load_balancing/policies/round_robin'
18
+ require 'cassandra/load_balancing/policies/token_aware'
18
19
  require 'cassandra/load_balancing/policies/white_list'
@@ -124,7 +124,7 @@ module Cassandra
124
124
  if LOCAL_CONSISTENCIES.include?(options.consistency) && !@use_remote
125
125
  remote = EMPTY_ARRAY
126
126
  else
127
- remote = @remote
127
+ remote = @remote
128
128
  end
129
129
 
130
130
  position = @position
@@ -52,12 +52,22 @@ module Cassandra
52
52
  mon_initialize
53
53
  end
54
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
55
60
  def host_up(host)
56
61
  synchronize { @hosts = @hosts.dup.push(host) }
57
62
 
58
63
  self
59
64
  end
60
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
61
71
  def host_down(host)
62
72
  synchronize do
63
73
  @hosts = @hosts.dup
@@ -67,18 +77,45 @@ module Cassandra
67
77
  self
68
78
  end
69
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
70
85
  def host_found(host)
71
86
  self
72
87
  end
73
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
74
94
  def host_lost(host)
75
95
  self
76
96
  end
77
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
78
105
  def distance(host)
79
106
  @hosts.include?(host) ? :local : :ignore
80
107
  end
81
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
82
119
  def plan(keyspace, statement, options)
83
120
  hosts = @hosts
84
121
  position = @position
@@ -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