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

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


The following commit(s) were added to refs/heads/branch-3.1 by this push:
     new af846b20acf branch-3.1: [Fix](mow) Fix DeleteBitmap's assignment 
operator and constructor #52582 (#52975)
af846b20acf is described below

commit af846b20acfb7ab1610040b0b0207e32aecb1b5e
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Wed Jul 9 14:49:31 2025 +0800

    branch-3.1: [Fix](mow) Fix DeleteBitmap's assignment operator and 
constructor #52582 (#52975)
    
    Cherry-picked from #52582
    
    Co-authored-by: bobhan1 <[email protected]>
---
 be/src/olap/tablet_meta.cpp                        |  30 ++++--
 be/src/olap/tablet_meta.h                          |   4 +-
 .../cloud/test_cloud_mow_sc_inc_rowsets_dup.out    | Bin 0 -> 197 bytes
 .../cloud/test_cloud_mow_sc_inc_rowsets_dup.groovy | 103 +++++++++++++++++++++
 4 files changed, 128 insertions(+), 9 deletions(-)

diff --git a/be/src/olap/tablet_meta.cpp b/be/src/olap/tablet_meta.cpp
index a53518eb6e4..a6a2f900501 100644
--- a/be/src/olap/tablet_meta.cpp
+++ b/be/src/olap/tablet_meta.cpp
@@ -1116,24 +1116,40 @@ DeleteBitmapAggCache* 
DeleteBitmapAggCache::create_instance(size_t capacity) {
 DeleteBitmap::DeleteBitmap(int64_t tablet_id) : _tablet_id(tablet_id) {}
 
 DeleteBitmap::DeleteBitmap(const DeleteBitmap& o) {
-    delete_bitmap = o.delete_bitmap; // just copy data
+    std::shared_lock l1(o.lock);
+    delete_bitmap = o.delete_bitmap;
     _tablet_id = o._tablet_id;
 }
 
 DeleteBitmap& DeleteBitmap::operator=(const DeleteBitmap& o) {
-    delete_bitmap = o.delete_bitmap; // just copy data
-    _tablet_id = o._tablet_id;
+    if (this == &o) return *this;
+    if (this < &o) {
+        std::unique_lock l1(lock);
+        std::shared_lock l2(o.lock);
+        delete_bitmap = o.delete_bitmap;
+        _tablet_id = o._tablet_id;
+    } else {
+        std::shared_lock l2(o.lock);
+        std::unique_lock l1(lock);
+        delete_bitmap = o.delete_bitmap;
+        _tablet_id = o._tablet_id;
+    }
     return *this;
 }
 
-DeleteBitmap::DeleteBitmap(DeleteBitmap&& o) {
+DeleteBitmap::DeleteBitmap(DeleteBitmap&& o) noexcept {
+    std::scoped_lock l(o.lock, o._rowset_cache_version_lock);
     delete_bitmap = std::move(o.delete_bitmap);
-    _tablet_id = o._tablet_id;
+    _tablet_id = std::move(o._tablet_id);
+    o._rowset_cache_version.clear();
 }
 
-DeleteBitmap& DeleteBitmap::operator=(DeleteBitmap&& o) {
+DeleteBitmap& DeleteBitmap::operator=(DeleteBitmap&& o) noexcept {
+    if (this == &o) return *this;
+    std::scoped_lock l(lock, o.lock, o._rowset_cache_version_lock);
     delete_bitmap = std::move(o.delete_bitmap);
-    _tablet_id = o._tablet_id;
+    _tablet_id = std::move(o._tablet_id);
+    o._rowset_cache_version.clear();
     return *this;
 }
 
diff --git a/be/src/olap/tablet_meta.h b/be/src/olap/tablet_meta.h
index 0937dfbac9e..36aa566c7ef 100644
--- a/be/src/olap/tablet_meta.h
+++ b/be/src/olap/tablet_meta.h
@@ -427,8 +427,8 @@ public:
     /**
      * Move c-tor for making delete bitmap snapshot on read path
      */
-    DeleteBitmap(DeleteBitmap&& r);
-    DeleteBitmap& operator=(DeleteBitmap&& r);
+    DeleteBitmap(DeleteBitmap&& r) noexcept;
+    DeleteBitmap& operator=(DeleteBitmap&& r) noexcept;
 
     static DeleteBitmap from_pb(const DeleteBitmapPB& pb, int64_t tablet_id);
 
diff --git 
a/regression-test/data/fault_injection_p0/cloud/test_cloud_mow_sc_inc_rowsets_dup.out
 
b/regression-test/data/fault_injection_p0/cloud/test_cloud_mow_sc_inc_rowsets_dup.out
new file mode 100644
index 00000000000..545f2c2edbb
Binary files /dev/null and 
b/regression-test/data/fault_injection_p0/cloud/test_cloud_mow_sc_inc_rowsets_dup.out
 differ
diff --git 
a/regression-test/suites/fault_injection_p0/cloud/test_cloud_mow_sc_inc_rowsets_dup.groovy
 
b/regression-test/suites/fault_injection_p0/cloud/test_cloud_mow_sc_inc_rowsets_dup.groovy
new file mode 100644
index 00000000000..f57a1b4de1f
--- /dev/null
+++ 
b/regression-test/suites/fault_injection_p0/cloud/test_cloud_mow_sc_inc_rowsets_dup.groovy
@@ -0,0 +1,103 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+import java.util.concurrent.TimeUnit
+import org.awaitility.Awaitility
+
+suite("test_cloud_mow_sc_inc_rowsets_dup", "nonConcurrent") {
+    if (!isCloudMode()) {
+        return
+    }
+
+    GetDebugPoint().clearDebugPointsForAllFEs()
+    GetDebugPoint().clearDebugPointsForAllBEs()
+
+    def table1 = "test_cloud_mow_sc_inc_rowsets_dup"
+    sql "DROP TABLE IF EXISTS ${table1} FORCE;"
+    sql """ CREATE TABLE IF NOT EXISTS ${table1} (
+            `k1` int NOT NULL,
+            `c1` int,
+            `c2` int,
+            `c3` int
+            )UNIQUE KEY(k1)
+        DISTRIBUTED BY HASH(k1) BUCKETS 1
+        PROPERTIES (
+            "enable_unique_key_merge_on_write" = "true",
+            "disable_auto_compaction" = "true",
+            "replication_num" = "1"); """
+
+    sql "insert into ${table1} values(1,1,1,10);"  // 2
+    sql "insert into ${table1} values(2,2,2,20);"  // 3
+    sql "insert into ${table1} values(3,3,3,30);"  // 4
+    sql "sync;"
+    qt_sql "select * from ${table1} order by k1;"
+
+    def backends = sql_return_maparray('show backends')
+    def tabletStats = sql_return_maparray("show tablets from ${table1};")
+    assert tabletStats.size() == 1
+    def tabletId = tabletStats[0].TabletId
+    def tabletBackendId = tabletStats[0].BackendId
+    def tabletBackend
+    for (def be : backends) {
+        if (be.BackendId == tabletBackendId) {
+            tabletBackend = be
+            break;
+        }
+    }
+    logger.info("tablet ${tabletId} on backend ${tabletBackend.Host} with 
backendId=${tabletBackend.BackendId}");
+
+    try {
+        
GetDebugPoint().enableDebugPointForAllBEs("CloudSchemaChangeJob::_process_delete_bitmap.before_new_inc.block")
+        sql "alter table ${table1} modify column c2 varchar(100);"
+
+        Thread.sleep(1000)
+
+        tabletStats = sql_return_maparray("show tablets from ${table1};")
+        def newTabletId = "-1"
+        for (def stat : tabletStats) {
+            if (stat.TabletId != tabletId) {
+                newTabletId = stat.TabletId
+                break
+            }
+        }
+        logger.info("new_tablet_id: ${newTabletId}")
+
+        sql "insert into ${table1} values(1,99,99,99);"
+        sql "insert into ${table1} values(1,99,99,99);"
+        sql "insert into ${table1} values(1,99,99,99);"
+        sql "insert into ${table1} values(1,99,99,99);"
+
+        Thread.sleep(1000)
+
+        
GetDebugPoint().disableDebugPointForAllBEs("CloudSchemaChangeJob::_process_delete_bitmap.before_new_inc.block")
+
+        waitForSchemaChangeDone {
+            sql """ SHOW ALTER TABLE COLUMN WHERE TableName='${table1}' ORDER 
BY createtime DESC LIMIT 1 """
+            time 1000
+        }
+
+        qt_dup_key_count "select k1,count() as cnt from ${table1} group by k1 
having cnt>1;"
+        order_qt_sql "select * from ${table1};"
+
+    } catch(Exception e) {
+        logger.info(e.getMessage())
+        throw e
+    } finally {
+        GetDebugPoint().clearDebugPointsForAllBEs()
+        GetDebugPoint().clearDebugPointsForAllFEs()
+    }
+}


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

Reply via email to