github-actions[bot] commented on code in PR #65550:
URL: https://github.com/apache/doris/pull/65550#discussion_r3780954829


##########
cloud/src/recycler/recycler.cpp:
##########
@@ -5067,6 +5189,33 @@ int InstanceRecycler::recycle_rowsets() {
         return 0;
     };
 
+    auto submit_recycle_prepare_rowsets_job = [&](std::string key, std::string 
resource_id,
+                                                  int64_t tablet_id, 
std::string rowset_id) {
+        int ret = worker_pool->submit([&, key = std::move(key),
+                                       resource_id = std::move(resource_id), 
tablet_id,
+                                       rowset_id = std::move(rowset_id)]() 
mutable {
+            std::vector<std::string> aborted_keys;
+            if (batch_abort_txn_or_job_for_recycle<RecycleRowsetPB>({key}, 
aborted_keys) != 0 ||
+                aborted_keys.empty()) {
+                return;
+            }
+            if (delete_rowset_data(resource_id, tablet_id, rowset_id) != 0) {
+                LOG(WARNING) << "failed to delete rowset data, key=" << 
hex(key);
+                return;
+            }
+            if (delete_versioned_delete_bitmap_kvs(tablet_id, rowset_id) != 0) 
{
+                return;
+            }
+            if (txn_remove(txn_kv_.get(), aborted_keys) != 0) {

Review Comment:
   [P2] Count successful abort-protected deletions
   
   After this removal succeeds, the new PREPARE path exits without incrementing 
`num_recycled` as the other prefix/formal deletion workers do. An all-PREPARE 
abort-enabled run can therefore delete every object and KV while its completion 
log reports `num_recycled=0`. Update the counter after successful KV removal 
and cover it in the new PREPARE tests.



##########
cloud/src/recycler/recycler.cpp:
##########
@@ -5177,8 +5302,34 @@ int InstanceRecycler::recycle_rowsets() {
                   << " creation_time=" << rowset_meta->creation_time()
                   << " task_type=" << metrics_context.operation_type;
         if (rowset.type() == RecycleRowsetPB::PREPARE) {
-            // unable to calculate file path, can only be deleted by rowset id 
prefix
+            if (config::enable_mark_delete_rowset_before_recycle) {
+                if (need_mark_rowset_as_recycled(rowset.rowset_meta())) {
+                    rowset_keys_to_mark_recycled.emplace_back(k);
+                    LOG(INFO) << "rowset queued to mark as recycled, recycler 
will delete data and "
+                                 "kv "
+                                 "at next turn, instance_id="
+                              << instance_id_ << " tablet_id=" << 
rowset_meta->tablet_id()
+                              << " version=[" << rowset_meta->start_version() 
<< '-'
+                              << rowset_meta->end_version() << "]";
+                    return 0;
+                }
+            }
+
             num_prepare += 1;
+            if 
(config::enable_abort_txn_and_job_for_delete_rowset_before_recycle &&
+                rowset_meta->end_version() != 1) {
+                if (make_related_txn_or_job_abort_task(rowset).has_value()) {
+                    LOG(INFO) << "rowset queued to abort related txn or job 
before recycling, "
+                                 "instance_id="
+                              << instance_id_ << " tablet_id=" << 
rowset_meta->tablet_id()
+                              << " version=[" << rowset_meta->start_version() 
<< '-'
+                              << rowset_meta->end_version() << "]";
+                    submit_recycle_prepare_rowsets_job(std::string(k), 
rowset_meta->resource_id(),

Review Comment:
   [P2] Coalesce PREPARE aborts by owner
   
   This submits one abort transaction per rowset, so the default 32 workers 
race when many PREPARE rowsets share one load txn or tablet job. They all 
read/write the same owner record; one commit wins and the losers return 
`TXN_CONFLICT`, retaining already-expired keys until the next recycler interval 
(normally 3600s). Group by `txn_id` or exact `(tablet_id, job_id)`, abort once, 
and fan the result out to all owned keys. The added 257-key test does not cover 
this: an earlier test leaks `worker_pool_size=1`, and each invocation here 
passes only `{key}`, so it neither exercises production concurrency nor the 
256-item collector batch.



##########
cloud/src/recycler/recycler.cpp:
##########
@@ -5990,12 +6104,13 @@ int InstanceRecycler::recycle_tmp_rowsets() {
         }
 
         if (config::enable_abort_txn_and_job_for_delete_rowset_before_recycle) 
{
-            if (make_deferred_abort_task(rowset).has_value()) {
+            if (make_related_txn_or_job_abort_task(rowset).has_value()) {
                 LOG(INFO) << "rowset queued to abort related txn or job after 
current scan batch, "
                              "instance_id="
                           << instance_id_ << " tablet_id=" << 
rowset.tablet_id() << " version=["
                           << rowset.start_version() << '-' << 
rowset.end_version() << "]";
                 tmp_rowset_keys_to_abort.emplace_back(k);
+                return 0;

Review Comment:
   [P2] Preserve expired accounting when deferring tmp aborts
   
   This new return skips `++num_expired` and `expired_rowset_size += v.size()` 
below for every owner-associated tmp rowset. When the worker aborts and deletes 
the key successfully it still increments `num_recycled`, so a run can report 
`num_recycled > num_expired` and zero expired metadata bytes for the data it 
just reclaimed. Record the expired key/value before deferring the abort (or 
account from the worker's reread) and cover these completion fields in the 
tmp-rowset tests.



##########
cloud/src/recycler/recycler.cpp:
##########
@@ -2081,77 +2147,125 @@ int collect_deferred_abort_tasks(TxnKv* txn_kv, const 
std::string& instance_id,
 
 template <typename T>
 int InstanceRecycler::batch_abort_txn_or_job_for_recycle(const 
std::vector<std::string>& keys,
-                                                         bool 
skip_base_version) {
-    std::vector<DeferredRecycleAbortTask> abort_tasks;
-    if (collect_deferred_abort_tasks<T>(txn_kv_.get(), instance_id_, keys, 
&abort_tasks,
-                                        skip_base_version) != 0) {
+                                                         
std::vector<std::string>& aborted_keys) {
+    std::vector<RelatedTxnOrJobAbortTask> abort_tasks;
+    if (collect_deferred_abort_tasks<T>(txn_kv_.get(), instance_id_, keys, 
&abort_tasks) != 0) {
         LOG(WARNING) << "failed to collect rowset abort tasks, instance_id=" 
<< instance_id_;
         return -1;
     }
+    int ret = 0;
     for (const auto& abort_task : abort_tasks) {
-        LOG(INFO) << "begin to abort txn or job for related rowset, 
instance_id=" << instance_id_
-                  << " tablet_id=" << abort_task.tablet_id << " version=["
-                  << abort_task.start_version << '-' << abort_task.end_version 
<< "]";
         int abort_ret = 0;
-        if (abort_task.type == DeferredRecycleAbortTask::Type::TXN) {
+        if (abort_task.type == RelatedTxnOrJobAbortTask::Type::TXN) {
             abort_ret = abort_txn_for_related_rowset(abort_task.txn_id);
         } else {
-            RowsetMetaCloudPB rowset_meta;
-            rowset_meta.set_tablet_id(abort_task.tablet_id);
-            rowset_meta.set_rowset_id_v2(abort_task.rowset_id);
-            rowset_meta.set_job_id(abort_task.job_id);
-            abort_ret = abort_job_for_related_rowset(rowset_meta);
+            abort_ret = abort_job_for_related_rowset(abort_task.tablet_id, 
abort_task.rowset_id,
+                                                     abort_task.job_id);
         }
         if (abort_ret != 0) {
             LOG(WARNING) << "failed to abort txn or job for related rowset, 
instance_id="
                          << instance_id_ << " tablet_id=" << 
abort_task.tablet_id << " version=["
                          << abort_task.start_version << '-' << 
abort_task.end_version << "]";
-            return abort_ret;
+            ret = abort_ret;
+            continue;
         }
+        aborted_keys.emplace_back(abort_task.key);
     }
-    return 0;
+    return ret;
 }
 
-int collect_prepare_delete_tasks(TxnKv* txn_kv, const std::string& instance_id,
-                                 const std::vector<std::string>& keys,
-                                 
std::vector<DeferredRecyclePrepareDeleteTask>* delete_tasks) {
-    constexpr size_t kPrepareCheckBatchSize = 256;
-    for (size_t offset = 0; offset < keys.size(); offset += 
kPrepareCheckBatchSize) {
-        size_t limit = std::min(keys.size(), offset + kPrepareCheckBatchSize);
-        std::unique_ptr<Transaction> txn;
-        TxnErrorCode err = txn_kv->create_txn(&txn);
-        if (err != TxnErrorCode::TXN_OK) {
-            LOG(WARNING) << "failed to create txn, instance_id=" << 
instance_id;
-            return -1;
+void InstanceRecycler::submit_recycle_tmp_rowsets_job(
+        SimpleThreadPool& worker_pool, std::vector<std::string> 
tmp_rowset_keys_to_delete,
+        std::vector<std::string> rowset_keys_to_mark, std::vector<std::string> 
rowset_keys_to_abort,
+        std::atomic_long* num_recycled, RecyclerMetricsContext* 
metrics_context) {
+    if (tmp_rowset_keys_to_delete.empty() && rowset_keys_to_mark.empty() &&
+        rowset_keys_to_abort.empty()) {
+        return;
+    }
+    worker_pool.submit([this, tmp_rowset_keys_to_delete = 
std::move(tmp_rowset_keys_to_delete),
+                        rowset_keys_to_mark = std::move(rowset_keys_to_mark),
+                        rowset_keys_to_abort = 
std::move(rowset_keys_to_abort), num_recycled,
+                        metrics_context]() mutable {
+        if (!rowset_keys_to_mark.empty() &&
+            batch_mark_rowsets_as_recycled<RowsetMetaCloudPB>(txn_kv_.get(), 
instance_id_,
+                                                              
rowset_keys_to_mark) != 0) {
+            LOG(WARNING) << "failed to batch mark tmp rowsets as recycled, 
instance_id="
+                         << instance_id_;
+            return;
         }
-        for (size_t idx = offset; idx < limit; ++idx) {
-            const std::string& key = keys[idx];
+
+        if (!rowset_keys_to_abort.empty() &&
+            
batch_abort_txn_or_job_for_recycle<RowsetMetaCloudPB>(rowset_keys_to_abort,
+                                                                  
tmp_rowset_keys_to_delete) != 0) {
+            LOG(WARNING) << "failed to abort some txn or job for related tmp 
rowset, "
+                            "instance_id="
+                         << instance_id_;
+        }
+
+        // Keys that do not need an abort were added during the scan. Keys 
related to a txn
+        // or job are added only after the abort succeeds. A failed abort 
leaves its tmp
+        // rowset KV for the next recycler round.
+        std::map<std::string, RowsetMetaCloudPB> tmp_rowsets_to_delete;
+        std::vector<std::string> current_tmp_rowset_keys;
+        std::vector<std::string> current_tmp_rowset_ref_count_keys;
+        for (const auto& key : tmp_rowset_keys_to_delete) {
+            // The tmp rowset may have changed after the scan. Read it again 
before deleting
+            // its object data and metadata.
             std::string val;
-            err = txn->get(key, &val);
-            if (err == TxnErrorCode::TXN_KEY_NOT_FOUND) {
-                // has already been removed
+            int ret = txn_get(txn_kv_.get(), key, val);

Review Comment:
   [P2] Batch the tmp-rowset freshness reads
   
   This loop calls `txn_get()` once per key; that helper creates a new 
transaction and synchronously waits for one snapshot point read. A scan page 
can contain 10,000 expired tmp keys, so one worker can perform 10,000 serial 
FDB round trips before any object cleanup begins. Keep the post-abort freshness 
check, but use snapshot `batch_get` in bounded chunks (the existing API issues 
up to 1,000 FDB gets concurrently) and retain the per-key missing/parse 
handling. Please add a large-batch read-count or instrumentation test.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to