yugabyte-ycql-driver 3.2.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +13 -0
  3. data/README.md +242 -0
  4. data/ext/cassandra_murmur3/cassandra_murmur3.c +178 -0
  5. data/ext/cassandra_murmur3/extconf.rb +2 -0
  6. data/lib/cassandra/address_resolution.rb +36 -0
  7. data/lib/cassandra/address_resolution/policies.rb +2 -0
  8. data/lib/cassandra/address_resolution/policies/ec2_multi_region.rb +56 -0
  9. data/lib/cassandra/address_resolution/policies/none.rb +35 -0
  10. data/lib/cassandra/aggregate.rb +123 -0
  11. data/lib/cassandra/argument.rb +51 -0
  12. data/lib/cassandra/attr_boolean.rb +33 -0
  13. data/lib/cassandra/auth.rb +100 -0
  14. data/lib/cassandra/auth/providers.rb +17 -0
  15. data/lib/cassandra/auth/providers/password.rb +65 -0
  16. data/lib/cassandra/cassandra_logger.rb +80 -0
  17. data/lib/cassandra/cluster.rb +331 -0
  18. data/lib/cassandra/cluster/client.rb +1612 -0
  19. data/lib/cassandra/cluster/connection_pool.rb +78 -0
  20. data/lib/cassandra/cluster/connector.rb +372 -0
  21. data/lib/cassandra/cluster/control_connection.rb +962 -0
  22. data/lib/cassandra/cluster/failed_connection.rb +35 -0
  23. data/lib/cassandra/cluster/metadata.rb +142 -0
  24. data/lib/cassandra/cluster/options.rb +145 -0
  25. data/lib/cassandra/cluster/registry.rb +284 -0
  26. data/lib/cassandra/cluster/schema.rb +405 -0
  27. data/lib/cassandra/cluster/schema/cql_type_parser.rb +112 -0
  28. data/lib/cassandra/cluster/schema/fetchers.rb +1627 -0
  29. data/lib/cassandra/cluster/schema/fqcn_type_parser.rb +175 -0
  30. data/lib/cassandra/cluster/schema/partitioners.rb +21 -0
  31. data/lib/cassandra/cluster/schema/partitioners/murmur3.rb +45 -0
  32. data/lib/cassandra/cluster/schema/partitioners/ordered.rb +37 -0
  33. data/lib/cassandra/cluster/schema/partitioners/random.rb +37 -0
  34. data/lib/cassandra/cluster/schema/replication_strategies.rb +21 -0
  35. data/lib/cassandra/cluster/schema/replication_strategies/network_topology.rb +102 -0
  36. data/lib/cassandra/cluster/schema/replication_strategies/none.rb +39 -0
  37. data/lib/cassandra/cluster/schema/replication_strategies/simple.rb +44 -0
  38. data/lib/cassandra/column.rb +66 -0
  39. data/lib/cassandra/column_container.rb +326 -0
  40. data/lib/cassandra/compression.rb +69 -0
  41. data/lib/cassandra/compression/compressors/lz4.rb +73 -0
  42. data/lib/cassandra/compression/compressors/snappy.rb +69 -0
  43. data/lib/cassandra/custom_data.rb +53 -0
  44. data/lib/cassandra/driver.rb +260 -0
  45. data/lib/cassandra/errors.rb +784 -0
  46. data/lib/cassandra/execution/info.rb +69 -0
  47. data/lib/cassandra/execution/options.rb +267 -0
  48. data/lib/cassandra/execution/profile.rb +153 -0
  49. data/lib/cassandra/execution/profile_manager.rb +71 -0
  50. data/lib/cassandra/execution/trace.rb +192 -0
  51. data/lib/cassandra/executors.rb +113 -0
  52. data/lib/cassandra/function.rb +156 -0
  53. data/lib/cassandra/function_collection.rb +85 -0
  54. data/lib/cassandra/future.rb +794 -0
  55. data/lib/cassandra/host.rb +102 -0
  56. data/lib/cassandra/index.rb +118 -0
  57. data/lib/cassandra/keyspace.rb +473 -0
  58. data/lib/cassandra/listener.rb +87 -0
  59. data/lib/cassandra/load_balancing.rb +121 -0
  60. data/lib/cassandra/load_balancing/policies.rb +20 -0
  61. data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +172 -0
  62. data/lib/cassandra/load_balancing/policies/round_robin.rb +141 -0
  63. data/lib/cassandra/load_balancing/policies/token_aware.rb +149 -0
  64. data/lib/cassandra/load_balancing/policies/white_list.rb +100 -0
  65. data/lib/cassandra/materialized_view.rb +92 -0
  66. data/lib/cassandra/null_logger.rb +56 -0
  67. data/lib/cassandra/protocol.rb +102 -0
  68. data/lib/cassandra/protocol/coder.rb +1085 -0
  69. data/lib/cassandra/protocol/cql_byte_buffer.rb +418 -0
  70. data/lib/cassandra/protocol/cql_protocol_handler.rb +448 -0
  71. data/lib/cassandra/protocol/request.rb +41 -0
  72. data/lib/cassandra/protocol/requests/auth_response_request.rb +51 -0
  73. data/lib/cassandra/protocol/requests/batch_request.rb +117 -0
  74. data/lib/cassandra/protocol/requests/credentials_request.rb +51 -0
  75. data/lib/cassandra/protocol/requests/execute_request.rb +122 -0
  76. data/lib/cassandra/protocol/requests/options_request.rb +39 -0
  77. data/lib/cassandra/protocol/requests/prepare_request.rb +59 -0
  78. data/lib/cassandra/protocol/requests/query_request.rb +112 -0
  79. data/lib/cassandra/protocol/requests/register_request.rb +38 -0
  80. data/lib/cassandra/protocol/requests/startup_request.rb +49 -0
  81. data/lib/cassandra/protocol/requests/void_query_request.rb +24 -0
  82. data/lib/cassandra/protocol/response.rb +28 -0
  83. data/lib/cassandra/protocol/responses/already_exists_error_response.rb +50 -0
  84. data/lib/cassandra/protocol/responses/auth_challenge_response.rb +36 -0
  85. data/lib/cassandra/protocol/responses/auth_success_response.rb +36 -0
  86. data/lib/cassandra/protocol/responses/authenticate_response.rb +36 -0
  87. data/lib/cassandra/protocol/responses/error_response.rb +142 -0
  88. data/lib/cassandra/protocol/responses/event_response.rb +30 -0
  89. data/lib/cassandra/protocol/responses/function_failure_error_response.rb +52 -0
  90. data/lib/cassandra/protocol/responses/prepared_result_response.rb +62 -0
  91. data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +59 -0
  92. data/lib/cassandra/protocol/responses/read_failure_error_response.rb +71 -0
  93. data/lib/cassandra/protocol/responses/read_timeout_error_response.rb +61 -0
  94. data/lib/cassandra/protocol/responses/ready_response.rb +43 -0
  95. data/lib/cassandra/protocol/responses/result_response.rb +42 -0
  96. data/lib/cassandra/protocol/responses/rows_result_response.rb +39 -0
  97. data/lib/cassandra/protocol/responses/schema_change_event_response.rb +73 -0
  98. data/lib/cassandra/protocol/responses/schema_change_result_response.rb +70 -0
  99. data/lib/cassandra/protocol/responses/set_keyspace_result_response.rb +37 -0
  100. data/lib/cassandra/protocol/responses/status_change_event_response.rb +39 -0
  101. data/lib/cassandra/protocol/responses/supported_response.rb +36 -0
  102. data/lib/cassandra/protocol/responses/topology_change_event_response.rb +33 -0
  103. data/lib/cassandra/protocol/responses/unavailable_error_response.rb +58 -0
  104. data/lib/cassandra/protocol/responses/unprepared_error_response.rb +48 -0
  105. data/lib/cassandra/protocol/responses/void_result_response.rb +34 -0
  106. data/lib/cassandra/protocol/responses/write_failure_error_response.rb +73 -0
  107. data/lib/cassandra/protocol/responses/write_timeout_error_response.rb +63 -0
  108. data/lib/cassandra/protocol/v1.rb +326 -0
  109. data/lib/cassandra/protocol/v3.rb +358 -0
  110. data/lib/cassandra/protocol/v4.rb +478 -0
  111. data/lib/cassandra/reconnection.rb +49 -0
  112. data/lib/cassandra/reconnection/policies.rb +20 -0
  113. data/lib/cassandra/reconnection/policies/constant.rb +46 -0
  114. data/lib/cassandra/reconnection/policies/exponential.rb +79 -0
  115. data/lib/cassandra/result.rb +276 -0
  116. data/lib/cassandra/retry.rb +154 -0
  117. data/lib/cassandra/retry/policies.rb +21 -0
  118. data/lib/cassandra/retry/policies/default.rb +53 -0
  119. data/lib/cassandra/retry/policies/downgrading_consistency.rb +73 -0
  120. data/lib/cassandra/retry/policies/fallthrough.rb +39 -0
  121. data/lib/cassandra/session.rb +270 -0
  122. data/lib/cassandra/statement.rb +32 -0
  123. data/lib/cassandra/statements.rb +23 -0
  124. data/lib/cassandra/statements/batch.rb +146 -0
  125. data/lib/cassandra/statements/bound.rb +65 -0
  126. data/lib/cassandra/statements/prepared.rb +235 -0
  127. data/lib/cassandra/statements/simple.rb +118 -0
  128. data/lib/cassandra/statements/void.rb +38 -0
  129. data/lib/cassandra/table.rb +240 -0
  130. data/lib/cassandra/time.rb +103 -0
  131. data/lib/cassandra/time_uuid.rb +78 -0
  132. data/lib/cassandra/timestamp_generator.rb +37 -0
  133. data/lib/cassandra/timestamp_generator/simple.rb +38 -0
  134. data/lib/cassandra/timestamp_generator/ticking_on_duplicate.rb +58 -0
  135. data/lib/cassandra/trigger.rb +67 -0
  136. data/lib/cassandra/tuple.rb +131 -0
  137. data/lib/cassandra/types.rb +1704 -0
  138. data/lib/cassandra/udt.rb +443 -0
  139. data/lib/cassandra/util.rb +464 -0
  140. data/lib/cassandra/uuid.rb +110 -0
  141. data/lib/cassandra/uuid/generator.rb +212 -0
  142. data/lib/cassandra/version.rb +21 -0
  143. data/lib/datastax/cassandra.rb +47 -0
  144. data/lib/ycql.rb +842 -0
  145. metadata +243 -0
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright 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
+ # @private
22
+ class FailedConnection
23
+ attr_reader :error, :host
24
+
25
+ def initialize(error, host)
26
+ @error = error
27
+ @host = host
28
+ end
29
+
30
+ def connected?
31
+ false
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,142 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright 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
+ # @private
22
+ class Metadata
23
+ include MonitorMixin
24
+
25
+ attr_reader :name
26
+
27
+ def initialize(cluster_registry,
28
+ cluster_schema,
29
+ schema_partitioners,
30
+ replication_strategies,
31
+ default_replication_strategy)
32
+ @registry = cluster_registry
33
+ @schema = cluster_schema
34
+ @partitioners = schema_partitioners
35
+ @strategies = replication_strategies
36
+ @default_strategy = default_replication_strategy
37
+ @token_replicas = ::Hash.new
38
+ @token_ring = ::Array.new
39
+ end
40
+
41
+ def find_replicas(keyspace, statement)
42
+ return EMPTY_LIST unless statement.respond_to?(:partition_key) && statement.respond_to?(:keyspace)
43
+
44
+ keyspace = String(statement.keyspace || keyspace)
45
+ partition_key = statement.partition_key
46
+ return EMPTY_LIST unless keyspace && partition_key
47
+
48
+ partitioner = @partitioner
49
+ return EMPTY_LIST unless partitioner
50
+
51
+ keyspace_hosts = @token_replicas[keyspace]
52
+ return EMPTY_LIST if keyspace_hosts.nil? || keyspace_hosts.empty?
53
+
54
+ token = partitioner.create_token(partition_key)
55
+ index = insertion_point(@token_ring, token)
56
+ index = 0 if index >= @token_ring.size
57
+ hosts = keyspace_hosts[@token_ring[index]]
58
+ return EMPTY_LIST unless hosts
59
+
60
+ hosts
61
+ end
62
+
63
+ def update(data)
64
+ @name = data['cluster_name']
65
+ @partitioner = @partitioners[data['partitioner']]
66
+
67
+ self
68
+ end
69
+
70
+ def rebuild_token_map
71
+ partitioner = @partitioner
72
+ return self unless partitioner
73
+
74
+ tokens = ::SortedSet.new
75
+ token_to_host = ::Hash.new
76
+
77
+ @registry.each_host do |host|
78
+ host.tokens.each do |token|
79
+ token = begin
80
+ partitioner.parse_token(token)
81
+ rescue
82
+ next
83
+ end
84
+ tokens.add(token)
85
+ token_to_host[token] = host
86
+ end
87
+ end
88
+
89
+ token_ring = tokens.to_a
90
+ token_replicas = ::Hash.new
91
+ token_maps = ::Hash.new
92
+
93
+ @schema.each_keyspace do |keyspace|
94
+ replication = keyspace.replication
95
+ key = replication_key(replication.klass, replication.options)
96
+
97
+ unless token_maps.include?(key)
98
+ strategy = @strategies[replication.klass] || @default_strategy
99
+ token_maps[key] = strategy.replication_map(
100
+ token_to_host,
101
+ token_ring,
102
+ replication.options
103
+ )
104
+ end
105
+
106
+ token_replicas[keyspace.name] = token_maps[key]
107
+ end
108
+
109
+ @token_replicas = token_replicas
110
+ @token_ring = token_ring
111
+
112
+ self
113
+ end
114
+
115
+ private
116
+
117
+ def replication_key(klass, options)
118
+ (klass + ':' + options.keys.sort.map {|k| "#{k}=#{options[k]}"}.join(',')).hash
119
+ end
120
+
121
+ def insertion_point(list, item)
122
+ min = 0
123
+ max = list.size - 1
124
+
125
+ while min <= max
126
+ idx = (min + max) / 2
127
+ val = list[idx]
128
+
129
+ if val < item
130
+ min = idx + 1
131
+ elsif val > item
132
+ max = idx - 1
133
+ else
134
+ return idx # item found
135
+ end
136
+ end
137
+
138
+ min # item not found.
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,145 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright 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
+ # @private
22
+ class Options
23
+ extend AttrBoolean
24
+
25
+ attr_reader :auth_provider, :compressor, :connect_timeout, :credentials,
26
+ :heartbeat_interval, :idle_timeout, :port, :schema_refresh_delay,
27
+ :schema_refresh_timeout, :ssl, :custom_type_handlers
28
+ attr_boolean :protocol_negotiable, :synchronize_schema, :nodelay, :allow_beta_protocol
29
+
30
+ attr_accessor :protocol_version
31
+
32
+ def initialize(logger,
33
+ protocol_version,
34
+ credentials,
35
+ auth_provider,
36
+ compressor,
37
+ port,
38
+ connect_timeout,
39
+ ssl,
40
+ connections_per_local_node,
41
+ connections_per_remote_node,
42
+ heartbeat_interval,
43
+ idle_timeout,
44
+ synchronize_schema,
45
+ schema_refresh_delay,
46
+ schema_refresh_timeout,
47
+ nodelay,
48
+ requests_per_connection,
49
+ custom_types,
50
+ allow_beta_protocol)
51
+ @logger = logger
52
+ @protocol_version = protocol_version
53
+ @credentials = credentials
54
+ @auth_provider = auth_provider
55
+ @compressor = compressor
56
+ @port = port
57
+ @connect_timeout = connect_timeout
58
+ @ssl = ssl
59
+ @heartbeat_interval = heartbeat_interval
60
+ @idle_timeout = idle_timeout
61
+ @synchronize_schema = synchronize_schema
62
+ @schema_refresh_delay = schema_refresh_delay
63
+ @schema_refresh_timeout = schema_refresh_timeout
64
+ @nodelay = nodelay
65
+ @allow_beta_protocol = allow_beta_protocol
66
+ @custom_type_handlers = {}
67
+ custom_types.each do |type_klass|
68
+ @custom_type_handlers[type_klass.type] = type_klass
69
+ end
70
+
71
+ @connections_per_local_node = connections_per_local_node
72
+ @connections_per_remote_node = connections_per_remote_node
73
+ @requests_per_connection = requests_per_connection
74
+
75
+ # If @protocol_version is nil, it means we want the driver to negotiate the
76
+ # protocol starting with our known max. If @protocol_version is not nil,
77
+ # it means the user wants us to use a particular version, so we should not
78
+ # support negotiation.
79
+
80
+ @protocol_negotiable = @protocol_version.nil?
81
+ @protocol_version ||= allow_beta_protocol ?
82
+ Cassandra::Protocol::Versions::BETA_VERSION :
83
+ Cassandra::Protocol::Versions::MAX_SUPPORTED_VERSION
84
+ end
85
+
86
+ def compression
87
+ @compressor && @compressor.algorithm
88
+ end
89
+
90
+ def create_authenticator(authentication_class, host)
91
+ if @auth_provider
92
+ # Auth providers should take an auth-class and host, but they used to not, so for backward compatibility
93
+ # we figure out if this provider does, and if so send both args, otherwise just send the auth-class.
94
+
95
+ if @auth_provider.method(:create_authenticator).arity == 1
96
+ @auth_provider.create_authenticator(authentication_class)
97
+ else
98
+ @auth_provider.create_authenticator(authentication_class, host)
99
+ end
100
+ end
101
+ end
102
+
103
+ def connections_per_local_node
104
+ # Return the option if set.
105
+ return @connections_per_local_node if @connections_per_local_node
106
+
107
+ # For v3 and later, default is 1 local connection.
108
+ # For v2 and earlier, default is 2 local connections.
109
+ # Return the default
110
+ (@protocol_version > 2) ? 1 : 2
111
+ end
112
+
113
+ def connections_per_remote_node
114
+ # Return the option if set; otherwise return the default (1).
115
+ @connections_per_remote_node || 1
116
+ end
117
+
118
+ def requests_per_connection
119
+ # There are a few possibilities here based on @requests_per_connection:
120
+ # nil: default to 1024 for protocol 3 and later, 128 for < 3.
121
+ # we're in v2 and value too high: return 128. We don't worry
122
+ # about this case for v3+ because option validation in
123
+ # Cassandra::cluster_async takes care of that.
124
+ # good value: return it.
125
+ #
126
+ # NOTE: We can't compute and cache the result because protocol_version
127
+ # can change over time in theory (if all nodes are upgraded to a new
128
+ # version of Cassandra)
129
+
130
+ # Return the default if option wasn't specified.
131
+ default_requests_per_connection = @protocol_version > 2 ? 1024 : 128
132
+ return default_requests_per_connection unless @requests_per_connection
133
+
134
+ if @requests_per_connection > 128 && @protocol_version < 3
135
+ @logger.warn(
136
+ ":requests_per_connection setting of #{@requests_per_connection} is more " \
137
+ 'than the max of 128 for protocol v2. Falling back to 128.'
138
+ )
139
+ return 128
140
+ end
141
+ @requests_per_connection
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,284 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright 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
+ # @private
22
+ class Registry
23
+ include MonitorMixin
24
+
25
+ def initialize(logger)
26
+ @logger = logger
27
+ @hosts = ::Hash.new
28
+ @listeners = ::Array.new
29
+
30
+ mon_initialize
31
+ end
32
+
33
+ def add_listener(listener)
34
+ synchronize do
35
+ listeners = @listeners.dup
36
+ listeners.push(listener)
37
+ @listeners = listeners
38
+ end
39
+
40
+ self
41
+ end
42
+
43
+ def remove_listener(listener)
44
+ synchronize do
45
+ listeners = @listeners.dup
46
+ listeners.delete(listener)
47
+ @listeners = listeners
48
+ end
49
+
50
+ self
51
+ end
52
+
53
+ def each_host(&block)
54
+ if block_given?
55
+ @hosts.each_value(&block)
56
+ self
57
+ else
58
+ @hosts.values
59
+ end
60
+ end
61
+ alias hosts each_host
62
+
63
+ # @param address [IPAddr] resolved address of the node
64
+ def host(address)
65
+ @hosts[address.to_s]
66
+ end
67
+
68
+ # @param address [IPAddr] resolved address of the node
69
+ def has_host?(address)
70
+ @hosts.key?(address.to_s)
71
+ end
72
+
73
+ # @param address [IPAddr] resolved address of the node
74
+ # @param data [Hash<String, String>] attributes of the host, typically a row from system.local or system.peers.
75
+ def host_found(address, data = {})
76
+ ip = address.to_s
77
+ host = @hosts[ip]
78
+
79
+ if host
80
+ if host.id == data['host_id'] &&
81
+ host.release_version == data['release_version'] &&
82
+ host.rack == data['rack'] &&
83
+ host.datacenter == data['data_center'] &&
84
+ host.broadcast_address == data['broadcast_address'] &&
85
+ host.listen_address == data['listen_address']
86
+
87
+ return self if host.up?
88
+
89
+ host = toggle_up(host)
90
+ else
91
+ @logger.debug("Host #{host.ip} metadata has been updated, it will be " \
92
+ 'considered lost and found')
93
+
94
+ notify_lost(host)
95
+
96
+ host = create_host(address, data)
97
+
98
+ notify_found(host)
99
+ end
100
+ else
101
+ host = create_host(address, data)
102
+
103
+ notify_found(host)
104
+ end
105
+
106
+ synchronize do
107
+ hosts = @hosts.dup
108
+ hosts[ip] = host
109
+ @hosts = hosts
110
+ end
111
+
112
+ self
113
+ end
114
+
115
+ # @param address [IPAddr] resolved address of the node
116
+ def host_down(address)
117
+ ip = address.to_s
118
+ host = @hosts[ip]
119
+
120
+ return self unless host && !host.down?
121
+
122
+ host = toggle_down(host)
123
+
124
+ synchronize do
125
+ hosts = @hosts.dup
126
+ hosts[ip] = host
127
+ @hosts = hosts
128
+ end
129
+
130
+ self
131
+ end
132
+
133
+ # @param address [IPAddr] resolved address of the node
134
+ def host_up(address)
135
+ ip = address.to_s
136
+ host = @hosts[ip]
137
+
138
+ return self unless host && !host.up?
139
+
140
+ host = toggle_up(host)
141
+
142
+ synchronize do
143
+ hosts = @hosts.dup
144
+ hosts[ip] = host
145
+ @hosts = hosts
146
+ end
147
+
148
+ self
149
+ end
150
+
151
+ # @param address [IPAddr] resolved address of the node
152
+ def host_lost(address)
153
+ ip = address.to_s
154
+ host = nil
155
+
156
+ return self unless @hosts.key?(ip)
157
+
158
+ synchronize do
159
+ hosts = @hosts.dup
160
+ host = hosts.delete(ip)
161
+ @hosts = hosts
162
+ end
163
+
164
+ notify_lost(host)
165
+
166
+ host
167
+ end
168
+
169
+ private
170
+
171
+ # @param ip [String] resolved address of the node
172
+ # @param data [Hash<String, String>] attributes of the host, typically a row from system.local or system.peers.
173
+ def create_host(ip, data)
174
+ Host.new(ip,
175
+ data['host_id'],
176
+ data['rack'],
177
+ data['data_center'],
178
+ data['release_version'],
179
+ Array(data['tokens']).freeze,
180
+ :up,
181
+ data['broadcast_address'],
182
+ data['listen_address'])
183
+ end
184
+
185
+ # @param host [Host] host that is found to be up.
186
+ def toggle_up(host)
187
+ host = Host.new(host.ip,
188
+ host.id,
189
+ host.rack,
190
+ host.datacenter,
191
+ host.release_version,
192
+ host.tokens,
193
+ :up,
194
+ host.broadcast_address,
195
+ host.listen_address)
196
+ @logger.debug("Host #{host.ip} is up")
197
+ @listeners.each do |listener|
198
+ begin
199
+ listener.host_up(host)
200
+ rescue
201
+ nil
202
+ end
203
+ end
204
+ host
205
+ end
206
+
207
+ # @param host [Host] host that is found to be down.
208
+ def toggle_down(host)
209
+ host = Host.new(host.ip,
210
+ host.id,
211
+ host.rack,
212
+ host.datacenter,
213
+ host.release_version,
214
+ host.tokens,
215
+ :down,
216
+ host.broadcast_address,
217
+ host.listen_address)
218
+ @logger.debug("Host #{host.ip} is down")
219
+ @listeners.reverse_each do |listener|
220
+ begin
221
+ listener.host_down(host)
222
+ rescue
223
+ nil
224
+ end
225
+ end
226
+ host
227
+ end
228
+
229
+ # @param host [Host] host that is lost.
230
+ def notify_lost(host)
231
+ if host.up?
232
+ @logger.debug("Host #{host.ip} is down and lost")
233
+ host = Host.new(host.ip,
234
+ host.id,
235
+ host.rack,
236
+ host.datacenter,
237
+ host.release_version,
238
+ host.tokens,
239
+ :down,
240
+ host.broadcast_address,
241
+ host.listen_address)
242
+ @listeners.reverse_each do |listener|
243
+ begin
244
+ listener.host_down(host)
245
+ rescue
246
+ nil
247
+ end
248
+ begin
249
+ listener.host_lost(host)
250
+ rescue
251
+ nil
252
+ end
253
+ end
254
+ else
255
+ @logger.debug("Host #{host.ip} is lost")
256
+ @listeners.reverse_each do |listener|
257
+ begin
258
+ listener.host_lost(host)
259
+ rescue
260
+ nil
261
+ end
262
+ end
263
+ end
264
+ end
265
+
266
+ # @param host [Host] host that is found.
267
+ def notify_found(host)
268
+ @logger.debug("Host #{host.ip} is found and up")
269
+ @listeners.each do |listener|
270
+ begin
271
+ listener.host_found(host)
272
+ rescue
273
+ nil
274
+ end
275
+ begin
276
+ listener.host_up(host)
277
+ rescue
278
+ nil
279
+ end
280
+ end
281
+ end
282
+ end
283
+ end
284
+ end