/*
 * Copyright DataStax, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.datastax.oss.driver.api.core.metadata;

import com.datastax.oss.driver.api.core.Version;
import com.datastax.oss.driver.api.core.loadbalancing.LoadBalancingPolicy;
import com.datastax.oss.driver.api.core.loadbalancing.NodeDistance;
import com.datastax.oss.driver.api.core.session.Session;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.net.InetSocketAddress;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;

Metadata about a Cassandra node in the cluster.

This object is mutable, all of its properties may be updated at runtime to reflect the latest state of the node.

Note that the default implementation returned by the driver uses reference equality. A Session will always return the same instance for a given host id. However, instances coming from different sessions will not be equal, even if they refer to the same host id.

/** * Metadata about a Cassandra node in the cluster. * * <p>This object is mutable, all of its properties may be updated at runtime to reflect the latest * state of the node. * * <p>Note that the default implementation returned by the driver uses <b>reference equality</b>. A * {@link Session} will always return the same instance for a given {@link #getHostId() host id}. * However, instances coming from different sessions will not be equal, even if they refer to the * same host id. */
public interface Node {
The information that the driver uses to connect to the node.

In default deployments, the endpoint address is usually derived from the node's broadcast RPC address for peers hosts. For the control host however, the driver doesn't rely on that value because it may be wrong (see CASSANDRA-11181); instead, it simply uses the control connection's own endpoint.

When behind a proxy, the endpoint reported here usually refers to the proxy itself, and is unrelated to the node's broadcast RPC address.

/** * The information that the driver uses to connect to the node. * * <p>In default deployments, the endpoint address is usually derived from the node's {@linkplain * #getBroadcastAddress() broadcast RPC address} for peers hosts. For the control host however, * the driver doesn't rely on that value because it may be wrong (see CASSANDRA-11181); instead, * it simply uses the control connection's own endpoint. * * <p>When behind a proxy, the endpoint reported here usually refers to the proxy itself, and is * unrelated to the node's broadcast RPC address. */
@NonNull EndPoint getEndPoint();
The node's broadcast RPC address. That is, the address that the node expects clients to connect to.

This is computed from values reported in system.local.rpc_address and system.peers.rpc_address (Cassandra 3), or system.local.rpc_address, system.local.rpc_port, system.peers_v2.native_address and system.peers_v2.native_port (Cassandra 4+).

However, the address reported here might not be what the driver uses directly; to know which address the driver is really using to connect to this node, check getEndPoint().

This may not be known at all times. In particular, some Cassandra versions (less than 2.0.16, 2.1.6 or 2.2.0-rc1) don't store it in the system.local table, so this will be unknown for the control node, until the control connection reconnects to another node.

See Also:
/** * The node's broadcast RPC address. That is, the address that the node expects clients to connect * to. * * <p>This is computed from values reported in {@code system.local.rpc_address} and {@code * system.peers.rpc_address} (Cassandra 3), or {@code system.local.rpc_address}, {@code * system.local.rpc_port}, {@code system.peers_v2.native_address} and {@code * system.peers_v2.native_port} (Cassandra 4+). * * <p>However, the address reported here might not be what the driver uses directly; to know which * address the driver is really using to connect to this node, check {@link #getEndPoint()}. * * <p>This may not be known at all times. In particular, some Cassandra versions (less than * 2.0.16, 2.1.6 or 2.2.0-rc1) don't store it in the {@code system.local} table, so this will be * unknown for the control node, until the control connection reconnects to another node. * * @see <a href="https://issues.apache.org/jira/browse/CASSANDRA-9436">CASSANDRA-9436 (where the * information was added to system.local)</a> */
@NonNull Optional<InetSocketAddress> getBroadcastRpcAddress();
The node's broadcast address. That is, the address that other nodes use to communicate with that node.

This is computed from values reported in system.local.broadcast_address and system.peers.peer (Cassandra 3), or system.local.broadcast_address, system.local.broadcast_port, system.peers_v2.peer and system.peers_v2.peer_port (Cassandra 4+). If the port is set to 0 it is unknown.

This may not be known at all times. In particular, some Cassandra versions (less than 2.0.16, 2.1.6 or 2.2.0-rc1) don't store it in the system.local table, so this will be unknown for the control node, until the control connection reconnects to another node.

See Also:
/** * The node's broadcast address. That is, the address that other nodes use to communicate with * that node. * * <p>This is computed from values reported in {@code system.local.broadcast_address} and {@code * system.peers.peer} (Cassandra 3), or {@code system.local.broadcast_address}, {@code * system.local.broadcast_port}, {@code system.peers_v2.peer} and {@code * system.peers_v2.peer_port} (Cassandra 4+). If the port is set to 0 it is unknown. * * <p>This may not be known at all times. In particular, some Cassandra versions (less than * 2.0.16, 2.1.6 or 2.2.0-rc1) don't store it in the {@code system.local} table, so this will be * unknown for the control node, until the control connection reconnects to another node. * * @see <a href="https://issues.apache.org/jira/browse/CASSANDRA-9436">CASSANDRA-9436 (where the * information was added to system.local)</a> */
@NonNull Optional<InetSocketAddress> getBroadcastAddress();
The node's listen address. That is, the address that the Cassandra process binds to.

This is computed from values reported in system.local.listen_address (Cassandra 3), or system.local.listen_address and system.local.listen_port (Cassandra 4+). If the port is set to 0 it is unknown.

This may not be known at all times. In particular, current Cassandra versions (up to 3.11) only store it in system.local, so this will be known only for the control node.

/** * The node's listen address. That is, the address that the Cassandra process binds to. * * <p>This is computed from values reported in {@code system.local.listen_address} (Cassandra 3), * or {@code system.local.listen_address} and {@code system.local.listen_port} (Cassandra 4+). If * the port is set to 0 it is unknown. * * <p>This may not be known at all times. In particular, current Cassandra versions (up to 3.11) * only store it in {@code system.local}, so this will be known only for the control node. */
@NonNull Optional<InetSocketAddress> getListenAddress();
The datacenter that this node belongs to (according to the server-side snitch).

This should be non-null in a healthy deployment, but the driver will still function, and report null here, if the server metadata was corrupted.

/** * The datacenter that this node belongs to (according to the server-side snitch). * * <p>This should be non-null in a healthy deployment, but the driver will still function, and * report {@code null} here, if the server metadata was corrupted. */
@Nullable String getDatacenter();
The rack that this node belongs to (according to the server-side snitch).

This should be non-null in a healthy deployment, but the driver will still function, and report null here, if the server metadata was corrupted.

/** * The rack that this node belongs to (according to the server-side snitch). * * <p>This should be non-null in a healthy deployment, but the driver will still function, and * report {@code null} here, if the server metadata was corrupted. */
@Nullable String getRack();
The Cassandra version of the server.

This should be non-null in a healthy deployment, but the driver will still function, and report null here, if the server metadata was corrupted or the reported version could not be parsed.

/** * The Cassandra version of the server. * * <p>This should be non-null in a healthy deployment, but the driver will still function, and * report {@code null} here, if the server metadata was corrupted or the reported version could * not be parsed. */
@Nullable Version getCassandraVersion();
An additional map of free-form properties.

This is intended for future evolution or custom driver extensions. The contents of this map are unspecified and may change at any point in time, always check for the existence of a key before using it.

Note that the returned map is immutable: if the properties change, this is reflected by publishing a new map instance, therefore you must call this method again to see the changes.

/** * An additional map of free-form properties. * * <p>This is intended for future evolution or custom driver extensions. The contents of this map * are unspecified and may change at any point in time, always check for the existence of a key * before using it. * * <p>Note that the returned map is immutable: if the properties change, this is reflected by * publishing a new map instance, therefore you must call this method again to see the changes. */
@NonNull Map<String, Object> getExtras(); @NonNull NodeState getState();
The last time that this node transitioned to the UP state, in milliseconds since the epoch, or -1 if it's not up at the moment.
/** * The last time that this node transitioned to the UP state, in milliseconds since the epoch, or * -1 if it's not up at the moment. */
long getUpSinceMillis();
The total number of active connections currently open by this driver instance to the node. This can be either pooled connections, or the control connection.
/** * The total number of active connections currently open by this driver instance to the node. This * can be either pooled connections, or the control connection. */
int getOpenConnections();
Whether the driver is currently trying to reconnect to this node. That is, whether the active connection count is below the value mandated by the configuration. This does not mean that the node is down, there could be some active connections but not enough.
/** * Whether the driver is currently trying to reconnect to this node. That is, whether the active * connection count is below the value mandated by the configuration. This does not mean that the * node is down, there could be some active connections but not enough. */
boolean isReconnecting();
The distance assigned to this node by the LoadBalancingPolicy, that controls certain aspects of connection management.

This is exposed here for information only. Distance events are handled internally by the driver.

/** * The distance assigned to this node by the {@link LoadBalancingPolicy}, that controls certain * aspects of connection management. * * <p>This is exposed here for information only. Distance events are handled internally by the * driver. */
@NonNull NodeDistance getDistance();
The host ID that is assigned to this node by Cassandra. This value can be used to uniquely identify a node even when the underling IP address changes.

This information is always present once the session has initialized. However, there is a narrow corner case where a driver client can observe a null value: if a NodeStateListener is registered, the very first onUp call will reference a node that has a null id (that node is the initial contact point, and the driver hasn't read host ids from system.local and system.peers yet). Beyond that point — including any other onUp call — the host id will always be present.

CqlSession session = CqlSession.builder()
    .withNodeStateListener(
        new NodeStateListenerBase() {
          @Override
          public void onUp(@NonNull Node node) {
            // node.getHostId() == null for the first invocation only
          }
        })
    .build();
/** * The host ID that is assigned to this node by Cassandra. This value can be used to uniquely * identify a node even when the underling IP address changes. * * <p>This information is always present once the session has initialized. However, there is a * narrow corner case where a driver client can observe a null value: if a {@link * NodeStateListener} is registered, the <b>very first</b> {@code onUp} call will reference a node * that has a null id (that node is the initial contact point, and the driver hasn't read host ids * from {@code system.local} and {@code system.peers} yet). Beyond that point &mdash; including * any other {@code onUp} call &mdash; the host id will always be present. * * <pre> * CqlSession session = CqlSession.builder() * .withNodeStateListener( * new NodeStateListenerBase() { * &#64;Override * public void onUp(@NonNull Node node) { * // node.getHostId() == null for the first invocation only * } * }) * .build(); * </pre> */
@Nullable UUID getHostId();
The current version that is associated with the node's schema.

This should be non-null in a healthy deployment, but the driver will still function, and report null here, if the server metadata was corrupted.

/** * The current version that is associated with the node's schema. * * <p>This should be non-null in a healthy deployment, but the driver will still function, and * report {@code null} here, if the server metadata was corrupted. */
@Nullable UUID getSchemaVersion(); }