SGF-549 - Configure DiskStores with annotations.

(cherry picked from commit c99d6ffbf8)
Signed-off-by: John Blum <jblum@pivotal.io>
This commit is contained in:
John Blum
2016-12-11 23:03:04 -08:00
parent ccca168c6e
commit ed7a1ade7b
5 changed files with 765 additions and 0 deletions

View File

@@ -0,0 +1,139 @@
/*
* Copyright 2016 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 org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.gemfire.DiskStoreFactoryBean;
import org.springframework.data.gemfire.config.xml.GemfireConstants;
import org.springframework.data.gemfire.util.ArrayUtils;
/**
* The {@link DiskStoreConfiguration} class is a Spring {@link ImportBeanDefinitionRegistrar} used to register
* a GemFire/Geode {@link org.apache.geode.cache.DiskStore} bean definition.
*
* @author John Blum
* @see org.springframework.beans.factory.config.BeanDefinition
* @see org.springframework.beans.factory.support.BeanDefinitionBuilder
* @see org.springframework.beans.factory.support.BeanDefinitionRegistry
* @see org.springframework.context.annotation.ImportBeanDefinitionRegistrar
* @see org.springframework.data.gemfire.DiskStoreFactoryBean
* @see org.springframework.data.gemfire.config.annotation.EnableDiskStore
* @see org.springframework.data.gemfire.config.annotation.EnableDiskStores
* @see org.apache.geode.cache.DiskStore
* @since 1.9.0
*/
public class DiskStoreConfiguration implements ImportBeanDefinitionRegistrar {
/**
* @inheritDoc
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
if (importingClassMetadata.hasAnnotation(EnableDiskStore.class.getName())) {
AnnotationAttributes enableDiskStoreAttributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableDiskStore.class.getName()));
registerDiskStoreBeanDefinition(importingClassMetadata, enableDiskStoreAttributes, registry);
}
}
/* (non-Javadoc) */
protected void registerDiskStoreBeanDefinition(AnnotationMetadata importingClassMetadata,
AnnotationAttributes enableDiskStoreAttributes, BeanDefinitionRegistry registry) {
BeanDefinitionBuilder diskStoreFactoryBeanBuilder =
BeanDefinitionBuilder.genericBeanDefinition(DiskStoreFactoryBean.class);
String diskStoreName = enableDiskStoreAttributes.getString("name");
diskStoreFactoryBeanBuilder.addPropertyValue("beanName", diskStoreName);
diskStoreFactoryBeanBuilder.addPropertyReference("cache", GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME);
setPropertyValueIfNotDefault(diskStoreFactoryBeanBuilder, "allowForceCompaction",
enableDiskStoreAttributes.getBoolean("allowForceCompaction"), false);
setPropertyValueIfNotDefault(diskStoreFactoryBeanBuilder, "autoCompact",
enableDiskStoreAttributes.getBoolean("autoCompact"), false);
setPropertyValueIfNotDefault(diskStoreFactoryBeanBuilder, "compactionThreshold",
enableDiskStoreAttributes.<Integer>getNumber("compactionThreshold"), 50);
setPropertyValueIfNotDefault(diskStoreFactoryBeanBuilder, "diskUsageCriticalPercentage",
enableDiskStoreAttributes.<Float>getNumber("diskUsageCriticalPercentage"), 99.0f);
setPropertyValueIfNotDefault(diskStoreFactoryBeanBuilder, "diskUsageWarningPercentage",
enableDiskStoreAttributes.<Float>getNumber("diskUsageWarningPercentage"), 90.0f);
setPropertyValueIfNotDefault(diskStoreFactoryBeanBuilder, "maxOplogSize",
enableDiskStoreAttributes.<Long>getNumber("maxOplogSize"), 1024L);
setPropertyValueIfNotDefault(diskStoreFactoryBeanBuilder, "queueSize",
enableDiskStoreAttributes.<Integer>getNumber("queueSize"), 0);
setPropertyValueIfNotDefault(diskStoreFactoryBeanBuilder, "timeInterval",
enableDiskStoreAttributes.<Long>getNumber("timeInterval"), 1000L);
setPropertyValueIfNotDefault(diskStoreFactoryBeanBuilder, "writeBufferSize",
enableDiskStoreAttributes.<Integer>getNumber("writeBufferSize"), 32768);
parseDiskStoreDiskDirectories(importingClassMetadata, enableDiskStoreAttributes, diskStoreFactoryBeanBuilder);
registry.registerBeanDefinition(diskStoreName, diskStoreFactoryBeanBuilder.getBeanDefinition());
}
/* (non-Javadoc) */
protected BeanDefinitionBuilder parseDiskStoreDiskDirectories(AnnotationMetadata importingClassMetadata,
AnnotationAttributes enableDiskStoreAttributes, BeanDefinitionBuilder diskStoreBeanFactoryBuilder) {
AnnotationAttributes[] diskDirectories = ArrayUtils.nullSafeArray(
enableDiskStoreAttributes.getAnnotationArray("diskDirectories"), AnnotationAttributes.class);
ManagedList<BeanDefinition> diskDirectoryBeans = new ManagedList<BeanDefinition>(diskDirectories.length);
for (AnnotationAttributes diskDirectoryAttributes : diskDirectories) {
BeanDefinitionBuilder diskDirectoryBuilder =
BeanDefinitionBuilder.genericBeanDefinition(DiskStoreFactoryBean.DiskDir.class);
diskDirectoryBuilder.addConstructorArgValue(diskDirectoryAttributes.getString("location"));
diskDirectoryBuilder.addConstructorArgValue(diskDirectoryAttributes.<Integer>getNumber("maxSize"));
diskDirectoryBeans.add(diskDirectoryBuilder.getBeanDefinition());
}
if (!diskDirectoryBeans.isEmpty()) {
diskStoreBeanFactoryBuilder.addPropertyValue("diskDirs", diskDirectoryBeans);
}
return diskStoreBeanFactoryBuilder;
}
/* (non-Javadoc) */
private <T> BeanDefinitionBuilder setPropertyValueIfNotDefault(BeanDefinitionBuilder beanDefinitionBuilder,
String propertyName, T value, T defaultValue) {
return (value != null && !value.equals(defaultValue) ?
beanDefinitionBuilder.addPropertyValue(propertyName, value) : beanDefinitionBuilder);
}
}

