blob: 29f664e257bcd9a9c209db1dadd72389719400b5 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.ignite.spi.discovery.tcp.internal;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.apache.ignite.cache.CacheMetrics;
import org.apache.ignite.cluster.ClusterMetrics;
import org.apache.ignite.cluster.ClusterNode;
import org.apache.ignite.internal.ClusterMetricsSnapshot;
import org.apache.ignite.internal.IgniteNodeAttributes;
import org.apache.ignite.internal.processors.cache.CacheMetricsSnapshot;
import org.apache.ignite.internal.util.lang.GridMetadataAwareAdapter;
import org.apache.ignite.internal.util.tostring.GridToStringExclude;
import org.apache.ignite.internal.util.tostring.GridToStringInclude;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.lang.IgnitePredicate;
import org.apache.ignite.lang.IgniteProductVersion;
import org.apache.ignite.spi.discovery.DiscoveryMetricsProvider;
import org.jetbrains.annotations.Nullable;
import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_DAEMON;
import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_NODE_CONSISTENT_ID;
/**
* Node for {@link org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi}.
* <p>
* <strong>This class is not intended for public use</strong> and has been made
* <tt>public</tt> due to certain limitations of Java technology.
*/
public class TcpDiscoveryNode extends GridMetadataAwareAdapter implements ClusterNode,
Comparable<TcpDiscoveryNode>, Externalizable {
/** */
private static final long serialVersionUID = 0L;
/** Node ID. */
private UUID id;
/** Consistent ID. */
private Object consistentId;
/** Node attributes. */
@GridToStringExclude
private Map<String, Object> attrs;
/** Internal discovery addresses as strings. */
@GridToStringInclude
private Collection<String> addrs;
/** Internal discovery host names as strings. */
private Collection<String> hostNames;
/** */
@GridToStringInclude
private Collection<InetSocketAddress> sockAddrs;
/** */
@GridToStringInclude
private int discPort;
/** Node metrics. */
@GridToStringExclude
private volatile ClusterMetrics metrics;
/** Node cache metrics. */
@GridToStringExclude
private volatile Map<Integer, CacheMetrics> cacheMetrics;
/** Node order in the topology. */
private volatile long order;
/** Node order in the topology (internal). */
private volatile long intOrder;
/** The most recent time when heartbeat message was received from the node. */
@GridToStringExclude
private volatile long lastUpdateTime = U.currentTimeMillis();
/** The most recent time when node exchanged a message with a remote node. */
private volatile long lastExchangeTime = U.currentTimeMillis();
/** Metrics provider (transient). */
@GridToStringExclude
private DiscoveryMetricsProvider metricsProvider;
/** Visible flag (transient). */
@GridToStringExclude
private boolean visible;
/** Grid local node flag (transient). */
private boolean loc;
/** Version. */
private IgniteProductVersion ver;
/** Alive check (used by clients). */
@GridToStringExclude
private transient int aliveCheck;
/** Client router node ID. */
@GridToStringExclude
private UUID clientRouterNodeId;
/** */
@GridToStringExclude
private volatile transient InetSocketAddress lastSuccessfulAddr;
/**
* Public default no-arg constructor for {@link Externalizable} interface.
*/
public TcpDiscoveryNode() {
// No-op.
}
/**
* Constructor.
*
* @param id Node Id.
* @param addrs Addresses.
* @param hostNames Host names.
* @param discPort Port.
* @param metricsProvider Metrics provider.
* @param ver Version.
* @param consistentId Node consistent ID.
*/
public TcpDiscoveryNode(UUID id,
Collection<String> addrs,
Collection<String> hostNames,
int discPort,
DiscoveryMetricsProvider metricsProvider,
IgniteProductVersion ver,
Serializable consistentId)
{
assert id != null;
assert !F.isEmpty(addrs);
assert metricsProvider != null;
assert ver != null;
this.id = id;
List<String> sortedAddrs = new ArrayList<>(addrs);
Collections.sort(sortedAddrs);
this.addrs = sortedAddrs;
this.hostNames = hostNames;
this.discPort = discPort;
this.metricsProvider = metricsProvider;
this.ver = ver;
this.consistentId = consistentId != null ? consistentId : U.consistentId(sortedAddrs, discPort);
metrics = metricsProvider.metrics();
cacheMetrics = metricsProvider.cacheMetrics();
sockAddrs = U.toSocketAddresses(this, discPort);
}
/**
* @return Last successfully connected address.
*/
@Nullable public InetSocketAddress lastSuccessfulAddress() {
return lastSuccessfulAddr;
}
/**
* @param lastSuccessfulAddr Last successfully connected address.
*/
public void lastSuccessfulAddress(InetSocketAddress lastSuccessfulAddr) {
this.lastSuccessfulAddr = lastSuccessfulAddr;
}
/** {@inheritDoc} */
@Override public UUID id() {
return id;
}
/** {@inheritDoc} */
@Override public Object consistentId() {
return consistentId;
}
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Override public <T> T attribute(String name) {
// Even though discovery SPI removes this attribute after authentication, keep this check for safety.
if (IgniteNodeAttributes.ATTR_SECURITY_CREDENTIALS.equals(name))
return null;
return (T)attrs.get(name);
}
/** {@inheritDoc} */
@Override public Map<String, Object> attributes() {
// Even though discovery SPI removes this attribute after authentication, keep this check for safety.
return F.view(attrs, new IgnitePredicate<String>() {
@Override public boolean apply(String s) {
return !IgniteNodeAttributes.ATTR_SECURITY_CREDENTIALS.equals(s);
}
});
}
/**
* Sets node attributes.
*
* @param attrs Node attributes.
*/
public void setAttributes(Map<String, Object> attrs) {
this.attrs = U.sealMap(attrs);
}
/**
* Gets node attributes without filtering.
*
* @return Node attributes without filtering.
*/
public Map<String, Object> getAttributes() {
return attrs;
}
/** {@inheritDoc} */
@Override public ClusterMetrics metrics() {
if (metricsProvider != null) {
ClusterMetrics metrics0 = metricsProvider.metrics();
metrics = metrics0;
return metrics0;
}
return metrics;
}
/**
* Sets node metrics.
*
* @param metrics Node metrics.
*/
public void setMetrics(ClusterMetrics metrics) {
assert metrics != null;
this.metrics = metrics;
}
/**
* Gets collections of cache metrics for this node. Note that node cache metrics are constantly updated
* and provide up to date information about caches.
* <p>
* Cache metrics are updated with some delay which is directly related to heartbeat
* frequency. For example, when used with default
* {@link org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi} the update will happen every {@code 2} seconds.
*
* @return Runtime metrics snapshots for this node.
*/
public Map<Integer, CacheMetrics> cacheMetrics() {
if (metricsProvider != null) {
Map<Integer, CacheMetrics> cacheMetrics0 = metricsProvider.cacheMetrics();
cacheMetrics = cacheMetrics0;
return cacheMetrics0;
}
return cacheMetrics;
}
/**
* Sets node cache metrics.
*
* @param cacheMetrics Cache metrics.
*/
public void setCacheMetrics(Map<Integer, CacheMetrics> cacheMetrics) {
this.cacheMetrics = cacheMetrics != null ? cacheMetrics : Collections.<Integer, CacheMetrics>emptyMap();
}
/**
* @return Internal order.
*/
public long internalOrder() {
return intOrder;
}
/**
* @param intOrder Internal order of the node.
*/
public void internalOrder(long intOrder) {
assert intOrder > 0;
this.intOrder = intOrder;
}
/**
* @return Order.
*/
@Override public long order() {
return order;
}
/**
* @param order Order of the node.
*/
public void order(long order) {
assert order > 0 : "Order is invalid: " + this;
this.order = order;
}
/** {@inheritDoc} */
@Override public IgniteProductVersion version() {
return ver;
}
/**
* @param ver Version.
*/
public void version(IgniteProductVersion ver) {
assert ver != null;
this.ver = ver;
}
/** {@inheritDoc} */
@Override public Collection<String> addresses() {
return addrs;
}
/** {@inheritDoc} */
@Override public boolean isLocal() {
return loc;
}
/**
* @param loc Grid local node flag.
*/
public void local(boolean loc) {
this.loc = loc;
}
/** {@inheritDoc} */
@Override public boolean isDaemon() {
return "true".equalsIgnoreCase((String)attribute(ATTR_DAEMON));
}
/** {@inheritDoc} */
@Override public Collection<String> hostNames() {
return hostNames;
}
/**
* @return Discovery port.
*/
public int discoveryPort() {
return discPort;
}
/**
* @return Addresses that could be used by discovery.
*/
public Collection<InetSocketAddress> socketAddresses() {
return sockAddrs;
}
/**
* Gets node last update time.
*
* @return Time of the last heartbeat.
*/
public long lastUpdateTime() {
return lastUpdateTime;
}
/**
* Sets node last update.
*
* @param lastUpdateTime Time of last metrics update.
*/
public void lastUpdateTime(long lastUpdateTime) {
assert lastUpdateTime > 0;
this.lastUpdateTime = lastUpdateTime;
}
/**
* Gets the last time a node exchanged a message with a remote node.
*
* @return Time in milliseconds.
*/
public long lastExchangeTime() {
return lastExchangeTime;
}
/**
* Sets the last time a node exchanged a message with a remote node.
*
* @param lastExchangeTime Time in milliseconds.
*/
public void lastExchangeTime(long lastExchangeTime) {
this.lastExchangeTime = lastExchangeTime;
}
/**
* Gets visible flag.
*
* @return {@code true} if node is in visible state.
*/
public boolean visible() {
return visible;
}
/**
* Sets visible flag.
*
* @param visible {@code true} if node is in visible state.
*/
public void visible(boolean visible) {
this.visible = visible;
}
/** {@inheritDoc} */
@Override public boolean isClient() {
return clientRouterNodeId != null;
}
/**
* Decrements alive check value and returns new one.
*
* @return Alive check value.
*/
public int decrementAliveCheck() {
assert isClient();
return --aliveCheck;
}
/**
* @param aliveCheck Alive check value.
*/
public void aliveCheck(int aliveCheck) {
assert isClient();
this.aliveCheck = aliveCheck;
}
/**
* @return Client router node ID.
*/
public UUID clientRouterNodeId() {
return clientRouterNodeId;
}
/**
* @param clientRouterNodeId Client router node ID.
*/
public void clientRouterNodeId(UUID clientRouterNodeId) {
this.clientRouterNodeId = clientRouterNodeId;
}
/**
* @param newId New node ID.
*/
public void onClientDisconnected(UUID newId) {
id = newId;
}
/**
* @return Copy of local node for client reconnect request.
*/
public TcpDiscoveryNode clientReconnectNode() {
TcpDiscoveryNode node = new TcpDiscoveryNode(id, addrs, hostNames, discPort, metricsProvider, ver,
null);
node.attrs = attrs;
node.clientRouterNodeId = clientRouterNodeId;
return node;
}
/** {@inheritDoc} */
@Override public int compareTo(@Nullable TcpDiscoveryNode node) {
if (node == null)
return 1;
int res = Long.compare(internalOrder(), node.internalOrder());
if (res == 0) {
assert id().equals(node.id()) : "Duplicate order [this=" + this + ", other=" + node + ']';
res = id().compareTo(node.id());
}
return res;
}
/** {@inheritDoc} */
@Override public void writeExternal(ObjectOutput out) throws IOException {
U.writeUuid(out, id);
U.writeMap(out, attrs);
U.writeCollection(out, addrs);
U.writeCollection(out, hostNames);
out.writeInt(discPort);
// Cluster metrics
byte[] mtr = null;
ClusterMetrics metrics = this.metrics;
if (metrics != null)
mtr = ClusterMetricsSnapshot.serialize(metrics);
U.writeByteArray(out, mtr);
// Cache metrics
Map<Integer, CacheMetrics> cacheMetrics = this.cacheMetrics;
out.writeInt(cacheMetrics == null ? 0 : cacheMetrics.size());
if (!F.isEmpty(cacheMetrics))
for (Map.Entry<Integer, CacheMetrics> m : cacheMetrics.entrySet()) {
out.writeInt(m.getKey());
out.writeObject(m.getValue());
}
out.writeLong(order);
out.writeLong(intOrder);
out.writeObject(ver);
U.writeUuid(out, clientRouterNodeId);
}
/** {@inheritDoc} */
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
id = U.readUuid(in);
attrs = U.sealMap(U.<String, Object>readMap(in));
addrs = U.readCollection(in);
hostNames = U.readCollection(in);
discPort = in.readInt();
sockAddrs = U.toSocketAddresses(this, discPort);
Object consistentIdAttr = attrs.get(ATTR_NODE_CONSISTENT_ID);
consistentId = consistentIdAttr != null ? consistentIdAttr : U.consistentId(addrs, discPort);
// Cluster metrics
byte[] mtr = U.readByteArray(in);
if (mtr != null)
metrics = ClusterMetricsSnapshot.deserialize(mtr, 0);
// Cache metrics
int size = in.readInt();
Map<Integer, CacheMetrics> cacheMetrics =
size > 0 ? U.<Integer, CacheMetrics>newHashMap(size) : Collections.<Integer, CacheMetrics>emptyMap();
for (int i = 0; i < size; i++) {
int id = in.readInt();
CacheMetricsSnapshot m = (CacheMetricsSnapshot) in.readObject();
cacheMetrics.put(id, m);
}
order = in.readLong();
intOrder = in.readLong();
ver = (IgniteProductVersion)in.readObject();
clientRouterNodeId = U.readUuid(in);
}
/** {@inheritDoc} */
@Override public int hashCode() {
return id.hashCode();
}
/** {@inheritDoc} */
@Override public boolean equals(Object o) {
return F.eqNodes(this, o);
}
/** {@inheritDoc} */
@Override public String toString() {
return S.toString(TcpDiscoveryNode.class, this, "isClient", isClient());
}
}