Coverage Report

Created: 2026-10-30 14:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/storage/predicate/shared_predicate.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#pragma once
19
20
#include <atomic>
21
#include <cstdint>
22
#include <memory>
23
24
#include "common/factory_creator.h"
25
#include "core/column/column_dictionary.h"
26
#include "storage/index/bloom_filter/bloom_filter.h"
27
#include "storage/index/inverted/inverted_index_reader.h"
28
#include "storage/predicate/column_predicate.h"
29
30
namespace doris {
31
32
// SharedPredicate only used on topn runtime predicate.
33
// Runtime predicate globally share one predicate, to ensure that updates can be real-time.
34
// At the beginning nested predicate may be nullptr, in which case predicate always returns true.
35
class SharedPredicate final : public ColumnPredicate {
36
    ENABLE_FACTORY_CREATOR(SharedPredicate);
37
38
public:
39
    SharedPredicate(uint32_t column_id, std::string col_name)
40
789
            : ColumnPredicate(column_id, col_name, PrimitiveType::INVALID_TYPE),
41
789
              _mtx(std::make_shared<std::shared_mutex>()) {}
42
    SharedPredicate(const ColumnPredicate& other) = delete;
43
    SharedPredicate(const SharedPredicate& other, uint32_t column_id)
44
0
            : ColumnPredicate(other, column_id), _mtx(std::make_shared<std::shared_mutex>()) {
45
0
        const auto state = other.snapshot();
46
0
        _nested = state.predicate ? state.predicate->clone(column_id) : nullptr;
47
0
        _version.store(state.version, std::memory_order_relaxed);
48
0
    }
49
789
    ~SharedPredicate() override = default;
50
4.62k
    std::string debug_string() const override {
51
4.62k
        std::shared_lock<std::shared_mutex> lock(*_mtx);
52
4.62k
        fmt::memory_buffer debug_string_buffer;
53
4.62k
        fmt::format_to(debug_string_buffer, "SharedPredicate({}, nested={})",
54
4.62k
                       ColumnPredicate::debug_string(), _nested ? _nested->debug_string() : "null");
55
4.62k
        return fmt::to_string(debug_string_buffer);
56
4.62k
    }
57
6.78k
    std::shared_ptr<ColumnPredicate> clone(uint32_t column_id) const override {
58
        // All scanner thread should share the same SharedPredicate object.
59
6.78k
        return std::const_pointer_cast<ColumnPredicate>(shared_from_this());
60
6.78k
    }
61
62
1.44k
    bool is_runtime_filter() const override { return true; }
63
64
31.0k
    PredicateType type() const override {
65
31.0k
        std::shared_lock<std::shared_mutex> lock(*_mtx);
66
31.0k
        if (!_nested) {
67
            // topn filter is le or ge
68
15.8k
            return PredicateType::LE;
69
15.8k
        }
70
15.2k
        return _nested->type();
71
31.0k
    }
72
4.63k
    PrimitiveType primitive_type() const override {
73
4.63k
        std::shared_lock<std::shared_mutex> lock(*_mtx);
74
4.63k
        if (!_nested) {
75
1.49k
            return PrimitiveType::INVALID_TYPE;
76
1.49k
        }
77
3.13k
        return _nested->primitive_type();
78
4.63k
    }
79
80
3.95k
    void set_nested(const std::shared_ptr<ColumnPredicate>& nested) {
81
3.95k
        std::unique_lock<std::shared_mutex> lock(*_mtx);
82
3.95k
        _nested = nested;
83
3.95k
        _version.fetch_add(1, std::memory_order_release);
84
3.95k
    }
85
86
28.0k
    uint64_t version() const { return _version.load(std::memory_order_acquire); }
87
88
    struct Snapshot {
89
        uint64_t version;
90
        std::shared_ptr<const ColumnPredicate> predicate;
91
    };
92
93
    // Keep the immutable comparison alive after releasing the lock. A concurrent update must
94
    // not pair version 2 with version 1's bound, or hold the producer lock during index I/O.
95
1.91k
    Snapshot snapshot() const {
96
1.91k
        std::shared_lock<std::shared_mutex> lock(*_mtx);
97
1.91k
        return {.version = _version.load(std::memory_order_relaxed), .predicate = _nested};
98
1.91k
    }
99
100
    Status evaluate(const IndexFieldNameAndTypePair& name_with_type, IndexIterator* iterator,
101
12
                    uint32_t num_rows, roaring::Roaring* bitmap) const override {
102
12
        std::shared_lock<std::shared_mutex> lock(*_mtx);
103
12
        if (!_nested) {
104
11
            return Status::OK();
105
11
        }
106
1
        return _nested->evaluate(name_with_type, iterator, num_rows, bitmap);
107
12
    }
108
109
    void evaluate_and(const IColumn& column, const uint16_t* sel, uint16_t size,
110
0
                      bool* flags) const override {
111
0
        std::shared_lock<std::shared_mutex> lock(*_mtx);
112
0
        if (!_nested) {
113
0
            return;
114
0
        }
115
0
        return _nested->evaluate_and(column, sel, size, flags);
116
0
    }
117
118
    void evaluate_or(const IColumn& column, const uint16_t* sel, uint16_t size,
119
0
                     bool* flags) const override {
120
0
        DCHECK(false) << "should not reach here";
121
0
    }
122
123
23.9k
    bool evaluate_and(const segment_v2::ZoneMap& zone_map) const override {
124
23.9k
        std::shared_lock<std::shared_mutex> lock(*_mtx);
125
23.9k
        if (!_nested) {
126
11.8k
            return ColumnPredicate::evaluate_and(zone_map);
127
11.8k
        }
128
12.1k
        return _nested->evaluate_and(zone_map);
129
23.9k
    }
130
131
0
    bool evaluate_del(const segment_v2::ZoneMap& zone_map) const override {
132
0
        std::shared_lock<std::shared_mutex> lock(*_mtx);
133
0
        if (!_nested) {
134
0
            return ColumnPredicate::evaluate_del(zone_map);
135
0
        }
136
0
        return _nested->evaluate_del(zone_map);
137
0
    }
138
139
0
    bool evaluate_and(const BloomFilter* bf) const override {
140
0
        std::shared_lock<std::shared_mutex> lock(*_mtx);
141
0
        if (!_nested) {
142
0
            return ColumnPredicate::evaluate_and(bf);
143
0
        }
144
0
        return _nested->evaluate_and(bf);
145
0
    }
146
147
13.4k
    bool can_do_bloom_filter(bool ngram) const override {
148
13.4k
        std::shared_lock<std::shared_mutex> lock(*_mtx);
149
13.4k
        if (!_nested) {
150
8.52k
            return ColumnPredicate::can_do_bloom_filter(ngram);
151
8.52k
        }
152
4.91k
        return _nested->can_do_bloom_filter(ngram);
153
13.4k
    }
154
155
10.0k
    void evaluate_vec(const IColumn& column, uint16_t size, bool* flags) const override {
156
10.0k
        std::shared_lock<std::shared_mutex> lock(*_mtx);
157
10.0k
        if (!_nested) {
158
8.52M
            for (uint16_t i = 0; i < size; ++i) {
159
8.52M
                flags[i] = true;
160
8.52M
            }
161
4.52k
            return;
162
4.52k
        }
163
5.49k
        _nested->evaluate_vec(column, size, flags);
164
5.49k
    }
165
166
1.21k
    void evaluate_and_vec(const IColumn& column, uint16_t size, bool* flags) const override {
167
1.21k
        std::shared_lock<std::shared_mutex> lock(*_mtx);
168
1.21k
        if (!_nested) {
169
580
            return;
170
580
        }
171
630
        _nested->evaluate_and_vec(column, size, flags);
172
630
    }
173
174
0
    std::string get_search_str() const override {
175
0
        std::shared_lock<std::shared_mutex> lock(*_mtx);
176
0
        if (!_nested) {
177
0
            DCHECK(false) << "should not reach here";
178
0
        }
179
0
        return _nested->get_search_str();
180
0
    }
181
182
0
    bool evaluate_and(ParquetPredicate::ColumnStat* statistic) const override {
183
0
        std::shared_lock<std::shared_mutex> lock(*_mtx);
184
0
        if (!_nested) {
185
            // at the begining _nested will be null, so return true.
186
0
            return true;
187
0
        }
188
0
        return _nested->evaluate_and(statistic);
189
0
    }
190
191
    bool evaluate_and(ParquetPredicate::CachedPageIndexStat* statistic,
192
0
                      RowRanges* row_ranges) const override {
193
0
        std::shared_lock<std::shared_mutex> lock(*_mtx);
194
195
0
        if (!_nested) {
196
            // at the begining _nested will be null, so return true.
197
0
            row_ranges->add(statistic->row_group_range);
198
0
            return true;
199
0
        }
200
0
        return _nested->evaluate_and(statistic, row_ranges);
201
0
    }
202
203
private:
204
400
    uint16_t _evaluate_inner(const IColumn& column, uint16_t* sel, uint16_t size) const override {
205
400
        std::shared_lock<std::shared_mutex> lock(*_mtx);
206
400
        if (!_nested) {
207
96
            return size;
208
96
        }
209
304
        return _nested->evaluate(column, sel, size);
210
400
    }
211
212
    mutable std::shared_ptr<std::shared_mutex> _mtx;
213
    std::shared_ptr<ColumnPredicate> _nested;
214
    std::atomic<uint64_t> _version {0};
215
};
216
217
} //namespace doris