View File

@@ -0,0 +1,89 @@
/*
* Copyright 2016 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 org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.gemfire.util.ArrayUtils;
/**
* The {@link DiskStoresConfiguration} class is a Spring {@link org.springframework.context.annotation.ImportBeanDefinitionRegistrar}
* used to register multiple GemFire/Geode {@link org.apache.geode.cache.DiskStore} bean definitions.
*
* @author John Blum
* @see org.springframework.beans.factory.support.BeanDefinitionRegistry
* @see org.springframework.data.gemfire.config.annotation.DiskStoreConfiguration
* @see org.springframework.data.gemfire.config.annotation.EnableDiskStore
* @see org.springframework.data.gemfire.config.annotation.EnableDiskStores
* @see org.apache.geode.cache.DiskStore
* @since 1.9.0
*/
public class DiskStoresConfiguration extends DiskStoreConfiguration {
/**
* @inheritDoc
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
if (importingClassMetadata.hasAnnotation(EnableDiskStores.class.getName())) {
AnnotationAttributes enableDiskStoresAttributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableDiskStores.class.getName()));
AnnotationAttributes[] diskStores = ArrayUtils.nullSafeArray(
enableDiskStoresAttributes.getAnnotationArray("diskStores"), AnnotationAttributes.class);
for (AnnotationAttributes diskStoreAttributes : diskStores) {
registerDiskStoreBeanDefinition(importingClassMetadata,
mergeDiskStoreAttributes(enableDiskStoresAttributes, diskStoreAttributes), registry);
}
}
}
/* (non-Javadoc) */
protected AnnotationAttributes mergeDiskStoreAttributes(AnnotationAttributes enableDiskStoresAttributes,
AnnotationAttributes diskStoreAttributes) {
setAttributeIfNotDefault(diskStoreAttributes, "autoCompact",
enableDiskStoresAttributes.getBoolean("autoCompact"), false);
setAttributeIfNotDefault(diskStoreAttributes, "compactionThreshold",
enableDiskStoresAttributes.<Integer>getNumber("compactionThreshold"), 50);
setAttributeIfNotDefault(diskStoreAttributes, "maxOplogSize",
enableDiskStoresAttributes.<Integer>getNumber("maxOplogSize"), 1024);
return diskStoreAttributes;
}
/* (non-Javadoc) */
private <T> void setAttributeIfNotDefault(AnnotationAttributes diskStoreAttributes,
String attributeName, T newValue, T defaultValue) {
if (!diskStoreAttributes.containsKey(attributeName)
|| toString(diskStoreAttributes.get(attributeName)).equals(toString(defaultValue))) {
diskStoreAttributes.put(attributeName, newValue);
}
}
/* (non-Javadoc) */
private String toString(Object value) {
return String.valueOf(value);
}
}

View File

