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 6fc573b4f4b branch-4.1: [bug](cloud restore) rewrite table properties 
and partition info in cloud restore (#64466)
6fc573b4f4b is described below

commit 6fc573b4f4b99cd027c2895e41b105a216f32229
Author: xy720 <[email protected]>
AuthorDate: Tue Jun 16 16:12:09 2026 +0800

    branch-4.1: [bug](cloud restore) rewrite table properties and partition 
info in cloud restore (#64466)
    
    ### What problem does this PR solve?
    
    pick #63696
    
    ### Check List (For Author)
    
    - Test <!-- At least one of them must be included. -->
        - [ ] Regression test
        - [x] Unit Test
        - [ ] Manual test (add detailed scripts or steps below)
        - [ ] No need to test or manual test. Explain why:
    - [ ] This is a refactor/code format and no logic has been changed.
            - [ ] Previous test can cover this change.
            - [ ] No code files have been changed.
            - [ ] Other reason <!-- Add your reason?  -->
    
    - Behavior changed:
        - [x] No.
        - [ ] Yes. <!-- Explain the behavior change -->
    
    - Does this need documentation?
        - [x] No.
    - [ ] Yes. <!-- Add document PR link here. eg:
    https://github.com/apache/doris-website/pull/1214 -->
    
    ### Check List (For Reviewer who merge this PR)
    
    - [ ] Confirm the release note
    - [ ] Confirm test cases
    - [ ] Confirm document
    - [ ] Add branch pick label <!-- Add branch pick label that this PR
    should merge into -->
---
 .../java/org/apache/doris/backup/RestoreJob.java   |  26 ++++-
 .../org/apache/doris/catalog/PartitionInfo.java    |  31 +++++-
 .../org/apache/doris/catalog/TableProperty.java    |  12 ++
 .../cloud/common/util/CloudPropertyAnalyzer.java   |   1 +
 .../org/apache/doris/catalog/OlapTableTest.java    | 122 +++++++++++++++++++++
 ...st_show_create_table_with_storage_policy.groovy |   6 +-
 6 files changed, 189 insertions(+), 9 deletions(-)

diff --git a/fe/fe-core/src/main/java/org/apache/doris/backup/RestoreJob.java 
b/fe/fe-core/src/main/java/org/apache/doris/backup/RestoreJob.java
index fbd0148f7ca..5297d6f13f9 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/backup/RestoreJob.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/backup/RestoreJob.java
@@ -1140,9 +1140,20 @@ public class RestoreJob extends AbstractJob implements 
GsonPostProcessable {
                     if (reserveReplica) {
                         restoreReplicaAlloc = 
remotePartitionInfo.getReplicaAllocation(remotePartId);
                     }
+                    boolean isInMemory = 
remotePartitionInfo.getIsInMemory(remotePartId);
+                    if (Config.isCloudMode()) {
+                        // In cloud mode, storage_medium, cooldown_time, 
storage_policy and in_memory
+                        // from the source cluster are not applicable. Reset 
them to defaults.
+                        remoteDataProperty = new DataProperty(
+                                DataProperty.DEFAULT_STORAGE_MEDIUM,
+                                DataProperty.MAX_COOLDOWN_TIME_MS,
+                                "",
+                                remoteDataProperty.isMutable());
+                        isInMemory = false;
+                    }
                     localPartitionInfo.addPartition(restoredPart.getId(), 
false, remoteItem,
                             remoteDataProperty, restoreReplicaAlloc,
-                            remotePartitionInfo.getIsInMemory(remotePartId),
+                            isInMemory,
                             remotePartitionInfo.getIsMutable(remotePartId));
                 }
                 localTbl.addPartition(restoredPart);
@@ -1678,9 +1689,20 @@ public class RestoreJob extends AbstractJob implements 
GsonPostProcessable {
             if (reserveReplica) {
                 restoreReplicaAlloc = 
remotePartitionInfo.getReplicaAllocation(remotePartId);
             }
+            boolean isInMemory = 
remotePartitionInfo.getIsInMemory(remotePartId);
+            if (Config.isCloudMode()) {
+                // In cloud mode, storage_medium, cooldown_time, 
storage_policy and in_memory
+                // from the source cluster are not applicable. Reset them to 
defaults.
+                remoteDataProperty = new DataProperty(
+                        DataProperty.DEFAULT_STORAGE_MEDIUM,
+                        DataProperty.MAX_COOLDOWN_TIME_MS,
+                        "",
+                        remoteDataProperty.isMutable());
+                isInMemory = false;
+            }
             localPartitionInfo.addPartition(restorePart.getId(), false, 
remotePartitionInfo.getItem(remotePartId),
                     remoteDataProperty, restoreReplicaAlloc,
-                    remotePartitionInfo.getIsInMemory(remotePartId),
+                    isInMemory,
                     remotePartitionInfo.getIsMutable(remotePartId));
             localTbl.addPartition(restorePart);
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/catalog/PartitionInfo.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/PartitionInfo.java
index 89e6c637a3a..5cec453baac 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/PartitionInfo.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/PartitionInfo.java
@@ -25,6 +25,7 @@ import org.apache.doris.analysis.PartitionDesc;
 import org.apache.doris.analysis.PartitionValue;
 import org.apache.doris.analysis.SinglePartitionDesc;
 import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.Config;
 import org.apache.doris.common.DdlException;
 import org.apache.doris.thrift.TStorageMedium;
 import org.apache.doris.thrift.TTabletType;
@@ -427,15 +428,33 @@ public class PartitionInfo {
         idToStoragePolicy = Maps.newHashMap();
 
         for (Map.Entry<Long, Long> entry : partitionIdMap.entrySet()) {
-            idToDataProperty.put(entry.getKey(), 
origIdToDataProperty.get(entry.getValue()));
-            idToReplicaAllocation.put(entry.getKey(),
-                    restoreReplicaAlloc == null ? 
origIdToReplicaAllocation.get(entry.getValue())
+            long newPartId = entry.getKey();
+            long origPartId = entry.getValue();
+
+            if (Config.isCloudMode()) {
+                // In cloud mode, storage_medium, cooldown_time, and 
storage_policy are not applicable.
+                // Reset DataProperty to default and clear storage policy to 
avoid carrying over
+                // source cluster's storage settings that have no meaning in 
cloud mode.
+                DataProperty origDataProperty = 
origIdToDataProperty.get(origPartId);
+                idToDataProperty.put(newPartId, new DataProperty(
+                        DataProperty.DEFAULT_STORAGE_MEDIUM,
+                        DataProperty.MAX_COOLDOWN_TIME_MS,
+                        "",
+                        origDataProperty != null ? 
origDataProperty.isMutable() : true));
+                idToStoragePolicy.put(newPartId, "");
+                idToInMemory.put(newPartId, false);
+            } else {
+                idToDataProperty.put(newPartId, 
origIdToDataProperty.get(origPartId));
+                idToStoragePolicy.put(newPartId, 
origIdToStoragePolicy.getOrDefault(origPartId, ""));
+                idToInMemory.put(newPartId, origIdToInMemory.get(origPartId));
+            }
+
+            idToReplicaAllocation.put(newPartId,
+                    restoreReplicaAlloc == null ? 
origIdToReplicaAllocation.get(origPartId)
                             : restoreReplicaAlloc);
             if (!isSinglePartitioned) {
-                idToItem.put(entry.getKey(), 
origIdToItem.get(entry.getValue()));
+                idToItem.put(newPartId, origIdToItem.get(origPartId));
             }
-            idToInMemory.put(entry.getKey(), 
origIdToInMemory.get(entry.getValue()));
-            idToStoragePolicy.put(entry.getKey(), 
origIdToStoragePolicy.getOrDefault(entry.getValue(), ""));
         }
     }
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/catalog/TableProperty.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/TableProperty.java
index 584eb6dde24..830a668a3a5 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/TableProperty.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/TableProperty.java
@@ -19,6 +19,7 @@ package org.apache.doris.catalog;
 
 import org.apache.doris.analysis.DataSortInfo;
 import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.Config;
 import org.apache.doris.common.util.PropertyAnalyzer;
 import org.apache.doris.persist.OperationType;
 import org.apache.doris.persist.gson.GsonPostProcessable;
@@ -184,6 +185,17 @@ public class TableProperty implements GsonPostProcessable {
      */
     public TableProperty resetPropertiesForRestore(boolean 
reserveDynamicPartitionEnable, boolean reserveReplica,
                                                    ReplicaAllocation 
replicaAlloc) {
+        if (Config.isCloudMode()) {
+            // In cloud mode, rewrite all unsupported or forced properties 
from the source cluster.
+            // These properties (e.g., replication_num, 
replication_allocation, storage_policy,
+            // storage_medium, in_memory, etc.) are not applicable in cloud 
mode. If kept, they would
+            // cause some critical problems.
+            PropertyAnalyzer.getInstance().rewriteForceProperties(properties);
+            buildInMemory();
+            buildStorageMedium();
+            buildStoragePolicy();
+            buildMinLoadReplicaNum();
+        }
         // disable dynamic partition
         if (properties.containsKey(DynamicPartitionProperty.ENABLE)) {
             if (!reserveDynamicPartitionEnable) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/cloud/common/util/CloudPropertyAnalyzer.java
 
b/fe/fe-core/src/main/java/org/apache/doris/cloud/common/util/CloudPropertyAnalyzer.java
index 7ac160f4b18..6acb3577f82 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/cloud/common/util/CloudPropertyAnalyzer.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/cloud/common/util/CloudPropertyAnalyzer.java
@@ -41,6 +41,7 @@ public class CloudPropertyAnalyzer extends PropertyAnalyzer {
                 RewriteProperty.delete("default." + 
PropertyAnalyzer.PROPERTIES_REPLICATION_NUM),
                 RewriteProperty.delete("default." + 
PropertyAnalyzer.PROPERTIES_REPLICATION_ALLOCATION),
                 
RewriteProperty.delete(DynamicPartitionProperty.STORAGE_MEDIUM),
+                
RewriteProperty.delete(DynamicPartitionProperty.STORAGE_POLICY),
                 
RewriteProperty.replace(DynamicPartitionProperty.REPLICATION_NUM,
                         
String.valueOf(ReplicaAllocation.DEFAULT_ALLOCATION.getTotalReplicaNum())),
                 
RewriteProperty.replace(DynamicPartitionProperty.REPLICATION_ALLOCATION,
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/catalog/OlapTableTest.java 
b/fe/fe-core/src/test/java/org/apache/doris/catalog/OlapTableTest.java
index ec9670cb8e7..045c4dee3ea 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/catalog/OlapTableTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/catalog/OlapTableTest.java
@@ -20,6 +20,7 @@ package org.apache.doris.catalog;
 import org.apache.doris.analysis.IndexDef;
 import org.apache.doris.analysis.UserIdentity;
 import org.apache.doris.catalog.TableIf.TableType;
+import org.apache.doris.cloud.common.util.CloudPropertyAnalyzer;
 import org.apache.doris.cloud.proto.Cloud;
 import org.apache.doris.cloud.rpc.VersionHelper;
 import org.apache.doris.common.Config;
@@ -33,6 +34,7 @@ import org.apache.doris.resource.Tag;
 import org.apache.doris.resource.computegroup.ComputeGroup;
 import org.apache.doris.system.Backend;
 import org.apache.doris.thrift.TFetchOption;
+import org.apache.doris.thrift.TStorageMedium;
 import org.apache.doris.thrift.TStorageType;
 import org.apache.doris.utframe.UtFrameUtils;
 
@@ -42,6 +44,8 @@ import mockit.Mock;
 import mockit.MockUp;
 import org.junit.Assert;
 import org.junit.Test;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
 
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
@@ -140,6 +144,124 @@ public class OlapTableTest {
         Assert.assertEquals((short) 3, 
olapTable.getDefaultReplicaAllocation().getTotalReplicaNum());
     }
 
+    @Test
+    public void testResetPropertiesForRestoreInCloudMode() {
+        // simulate a restoring table with properties that are unsupported in 
cloud mode
+        Map<String, String> properties = Maps.newHashMap();
+        properties.put(DynamicPartitionProperty.ENABLE, "true");
+        properties.put(DynamicPartitionProperty.TIME_UNIT, "DAY");
+        properties.put(DynamicPartitionProperty.TIME_ZONE, "Asia/Shanghai");
+        properties.put(DynamicPartitionProperty.START, "-3");
+        properties.put(DynamicPartitionProperty.END, "3");
+        properties.put(DynamicPartitionProperty.PREFIX, "p");
+        properties.put(DynamicPartitionProperty.BUCKETS, "10");
+        properties.put(DynamicPartitionProperty.REPLICATION_NUM, "3");
+        properties.put(DynamicPartitionProperty.REPLICATION_ALLOCATION, 
"tag.location.default:3");
+        properties.put(DynamicPartitionProperty.STORAGE_MEDIUM, "SSD");
+        properties.put(PropertyAnalyzer.PROPERTIES_INMEMORY, "true");
+        properties.put(PropertyAnalyzer.PROPERTIES_STORAGE_MEDIUM, "SSD");
+        properties.put(PropertyAnalyzer.PROPERTIES_STORAGE_POLICY, 
"s3_policy");
+        properties.put(PropertyAnalyzer.PROPERTIES_STORAGE_COOLDOWN_TIME, 
"2025-01-01 00:00:00");
+        properties.put(PropertyAnalyzer.PROPERTIES_MIN_LOAD_REPLICA_NUM, "2");
+        properties.put(PropertyAnalyzer.PROPERTIES_REPLICATION_NUM, "3");
+        properties.put(PropertyAnalyzer.PROPERTIES_REPLICATION_ALLOCATION, 
"tag.location.default:3");
+        properties.put("default." + 
PropertyAnalyzer.PROPERTIES_REPLICATION_NUM, "3");
+        properties.put("default." + 
PropertyAnalyzer.PROPERTIES_REPLICATION_ALLOCATION, "tag.location.default:3");
+
+        TableProperty tableProperty = new TableProperty(properties);
+        OlapTable olapTable = new OlapTable();
+        olapTable.setTableProperty(tableProperty);
+
+        try (MockedStatic<Config> mockedConfig = 
Mockito.mockStatic(Config.class, Mockito.CALLS_REAL_METHODS);
+                    MockedStatic<PropertyAnalyzer> mockedPA =
+                            Mockito.mockStatic(PropertyAnalyzer.class, 
Mockito.CALLS_REAL_METHODS)) {
+            mockedConfig.when(Config::isCloudMode).thenReturn(true);
+            mockedConfig.when(Config::isNotCloudMode).thenReturn(false);
+            mockedPA.when(PropertyAnalyzer::getInstance).thenReturn(new 
CloudPropertyAnalyzer());
+
+            ReplicaAllocation cloudReplicaAlloc = new 
ReplicaAllocation((short) 1);
+            // reserveDynamicPartitionEnable=true, reserveReplica=false 
(forced in cloud mode)
+            olapTable.resetPropertiesForRestore(true, false, 
cloudReplicaAlloc, false);
+
+            Map<String, String> resultProps = 
olapTable.getTableProperty().getProperties();
+            
Assert.assertFalse(resultProps.containsKey(PropertyAnalyzer.PROPERTIES_INMEMORY));
+            
Assert.assertFalse(resultProps.containsKey(PropertyAnalyzer.PROPERTIES_STORAGE_MEDIUM));
+            
Assert.assertFalse(resultProps.containsKey(PropertyAnalyzer.PROPERTIES_STORAGE_POLICY));
+            
Assert.assertFalse(resultProps.containsKey(PropertyAnalyzer.PROPERTIES_STORAGE_COOLDOWN_TIME));
+            
Assert.assertFalse(resultProps.containsKey(PropertyAnalyzer.PROPERTIES_MIN_LOAD_REPLICA_NUM));
+            Assert.assertEquals((short) 1, 
olapTable.getDefaultReplicaAllocation().getTotalReplicaNum());
+            Assert.assertFalse(olapTable.getTableProperty().isInMemory());
+            Assert.assertNull(olapTable.getTableProperty().getStorageMedium());
+            Assert.assertEquals("", 
olapTable.getTableProperty().getStoragePolicy());
+            
Assert.assertTrue(olapTable.getTableProperty().getDynamicPartitionProperty().getEnable());
+            
Assert.assertTrue(resultProps.containsKey(DynamicPartitionProperty.REPLICATION_NUM));
+            
Assert.assertTrue(resultProps.containsKey(DynamicPartitionProperty.REPLICATION_ALLOCATION));
+            
Assert.assertFalse(resultProps.containsKey(DynamicPartitionProperty.STORAGE_MEDIUM));
+        }
+    }
+
+    @Test
+    public void testResetPartitionIdForRestore() {
+        PartitionInfo partitionInfo = new PartitionInfo(PartitionType.RANGE);
+        long origPartId = 1000L;
+        DataProperty origDataProperty = new DataProperty(TStorageMedium.SSD, 
1735689600000L, "s3_policy");
+        ReplicaAllocation origReplicaAlloc = new ReplicaAllocation((short) 3);
+        partitionInfo.addPartition(origPartId, origDataProperty, 
origReplicaAlloc, true, true);
+
+        Map<Long, Long> partitionIdMap = Maps.newHashMap();
+        long newPartId = 2000L;
+        partitionIdMap.put(newPartId, origPartId);
+
+        ReplicaAllocation restoreReplicaAlloc = new ReplicaAllocation((short) 
2);
+
+        try (MockedStatic<Config> mockedConfig = 
Mockito.mockStatic(Config.class, Mockito.CALLS_REAL_METHODS)) {
+            mockedConfig.when(Config::isCloudMode).thenReturn(false);
+            mockedConfig.when(Config::isNotCloudMode).thenReturn(true);
+
+            partitionInfo.resetPartitionIdForRestore(partitionIdMap, 
restoreReplicaAlloc, false);
+            Assert.assertEquals((short) 2,
+                    
partitionInfo.getReplicaAllocation(newPartId).getTotalReplicaNum());
+            DataProperty newDataProperty = 
partitionInfo.getDataProperty(newPartId);
+            Assert.assertEquals(TStorageMedium.SSD, 
newDataProperty.getStorageMedium());
+            Assert.assertEquals(1735689600000L, 
newDataProperty.getCooldownTimeMs());
+            Assert.assertEquals("s3_policy", 
newDataProperty.getStoragePolicy());
+            Assert.assertTrue(partitionInfo.getIsInMemory(newPartId));
+        }
+    }
+
+    @Test
+    public void testResetPartitionIdForRestoreInCloudMode() {
+        PartitionInfo partitionInfo = new PartitionInfo(PartitionType.RANGE);
+        long origPartId = 1000L;
+        DataProperty origDataProperty = new DataProperty(TStorageMedium.SSD, 
1735689600000L, "s3_policy");
+        ReplicaAllocation origReplicaAlloc = new ReplicaAllocation((short) 3);
+        partitionInfo.addPartition(origPartId, origDataProperty, 
origReplicaAlloc, true, true);
+
+        Map<Long, Long> partitionIdMap = Maps.newHashMap();
+        long newPartId = 2000L;
+        partitionIdMap.put(newPartId, origPartId);
+
+        ReplicaAllocation cloudReplicaAlloc = new ReplicaAllocation((short) 1);
+
+        try (MockedStatic<Config> mockedConfig = 
Mockito.mockStatic(Config.class, Mockito.CALLS_REAL_METHODS);
+                    MockedStatic<PropertyAnalyzer> mockedPA =
+                            Mockito.mockStatic(PropertyAnalyzer.class, 
Mockito.CALLS_REAL_METHODS)) {
+            mockedConfig.when(Config::isCloudMode).thenReturn(true);
+            mockedConfig.when(Config::isNotCloudMode).thenReturn(false);
+            mockedPA.when(PropertyAnalyzer::getInstance).thenReturn(new 
CloudPropertyAnalyzer());
+
+            partitionInfo.resetPartitionIdForRestore(partitionIdMap, 
cloudReplicaAlloc, false);
+            Assert.assertEquals((short) 1,
+                    
partitionInfo.getReplicaAllocation(newPartId).getTotalReplicaNum());
+            DataProperty newDataProperty = 
partitionInfo.getDataProperty(newPartId);
+            Assert.assertEquals(DataProperty.DEFAULT_STORAGE_MEDIUM, 
newDataProperty.getStorageMedium());
+            Assert.assertEquals(DataProperty.MAX_COOLDOWN_TIME_MS, 
newDataProperty.getCooldownTimeMs());
+            Assert.assertEquals("", newDataProperty.getStoragePolicy());
+            Assert.assertTrue(newDataProperty.isMutable());
+            Assert.assertFalse(partitionInfo.getIsInMemory(newPartId));
+        }
+    }
+
     @Test
     public void testBuildVariantEnableFlattenNestedWithLegacyPropertyKey() 
throws IOException {
         Map<String, String> properties = Maps.newHashMap();
diff --git 
a/regression-test/suites/show_p0/test_show_create_table_with_storage_policy.groovy
 
b/regression-test/suites/show_p0/test_show_create_table_with_storage_policy.groovy
index 9194984c854..1b973bf419e 100644
--- 
a/regression-test/suites/show_p0/test_show_create_table_with_storage_policy.groovy
+++ 
b/regression-test/suites/show_p0/test_show_create_table_with_storage_policy.groovy
@@ -89,7 +89,11 @@ suite("test_show_create_table_with_storage_policy") {
     String createSql = ret[0][1]
 
     ret = sql """ SHOW PARTITIONS FROM ${tableName} """
-    assertEquals(ret[9][12], storagePolicyName)
+    if (!isCloudMode()) {
+        assertEquals(ret[9][12], storagePolicyName)
+    } else {
+        assertEquals(ret[9][12], "")
+    }
 
     sql """ DROP TABLE IF EXISTS ${tableName} """
     // create table successfully with stmt from show create table


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

Reply via email to