/*
* 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.networking.nio.iobalancer;
import com.hazelcast.config.Config;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.instance.HazelcastInstanceFactory;
import com.hazelcast.internal.ascii.HTTPCommunicator;
import com.hazelcast.internal.networking.nio.NioEventLoopGroup;
import com.hazelcast.nio.Address;
import com.hazelcast.nio.Protocols;
import com.hazelcast.nio.tcp.TcpIpConnectionManager;
import com.hazelcast.spi.properties.GroupProperty;
import com.hazelcast.test.AssertTask;
import com.hazelcast.test.HazelcastSerialClassRunner;
import com.hazelcast.test.HazelcastTestSupport;
import com.hazelcast.test.annotation.NightlyTest;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import java.io.IOException;
import java.net.Socket;
import static org.junit.Assert.assertEquals;
@RunWith(HazelcastSerialClassRunner.class)
@Category(NightlyTest.class)
public class IOBalancerMemoryLeakTest extends HazelcastTestSupport {
@Before
@After
public void killAllHazelcastInstances() throws IOException {
HazelcastInstanceFactory.terminateAll();
}
@Test
public void testMemoryLeak_with_RestConnections() throws IOException {
Config config = new Config();
config.getGroupConfig().setName(randomName());
config.setProperty(GroupProperty.REST_ENABLED.getName(), "true");
config.setProperty(GroupProperty.IO_BALANCER_INTERVAL_SECONDS.getName(), "1");
HazelcastInstance instance = Hazelcast.newHazelcastInstance(config);
HTTPCommunicator communicator = new HTTPCommunicator(instance);
TcpIpConnectionManager connectionManager = (TcpIpConnectionManager) getConnectionManager(instance);
for (int i = 0; i < 100; i++) {
communicator.getClusterInfo();
}
final IOBalancer ioBalancer = getIoBalancer(connectionManager);
assertTrueEventually(new AssertTask() {
@Override
public void run() throws Exception {
int inHandlerSize = ioBalancer.getInLoadTracker().getHandlers().size();
int outHandlerSize = ioBalancer.getOutLoadTracker().getHandlers().size();
assertEquals(0, inHandlerSize);
assertEquals(0, outHandlerSize);
}
});
}
@Test
public void testMemoryLeak_with_SocketConnections() throws IOException {
Config config = new Config();
config.getGroupConfig().setName(randomName());
config.setProperty(GroupProperty.IO_BALANCER_INTERVAL_SECONDS.getName(), "1");
HazelcastInstance instance = Hazelcast.newHazelcastInstance(config);
final Address address = instance.getCluster().getLocalMember().getAddress();
int threadCount = 10;
final int connectionCountPerThread = 100;
Runnable runnable = new Runnable() {
public void run() {
for (int i = 0; i < connectionCountPerThread; i++) {
Socket socket;
try {
socket = new Socket(address.getHost(), address.getPort());
socket.getOutputStream().write(Protocols.CLUSTER.getBytes());
sleepMillis(1000);
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
Thread[] threads = new Thread[threadCount];
for (int i = 0; i < threadCount; i++) {
threads[i] = new Thread(runnable);
threads[i].start();
}
assertJoinable(threads);
TcpIpConnectionManager connectionManager = (TcpIpConnectionManager) getConnectionManager(instance);
final IOBalancer ioBalancer = getIoBalancer(connectionManager);
assertTrueEventually(new AssertTask() {
@Override
public void run() throws Exception {
LoadTracker inLoadTracker = ioBalancer.getInLoadTracker();
LoadTracker outLoadTracker = ioBalancer.getOutLoadTracker();
int inHandlerSize = inLoadTracker.getHandlers().size();
int outHandlerSize = outLoadTracker.getHandlers().size();
int inHandlerEventsCount = inLoadTracker.getHandlerEventsCounter().keySet().size();
int outHandlerEventsCount = outLoadTracker.getHandlerEventsCounter().keySet().size();
int inLastEventsCount = inLoadTracker.getLastEventCounter().keySet().size();
int outLastEventsCount = outLoadTracker.getLastEventCounter().keySet().size();
assertEquals(0, inHandlerSize);
assertEquals(0, outHandlerSize);
assertEquals(0, inHandlerEventsCount);
assertEquals(0, outHandlerEventsCount);
assertEquals(0, inLastEventsCount);
assertEquals(0, outLastEventsCount);
}
});
}
private static IOBalancer getIoBalancer(TcpIpConnectionManager connectionManager) {
NioEventLoopGroup threadingModel = (NioEventLoopGroup)connectionManager.getEventLoopGroup();
return threadingModel.getIOBalancer();
}
}