com.gemstone.gemfire.management.internal.FederatingManager 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.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.management.InstanceNotFoundException;
import javax.management.Notification;
import javax.management.ObjectName;
import com.gemstone.gemfire.cache.AttributesFactory;
import com.gemstone.gemfire.cache.Cache;
import com.gemstone.gemfire.cache.DataPolicy;
import com.gemstone.gemfire.cache.EvictionAction;
import com.gemstone.gemfire.cache.EvictionAttributes;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.RegionAttributes;
import com.gemstone.gemfire.cache.RegionExistsException;
import com.gemstone.gemfire.cache.Scope;
import com.gemstone.gemfire.distributed.DistributedMember;
import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem;
import com.gemstone.gemfire.distributed.internal.membership.InternalDistributedMember;
import com.gemstone.gemfire.internal.cache.InternalRegionArguments;
import com.gemstone.gemfire.internal.cache.HasCachePerfStats;
import com.gemstone.gemfire.internal.cache.CachePerfStats;
import com.gemstone.gemfire.management.ManagementException;
/**
* Manager implementation which manages federated MBeans for the entire
* DistributedSystem and controls the JMX server endpoints for JMX clients to
* connect, such as an RMI server.
*
* The FederatingManager is only appropriate for a peer or server in a GemFire
* distributed system.
*
* @author Pivotal Software, Inc.
* @since 7.0
*/
public class FederatingManager extends Manager {
/**
*
* This Executor uses a pool of thread to execute the member addition /removal tasks, This will
* utilize the processing powers available. Going with unbounded queue because
* tasks wont be unbounded in practical situation as number of members will be
* a finite set at any given point of time
*/
private ExecutorService pooledMembershipExecutor;
/**
* Proxy factory is used to create , remove proxies
*/
protected MBeanProxyFactory proxyFactory;
/**
* Remote Filter chain for local MBean filters
*/
private RemoteFilterChain remoteFilterChain;
private MBeanJMXAdapter jmxAdapter;
private MemberMessenger messenger;
private SystemManagementService service;
/**
* Public Constructor
*
* @param jmxAdapter
* JMX Adpater
* @param repo
* Management resource repo
* @param system
* Internal Distributed System
* @param service
* SystemManagement Service
*/
public FederatingManager(MBeanJMXAdapter jmxAdapter,
ManagementResourceRepo repo, InternalDistributedSystem system, SystemManagementService service, Cache cache) {
super(repo, system, cache);
this.remoteFilterChain = new RemoteFilterChain();
this.service = service;
this.proxyFactory = new MBeanProxyFactory(remoteFilterChain, jmxAdapter,
service);
this.jmxAdapter = jmxAdapter;
this.messenger = new MemberMessenger(jmxAdapter, repo, system);
}
/**
* This method will be invoked whenever a member wants to be a managing node.
* The exception Management exception has to be handled by the caller.
*/
@Override
public synchronized void startManager() {
try {
if (logger.fineEnabled()) {
logger.fine("Starting the Manager.... ");
}
running = true;
startManagingActivity();
messenger.broadcastManagerInfo();
} catch (InterruptedException e) {
running = false;
throw new ManagementException(e);
} catch (Exception e) {
running = false;
throw new ManagementException(e);
}
}
public synchronized void stopManager() {
// remove hidden mgmt regions and federatedMBeans
if(!running){
return;
}
running = false;
if (logger.fineEnabled()) {
logger.fine("Stopping the Manager.... ");
}
stopManagingActivity();
}
/**
* This method will be invoked from MembershipListener which is registered
* when the member becomes a Management node.
*
* This method will delegate task to another thread and exit, so that it wont
* block the membership listener
* @param member
*/
public void addMember(DistributedMember member) {
GIITask giiTask = new GIITask(member);
pooledMembershipExecutor.submit(giiTask);
}
/**
* This method will be invoked from MembershipListener which is registered
* when the member becomes a Management node.
*
* This method will delegate task to another thread and exit, so that it wont
* block the membership listener
*
* @param member
*/
public void removeMember(DistributedMember member, boolean crashed) {
RemoveMemberTask removeTask = new RemoveMemberTask(member, crashed);
pooledMembershipExecutor.submit(removeTask);
}
private class RemoveMemberTask implements Callable {
private DistributedMember member;
boolean crashed;
protected RemoveMemberTask(DistributedMember member, boolean crashed) {
this.member = member;
this.crashed = crashed;
}
public DistributedMember call() {
return removeMemberArtifacts(member, crashed);
}
}
private DistributedMember removeMemberArtifacts(DistributedMember member, boolean crashed) {
Region proxyRegion = repo.getEntryFromMonitoringRegionMap(member);
Region notifRegion = repo.getEntryFromNotifRegionMap(member);
if (proxyRegion == null && notifRegion == null) {
return member;
}
repo.romoveEntryFromMonitoringRegionMap(member);
repo.removeEntryFromNotifRegionMap(member);
// If cache is closed all the regions would have been
// destroyed implicitly
if (!cache.isClosed()) {
proxyFactory.removeAllProxies(member, proxyRegion);
proxyRegion.localDestroyRegion();
notifRegion.localDestroyRegion();
}
if (!cache.getDistributedSystem().getDistributedMember().equals(member)) {
service.memberDeparted((InternalDistributedMember) member, crashed);
}
return member;
}
/**
* This method will be invoked from MembershipListener which is registered
* when the member becomes a Management node.
*
* this method will delegate task to another thread and exit, so that it wont
* block the membership listener
*
* @param member
*/
public void suspectMember(DistributedMember member, InternalDistributedMember whoSuspected) {
service.memberSuspect((InternalDistributedMember) member, whoSuspected);
}
/**
* This method will be invoked when a node transitions from managed node to
* managing node This method will block for all GIIs to be completed But each
* GII is given a specific time frame. After that the task will be marked as
* cancelled.
*
* @throws InterruptedException
*/
public void startManagingActivity() throws Exception {
Set members = cache
.getDistributionManager().getOtherDistributionManagerIds();
Iterator it = members.iterator();
DistributedMember member;
Runtime rt = Runtime.getRuntime();
pooledMembershipExecutor = Executors
.newFixedThreadPool(rt.availableProcessors());
List giiTaskList = new ArrayList();
List> futureTaskList;
while (it.hasNext()) {
member = it.next();
giiTaskList.add(new GIITask(member));
}
try {
if (logger.fineEnabled()) {
logger.fine("Management Resource creation started : ");
}
futureTaskList = pooledMembershipExecutor.invokeAll(giiTaskList);
for (Future futureTask : futureTaskList) {
String memberId = null;
try {
DistributedMember returnedMember = futureTask.get();
if(returnedMember != null){
memberId = returnedMember.getId();
}
if (futureTask.isDone()) {
if (logger.fineEnabled()) {
logger.fine("Monitoring Resource Created for : " + memberId);
}
}
if (futureTask.isCancelled()) {
// Retry mechanism can be added here after discussions
if (logger.fineEnabled()) {
logger
.fine("Monitoring resource Creation Failed for : " + memberId);
}
}
} catch (ExecutionException e) {
if (logger.fineEnabled()) {
logger.fine("ExecutionException during Management GII " + e);
}
} catch(CancellationException e){
if (logger.fineEnabled()) {
ManagementException mgEx = new ManagementException(e.fillInStackTrace());
logger
.fine("InterruptedException while creating Monitoring resource with error : "
+ mgEx.getMessage());
}
}
}
} catch (InterruptedException e) {
if (logger.fineEnabled()) {
ManagementException mgEx = new ManagementException(e.fillInStackTrace());
logger
.fine("InterruptedException while creating Monitoring resource with error : "
+ mgEx.getMessage());
}
} finally {
}
}
/**
* This method will be invoked whenever a member stops being a managing node.
* The exception Management exception has to be handled by the caller.
*
* @throws ManagementException
*
*/
private void stopManagingActivity() {
try {
pooledMembershipExecutor.shutdown();
Iterator it = repo.getMonitoringRegionMap().keySet()
.iterator();
while (it.hasNext()) {
removeMemberArtifacts(it.next(), false);
}
} catch (Exception e) {
throw new ManagementException(e);
}finally{
// For future use
}
}
@Override
public boolean isRunning() {
return running;
}
/**
* Actual task of doing the GII
*
* It will perform the GII request which might originate from
* TranstionListener or Membership Listener.
*
*
*
*
* Managing Node side resources are created per member which is visible to
* this node
*
* 1)Management Region : its a Replicated NO_ACK region 2)Notification Region
* : its a Replicated Proxy NO_ACK region
*
* Listeners are added to the above two regions 1) ManagementCacheListener()
* 2) NotificationCacheListener
*
* This task can be cancelled from the calling thread if a timeout happens. In
* that case we have to handle the thread interrupt
*
* @author rishim
*
*/
private class GIITask implements Callable {
private DistributedMember member;
protected GIITask(DistributedMember member) {
this.member = member;
}
public DistributedMember call() {
Region proxyMonitoringRegion = null;
Region proxyNotificationgRegion = null;
boolean proxyCreatedForMember = false;
try {
// GII wont start at all if its interrupted
if (!Thread.currentThread().isInterrupted()) {
// as the regions will be internal regions
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);
// Monitoring region for member is created
AttributesFactory monitorAttrFactory = new AttributesFactory();
monitorAttrFactory.setScope(Scope.DISTRIBUTED_NO_ACK);
monitorAttrFactory.setDataPolicy(DataPolicy.REPLICATE);
monitorAttrFactory.setConcurrencyChecksEnabled(false);
ManagementCacheListener mgmtCacheListener = new ManagementCacheListener(proxyFactory);
monitorAttrFactory.addCacheListener(mgmtCacheListener);
RegionAttributes monitoringRegionAttrs = monitorAttrFactory
.create();
// Notification region for member is created
AttributesFactory notifAttrFactory = new AttributesFactory();
notifAttrFactory.setScope(Scope.DISTRIBUTED_NO_ACK);
notifAttrFactory.setDataPolicy(DataPolicy.REPLICATE);
notifAttrFactory.setConcurrencyChecksEnabled(false);
// Fix for issue #49638, evict the internal region _notificationRegion
notifAttrFactory.setEvictionAttributes(EvictionAttributes.createLRUEntryAttributes(ManagementConstants.NOTIF_REGION_MAX_ENTRIES,
EvictionAction.LOCAL_DESTROY));
NotificationCacheListener notifListener = new NotificationCacheListener(proxyFactory);
notifAttrFactory.addCacheListener(notifListener);
RegionAttributes notifRegionAttrs = notifAttrFactory.create();
boolean proxyMonitoringRegionCreated = false;
boolean proxyNotifRegionCreated = false;
String appender = MBeanJMXAdapter.getUniqueIDForMember(member);
try {
if (!running) {
return null;
}
proxyMonitoringRegion = cache.createVMRegion(ManagementConstants.MONITORING_REGION + "_" + appender, monitoringRegionAttrs, internalArgs);
proxyMonitoringRegionCreated = true;
} catch (com.gemstone.gemfire.cache.TimeoutException e) {
if (logger.fineEnabled()) {
logger.fine("Error During Internal Region creation" + e);
}
throw new ManagementException(e);
} catch (RegionExistsException e) {
if (logger.fineEnabled()) {
logger.fine("Error During Internal Region creation" + e);
}
throw new ManagementException(e);
} catch (IOException e) {
if (logger.fineEnabled()) {
logger.fine("Error During Internal Region creation" + e);
}
throw new ManagementException(e);
} catch (ClassNotFoundException e) {
if (logger.fineEnabled()) {
logger.fine("Error During Internal Region creation" + e);
}
throw new ManagementException(e);
}
try {
if (!running) {
return null;
}
proxyNotificationgRegion = cache.createVMRegion(ManagementConstants.NOTIFICATION_REGION + "_" + appender, notifRegionAttrs, internalArgs);
proxyNotifRegionCreated = true;
} catch (com.gemstone.gemfire.cache.TimeoutException e) {
if (logger.fineEnabled()) {
logger.fine("Error During Internal Region creation" + e);
}
throw new ManagementException(e);
} catch (RegionExistsException e) {
if (logger.fineEnabled()) {
logger.fine("Error During Internal Region creation" + e);
}
throw new ManagementException(e);
} catch (IOException e) {
if (logger.fineEnabled()) {
logger.fine("Error During Internal Region creation" + e);
}
throw new ManagementException(e);
} catch (ClassNotFoundException e) {
if (logger.fineEnabled()) {
logger.fine("Error During Internal Region creation" + e);
}
throw new ManagementException(e);
} finally {
if (!proxyNotifRegionCreated && proxyMonitoringRegionCreated) {
// Destroy the proxy region if proxy notification
// region is not created
proxyMonitoringRegion.localDestroyRegion();
}
}
if (logger.fineEnabled()) {
logger.fine("Management Region created with Name : " + proxyMonitoringRegion.getName());
logger.fine("Notification Region created with Name : " + proxyNotificationgRegion.getName());
}
// Only the exception case would have destroyed the proxy
// regions. We can safely proceed here.
repo.putEntryInMonitoringRegionMap(member, proxyMonitoringRegion);
repo.putEntryInNotifRegionMap(member, proxyNotificationgRegion);
try {
if (!running) {
return null;
}
proxyFactory.createAllProxies(member, proxyMonitoringRegion);
proxyCreatedForMember = true;
mgmtCacheListener.markReady();
notifListener.markReady();
} catch (Exception e) {
if (logger.fineEnabled()) {
logger.fine("Error During GII Proxy creation" + e);
}
throw new ManagementException(e);
}
}
} catch (Exception e) {
throw new ManagementException(e);
}
// Before completing task intimate all listening ProxyListener which might send notifications.
service.memberJoined((InternalDistributedMember) member);
// Send manager info to the added member
messenger.sendManagerInfo(member);
return member;
}
}
/**
*For internal Use only
*/
public MBeanProxyFactory getProxyFactory() {
return proxyFactory;
}
/**
* This will return the last updated time of the proxyMBean
*
* @param objectName
* {@link javax.management.ObjectName} of the MBean
* @return last updated time of the proxy
*
* @throws InstanceNotFoundException
*/
public long getLastUpdateTime(ObjectName objectName) {
return proxyFactory.getLastUpdateTime(objectName);
}
/**
* Find a particular proxy instance for a {@link javax.management.ObjectName}
* , {@link com.gemstone.gemfire.distributed.DistributedMember} and interface
* class If the proxy interface does not implement the given interface class a
* {@link java.lang.ClassCastException}. will be thrown
*
* @param objectName
* {@link javax.management.ObjectName} of the MBean
* @param interfaceClass
* interface class implemented by proxy
* @return an instance of proxy exposing the given interface
*/
public T findProxy(ObjectName objectName, Class interfaceClass) {
return proxyFactory.findProxy(objectName, interfaceClass);
}
/**
* Find a set of proxies given a
* {@link com.gemstone.gemfire.distributed.DistributedMember}
*
* @param member
* {@link com.gemstone.gemfire.distributed.DistributedMember}
* @return a set of {@link javax.management.ObjectName}
*/
public Set findAllProxies(DistributedMember member) {
return proxyFactory.findAllProxies(member);
}
public MemberMessenger getMessenger() {
return messenger;
}
}