package rocks.inspectit.shared.cs.storage.processor.write.impl; import java.util.Collections; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import rocks.inspectit.shared.all.communication.DefaultData; import rocks.inspectit.shared.all.communication.data.InvocationAwareData; import rocks.inspectit.shared.all.communication.data.InvocationAwareData.MutableInt; import rocks.inspectit.shared.all.indexing.IIndexQuery; import rocks.inspectit.shared.all.serializer.util.KryoSerializationPreferences; import rocks.inspectit.shared.cs.indexing.aggregation.IAggregator; import rocks.inspectit.shared.cs.indexing.aggregation.impl.AggregationPerformer; import rocks.inspectit.shared.cs.storage.StorageData; import rocks.inspectit.shared.cs.storage.StorageManager; import rocks.inspectit.shared.cs.storage.StorageWriter; import rocks.inspectit.shared.cs.storage.processor.write.AbstractWriteDataProcessor; /** * Processor that can create a cached result set for a storage with given query and aggregator. * * @author Ivan Senic * * @param <E> * Type of elements processed. */ public class QueryCachingDataProcessor<E extends DefaultData> extends AbstractWriteDataProcessor { /** * {@link IIndexQuery} to take into consideration. */ private IIndexQuery query; /** * {@link IAggregator} for aggregaton. */ private IAggregator<E> aggregator; /** * {@link AggregationPerformer}s must be separated by platform ID. */ private ConcurrentHashMap<Long, AggregationPerformer<E>> aggregationPerformerMap; /** * @param query * {@link IIndexQuery} to take into consideration. * @param aggregator * {@link IAggregator} for aggregaton. */ public QueryCachingDataProcessor(IIndexQuery query, IAggregator<E> aggregator) { this.query = query; this.aggregator = aggregator; this.aggregationPerformerMap = new ConcurrentHashMap<>(4, 0.75f, 1); } /** * {@inheritDoc} */ @SuppressWarnings("unchecked") @Override protected void processData(DefaultData defaultData, Map<?, ?> kryoPreferences) { Long key = Long.valueOf(defaultData.getPlatformIdent()); AggregationPerformer<E> aggregationPerformer = aggregationPerformerMap.get(key); if (null == aggregationPerformer) { aggregationPerformer = aggregationPerformerMap.putIfAbsent(key, new AggregationPerformer<>(aggregator)); if (null == aggregationPerformer) { aggregationPerformer = aggregationPerformerMap.get(key); } } // deal with no saving of the invocation affiliation for cached views as well if (Boolean.FALSE.equals(kryoPreferences.get(KryoSerializationPreferences.WRITE_INVOCATION_AFFILIATION_DATA)) && (defaultData instanceof InvocationAwareData)) { InvocationAwareData invocationAwareData = (InvocationAwareData) defaultData; Map<Long, MutableInt> temp = invocationAwareData.getInvocationsParentsIdMap(); invocationAwareData.setInvocationsParentsIdMap(Collections.<Long, MutableInt> emptyMap()); aggregationPerformer.processElement((E) defaultData); invocationAwareData.setInvocationsParentsIdMap(temp); } else { aggregationPerformer.processElement((E) defaultData); } } /** * {@inheritDoc} */ @Override public boolean canBeProcessed(DefaultData defaultData) { return defaultData.isQueryComplied(query); } /** * {@inheritDoc} */ @Override public void onFinalization(StorageManager storageManager, StorageWriter storageWriter, StorageData storageData) throws Exception { for (Map.Entry<Long, AggregationPerformer<E>> entry : aggregationPerformerMap.entrySet()) { query.setPlatformIdent(entry.getKey().longValue()); AggregationPerformer<E> aggregationPerformer = entry.getValue(); storageManager.cacheStorageData(storageData, aggregationPerformer.getResultList(), storageManager.getCachedDataHash(query, aggregator)); } } }