SGF-515 - Configure Geode Off-Heap Memory with annotations.

This commit is contained in:
John Blum
2016-09-09 13:35:19 -07:00
parent b8502ddba7
commit 7c45354f20
3 changed files with 274 additions and 18 deletions

View File

@@ -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<K, V> extends RegionLookupFactoryBean<K,
private boolean destroy = false;
private boolean running;
private Boolean offHeap;
private Boolean persistent;
private CacheListener<K, V>[] cacheListeners;
@@ -110,18 +111,18 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
RegionFactory<K, V> 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<K, V> listener : cacheListeners) {
regionFactory.addCacheListener(listener);
@@ -431,6 +432,7 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
* @see com.gemstone.gemfire.cache.RegionFactory
*/
protected void postProcess(RegionFactory<K, V> regionFactory) {
regionFactory.setOffHeap(Boolean.TRUE.equals(offHeap));
}
/**
@@ -662,6 +664,37 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
this.gatewaySenders = gatewaySenders;
}
/**
* Sets whether to enable this {@link Region} to store it's data in off-heap memory.
*
* @param offHeap Boolean value indicating whether to enable off-heap memory for this Region.
* @see com.gemstone.gemfire.cache.RegionFactory#setOffHeap(boolean)
*/
public void setOffHeap(Boolean offHeap) {
this.offHeap = offHeap;
}
/**
* Returns a {@link Boolean} value indicating whether off-heap memory was enabled for this {@link Region}.
* Off-heap will be enabled if this method returns a non-{@literal null} {@link Boolean} value that evaluates
* to {@literal true}.
*
* @return a {@link Boolean} value indicating whether off-heap is enabled for this {@link Region}.
*/
public Boolean getOffHeap() {
return offHeap;
}
/**
* Returns a boolean value indicating whether off-heap has been enabled for this {@link Region}.
*
* @return a {@literal boolean} value indicating whether off-heap has been enabled for this {@link Region}.
* @see #getOffHeap()
*/
public boolean isOffHeap() {
return Boolean.TRUE.equals(getOffHeap());
}
public void setPersistent(Boolean persistent) {
this.persistent = persistent;
}
@@ -778,5 +811,4 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
stop();
callback.run();
}
}

View File

@@ -0,0 +1,67 @@
/*
* 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.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
/**
* The EnableOffHeap annotation marks a Spring {@link org.springframework.context.annotation.Configuration @Configuration}
* annotated class to configure and enable Apache Geode Off-Heap Memory support and data storage
* in Geode's cache {@link com.gemstone.gemfire.cache.Region Regions}.
*
* @author John Blum
* @see org.springframework.data.gemfire.config.annotation.OffHeapConfiguration
* @since 1.9.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(OffHeapConfiguration.class)
@SuppressWarnings("unused")
public @interface EnableOffHeap {
/**
* Specifies the size of off-heap memory in megabytes (m) or gigabytes (g). For example:
*
* <pre>
* <code>
* off-heap-memory-size=4096m
* off-heap-memory-size=120g
* </code>
* </pre>
*
* 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 {};
}

View File

@@ -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<String, Object> 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<String, Object> 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<String> REGION_FACTORY_BEAN_TYPES = new HashSet<String>(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<String> regionNames;
protected OffHeapBeanFactoryPostProcessor(String[] regionNames) {
this(CollectionUtils.asSet(ArrayUtils.nullSafeArray(regionNames, String.class)));
}
protected OffHeapBeanFactoryPostProcessor(Set<String> 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<String> getBeanNames(String beanName, BeanDefinition bean, BeanFactory beanFactory) {
Collection<String> beanNames = new HashSet<String>();
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;
}
}
}