<commit_before>// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.search.searchchain;

import com.yahoo.component.chain.Chain;
import com.yahoo.language.Linguistics;
import com.yahoo.language.simple.SimpleLinguistics;
import com.yahoo.prelude.IndexFacts;
import com.yahoo.prelude.Ping;
import com.yahoo.prelude.Pong;
import com.yahoo.language.process.SpecialTokenRegistry;
import com.yahoo.processing.Processor;
import com.yahoo.processing.Request;
import com.yahoo.processing.Response;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
import com.yahoo.search.Searcher;
import com.yahoo.search.cluster.PingableSearcher;
import com.yahoo.search.rendering.RendererRegistry;
import com.yahoo.search.statistics.TimeTracker;

import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

/**
 * <p>An execution of a search chain. This keeps track of the call state for an execution (in the calling thread)
 * of the searchers of a search chain.</p>
 *
 * <p>To execute a search chain, simply do
 * <pre>
 *     Result result = new Execution(mySearchChain, execution.context()).search(query)
 * </pre>
 *
 *
 * <p>See also {@link AsyncExecution}, which performs an execution in a separate thread than the caller.</p>
 *
 * <p>Execution instances should not be reused for multiple separate executions.</p>
 *
 * @author bratseth
 */
public class Execution extends com.yahoo.processing.execution.Execution {

    public static final String ATTRIBUTEPREFETCH = "attributeprefetch";

    /**
     * The execution context is the search chain's current view of the indexes,
     * search chain registrys, etc. Searcher instances may set values here to
     * change the behavior of the rest of the search chain.
     * <p>
     * The Context class simply carries a set of objects which define the
     * environment for the search. <b>Important:</b> All objects available through context need to
     * be either truly immutable or support the freeze pattern.
     * <p>
     * If you are implementing a searcher where you need to create a new Context
     * instance to create an Execution, you should use the context from the
     * execution the searcher was invoked from. You can also copy
     * (Context.shallowCopy()) the incoming context if it is necessary to do
     * more. In other words, a minimal example would be:<br>
     * new Execution(searchChain, execution.context())
     */
    public static final class Context {

        /** Whether the search should perform detailed diagnostics. */
        private boolean detailedDiagnostics = false;

        /** Whether the container was considered to be in a breakdown state when this query started. */
        private boolean breakdown = false;

        /**
         * The search chain registry current when this execution was created, or
         * when the registry was first accessed, or null if it was not set on
         * creation or has been accessed yet. No setter method is intentional.
         */
        private SearchChainRegistry searchChainRegistry = null;

        private IndexFacts indexFacts = null;

        /** The current set of special tokens */
        private SpecialTokenRegistry tokenRegistry = null;

        /** The current template registry */
        private RendererRegistry rendererRegistry = null;

        /** The current linguistics */
        private Linguistics linguistics = null;

        private Executor executor;

        /** Always set if this context belongs to an execution, never set if it does not. */
        private final Execution owner;

        // Please don't add more constructors to the public interface of Context
        // unless the constructor is reasonably safe for an inexperienced user
        // in a production setting. Since queries blow up in a spectacular
        // fashion if Context is in a bad state, the Context() constructor is
        // package private.

        /** Create a context used to carry state into another context */
        Context() { this.owner = null; }

        /** Create a context which belongs to an execution */
        Context(Execution owner) { this.owner = owner; }

        /**
         * Creates a context from arguments, all of which may be null, though
         * this can be risky. If you are doing this outside a test, it is
         * usually better to do something like execution.context().shallowCopy()
         * instead, and then set the fields you need to change. It is also safe
         * to use the context from the incoming execution directly. In other
         * words, a plug-in writer should practically never construct a Context
         * instance directly.
         * <p>
         * This context is never attached to an execution but is used to carry state into
         * another context.
         */
        public Context(SearchChainRegistry searchChainRegistry, IndexFacts indexFacts,
                       SpecialTokenRegistry tokenRegistry, RendererRegistry rendererRegistry, Linguistics linguistics,
                       Executor executor) {
            owner = null;
            // Four methods need to be updated when adding something:
            // fill(Context), populateFrom(Context), equals(Context) and,
            // obviously, the most complete constructor.
            this.searchChainRegistry = searchChainRegistry;
            this.indexFacts = indexFacts;
            this.tokenRegistry = tokenRegistry;
            this.rendererRegistry = rendererRegistry;
            this.linguistics = linguistics;
            this.executor = Objects.requireNonNull(executor, "The executor cannot be null");
        }

