/*
* 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.management;
import com.hazelcast.cache.CacheStatistics;
import com.hazelcast.cache.impl.CacheService;
import com.hazelcast.cache.impl.ICacheService;
import com.hazelcast.collection.impl.queue.QueueService;
import com.hazelcast.config.CacheConfig;
import com.hazelcast.config.Config;
import com.hazelcast.config.GroupConfig;
import com.hazelcast.config.SSLConfig;
import com.hazelcast.core.Client;
import com.hazelcast.core.Member;
import com.hazelcast.executor.impl.DistributedExecutorService;
import com.hazelcast.hotrestart.HotRestartService;
import com.hazelcast.instance.HazelcastInstanceImpl;
import com.hazelcast.instance.MemberImpl;
import com.hazelcast.instance.Node;
import com.hazelcast.internal.cluster.ClusterService;
import com.hazelcast.internal.management.dto.ClientEndPointDTO;
import com.hazelcast.internal.management.dto.ClusterHotRestartStatusDTO;
import com.hazelcast.internal.partition.InternalPartitionService;
import com.hazelcast.map.impl.MapService;
import com.hazelcast.monitor.LocalExecutorStats;
import com.hazelcast.monitor.LocalMapStats;
import com.hazelcast.monitor.LocalMemoryStats;
import com.hazelcast.monitor.LocalMultiMapStats;
import com.hazelcast.monitor.LocalOperationStats;
import com.hazelcast.monitor.LocalQueueStats;
import com.hazelcast.monitor.LocalReplicatedMapStats;
import com.hazelcast.monitor.LocalTopicStats;
import com.hazelcast.monitor.LocalWanStats;
import com.hazelcast.monitor.TimedMemberState;
import com.hazelcast.monitor.WanSyncState;
import com.hazelcast.monitor.impl.HotRestartStateImpl;
import com.hazelcast.monitor.impl.LocalCacheStatsImpl;
import com.hazelcast.monitor.impl.LocalMemoryStatsImpl;
import com.hazelcast.monitor.impl.LocalOperationStatsImpl;
import com.hazelcast.monitor.impl.MemberPartitionStateImpl;
import com.hazelcast.monitor.impl.MemberStateImpl;
import com.hazelcast.monitor.impl.NodeStateImpl;
import com.hazelcast.multimap.impl.MultiMapService;
import com.hazelcast.nio.Address;
import com.hazelcast.replicatedmap.impl.ReplicatedMapService;
import com.hazelcast.spi.StatisticsAwareService;
import com.hazelcast.spi.impl.NodeEngineImpl;
import com.hazelcast.spi.impl.servicemanager.ServiceInfo;
import com.hazelcast.spi.partition.IPartition;
import com.hazelcast.spi.properties.GroupProperty;
import com.hazelcast.topic.impl.TopicService;
import com.hazelcast.wan.WanReplicationService;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* A Factory for creating {@link com.hazelcast.monitor.TimedMemberState} instances.
*/
public class TimedMemberStateFactory {
private static final int INITIAL_PARTITION_SAFETY_CHECK_DELAY = 15;
private static final int PARTITION_SAFETY_CHECK_PERIOD = 60;
private final HazelcastInstanceImpl instance;
private final int maxVisibleInstanceCount;
private final boolean cacheServiceEnabled;
private volatile boolean memberStateSafe = true;
public TimedMemberStateFactory(HazelcastInstanceImpl instance) {
this.instance = instance;
Node node = instance.node;
maxVisibleInstanceCount = node.getProperties().getInteger(GroupProperty.MC_MAX_VISIBLE_INSTANCE_COUNT);
cacheServiceEnabled = isCacheServiceEnabled();
}
private boolean isCacheServiceEnabled() {
NodeEngineImpl nodeEngine = instance.node.nodeEngine;
Collection<ServiceInfo> serviceInfos = nodeEngine.getServiceInfos(CacheService.class);
return !serviceInfos.isEmpty();
}
public void init() {
instance.node.nodeEngine.getExecutionService().scheduleWithRepetition(new Runnable() {
@Override
public void run() {
memberStateSafe = instance.getPartitionService().isLocalMemberSafe();
}
}, INITIAL_PARTITION_SAFETY_CHECK_DELAY, PARTITION_SAFETY_CHECK_PERIOD, TimeUnit.SECONDS);
}
public TimedMemberState createTimedMemberState() {
MemberStateImpl memberState = new MemberStateImpl();
Collection<StatisticsAwareService> services = instance.node.nodeEngine.getServices(StatisticsAwareService.class);
TimedMemberState timedMemberState = new TimedMemberState();
createMemberState(timedMemberState, memberState, services);
timedMemberState.setMaster(instance.node.isMaster());
timedMemberState.setMemberList(new ArrayList<String>());
if (timedMemberState.isMaster()) {
Set<Member> memberSet = instance.getCluster().getMembers();
for (Member member : memberSet) {
MemberImpl memberImpl = (MemberImpl) member;
Address address = memberImpl.getAddress();
timedMemberState.getMemberList().add(address.getHost() + ":" + address.getPort());
}
}
timedMemberState.setMemberState(memberState);
GroupConfig groupConfig = instance.getConfig().getGroupConfig();
timedMemberState.setClusterName(groupConfig.getName());
SSLConfig sslConfig = instance.getConfig().getNetworkConfig().getSSLConfig();
timedMemberState.setSslEnabled(sslConfig != null && sslConfig.isEnabled());
return timedMemberState;
}
protected LocalMemoryStats getMemoryStats() {
return new LocalMemoryStatsImpl(instance.getMemoryStats());
}
protected LocalOperationStats getOperationStats() {
return new LocalOperationStatsImpl(instance.node);
}
private void createMemberState(TimedMemberState timedMemberState, MemberStateImpl memberState,
Collection<StatisticsAwareService> services) {
Node node = instance.node;
HashSet<ClientEndPointDTO> serializableClientEndPoints = new HashSet<ClientEndPointDTO>();
for (Client client : instance.node.clientEngine.getClients()) {
serializableClientEndPoints.add(new ClientEndPointDTO(client));
}
memberState.setClients(serializableClientEndPoints);
Address thisAddress = node.getThisAddress();
memberState.setAddress(thisAddress.getHost() + ":" + thisAddress.getPort());
TimedMemberStateFactoryHelper.registerJMXBeans(instance, memberState);
MemberPartitionStateImpl memberPartitionState = (MemberPartitionStateImpl) memberState.getMemberPartitionState();
InternalPartitionService partitionService = node.getPartitionService();
IPartition[] partitions = partitionService.getPartitions();
List<Integer> partitionList = memberPartitionState.getPartitions();
for (IPartition partition : partitions) {
if (partition.isLocal()) {
partitionList.add(partition.getPartitionId());
}
}
memberPartitionState.setMigrationQueueSize(partitionService.getMigrationQueueSize());
memberPartitionState.setMemberStateSafe(memberStateSafe);
memberState.setLocalMemoryStats(getMemoryStats());
memberState.setOperationStats(getOperationStats());
TimedMemberStateFactoryHelper.createRuntimeProps(memberState);
createMemState(timedMemberState, memberState, services);
createNodeState(memberState);
createHotRestartState(memberState);
createClusterHotRestartStatus(memberState);
createWanSyncState(memberState);
}
private void createHotRestartState(MemberStateImpl memberState) {
final HotRestartService hotRestartService = instance.node.getNodeExtension().getHotRestartService();
boolean hotBackupEnabled = hotRestartService.isHotBackupEnabled();
final HotRestartStateImpl state = new HotRestartStateImpl(hotRestartService.getBackupTaskStatus(), hotBackupEnabled);
memberState.setHotRestartState(state);
}
private void createClusterHotRestartStatus(MemberStateImpl memberState) {
final ClusterHotRestartStatusDTO state =
instance.node.getNodeExtension().getInternalHotRestartService().getCurrentClusterHotRestartStatus();
memberState.setClusterHotRestartStatus(state);
}
private void createNodeState(MemberStateImpl memberState) {
Node node = instance.node;
ClusterService cluster = instance.node.clusterService;
NodeStateImpl nodeState = new NodeStateImpl(cluster.getClusterState(), node.getState(),
cluster.getClusterVersion(), node.getVersion());
memberState.setNodeState(nodeState);
}
private void createWanSyncState(MemberStateImpl memberState) {
WanReplicationService wanReplicationService = instance.node.nodeEngine.getWanReplicationService();
WanSyncState wanSyncState = wanReplicationService.getWanSyncState();
if (wanSyncState != null) {
memberState.setWanSyncState(wanSyncState);
}
}
private void createMemState(TimedMemberState timedMemberState, MemberStateImpl memberState,
Collection<StatisticsAwareService> services) {
int count = 0;
Config config = instance.getConfig();
Set<String> longInstanceNames = new HashSet<String>(maxVisibleInstanceCount);
for (StatisticsAwareService service : services) {
if (count < maxVisibleInstanceCount) {
if (service instanceof MapService) {
count = handleMap(memberState, count, config, ((MapService) service).getStats(), longInstanceNames);
} else if (service instanceof MultiMapService) {
count = handleMultimap(memberState, count, config, ((MultiMapService) service).getStats(), longInstanceNames);
} else if (service instanceof QueueService) {
count = handleQueue(memberState, count, config, ((QueueService) service).getStats(), longInstanceNames);
} else if (service instanceof TopicService) {
count = handleTopic(memberState, count, config, ((TopicService) service).getStats(), longInstanceNames);
} else if (service instanceof DistributedExecutorService) {
count = handleExecutorService(memberState, count, config,
((DistributedExecutorService) service).getStats(), longInstanceNames);
} else if (service instanceof ReplicatedMapService) {
count = handleReplicatedMap(memberState, count, config, ((ReplicatedMapService) service).getStats(),
longInstanceNames);
}
}
}
WanReplicationService wanReplicationService = instance.node.nodeEngine.getWanReplicationService();
Map<String, LocalWanStats> wanStats = wanReplicationService.getStats();
if (wanStats != null) {
count = handleWan(memberState, count, wanStats, longInstanceNames);
}
if (cacheServiceEnabled) {
ICacheService cacheService = getCacheService();
for (CacheConfig cacheConfig : cacheService.getCacheConfigs()) {
if (cacheConfig.isStatisticsEnabled() && count < maxVisibleInstanceCount) {
CacheStatistics statistics = cacheService.getStatistics(cacheConfig.getNameWithPrefix());
//Statistics can be null for a short period of time since config is created at first then stats map
//is filled.git
if (statistics != null) {
count = handleCache(memberState, count, cacheConfig, statistics, longInstanceNames);
}
}
}
}
timedMemberState.setInstanceNames(longInstanceNames);
}
private int handleExecutorService(MemberStateImpl memberState, int count, Config config,
Map<String, LocalExecutorStats> executorServices,
Set<String> longInstanceNames) {
for (Map.Entry<String, LocalExecutorStats> entry : executorServices.entrySet()) {
String name = entry.getKey();
if (count >= maxVisibleInstanceCount) {
break;
} else if (config.findExecutorConfig(name).isStatisticsEnabled()) {
LocalExecutorStats stats = entry.getValue();
memberState.putLocalExecutorStats(name, stats);
longInstanceNames.add("e:" + name);
++count;
}
}
return count;
}
private int handleMultimap(MemberStateImpl memberState, int count, Config config, Map<String, LocalMultiMapStats> multiMaps,
Set<String> longInstanceNames) {
for (Map.Entry<String, LocalMultiMapStats> entry : multiMaps.entrySet()) {
String name = entry.getKey();
if (count >= maxVisibleInstanceCount) {
break;
} else if (config.findMultiMapConfig(name).isStatisticsEnabled()) {
LocalMultiMapStats stats = entry.getValue();
memberState.putLocalMultiMapStats(name, stats);
longInstanceNames.add("m:" + name);
++count;
}
}
return count;
}
private int handleReplicatedMap(MemberStateImpl memberState, int count, Config
config, Map<String, LocalReplicatedMapStats> replicatedMaps, Set<String> longInstanceNames) {
for (Map.Entry<String, LocalReplicatedMapStats> entry : replicatedMaps.entrySet()) {
String name = entry.getKey();
if (count >= maxVisibleInstanceCount) {
break;
} else if (config.findReplicatedMapConfig(name).isStatisticsEnabled()) {
LocalReplicatedMapStats stats = entry.getValue();
memberState.putLocalReplicatedMapStats(name, stats);
longInstanceNames.add("r:" + name);
++count;
}
}
return count;
}
private int handleTopic(MemberStateImpl memberState, int count, Config config, Map<String, LocalTopicStats> topics,
Set<String> longInstanceNames) {
for (Map.Entry<String, LocalTopicStats> entry : topics.entrySet()) {
String name = entry.getKey();
if (count >= maxVisibleInstanceCount) {
break;
} else if (config.findTopicConfig(name).isStatisticsEnabled()) {
LocalTopicStats stats = entry.getValue();
memberState.putLocalTopicStats(name, stats);
longInstanceNames.add("t:" + name);
++count;
}
}
return count;
}
private int handleQueue(MemberStateImpl memberState, int count, Config config, Map<String, LocalQueueStats> queues,
Set<String> longInstanceNames) {
for (Map.Entry<String, LocalQueueStats> entry : queues.entrySet()) {
String name = entry.getKey();
if (count >= maxVisibleInstanceCount) {
break;
} else if (config.findQueueConfig(name).isStatisticsEnabled()) {
LocalQueueStats stats = entry.getValue();
memberState.putLocalQueueStats(name, stats);
longInstanceNames.add("q:" + name);
++count;
}
}
return count;
}
private int handleMap(MemberStateImpl memberState, int count, Config config, Map<String, LocalMapStats> maps,
Set<String> longInstanceNames) {
for (Map.Entry<String, LocalMapStats> entry : maps.entrySet()) {
String name = entry.getKey();
if (count >= maxVisibleInstanceCount) {
break;
} else if (config.findMapConfig(name).isStatisticsEnabled()) {
LocalMapStats stats = entry.getValue();
memberState.putLocalMapStats(name, stats);
longInstanceNames.add("c:" + name);
++count;
}
}
return count;
}
private int handleWan(MemberStateImpl memberState, int count, Map<String, LocalWanStats> wans,
Set<String> longInstanceNames) {
for (Map.Entry<String, LocalWanStats> entry : wans.entrySet()) {
String schemeName = entry.getKey();
LocalWanStats stats = entry.getValue();
memberState.putLocalWanStats(schemeName, stats);
longInstanceNames.add("w:" + schemeName);
count++;
}
return count;
}
private int handleCache(MemberStateImpl memberState, int count, CacheConfig config, CacheStatistics cacheStatistics,
Set<String> longInstanceNames) {
memberState.putLocalCacheStats(config.getNameWithPrefix(), new LocalCacheStatsImpl(cacheStatistics));
longInstanceNames.add("j:" + config.getNameWithPrefix());
return ++count;
}
private ICacheService getCacheService() {
return instance.node.nodeEngine.getService(ICacheService.SERVICE_NAME);
}
}