All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gemstone.gemfire.management.internal.LocalManager Maven / Gradle / Ivy

There is a newer version: 2.0-BETA
Show newest version
/*
 * 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;
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy