Coverage Report

Created: 2026-07-08 17:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/exec/operator/materialization_opertor.cpp
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
#include "exec/operator/materialization_opertor.h"
19
20
#include <bthread/countdown_event.h>
21
#include <fmt/format.h>
22
#include <gen_cpp/internal_service.pb.h>
23
24
#include <set>
25
#include <sstream>
26
#include <utility>
27
28
#include "cloud/config.h"
29
#include "common/config.h"
30
#include "common/status.h"
31
#include "core/block/block.h"
32
#include "core/column/column.h"
33
#include "exec/operator/operator.h"
34
#include "exec/rowid_fetcher.h"
35
#include "exec/scan/file_scanner.h"
36
#include "util/brpc_client_cache.h"
37
#include "util/brpc_closure.h"
38
#include "util/pretty_printer.h"
39
40
namespace doris {
41
42
namespace {
43
44
constexpr const char* TOPN_LAZY_MAT_PHASE2_PER_BACKEND =
45
        "TopNLazyMaterializationSecondPhasePerBackend";
46
constexpr const char* TOPN_LAZY_MAT_PHASE2_PER_BACKEND_ROWS_READ =
47
        "TopNLazyMaterializationSecondPhasePerBackendRowsRead";
48
constexpr const char* TOPN_LAZY_MAT_PHASE2_PER_BACKEND_SEGMENTS_READ =
49
        "TopNLazyMaterializationSecondPhasePerBackendSegmentsRead";
50
constexpr const char* TOPN_LAZY_MAT_PHASE2_PER_BACKEND_LOCAL_IO_COUNT =
51
        "TopNLazyMaterializationSecondPhasePerBackendLocalIOCount";
52
constexpr const char* TOPN_LAZY_MAT_PHASE2_PER_BACKEND_LOCAL_IO_BYTES =
53
        "TopNLazyMaterializationSecondPhasePerBackendLocalIOBytes";
54
constexpr const char* TOPN_LAZY_MAT_PHASE2_PER_BACKEND_REMOTE_IO_COUNT =
55
        "TopNLazyMaterializationSecondPhasePerBackendRemoteIOCount";
56
constexpr const char* TOPN_LAZY_MAT_PHASE2_PER_BACKEND_REMOTE_IO_BYTES =
57
        "TopNLazyMaterializationSecondPhasePerBackendRemoteIOBytes";
58
constexpr const char* TOPN_LAZY_MAT_PHASE2_PER_BACKEND_SKIP_CACHE_IO_COUNT =
59
        "TopNLazyMaterializationSecondPhasePerBackendSkipCacheIOCount";
60
constexpr const char* TOPN_LAZY_MAT_PHASE2_PER_BACKEND_WRITE_CACHE_BYTES =
61
        "TopNLazyMaterializationSecondPhasePerBackendWriteCacheBytes";
62
constexpr const char* TOPN_LAZY_MAT_PHASE2_PER_BACKEND_LOCAL_IO_TIME =
63
        "TopNLazyMaterializationSecondPhasePerBackendLocalIOTime";
64
constexpr const char* TOPN_LAZY_MAT_PHASE2_PER_BACKEND_REMOTE_IO_TIME =
65
        "TopNLazyMaterializationSecondPhasePerBackendRemoteIOTime";
66
constexpr const char* TOPN_LAZY_MAT_PHASE2_PER_BACKEND_WRITE_CACHE_IO_TIME =
67
        "TopNLazyMaterializationSecondPhasePerBackendWriteCacheIOTime";
68
69
void update_counter(RuntimeProfile* profile, const std::string& name, TUnit::type unit,
70
16
                    int64_t value) {
71
16
    COUNTER_UPDATE(ADD_COUNTER_WITH_LEVEL(profile, name, unit, 2), value);
72
16
}
73
74
void update_topn_lazy_materialization_profile(RuntimeProfile* profile,
75
0
                                              const PTopNLazyMaterializationFileCacheStats& stats) {
76
0
    if (profile == nullptr) {
77
0
        return;
78
0
    }
79
0
    update_counter(profile, RowIdStorageReader::TopNLazyMaterializationSecondPhaseLocalIOCount,
80
0
                   TUnit::UNIT, stats.local_io_count());
81
0
    update_counter(profile, RowIdStorageReader::TopNLazyMaterializationSecondPhaseLocalIOBytes,
82
0
                   TUnit::BYTES, stats.local_io_bytes());
83
0
    update_counter(profile, RowIdStorageReader::TopNLazyMaterializationSecondPhaseRemoteIOCount,
84
0
                   TUnit::UNIT, stats.remote_io_count());
85
0
    update_counter(profile, RowIdStorageReader::TopNLazyMaterializationSecondPhaseRemoteIOBytes,
86
0
                   TUnit::BYTES, stats.remote_io_bytes());
87
0
    update_counter(profile, RowIdStorageReader::TopNLazyMaterializationSecondPhaseSkipCacheIOCount,
88
0
                   TUnit::UNIT, stats.skip_cache_io_count());
89
0
    update_counter(profile, RowIdStorageReader::TopNLazyMaterializationSecondPhaseWriteCacheBytes,
90
0
                   TUnit::BYTES, stats.write_cache_bytes());
91
0
    update_counter(profile, RowIdStorageReader::TopNLazyMaterializationSecondPhaseLocalIOTime,
92
0
                   TUnit::TIME_NS, stats.local_io_time());
93
0
    update_counter(profile, RowIdStorageReader::TopNLazyMaterializationSecondPhaseRemoteIOTime,
94
0
                   TUnit::TIME_NS, stats.remote_io_time());
95
0
    update_counter(profile, RowIdStorageReader::TopNLazyMaterializationSecondPhaseWriteCacheIOTime,
96
0
                   TUnit::TIME_NS, stats.write_cache_io_time());
97
0
}
98
99
8
int64_t count_request_rows(const PMultiGetRequestV2& request) {
100
8
    int64_t rows = 0;
101
12
    for (const auto& request_block_desc : request.request_block_descs()) {
102
12
        rows += request_block_desc.row_id_size();
103
12
    }
104
8
    return rows;
105
8
}
106
107
8
int64_t count_request_segments(const PMultiGetRequestV2& request) {
108
8
    std::set<uint32_t> file_ids;
109
12
    for (const auto& request_block_desc : request.request_block_descs()) {
110
12
        DCHECK_EQ(request_block_desc.file_id_size(), request_block_desc.row_id_size());
111
12
        for (const auto file_id : request_block_desc.file_id()) {
112
11
            file_ids.insert(file_id);
113
11
        }
114
12
    }
115
8
    return file_ids.size();
116
8
}
117
118
template <typename AppendValue>
119
48
std::string format_array(size_t size, AppendValue append_value) {
120
48
    std::stringstream values;
121
48
    values << "[";
122
144
    for (size_t i = 0; i < size; ++i) {
123
96
        append_value(values, i);
124
96
        values << ", ";
125
96
    }
126
48
    values << "]";
127
48
    return values.str();
128
48
}
materialization_opertor.cpp:_ZN5doris12_GLOBAL__N_112format_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_0EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmT_
Line
Count
Source
119
4
std::string format_array(size_t size, AppendValue append_value) {
120
4
    std::stringstream values;
121
4
    values << "[";
122
12
    for (size_t i = 0; i < size; ++i) {
123
8
        append_value(values, i);
124
8
        values << ", ";
125
8
    }
126
4
    values << "]";
127
4
    return values.str();
128
4
}
materialization_opertor.cpp:_ZN5doris12_GLOBAL__N_112format_arrayIZNS0_20format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_1EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_EUlRNS7_18basic_stringstreamIcSA_SB_EEmE_EESC_mSF_
Line
Count
Source
119
4
std::string format_array(size_t size, AppendValue append_value) {
120
4
    std::stringstream values;
121
4
    values << "[";
122
12
    for (size_t i = 0; i < size; ++i) {
123
8
        append_value(values, i);
124
8
        values << ", ";
125
8
    }
126
4
    values << "]";
127
4
    return values.str();
128
4
}
materialization_opertor.cpp:_ZN5doris12_GLOBAL__N_112format_arrayIZNS0_20format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_2EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_EUlRNS7_18basic_stringstreamIcSA_SB_EEmE_EESC_mSF_
Line
Count
Source
119
4
std::string format_array(size_t size, AppendValue append_value) {
120
4
    std::stringstream values;
121
4
    values << "[";
122
12
    for (size_t i = 0; i < size; ++i) {
123
8
        append_value(values, i);
124
8
        values << ", ";
125
8
    }
126
4
    values << "]";
127
4
    return values.str();
128
4
}
materialization_opertor.cpp:_ZN5doris12_GLOBAL__N_112format_arrayIZNS0_20format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_3EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_EUlRNS7_18basic_stringstreamIcSA_SB_EEmE_EESC_mSF_
Line
Count
Source
119
4
std::string format_array(size_t size, AppendValue append_value) {
120
4
    std::stringstream values;
121
4
    values << "[";
122
12
    for (size_t i = 0; i < size; ++i) {
123
8
        append_value(values, i);
124
8
        values << ", ";
125
8
    }
126
4
    values << "]";
127
4
    return values.str();
128
4
}
materialization_opertor.cpp:_ZN5doris12_GLOBAL__N_112format_arrayIZNS0_20format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_4EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_EUlRNS7_18basic_stringstreamIcSA_SB_EEmE_EESC_mSF_
Line
Count
Source
119
4
std::string format_array(size_t size, AppendValue append_value) {
120
4
    std::stringstream values;
121
4
    values << "[";
122
12
    for (size_t i = 0; i < size; ++i) {
123
8
        append_value(values, i);
124
8
        values << ", ";
125
8
    }
126
4
    values << "]";
127
4
    return values.str();
128
4
}
materialization_opertor.cpp:_ZN5doris12_GLOBAL__N_112format_arrayIZNS0_20format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_5EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_EUlRNS7_18basic_stringstreamIcSA_SB_EEmE_EESC_mSF_
Line
Count
Source
119
4
std::string format_array(size_t size, AppendValue append_value) {
120
4
    std::stringstream values;
121
4
    values << "[";
122
12
    for (size_t i = 0; i < size; ++i) {
123
8
        append_value(values, i);
124
8
        values << ", ";
125
8
    }
126
4
    values << "]";
127
4
    return values.str();
128
4
}
materialization_opertor.cpp:_ZN5doris12_GLOBAL__N_112format_arrayIZNS0_20format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_6EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_EUlRNS7_18basic_stringstreamIcSA_SB_EEmE_EESC_mSF_
Line
Count
Source
119
4
std::string format_array(size_t size, AppendValue append_value) {
120
4
    std::stringstream values;
121
4
    values << "[";
122
12
    for (size_t i = 0; i < size; ++i) {
123
8
        append_value(values, i);
124
8
        values << ", ";
125
8
    }
126
4
    values << "]";
127
4
    return values.str();
128
4
}
materialization_opertor.cpp:_ZN5doris12_GLOBAL__N_112format_arrayIZNS0_20format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_7EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_EUlRNS7_18basic_stringstreamIcSA_SB_EEmE_EESC_mSF_
Line
Count
Source
119
4
std::string format_array(size_t size, AppendValue append_value) {
120
4
    std::stringstream values;
121
4
    values << "[";
122
12
    for (size_t i = 0; i < size; ++i) {
123
8
        append_value(values, i);
124
8
        values << ", ";
125
8
    }
126
4
    values << "]";
127
4
    return values.str();
128
4
}
materialization_opertor.cpp:_ZN5doris12_GLOBAL__N_112format_arrayIZNS0_20format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_8EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_EUlRNS7_18basic_stringstreamIcSA_SB_EEmE_EESC_mSF_
Line
Count
Source
119
4
std::string format_array(size_t size, AppendValue append_value) {
120
4
    std::stringstream values;
121
4
    values << "[";
122
12
    for (size_t i = 0; i < size; ++i) {
123
8
        append_value(values, i);
124
8
        values << ", ";
125
8
    }
126
4
    values << "]";
127
4
    return values.str();
128
4
}
materialization_opertor.cpp:_ZN5doris12_GLOBAL__N_112format_arrayIZNS0_20format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_9EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_EUlRNS7_18basic_stringstreamIcSA_SB_EEmE_EESC_mSF_
Line
Count
Source
119
4
std::string format_array(size_t size, AppendValue append_value) {
120
4
    std::stringstream values;
121
4
    values << "[";
122
12
    for (size_t i = 0; i < size; ++i) {
123
8
        append_value(values, i);
124
8
        values << ", ";
125
8
    }
126
4
    values << "]";
127
4
    return values.str();
128
4
}
materialization_opertor.cpp:_ZN5doris12_GLOBAL__N_112format_arrayIZNS0_20format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE4$_10EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_EUlRNS7_18basic_stringstreamIcSA_SB_EEmE_EESC_mSF_
Line
Count
Source
119
4
std::string format_array(size_t size, AppendValue append_value) {
120
4
    std::stringstream values;
121
4
    values << "[";
122
12
    for (size_t i = 0; i < size; ++i) {
123
8
        append_value(values, i);
124
8
        values << ", ";
125
8
    }
126
4
    values << "]";
127
4
    return values.str();
128
4
}
materialization_opertor.cpp:_ZN5doris12_GLOBAL__N_112format_arrayIZNS0_20format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE4$_11EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_EUlRNS7_18basic_stringstreamIcSA_SB_EEmE_EESC_mSF_
Line
Count
Source
119
4
std::string format_array(size_t size, AppendValue append_value) {
120
4
    std::stringstream values;
121
4
    values << "[";
122
12
    for (size_t i = 0; i < size; ++i) {
123
8
        append_value(values, i);
124
8
        values << ", ";
125
8
    }
126
4
    values << "]";
127
4
    return values.str();
128
4
}
129
130
template <typename GetValue>
131
44
std::string format_counter_array(size_t size, TUnit::type unit, GetValue get_value) {
132
88
    return format_array(size, [&](std::stringstream& values, size_t i) {
133
88
        values << PrettyPrinter::print(static_cast<int64_t>(get_value(i)), unit);
134
88
    });
materialization_opertor.cpp:_ZZN5doris12_GLOBAL__N_120format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_1EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_ENKUlRNS6_18basic_stringstreamIcS9_SA_EEmE_clESH_m
Line
Count
Source
132
8
    return format_array(size, [&](std::stringstream& values, size_t i) {
133
8
        values << PrettyPrinter::print(static_cast<int64_t>(get_value(i)), unit);
134
8
    });
materialization_opertor.cpp:_ZZN5doris12_GLOBAL__N_120format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_2EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_ENKUlRNS6_18basic_stringstreamIcS9_SA_EEmE_clESH_m
Line
Count
Source
132
8
    return format_array(size, [&](std::stringstream& values, size_t i) {
133
8
        values << PrettyPrinter::print(static_cast<int64_t>(get_value(i)), unit);
134
8
    });
materialization_opertor.cpp:_ZZN5doris12_GLOBAL__N_120format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_3EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_ENKUlRNS6_18basic_stringstreamIcS9_SA_EEmE_clESH_m
Line
Count
Source
132
8
    return format_array(size, [&](std::stringstream& values, size_t i) {
133
8
        values << PrettyPrinter::print(static_cast<int64_t>(get_value(i)), unit);
134
8
    });
materialization_opertor.cpp:_ZZN5doris12_GLOBAL__N_120format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_4EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_ENKUlRNS6_18basic_stringstreamIcS9_SA_EEmE_clESH_m
Line
Count
Source
132
8
    return format_array(size, [&](std::stringstream& values, size_t i) {
133
8
        values << PrettyPrinter::print(static_cast<int64_t>(get_value(i)), unit);
134
8
    });
materialization_opertor.cpp:_ZZN5doris12_GLOBAL__N_120format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_5EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_ENKUlRNS6_18basic_stringstreamIcS9_SA_EEmE_clESH_m
Line
Count
Source
132
8
    return format_array(size, [&](std::stringstream& values, size_t i) {
133
8
        values << PrettyPrinter::print(static_cast<int64_t>(get_value(i)), unit);
134
8
    });
materialization_opertor.cpp:_ZZN5doris12_GLOBAL__N_120format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_6EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_ENKUlRNS6_18basic_stringstreamIcS9_SA_EEmE_clESH_m
Line
Count
Source
132
8
    return format_array(size, [&](std::stringstream& values, size_t i) {
133
8
        values << PrettyPrinter::print(static_cast<int64_t>(get_value(i)), unit);
134
8
    });
materialization_opertor.cpp:_ZZN5doris12_GLOBAL__N_120format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_7EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_ENKUlRNS6_18basic_stringstreamIcS9_SA_EEmE_clESH_m
Line
Count
Source
132
8
    return format_array(size, [&](std::stringstream& values, size_t i) {
133
8
        values << PrettyPrinter::print(static_cast<int64_t>(get_value(i)), unit);
134
8
    });
materialization_opertor.cpp:_ZZN5doris12_GLOBAL__N_120format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_8EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_ENKUlRNS6_18basic_stringstreamIcS9_SA_EEmE_clESH_m
Line
Count
Source
132
8
    return format_array(size, [&](std::stringstream& values, size_t i) {
133
8
        values << PrettyPrinter::print(static_cast<int64_t>(get_value(i)), unit);
134
8
    });
materialization_opertor.cpp:_ZZN5doris12_GLOBAL__N_120format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_9EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_ENKUlRNS6_18basic_stringstreamIcS9_SA_EEmE_clESH_m
Line
Count
Source
132
8
    return format_array(size, [&](std::stringstream& values, size_t i) {
133
8
        values << PrettyPrinter::print(static_cast<int64_t>(get_value(i)), unit);
134
8
    });
materialization_opertor.cpp:_ZZN5doris12_GLOBAL__N_120format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE4$_10EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_ENKUlRNS6_18basic_stringstreamIcS9_SA_EEmE_clESH_m
Line
Count
Source
132
8
    return format_array(size, [&](std::stringstream& values, size_t i) {
133
8
        values << PrettyPrinter::print(static_cast<int64_t>(get_value(i)), unit);
134
8
    });
materialization_opertor.cpp:_ZZN5doris12_GLOBAL__N_120format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE4$_11EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_ENKUlRNS6_18basic_stringstreamIcS9_SA_EEmE_clESH_m
Line
Count
Source
132
8
    return format_array(size, [&](std::stringstream& values, size_t i) {
133
8
        values << PrettyPrinter::print(static_cast<int64_t>(get_value(i)), unit);
134
8
    });
135
44
}
materialization_opertor.cpp:_ZN5doris12_GLOBAL__N_120format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_1EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_
Line
Count
Source
131
4
std::string format_counter_array(size_t size, TUnit::type unit, GetValue get_value) {
132
4
    return format_array(size, [&](std::stringstream& values, size_t i) {
133
4
        values << PrettyPrinter::print(static_cast<int64_t>(get_value(i)), unit);
134
4
    });
135
4
}
materialization_opertor.cpp:_ZN5doris12_GLOBAL__N_120format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_2EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_
Line
Count
Source
131
4
std::string format_counter_array(size_t size, TUnit::type unit, GetValue get_value) {
132
4
    return format_array(size, [&](std::stringstream& values, size_t i) {
133
4
        values << PrettyPrinter::print(static_cast<int64_t>(get_value(i)), unit);
134
4
    });
135
4
}
materialization_opertor.cpp:_ZN5doris12_GLOBAL__N_120format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_3EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_
Line
Count
Source
131
4
std::string format_counter_array(size_t size, TUnit::type unit, GetValue get_value) {
132
4
    return format_array(size, [&](std::stringstream& values, size_t i) {
133
4
        values << PrettyPrinter::print(static_cast<int64_t>(get_value(i)), unit);
134
4
    });
135
4
}
materialization_opertor.cpp:_ZN5doris12_GLOBAL__N_120format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_4EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_
Line
Count
Source
131
4
std::string format_counter_array(size_t size, TUnit::type unit, GetValue get_value) {
132
4
    return format_array(size, [&](std::stringstream& values, size_t i) {
133
4
        values << PrettyPrinter::print(static_cast<int64_t>(get_value(i)), unit);
134
4
    });
135
4
}
materialization_opertor.cpp:_ZN5doris12_GLOBAL__N_120format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_5EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_
Line
Count
Source
131
4
std::string format_counter_array(size_t size, TUnit::type unit, GetValue get_value) {
132
4
    return format_array(size, [&](std::stringstream& values, size_t i) {
133
4
        values << PrettyPrinter::print(static_cast<int64_t>(get_value(i)), unit);
134
4
    });
135
4
}
materialization_opertor.cpp:_ZN5doris12_GLOBAL__N_120format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_6EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_
Line
Count
Source
131
4
std::string format_counter_array(size_t size, TUnit::type unit, GetValue get_value) {
132
4
    return format_array(size, [&](std::stringstream& values, size_t i) {
133
4
        values << PrettyPrinter::print(static_cast<int64_t>(get_value(i)), unit);
134
4
    });
135
4
}
materialization_opertor.cpp:_ZN5doris12_GLOBAL__N_120format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_7EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_
Line
Count
Source
131
4
std::string format_counter_array(size_t size, TUnit::type unit, GetValue get_value) {
132
4
    return format_array(size, [&](std::stringstream& values, size_t i) {
133
4
        values << PrettyPrinter::print(static_cast<int64_t>(get_value(i)), unit);
134
4
    });
135
4
}
materialization_opertor.cpp:_ZN5doris12_GLOBAL__N_120format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_8EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_
Line
Count
Source
131
4
std::string format_counter_array(size_t size, TUnit::type unit, GetValue get_value) {
132
4
    return format_array(size, [&](std::stringstream& values, size_t i) {
133
4
        values << PrettyPrinter::print(static_cast<int64_t>(get_value(i)), unit);
134
4
    });
135
4
}
materialization_opertor.cpp:_ZN5doris12_GLOBAL__N_120format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE3$_9EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_
Line
Count
Source
131
4
std::string format_counter_array(size_t size, TUnit::type unit, GetValue get_value) {
132
4
    return format_array(size, [&](std::stringstream& values, size_t i) {
133
4
        values << PrettyPrinter::print(static_cast<int64_t>(get_value(i)), unit);
134
4
    });
135
4
}
materialization_opertor.cpp:_ZN5doris12_GLOBAL__N_120format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE4$_10EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_
Line
Count
Source
131
4
std::string format_counter_array(size_t size, TUnit::type unit, GetValue get_value) {
132
4
    return format_array(size, [&](std::stringstream& values, size_t i) {
133
4
        values << PrettyPrinter::print(static_cast<int64_t>(get_value(i)), unit);
134
4
    });
135
4
}
materialization_opertor.cpp:_ZN5doris12_GLOBAL__N_120format_counter_arrayIZNS_26MaterializationSharedState41_update_topn_lazy_materialization_profileEPNS_14RuntimeProfileEE4$_11EENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmNS_5TUnit4typeET_
Line
Count
Source
131
4
std::string format_counter_array(size_t size, TUnit::type unit, GetValue get_value) {
132
4
    return format_array(size, [&](std::stringstream& values, size_t i) {
133
4
        values << PrettyPrinter::print(static_cast<int64_t>(get_value(i)), unit);
134
4
    });
135
4
}
136
137
} // namespace
138
139
3
void MaterializationSharedState::get_block(Block* block) {
140
12
    for (int i = 0, j = 0, rowid_to_block_loc = rowid_locs[j]; i < origin_block.columns(); i++) {
141
9
        if (i != rowid_to_block_loc) {
142
4
            block->insert(origin_block.get_by_position(i));
143
5
        } else {
144
5
            auto response_block = response_blocks[j].to_block();
145
10
            for (int k = 0; k < response_block.columns(); k++) {
146
5
                auto& data = response_block.get_by_position(k);
147
5
                response_blocks[j].mutable_columns()[k] = data.column->clone_empty();
148
5
                block->insert(data);
149
5
            }
150
5
            if (++j < rowid_locs.size()) {
151
2
                rowid_to_block_loc = rowid_locs[j];
152
2
            }
153
5
        }
154
9
    }
155
3
    origin_block.clear();
156
3
}
157
158
void MaterializationSharedState::_update_topn_lazy_materialization_profile(
159
4
        RuntimeProfile* profile) {
160
4
    DORIS_CHECK(profile != nullptr);
161
8
    for (const auto& [backend_id, rpc_struct] : rpc_struct_map) {
162
8
        const int64_t rows_read = count_request_rows(rpc_struct.request);
163
8
        const int64_t segments_read = count_request_segments(rpc_struct.request);
164
8
        update_counter(profile, RowIdStorageReader::TopNLazyMaterializationSecondPhaseRowsRead,
165
8
                       TUnit::UNIT, rows_read);
166
8
        update_counter(profile, RowIdStorageReader::TopNLazyMaterializationSecondPhaseSegmentsRead,
167
8
                       TUnit::UNIT, segments_read);
168
169
8
        auto& stats = _topn_lazy_materialization_backend_stats[backend_id];
170
8
        if (stats.backend.empty()) {
171
8
            stats.backend = rpc_struct.backend_address.empty() ? fmt::format("id={}", backend_id)
172
8
                                                               : rpc_struct.backend_address;
173
8
        }
174
8
        stats.rows_read += rows_read;
175
8
        stats.segments_read += segments_read;
176
8
        if (!rpc_struct.response.has_topn_lazy_materialization_file_cache_stats()) {
177
8
            continue;
178
8
        }
179
180
0
        const auto& file_cache_stats =
181
0
                rpc_struct.response.topn_lazy_materialization_file_cache_stats();
182
0
        update_topn_lazy_materialization_profile(profile, file_cache_stats);
183
0
        stats.local_io_count += file_cache_stats.local_io_count();
184
0
        stats.local_io_bytes += file_cache_stats.local_io_bytes();
185
0
        stats.remote_io_count += file_cache_stats.remote_io_count();
186
0
        stats.remote_io_bytes += file_cache_stats.remote_io_bytes();
187
0
        stats.skip_cache_io_count += file_cache_stats.skip_cache_io_count();
188
0
        stats.write_cache_bytes += file_cache_stats.write_cache_bytes();
189
0
        stats.local_io_time += file_cache_stats.local_io_time();
190
0
        stats.remote_io_time += file_cache_stats.remote_io_time();
191
0
        stats.write_cache_io_time += file_cache_stats.write_cache_io_time();
192
0
    }
193
194
4
    std::vector<const TopNLazyMaterializationBackendStats*> stats;
195
4
    stats.reserve(_topn_lazy_materialization_backend_stats.size());
196
8
    for (const auto& [_, backend_stats] : _topn_lazy_materialization_backend_stats) {
197
8
        stats.push_back(&backend_stats);
198
8
    }
199
200
4
    const size_t size = stats.size();
201
4
    profile->add_info_string(TOPN_LAZY_MAT_PHASE2_PER_BACKEND,
202
8
                             format_array(size, [&](std::stringstream& values, size_t i) {
203
8
                                 values << stats[i]->backend;
204
8
                             }));
205
4
    profile->add_info_string(
206
4
            TOPN_LAZY_MAT_PHASE2_PER_BACKEND_ROWS_READ,
207
8
            format_counter_array(size, TUnit::UNIT, [&](size_t i) { return stats[i]->rows_read; }));
208
4
    profile->add_info_string(TOPN_LAZY_MAT_PHASE2_PER_BACKEND_SEGMENTS_READ,
209
8
                             format_counter_array(size, TUnit::UNIT, [&](size_t i) {
210
8
                                 return stats[i]->segments_read;
211
8
                             }));
212
4
    profile->add_info_string(TOPN_LAZY_MAT_PHASE2_PER_BACKEND_LOCAL_IO_COUNT,
213
8
                             format_counter_array(size, TUnit::UNIT, [&](size_t i) {
214
8
                                 return stats[i]->local_io_count;
215
8
                             }));
216
4
    profile->add_info_string(TOPN_LAZY_MAT_PHASE2_PER_BACKEND_LOCAL_IO_BYTES,
217
8
                             format_counter_array(size, TUnit::BYTES, [&](size_t i) {
218
8
                                 return stats[i]->local_io_bytes;
219
8
                             }));
220
4
    profile->add_info_string(TOPN_LAZY_MAT_PHASE2_PER_BACKEND_REMOTE_IO_COUNT,
221
8
                             format_counter_array(size, TUnit::UNIT, [&](size_t i) {
222
8
                                 return stats[i]->remote_io_count;
223
8
                             }));
224
4
    profile->add_info_string(TOPN_LAZY_MAT_PHASE2_PER_BACKEND_REMOTE_IO_BYTES,
225
8
                             format_counter_array(size, TUnit::BYTES, [&](size_t i) {
226
8
                                 return stats[i]->remote_io_bytes;
227
8
                             }));
228
4
    profile->add_info_string(TOPN_LAZY_MAT_PHASE2_PER_BACKEND_SKIP_CACHE_IO_COUNT,
229
8
                             format_counter_array(size, TUnit::UNIT, [&](size_t i) {
230
8
                                 return stats[i]->skip_cache_io_count;
231
8
                             }));
232
4
    profile->add_info_string(TOPN_LAZY_MAT_PHASE2_PER_BACKEND_WRITE_CACHE_BYTES,
233
8
                             format_counter_array(size, TUnit::BYTES, [&](size_t i) {
234
8
                                 return stats[i]->write_cache_bytes;
235
8
                             }));
236
4
    profile->add_info_string(TOPN_LAZY_MAT_PHASE2_PER_BACKEND_LOCAL_IO_TIME,
237
8
                             format_counter_array(size, TUnit::TIME_NS, [&](size_t i) {
238
8
                                 return stats[i]->local_io_time;
239
8
                             }));
240
4
    profile->add_info_string(TOPN_LAZY_MAT_PHASE2_PER_BACKEND_REMOTE_IO_TIME,
241
8
                             format_counter_array(size, TUnit::TIME_NS, [&](size_t i) {
242
8
                                 return stats[i]->remote_io_time;
243
8
                             }));
244
4
    profile->add_info_string(TOPN_LAZY_MAT_PHASE2_PER_BACKEND_WRITE_CACHE_IO_TIME,
245
8
                             format_counter_array(size, TUnit::TIME_NS, [&](size_t i) {
246
8
                                 return stats[i]->write_cache_io_time;
247
8
                             }));
248
4
}
249
250
// Merges RPC responses from multiple BEs into `response_blocks` in the original row order.
251
//
252
// After parallel multiget_data_v2 RPCs complete, each BE's response contains a partial block
253
// with only the rows that BE owns (ordered by file_id/row_id). This function reassembles them
254
// into the correct TopN output order using `block_order_results` as the ordering guide.
255
//
256
// Data flow:
257
//   rpc_struct_map[backend_id].response  (per-BE partial blocks, unordered across BEs)
258
//       + block_order_results[i][j]      (maps each output row → its source backend_id)
259
//       → response_blocks[i]             (final merged result in original TopN row order)
260
4
Status MaterializationSharedState::merge_multi_response(RuntimeProfile* profile) {
261
4
    _update_topn_lazy_materialization_profile(profile);
262
263
    // Outer loop: iterate over each relation (i.e., each rowid column / table).
264
    // A query with lazy materialization on 2 tables would have block_order_results.size() == 2,
265
    // each with its own set of response_blocks and RPC request_block_descs.
266
9
    for (int i = 0; i < block_order_results.size(); ++i) {
267
        // Maps backend_id → (deserialized block from that BE, row cursor into the block).
268
        // The cursor tracks how many rows we've consumed from this BE's block so far,
269
        // since the rows in the partial block are in the same order as the row_ids we sent.
270
271
        // block_maps must be rebuilt for each relation (each i), because a backend that
272
        // returned a non-empty block for relation i-1 may return an empty block for
273
        // relation i (e.g. it holds rows only from one of the two tables in a UNION ALL).
274
        // Keeping block_maps across iterations would leave stale entries from the previous
275
        // relation and miss entries for the current one, causing the
276
        // "backend_id not found in block_maps" error.
277
6
        std::unordered_map<int64_t, std::pair<Block, int>> block_maps;
278
279
        // Phase 1: Deserialize the i-th response block from every BE into block_maps.
280
        // Each BE's response.blocks(i) corresponds to the i-th relation's fetched columns.
281
12
        for (auto& [backend_id, rpc_struct] : rpc_struct_map) {
282
12
            Block partial_block;
283
12
            size_t uncompressed_size = 0;
284
12
            int64_t uncompressed_time = 0;
285
12
            DCHECK(rpc_struct.response.blocks_size() > i);
286
12
            RETURN_IF_ERROR(partial_block.deserialize(rpc_struct.response.blocks(i).block(),
287
12
                                                      &uncompressed_size, &uncompressed_time));
288
            // Check multiget result rows matches request row id count.
289
            // 1. A BE may return an empty block event if
290
            // request.request_block_descs(i).row_id_size() != 0:
291
            // If the id_file_map was GC'd on the BE before it could process the request,
292
            // refer 'if (!id_file_map)' in RowIdStorageReader::read_by_rowids.
293
            // 2. Report error in any case where the row count doesn't match, even if it's not empty,
294
            //    since that indicates a bug in BE's row fetching logic or serialization logic.
295
12
            if (rpc_struct.request.request_block_descs(i).row_id_size() != partial_block.rows()) {
296
1
                return Status::InternalError(
297
1
                        fmt::format("merge_multi_response, "
298
1
                                    "backend_id {} returned block with row count {} not match "
299
1
                                    "request row id count {}",
300
1
                                    backend_id, partial_block.rows(),
301
1
                                    rpc_struct.request.request_block_descs(i).row_id_size()));
302
1
            }
303
11
            if (rpc_struct.response.blocks(i).has_profile()) {
304
0
                auto response_profile =
305
0
                        RuntimeProfile::from_proto(rpc_struct.response.blocks(i).profile());
306
0
                _update_profile_info(backend_id, response_profile.get());
307
0
            }
308
309
            // Only insert non-empty blocks. A BE may return an empty block if
310
            // request.request_block_descs(i).row_id_size() is 0
311
11
            if (!partial_block.is_empty_column()) {
312
                // Reset row cursor to 0 — we'll consume rows from this block sequentially.
313
9
                block_maps[backend_id] = std::make_pair(std::move(partial_block), 0);
314
9
            }
315
11
        }
316
317
        // return error if any column in response block is not compatible with source block column
318
10
        for (int k = 0; k < response_blocks[i].columns(); ++k) {
319
5
            const auto& resp_col_type = response_blocks[i].get_datatype_by_position(k);
320
8
            for (const auto& [_, source_block_rows] : block_maps) {
321
8
                RETURN_IF_ERROR(resp_col_type->check_column(
322
8
                        *source_block_rows.first.get_by_position(k).column));
323
8
            }
324
5
        }
325
        // Phase 2: Walk the original row order and copy each row from the correct BE's block
326
        // into response_blocks[i]. block_order_results[i][j] tells us which backend_id owns
327
        // row j. A value of 0 means the rowid was NULL (e.g., from an outer join).
328
16
        for (int j = 0; j < block_order_results[i].size(); ++j) {
329
11
            auto backend_id = block_order_results[i][j];
330
            // Non-null rowid: copy the next row from this BE's partial block.
331
11
            if (backend_id) {
332
8
                if (UNLIKELY(block_maps.find(backend_id) == block_maps.end())) {
333
0
                    return Status::InternalError(
334
0
                            fmt::format("MaterializationSharedState::merge_multi_response, "
335
0
                                        "backend_id {} not found in block_maps",
336
0
                                        backend_id));
337
0
                }
338
                // source_block_rows.first  = the deserialized Block from this BE
339
                // source_block_rows.second = current row cursor (how many rows consumed so far)
340
8
                auto& source_block_rows = block_maps[backend_id];
341
8
                DCHECK(source_block_rows.second < source_block_rows.first.rows());
342
                // Copy column-by-column from the source block's current row into response_blocks.
343
16
                for (int k = 0; k < response_blocks[i].columns(); ++k) {
344
8
                    response_blocks[i].get_column_by_position(k)->insert_from(
345
8
                            *source_block_rows.first.get_by_position(k).column,
346
8
                            source_block_rows.second);
347
8
                }
348
                // Advance the cursor — next time we see this backend_id, we take the next row.
349
8
                source_block_rows.second++;
350
8
            } else {
351
6
                for (int k = 0; k < response_blocks[i].columns(); ++k) {
352
3
                    response_blocks[i].get_column_by_position(k)->insert_default();
353
3
                }
354
3
            }
355
11
        }
356
5
    }
357
358
    // clear request/response
359
    // Phase 3: Clear the row_id and file_id arrays in each RPC request to prepare for the
360
    // next batch. The request template (column_descs, slots, etc.) is reused across batches;
361
    // only the per-row data (file_id, row_id) needs to be cleared.
362
6
    for (auto& [_, rpc_struct] : rpc_struct_map) {
363
16
        for (int i = 0; i < rpc_struct.request.request_block_descs_size(); ++i) {
364
10
            rpc_struct.request.mutable_request_block_descs(i)->clear_row_id();
365
10
            rpc_struct.request.mutable_request_block_descs(i)->clear_file_id();
366
10
        }
367
6
    }
368
3
    return Status::OK();
369
4
}
370
371
void MaterializationSharedState::_update_profile_info(int64_t backend_id,
372
0
                                                      RuntimeProfile* response_profile) {
373
0
    if (!backend_profile_info_string.contains(backend_id)) {
374
0
        backend_profile_info_string.emplace(backend_id,
375
0
                                            std::map<std::string, fmt::memory_buffer> {});
376
0
    }
377
0
    auto& info_map = backend_profile_info_string[backend_id];
378
379
0
    auto update_profile_info_key = [&](const std::string& info_key) {
380
0
        const auto* info_value = response_profile->get_info_string(info_key);
381
0
        if (info_value == nullptr) [[unlikely]] {
382
0
            LOG(WARNING) << "Get row id fetch rpc profile success, but no info key :" << info_key;
383
0
            return;
384
0
        }
385
0
        if (!info_map.contains(info_key)) {
386
0
            info_map.emplace(info_key, fmt::memory_buffer {});
387
0
        }
388
0
        fmt::format_to(info_map[info_key], "{}, ", *info_value);
389
0
    };
390
391
0
    update_profile_info_key(RowIdStorageReader::ScannersRunningTimeProfile);
392
0
    update_profile_info_key(RowIdStorageReader::InitReaderAvgTimeProfile);
393
0
    update_profile_info_key(RowIdStorageReader::GetBlockAvgTimeProfile);
394
0
    update_profile_info_key(RowIdStorageReader::FileReadLinesProfile);
395
0
    update_profile_info_key(FileScanner::FileReadBytesProfile);
396
0
    update_profile_info_key(FileScanner::FileReadTimeProfile);
397
0
}
398
399
1
Status MaterializationSharedState::create_muiltget_result(const Columns& columns, bool child_eos) {
400
1
    const auto rows = columns.empty() ? 0 : columns[0]->size();
401
1
    block_order_results.resize(columns.size());
402
403
2
    for (int i = 0; i < columns.size(); ++i) {
404
1
        const uint8_t* null_map = nullptr;
405
1
        const ColumnString* column_rowid = nullptr;
406
1
        const auto& column = columns[i];
407
408
1
        if (const auto* const column_ptr = check_and_get_column<ColumnNullable>(*column)) {
409
0
            null_map = column_ptr->get_null_map_data().data();
410
0
            column_rowid =
411
0
                    assert_cast<const ColumnString*>(column_ptr->get_nested_column_ptr().get());
412
1
        } else {
413
1
            column_rowid = assert_cast<const ColumnString*>(column.get());
414
1
        }
415
416
1
        auto& block_order = block_order_results[i];
417
1
        block_order.resize(rows);
418
419
3
        for (int j = 0; j < rows; ++j) {
420
2
            if (!null_map || !null_map[j]) {
421
2
                DCHECK(column_rowid->get_data_at(j).size == sizeof(GlobalRowLoacationV2));
422
2
                GlobalRowLoacationV2 row_location =
423
2
                        *((GlobalRowLoacationV2*)column_rowid->get_data_at(j).data);
424
2
                auto rpc_struct = rpc_struct_map.find(row_location.backend_id);
425
2
                if (UNLIKELY(rpc_struct == rpc_struct_map.end())) {
426
0
                    return Status::InternalError(
427
0
                            "MaterializationSinkOperatorX failed to find rpc_struct, backend_id={}",
428
0
                            row_location.backend_id);
429
0
                }
430
2
                rpc_struct->second.request.mutable_request_block_descs(i)->add_row_id(
431
2
                        row_location.row_id);
432
2
                rpc_struct->second.request.mutable_request_block_descs(i)->add_file_id(
433
2
                        row_location.file_id);
434
2
                block_order[j] = row_location.backend_id;
435
436
                // Count rows per backend
437
2
                _backend_rows_count[row_location.backend_id]++;
438
2
            } else {
439
0
                block_order[j] = 0;
440
0
            }
441
2
        }
442
1
    }
443
444
    // Update max rows per backend
445
2
    for (const auto& [_, row_count] : _backend_rows_count) {
446
2
        if (row_count > _max_rows_per_backend) {
447
1
            _max_rows_per_backend = row_count;
448
1
        }
449
2
    }
450
451
1
    eos = child_eos;
452
1
    need_merge_block = rows > 0;
453
454
1
    return Status::OK();
455
1
}
456
457
Status MaterializationSharedState::init_multi_requests(
458
0
        const TMaterializationNode& materialization_node, RuntimeState* state) {
459
0
    rpc_struct_inited = true;
460
0
    PMultiGetRequestV2 multi_get_request;
461
    // Initialize the base struct of PMultiGetRequestV2
462
0
    multi_get_request.set_be_exec_version(state->be_exec_version());
463
0
    multi_get_request.set_wg_id(state->get_query_ctx()->workload_group()->id());
464
0
    multi_get_request.set_file_cache_remote_only_on_miss(
465
0
            config::is_cloud_mode() &&
466
0
            state->query_options().enable_topn_lazy_mat_phase2_no_write_file_cache);
467
0
    auto* query_id = multi_get_request.mutable_query_id();
468
0
    query_id->set_hi(state->query_id().hi);
469
0
    query_id->set_lo(state->query_id().lo);
470
0
    DCHECK_EQ(materialization_node.column_descs_lists.size(),
471
0
              materialization_node.slot_locs_lists.size());
472
473
0
    const auto& tuple_desc =
474
0
            state->desc_tbl().get_tuple_descriptor(materialization_node.intermediate_tuple_id);
475
0
    const auto& slots = tuple_desc->slots();
476
0
    response_blocks = std::vector<MutableBlock>(materialization_node.column_descs_lists.size());
477
478
0
    for (int i = 0; i < materialization_node.column_descs_lists.size(); ++i) {
479
0
        auto* request_block_desc = multi_get_request.add_request_block_descs();
480
0
        request_block_desc->set_fetch_row_store(materialization_node.fetch_row_stores[i]);
481
        // Initialize the column_descs and slot_locs
482
0
        const auto& column_descs = materialization_node.column_descs_lists[i];
483
0
        for (const auto& column_desc_item : column_descs) {
484
0
            TabletColumn(column_desc_item).to_schema_pb(request_block_desc->add_column_descs());
485
0
        }
486
487
0
        const auto& slot_locs = materialization_node.slot_locs_lists[i];
488
0
        tuple_desc->to_protobuf(request_block_desc->mutable_desc());
489
490
0
        const auto& column_idxs = materialization_node.column_idxs_lists[i];
491
0
        for (auto idx : column_idxs) {
492
0
            request_block_desc->add_column_idxs(idx);
493
0
        }
494
495
0
        std::vector<SlotDescriptor*> slots_res;
496
0
        for (const auto& slot_loc_item : slot_locs) {
497
0
            slots[slot_loc_item]->to_protobuf(request_block_desc->add_slots());
498
0
            slots_res.emplace_back(slots[slot_loc_item]);
499
0
        }
500
0
        response_blocks[i] = MutableBlock(Block(slots_res, 10));
501
0
    }
502
503
    // Initialize the stubs and requests for each BE
504
0
    for (const auto& node_info : materialization_node.nodes_info.nodes) {
505
0
        auto client = ExecEnv::GetInstance()->brpc_internal_client_cache()->get_client(
506
0
                node_info.host, node_info.async_internal_port);
507
0
        if (!client) {
508
0
            LOG(WARNING) << "Get rpc stub failed, host=" << node_info.host
509
0
                         << ", port=" << node_info.async_internal_port;
510
0
            return Status::InternalError("RowIDFetcher failed to init rpc client, host={}, port={}",
511
0
                                         node_info.host, node_info.async_internal_port);
512
0
        }
513
0
        rpc_struct_map.emplace(node_info.id,
514
0
                               FetchRpcStruct {.stub = std::move(client),
515
0
                                               .cntl = std::make_unique<brpc::Controller>(),
516
0
                                               .request = multi_get_request,
517
0
                                               .response = PMultiGetResponseV2(),
518
0
                                               .backend_address = fmt::format(
519
0
                                                       "id={} {}:{}", node_info.id, node_info.host,
520
0
                                                       node_info.async_internal_port)});
521
0
    }
522
523
0
    return Status::OK();
524
0
}
525
526
0
Status MaterializationOperator::init(const doris::TPlanNode& tnode, doris::RuntimeState* state) {
527
0
    RETURN_IF_ERROR(OperatorXBase::init(tnode, state));
528
0
    DCHECK(tnode.__isset.materialization_node);
529
0
    _materialization_node = tnode.materialization_node;
530
    // Create result_expr_ctx_lists_ from thrift exprs.
531
0
    const auto& fetch_expr_lists = tnode.materialization_node.fetch_expr_lists;
532
0
    RETURN_IF_ERROR(VExpr::create_expr_trees(fetch_expr_lists, _rowid_exprs));
533
0
    return Status::OK();
534
0
}
535
536
0
Status MaterializationOperator::prepare(RuntimeState* state) {
537
0
    RETURN_IF_ERROR(Base::prepare(state));
538
0
    RETURN_IF_ERROR(VExpr::prepare(_rowid_exprs, state, _child->row_desc()));
539
0
    RETURN_IF_ERROR(VExpr::open(_rowid_exprs, state));
540
0
    return Status::OK();
541
0
}
542
543
0
bool MaterializationOperator::need_more_input_data(RuntimeState* state) const {
544
0
    auto& local_state = get_local_state(state);
545
0
    return !local_state._materialization_state.origin_block.rows() &&
546
0
           !local_state._materialization_state.eos;
547
0
}
548
549
0
Status MaterializationOperator::pull(RuntimeState* state, Block* output_block, bool* eos) const {
550
0
    auto& local_state = get_local_state(state);
551
0
    output_block->clear();
552
0
    if (local_state._materialization_state.need_merge_block) {
553
0
        local_state._materialization_state.get_block(output_block);
554
0
    }
555
0
    *eos = local_state._materialization_state.eos;
556
557
0
    if (*eos) {
558
0
        for (const auto& [backend_id, child_info] :
559
0
             local_state._materialization_state.backend_profile_info_string) {
560
0
            auto* child_profile = local_state.operator_profile()->create_child(
561
0
                    "RowIDFetcher: BackendId:" + std::to_string(backend_id));
562
0
            for (const auto& [info_key, info_value] :
563
0
                 local_state._materialization_state.backend_profile_info_string[backend_id]) {
564
0
                child_profile->add_info_string(info_key, "{" + fmt::to_string(info_value) + "}");
565
0
            }
566
0
            local_state.operator_profile()->add_child(child_profile, true);
567
0
        }
568
0
    }
569
570
0
    return Status::OK();
571
0
}
572
573
0
Status MaterializationOperator::push(RuntimeState* state, Block* in_block, bool eos) const {
574
0
    auto& local_state = get_local_state(state);
575
0
    SCOPED_TIMER(local_state.exec_time_counter());
576
0
    if (!local_state._materialization_state.rpc_struct_inited) {
577
0
        RETURN_IF_ERROR(local_state._materialization_state.init_multi_requests(
578
0
                _materialization_node, state));
579
0
    }
580
581
0
    if (in_block->rows() > 0 || eos) {
582
        // execute the rowid exprs
583
0
        Columns columns;
584
0
        if (in_block->rows() != 0) {
585
0
            local_state._materialization_state.rowid_locs.resize(_rowid_exprs.size());
586
0
            for (int i = 0; i < _rowid_exprs.size(); ++i) {
587
0
                const auto& rowid_expr = _rowid_exprs[i];
588
0
                RETURN_IF_ERROR(rowid_expr->execute(
589
0
                        in_block, &local_state._materialization_state.rowid_locs[i]));
590
0
                columns.emplace_back(
591
0
                        in_block->get_by_position(local_state._materialization_state.rowid_locs[i])
592
0
                                .column);
593
0
            }
594
0
            local_state._materialization_state.origin_block.swap(*in_block);
595
0
        }
596
0
        RETURN_IF_ERROR(local_state._materialization_state.create_muiltget_result(columns, eos));
597
598
0
        auto size = local_state._materialization_state.rpc_struct_map.size();
599
0
        bthread::CountdownEvent counter(static_cast<int>(size));
600
0
        MonotonicStopWatch rpc_timer(true);
601
0
        for (auto& [backend_id, rpc_struct] : local_state._materialization_state.rpc_struct_map) {
602
0
            auto* callback = brpc::NewCallback(fetch_callback, &counter);
603
0
            rpc_struct.cntl->set_timeout_ms(state->execution_timeout() * 1000);
604
            // send brpc request
605
0
            rpc_struct.stub->multiget_data_v2(rpc_struct.cntl.get(), &rpc_struct.request,
606
0
                                              &rpc_struct.response, callback);
607
0
        }
608
0
        counter.wait();
609
0
        if (auto time = rpc_timer.elapsed_time(); time > local_state._max_rpc_timer->value()) {
610
0
            local_state._max_rpc_timer->set(time);
611
0
        }
612
613
0
        for (auto& [backend_id, rpc_struct] : local_state._materialization_state.rpc_struct_map) {
614
0
            if (rpc_struct.cntl->Failed()) {
615
0
                std::string error_text =
616
0
                        "Failed to send brpc request, error_text=" + rpc_struct.cntl->ErrorText() +
617
0
                        " Materialization Sink node id:" + std::to_string(node_id()) +
618
0
                        " target_backend_id:" + std::to_string(backend_id);
619
0
                return Status::InternalError(error_text);
620
0
            }
621
0
            if (rpc_struct.response.status().status_code() != 0) {
622
0
                Status st = Status::create(rpc_struct.response.status());
623
0
                st.append(fmt::format(", Backend:{}, Materialization Sink node id:{}", backend_id,
624
0
                                      node_id()));
625
0
                return st;
626
0
            }
627
0
            rpc_struct.cntl->Reset();
628
0
        }
629
630
0
        if (local_state._materialization_state.need_merge_block) {
631
0
            SCOPED_TIMER(local_state._merge_response_timer);
632
0
            RETURN_IF_ERROR(local_state._materialization_state.merge_multi_response(
633
0
                    local_state.operator_profile()));
634
0
            local_state._max_rows_per_backend_counter->set(
635
0
                    (int64_t)local_state._materialization_state._max_rows_per_backend);
636
0
        }
637
0
    }
638
639
0
    return Status::OK();
640
0
}
641
642
} // namespace doris