Coverage Report

Created: 2026-09-01 18:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/storage/rowid_conversion.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#pragma once
19
20
#include <map>
21
#include <vector>
22
23
#include "common/cast_set.h"
24
#include "common/check.h"
25
#include "runtime/thread_context.h"
26
#include "storage/olap_common.h"
27
#include "storage/utils.h"
28
29
namespace doris {
30
31
// For unique key merge on write table, we should update delete bitmap
32
// of destination rowset when compaction finished.
33
// Through the row id correspondence between the source rowset and the
34
// destination rowset, we can quickly update the delete bitmap of the
35
// destination rowset.
36
class RowIdConversion {
37
public:
38
    struct DestinationRowId {
39
        uint32_t segment_pos;
40
        uint32_t row_id;
41
    };
42
43
271
    RowIdConversion() = default;
44
271
    ~RowIdConversion() { RELEASE_THREAD_MEM_TRACKER(_seg_rowid_map_mem_used); }
45
46
    Status init_segment_map(const RowsetId& src_rowset_id, const std::vector<uint32_t>& segment_ids,
47
420
                            const std::vector<uint32_t>& num_rows) {
48
420
        DCHECK_EQ(segment_ids.size(), num_rows.size());
49
1.15k
        for (size_t i = 0; i < num_rows.size(); i++) {
50
733
            auto src_segment = std::pair<RowsetId, uint32_t> {src_rowset_id, segment_ids[i]};
51
733
            auto iter = _segment_to_id_map.find(src_segment);
52
            // Each segment-group reader initializes all source segments, so reuse existing maps.
53
733
            if (iter != _segment_to_id_map.end()) {
54
20
                DORIS_CHECK_LT(iter->second, _segments_rowid_map.size());
55
20
                DORIS_CHECK_EQ(_segments_rowid_map[iter->second].size(), num_rows[i]);
56
20
                continue;
57
20
            }
58
59
713
            constexpr size_t RESERVED_MEMORY = 10 * 1024 * 1024; // 10M
60
713
            if (doris::GlobalMemoryArbitrator::is_exceed_hard_mem_limit(RESERVED_MEMORY)) {
61
0
                return Status::MemoryLimitExceeded(fmt::format(
62
0
                        "RowIdConversion init_segment_map failed, process memory exceed limit or "
63
0
                        "sys available memory less than low water mark , {}, "
64
0
                        "consuming "
65
0
                        "tracker:<{}>, peak used {}, current used {}.",
66
0
                        doris::GlobalMemoryArbitrator::process_mem_log_str(),
67
0
                        doris::thread_context()
68
0
                                ->thread_mem_tracker_mgr->limiter_mem_tracker()
69
0
                                ->label(),
70
0
                        doris::thread_context()
71
0
                                ->thread_mem_tracker_mgr->limiter_mem_tracker()
72
0
                                ->peak_consumption(),
73
0
                        doris::thread_context()
74
0
                                ->thread_mem_tracker_mgr->limiter_mem_tracker()
75
0
                                ->consumption()));
76
0
            }
77
78
713
            uint32_t id = cast_set<uint32_t>(_segments_rowid_map.size());
79
713
            auto insert_result = _segment_to_id_map.emplace(src_segment, id);
80
713
            DORIS_CHECK(insert_result.second);
81
713
            _id_to_segment_map.push_back(src_segment);
82
713
            std::vector<std::pair<uint32_t, uint32_t>> vec(
83
713
                    num_rows[i], std::pair<uint32_t, uint32_t>(UINT32_MAX, UINT32_MAX));
84
85
            //NOTE: manually count _segments_rowid_map's memory here, because _segments_rowid_map could be used by indexCompaction.
86
            // indexCompaction is a thridparty code, it's too complex to modify it.
87
            // refer compact_column.
88
713
            track_mem_usage(vec.capacity());
89
713
            _segments_rowid_map.emplace_back(std::move(vec));
90
713
        }
91
420
        return Status::OK();
92
420
    }
93
94
    // set dst rowset id
95
149
    void set_dst_rowset_id(const RowsetId& dst_rowset_id) { _dst_rowst_id = dst_rowset_id; }
96
27
    const RowsetId& get_dst_rowset_id() const { return _dst_rowst_id; }
97
98
    // add row id to the map
99
    void add(const std::vector<RowLocation>& rss_row_ids,
100
1.78k
             const std::vector<uint32_t>& dst_segments_num_row) {
101
4.75M
        for (auto& item : rss_row_ids) {
102
4.75M
            if (item.row_id == -1) {
103
0
                continue;
104
0
            }
105
4.75M
            uint32_t id = _segment_to_id_map.at(
106
4.75M
                    std::pair<RowsetId, uint32_t> {item.rowset_id, item.segment_id});
107
4.75M
            if (_cur_dst_segment_pos < dst_segments_num_row.size() &&
108
4.75M
                _cur_dst_segment_rowid >= dst_segments_num_row[_cur_dst_segment_pos]) {
109
1.15k
                _cur_dst_segment_pos++;
110
1.15k
                _cur_dst_segment_rowid = 0;
111
1.15k
            }
112
4.75M
            _segments_rowid_map[id][item.row_id] =
113
4.75M
                    std::pair<uint32_t, uint32_t> {_cur_dst_segment_pos, _cur_dst_segment_rowid++};
114
4.75M
        }
115
1.78k
    }
116
117
    // Get the destination segment position and row id. The physical destination segment id is
118
    // resolved only after the output rowset is built.
119
    // return non-zero if the src RowLocation does not exist
120
1.77M
    int get(const RowLocation& src, DestinationRowId* dst) const {
121
1.77M
        auto iter = _segment_to_id_map.find({src.rowset_id, src.segment_id});
122
1.77M
        if (iter == _segment_to_id_map.end()) {
123
1
            return -1;
124
1
        }
125
1.77M
        const auto& rowid_map = _segments_rowid_map[iter->second];
126
1.77M
        if (src.row_id >= rowid_map.size()) {
127
1
            return -1;
128
1
        }
129
1.77M
        auto& [dst_segment_pos, dst_rowid] = rowid_map[src.row_id];
130
1.77M
        if (dst_segment_pos == UINT32_MAX && dst_rowid == UINT32_MAX) {
131
764k
            return -1;
132
764k
        }
133
134
1.00M
        dst->segment_pos = dst_segment_pos;
135
1.00M
        dst->row_id = dst_rowid;
136
1.00M
        return 0;
137
1.77M
    }
138
139
    const std::vector<std::vector<std::pair<uint32_t, uint32_t>>>& get_rowid_conversion_map()
140
29
            const {
141
29
        return _segments_rowid_map;
142
29
    }
143
144
29
    const std::map<std::pair<RowsetId, uint32_t>, uint32_t>& get_src_segment_to_id_map() {
145
29
        return _segment_to_id_map;
146
29
    }
147
148
0
    std::pair<RowsetId, uint32_t> get_segment_by_id(uint32_t id) const {
149
0
        DCHECK_GT(_id_to_segment_map.size(), id);
150
0
        return _id_to_segment_map.at(id);
151
0
    }
152
153
0
    uint32_t get_id_by_segment(const std::pair<RowsetId, uint32_t>& segment) const {
154
0
        return _segment_to_id_map.at(segment);
155
0
    }
156
157
private:
158
713
    void track_mem_usage(size_t delta_std_pair_cap) {
159
713
        _std_pair_cap += delta_std_pair_cap;
160
161
713
        size_t new_size =
162
713
                _std_pair_cap * sizeof(std::pair<uint32_t, uint32_t>) +
163
713
                _segments_rowid_map.capacity() * sizeof(std::vector<std::pair<uint32_t, uint32_t>>);
164
713
        CONSUME_THREAD_MEM_TRACKER(new_size - _seg_rowid_map_mem_used);
165
0
        _seg_rowid_map_mem_used = new_size;
166
713
    }
167
168
private:
169
    // the first level vector: index indicates src segment.
170
    // the second level vector: index indicates row id of source segment,
171
    // value indicates destination segment position and row id.
172
    // <UINT32_MAX, UINT32_MAX> indicates current row not exist.
173
    std::vector<std::vector<std::pair<uint32_t, uint32_t>>> _segments_rowid_map;
174
    size_t _seg_rowid_map_mem_used {0};
175
    size_t _std_pair_cap {0};
176
177
    // Map source segment to 0 to n
178
    std::map<std::pair<RowsetId, uint32_t>, uint32_t> _segment_to_id_map;
179
180
    // Map 0 to n to source segment
181
    std::vector<std::pair<RowsetId, uint32_t>> _id_to_segment_map;
182
183
    // dst rowset id
184
    RowsetId _dst_rowst_id;
185
186
    // current dst segment position
187
    std::uint32_t _cur_dst_segment_pos = 0;
188
189
    // current rowid of dst segment
190
    std::uint32_t _cur_dst_segment_rowid = 0;
191
};
192
193
} // namespace doris