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

gavinchou pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 149cb668fb9 [fix](cloud) Avoid deleting nonexistent delete bitmap 
files (#62967)
149cb668fb9 is described below

commit 149cb668fb90dffd9338022245a0bb94cdde5215
Author: Yixuan Wang <[email protected]>
AuthorDate: Wed May 6 15:48:25 2026 +0800

    [fix](cloud) Avoid deleting nonexistent delete bitmap files (#62967)
    
    When recycling rowset data, the recycler treated a missing versioned delete 
bitmap meta key as "not packed" and added the standalone delete bitmap object 
path to the delete_files request. This caused unnecessary delete object 
requests for `<rowset_id>_delete_bitmap.db` even when no delete bitmap storage 
metadata existed.
    
    The fix makes delete bitmap storage handling explicit: missing meta, FDB 
storage, standalone file storage, and packed file storage are distinguished. 
The recycler now only deletes `<rowset_id>_delete_bitmap.db` when the metadata 
explicitly indicates a standalone delete bitmap file.
---
 cloud/src/recycler/recycler.cpp | 45 ++++++++++++++++++++---------------
 cloud/src/recycler/recycler.h   | 14 +++++++----
 cloud/test/mock_accessor.h      |  2 +-
 cloud/test/recycler_test.cpp    | 52 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 89 insertions(+), 24 deletions(-)

diff --git a/cloud/src/recycler/recycler.cpp b/cloud/src/recycler/recycler.cpp
index 0417ddaa2f4..e7ea909906b 100644
--- a/cloud/src/recycler/recycler.cpp
+++ b/cloud/src/recycler/recycler.cpp
@@ -3000,18 +3000,17 @@ int InstanceRecycler::delete_rowset_data(const 
RowsetMetaCloudPB& rs_meta_pb) {
         }
     }
 
-    // Process delete bitmap - check if it's stored in packed file
-    bool delete_bitmap_is_packed = false;
+    // Process delete bitmap - check where it's stored.
+    DeleteBitmapStorageType delete_bitmap_storage_type = 
DeleteBitmapStorageType::NOT_FOUND;
     if (decrement_delete_bitmap_packed_file_ref_counts(tablet_id, rowset_id,
-                                                       
&delete_bitmap_is_packed) != 0) {
+                                                       
&delete_bitmap_storage_type) != 0) {
         LOG_WARNING("failed to decrement delete bitmap packed file ref count")
                 .tag("instance_id", instance_id_)
                 .tag("tablet_id", tablet_id)
                 .tag("rowset_id", rowset_id);
         return -1;
     }