@@ -0,0 +1,168 @@
/*
* Copyright 2016 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;
import org.springframework.core.annotation.AliasFor;
/**
* The {@link EnableDiskStore} annotation marks a Spring {@link org.springframework.context.annotation.Configuration @Configuration}
* annotated application class to configure a single GemFire/Geode {@link org.apache.geode.cache.DiskStore} bean
* in the Spring context in which to persist or overflow data from 1 or more GemFire/Geode
* {@link org.apache.geode.cache.Region Regions}
*
* @author John Blum
* @see org.springframework.context.annotation.Import
* @see org.springframework.core.annotation.AliasFor
* @see org.springframework.data.gemfire.config.annotation.DiskStoreConfiguration
* @see org.springframework.data.gemfire.config.annotation.EnableDiskStores
* @see org.apache.geode.cache.DiskStore
* @see org.apache.geode.cache.Region
* @since 1.9.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(DiskStoreConfiguration.class)
@SuppressWarnings({ "unused" })
public @interface EnableDiskStore {
/**
* Name of the {@link org.apache.geode.cache.DiskStore}.
*/
@AliasFor(attribute = "name")
String value() default "";
/**
* Name of the {@link org.apache.geode.cache.DiskStore}.
*/
@AliasFor(attribute = "value")
String name() default "";
/**
* Set to true to allow disk compaction to be forced on this disk store.
*
* Default is {@literal false}.
*/
boolean allowForceCompaction() default false;
/**
* Set to true to automatically compact the disk files.
*
* Default is {@literal false}.
*/
boolean autoCompact() default false;
/**
* The threshold at which an oplog will become compactable. Until it reaches this threshold the oplog
* will not be compacted.
*
* The threshold is a percentage in the range 0 to 100.
*
* Defaults to {@literal 50} percent.
*/
int compactionThreshold() default 50;
/**
* File system directory location(s) in which the {@link org.apache.geode.cache.DiskStore} files are stored.
*
* Defaults to current working directory with 2 petabytes of storage capacity maximum size.
*/
DiskDirectory[] diskDirectories() default {};
/**
* Disk usage above this threshold generates an error message and shuts down the member's cache.
*
* For example, if the threshold is set to 99%, then falling under 10 GB of free disk space on a 1 TB drive
* generates the error and shuts down the cache.
*
* Set to "0" (zero) to disable.
*
* Defaults to {@literal 99} percent.
*/
float diskUsageCriticalPercentage() default 99.0f;
/**
* Disk usage above this threshold generates a warning message.
*
* For example, if the threshold is set to 90%, then on a 1 TB drive falling under 100 GB of free disk space
* generates the warning.
*
* Set to "0" (zero) to disable.
*
* Defaults to {@literal 90} percent.
*/
float diskUsageWarningPercentage() default 90.0f;
/**
* The maximum size, in megabytes, of an oplog (operation log) file.
*
* Defaults to {@literal 1024} MB.
*/
long maxOplogSize() default 1024L;
/**
* Maximum number of operations that can be asynchronously queued to be written to disk.
*
* Defaults to {@literal 0} (unlimited).
*/
int queueSize() default 0;
/**
* The number of milliseconds that can elapse before unwritten data is written to disk.
*
* Defaults to {@literal 1000} ms.
*/
long timeInterval() default 1000L;
/**
* The size of the write buffer that this disk store uses when writing data to disk.
*
* Larger values may increase performance but use more memory. The disk store allocates
* one direct memory buffer of this size.
*
* Defaults to {@literal 32768} bytes.
*/
int writeBufferSize() default 32768;
@interface DiskDirectory {
/**
* File system directory location of the {@link org.apache.geode.cache.DiskStore} files.
*
* Defaults to current working directory.
*/
String location() default ".";
/**
* Maximum amount of space to use for the disk store, in megabytes.
*
* Defaults to {@literal 2} petabytes.
*/
int maxSize() default Integer.MAX_VALUE;
}
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright 2016 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 {@link EnableDiskStores} annotation marks a Spring {@link org.springframework.context.annotation.Configuration @Configuration}
* annotated application class to configure 1 or more GemFire/Geode {@link org.apache.geode.cache.DiskStore} beans
* in the Spring context in which to persist or overflow data from 1 or more GemFire/Geode
* {@link org.apache.geode.cache.Region Regions}
*
* @author John Blum
* @see org.springframework.context.annotation.Import
* @see org.springframework.data.gemfire.config.annotation.DiskStoresConfiguration
* @see org.springframework.data.gemfire.config.annotation.EnableDiskStore
* @see org.apache.geode.cache.DiskStore
* @see org.apache.geode.cache.Region
* @since 1.9.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(DiskStoresConfiguration.class)
@SuppressWarnings({ "unused" })
public @interface EnableDiskStores {
/**
* Set to true to automatically compact the disk files.
*
* Default is {@literal false}.
*/
boolean autoCompact() default false;
/**
* The threshold at which an oplog will become compactable. Until it reaches this threshold the oplog
* will not be compacted.
*
* The threshold is a percentage in the range 0 to 100.
*
* Defaults to {@literal 50} percent.
*/
int compactionThreshold() default 50;
/**
* The maximum size, in megabytes, of an oplog (operation log) file.
*
* Defaults to {@literal 1024} MB.
*/
long maxOplogSize() default 1024L;
/**
* Defines 1 or more GemFire/Geode {@link org.apache.geode.cache.DiskStore DiskStores}.
*/
EnableDiskStore[] diskStores();
}