Coverage Report

Created: 2026-07-12 14:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/cloud/cloud_committed_rs_mgr.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 "cloud/cloud_committed_rs_mgr.h"
19
20
#include <chrono>
21
22
#include "cloud/config.h"
23
#include "common/logging.h"
24
#include "storage/rowset/rowset_meta.h"
25
#include "util/thread.h"
26
27
namespace doris {
28
24
CloudCommittedRSMgr::CloudCommittedRSMgr() : _stop_latch(1) {}
29
30
24
CloudCommittedRSMgr::~CloudCommittedRSMgr() {
31
24
    _stop_latch.count_down();
32
24
    if (_clean_thread) {
33
0
        _clean_thread->join();
34
0
    }
35
24
}
36
37
0
Status CloudCommittedRSMgr::init() {
38
0
    auto st = Thread::create(
39
0
            "CloudCommittedRSMgr", "clean_committed_rs_thread",
40
0
            [this]() { this->_clean_thread_callback(); }, &_clean_thread);
41
0
    if (!st.ok()) {
42
0
        LOG(WARNING) << "failed to create thread for CloudCommittedRSMgr, error: " << st;
43
0
    }
44
0
    return st;
45
0
}
46
47
void CloudCommittedRSMgr::add_committed_rowset(int64_t txn_id, int64_t tablet_id,
48
                                               RowsetMetaSharedPtr rowset_meta,
49
58
                                               int64_t expiration_time) {
50
58
    int64_t txn_expiration_min =
51
58
            duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch())
52
58
                    .count() +
53
58
            config::tablet_txn_info_min_expired_seconds;
54
58
    expiration_time = std::max(txn_expiration_min, expiration_time);
55
58
    std::unique_lock<std::shared_mutex> wlock(_rwlock);
56
58
    TxnTabletKey key(txn_id, tablet_id);
57
58
    _committed_rs_map.insert_or_assign(key, CommittedRowsetValue(rowset_meta, expiration_time));
58
58
    _expiration_map.emplace(expiration_time, key);
59
58
    LOG(INFO) << "add pending rowset, txn_id=" << txn_id << ", tablet_id=" << tablet_id
60
58
              << ", rowset_id=" << rowset_meta->rowset_id().to_string()
61
58
              << ", expiration_time=" << expiration_time;
62
58
}
63
64
Result<std::pair<RowsetMetaSharedPtr, int64_t>> CloudCommittedRSMgr::get_committed_rowset(
65
96
        int64_t txn_id, int64_t tablet_id) {
66
96
    std::shared_lock<std::shared_mutex> rlock(_rwlock);
67
96
    TxnTabletKey key(txn_id, tablet_id);
68
96
    if (auto it = _empty_rowset_markers.find(key); it != _empty_rowset_markers.end()) {
69
20
        return std::make_pair(nullptr, it->second);
70
20
    }
71
76
    auto iter = _committed_rs_map.find(key);
72
76
    if (iter == _committed_rs_map.end()) {
73
14
        return ResultError(Status::Error<ErrorCode::NOT_FOUND>(
74
14
                "committed rowset not found, txn_id={}, tablet_id={}", txn_id, tablet_id));
75
14
    }
76
62
    return std::make_pair(iter->second.rowset_meta, iter->second.expiration_time);
77
76
}
78
79
2
void CloudCommittedRSMgr::remove_committed_rowset(int64_t txn_id, int64_t tablet_id) {
80
2
    std::unique_lock<std::shared_mutex> wlock(_rwlock);
81
2
    _committed_rs_map.erase({txn_id, tablet_id});
82
2
}
83
84
6
void CloudCommittedRSMgr::remove_expired_committed_rowsets() {
85
6
    std::unique_lock<std::shared_mutex> wlock(_rwlock);
86
6
    int64_t current_time = std::chrono::duration_cast<std::chrono::seconds>(
87
6
                                   std::chrono::system_clock::now().time_since_epoch())
88
6
                                   .count();
89
90
14
    while (!_expiration_map.empty()) {
91
12
        auto iter = _expiration_map.begin();
92
12
        if (!_committed_rs_map.contains(iter->second) &&
93
12
            !_empty_rowset_markers.contains(iter->second)) {
94
0
            _expiration_map.erase(iter);
95
0
            continue;
96
0
        }
97
12
        int64_t expiration_time = iter->first;
98
12
        if (expiration_time > current_time) {
99
4
            break;
100
4
        }
101
102
8
        auto key = iter->second;
103
8
        _expiration_map.erase(iter);
104
105
8
        auto it_rs = _committed_rs_map.find(key);
106
8
        if (it_rs != _committed_rs_map.end() && it_rs->second.expiration_time == expiration_time) {
107
4
            _committed_rs_map.erase(it_rs);
108
4
            LOG(INFO) << "clean expired pending cloud rowset, txn_id=" << key.txn_id
109
4
                      << ", tablet_id=" << key.tablet_id << ", expiration_time=" << expiration_time;
110
4
        }
111
8
        auto it_empty = _empty_rowset_markers.find(key);
112
8
        if (it_empty != _empty_rowset_markers.end() && it_empty->second == expiration_time) {
113
4
            _empty_rowset_markers.erase(it_empty);
114
4
            LOG(INFO) << "clean expired empty rowset marker, txn_id=" << key.txn_id
115
4
                      << ", tablet_id=" << key.tablet_id << ", expiration_time=" << expiration_time;
116
4
        }
117
8
    }
118
6
}
119
120
void CloudCommittedRSMgr::mark_empty_rowset(int64_t txn_id, int64_t tablet_id,
121
18
                                            int64_t txn_expiration) {
122
18
    int64_t txn_expiration_min =
123
18
            duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch())
124
18
                    .count() +
125
18
            config::tablet_txn_info_min_expired_seconds;
126
18
    txn_expiration = std::max(txn_expiration_min, txn_expiration);
127
128
18
    std::unique_lock<std::shared_mutex> wlock(_rwlock);
129
18
    TxnTabletKey txn_key(txn_id, tablet_id);
130
18
    _empty_rowset_markers.insert_or_assign(txn_key, txn_expiration);
131
18
    _expiration_map.emplace(txn_expiration, txn_key);
132
18
}
133
134
0
void CloudCommittedRSMgr::_clean_thread_callback() {
135
0
    do {
136
0
        remove_expired_committed_rowsets();
137
0
    } while (!_stop_latch.wait_for(
138
0
            std::chrono::seconds(config::remove_expired_tablet_txn_info_interval_seconds)));
139
0
}
140
} // namespace doris