yugabyte-ycql-driver 3.2.3.1

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 (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