/*
* 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.internal.processors.platform.cluster;
import java.util.ArrayList;
import java.util.Collection;
import java.util.UUID;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteCluster;
import org.apache.ignite.cluster.ClusterMetrics;
import org.apache.ignite.cluster.ClusterNode;
import org.apache.ignite.internal.cluster.ClusterGroupEx;
import org.apache.ignite.internal.binary.BinaryRawReaderEx;
import org.apache.ignite.internal.binary.BinaryRawWriterEx;
import org.apache.ignite.internal.processors.platform.PlatformAbstractTarget;
import org.apache.ignite.internal.processors.platform.PlatformContext;
import org.apache.ignite.internal.processors.platform.PlatformTarget;
import org.apache.ignite.internal.processors.platform.cache.PlatformCache;
import org.apache.ignite.internal.processors.platform.utils.PlatformUtils;
import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
import org.jetbrains.annotations.Nullable;
/**
* Interop projection.
*/
@SuppressWarnings({"UnusedDeclaration"})
public class PlatformClusterGroup extends PlatformAbstractTarget {
/** */
private static final int OP_FOR_ATTRIBUTE = 2;
/** */
private static final int OP_FOR_CACHE = 3;
/** */
private static final int OP_FOR_CLIENT = 4;
/** */
private static final int OP_FOR_DATA = 5;
/** */
private static final int OP_FOR_HOST = 6;
/** */
private static final int OP_FOR_NODE_IDS = 7;
/** */
private static final int OP_METRICS = 9;
/** */
private static final int OP_METRICS_FILTERED = 10;
/** */
private static final int OP_NODE_METRICS = 11;
/** */
private static final int OP_NODES = 12;
/** */
private static final int OP_PING_NODE = 13;
/** */
private static final int OP_TOPOLOGY = 14;
/** */
private static final int OP_FOR_OTHERS = 16;
/** */
private static final int OP_FOR_REMOTES = 17;
/** */
private static final int OP_FOR_DAEMONS = 18;
/** */
private static final int OP_FOR_RANDOM = 19;
/** */
private static final int OP_FOR_OLDEST = 20;
/** */
private static final int OP_FOR_YOUNGEST = 21;
/** */
private static final int OP_RESET_METRICS = 22;
/** */
private static final int OP_FOR_SERVERS = 23;
/** */
private static final int OP_CACHE_METRICS = 24;
/** */
private static final int OP_RESET_LOST_PARTITIONS = 25;
/** Projection. */
private final ClusterGroupEx prj;
/**
* Constructor.
*
* @param platformCtx Context.
* @param prj Projection.
*/
public PlatformClusterGroup(PlatformContext platformCtx, ClusterGroupEx prj) {
super(platformCtx);
this.prj = prj;
}
/** {@inheritDoc} */
@SuppressWarnings("deprecation")
@Override public void processOutStream(int type, BinaryRawWriterEx writer) throws IgniteCheckedException {
switch (type) {
case OP_METRICS:
platformCtx.writeClusterMetrics(writer, prj.metrics());
break;
default:
super.processOutStream(type, writer);
}
}
/** {@inheritDoc} */
@SuppressWarnings({"ConstantConditions", "deprecation"})
@Override public void processInStreamOutStream(int type, BinaryRawReaderEx reader, BinaryRawWriterEx writer)
throws IgniteCheckedException {
switch (type) {
case OP_METRICS_FILTERED: {
Collection<UUID> ids = PlatformUtils.readCollection(reader);
platformCtx.writeClusterMetrics(writer, prj.forNodeIds(ids).metrics());
break;
}
case OP_NODES: {
long oldTopVer = reader.readLong();
long curTopVer = platformCtx.kernalContext().discovery().topologyVersion();
if (curTopVer > oldTopVer) {
writer.writeBoolean(true);
writer.writeLong(curTopVer);
// At this moment topology version might have advanced, and due to this race
// we return outdated top ver to the callee. But this race is benign, the only
// possible side effect is that the user will re-request nodes and we will return
// the same set of nodes but with more recent topology version.
Collection<ClusterNode> nodes = prj.nodes();
platformCtx.writeNodes(writer, nodes);
}
else
// No discovery events since last invocation.
writer.writeBoolean(false);
break;
}
case OP_NODE_METRICS: {
UUID nodeId = reader.readUuid();
long lastUpdateTime = reader.readLong();
// Ask discovery because node might have been filtered out of current projection.
ClusterNode node = platformCtx.kernalContext().discovery().node(nodeId);
ClusterMetrics metrics = null;
if (node != null) {
ClusterMetrics metrics0 = node.metrics();
long triggerTime = lastUpdateTime + platformCtx.kernalContext().config().getMetricsUpdateFrequency();
metrics = metrics0.getLastUpdateTime() > triggerTime ? metrics0 : null;
}
platformCtx.writeClusterMetrics(writer, metrics);
break;
}
case OP_TOPOLOGY: {
long topVer = reader.readLong();
platformCtx.writeNodes(writer, topology(topVer));
break;
}
case OP_CACHE_METRICS: {
String cacheName = reader.readString();
IgniteCache cache = platformCtx.kernalContext().grid().cache(cacheName);
PlatformCache.writeCacheMetrics(writer, cache.metrics(prj));
break;
}
default:
super.processInStreamOutStream(type, reader, writer);
}
}
/** {@inheritDoc} */
@Override public long processInStreamOutLong(int type, BinaryRawReaderEx reader) throws IgniteCheckedException {
switch (type) {
case OP_PING_NODE:
return pingNode(reader.readUuid()) ? TRUE : FALSE;
case OP_RESET_LOST_PARTITIONS:
int cnt = reader.readInt();
Collection<String> cacheNames = new ArrayList<>(cnt);
for (int i = 0; i < cnt; i++) {
cacheNames.add(reader.readString());
}
platformCtx.kernalContext().grid().resetLostPartitions(cacheNames);
return TRUE;
default:
return super.processInStreamOutLong(type, reader);
}
}
/** {@inheritDoc} */
@Override public PlatformTarget processInStreamOutObject(int type, BinaryRawReaderEx reader)
throws IgniteCheckedException {
switch (type) {
case OP_FOR_NODE_IDS: {
Collection<UUID> ids = PlatformUtils.readCollection(reader);
return new PlatformClusterGroup(platformCtx, (ClusterGroupEx)prj.forNodeIds(ids));
}
case OP_FOR_ATTRIBUTE:
return new PlatformClusterGroup(platformCtx,
(ClusterGroupEx)prj.forAttribute(reader.readString(), reader.readString()));
case OP_FOR_CACHE: {
String cacheName = reader.readString();
return new PlatformClusterGroup(platformCtx, (ClusterGroupEx)prj.forCacheNodes(cacheName));
}
case OP_FOR_CLIENT: {
String cacheName = reader.readString();
return new PlatformClusterGroup(platformCtx, (ClusterGroupEx)prj.forClientNodes(cacheName));
}
case OP_FOR_DATA: {
String cacheName = reader.readString();
return new PlatformClusterGroup(platformCtx, (ClusterGroupEx)prj.forDataNodes(cacheName));
}
case OP_FOR_HOST: {
UUID nodeId = reader.readUuid();
ClusterNode node = prj.node(nodeId);
return new PlatformClusterGroup(platformCtx, (ClusterGroupEx) prj.forHost(node));
}
default:
return super.processInStreamOutObject(type, reader);
}
}
/** {@inheritDoc} */
@Override public PlatformTarget processInObjectStreamOutObjectStream(
int type, @Nullable PlatformTarget arg, BinaryRawReaderEx reader, BinaryRawWriterEx writer)
throws IgniteCheckedException {
switch (type) {
case OP_FOR_OTHERS: {
PlatformClusterGroup exclude = (PlatformClusterGroup) arg;
assert exclude != null;
return new PlatformClusterGroup(platformCtx, (ClusterGroupEx)prj.forOthers(exclude.prj));
}
}
return super.processInObjectStreamOutObjectStream(type, arg, reader, writer);
}
/** {@inheritDoc} */
@Override public PlatformTarget processOutObject(int type) throws IgniteCheckedException {
switch (type) {
case OP_FOR_REMOTES:
return new PlatformClusterGroup(platformCtx, (ClusterGroupEx)prj.forRemotes());
case OP_FOR_DAEMONS:
return new PlatformClusterGroup(platformCtx, (ClusterGroupEx)prj.forDaemons());
case OP_FOR_RANDOM:
return new PlatformClusterGroup(platformCtx, (ClusterGroupEx)prj.forRandom());
case OP_FOR_OLDEST:
return new PlatformClusterGroup(platformCtx, (ClusterGroupEx)prj.forOldest());
case OP_FOR_YOUNGEST:
return new PlatformClusterGroup(platformCtx, (ClusterGroupEx)prj.forYoungest());
case OP_FOR_SERVERS:
return new PlatformClusterGroup(platformCtx, (ClusterGroupEx)prj.forServers());
}
return super.processOutObject(type);
}
/** {@inheritDoc} */
@Override public long processInLongOutLong(int type, long val) throws IgniteCheckedException {
switch (type) {
case OP_RESET_METRICS: {
assert prj instanceof IgniteCluster; // Can only be invoked on top-level cluster group.
((IgniteCluster)prj).resetMetrics();
return TRUE;
}
}
return super.processInLongOutLong(type, val);
}
/**
* @return Projection.
*/
public ClusterGroupEx projection() {
return prj;
}
/**
* Pings a remote node.
*/
private boolean pingNode(UUID nodeId) {
assert prj instanceof IgniteCluster; // Can only be invoked on top-level cluster group.
return ((IgniteCluster)prj).pingNode(nodeId);
}
/**
* Gets a topology by version. Returns {@code null} if topology history storage doesn't contain
* specified topology version (history currently keeps last {@code 1000} snapshots).
*
* @param topVer Topology version.
* @return Collection of grid nodes which represented by specified topology version,
* if it is present in history storage, {@code null} otherwise.
* @throws UnsupportedOperationException If underlying SPI implementation does not support
* topology history. Currently only {@link TcpDiscoverySpi}
* supports topology history.
*/
private Collection<ClusterNode> topology(long topVer) {
assert prj instanceof IgniteCluster; // Can only be invoked on top-level cluster group.
return ((IgniteCluster)prj).topology(topVer);
}
}