-    // Only delete standalone delete bitmap file if not stored in packed file
-    if (!delete_bitmap_is_packed) {
+    if (delete_bitmap_storage_type == 
DeleteBitmapStorageType::STANDALONE_FILE) {
         file_paths.push_back(delete_bitmap_path(tablet_id, rowset_id));
     }
     // TODO(AlexYue): seems could do do batch
@@ -3257,11 +3256,11 @@ int 
InstanceRecycler::decrement_packed_file_ref_counts(const doris::RowsetMetaCl
     return ret;
 }
 
-int InstanceRecycler::decrement_delete_bitmap_packed_file_ref_counts(int64_t 
tablet_id,
-                                                                     const 
std::string& rowset_id,
-                                                                     bool* 
out_is_packed) {
-    if (out_is_packed) {
-        *out_is_packed = false;
+int InstanceRecycler::decrement_delete_bitmap_packed_file_ref_counts(
+        int64_t tablet_id, const std::string& rowset_id,
+        DeleteBitmapStorageType* out_storage_type) {
+    if (out_storage_type) {
+        *out_storage_type = DeleteBitmapStorageType::NOT_FOUND;
     }
 
     // Get delete bitmap storage info from FDB
@@ -3305,15 +3304,24 @@ int 
InstanceRecycler::decrement_delete_bitmap_packed_file_ref_counts(int64_t tab
         return -1;
     }
 
-    // Check if delete bitmap is stored in packed file
+    if (storage.store_in_fdb()) {
+        if (out_storage_type) {
+            *out_storage_type = DeleteBitmapStorageType::IN_FDB;
+        }
+        return 0;
+    }
+
+    // Check if delete bitmap is stored in standalone file.
     if (!storage.has_packed_slice_location() ||
         storage.packed_slice_location().packed_file_path().empty()) {
-        // Not stored in packed file, nothing to do
+        if (out_storage_type) {
+            *out_storage_type = DeleteBitmapStorageType::STANDALONE_FILE;
+        }
         return 0;
     }
 
-    if (out_is_packed) {
-        *out_is_packed = true;
+    if (out_storage_type) {
+        *out_storage_type = DeleteBitmapStorageType::PACKED_FILE;
     }
 
     const auto& packed_loc = storage.packed_slice_location();
@@ -3652,10 +3660,10 @@ int InstanceRecycler::delete_rowset_data(
             continue;
         }
 
-        // Process delete bitmap - check if it's stored in packed file
-        bool delete_bitmap_is_packed = false;
+        // Process delete bitmap - check where it's stored.
+        DeleteBitmapStorageType delete_bitmap_storage_type = 
DeleteBitmapStorageType::NOT_FOUND;
         if (decrement_delete_bitmap_packed_file_ref_counts(tablet_id, 
rowset_id,
-                                                           
&delete_bitmap_is_packed) != 0) {
+                                                           
&delete_bitmap_storage_type) != 0) {
             LOG_WARNING("failed to decrement delete bitmap packed file ref 
count")
                     .tag("instance_id", instance_id_)
                     .tag("tablet_id", tablet_id)
@@ -3663,8 +3671,7 @@ int InstanceRecycler::delete_rowset_data(
             ret = -1;
             continue;
         }
-        // Only delete standalone delete bitmap file if not stored in packed 
file
-        if (!delete_bitmap_is_packed) {
+        if (delete_bitmap_storage_type == 
DeleteBitmapStorageType::STANDALONE_FILE) {
             file_paths.push_back(delete_bitmap_path(tablet_id, rowset_id));
         }
 
diff --git a/cloud/src/recycler/recycler.h b/cloud/src/recycler/recycler.h
index ab03460093a..e04a69e0ec5 100644
--- a/cloud/src/recycler/recycler.h
+++ b/cloud/src/recycler/recycler.h
@@ -463,13 +463,19 @@ private:
     // Returns 0 for success, -1 for error.
     int decrement_packed_file_ref_counts(const doris::RowsetMetaCloudPB& 
rs_meta_pb);
 
-    // Decrement packed file ref count for delete bitmap if it's stored in 
packed file.
+    enum class DeleteBitmapStorageType {
+        NOT_FOUND,
+        IN_FDB,
+        STANDALONE_FILE,
+        PACKED_FILE,
+    };
+
+    // Process delete bitmap storage and decrement packed file ref count when 
needed.
     // Returns 0 for success, -1 for error.
-    // If delete bitmap is not stored in packed file, this function does 
nothing and returns 0.
-    // out_is_packed: if not null, will be set to true if delete bitmap is 
stored in packed file.
+    // out_storage_type: if not null, will be set to the delete bitmap storage 
type.
     int decrement_delete_bitmap_packed_file_ref_counts(int64_t tablet_id,
                                                        const std::string& 
rowset_id,
-                                                       bool* out_is_packed);
+                                                       
DeleteBitmapStorageType* out_storage_type);
 
     int delete_packed_file_and_kv(const std::string& packed_file_path,
                                   const std::string& packed_key,
diff --git a/cloud/test/mock_accessor.h b/cloud/test/mock_accessor.h
index 6c187b7ca99..0e29c383899 100644
--- a/cloud/test/mock_accessor.h
+++ b/cloud/test/mock_accessor.h
@@ -151,7 +151,7 @@ inline int MockAccessor::delete_all(int64_t 
expiration_time) {
 }
 
 inline int MockAccessor::delete_files(const std::vector<std::string>& paths) {
-    TEST_SYNC_POINT_RETURN_WITH_VALUE("MockAccessor::delete_files", (int)0);
+    TEST_SYNC_POINT_RETURN_WITH_VALUE("MockAccessor::delete_files", (int)0, 
&paths);
 
     for (auto&& path : paths) {
         delete_file(path);
diff --git a/cloud/test/recycler_test.cpp b/cloud/test/recycler_test.cpp
index 8a657314288..ffe2401862b 100644
--- a/cloud/test/recycler_test.cpp
+++ b/cloud/test/recycler_test.cpp
@@ -33,6 +33,7 @@
 #include <exception>
 #include <future>
 #include <memory>
+#include <numeric>
 #include <random>
 #include <string>
 #include <string_view>
@@ -5571,6 +5572,57 @@ TEST(RecyclerTest, delete_rowset_data) {
     }
 }
 
+TEST(RecyclerTest, delete_rowset_data_without_delete_bitmap_meta) {
+    auto txn_kv = std::make_shared<MemTxnKv>();
+    ASSERT_EQ(txn_kv->init(), 0);
+
+    constexpr std::string_view resource_id = 
"delete_rowset_data_without_delete_bitmap_meta";
+    InstanceInfoPB instance;
+    instance.set_instance_id(instance_id);
+    auto obj_info = instance.add_obj_info();
+    obj_info->set_id(std::string(resource_id));
+    obj_info->set_ak(config::test_s3_ak);
+    obj_info->set_sk(config::test_s3_sk);
+    obj_info->set_endpoint(config::test_s3_endpoint);
+    obj_info->set_region(config::test_s3_region);
+    obj_info->set_bucket(config::test_s3_bucket);
+    obj_info->set_prefix(std::string(resource_id));
+
+    InstanceRecycler recycler(txn_kv, instance, thread_group,
+                              std::make_shared<TxnLazyCommitter>(txn_kv));
+    ASSERT_EQ(recycler.init(), 0);
+    auto accessor = recycler.accessor_map_.begin()->second;
+
+    doris::TabletSchemaCloudPB schema;
+    schema.set_schema_version(1);
+    schema.set_inverted_index_storage_format(InvertedIndexStorageFormatPB::V1);
+
+    auto rowset = create_rowset(std::string(resource_id), 10002, 10001, 1, 
schema);
+    ASSERT_EQ(create_recycle_rowset(txn_kv.get(), accessor.get(), rowset, 
RecycleRowsetPB::COMPACT,
+                                    true),
+              0);
+
+    auto sp = SyncPoint::get_instance();
+    DORIS_CLOUD_DEFER {
+        SyncPoint::get_instance()->clear_all_call_backs();
+    };
+    std::vector<std::string> deleted_paths;
+    sp->set_call_back("MockAccessor::delete_files", [&](auto&& args) {
+        auto* paths = try_any_cast<const std::vector<std::string>*>(args[0]);
+        deleted_paths.insert(deleted_paths.end(), paths->begin(), 
paths->end());
+    });
+    sp->enable_processing();
+
+    ASSERT_EQ(recycler.delete_rowset_data(rowset), 0);
+    ASSERT_EQ(deleted_paths.size(), 1)
+            << " size: " << deleted_paths.size() << " content: "
+            << std::accumulate(deleted_paths.begin(), deleted_paths.end(), 
std::string(),
+                               [](const std::string& str, const std::string& 
it) {
+                                   return str.empty() ? it : str + ", " + it;
+                               });
+    EXPECT_EQ(deleted_paths[0], segment_path(rowset.tablet_id(), 
rowset.rowset_id_v2(), 0));
+}
+
 TEST(RecyclerTest, delete_rowset_data_packed_file_single_rowset) {
     auto txn_kv = std::make_shared<MemTxnKv>();
     ASSERT_EQ(txn_kv->init(), 0);


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

Reply via email to