/* * 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.modules.session.bootstrap; import org.apache.geode.cache.GemFireCache; import org.apache.geode.cache.control.ResourceManager; import org.apache.geode.distributed.internal.AbstractDistributionConfig; import org.apache.geode.distributed.internal.DistributionConfig; import org.apache.geode.internal.cache.LocalRegion; import org.apache.geode.modules.util.Banner; import org.apache.geode.modules.util.RegionHelper; import org.apache.geode.modules.util.ResourceManagerValidator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; import static org.apache.geode.distributed.ConfigurationProperties.*; public abstract class AbstractCache { protected GemFireCache cache; private static final DateFormat FORMAT = new SimpleDateFormat("yyyy-MM-dd"); protected static final String DEFAULT_LOG_FILE_NAME = RegionHelper.NAME + "." + FORMAT.format(new Date()) + ".log"; protected static final String DEFAULT_STATISTIC_ARCHIVE_FILE_NAME = RegionHelper.NAME + ".gfs"; protected static final float DEFAULT_EVICTION_HEAP_PERCENTAGE = LocalRegion.DEFAULT_HEAPLRU_EVICTION_HEAP_PERCENTAGE; protected static final float DEFAULT_CRITICAL_HEAP_PERCENTAGE = ResourceManager.DEFAULT_CRITICAL_PERCENTAGE; protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractCache.class); protected float evictionHeapPercentage = DEFAULT_EVICTION_HEAP_PERCENTAGE; protected float criticalHeapPercentage = DEFAULT_CRITICAL_HEAP_PERCENTAGE; protected boolean rebalance = false; protected final Map<String, String> gemfireProperties; private final AtomicBoolean started = new AtomicBoolean(false); /** * Instance reference which is set in static initialization blocks of any subclasses. */ protected static AbstractCache instance = null; public AbstractCache() { this.gemfireProperties = new ConcurrentHashMap<String, String>(); } public void lifecycleEvent(LifecycleTypeAdapter eventType) { if (getLogger().isDebugEnabled()) { getLogger().debug("Received " + eventType + " event"); } if (eventType.equals(LifecycleTypeAdapter.START) && started.compareAndSet(false, true)) { // Create or retrieve the cache getLogger().info("Initializing " + Banner.getString()); createOrRetrieveCache(); // Initialize the resource manager initializeResourceManager(); } else if (eventType.equals(LifecycleTypeAdapter.AFTER_START)) { if (getRebalance()) { rebalanceCache(); } } else if (eventType.equals(LifecycleTypeAdapter.STOP)) { started.set(false); } } public boolean isStarted() { return started.get(); } public void close() { getCache().close(); while (!getCache().isClosed()) { } started.set(false); } public GemFireCache getCache() { return this.cache; } public String getLogFileName() { String logFileName = getGemFireProperties().get(LOG_FILE); if (logFileName == null) { logFileName = DEFAULT_LOG_FILE_NAME; } return logFileName; } public String getStatisticArchiveFileName() { String statisticsArchiveFileName = getGemFireProperties().get(STATISTIC_ARCHIVE_FILE); if (statisticsArchiveFileName == null) { statisticsArchiveFileName = DEFAULT_STATISTIC_ARCHIVE_FILE_NAME; } return statisticsArchiveFileName; } public String getCacheXmlFileName() { String cacheXmlFileName = getGemFireProperties().get(CACHE_XML_FILE); if (cacheXmlFileName == null) { cacheXmlFileName = getDefaultCacheXmlFileName(); } return cacheXmlFileName; } protected File getCacheXmlFile() { String cacheXmlFileName = getCacheXmlFileName(); File cacheXmlFile = new File(cacheXmlFileName); // If the cache xml file is not absolute, point it at the conf directory. if (!cacheXmlFile.isAbsolute()) { if (System.getProperty("catalina.base") != null) { cacheXmlFile = new File(System.getProperty("catalina.base") + "/conf/", cacheXmlFileName); } } return cacheXmlFile; } public float getEvictionHeapPercentage() { return this.evictionHeapPercentage; } public void setEvictionHeapPercentage(String evictionHeapPercentage) { this.evictionHeapPercentage = Float.valueOf(evictionHeapPercentage); } public float getCriticalHeapPercentage() { return this.criticalHeapPercentage; } public void setCriticalHeapPercentage(String criticalHeapPercentage) { this.criticalHeapPercentage = Float.valueOf(criticalHeapPercentage); } public void setRebalance(boolean rebalance) { this.rebalance = rebalance; } public boolean getRebalance() { return this.rebalance; } public Map<String, String> getGemFireProperties() { return this.gemfireProperties; } public void setProperty(String name, String value) { // TODO Look at fake attributes if (name.equals("className")) { return; } // Determine the validity of the input property boolean validProperty = false; for (String gemfireProperty : AbstractDistributionConfig._getAttNames()) { if (name.equals(gemfireProperty)) { validProperty = true; break; } } // If it is a valid GemFire property, add it to the the GemFire properties. // Otherwise, log a warning. if (validProperty) { this.gemfireProperties.put(name, value); } else { getLogger().warn("The input property named " + name + " is not a valid GemFire property. It is being ignored."); } } public Logger getLogger() { return LOGGER; } protected Properties createDistributedSystemProperties() { Properties properties = new Properties(); // Add any additional gemfire properties for (Map.Entry<String, String> entry : this.gemfireProperties.entrySet()) { properties.put(entry.getKey(), entry.getValue()); } // Replace the cache xml file in the properties File cacheXmlFile = getCacheXmlFile(); String absoluteCacheXmlFileName = cacheXmlFile.getAbsolutePath(); // If the file doesn't exist and the name is the default, set cache-xml-file // to the GemFire default. This is for the case where only the jars have been // installed and no default cache.xml exists in the conf directory. if (getCacheXmlFileName().equals(getDefaultCacheXmlFileName()) && !cacheXmlFile.exists()) { absoluteCacheXmlFileName = DistributionConfig.DEFAULT_CACHE_XML_FILE.getName(); } properties.put(CACHE_XML_FILE, absoluteCacheXmlFileName); // Replace the log file in the properties properties.put(LOG_FILE, getLogFile().getAbsolutePath()); // Replace the statistics archive file in the properties File statisticArchiveFile = getStatisticArchiveFile(); if (statisticArchiveFile == null) { // Remove the statistics archive file name since statistic sampling is disabled properties.remove(STATISTIC_ARCHIVE_FILE); properties.remove(STATISTIC_SAMPLING_ENABLED); } else { properties.put(STATISTIC_ARCHIVE_FILE, statisticArchiveFile.getAbsolutePath()); } getLogger().info("Creating distributed system from: " + properties); return properties; } protected void closeCache() { if (getLogger().isDebugEnabled()) { getLogger().debug("Closing " + this.cache); } if (getCache() != null) { getCache().close(); } getLogger().info("Closed " + this.cache); } protected File getLogFile() { String logFileName = getLogFileName(); File logFile = new File(logFileName); // If the log file is not absolute, point it at the logs directory. if (!logFile.isAbsolute()) { if (System.getProperty("catalina.base") != null) { logFile = new File(System.getProperty("catalina.base") + "/logs/", logFileName); } else if (System.getProperty("weblogic.Name") != null) { String weblogicName = System.getProperty("weblogic.Name"); String separator = System.getProperty("file.separator"); logFile = new File( "servers" + separator + weblogicName + separator + "logs" + separator + logFileName); } else { logFile = new File(System.getProperty(DistributionConfig.GEMFIRE_PREFIX + "logdir"), logFileName); } } return logFile; } protected File getStatisticArchiveFile() { File statisticsArchiveFile = null; String statisticSamplingEnabled = getGemFireProperties().get(STATISTIC_SAMPLING_ENABLED); if (statisticSamplingEnabled != null && statisticSamplingEnabled.equals("true")) { String statisticsArchiveFileName = getStatisticArchiveFileName(); statisticsArchiveFile = new File(statisticsArchiveFileName); // If the statistics archive file is not absolute, point it at the logs directory. if (!statisticsArchiveFile.isAbsolute()) { if (System.getProperty("catalina.base") != null) { statisticsArchiveFile = new File(System.getProperty("catalina.base") + "/logs/", statisticsArchiveFileName); } else if (System.getProperty("weblogic.Name") != null) { String weblogicName = System.getProperty("weblogic.Name"); String separator = System.getProperty("file.separator"); statisticsArchiveFile = new File("servers" + separator + weblogicName + separator + "logs" + separator + statisticsArchiveFileName); } else { statisticsArchiveFile = new File(System.getProperty(DistributionConfig.GEMFIRE_PREFIX + "statisticsdir"), statisticsArchiveFileName); } } } return statisticsArchiveFile; } protected void initializeResourceManager() { // Get current eviction and critical heap percentages ResourceManager rm = getCache().getResourceManager(); float currentEvictionHeapPercentage = rm.getEvictionHeapPercentage(); float currentCriticalHeapPercentage = rm.getCriticalHeapPercentage(); // Set new eviction and critical heap percentages if necessary if (getEvictionHeapPercentage() != currentEvictionHeapPercentage || getCriticalHeapPercentage() != currentCriticalHeapPercentage) { if (getLogger().isDebugEnabled()) { StringBuilder builder = new StringBuilder(); builder.append("Previous eviction heap percentage=").append(currentEvictionHeapPercentage) .append("; critical heap percentage=").append(currentCriticalHeapPercentage); getLogger().debug(builder.toString()); builder.setLength(0); builder.append("Requested eviction heap percentage=").append(getEvictionHeapPercentage()) .append("; critical heap percentage=").append(getCriticalHeapPercentage()); getLogger().debug(builder.toString()); } if (currentCriticalHeapPercentage == 0.0f) { // If the current critical heap percentage is 0 (disabled), set eviction // heap percentage first, then set the critical heap percentage. At this // point, the eviction heap percentage can be set to anything. try { rm.setEvictionHeapPercentage(getEvictionHeapPercentage()); rm.setCriticalHeapPercentage(getCriticalHeapPercentage()); } catch (IllegalArgumentException e) { handleResourceManagerException(e, currentEvictionHeapPercentage, currentCriticalHeapPercentage); rm.setEvictionHeapPercentage(currentEvictionHeapPercentage); rm.setCriticalHeapPercentage(currentCriticalHeapPercentage); } } else if (getCriticalHeapPercentage() >= currentCriticalHeapPercentage) { // If the requested critical heap percentage is >= the current critical // heap percentage, then set the critical heap percentage first since it // can safely be slid up. Then, set the eviction heap percentage. try { rm.setCriticalHeapPercentage(getCriticalHeapPercentage()); rm.setEvictionHeapPercentage(getEvictionHeapPercentage()); } catch (IllegalArgumentException e) { handleResourceManagerException(e, currentEvictionHeapPercentage, currentCriticalHeapPercentage); rm.setCriticalHeapPercentage(currentCriticalHeapPercentage); rm.setEvictionHeapPercentage(currentEvictionHeapPercentage); } } else { // If the requested critical heap percentage is < the current critical // heap percentage, then set the eviction heap percentage first since it // can safely be slid down. Then, set the critical heap percentage. try { rm.setEvictionHeapPercentage(getEvictionHeapPercentage()); rm.setCriticalHeapPercentage(getCriticalHeapPercentage()); } catch (IllegalArgumentException e) { handleResourceManagerException(e, currentEvictionHeapPercentage, currentCriticalHeapPercentage); rm.setEvictionHeapPercentage(currentEvictionHeapPercentage); rm.setCriticalHeapPercentage(currentCriticalHeapPercentage); } } if (getLogger().isDebugEnabled()) { StringBuilder builder = new StringBuilder(); builder.append("Actual eviction heap percentage=").append(rm.getEvictionHeapPercentage()) .append("; critical heap percentage=").append(rm.getCriticalHeapPercentage()); getLogger().debug(builder.toString()); } } // Validate java startup parameters (done after setting the eviction and // critical heap percentages so that the CMSInitiatingOccupancyFraction can // be compared against them. ResourceManagerValidator.validateJavaStartupParameters(getCache()); } private void handleResourceManagerException(IllegalArgumentException e, float currentEvictionHeapPercentage, float currentCriticalHeapPercentage) { StringBuilder builder = new StringBuilder(); builder.append("Caught exception attempting to set eviction heap percentage=") .append(getEvictionHeapPercentage()).append(" and critical heap percentage=") .append(getCriticalHeapPercentage()) .append( ". The percentages will be set back to their previous values (eviction heap percentage=") .append(currentEvictionHeapPercentage).append(" and critical heap percentage=") .append(currentCriticalHeapPercentage).append(")."); getLogger().warn(builder.toString(), e); } @Override public String toString() { return new StringBuilder().append(getClass().getSimpleName()).append("[").append("cache=") .append(this.cache).append("]").toString(); } protected abstract void createOrRetrieveCache(); protected abstract void rebalanceCache(); protected abstract String getDefaultCacheXmlFileName(); }