<commit_before>
/*
 * Carrot2 project.
 *
 * Copyright (C) 2002-2012, <NAME>, <NAME>.
 * All rights reserved.
 *
 * Refer to the full license file "carrot2.LICENSE"
 * in the root folder of the repository checkout or at:
 * http://www.carrot2.org/carrot2.LICENSE
 */

package org.carrot2.core;

import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;

import org.carrot2.core.Controller.IControllerStatisticsProvider;
import org.carrot2.core.attribute.Processing;
import org.carrot2.util.ExceptionUtils;
import org.carrot2.util.Pair;
import org.carrot2.util.attribute.*;

import com.google.common.cache.*;
import com.google.common.collect.*;
import com.google.common.util.concurrent.UncheckedExecutionException;

/**
 * An {@link IProcessingComponentManager} that implements processing results caching
 * functionality.
 * <p>
 * This manager wraps some delegate manager (e.g. a
 * {@link SimpleProcessingComponentManager} or a {@link PoolingProcessingComponentManager}
 * ) and wraps the components the delegate with a functionality that either returns the
 * results from cache or performs the processing if the result are not yet cached.
 * </p>
 */
public class CachingProcessingComponentManager implements IProcessingComponentManager,
    Controller.IControllerStatisticsProvider
{
    /** The delegate manager that prepares the actual processing components */
    final IProcessingComponentManager delegate;

    /**
     * Descriptors of {@link Input} and {@link Output} {@link Processing} attributes of
     * components whose output is to be cached.
     */
    private final Map<Pair<Class<? extends IProcessingComponent>, String>, InputOutputAttributeDescriptors> cachedComponentAttributeDescriptors = Maps
        .newHashMap();

    /**
     * A set of {@link IProcessingComponent}s whose data should be cached internally.
     */
    final Set<Class<? extends IProcessingComponent>> cachedComponentClasses;

    /**
     * Populates on-demand and caches the data from components of classes provided in
     * {@link #cachedComponentClasses}. The key of the cache is a map of all {@link Input}
     * {@link Processing} attributes of the component for which caching is performed. The
     * value of the cache is a map of all {@link Output} {@link Processing} attributes
     * produced by the component.
     */
    private Cache<AttributeMapCacheKey, Map<String,Object>> cache;

    /** Cache statistics keys. */
    static final String CACHE_MISSES = "cache.misses";
    static final String CACHE_HITS_TOTAL = "cache.hits.total";

    /**
     * Creates a {@link CachingProcessingComponentManager}.
     * 
     * @param delegate the manager to handle the preparation of the actual processing
     *            component instances
     * @param cachedComponentClasses classes of components whose output should be cached
     *            by the controller. If a superclass is provided here, e.g.
     *            {@link IDocumentSource}, all its subclasses will be subject to caching.
     *            If {@link IProcessingComponent} is provided here, output of all
     *            components will be cached.
     */
    public CachingProcessingComponentManager(IProcessingComponentManager delegate,
        Class<? extends IProcessingComponent>... cachedComponentClasses)
    {
        this.delegate = delegate;
        this.cachedComponentClasses = ImmutableSet.copyOf(cachedComponentClasses);

        // Initialize cache.
        cache = CacheBuilder.newBuilder()
            .maximumSize(100)
            .recordStats()
            .weakValues()
            .build();
    }

    public void init(IControllerContext context, Map<String, Object> attributes,
        ProcessingComponentConfiguration... configurations)
    {
        delegate.init(context, attributes, configurations);
    }

    public IProcessingComponent prepare(Class<? extends IProcessingComponent> clazz,
        String id, Map<String, Object> inputAttributes,
        Map<String, Object> outputAttributes)
    {
        // If the processing component is to be cached, wrap with our internal
        // processing component implementation that will do the caching.

        // One very important implementation detail is that the only moment we can pass
        // all input attributes (including the processing-time ones) to the component
        // wrapper is here when we create it. For this reason, the controller needs to
        // pass all attributes at this state, even though the other manager will likely
        // use only the init-time attributes. The same goes for output attributes,
        // these will be collected to the map we provide during the creation of the
        // wrapper.
        for (Class<?> cachedClass : cachedComponentClasses)
        {<commit_msg>CARROT-926: Assertion failed on testStress. Very likely a regression bug introduced as part of switching to Guava Cache. The default specification asked for weakValues() whereas the previous behavior (and assumptions) were tuned for hard referenced values.<commit_after>
/*
 * Carrot2 project.
 *
 * Copyright (C) 2002-2012, <NAME>, <NAME>.
 * All rights reserved.
 *
 * Refer to the full license file "carrot2.LICENSE"
 * in the root folder of the repository checkout or at:
 * http://www.carrot2.org/carrot2.LICENSE
 */

package org.carrot2.core;

import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;

import org.carrot2.core.Controller.IControllerStatisticsProvider;
import org.carrot2.core.attribute.Processing;
import org.carrot2.util.ExceptionUtils;
import org.carrot2.util.Pair;
import org.carrot2.util.attribute.*;

import com.google.common.cache.*;
import com.google.common.collect.*;
import com.google.common.util.concurrent.UncheckedExecutionException;

/**
 * An {@link IProcessingComponentManager} that implements processing results caching
 * functionality.
 * <p>
 * This manager wraps some delegate manager (e.g. a
 * {@link SimpleProcessingComponentManager} or a {@link PoolingProcessingComponentManager}
 * ) and wraps the components the delegate with a functionality that either returns the
 * results from cache or performs the processing if the result are not yet cached.
 * </p>
 */
public class CachingProcessingComponentManager implements IProcessingComponentManager,
    Controller.IControllerStatisticsProvider
{
    /** The delegate manager that prepares the actual processing components */
    final IProcessingComponentManager delegate;

    /**
     * Descriptors of {@link Input} and {@link Output} {@link Processing} attributes of
     * components whose output is to be cached.
     */
    private final Map<Pair<Class<? extends IProcessingComponent>, String>, InputOutputAttributeDescriptors> cachedComponentAttributeDescriptors = Maps
        .newHashMap();

    /**
     * A set of {@link IProcessingComponent}s whose data should be cached internally.
     */
    final Set<Class<? extends IProcessingComponent>> cachedComponentClasses;

    /**
     * Populates on-demand and caches the data from components of classes provided in
     * {@link #cachedComponentClasses}. The key of the cache is a map of all {@link Input}
     * {@link Processing} attributes of the component for which caching is performed. The
     * value of the cache is a map of all {@link Output} {@link Processing} attributes
     * produced by the component.
     */
    private Cache<AttributeMapCacheKey, Map<String,Object>> cache;

    /** Cache statistics keys. */
    static final String CACHE_MISSES = "cache.misses";
    static final String CACHE_HITS_TOTAL = "cache.hits.total";

    /**
     * Creates a {@link CachingProcessingComponentManager}.
     * 
     * @param delegate the manager to handle the preparation of the actual processing
     *            component instances
     * @param cachedComponentClasses classes of components whose output should be cached
     *            by the controller. If a superclass is provided here, e.g.
     *            {@link IDocumentSource}, all its subclasses will be subject to caching.
     *            If {@link IProcessingComponent} is provided here, output of all
     *            components will be cached.
     */
    public CachingProcessingComponentManager(IProcessingComponentManager delegate,
        Class<? extends IProcessingComponent>... cachedComponentClasses)
    {
        this.delegate = delegate;
        this.cachedComponentClasses = ImmutableSet.copyOf(cachedComponentClasses);

        // Initialize cache.
        cache = CacheBuilder.newBuilder()
            .maximumSize(100)
            .recordStats()
            .build();
    }

    public void init(IControllerContext context, Map<String, Object> attributes,
        ProcessingComponentConfiguration... configurations)
    {
        delegate.init(context, attributes, configurations);
    }

    public IProcessingComponent prepare(Class<? extends IProcessingComponent> clazz,
        String id, Map<String, Object> inputAttributes,
        Map<String, Object> outputAttributes)
    {
        // If the processing component is to be cached, wrap with our internal
        // processing component implementation that will do the caching.

        // One very important implementation detail is that the only moment we can pass
        // all input attributes (including the processing-time ones) to the component
        // wrapper is here when we create it. For this reason, the controller needs to
        // pass all attributes at this state, even though the other manager will likely
        // use only the init-time attributes. The same goes for output attributes,
        // these will be collected to the map we provide during the creation of the
        // wrapper.
        for (Class<?> cachedClass : cachedComponentClasses)
        {
{'fraction_non_alphanumeric': 0.0780062810252254, 'fraction_numerical': 0.004558808631344342, 'mean_word_length': 3.2625215889464596, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7252514', 'n_tokens_mistral': 2398, 'n_tokens_neox': 2333, 'n_words': 926}