Skip to content

Commit f48b520

Browse files
authored
Merge branch 'master' into file_cache_admission_control
2 parents ece61a7 + 3ec56d7 commit f48b520

File tree

478 files changed

+14878
-8949
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

478 files changed

+14878
-8949
lines changed

.github/workflows/auto-cherry-pick.yml

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ permissions:
3131
jobs:
3232
auto_cherry_pick:
3333
runs-on: ubuntu-latest
34-
if: ${{(contains(github.event.pull_request.labels.*.name, 'dev/4.0.x') || contains(github.event.pull_request.labels.*.name, 'dev/3.1.x') || github.event.label.name == 'dev/4.0.x' || github.event.label.name == 'dev/3.1.x') && github.event.pull_request.merged == true }}
34+
if: ${{(contains(github.event.pull_request.labels.*.name, 'dev/4.0.x') || github.event.label.name == 'dev/4.0.x') && github.event.pull_request.merged == true }}
3535
steps:
3636
- name: Checkout repository
3737
uses: actions/checkout@v3
@@ -54,14 +54,7 @@ jobs:
5454
else
5555
echo "SHA matches: $calculated_sha"
5656
fi
57-
- name: Auto cherry-pick to branch-3.1
58-
if: ${{ ((github.event.action == 'labeled' && github.event.label.name == 'dev/3.1.x'))|| ((github.event_name == 'pull_request_target' && github.event.action == 'closed') && contains(github.event.pull_request.labels.*.name, 'dev/3.1.x')) }}
59-
env:
60-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
61-
REPO_NAME: ${{ github.repository }}
62-
CONFLICT_LABEL: dev/3.1.x-conflict
63-
run: |
64-
python tools/auto-pick-script.py ${{ github.event.pull_request.number }} branch-3.1
57+
6558
- name: Auto cherry-pick to branch-4.0
6659
if: ${{ ((github.event.action == 'labeled' && github.event.label.name == 'dev/4.0.x'))|| ((github.event_name == 'pull_request_target' && github.event.action == 'closed') && contains(github.event.pull_request.labels.*.name, 'dev/4.0.x')) }}
6760
env:

NOTICE.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Apache Doris
2-
Copyright 2018-2025 The Apache Software Foundation
2+
Copyright 2018-2026 The Apache Software Foundation
33

