Coverage Report

Created: 2026-08-07 16:01

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