From 7c45354f20ade2aee06e40ace81ef8bc8442b185 Mon Sep 17 00:00:00 2001 From: John Blum Date: Fri, 9 Sep 2016 13:35:19 -0700 Subject: [PATCH] SGF-515 - Configure Geode Off-Heap Memory with annotations. --- .../data/gemfire/RegionFactoryBean.java | 68 ++++++-- .../config/annotation/EnableOffHeap.java | 67 ++++++++ .../annotation/OffHeapConfiguration.java | 157 ++++++++++++++++++ 3 files changed, 274 insertions(+), 18 deletions(-) create mode 100644 src/main/java/org/springframework/data/gemfire/config/annotation/EnableOffHeap.java create mode 100644 src/main/java/org/springframework/data/gemfire/config/annotation/OffHeapConfiguration.java diff --git a/src/main/java/org/springframework/data/gemfire/RegionFactoryBean.java b/src/main/java/org/springframework/data/gemfire/RegionFactoryBean.java index 0b6cb503..c982e342 100644 --- a/src/main/java/org/springframework/data/gemfire/RegionFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/RegionFactoryBean.java @@ -18,17 +18,6 @@ package org.springframework.data.gemfire; import java.lang.reflect.Field; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.context.SmartLifecycle; -import org.springframework.core.io.Resource; -import org.springframework.data.gemfire.client.ClientRegionFactoryBean; -import org.springframework.data.gemfire.support.RegionShortcutWrapper; -import org.springframework.util.Assert; -import org.springframework.util.ObjectUtils; -import org.springframework.util.ReflectionUtils; - import com.gemstone.gemfire.cache.AttributesFactory; import com.gemstone.gemfire.cache.Cache; import com.gemstone.gemfire.cache.CacheListener; @@ -48,6 +37,17 @@ import com.gemstone.gemfire.cache.asyncqueue.AsyncEventQueue; import com.gemstone.gemfire.cache.wan.GatewaySender; import com.gemstone.gemfire.internal.cache.UserSpecifiedRegionAttributes; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.context.SmartLifecycle; +import org.springframework.core.io.Resource; +import org.springframework.data.gemfire.client.ClientRegionFactoryBean; +import org.springframework.data.gemfire.support.RegionShortcutWrapper; +import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; +import org.springframework.util.ReflectionUtils; + /** * Base class for FactoryBeans used to create GemFire {@link Region}s. Will try * to first locate the region (by name) and, in case none if found, proceed to @@ -71,6 +71,7 @@ public abstract class RegionFactoryBean extends RegionLookupFactoryBean[] cacheListeners; @@ -110,18 +111,18 @@ public abstract class RegionFactoryBean extends RegionLookupFactoryBean regionFactory = createRegionFactory(cache); - if (!ObjectUtils.isEmpty(gatewaySenders)) { - for (Object gatewaySender : gatewaySenders) { - regionFactory.addGatewaySenderId(((GatewaySender) gatewaySender).getId()); - } - } - if (!ObjectUtils.isEmpty(asyncEventQueues)) { for (Object asyncEventQueue : asyncEventQueues) { regionFactory.addAsyncEventQueueId(((AsyncEventQueue) asyncEventQueue).getId()); } } + if (!ObjectUtils.isEmpty(gatewaySenders)) { + for (Object gatewaySender : gatewaySenders) { + regionFactory.addGatewaySenderId(((GatewaySender) gatewaySender).getId()); + } + } + if (!ObjectUtils.isEmpty(cacheListeners)) { for (CacheListener listener : cacheListeners) { regionFactory.addCacheListener(listener); @@ -431,6 +432,7 @@ public abstract class RegionFactoryBean extends RegionLookupFactoryBean regionFactory) { + regionFactory.setOffHeap(Boolean.TRUE.equals(offHeap)); } /** @@ -662,6 +664,37 @@ public abstract class RegionFactoryBean extends RegionLookupFactoryBean extends RegionLookupFactoryBean + * + * off-heap-memory-size=4096m + * off-heap-memory-size=120g + * + * + * + * Defaults to unset. + */ + String memorySize(); + + /** + * Idenfitied the Regions by name in which the off-heap memory setting will be applied. + * + * Defaults to all Regions. + */ + String[] regionNames() default {}; + +} diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/OffHeapConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/OffHeapConfiguration.java new file mode 100644 index 00000000..5971b21c --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/OffHeapConfiguration.java @@ -0,0 +1,157 @@ +/* + * Copyright 2012 the original author or authors. + * + * 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. + * + */ + +package org.springframework.data.gemfire.config.annotation; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import com.gemstone.gemfire.cache.Region; + +import org.springframework.beans.BeansException; +import org.springframework.beans.PropertyValue; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.data.gemfire.GenericRegionFactoryBean; +import org.springframework.data.gemfire.LocalRegionFactoryBean; +import org.springframework.data.gemfire.PartitionedRegionFactoryBean; +import org.springframework.data.gemfire.ReplicatedRegionFactoryBean; +import org.springframework.data.gemfire.client.ClientRegionFactoryBean; +import org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport; +import org.springframework.data.gemfire.util.ArrayUtils; +import org.springframework.data.gemfire.util.CollectionUtils; +import org.springframework.data.gemfire.util.PropertiesBuilder; + +/** + * The OffHeapConfiguration class is a Spring {@link org.springframework.context.annotation.ImportBeanDefinitionRegistrar} + * capable of enabling GemFire cache {@link Region Regions} to use Off-Heap memory for data storage. + * + * @author John Blum + * @see org.springframework.data.gemfire.config.annotation.EnableOffHeap + * @see org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport + * @since 1.9.0 + */ +public class OffHeapConfiguration extends EmbeddedServiceConfigurationSupport { + + /* (non-Javadoc) */ + @Override + protected Class getAnnotationType() { + return EnableOffHeap.class; + } + + /* (non-Javadoc) */ + @Override + protected void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, + Map annotationAttributes, BeanDefinitionRegistry registry) { + + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition( + OffHeapBeanFactoryPostProcessor.class); + + builder.addConstructorArgValue(annotationAttributes.get("regionNames")); + + registry.registerBeanDefinition(generateBeanName(OffHeapBeanFactoryPostProcessor.class), + builder.getBeanDefinition()); + } + + /* (non-Javadoc) */ + @Override + protected Properties toGemFireProperties(Map annotationAttributes) { + PropertiesBuilder gemfireProperties = PropertiesBuilder.create(); + + gemfireProperties.setProperty("off-heap-memory-size", annotationAttributes.get("memorySize")); + + return gemfireProperties.build(); + } + + @SuppressWarnings("unused") + protected static class OffHeapBeanFactoryPostProcessor implements BeanFactoryPostProcessor { + + protected static final Set REGION_FACTORY_BEAN_TYPES = new HashSet(5); + + static { + REGION_FACTORY_BEAN_TYPES.add(ClientRegionFactoryBean.class.getName()); + REGION_FACTORY_BEAN_TYPES.add(GenericRegionFactoryBean.class.getName()); + REGION_FACTORY_BEAN_TYPES.add(LocalRegionFactoryBean.class.getName()); + REGION_FACTORY_BEAN_TYPES.add(PartitionedRegionFactoryBean.class.getName()); + REGION_FACTORY_BEAN_TYPES.add(ReplicatedRegionFactoryBean.class.getName()); + } + + private final Set regionNames; + + protected OffHeapBeanFactoryPostProcessor(String[] regionNames) { + this(CollectionUtils.asSet(ArrayUtils.nullSafeArray(regionNames, String.class))); + } + + protected OffHeapBeanFactoryPostProcessor(Set regionNames) { + this.regionNames = CollectionUtils.nullSafeSet(regionNames); + } + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + for (String beanName : beanFactory.getBeanDefinitionNames()) { + BeanDefinition bean = beanFactory.getBeanDefinition(beanName); + + if (isTargetedRegionBean(beanName, bean, beanFactory)) { + bean.getPropertyValues().addPropertyValue("offHeap", true); + } + } + } + + boolean isTargetedRegionBean(String beanName, BeanDefinition bean, + ConfigurableListableBeanFactory beanFactory) { + + return (isRegionBean(bean) && isNamedRegion(beanName, bean, beanFactory)); + } + + boolean isRegionBean(BeanDefinition bean) { + return (bean != null && REGION_FACTORY_BEAN_TYPES.contains(bean.getBeanClassName())); + } + + boolean isNamedRegion(String beanName, BeanDefinition bean, ConfigurableListableBeanFactory beanFactory) { + return (CollectionUtils.isEmpty(regionNames) || CollectionUtils.containsAny(regionNames, + getBeanNames(beanName, bean, beanFactory))); + } + + Collection getBeanNames(String beanName, BeanDefinition bean, BeanFactory beanFactory) { + Collection beanNames = new HashSet(); + + beanNames.add(beanName); + Collections.addAll(beanNames, beanFactory.getAliases(beanName)); + + PropertyValue regionName = bean.getPropertyValues().getPropertyValue("regionName"); + + if (regionName != null) { + Object regionNameValue = regionName.getValue(); + + if (regionNameValue != null) { + beanNames.add(regionNameValue.toString()); + } + } + + return beanNames; + } + } +}