/*
* Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved.
*
* 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.hazelcast.internal.diagnostics;
import com.hazelcast.internal.networking.EventLoopGroup;
import com.hazelcast.internal.networking.nio.NioEventLoopGroup;
import com.hazelcast.internal.networking.nio.NioThread;
import com.hazelcast.logging.ILogger;
import com.hazelcast.nio.ConnectionManager;
import com.hazelcast.nio.tcp.TcpIpConnectionManager;
import com.hazelcast.spi.impl.NodeEngineImpl;
import com.hazelcast.spi.properties.HazelcastProperties;
import com.hazelcast.spi.properties.HazelcastProperty;
import static com.hazelcast.internal.diagnostics.Diagnostics.PREFIX;
import static java.util.concurrent.TimeUnit.SECONDS;
/**
* The {@link NetworkingPlugin} is an experimental plugin meant for detecting imbalance in the io system. This plugin will
* probably mostly be used for internal purposes to get a better understanding of imbalances. Normally imbalances are taken
* care of by the IOBalancer; but we need to make sure it makes the right choice.
*
* This plugin can be used on server and client side.
*/
public class NetworkingPlugin extends DiagnosticsPlugin {
/**
* The period in seconds this plugin runs.
*
* If set to 0, the plugin is disabled.
*/
public static final HazelcastProperty PERIOD_SECONDS = new HazelcastProperty(PREFIX + ".networking.seconds", 0, SECONDS);
private static final double HUNDRED = 100d;
private final NioEventLoopGroup eventLoopGroup;
private final long periodMillis;
public NetworkingPlugin(NodeEngineImpl nodeEngine) {
this(nodeEngine.getProperties(), getThreadingModel(nodeEngine), nodeEngine.getLogger(NetworkingPlugin.class));
}
public NetworkingPlugin(HazelcastProperties properties, EventLoopGroup eventLoopGroup, ILogger logger) {
super(logger);
if (eventLoopGroup instanceof NioEventLoopGroup) {
this.eventLoopGroup = (NioEventLoopGroup) eventLoopGroup;
} else {
this.eventLoopGroup = null;
}
this.periodMillis = this.eventLoopGroup == null ? 0 : properties.getMillis(PERIOD_SECONDS);
}
private static EventLoopGroup getThreadingModel(NodeEngineImpl nodeEngine) {
ConnectionManager connectionManager = nodeEngine.getNode().getConnectionManager();
if (!(connectionManager instanceof TcpIpConnectionManager)) {
return null;
}
return ((TcpIpConnectionManager) connectionManager).getEventLoopGroup();
}
@Override
public long getPeriodMillis() {
return periodMillis;
}
@Override
public void onStart() {
logger.info("Plugin:active: period-millis:" + periodMillis);
}
@Override
public void run(DiagnosticsLogWriter writer) {
writer.startSection("Networking");
writer.startSection("InputThreads");
render(writer, eventLoopGroup.getInputThreads());
writer.endSection();
writer.startSection("OutputThreads");
render(writer, eventLoopGroup.getOutputThreads());
writer.endSection();
writer.endSection();
}
private void render(DiagnosticsLogWriter writer, NioThread[] threads) {
if (threads == null) {
// this can become null due to stopping of the system.
return;
}
long totalPriorityFramesReceived = 0;
long totalFramesReceived = 0;
long totalBytesReceived = 0;
long totalEvents = 0;
long totalTaskCount = 0;
long totalHandleCount = 0;
for (NioThread thread : threads) {
totalBytesReceived += thread.bytesTransceived();
totalFramesReceived += thread.framesTransceived();
totalPriorityFramesReceived += thread.priorityFramesTransceived();
totalEvents += thread.eventCount();
totalTaskCount += thread.completedTaskCount();
totalHandleCount += thread.handleCount();
}
for (NioThread thread : threads) {
writer.startSection(thread.getName());
writer.writeKeyValueEntry("frames", toPercentage(thread.framesTransceived(), totalFramesReceived));
writer.writeKeyValueEntry("priority-frames",
toPercentage(thread.priorityFramesTransceived(), totalPriorityFramesReceived));
writer.writeKeyValueEntry("bytes", toPercentage(thread.bytesTransceived(), totalBytesReceived));
writer.writeKeyValueEntry("events", toPercentage(thread.eventCount(), totalEvents));
writer.writeKeyValueEntry("handle-count", toPercentage(thread.handleCount(), totalHandleCount));
writer.writeKeyValueEntry("tasks", toPercentage(thread.completedTaskCount(), totalTaskCount));
writer.endSection();
}
}
private String toPercentage(long amount, long total) {
double percentage = (HUNDRED * amount) / total;
return String.format("%1$,.2f", percentage) + " %";
}
}