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

org.apache.geode.management.internal.FederatingManager Maven / Gradle / Ivy

Go to download

Apache Geode provides a database-like consistency model, reliable transaction processing and a shared-nothing architecture to maintain very low latency performance with high concurrency processing

There is a newer version: 1.15.1
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The ASF licenses this file to You 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 org.apache.geode.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.Notification;
import javax.management.ObjectName;

import org.apache.logging.log4j.Logger;

import org.apache.geode.cache.AttributesFactory;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.EvictionAction;
import org.apache.geode.cache.EvictionAttributes;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.RegionExistsException;
import org.apache.geode.cache.Scope;
import org.apache.geode.distributed.DistributedMember;
import org.apache.geode.distributed.internal.InternalDistributedSystem;
import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
import org.apache.geode.internal.cache.CachePerfStats;
import org.apache.geode.internal.cache.HasCachePerfStats;
import org.apache.geode.internal.cache.InternalRegionArguments;
import org.apache.geode.internal.logging.LogService;
import org.apache.geode.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.
 * 
 * @since GemFire 7.0
 */
public class FederatingManager extends Manager {
  public static final Logger logger = LogService.getLogger();


  /**
   * 
   * 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.isDebugEnabled()) {
        logger.debug("Starting the Federating Manager.... ");
      }

      Runtime rt = Runtime.getRuntime();
      this.pooledMembershipExecutor = Executors.newFixedThreadPool(rt.availableProcessors());

      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.isDebugEnabled()) {
      logger.debug("Stopping the Federating Manager.... ");
    }
    stopManagingActivity();

  }

  /**
   * 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 {
      this.pooledMembershipExecutor.shutdownNow();
      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;
  }

  /**
   * 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);
    executeTask(new Runnable() {
      @Override
      public void run() {
        giiTask.call();
      }
    });
  }


  /**
   * 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);
    executeTask(removeTask);
  }

  private void submitTask(Callable task) {
    try {
      pooledMembershipExecutor.submit(task);
    } catch (java.util.concurrent.RejectedExecutionException ex) {
      // Ignore, we are getting shutdown
    }
  }

  private void executeTask(Runnable task) {
    try {
      pooledMembershipExecutor.execute(task);
    } catch (java.util.concurrent.RejectedExecutionException ex) {
      // Ignore, we are getting shutdown
    }
  }

  private class RemoveMemberTask implements Runnable {

    private DistributedMember member;

    boolean crashed;

    protected RemoveMemberTask(DistributedMember member, boolean crashed) {
      this.member = member;
      this.crashed = crashed;
    }

    public void run() {
      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
   * @param reason TODO
   */
  public void suspectMember(DistributedMember member, InternalDistributedMember whoSuspected,
      String reason) {
    service.memberSuspect((InternalDistributedMember) member, whoSuspected, reason);

  }

  /**
   * 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 {
    final boolean isDebugEnabled = logger.isDebugEnabled();

    Set members =
        cache.getDistributionManager().getOtherDistributionManagerIds();

    Iterator it = members.iterator();
    DistributedMember member;


    final List> giiTaskList = new ArrayList<>();

    List> futureTaskList;

    while (it.hasNext()) {
      member = it.next();
      giiTaskList.add(new GIITask(member));
    }

    try {
      if (isDebugEnabled) {
        logger.debug("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 (isDebugEnabled) {
              logger.debug("Monitoring Resource Created for : {}", memberId);
            }

          }
          if (futureTask.isCancelled()) {
            // Retry mechanism can be added here after discussions
            if (isDebugEnabled) {
              logger.debug("Monitoring resource Creation Failed for : {}", memberId);
            }

          }
        } catch (ExecutionException e) {
          if (isDebugEnabled) {
            logger.debug("ExecutionException during Management GII: {}", e.getMessage(), e);
          }

        } catch (CancellationException e) {
          if (isDebugEnabled) {
            ManagementException mgEx = new ManagementException(e.fillInStackTrace());
            logger.debug("InterruptedException while creating Monitoring resource with error : {}",
                mgEx.getMessage(), mgEx);
          }

        }

      }
    } catch (InterruptedException e) {
      if (isDebugEnabled) {
        ManagementException mgEx = new ManagementException(e.fillInStackTrace());
        logger.debug("InterruptedException while creating Monitoring resource with error : ",
            mgEx.getMessage(), mgEx);
      }

    } finally {
      if (isDebugEnabled) {
        logger.debug("Management Resource creation completed");
      }
    }

  }



  /**
   * 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
   * 
   * 
   */

  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 (org.apache.geode.cache.TimeoutException e) {
            if (logger.isDebugEnabled()) {
              logger.debug("Error During Internal Region creation {}", e.getMessage(), e);
            }
            throw new ManagementException(e);
          } catch (RegionExistsException e) {
            if (logger.isDebugEnabled()) {
              logger.debug("Error During Internal Region creation {}", e.getMessage(), e);
            }
            throw new ManagementException(e);
          } catch (IOException e) {
            if (logger.isDebugEnabled()) {
              logger.debug("Error During Internal Region creation {}", e.getMessage(), e);
            }

            throw new ManagementException(e);
          } catch (ClassNotFoundException e) {
            if (logger.isDebugEnabled()) {
              logger.debug("Error During Internal Region creation {}", e.getMessage(), e);
            }
            throw new ManagementException(e);
          }

          try {
            if (!running) {
              return null;
            }
            proxyNotificationgRegion =
                cache.createVMRegion(ManagementConstants.NOTIFICATION_REGION + "_" + appender,
                    notifRegionAttrs, internalArgs);
            proxyNotifRegionCreated = true;
          } catch (org.apache.geode.cache.TimeoutException e) {
            if (logger.isDebugEnabled()) {
              logger.debug("Error During Internal Region creation {}", e.getMessage(), e);
            }
            throw new ManagementException(e);
          } catch (RegionExistsException e) {
            if (logger.isDebugEnabled()) {
              logger.debug("Error During Internal Region creation {}", e.getMessage(), e);
            }
            throw new ManagementException(e);
          } catch (IOException e) {
            if (logger.isDebugEnabled()) {
              logger.debug("Error During Internal Region creation {}", e.getMessage(), e);
            }
            throw new ManagementException(e);
          } catch (ClassNotFoundException e) {
            if (logger.isDebugEnabled()) {
              logger.debug("Error During Internal Region creation {}", e.getMessage(), e);
            }
            throw new ManagementException(e);
          } finally {
            if (!proxyNotifRegionCreated && proxyMonitoringRegionCreated) {
              // Destroy the proxy region if proxy notification
              // region is not created
              proxyMonitoringRegion.localDestroyRegion();
            }

          }

          if (logger.isDebugEnabled()) {
            logger.debug("Management Region created with Name : {}",
                proxyMonitoringRegion.getName());
            logger.debug("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.isDebugEnabled()) {
              logger.debug("Error During GII Proxy creation {}", e.getMessage(), 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
   */
  public long getLastUpdateTime(ObjectName objectName) {
    return proxyFactory.getLastUpdateTime(objectName);
  }

  /**
   * Find a particular proxy instance for a {@link javax.management.ObjectName} ,
   * {@link org.apache.geode.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 org.apache.geode.distributed.DistributedMember}
   * 
   * @param member {@link org.apache.geode.distributed.DistributedMember}
   * @return a set of {@link javax.management.ObjectName}
   */
  public Set findAllProxies(DistributedMember member) {
    return proxyFactory.findAllProxies(member);
  }


  public MemberMessenger getMessenger() {
    return messenger;
  }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy