SGF-549 - Configure DiskStores with annotations.
(cherry picked from commit c99d6ffbf8)
Signed-off-by: John Blum <jblum@pivotal.io>
This commit is contained in:
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,289 @@
|
|||||||
|
/*
|
||||||
|
* 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 static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Matchers.anyBoolean;
|
||||||
|
import static org.mockito.Matchers.anyFloat;
|
||||||
|
import static org.mockito.Matchers.anyInt;
|
||||||
|
import static org.mockito.Matchers.anyLong;
|
||||||
|
import static org.mockito.Matchers.anyString;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
import org.apache.geode.cache.Cache;
|
||||||
|
import org.apache.geode.cache.DiskStore;
|
||||||
|
import org.apache.geode.cache.DiskStoreFactory;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
|
import org.mockito.stubbing.Answer;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for the {@link EnableDiskStore} and {@link EnableDiskStores} annotations as well as
|
||||||
|
* the {@link DiskStoreConfiguration} and {@link DiskStoresConfiguration} classes.
|
||||||
|
*
|
||||||
|
* @author John Blum
|
||||||
|
* @see org.junit.Test
|
||||||
|
* @see org.mockito.Mockito
|
||||||
|
* @since 1.9.0
|
||||||
|
*/
|
||||||
|
public class EnableDiskStoresConfigurationUnitTests {
|
||||||
|
|
||||||
|
private static final AtomicInteger MOCK_ID = new AtomicInteger(0);
|
||||||
|
|
||||||
|
private ConfigurableApplicationContext applicationContext;
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
if (applicationContext != null) {
|
||||||
|
applicationContext.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected void assertDiskStore(DiskStore diskStore, String name, boolean allowForceCompaction, boolean autoCompact,
|
||||||
|
int compactionThreshold, float diskUsageCriticalPercentage, float diskUsageWarningPercentage,
|
||||||
|
long maxOplogSize, int queueSize, long timeInterval, int writeBufferSize) {
|
||||||
|
|
||||||
|
assertThat(diskStore).isNotNull();
|
||||||
|
assertThat(diskStore.getName()).isEqualTo(name);
|
||||||
|
assertThat(diskStore.getAllowForceCompaction()).isEqualTo(allowForceCompaction);
|
||||||
|
assertThat(diskStore.getAutoCompact()).isEqualTo(autoCompact);
|
||||||
|
assertThat(diskStore.getCompactionThreshold()).isEqualTo(compactionThreshold);
|
||||||
|
assertThat(diskStore.getDiskUsageCriticalPercentage()).isEqualTo(diskUsageCriticalPercentage);
|
||||||
|
assertThat(diskStore.getDiskUsageWarningPercentage()).isEqualTo(diskUsageWarningPercentage);
|
||||||
|
assertThat(diskStore.getMaxOplogSize()).isEqualTo(maxOplogSize);
|
||||||
|
assertThat(diskStore.getQueueSize()).isEqualTo(queueSize);
|
||||||
|
assertThat(diskStore.getTimeInterval()).isEqualTo(timeInterval);
|
||||||
|
assertThat(diskStore.getWriteBufferSize()).isEqualTo(writeBufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected void assertDiskStoreDirectoryLocations(DiskStore diskStore, File... diskDirectories) {
|
||||||
|
assertThat(diskStore).isNotNull();
|
||||||
|
|
||||||
|
File[] diskStoreDirectories = diskStore.getDiskDirs();
|
||||||
|
|
||||||
|
assertThat(diskStoreDirectories).isNotNull();
|
||||||
|
assertThat(diskStoreDirectories.length).isEqualTo(diskDirectories.length);
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
for (File diskDirectory : diskDirectories) {
|
||||||
|
assertThat(diskStoreDirectories[index++]).isEqualTo(diskDirectory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected void assertDiskStoreDirectorySizes(DiskStore diskStore, int... diskDirectorySizes) {
|
||||||
|
assertThat(diskStore).isNotNull();
|
||||||
|
|
||||||
|
int[] diskStoreDirectorySizes = diskStore.getDiskDirSizes();
|
||||||
|
|
||||||
|
assertThat(diskStoreDirectorySizes).isNotNull();
|
||||||
|
assertThat(diskStoreDirectorySizes.length).isEqualTo(diskDirectorySizes.length);
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
for (int size : diskDirectorySizes) {
|
||||||
|
assertThat(diskStoreDirectorySizes[index++]).isEqualTo(size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected File newFile(String location) {
|
||||||
|
return new File(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected ConfigurableApplicationContext newApplicationContext(Class<?>... annotatedClasses) {
|
||||||
|
ConfigurableApplicationContext applicationContext = new AnnotationConfigApplicationContext(annotatedClasses);
|
||||||
|
applicationContext.registerShutdownHook();
|
||||||
|
return applicationContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void enableSingleDiskStore() {
|
||||||
|
applicationContext = newApplicationContext(SingleDiskStoreConfiguration.class);
|
||||||
|
|
||||||
|
DiskStore testDiskStore = applicationContext.getBean("TestDiskStore", DiskStore.class);
|
||||||
|
|
||||||
|
assertDiskStore(testDiskStore, "TestDiskStore", true, true, 75, 95.0f, 75.0f, 8192L, 100, 2000L, 65536);
|
||||||
|
assertDiskStoreDirectoryLocations(testDiskStore, newFile("/absolute/path/to/gemfire/disk/directory"),
|
||||||
|
newFile("relative/path/to/gemfire/disk/directory"));
|
||||||
|
assertDiskStoreDirectorySizes(testDiskStore, 1024, 4096);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void enablesMultipleDiskStores() {
|
||||||
|
applicationContext = newApplicationContext(MultipleDiskStoresConfiguration.class);
|
||||||
|
|
||||||
|
DiskStore testDiskStoreOne = applicationContext.getBean("TestDiskStoreOne", DiskStore.class);
|
||||||
|
|
||||||
|
assertDiskStore(testDiskStoreOne, "TestDiskStoreOne", false, true, 75, 99.0f, 90.0f, 2048L, 100, 1000L, 32768);
|
||||||
|
|
||||||
|
DiskStore testDiskStoreTwo = applicationContext.getBean("TestDiskStoreTwo", DiskStore.class);
|
||||||
|
|
||||||
|
assertDiskStore(testDiskStoreTwo, "TestDiskStoreTwo", true, true, 85, 99.0f, 90.0f, 4096L, 0, 1000L, 32768);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String mockName(String baseName) {
|
||||||
|
return String.format("%s%d", baseName, MOCK_ID.incrementAndGet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected static <R> Answer<R> newGetter(AtomicReference<R> returnValue) {
|
||||||
|
return invocation -> returnValue.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc) */
|
||||||
|
protected static <T, R> Answer<R> newSetter(Class<T> parameterType, AtomicReference<T> argument, R returnValue) {
|
||||||
|
return invocation -> {
|
||||||
|
argument.set(invocation.getArgumentAt(0, parameterType));
|
||||||
|
return returnValue;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
static class CacheConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
Cache gemfireCache() {
|
||||||
|
Cache mockCache = mock(Cache.class);
|
||||||
|
|
||||||
|
when(mockCache.createDiskStoreFactory()).thenAnswer(new Answer<DiskStoreFactory>() {
|
||||||
|
@Override
|
||||||
|
public DiskStoreFactory answer(InvocationOnMock invocation) throws Throwable {
|
||||||
|
final DiskStoreFactory mockDiskStoreFactory =
|
||||||
|
mock(DiskStoreFactory.class, mockName("MockDiskStoreFactory"));
|
||||||
|
|
||||||
|
final AtomicReference<Boolean> allowForceCompaction = new AtomicReference<>(false);
|
||||||
|
final AtomicReference<Boolean> autoCompact = new AtomicReference<>(false);
|
||||||
|
final AtomicReference<Integer> compactionThreshold = new AtomicReference<>(50);
|
||||||
|
final AtomicReference<File[]> diskDirectories = new AtomicReference<>(new File[0]);
|
||||||
|
final AtomicReference<int[]> diskDirectorySizes = new AtomicReference<>(new int[0]);
|
||||||
|
final AtomicReference<Float> diskUsageCriticalPercentage = new AtomicReference<>(99.0f);
|
||||||
|
final AtomicReference<Float> diskUsageWarningPercentage = new AtomicReference<>(90.0f);
|
||||||
|
final AtomicReference<Long> maxOplogSize = new AtomicReference<>(1024L);
|
||||||
|
final AtomicReference<Integer> queueSize = new AtomicReference<>(0);
|
||||||
|
final AtomicReference<Long> timeInterval = new AtomicReference<>(1000L);
|
||||||
|
final AtomicReference<Integer> writeBufferSize = new AtomicReference<>(32768);
|
||||||
|
|
||||||
|
when(mockDiskStoreFactory.setAllowForceCompaction(anyBoolean())).thenAnswer(
|
||||||
|
newSetter(Boolean.TYPE, allowForceCompaction, mockDiskStoreFactory));
|
||||||
|
|
||||||
|
when(mockDiskStoreFactory.setAutoCompact(anyBoolean())).thenAnswer(
|
||||||
|
newSetter(Boolean.TYPE, autoCompact, mockDiskStoreFactory));
|
||||||
|
|
||||||
|
when(mockDiskStoreFactory.setCompactionThreshold(anyInt())).thenAnswer(
|
||||||
|
newSetter(Integer.TYPE, compactionThreshold, mockDiskStoreFactory));
|
||||||
|
|
||||||
|
when(mockDiskStoreFactory.setDiskDirsAndSizes(any(File[].class), any(int[].class))).thenAnswer(
|
||||||
|
new Answer<DiskStoreFactory>() {
|
||||||
|
@Override public DiskStoreFactory answer(InvocationOnMock invocation) throws Throwable {
|
||||||
|
File[] localDiskDirectories = invocation.getArgumentAt(0, File[].class);
|
||||||
|
int[] localDiskDirectorySizes = invocation.getArgumentAt(1, int[].class);
|
||||||
|
|
||||||
|
diskDirectories.set(localDiskDirectories);
|
||||||
|
diskDirectorySizes.set(localDiskDirectorySizes);
|
||||||
|
|
||||||
|
return mockDiskStoreFactory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
when(mockDiskStoreFactory.setDiskUsageCriticalPercentage(anyFloat())).thenAnswer(
|
||||||
|
newSetter(Float.TYPE, diskUsageCriticalPercentage, mockDiskStoreFactory));
|
||||||
|
|
||||||
|
when(mockDiskStoreFactory.setDiskUsageWarningPercentage(anyFloat())).thenAnswer(
|
||||||
|
newSetter(Float.TYPE, diskUsageWarningPercentage, mockDiskStoreFactory));
|
||||||
|
|
||||||
|
when(mockDiskStoreFactory.setMaxOplogSize(anyLong())).thenAnswer(
|
||||||
|
newSetter(Long.TYPE, maxOplogSize, mockDiskStoreFactory));
|
||||||
|
|
||||||
|
when(mockDiskStoreFactory.setQueueSize(anyInt())).thenAnswer(
|
||||||
|
newSetter(Integer.TYPE, queueSize, mockDiskStoreFactory));
|
||||||
|
|
||||||
|
when(mockDiskStoreFactory.setTimeInterval(anyLong())).thenAnswer(
|
||||||
|
newSetter(Long.TYPE, timeInterval, mockDiskStoreFactory));
|
||||||
|
|
||||||
|
when(mockDiskStoreFactory.setWriteBufferSize(anyInt())).thenAnswer(
|
||||||
|
newSetter(Integer.TYPE, writeBufferSize, mockDiskStoreFactory));
|
||||||
|
|
||||||
|
when(mockDiskStoreFactory.create(anyString())).thenAnswer(new Answer<DiskStore>() {
|
||||||
|
@Override
|
||||||
|
public DiskStore answer(InvocationOnMock invocation) throws Throwable {
|
||||||
|
String diskStoreName = invocation.getArgumentAt(0, String.class);
|
||||||
|
|
||||||
|
DiskStore mockDiskStore = mock(DiskStore.class, diskStoreName);
|
||||||
|
|
||||||
|
when(mockDiskStore.getAllowForceCompaction()).thenAnswer(newGetter(allowForceCompaction));
|
||||||
|
when(mockDiskStore.getAutoCompact()).thenAnswer(newGetter(autoCompact));
|
||||||
|
when(mockDiskStore.getCompactionThreshold()).thenAnswer(newGetter(compactionThreshold));
|
||||||
|
when(mockDiskStore.getDiskDirs()).thenAnswer(newGetter(diskDirectories));
|
||||||
|
when(mockDiskStore.getDiskDirSizes()).thenAnswer(newGetter(diskDirectorySizes));
|
||||||
|
when(mockDiskStore.getDiskUsageCriticalPercentage()).thenAnswer(newGetter(diskUsageCriticalPercentage));
|
||||||
|
when(mockDiskStore.getDiskUsageWarningPercentage()).thenAnswer(newGetter(diskUsageWarningPercentage));
|
||||||
|
when(mockDiskStore.getMaxOplogSize()).thenAnswer(newGetter(maxOplogSize));
|
||||||
|
when(mockDiskStore.getName()).thenReturn(diskStoreName);
|
||||||
|
when(mockDiskStore.getQueueSize()).thenAnswer(newGetter(queueSize));
|
||||||
|
when(mockDiskStore.getTimeInterval()).thenAnswer(newGetter(timeInterval));
|
||||||
|
when(mockDiskStore.getWriteBufferSize()).thenAnswer(newGetter(writeBufferSize));
|
||||||
|
|
||||||
|
return mockDiskStore;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return mockDiskStoreFactory;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return mockCache;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EnableDiskStore(name = "TestDiskStore", allowForceCompaction = true, autoCompact = true, compactionThreshold = 75,
|
||||||
|
diskUsageCriticalPercentage = 95.0f, diskUsageWarningPercentage = 75.0f, maxOplogSize = 8192L, queueSize = 100,
|
||||||
|
timeInterval = 2000L, writeBufferSize = 65536, diskDirectories = {
|
||||||
|
@EnableDiskStore.DiskDirectory(location = "/absolute/path/to/gemfire/disk/directory", maxSize = 1024),
|
||||||
|
@EnableDiskStore.DiskDirectory(location = "relative/path/to/gemfire/disk/directory", maxSize = 4096)
|
||||||
|
})
|
||||||
|
static class SingleDiskStoreConfiguration extends CacheConfiguration {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@EnableDiskStores(autoCompact = true, compactionThreshold = 75, maxOplogSize = 2048L, diskStores = {
|
||||||
|
@EnableDiskStore(name = "TestDiskStoreOne", queueSize = 100),
|
||||||
|
@EnableDiskStore(name = "TestDiskStoreTwo", allowForceCompaction = true,
|
||||||
|
compactionThreshold = 85, maxOplogSize = 4096)
|
||||||
|
})
|
||||||
|
static class MultipleDiskStoresConfiguration extends CacheConfiguration {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user