44
This product includes software developed at
55
The Apache Software Foundation (http://www.apache.org/).

be/src/cloud/cloud_engine_calc_delete_bitmap_task.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,12 @@ Status CloudTabletCalcDeleteBitmapTask::handle() const {
224224
});
225225
Status status;
226226
if (_sub_txn_ids.empty()) {
227+
// Check empty rowset for non-sub_txn case
228+
if (_engine.txn_delete_bitmap_cache().is_empty_rowset(_transaction_id, _tablet_id)) {
229+
LOG(INFO) << "tablet=" << _tablet_id << ", txn=" << _transaction_id
230+
<< " is empty rowset, skip delete bitmap calculation";
231+
return Status::OK();
232+
}
227233
status = _handle_rowset(tablet, _version);
228234
} else {
229235
std::stringstream ss;
@@ -237,9 +243,18 @@ Status CloudTabletCalcDeleteBitmapTask::handle() const {
237243
std::vector<RowsetSharedPtr> invisible_rowsets;
238244
DeleteBitmapPtr tablet_delete_bitmap =
239245
std::make_shared<DeleteBitmap>(tablet->tablet_meta()->delete_bitmap());
240-
for (int i = 0; i < _sub_txn_ids.size(); ++i) {
246+
size_t empty_rowset_count = 0;
247+
for (size_t i = 0; i < _sub_txn_ids.size(); ++i) {
241248
int64_t sub_txn_id = _sub_txn_ids[i];
242249
int64_t version = _version + i;
250+
// Check empty rowset for each sub_txn using sub_txn_id
251+
if (_engine.txn_delete_bitmap_cache().is_empty_rowset(sub_txn_id, _tablet_id)) {
252+
LOG(INFO) << "tablet=" << _tablet_id << ", sub_txn=" << sub_txn_id
253+
<< ", version=" << version
254+
<< " is empty rowset, skip delete bitmap calculation";
255+
empty_rowset_count++;
256+
continue;
257+
}
243258
LOG(INFO) << "start calc delete bitmap for txn_id=" << _transaction_id
244259
<< ", sub_txn_id=" << sub_txn_id << ", table_id=" << tablet->table_id()
245260
<< ", partition_id=" << tablet->partition_id() << ", tablet_id=" << _tablet_id
@@ -254,7 +269,7 @@ Status CloudTabletCalcDeleteBitmapTask::handle() const {
254269
<< ", cur_version=" << version << ", status=" << status;
255270
return status;
256271
}
257-
DCHECK(invisible_rowsets.size() == i + 1);
272+
DCHECK(invisible_rowsets.size() == i + 1 - empty_rowset_count);
258273
}
259274
}
260275
DBUG_EXECUTE_IF("CloudCalcDbmTask.handle.return.block",

be/src/cloud/cloud_rowset_builder.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,15 @@ const RowsetMetaSharedPtr& CloudRowsetBuilder::rowset_meta() {
127127

128128
Status CloudRowsetBuilder::set_txn_related_delete_bitmap() {
129129
if (_tablet->enable_unique_key_merge_on_write()) {
130+
// For empty rowsets when skip_writing_empty_rowset_metadata=true,
131+
// store only a lightweight marker instead of full rowset info.
132+
// This allows CalcDeleteBitmapTask to detect and skip gracefully,
133+
// while using minimal memory (~16 bytes per entry).
134+
if (_skip_writing_rowset_metadata) {
135+
_engine.txn_delete_bitmap_cache().mark_empty_rowset(_req.txn_id, _tablet->tablet_id(),
136+
_req.txn_expiration);
137+
return Status::OK();
138+
}
130139
if (config::enable_merge_on_write_correctness_check && _rowset->num_rows() != 0) {
131140
auto st = _tablet->check_delete_bitmap_correctness(
132141
_delete_bitmap, _rowset->end_version() - 1, _req.txn_id, *_rowset_ids);

be/src/cloud/cloud_stream_load_executor.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ Status CloudStreamLoadExecutor::operate_txn_2pc(StreamLoadContext* ctx) {
104104

105105
Status CloudStreamLoadExecutor::commit_txn(StreamLoadContext* ctx) {
106106
DBUG_EXECUTE_IF("StreamLoadExecutor.commit_txn.block", DBUG_BLOCK);
107+
DBUG_EXECUTE_IF("StreamLoadExecutor.commit_txn.crash", {
108+
LOG(INFO) << "debug point " << DP_NAME << " trigger crash";
109+
volatile int* p = nullptr;
110+
*p = 1;
111+
});
107112
// forward to fe to excute commit transaction for MoW table
108113
if (ctx->is_mow_table() || !config::enable_stream_load_commit_txn_on_be ||
109114
ctx->load_type == TLoadType::ROUTINE_LOAD) {

be/src/cloud/cloud_tablet_mgr.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "common/status.h"
3030
#include "olap/lru_cache.h"
3131
#include "runtime/memory/cache_policy.h"
32+
#include "util/debug_points.h"
3233
#include "util/stack_util.h"
3334

3435
namespace doris {
@@ -148,7 +149,9 @@ CloudTabletMgr::CloudTabletMgr(CloudStorageEngine& engine)
148149
_tablet_map(std::make_unique<TabletMap>()),
149150
_cache(std::make_unique<LRUCachePolicy>(
150151
CachePolicy::CacheType::CLOUD_TABLET_CACHE, config::tablet_cache_capacity,
151-
LRUCacheType::NUMBER, 0, config::tablet_cache_shards, false /*enable_prune*/)) {}
152+
LRUCacheType::NUMBER, /*sweep time*/ 0, config::tablet_cache_shards,
153+
/*element_count_capacity*/ 0, /*enable_prune*/ false,
154+
/*is_lru_k*/ false)) {}
152155

153156
CloudTabletMgr::~CloudTabletMgr() = default;
154157

@@ -163,6 +166,7 @@ Result<std::shared_ptr<CloudTablet>> CloudTabletMgr::get_tablet(int64_t tablet_i
163166
SyncRowsetStats* sync_stats,
164167
bool force_use_only_cached,
165168
bool cache_on_miss) {
169+
DBUG_EXECUTE_IF("CloudTabletMgr::get_tablet.block", DBUG_BLOCK);
166170
// LRU value type. `Value`'s lifetime MUST NOT be longer than `CloudTabletMgr`
167171
class Value : public LRUCacheValueBase {
168172
public:

be/src/cloud/cloud_txn_delete_bitmap_cache.cpp

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ namespace doris {
3434

3535
CloudTxnDeleteBitmapCache::CloudTxnDeleteBitmapCache(size_t size_in_bytes)
3636
: LRUCachePolicy(CachePolicy::CacheType::CLOUD_TXN_DELETE_BITMAP_CACHE, size_in_bytes,
37-
LRUCacheType::SIZE, 86400, 4),
37+
LRUCacheType::SIZE, /*stale_sweep_time_s*/ 86400, /*num_shards*/ 4,
38+
/*element_count_capacity*/ 0, /*enable_prune*/ true,
39+
/*is_lru_k*/ false),
3840
_stop_latch(1) {}
3941

4042
CloudTxnDeleteBitmapCache::~CloudTxnDeleteBitmapCache() {
@@ -229,7 +231,9 @@ void CloudTxnDeleteBitmapCache::remove_expired_tablet_txn_info() {
229231
std::unique_lock<std::shared_mutex> wlock(_rwlock);
230232
while (!_expiration_txn.empty()) {
231233
auto iter = _expiration_txn.begin();
232-
if (_txn_map.find(iter->second) == _txn_map.end()) {
234+
bool in_txn_map = _txn_map.find(iter->second) != _txn_map.end();
235+
bool in_markers = _empty_rowset_markers.find(iter->second) != _empty_rowset_markers.end();
236+
if (!in_txn_map && !in_markers) {
233237
_expiration_txn.erase(iter);
234238
continue;
235239
}
@@ -239,6 +243,7 @@ void CloudTxnDeleteBitmapCache::remove_expired_tablet_txn_info() {
239243
if (iter->first > current_time) {
240244
break;
241245
}
246+
// Clean from _txn_map if exists
242247
auto txn_iter = _txn_map.find(iter->second);
243248
if ((txn_iter != _txn_map.end()) && (iter->first == txn_iter->second.txn_expiration)) {
244249
LOG_INFO("clean expired delete bitmap")
@@ -251,6 +256,14 @@ void CloudTxnDeleteBitmapCache::remove_expired_tablet_txn_info() {
251256
erase(cache_key);
252257
_txn_map.erase(iter->second);
253258
}
259+
// Clean from _empty_rowset_markers if exists
260+
auto marker_iter = _empty_rowset_markers.find(iter->second);
261+
if (marker_iter != _empty_rowset_markers.end()) {
262+
LOG_INFO("clean expired empty rowset marker")
263+
.tag("txn_id", iter->second.txn_id)
264+
.tag("tablet_id", iter->second.tablet_id);
265+
_empty_rowset_markers.erase(marker_iter);
266+
}
254267
_expiration_txn.erase(iter);
255268
}
256269
}
@@ -272,6 +285,32 @@ void CloudTxnDeleteBitmapCache::remove_unused_tablet_txn_info(TTransactionId tra
272285
}
273286
}
274287

288+
void CloudTxnDeleteBitmapCache::mark_empty_rowset(TTransactionId txn_id, int64_t tablet_id,
289+
int64_t txn_expiration) {
290+
int64_t txn_expiration_min =
291+
duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch())
292+
.count() +
293+
config::tablet_txn_info_min_expired_seconds;
294+
txn_expiration = std::max(txn_expiration_min, txn_expiration);
295+
296+
if (config::enable_mow_verbose_log) {
297+
LOG_INFO("mark empty rowset")
298+
.tag("txn_id", txn_id)
299+
.tag("tablet_id", tablet_id)
300+
.tag("expiration", txn_expiration);
301+
}
302+
std::unique_lock<std::shared_mutex> wlock(_rwlock);
303+
TxnKey txn_key(txn_id, tablet_id);
304+
_empty_rowset_markers.emplace(txn_key);
305+
_expiration_txn.emplace(txn_expiration, txn_key);
306+
}
307+
308+
bool CloudTxnDeleteBitmapCache::is_empty_rowset(TTransactionId txn_id, int64_t tablet_id) {
309+
std::shared_lock<std::shared_mutex> rlock(_rwlock);
310+
TxnKey txn_key(txn_id, tablet_id);
311+
return _empty_rowset_markers.contains(txn_key);
312+
}
313+
275314
void CloudTxnDeleteBitmapCache::_clean_thread_callback() {
276315
do {
277316
remove_expired_tablet_txn_info();

be/src/cloud/cloud_txn_delete_bitmap_cache.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,16 @@ class CloudTxnDeleteBitmapCache : public LRUCachePolicy {
5959

6060
void remove_unused_tablet_txn_info(TTransactionId transaction_id, int64_t tablet_id);
6161

62+
// Mark a rowset as empty/skipped (lightweight marker, no rowset stored)
63+
// Used for empty rowsets when skip_writing_empty_rowset_metadata is enabled
64+
void mark_empty_rowset(TTransactionId txn_id, int64_t tablet_id, int64_t txn_expiration);
65+
66+
// Check if this is a known empty/skipped rowset
67+
// Returns true if was marked as empty rowset
68+
// Note: Does not remove the marker, as CalcDeleteBitmapTask may retry.
69+
// Cleanup is handled by expiration-based removal in remove_expired_tablet_txn_info()
70+
bool is_empty_rowset(TTransactionId txn_id, int64_t tablet_id);
71+
6272
// !!!ATTENTION!!!: the delete bitmap stored in CloudTxnDeleteBitmapCache contains sentinel marks,
6373
// and the version in BitmapKey is DeleteBitmap::TEMP_VERSION_COMMON.
6474
// when using delete bitmap from this cache, the caller should manually remove these marks if don't need it
@@ -107,6 +117,9 @@ class CloudTxnDeleteBitmapCache : public LRUCachePolicy {
107117

108118
std::map<TxnKey, TxnVal> _txn_map;
109119
std::multimap<int64_t, TxnKey> _expiration_txn;
120+
// Lightweight markers for empty/skipped rowsets (only stores TxnKey, ~16 bytes per entry)
121+
// Used to track empty rowsets that were not committed to meta-service
122+
std::set<TxnKey> _empty_rowset_markers;
110123
std::shared_mutex _rwlock;
111124
std::shared_ptr<Thread> _clean_thread;
112125
CountDownLatch _stop_latch;

be/src/cloud/config.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ DEFINE_mBool(enable_cloud_tablet_report, "true");
110110

111111
DEFINE_mInt32(delete_bitmap_rpc_retry_times, "25");
112112

113-
DEFINE_mInt64(meta_service_rpc_reconnect_interval_ms, "5000");
113+
DEFINE_mInt64(meta_service_rpc_reconnect_interval_ms, "100");
114114

115115
DEFINE_mInt32(meta_service_conflict_error_retry_times, "10");
116116

@@ -135,7 +135,7 @@ DEFINE_mInt64(warm_up_rowset_sync_wait_max_timeout_ms, "120000");
135135
DEFINE_mBool(enable_warmup_immediately_on_new_rowset, "false");
136136

137137
// Packed file manager config
138-
DEFINE_mBool(enable_packed_file, "true");
138+
DEFINE_mBool(enable_packed_file, "false");
139139
DEFINE_mInt64(packed_file_size_threshold_bytes, "5242880"); // 5MB
140140
DEFINE_mInt64(packed_file_time_threshold_ms, "100"); // 100ms
141141
DEFINE_mInt64(packed_file_try_lock_timeout_ms, "5"); // 5ms

be/src/cloud/injection_point_action.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,17 @@ void set_return_error(const std::string& point, HttpRequest* req) {
279279
HttpChannel::send_reply(req, HttpStatus::OK, "OK");
280280
}
281281

282+
void set_segfault(const std::string& point, HttpRequest* req) {
283+
auto sp = SyncPoint::get_instance();
284+
sp->set_call_back(point, [point](auto&&) {
285+
LOG(INFO) << "injection point hit, point=" << point << " trigger segfault";
286+
// Intentional null dereference to crash the BE for testing.
287+
volatile int* p = nullptr;
288+
*p = 1;
289+
});
290+
HttpChannel::send_reply(req, HttpStatus::OK, "OK");
291+
}
292+
282293
void handle_set(HttpRequest* req) {
283294
auto& point = req->param("name");
284295
if (point.empty()) {
@@ -302,6 +313,9 @@ void handle_set(HttpRequest* req) {
302313
} else if (behavior == "return_error") {
303314
set_return_error(point, req);
304315
return;
316+
} else if (behavior == "segfault") {
317+
set_segfault(point, req);
318+
return;
305319
}
306320
HttpChannel::send_reply(req, HttpStatus::BAD_REQUEST, "unknown behavior: " + behavior);
307321
}
@@ -377,13 +391,15 @@ InjectionPointAction::InjectionPointAction() = default;
377391
// which is an int, valid values can be found in status.h, e.g. -235 or -230,
378392
// if `code` is not present return Status::InternalError. Optional `probability`
379393
// determines the percentage of times to inject the error (default 100).
394+
// * segfault: dereference a null pointer to crash BE intentionally
380395
// ```
381396
// curl "be_ip:http_port/api/injection_point/set?name=${injection_point_name}&behavior=sleep&duration=${x_millsec}" # sleep x millisecs
382397
// curl "be_ip:http_port/api/injection_point/set?name=${injection_point_name}&behavior=return" # return void
383398
// curl "be_ip:http_port/api/injection_point/set?name=${injection_point_name}&behavior=return_ok" # return ok
384399
// curl "be_ip:http_port/api/injection_point/set?name=${injection_point_name}&behavior=return_error" # internal error
385400
// curl "be_ip:http_port/api/injection_point/set?name=${injection_point_name}&behavior=return_error&code=${code}" # -235
386401
// curl "be_ip:http_port/api/injection_point/set?name=${injection_point_name}&behavior=return_error&code=${code}&probability=50" # inject with 50% probability
402+
// curl "be_ip:http_port/api/injection_point/set?name=${injection_point_name}&behavior=segfault" # crash BE
387403
// ```
388404
void InjectionPointAction::handle(HttpRequest* req) {
389405
LOG(INFO) << "handle InjectionPointAction " << req->debug_string();

0 commit comments

Comments
 (0)