        /** @deprecated pass an executor */
        @Deprecated // TODO: Remove on Vespa 8
        public Context(SearchChainRegistry searchChainRegistry, IndexFacts indexFacts,
                       SpecialTokenRegistry tokenRegistry, RendererRegistry rendererRegistry, Linguistics linguistics) {
            this(searchChainRegistry, indexFacts, tokenRegistry, rendererRegistry, linguistics, Runnable::run);
        }

        /** Creates a context stub with no information. This is for unit testing. */
        public static Context createContextStub() {
            return createContextStub(null);
        }

        /**
         * Create a Context instance where only the index related settings are
         * initialized. This is for unit testing.
         */
        public static Context createContextStub(IndexFacts indexFacts) {
            return createContextStub(null, indexFacts);
        }

        /**
         * Create a Context instance where only the search chain registry and index facts are
         * initialized. This is for unit testing.
         */
        public static Context createContextStub(SearchChainRegistry searchChainRegistry, IndexFacts indexFacts) {
            return createContextStub(searchChainRegistry, indexFacts, null);
        }

        /**
         * Create a Context instance where only the search chain registry, index facts and linguistics are
         * initialized. This is for unit testing.
         */
        public static Context createContextStub(SearchChainRegistry searchChainRegistry, IndexFacts indexFacts, Linguistics linguistics) {
            return new Context(searchChainRegistry, indexFacts, null, null, linguistics, Executors.newSingleThreadExecutor());
        }

