com.gemstone.gemfire.management.internal.LocalManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gemfire-core Show documentation
Show all versions of gemfire-core Show documentation
SnappyData store based off Pivotal GemFireXD
/*
* Copyright (c) 2010-2015 Pivotal Software, 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. See accompanying
* LICENSE file.
*/
package com.gemstone.gemfire.management.internal;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import javax.management.MalformedObjectNameException;
import javax.management.Notification;
import javax.management.ObjectName;
import com.gemstone.gemfire.CancelException;
import com.gemstone.gemfire.GemFireException;
import com.gemstone.gemfire.SystemFailure;
import com.gemstone.gemfire.cache.AttributesFactory;
import com.gemstone.gemfire.cache.Cache;
import com.gemstone.gemfire.cache.DataPolicy;
import com.gemstone.gemfire.cache.RegionAttributes;
import com.gemstone.gemfire.cache.RegionExistsException;
import com.gemstone.gemfire.cache.Scope;
import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem;
import com.gemstone.gemfire.internal.LogWriterImpl;
import com.gemstone.gemfire.internal.cache.CachePerfStats;
import com.gemstone.gemfire.internal.cache.HasCachePerfStats;
import com.gemstone.gemfire.internal.cache.InternalRegionArguments;
import com.gemstone.gemfire.management.ManagementException;
/**
* DistributionHelper solves the following problems
*
* a) Handles proxy creation when Management node comes up b) Handles proxy
* creation when a member joins c) Remove proxies when a member leaves or node
* stops being management node. d) Takes care to create resources like hidden
* regions for MBean and notification federation.
*
*
* @author rishim
*
*/
public class LocalManager extends Manager {
/**
* Management Task pushes data to the admin regions
*/
private ManagementTask managementTask;
/**
* This service will be responsible for executing ManagementTasks and
* periodically push data to localMonitoringRegion
*/
protected ScheduledExecutorService singleThreadFederationScheduler;
/**
* This map holds all the components which are eligible for federation.
* Although filters might prevent any of the component from getting federated.
*/
private Map federatedComponentMap;
private Object lock = new Object();
private SystemManagementService service;
/**
* Public constructor
*
* @param repo
* management resource repo
* @param system
* internal distributed system
*/
public LocalManager(ManagementResourceRepo repo,
InternalDistributedSystem system, SystemManagementService service, Cache cache) {
super(repo, system,cache);
this.service = service;
this.federatedComponentMap = new ConcurrentHashMap();
}
/**
* Managed Node side resources are created
*
* Management Region : its a Replicated NO_ACK region Notification Region :
* its a Replicated Proxy NO_ACK region
*
*/
private void startLocalManagement(
Map federatedComponentMap) {
synchronized (this) {
if (repo.getLocalMonitoringRegion() != null) {
return;
} else {
ThreadFactory tf = new ThreadFactory() {
public Thread newThread(final Runnable command) {
final Runnable r = new Runnable() {
public void run() {
command.run();
}
};
final ThreadGroup group = LogWriterImpl.createThreadGroup(ManagementStrings.MANAGEMENT_TASK_THREAD_GROUP
.toLocalizedString(), logger);
Thread thread = new Thread(group, r, ManagementStrings.MANAGEMENT_TASK.toLocalizedString());
thread.setDaemon(true);
return thread;
}
};
singleThreadFederationScheduler = Executors
.newSingleThreadScheduledExecutor(tf);
if(logger.fineEnabled()){
logger.fine("Creating Management Region : ");
}
/**
* Sharing the same Internal Argument for both notification region and
* monitoring region
**/
InternalRegionArguments internalArgs = new InternalRegionArguments();
internalArgs.setIsUsedForMetaRegion(true);
// Create anonymous stats holder for Management Regions
final HasCachePerfStats monitoringRegionStats = new HasCachePerfStats() {
public CachePerfStats getCachePerfStats() {
return new CachePerfStats(cache.getDistributedSystem(),
"managementRegionStats");
}
};
internalArgs.setCachePerfStatsHolder(monitoringRegionStats);
AttributesFactory monitorRegionAttributeFactory = new AttributesFactory();
monitorRegionAttributeFactory.setScope(Scope.DISTRIBUTED_NO_ACK);
monitorRegionAttributeFactory.setDataPolicy(DataPolicy.REPLICATE);
monitorRegionAttributeFactory.setConcurrencyChecksEnabled(false);
MonitoringRegionCacheListener localListener = new MonitoringRegionCacheListener(
service);
monitorRegionAttributeFactory.addCacheListener(localListener);
RegionAttributes monitoringRegionAttrs = monitorRegionAttributeFactory
.create();
AttributesFactory notificationRegionAttributeFactory = new AttributesFactory();
notificationRegionAttributeFactory.setScope(Scope.DISTRIBUTED_NO_ACK);
notificationRegionAttributeFactory.setDataPolicy(DataPolicy.EMPTY);
notificationRegionAttributeFactory.setConcurrencyChecksEnabled(false);
RegionAttributes notifRegionAttrs = notificationRegionAttributeFactory
.create();
String appender = MBeanJMXAdapter.getUniqueIDForMember(cache
.getDistributedSystem().getDistributedMember());
boolean monitoringRegionCreated = false;
boolean notifRegionCreated = false;
try {
repo.setLocalMonitoringRegion(cache.createVMRegion(
ManagementConstants.MONITORING_REGION + "_" + appender.toLowerCase(),//To handle hostNames with UpperCase
monitoringRegionAttrs, internalArgs));
monitoringRegionCreated = true;
} catch (com.gemstone.gemfire.cache.TimeoutException e) {
throw new ManagementException(e);
} catch (RegionExistsException e) {
throw new ManagementException(e);
} catch (IOException e) {
throw new ManagementException(e);
} catch (ClassNotFoundException e) {
throw new ManagementException(e);
}
try {
repo.setLocalNotificationRegion(cache.createVMRegion(
ManagementConstants.NOTIFICATION_REGION + "_" + appender.toLowerCase(),//To handle hostNames with UpperCase
notifRegionAttrs, internalArgs));
notifRegionCreated = true;
} catch (com.gemstone.gemfire.cache.TimeoutException e) {
throw new ManagementException(e);
} catch (RegionExistsException e) {
throw new ManagementException(e);
} catch (IOException e) {
throw new ManagementException(e);
} catch (ClassNotFoundException e) {
throw new ManagementException(e);
} finally {
if (!notifRegionCreated && monitoringRegionCreated) {
repo.getLocalMonitoringRegion().localDestroyRegion();
}
}
managementTask = new ManagementTask(federatedComponentMap);
// call run to get us initialized immediately with a sync call
managementTask.run();
// All local resources are created for the ManagementTask
// Now Management tasks can proceed.
int updateRate = cache.getDistributedSystem().getConfig().getJmxManagerUpdateRate();
singleThreadFederationScheduler.scheduleAtFixedRate(managementTask, updateRate, updateRate, TimeUnit.MILLISECONDS);
if (logger.fineEnabled()) {
logger.fine("Management Region created with Name : "
+ repo.getLocalMonitoringRegion().getName());
logger.fine("Notification Region created with Name : "
+ repo.getLocalNotificationRegion().getName());
}
}
}
}
public void markForFederation(ObjectName objName, FederationComponent fedComp) {
federatedComponentMap.put(objName, fedComp);
}
public void unMarkForFederation(ObjectName objName) {
synchronized (lock) {
if (federatedComponentMap.get(objName) != null) {
federatedComponentMap.remove(objName);
}
if (repo.getLocalMonitoringRegion() != null
&& repo.getLocalMonitoringRegion().get(objName.toString()) != null) {
// To delete an entry from the region
repo.getLocalMonitoringRegion().remove(objName.toString());
}
}
}
/**
* This method will shutdown various tasks running for management
*/
private void shutdownTasks() {
// No need of pooledGIIExecutor as this node wont do GII again
// so better to release resources
if (this.singleThreadFederationScheduler != null) {
List l = this.singleThreadFederationScheduler.shutdownNow();
}
}
/**
* Clean up management artifacts
*/
private void cleanUpResources() {
// InternalDistributedSystem.getConnectedInstance will return an instance if
// there is at least one connected instance and is not in the process of
// being disconnected.
if (!cache.isClosed() && InternalDistributedSystem.getConnectedInstance() !=null) {
if (repo.getLocalMonitoringRegion() != null) {
// To delete an entry from the region
for (String name : repo.getLocalMonitoringRegion().keySet()) {
ObjectName objName = null;
try {
objName = ObjectName.getInstance(name);
unMarkForFederation(objName);
} catch (MalformedObjectNameException e) {
if (logger.fineEnabled()) {
logger.fine("Unable to clean MBean: " + objName + "due to "
+ e.getMessage());
}
} catch (NullPointerException e) {
if (logger.fineEnabled()) {
logger.fine("Unable to clean MBean: " + objName + "due to "
+ e.getMessage());
}
}
}
repo.destroyLocalMonitoringRegion();
}
if (repo.getLocalNotificationRegion() != null) {
repo.destroyLocalNotifRegion();
}
}
}
/**
*For internal Use only
*/
public ScheduledExecutorService getFederationSheduler() {
return singleThreadFederationScheduler;
}
/**
* Internal testing hook.Not to be used from any where else.
* As soon as a mbean is created we can push the data into local region
* which will make the data available at managing node site.
*/
public void runManagementTaskAdhoc(){
managementTask.run();
}
/**
* This task is responsible for pushing data to the hidden region. It is
* executed in a single thread from
* Executors.newSingleThreadScheduledExecutor(); Only one thread will be
* responsible for pushing the data to the hidden region.
*
* (Note however that if this single thread terminates due to a failure during
* execution prior to shutdown, a new one will take its place if needed to
* execute subsequent tasks.) Tasks are guaranteed to execute sequentially,
* and no more than one task will be active at any given time. Unlike the
* otherwise equivalent newScheduledThreadPool(1) the returned
* executor is guaranteed not to be reconfigurable to use additional threads.
*
*
* @author rishim
*
*/
private class ManagementTask implements Runnable {
private Map replicaMap;
public ManagementTask(Map federatedComponentMap) throws ManagementException {
this.replicaMap = new HashMap();
}
@Override
public void run() {
if (logger.finestEnabled()) {
logger.finest("Federation started at managed node : ");
}
replicaMap.clear();
try {
synchronized (lock) {
Set keySet = federatedComponentMap.keySet();
if (keySet.size() == 0) {
return;
}
Iterator it = keySet.iterator();
while (it.hasNext()) {
ObjectName objectName = it.next();
FederationComponent fedCompInstance = federatedComponentMap.get(objectName);
if (Thread.interrupted()) {
replicaMap.clear();
return;
}
if (fedCompInstance != null) {
boolean stateChanged = fedCompInstance.refreshObjectState(service.isManager());
if (!stopCacheOps) {
String key = objectName.toString();
if (stateChanged || !repo.keyExistsInLocalMonitoringRegion(key)) {
replicaMap.put(key, fedCompInstance);
}
}
}
}
if (stopCacheOps) {
return;
}
if (Thread.interrupted()) {
replicaMap.clear();
return;
}
repo.putAllInLocalMonitoringRegion(replicaMap);
}
} catch (CancelException ex) {
if (logger.warningEnabled())
logger.warning(ManagementStrings.MANAGEMENT_TASK_CANCELLED);
return;
} catch(GemFireException ex){
if (!cache.isClosed() && logger.warningEnabled()) {
logger.warning(ex);
}
return; // Ignore Exception if cache is closing
} catch (VirtualMachineError e) {
SystemFailure.initiateFailure(e);
throw e;
} catch (Throwable th) {
SystemFailure.checkFailure();
// Catching all run time exception and Errors to
// pass to Thread group logger
// why is this invoking uncaughtException directly??
Thread currentThread = Thread.currentThread();
ThreadGroup tg = currentThread.getThreadGroup();
tg.uncaughtException(currentThread, th);
return;
}
if (logger.finestEnabled()) {
logger.finest("Federation completed at managed node : ");
}
}
}
@Override
public boolean isRunning() {
return running;
}
@Override
public void startManager() {
startLocalManagement(federatedComponentMap);
running = true;
}
@Override
public void stopManager() {
// Shutting down the GII executor as this node wont require
// it anymore
shutdownTasks();
// Clean up management Resources
cleanUpResources();
running = false;
}
public void stopCacheOps(){
stopCacheOps = true;
}
public void startCacheOps(){
stopCacheOps = false;
}
public Map getFedComponents(){
return federatedComponentMap;
}
}