This is an automated email from the ASF dual-hosted git repository.

yiguolei pushed a commit to branch branch-4.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-4.1 by this push:
     new 8faa9bc8e33 branch-4.1: [improve](cloud) Txn lazy commit defers 
deleting pending delete bitmaps #59413 (#61573)
8faa9bc8e33 is described below

commit 8faa9bc8e3378f8281bb83f1ee91c995eb7eb81a
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Tue Mar 24 15:25:00 2026 +0800

    branch-4.1: [improve](cloud) Txn lazy commit defers deleting pending delete 
bitmaps #59413 (#61573)
    
    Cherry-picked from #59413
    
    Co-authored-by: walter <[email protected]>
---
 cloud/src/common/config.h                     |  4 ++
 cloud/src/meta-service/meta_service_txn.cpp   | 80 +++++++++++++++++++++++++--
 cloud/src/meta-service/txn_lazy_committer.cpp | 59 +++++++++++++++++---
 cloud/src/meta-service/txn_lazy_committer.h   |  3 +-
 gensrc/proto/cloud.proto                      |  4 ++
 5 files changed, 138 insertions(+), 12 deletions(-)

diff --git a/cloud/src/common/config.h b/cloud/src/common/config.h
index 214f7599995..243ca05c680 100644
--- a/cloud/src/common/config.h
+++ b/cloud/src/common/config.h
@@ -320,6 +320,10 @@ CONF_Int32(parallel_txn_lazy_commit_num_threads, "0"); // 
hardware concurrency i
 CONF_mInt64(txn_lazy_max_rowsets_per_batch, "1000");
 CONF_mBool(txn_lazy_commit_shuffle_partitions, "true");
 CONF_Int64(txn_lazy_commit_shuffle_seed, "0"); // 0 means generate a random 
seed
+// WARNING: All meta-servers MUST be upgraded before changing this to true.
+// When enabled, defer deleting pending delete bitmaps until lazy commit 
completes.
+// This reduces contention during transaction commit by extending delete 
bitmap locks.
+CONF_mBool(txn_lazy_commit_defer_deleting_pending_delete_bitmaps, "false");
 // max TabletIndexPB num for batch get
 CONF_Int32(max_tablet_index_num_per_batch, "1000");
 CONF_Int32(max_restore_job_rowsets_per_batch, "1000");
diff --git a/cloud/src/meta-service/meta_service_txn.cpp 
b/cloud/src/meta-service/meta_service_txn.cpp
index adddd83744f..863f3f7dea2 100644
--- a/cloud/src/meta-service/meta_service_txn.cpp
+++ b/cloud/src/meta-service/meta_service_txn.cpp
@@ -1234,6 +1234,64 @@ void update_tablet_stats(const StatsTabletKeyInfo& info, 
const TabletStats& stat
     }
 }
 