        /**
         * Populate missing values in this from the given context.
         * Values which are non-null in this will not be overwritten.
         *
         * @param sourceContext the context from which to get the parameters
         */
        // TODO: Deprecate
        public void populateFrom(Context sourceContext) {
            // breakdown and detailedDiagnostics has no unset state, so they are always copied
            detailedDiagnostics = sourceContext.detailedDiagnostics;
            breakdown = sourceContext.breakdown;
            if (indexFacts == null)
                indexFacts = sourceContext.indexFacts;
            if (tokenRegistry == null)<commit_msg>Always create a renderer registry<commit_after>// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.search.searchchain;

import com.yahoo.component.chain.Chain;
import com.yahoo.language.Linguistics;
import com.yahoo.language.simple.SimpleLinguistics;
import com.yahoo.prelude.IndexFacts;
import com.yahoo.prelude.Ping;
import com.yahoo.prelude.Pong;
import com.yahoo.language.process.SpecialTokenRegistry;
import com.yahoo.processing.Processor;
import com.yahoo.processing.Request;
import com.yahoo.processing.Response;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
import com.yahoo.search.Searcher;
import com.yahoo.search.cluster.PingableSearcher;
import com.yahoo.search.rendering.Renderer;
import com.yahoo.search.rendering.RendererRegistry;
import com.yahoo.search.statistics.TimeTracker;

import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

/**
 * <p>An execution of a search chain. This keeps track of the call state for an execution (in the calling thread)
 * of the searchers of a search chain.</p>
 *
 * <p>To execute a search chain, simply do
 * <pre>
 *     Result result = new Execution(mySearchChain, execution.context()).search(query)
 * </pre>
 *
 *
 * <p>See also {@link AsyncExecution}, which performs an execution in a separate thread than the caller.</p>
 *
 * <p>Execution instances should not be reused for multiple separate executions.</p>
 *
 * @author bratseth
 */
public class Execution extends com.yahoo.processing.execution.Execution {

    public static final String ATTRIBUTEPREFETCH = "attributeprefetch";

    /**
     * The execution context is the search chain's current view of the indexes,
     * search chain registrys, etc. Searcher instances may set values here to
     * change the behavior of the rest of the search chain.
     * <p>
     * The Context class simply carries a set of objects which define the
     * environment for the search. <b>Important:</b> All objects available through context need to
     * be either truly immutable or support the freeze pattern.
     * <p>
     * If you are implementing a searcher where you need to create a new Context
     * instance to create an Execution, you should use the context from the
     * execution the searcher was invoked from. You can also copy
     * (Context.shallowCopy()) the incoming context if it is necessary to do
     * more. In other words, a minimal example would be:<br>
     * new Execution(searchChain, execution.context())
     */
    public static final class Context {

        /** Whether the search should perform detailed diagnostics. */
        private boolean detailedDiagnostics = false;

        /** Whether the container was considered to be in a breakdown state when this query started. */
        private boolean breakdown = false;

        /**
         * The search chain registry current when this execution was created, or
         * when the registry was first accessed, or null if it was not set on
         * creation or has been accessed yet. No setter method is intentional.
         */
        private SearchChainRegistry searchChainRegistry = null;

        private IndexFacts indexFacts = null;

        /** The current set of special tokens */
        private SpecialTokenRegistry tokenRegistry = null;

        /** The current template registry */
        private RendererRegistry rendererRegistry = null;

        /** The current linguistics */
        private Linguistics linguistics = null;

        private Executor executor;

        /** Always set if this context belongs to an execution, never set if it does not. */
        private final Execution owner;

        // Please don't add more constructors to the public interface of Context
        // unless the constructor is reasonably safe for an inexperienced user
        // in a production setting. Since queries blow up in a spectacular
        // fashion if Context is in a bad state, the Context() constructor is
        // package private.

        /** Create a context used to carry state into another context */
        Context() { this.owner = null; }

        /** Create a context which belongs to an execution */
        Context(Execution owner) { this.owner = owner; }

        /**
         * Creates a context from arguments, all of which may be null, though
         * this can be risky. If you are doing this outside a test, it is
         * usually better to do something like execution.context().shallowCopy()
         * instead, and then set the fields you need to change. It is also safe
         * to use the context from the incoming execution directly. In other
         * words, a plug-in writer should practically never construct a Context
         * instance directly.
         * <p>
         * This context is never attached to an execution but is used to carry state into
         * another context.
         */
        public Context(SearchChainRegistry searchChainRegistry, IndexFacts indexFacts,
                       SpecialTokenRegistry tokenRegistry, RendererRegistry rendererRegistry, Linguistics linguistics,
                       Executor executor) {
            owner = null;
            // Four methods need to be updated when adding something:
            // fill(Context), populateFrom(Context), equals(Context) and,
            // obviously, the most complete constructor.
            this.searchChainRegistry = searchChainRegistry;
            this.indexFacts = indexFacts;
            this.tokenRegistry = tokenRegistry;
            this.rendererRegistry = rendererRegistry;
            this.linguistics = linguistics;
            this.executor = Objects.requireNonNull(executor, "The executor cannot be null");
        }

        /** @deprecated pass an executor */
        @Deprecated // TODO: Remove on Vespa 8
        public Context(SearchChainRegistry searchChainRegistry, IndexFacts indexFacts,
                       SpecialTokenRegistry tokenRegistry, RendererRegistry rendererRegistry, Linguistics linguistics) {
            this(searchChainRegistry, indexFacts, tokenRegistry, rendererRegistry, linguistics, Runnable::run);
        }

        /** Create a Context instance where everything except the given arguments is empty. This is for unit testing.*/
        public static Context createContextStub() {
            return createContextStub(null);
        }

        /** Create a Context instance where everything except the given arguments is empty. This is for unit testing.*/
        public static Context createContextStub(IndexFacts indexFacts) {
            return createContextStub(null, indexFacts);
        }

        /** Create a Context instance where everything except the given arguments is empty. This is for unit testing.*/
        public static Context createContextStub(SearchChainRegistry searchChainRegistry, IndexFacts indexFacts) {
            return createContextStub(searchChainRegistry, indexFacts, null);
        }

        /** Create a Context instance where everything except the given arguments is empty. This is for unit testing.*/
        public static Context createContextStub(SearchChainRegistry searchChainRegistry, IndexFacts indexFacts, Linguistics linguistics) {
            return new Context(searchChainRegistry,
                               indexFacts,
                               null,
                               new RendererRegistry(Runnable::run),
                               linguistics,
                               Executors.newSingleThreadExecutor());
        }

        /**
         * Populate missing values in this from the given context.
         * Values which are non-null in this will not be overwritten.
         *
         * @param sourceContext the context from which to get the parameters
         */
        // TODO: Deprecate
        public void populateFrom(Context sourceContext) {
            // breakdown and detailedDiagnostics has no unset state, so they are always copied
            detailedDiagnostics = sourceContext.detailedDiagnostics;
            breakdown = sourceContext.breakdown;
            if (indexFacts == null)
                indexFacts = sourceContext.indexFacts;
            if (tokenRegistry == null)
{'fraction_non_alphanumeric': 0.06746490001823376, 'fraction_numerical': 0.000364675135233696, 'mean_word_length': 2.6467198581560285, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6818359', 'n_tokens_mistral': 3903, 'n_tokens_neox': 3813, 'n_words': 1598}