From 6c20828e847a4c406e6525e7db85b24f874845a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20W=C4=85sik?= Date: Thu, 25 Apr 2013 12:34:13 +0200 Subject: [PATCH] Caching more mapping query methods, to prevent slow reflection and collection lookup for every request --- .../convert/ProfiledCustomConversions.java | 352 ++++++++++++++++++ .../ProfiledDefaultMongoTypeMapper.java | 114 ++++++ .../mapping/ProfiledMongoMappingContext.java | 29 ++ .../ProfiledMongoPersistanceEntity.java | 41 ++ .../mongodb/performance/PerformanceTests.java | 74 +++- 5 files changed, 608 insertions(+), 2 deletions(-) create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/ProfiledCustomConversions.java create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/ProfiledDefaultMongoTypeMapper.java create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/ProfiledMongoMappingContext.java create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/ProfiledMongoPersistanceEntity.java diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/ProfiledCustomConversions.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/ProfiledCustomConversions.java new file mode 100644 index 0000000000..12cafb902f --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/ProfiledCustomConversions.java @@ -0,0 +1,352 @@ +/* + * Copyright 2011-2013 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.mongodb.core.convert; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.GenericTypeResolver; +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.core.convert.converter.Converter; +import org.springframework.core.convert.converter.ConverterFactory; +import org.springframework.core.convert.converter.GenericConverter; +import org.springframework.core.convert.converter.GenericConverter.ConvertiblePair; +import org.springframework.core.convert.support.GenericConversionService; +import org.springframework.data.convert.JodaTimeConverters; +import org.springframework.data.convert.ReadingConverter; +import org.springframework.data.convert.WritingConverter; +import org.springframework.data.mapping.model.SimpleTypeHolder; +import org.springframework.data.mongodb.core.convert.MongoConverters.BigDecimalToStringConverter; +import org.springframework.data.mongodb.core.convert.MongoConverters.BigIntegerToStringConverter; +import org.springframework.data.mongodb.core.convert.MongoConverters.StringToBigDecimalConverter; +import org.springframework.data.mongodb.core.convert.MongoConverters.StringToBigIntegerConverter; +import org.springframework.data.mongodb.core.convert.MongoConverters.StringToURLConverter; +import org.springframework.data.mongodb.core.convert.MongoConverters.URLToStringConverter; +import org.springframework.data.mongodb.core.mapping.MongoSimpleTypes; +import org.springframework.util.Assert; + +/** + * Value object to capture custom conversion. That is essentially a {@link List} of converters and some additional logic + * around them. The converters are pretty much builds up two sets of types which Mongo basic types {@see #MONGO_TYPES} + * can be converted into and from. These types will be considered simple ones (which means they neither need deeper + * inspection nor nested conversion. Thus the {@link CustomConversions} also act as factory for {@link SimpleTypeHolder} + * . + * + * @author Oliver Gierke + */ +public class ProfiledCustomConversions extends CustomConversions { + + private static final Logger LOG = LoggerFactory.getLogger(CustomConversions.class); + private static final String READ_CONVERTER_NOT_SIMPLE = "Registering converter from %s to %s as reading converter although it doesn't convert from a Mongo supported type! You might wanna check you annotation setup at the converter implementation."; + private static final String WRITE_CONVERTER_NOT_SIMPLE = "Registering converter from %s to %s as writing converter although it doesn't convert to a Mongo supported type! You might wanna check you annotation setup at the converter implementation."; + + private final Set readingPairs; + private final Set writingPairs; + private final Set> customSimpleTypes; + private final SimpleTypeHolder simpleTypeHolder; + + private final List converters; + private ConcurrentHashMap,ConcurrentHashMap,CacheHolder>> cache = new ConcurrentHashMap, ConcurrentHashMap, CacheHolder>>(); + + /** + * Creates an empty {@link CustomConversions} object. + */ + public ProfiledCustomConversions() { + this(new ArrayList()); + } + + /** + * Creates a new {@link CustomConversions} instance registering the given converters. + * + * @param converters + */ + public ProfiledCustomConversions(List converters) { + + Assert.notNull(converters); + + this.readingPairs = new HashSet(); + this.writingPairs = new HashSet(); + this.customSimpleTypes = new HashSet>(); + + this.converters = new ArrayList(); + this.converters.add(CustomToStringConverter.INSTANCE); + this.converters.add(BigDecimalToStringConverter.INSTANCE); + this.converters.add(StringToBigDecimalConverter.INSTANCE); + this.converters.add(BigIntegerToStringConverter.INSTANCE); + this.converters.add(StringToBigIntegerConverter.INSTANCE); + this.converters.add(URLToStringConverter.INSTANCE); + this.converters.add(StringToURLConverter.INSTANCE); + this.converters.addAll(JodaTimeConverters.getConvertersToRegister()); + this.converters.addAll(converters); + + for (Object c : this.converters) { + registerConversion(c); + } + + this.simpleTypeHolder = new SimpleTypeHolder(customSimpleTypes, MongoSimpleTypes.HOLDER); + } + + /** + * Returns the underlying {@link SimpleTypeHolder}. + * + * @return + */ + public SimpleTypeHolder getSimpleTypeHolder() { + return simpleTypeHolder; + } + + /** + * Returns whether the given type is considered to be simple. That means it's either a general simple type or we have + * a writing {@link Converter} registered for a particular type. + * + * @see SimpleTypeHolder#isSimpleType(Class) + * @param type + * @return + */ + public boolean isSimpleType(Class type) { + return simpleTypeHolder.isSimpleType(type); + } + + /** + * Populates the given {@link GenericConversionService} with the convertes registered. + * + * @param conversionService + */ + public void registerConvertersIn(GenericConversionService conversionService) { + + for (Object converter : converters) { + + boolean added = false; + + if (converter instanceof Converter) { + conversionService.addConverter((Converter) converter); + added = true; + } + + if (converter instanceof ConverterFactory) { + conversionService.addConverterFactory((ConverterFactory) converter); + added = true; + } + + if (converter instanceof GenericConverter) { + conversionService.addConverter((GenericConverter) converter); + added = true; + } + + if (!added) { + throw new IllegalArgumentException("Given set contains element that is neither Converter nor ConverterFactory!"); + } + } + } + + /** + * Registers a conversion for the given converter. Inspects either generics or the {@link ConvertiblePair}s returned + * by a {@link GenericConverter}. + * + * @param converter + */ + private void registerConversion(Object converter) { + + Class type = converter.getClass(); + boolean isWriting = type.isAnnotationPresent(WritingConverter.class); + boolean isReading = type.isAnnotationPresent(ReadingConverter.class); + + if (converter instanceof GenericConverter) { + GenericConverter genericConverter = (GenericConverter) converter; + for (ConvertiblePair pair : genericConverter.getConvertibleTypes()) { + register(new ConverterRegistration(pair, isReading, isWriting)); + } + } else if (converter instanceof Converter) { + Class[] arguments = GenericTypeResolver.resolveTypeArguments(converter.getClass(), Converter.class); + register(new ConverterRegistration(arguments[0], arguments[1], isReading, isWriting)); + } else { + throw new IllegalArgumentException("Unsupported Converter type!"); + } + } + + /** + * Registers the given {@link ConvertiblePair} as reading or writing pair depending on the type sides being basic + * Mongo types. + * + * @param pair + */ + private void register(ConverterRegistration context) { + + ConvertiblePair pair = context.getConvertiblePair(); + + if (context.isReading()) { + + readingPairs.add(pair); + + if (LOG.isWarnEnabled() && !context.isSimpleSourceType()) { + LOG.warn(String.format(READ_CONVERTER_NOT_SIMPLE, pair.getSourceType(), pair.getTargetType())); + } + } + + if (context.isWriting()) { + + writingPairs.add(pair); + customSimpleTypes.add(pair.getSourceType()); + + if (LOG.isWarnEnabled() && !context.isSimpleTargetType()) { + LOG.warn(String.format(WRITE_CONVERTER_NOT_SIMPLE, pair.getSourceType(), pair.getTargetType())); + } + } + } + + /** + * Returns the target type to convert to in case we have a custom conversion registered to convert the given source + * type into a Mongo native one. + * + * @param source must not be {@literal null} + * @return + */ + public Class getCustomWriteTarget(Class source) { + return getCustomWriteTarget(source, null); + } + + /** + * Returns the target type we can write an onject of the given source type to. The returned type might be a subclass + * oth the given expected type though. If {@code expectedTargetType} is {@literal null} we will simply return the + * first target type matching or {@literal null} if no conversion can be found. + * + * @param source must not be {@literal null} + * @param expectedTargetType + * @return + */ + public Class getCustomWriteTarget(Class source, Class expectedTargetType) { + Assert.notNull(source); + return getCustomTarget(source, expectedTargetType, writingPairs); + } + + /** + * Returns whether we have a custom conversion registered to write into a Mongo native type. The returned type might + * be a subclass oth the given expected type though. + * + * @param source must not be {@literal null} + * @return + */ + public boolean hasCustomWriteTarget(Class source) { + return hasCustomWriteTarget(source, null); + } + + /** + * Returns whether we have a custom conversion registered to write an object of the given source type into an object + * of the given Mongo native target type. + * + * @param source must not be {@literal null}. + * @param expectedTargetType + * @return + */ + public boolean hasCustomWriteTarget(Class source, Class expectedTargetType) { + return getCustomWriteTarget(source, expectedTargetType) != null; + } + + /** + * Returns whether we have a custom conversion registered to read the given source into the given target type. + * + * @param source must not be {@literal null} + * @param expectedTargetType must not be {@literal null} + * @return + */ + public boolean hasCustomReadTarget(Class source, Class expectedTargetType) { + Assert.notNull(source); + Assert.notNull(expectedTargetType); + return getCustomReadTarget(source, expectedTargetType) != null; + } + + /** + * Inspects the given {@link ConvertiblePair} for ones that have a source compatible type as source. Additionally + * checks assignabilty of the target type if one is given. + * + * @param source must not be {@literal null} + * @param expectedTargetType + * @param pairs must not be {@literal null} + * @return + */ + private static Class getCustomTarget(Class source, Class expectedTargetType, Iterable pairs) { + + Assert.notNull(source); + Assert.notNull(pairs); + + for (ConvertiblePair typePair : pairs) { + if (typePair.getSourceType().isAssignableFrom(source)) { + Class targetType = typePair.getTargetType(); + if (expectedTargetType == null || targetType.isAssignableFrom(expectedTargetType)) { + return targetType; + } + } + } + + return null; + } + + private Class getCustomReadTarget(Class source, Class expectedTargetType) { + + Map, CacheHolder> map; + CacheHolder toReturn; + + if (expectedTargetType == null) { + expectedTargetType = Foo.class; + } + + if ((map = cache.get(source)) == null || (toReturn = map.get(expectedTargetType)) == null) { + Class target = getCustomTarget(source, expectedTargetType, readingPairs); + + if (cache.get(source) == null) { + cache.put(source, new ConcurrentHashMap, CacheHolder>()); + } + + if (target == null) { + toReturn = new CacheHolder(null); + cache.get(source).put(expectedTargetType, toReturn); + } else { + toReturn = new CacheHolder(target); + cache.get(source).put(expectedTargetType, toReturn); + } + } + return toReturn.clazz; + } + + @WritingConverter + private enum CustomToStringConverter implements GenericConverter { + INSTANCE; + + public Set getConvertibleTypes() { + ConvertiblePair localeToString = new ConvertiblePair(Locale.class, String.class); + ConvertiblePair booleanToString = new ConvertiblePair(Character.class, String.class); + return new HashSet(Arrays.asList(localeToString, booleanToString)); + } + + public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + return source.toString(); + } + } + + class Foo { + + } + + class CacheHolder { + Class clazz; + + CacheHolder(Class clazz) { + this.clazz = clazz; + } + } +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/ProfiledDefaultMongoTypeMapper.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/ProfiledDefaultMongoTypeMapper.java new file mode 100644 index 0000000000..6d8217f36d --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/ProfiledDefaultMongoTypeMapper.java @@ -0,0 +1,114 @@ +package org.springframework.data.mongodb.core.convert; + +import com.mongodb.BasicDBList; +import com.mongodb.DBObject; +import org.springframework.data.convert.DefaultTypeMapper; +import org.springframework.data.convert.SimpleTypeInformationMapper; +import org.springframework.data.convert.TypeInformationMapper; +import org.springframework.data.mapping.PersistentEntity; +import org.springframework.data.mapping.context.MappingContext; +import org.springframework.data.util.ClassTypeInformation; +import org.springframework.data.util.TypeInformation; +import org.springframework.util.Assert; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class ProfiledDefaultMongoTypeMapper extends DefaultTypeMapper implements MongoTypeMapper { + + public static final String DEFAULT_TYPE_KEY = "_class"; + @SuppressWarnings("rawtypes") + private static final TypeInformation LIST_TYPE_INFO = ClassTypeInformation.from(List.class); + @SuppressWarnings("rawtypes") + private static final TypeInformation MAP_TYPE_INFO = ClassTypeInformation.from(Map.class); + private String typeKey = DEFAULT_TYPE_KEY; + + private final DefaultMongoTypeMapper.DBObjectTypeAliasAccessor typeAliasAccessor; + + private ConcurrentHashMap> typeCache = new ConcurrentHashMap>(); + + public ProfiledDefaultMongoTypeMapper() { + this(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, Arrays.asList(SimpleTypeInformationMapper.INSTANCE)); + } + + public ProfiledDefaultMongoTypeMapper(String typeKey) { + this(typeKey, new DefaultMongoTypeMapper.DBObjectTypeAliasAccessor(typeKey), null, Arrays.asList(SimpleTypeInformationMapper.INSTANCE)); + } + + public ProfiledDefaultMongoTypeMapper(String typeKey, MappingContext, ?> mappingContext) { + this(typeKey, new DefaultMongoTypeMapper.DBObjectTypeAliasAccessor(typeKey), mappingContext, Arrays.asList(SimpleTypeInformationMapper.INSTANCE)); + } + + public ProfiledDefaultMongoTypeMapper(String typeKey, List mappers) { + this(typeKey, new DefaultMongoTypeMapper.DBObjectTypeAliasAccessor(typeKey), null, mappers); + } + + protected ProfiledDefaultMongoTypeMapper(String typeKey, DefaultMongoTypeMapper.DBObjectTypeAliasAccessor typeAliasAccessor, MappingContext, ?> mappingContext, List mappers) { + super(typeAliasAccessor, mappingContext, mappers); + this.typeAliasAccessor = typeAliasAccessor; + this.typeKey = typeKey; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.mongodb.core.convert.MongoTypeMapper#isTypeKey(java.lang.String) + */ + public boolean isTypeKey(String key) { + return typeKey == null ? false : typeKey.equals(key); + } + + /* (non-Javadoc) + * @see org.springframework.data.convert.DefaultTypeMapper#getFallbackTypeFor(java.lang.Object) + */ + @Override + protected TypeInformation getFallbackTypeFor(DBObject source) { + return source instanceof BasicDBList ? LIST_TYPE_INFO : MAP_TYPE_INFO; + } + + @Override + public TypeInformation readType(DBObject source, TypeInformation basicType) { + + Assert.notNull(source); + Class documentsTargetType = getDefaultedTypeToBeUsed(source); + + if (documentsTargetType == null) { + return basicType; + } + + Class rawType = basicType == null ? null : basicType.getType(); + + boolean isMoreConcreteCustomType = rawType == null ? true : rawType.isAssignableFrom(documentsTargetType) + && !rawType.equals(documentsTargetType); + return isMoreConcreteCustomType ? (TypeInformation) ClassTypeInformation.from(documentsTargetType) + : basicType; + } + + private Class getDefaultedTypeToBeUsed(DBObject source) { + + TypeInformation documentsTargetTypeInformation = readType(source); + documentsTargetTypeInformation = documentsTargetTypeInformation == null ? getFallbackTypeFor(source) + : documentsTargetTypeInformation; + return documentsTargetTypeInformation == null ? null : documentsTargetTypeInformation.getType(); + } + + @Override + public TypeInformation readType(DBObject source) { + + Object o = typeAliasAccessor.readAliasFrom(source); + + if (o == null) { + return null; + } + + TypeInformation typeInformation; + + if ((typeInformation = typeCache.get(o)) == null) { + typeInformation = super.readType(source); + typeCache.put(o, typeInformation); + } + return typeInformation; + } + +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/ProfiledMongoMappingContext.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/ProfiledMongoMappingContext.java new file mode 100644 index 0000000000..c12f003a78 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/ProfiledMongoMappingContext.java @@ -0,0 +1,29 @@ +package org.springframework.data.mongodb.core.mapping; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.data.util.TypeInformation; + +public class ProfiledMongoMappingContext extends MongoMappingContext { + + private ApplicationContext context; + + @Override + protected BasicMongoPersistentEntity createPersistentEntity(TypeInformation typeInformation) { + + ProfiledMongoPersistanceEntity entity = new ProfiledMongoPersistanceEntity(typeInformation); + + if (context != null) { + entity.setApplicationContext(context); + } + + return entity; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + + this.context = applicationContext; + super.setApplicationContext(applicationContext); + } +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/ProfiledMongoPersistanceEntity.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/ProfiledMongoPersistanceEntity.java new file mode 100644 index 0000000000..e675d1aa97 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/ProfiledMongoPersistanceEntity.java @@ -0,0 +1,41 @@ +package org.springframework.data.mongodb.core.mapping; + +import org.springframework.data.mapping.PersistentProperty; +import org.springframework.data.util.TypeInformation; + +import java.util.concurrent.ConcurrentHashMap; + +public class ProfiledMongoPersistanceEntity extends BasicMongoPersistentEntity { + + + private ConcurrentHashMap propertyCache = new ConcurrentHashMap(); + private ConcurrentHashMap,Boolean> constructorArgumentCache = new ConcurrentHashMap, Boolean>(); + + public ProfiledMongoPersistanceEntity(TypeInformation typeInformation) { + super(typeInformation); + } + + @Override + public void addPersistentProperty(MongoPersistentProperty property) { + + super.addPersistentProperty(property); + propertyCache.put(property.getName(), property); + } + + @Override + public MongoPersistentProperty getPersistentProperty(String name) { + return propertyCache.get(name); + } + + @Override + public boolean isConstructorArgument(PersistentProperty property) { + + Boolean toReturn; + + if ((toReturn = constructorArgumentCache.get(property)) == null) { + toReturn = super.isConstructorArgument(property); + constructorArgumentCache.put(property, toReturn); + } + return toReturn; + } +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/performance/PerformanceTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/performance/PerformanceTests.java index 28804dd7ea..9f63e3c8a5 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/performance/PerformanceTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/performance/PerformanceTests.java @@ -35,7 +35,11 @@ import org.springframework.data.annotation.PersistenceConstructor; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.SimpleMongoDbFactory; +import org.springframework.data.mongodb.core.convert.MappingMongoConverter; +import org.springframework.data.mongodb.core.convert.ProfiledCustomConversions; +import org.springframework.data.mongodb.core.convert.ProfiledDefaultMongoTypeMapper; import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.ProfiledMongoMappingContext; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.data.mongodb.repository.support.MongoRepositoryFactoryBean; @@ -60,7 +64,7 @@ public class PerformanceTests { private static final String DATABASE_NAME = "performance"; - private static final int NUMBER_OF_PERSONS = 30000; + private static final int NUMBER_OF_PERSONS = 3000; private static final StopWatch watch = new StopWatch(); private static final Collection IGNORED_WRITE_CONCERNS = Arrays.asList("MAJORITY", "REPLICAS_SAFE", "FSYNC_SAFE", "JOURNAL_SAFE"); @@ -70,12 +74,19 @@ public class PerformanceTests { Mongo mongo; MongoTemplate operations; PersonRepository repository; + MongoTemplate profiledMongoTemplate; @Before public void setUp() throws Exception { this.mongo = new Mongo(); - this.operations = new MongoTemplate(new SimpleMongoDbFactory(this.mongo, DATABASE_NAME)); + SimpleMongoDbFactory simpleMongoDbFactory = new SimpleMongoDbFactory(this.mongo, DATABASE_NAME); + this.operations = new MongoTemplate(simpleMongoDbFactory); + + MappingMongoConverter mappingMongoConverter = new MappingMongoConverter(simpleMongoDbFactory,new ProfiledMongoMappingContext()); + mappingMongoConverter.setTypeMapper(new ProfiledDefaultMongoTypeMapper()); + mappingMongoConverter.setCustomConversions(new ProfiledCustomConversions()); + this.profiledMongoTemplate = new MongoTemplate(simpleMongoDbFactory,mappingMongoConverter); MongoRepositoryFactoryBean factory = new MongoRepositoryFactoryBean(); factory.setMongoOperations(operations); @@ -98,6 +109,41 @@ public void doWithWriteConcern(String constantName, WriteConcern concern) { }); } + @Test + public void readAfterWarmup() { + + mongo.setWriteConcern(WriteConcern.SAFE); + + setupCollections(); + + writingObjectsUsingMongoTemplate("Writing %s objects using template"); + + for (int i = 0; i < 30; i++) { + readingUsingTemplate("Reading all objects using template"); + readingUsingProfiledTemplate("Reading all objects using template"); + } + + long time = 0; + + for (int i = 0; i < 100; i++) { + readingUsingProfiledTemplate2("Reading all objects using template"); + time += watch.getLastTaskTimeMillis(); + } + long after = time / 100; + + time = 0; + + for (int i = 0; i < 100; i++) { + readingUsingTemplate2("Reading all objects using template"); + time += watch.getLastTaskTimeMillis(); + } + long before = time / 100; + + System.out.println("Before ----------------------------> " + before); + System.out.println("After ----------------------------> " + after); + System.out.println("Diff ----------------------------> " + (100 - ((double) after / (double) before) * 100.0) + "%"); + } + @Test public void writeAndRead() { @@ -255,6 +301,30 @@ public List doInWatch() { }); } + private void readingUsingTemplate2(String template) { + executeWatchedWithTimeAndResultSize(String.format(template, NUMBER_OF_PERSONS), new WatchCallback>() { + public List doInWatch() { + return operations.findAll(Person.class, "template"); + } + }); + } + + private void readingUsingProfiledTemplate(String template) { + executeWatchedWithTimeAndResultSize(String.format(template, NUMBER_OF_PERSONS), new WatchCallback>() { + public List doInWatch() { + return profiledMongoTemplate.findAll(Person.class, "template"); + } + }); + } + + private void readingUsingProfiledTemplate2(String template) { + executeWatchedWithTimeAndResultSize(String.format(template, NUMBER_OF_PERSONS), new WatchCallback>() { + public List doInWatch() { + return profiledMongoTemplate.findAll(Person.class, "template"); + } + }); + } + private void readingUsingRepository(String template) { executeWatchedWithTimeAndResultSize(String.format(template, NUMBER_OF_PERSONS), new WatchCallback>() { public List doInWatch() {