+// process mow table, check lock and update lock timeout
+void process_mow_when_commit_txn_deferred(
+        const CommitTxnRequest* request, const std::string& instance_id, 
MetaServiceCode& code,
+        std::string& msg, std::unique_ptr<Transaction>& txn,
+        std::unordered_map<int64_t, std::vector<int64_t>>& 
table_id_tablet_ids) {
+    int64_t txn_id = request->txn_id();
+    std::stringstream ss;
+    std::vector<std::string> lock_keys;
+    lock_keys.reserve(request->mow_table_ids().size());
+    for (auto table_id : request->mow_table_ids()) {
+        lock_keys.push_back(meta_delete_bitmap_update_lock_key({instance_id, 
table_id, -1}));
+    }
+    std::vector<std::optional<std::string>> lock_values;
+    TxnErrorCode err = txn->batch_get(&lock_values, lock_keys);
+    if (err != TxnErrorCode::TXN_OK) {
+        ss << "failed to get delete bitmap update lock key info, instance_id=" 
<< instance_id
+           << " err=" << err;
+        msg = ss.str();
+        code = cast_as<ErrCategory::READ>(err);
+        LOG(WARNING) << msg << " txn_id=" << txn_id;
+        return;
+    }
+    size_t total_locks = lock_keys.size();
+    for (size_t i = 0; i < total_locks; i++) {
+        int64_t table_id = request->mow_table_ids(i);
+        // When the key does not exist, it means the lock has been acquired
+        // by another transaction and successfully committed.
+        if (!lock_values[i].has_value()) {
+            ss << "get delete bitmap update lock info, lock is expired"
+               << " table_id=" << table_id << " key=" << hex(lock_keys[i]) << 
" txn_id=" << txn_id;
+            code = MetaServiceCode::LOCK_EXPIRED;
+            msg = ss.str();
+            LOG(WARNING) << msg << " txn_id=" << txn_id;
+            return;
+        }
+
+        DeleteBitmapUpdateLockPB lock_info;
+        if (!lock_info.ParseFromString(lock_values[i].value())) [[unlikely]] {
+            code = MetaServiceCode::PROTOBUF_PARSE_ERR;
+            msg = "failed to parse DeleteBitmapUpdateLockPB";
+            LOG(WARNING) << msg << " txn_id=" << txn_id;
+            return;
+        }
+        if (lock_info.lock_id() != request->txn_id()) {
+            ss << "lock is expired, locked by lock_id=" << lock_info.lock_id();
+            msg = ss.str();
+            code = MetaServiceCode::LOCK_EXPIRED;
+            return;
+        }
+        lock_info.set_expiration(std::numeric_limits<int64_t>::max());
+        txn->put(lock_keys[i], lock_info.SerializeAsString());
+        LOG(INFO) << "refresh delete bitmap lock, lock_key=" << 
hex(lock_keys[i])
+                  << " table_id=" << table_id << " txn_id=" << txn_id;
+    }
+    lock_keys.clear();
+    lock_values.clear();
+}
+
 // process mow table, check lock and remove pending key
 void process_mow_when_commit_txn(
         const CommitTxnRequest* request, const std::string& instance_id, 
MetaServiceCode& code,
@@ -2396,10 +2454,24 @@ void MetaServiceImpl::commit_txn_eventually(
         for (auto& [tablet_id, tablet_idx] : tablet_ids) {
             table_id_tablet_ids[tablet_idx.table_id()].push_back(tablet_id);
         }
-        process_mow_when_commit_txn(request, instance_id, code, msg, txn, 
table_id_tablet_ids);
-        if (code != MetaServiceCode::OK) {
-            LOG(WARNING) << "process mow failed, txn_id=" << txn_id << " 
code=" << code;
-            return;
+        if (config::txn_lazy_commit_defer_deleting_pending_delete_bitmaps) {
+            txn_info.clear_table_ids();
+            for (auto& [table_id, _] : table_id_tablet_ids) {
+                txn_info.add_table_ids(table_id);
+            }
+            txn_info.set_defer_deleting_pending_delete_bitmaps(true);
+            process_mow_when_commit_txn_deferred(request, instance_id, code, 
msg, txn,
+                                                 table_id_tablet_ids);
+            if (code != MetaServiceCode::OK) {
+                LOG(WARNING) << "process mow failed, txn_id=" << txn_id << " 
code=" << code;
+                return;
+            }
+        } else {
+            process_mow_when_commit_txn(request, instance_id, code, msg, txn, 
table_id_tablet_ids);
+            if (code != MetaServiceCode::OK) {
+                LOG(WARNING) << "process mow failed, txn_id=" << txn_id << " 
code=" << code;
+                return;
+            }
         }
 
         // table_id -> version, for response
diff --git a/cloud/src/meta-service/txn_lazy_committer.cpp 
b/cloud/src/meta-service/txn_lazy_committer.cpp
index 115161693b8..130745e5e0b 100644
--- a/cloud/src/meta-service/txn_lazy_committer.cpp
+++ b/cloud/src/meta-service/txn_lazy_committer.cpp
@@ -213,7 +213,8 @@ void convert_tmp_rowsets(
         MetaServiceCode& code, std::string& msg, int64_t db_id,
         std::vector<std::pair<std::string, doris::RowsetMetaCloudPB>>& 
tmp_rowsets_meta,
         std::map<int64_t, TabletIndexPB>& tablet_ids, bool is_versioned_write,
-        bool is_versioned_read, Versionstamp versionstamp, ResourceManager* 
resource_mgr) {
+        bool is_versioned_read, Versionstamp versionstamp, ResourceManager* 
resource_mgr,
+        bool defer_deleting_pending_delete_bitmaps) {
     std::stringstream ss;
     std::unique_ptr<Transaction> txn;
     TxnErrorCode err = txn_kv->create_txn(&txn);
@@ -483,6 +484,15 @@ void convert_tmp_rowsets(
         }
     }
 
+    if (defer_deleting_pending_delete_bitmaps) {
+        for (auto& [tablet_id, _] : tablet_stats) {
+            std::string pending_key = 
meta_pending_delete_bitmap_key({instance_id, tablet_id});
+            txn->remove(pending_key);
+            LOG(INFO) << "remove delete bitmap pending key, pending_key=" << 
hex(pending_key)
+                      << " txn_id=" << txn_id;
+        }
+    }
+
     TEST_SYNC_POINT_RETURN_WITH_VOID("convert_tmp_rowsets::before_commit", 
&code);
     err = txn->commit();
     if (err != TxnErrorCode::TXN_OK) {
@@ -495,7 +505,7 @@ void convert_tmp_rowsets(
 
 void make_committed_txn_visible(const std::string& instance_id, int64_t db_id, 
int64_t txn_id,
                                 std::shared_ptr<TxnKv> txn_kv, 
MetaServiceCode& code,
-                                std::string& msg) {
+                                std::string& msg, bool 
defer_deleting_pending_delete_bitmaps) {
     // 1. visible txn info
     // 2. remove running key and put recycle txn key
 
@@ -551,6 +561,35 @@ void make_committed_txn_visible(const std::string& 
instance_id, int64_t db_id, i
         LOG(INFO) << "remove running_key=" << hex(running_key) << " txn_id=" 
<< txn_id;
         txn->remove(running_key);
 
+        // Remove delete bitmap locks if deferring deletion
+        if (defer_deleting_pending_delete_bitmaps) {
+            for (int64_t table_id : txn_info.table_ids()) {
+                std::string lock_key =
+                        meta_delete_bitmap_update_lock_key({instance_id, 
table_id, -1});
+                // Read the lock first to check if it still belongs to the 
current txn
+                std::string lock_val;
+                TxnErrorCode err = txn->get(lock_key, &lock_val);
+                if (err == TxnErrorCode::TXN_OK) {
+                    DeleteBitmapUpdateLockPB lock_info;
+                    if (lock_info.ParseFromString(lock_val)) {
+                        // Only remove the lock if it still belongs to the 
current txn
+                        if (lock_info.lock_id() == txn_id) {
+                            txn->remove(lock_key);
+                            LOG(INFO) << "remove delete bitmap lock, 
lock_key=" << hex(lock_key)
+                                      << " table_id=" << table_id << " 
txn_id=" << txn_id;
+                        } else {
+                            LOG(WARNING) << "delete bitmap lock is held by 
another txn, "
+                                         << "lock_key=" << hex(lock_key) << " 
table_id=" << table_id
+                                         << " expected_txn_id=" << txn_id
+                                         << " actual_lock_id=" << 
lock_info.lock_id();
+                        }
+                    }
+                } else if (err != TxnErrorCode::TXN_KEY_NOT_FOUND) {
+                    LOG(WARNING) << "failed to get delete bitmap lock, 
lock_key=" << hex(lock_key)
+                                 << " table_id=" << table_id << " err=" << err;
+                }
+            }
+        }
         // The recycle txn pb will be written when recycle the commit txn log,
         // if the txn versioned write is enabled.
         if (!txn_info.versioned_write()) {
@@ -635,6 +674,7 @@ void TxnLazyCommitTask::commit() {
         return;
     }
 
+    bool defer_deleting_pending_delete_bitmaps = 
txn_info.defer_deleting_pending_delete_bitmaps();
     bool is_versioned_write = txn_info.versioned_write();
     bool is_versioned_read = txn_info.versioned_read();
     CloneChainReader meta_reader(instance_id_, txn_kv_.get(),
@@ -690,7 +730,8 @@ void TxnLazyCommitTask::commit() {
                     executor.add([&, partition_id, this]() {
                         return commit_partition(db_id, partition_id,
                                                 
partition_to_tmp_rowset_metas.at(partition_id),
-                                                is_versioned_read, 
is_versioned_write);
+                                                is_versioned_read, 
is_versioned_write,
+                                                
defer_deleting_pending_delete_bitmaps);
                     });
                 }
                 bool finished = false;
@@ -711,7 +752,8 @@ void TxnLazyCommitTask::commit() {
                 for (int64_t partition_id : partition_ids) {
                     std::tie(code_, msg_) = commit_partition(
                             db_id, partition_id, 
partition_to_tmp_rowset_metas[partition_id],
-                            is_versioned_read, is_versioned_write);
+                            is_versioned_read, is_versioned_write,
+                            defer_deleting_pending_delete_bitmaps);
                     if (code_ != MetaServiceCode::OK) break;
                 }
             }
@@ -720,7 +762,8 @@ void TxnLazyCommitTask::commit() {
                 LOG(WARNING) << "txn_id=" << txn_id_ << " code=" << code_ << " 
msg=" << msg_;
                 break;
             }
-            make_committed_txn_visible(instance_id_, db_id, txn_id_, txn_kv_, 
code_, msg_);
+            make_committed_txn_visible(instance_id_, db_id, txn_id_, txn_kv_, 
code_, msg_,
+                                       defer_deleting_pending_delete_bitmaps);
         } while (false);
     } while (code_ == MetaServiceCode::KV_TXN_CONFLICT &&
              retry_times++ < config::txn_store_retry_times);
@@ -729,7 +772,8 @@ void TxnLazyCommitTask::commit() {
 std::pair<MetaServiceCode, std::string> TxnLazyCommitTask::commit_partition(
         int64_t db_id, int64_t partition_id,
         const std::vector<std::pair<std::string, doris::RowsetMetaCloudPB>>& 
tmp_rowset_metas,
-        bool is_versioned_read, bool is_versioned_write) {
+        bool is_versioned_read, bool is_versioned_write,
+        bool defer_deleting_pending_delete_bitmaps) {
     std::stringstream ss;
     CloneChainReader meta_reader(instance_id_, txn_kv_.get(),
                                  
txn_lazy_committer_->resource_manager().get());
@@ -802,7 +846,8 @@ std::pair<MetaServiceCode, std::string> 
TxnLazyCommitTask::commit_partition(
         convert_tmp_rowsets(instance_id_, txn_id_, txn_kv_, code, msg, db_id,
                             sub_partition_tmp_rowset_metas, tablet_ids, 
is_versioned_write,
                             is_versioned_read, versionstamp,
-                            txn_lazy_committer_->resource_manager().get());
+                            txn_lazy_committer_->resource_manager().get(),
+                            defer_deleting_pending_delete_bitmaps);
         if (code != MetaServiceCode::OK) {
             return {code, msg};
         }
diff --git a/cloud/src/meta-service/txn_lazy_committer.h 
b/cloud/src/meta-service/txn_lazy_committer.h
index 8ab62aff89f..048ff7cf308 100644
--- a/cloud/src/meta-service/txn_lazy_committer.h
+++ b/cloud/src/meta-service/txn_lazy_committer.h
@@ -48,7 +48,8 @@ private:
     std::pair<MetaServiceCode, std::string> commit_partition(
             int64_t db_id, int64_t partition_id,
             const std::vector<std::pair<std::string, 
doris::RowsetMetaCloudPB>>& tmp_rowset_metas,
-            bool is_versioned_write, bool is_versioned_read);
+            bool is_versioned_write, bool is_versioned_read,
+            bool defer_deleting_pending_delete_bitmaps);
 
     std::string instance_id_;
     int64_t txn_id_;
diff --git a/gensrc/proto/cloud.proto b/gensrc/proto/cloud.proto
index 8350f0b70ad..f83b6c7ce5c 100644
--- a/gensrc/proto/cloud.proto
+++ b/gensrc/proto/cloud.proto
@@ -513,6 +513,10 @@ message TxnInfoPB {
     // TODO: There are more fields TBD
     optional bool versioned_write = 19;  // versioned write, don't need to 
write RecycleTxnPB again
     optional bool versioned_read = 20;  // whether to read versioned keys
+    // When enabled, defer deleting pending delete bitmaps until lazy commit 
completes.
+    // This is used for lazy commit to reduce contention during transaction 
commit.
+    // The delete bitmap locks will be extended and removed during lazy commit 
phase.
+    optional bool defer_deleting_pending_delete_bitmaps = 21;
 }
 
 // For check txn conflict and txn timeout


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to