aboutsummaryrefslogtreecommitdiffstats
path: root/searchcore/src/vespa/searchcore/proton/matching/match_thread.h
blob: 7467e6c50a6f7e2676a4d43c925599a1dd1c4b58 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#pragma once

#include "i_match_loop_communicator.h"
#include "match_params.h"
#include "matching_stats.h"
#include "result_processor.h"
#include "docid_range_scheduler.h"
#include <vespa/vespalib/util/runnable.h>
#include <vespa/vespalib/util/execution_profiler.h>
#include <vespa/vespalib/util/dual_merge_director.h>
#include <vespa/searchlib/common/resultset.h>
#include <vespa/searchlib/common/sortresults.h>
#include <vespa/searchlib/common/unique_issues.h>
#include <vespa/searchlib/queryeval/hitcollector.h>
#include <vespa/searchlib/fef/featureexecutor.h>

namespace search::engine {
    class Trace;
    class RelativeTime;
}

namespace search::fef {class RankProgram; }

namespace search::queryeval { class SearchIterator; }

namespace proton::matching {

class MatchTools;
class MatchToolsFactory;

/**
 * Runs a single match thread and keeps track of local state.
 **/
class MatchThread : public vespalib::Runnable
{
public:
    using UP = std::unique_ptr<MatchThread>;
    using SearchIterator = search::queryeval::SearchIterator;
    using MatchData = search::fef::MatchData;
    using HitCollector = search::queryeval::HitCollector;
    using RankProgram = search::fef::RankProgram;
    using LazyValue = search::fef::LazyValue;
    using Doom = vespalib::Doom;
    using Trace = search::engine::Trace;
    using RelativeTime = search::engine::RelativeTime;
    using UniqueIssues = search::UniqueIssues;

private:
    enum class RankDropLimitE { no, yes, track};
    size_t                        thread_id;
    size_t                        num_threads;
    MatchParams                   matchParams;
    const MatchToolsFactory      &matchToolsFactory;
    IMatchLoopCommunicator       &communicator;
    DocidRangeScheduler          &scheduler;
    IdleObserver                  idle_observer;
    uint32_t                      _distributionKey;
    ResultProcessor              &resultProcessor;
    vespalib::DualMergeDirector  &mergeDirector;
    std::unique_ptr<ResultProcessor::Context>  resultContext;
    MatchingStats::Partition      thread_stats;
    double                        total_time_s;
    double                        match_time_s;
    double                        wait_time_s;
    bool                          match_with_ranking;
    std::unique_ptr<Trace>        trace;
    std::unique_ptr<vespalib::ExecutionProfiler> match_profiler;
    std::unique_ptr<vespalib::ExecutionProfiler> first_phase_profiler;
    std::unique_ptr<vespalib::ExecutionProfiler> second_phase_profiler;
    UniqueIssues                  my_issues;

    class Context {
    public:
        Context(double rankDropLimit, MatchTools &tools, HitCollector &hits,
                uint32_t num_threads) __attribute__((noinline));
        template <RankDropLimitE use_rank_drop_limit>
        void rankHit(uint32_t docId);
        void addHit(uint32_t docId) { _hits.addHit(docId, search::zero_rank_value); }
        bool isBelowLimit() const { return matches < _matches_limit; }
        bool    isAtLimit() const { return matches == _matches_limit; }
        bool   atSoftDoom() const { return _doom.soft_doom(); }
        vespalib::duration timeLeft() const { return _doom.soft_left(); }
        uint32_t        matches;
    private:
        uint32_t        _matches_limit;
        LazyValue       _score_feature;
        double          _rankDropLimit;
        HitCollector   &_hits;
        const Doom     &_doom;
    public:
        std::vector<uint32_t> dropped;
    };

    double estimate_match_frequency(uint32_t matches, uint32_t searchedSoFar) __attribute__((noinline));
    SearchIterator *maybe_limit(MatchTools &tools, uint32_t matches, uint32_t docId, uint32_t endId) __attribute__((noinline));

    bool any_idle() const { return (idle_observer.get() > 0); }
    bool try_share(DocidRange &docid_range, uint32_t next_docid) __attribute__((noinline));

    template <typename Strategy, bool do_rank, bool do_limit, bool do_share_work, RankDropLimitE use_rank_drop_limit>
    uint32_t inner_match_loop(Context &context, MatchTools &tools, DocidRange &docid_range) __attribute__((noinline));

    template <typename Strategy, bool do_rank, bool do_limit, bool do_share_work, RankDropLimitE use_rank_drop_limit>
    void match_loop(MatchTools &tools, HitCollector &hits) __attribute__((noinline));

    template <bool do_rank, bool do_limit, bool do_share, RankDropLimitE use_rank_drop_limit>
    void match_loop_helper_rank_limit_share_drop(MatchTools &tools, HitCollector &hits);
    template <bool do_rank, bool do_limit, bool do_share> void match_loop_helper_rank_limit_share(MatchTools &tools, HitCollector &hits);
    template <bool do_rank, bool do_limit> void match_loop_helper_rank_limit(MatchTools &tools, HitCollector &hits);
    template <bool do_rank> void match_loop_helper_rank(MatchTools &tools, HitCollector &hits);
    void match_loop_helper(MatchTools &tools, HitCollector &hits);

    search::ResultSet::UP findMatches(MatchTools &tools);
    void secondPhase(MatchTools & tools, HitCollector & hits);

    void processResult(const Doom & doom, search::ResultSet::UP result, ResultProcessor::Context &context);

    bool isFirstThread() const { return thread_id == 0; }

    search::HitRank fallback_rank_value() const { return match_with_ranking ? search::default_rank_value : search::zero_rank_value; }

public:
    MatchThread(size_t thread_id_in,
                size_t num_threads_in,
                const MatchParams &mp,
                const MatchToolsFactory &mtf,
                IMatchLoopCommunicator &com,
                DocidRangeScheduler &sched,
                ResultProcessor &rp,
                vespalib::DualMergeDirector &md,
                uint32_t distributionKey,
                const Trace &parent_trace);
    void run() override;
    const MatchingStats::Partition &get_thread_stats() const { return thread_stats; }
    double get_match_time() const { return match_time_s; }
    std::unique_ptr<PartialResult> extract_result();
    const Trace & getTrace() const { return *trace; }
    const UniqueIssues &get_issues() const { return my_issues; }
};

}