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

zykkk 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 fc76577c24b branch-3.1: [fix](catalog) Prevent removing catalog from 
refresh queue on CREATE/ALTER (#57671)
fc76577c24b is described below

commit fc76577c24bd28f978613e1aab658c9b56c05e95
Author: zy-kkk <[email protected]>
AuthorDate: Wed Nov 5 17:54:02 2025 +0800

    branch-3.1: [fix](catalog) Prevent removing catalog from refresh queue on 
CREATE/ALTER (#57671)
    
    Problem Summary:
    
    catalogs are incorrectly removed from the auto-refresh queue when:
      - Creating a new catalog with `metadata_refresh_interval_sec`
      - Altering catalog properties via `ALTER CATALOG SET PROPERTIES`
    
    This causes auto-refresh to stop working even though
    `metadata_refresh_interval_sec` is configured.
    
    Root Cause:
    CREATE/ALTER CATALOG
      → resetToUninitialized()
      → onClose()
      → CatalogIf.super.onClose()
      → removeFromRefreshMap(catalogId)  ❌ Wrong!
    
    Fix:
    1. Remove `CatalogIf.super.onClose()` call from
    `ExternalCatalog.onClose()`
    - Prevents wrongly removing catalog from refresh queue during
    CREATE/ALTER
    2. Explicitly call `removeFromRefreshMap()` in
    `CatalogMgr.removeCatalog()`
      - Ensures catalog is properly removed when actually dropping it
---
 .../org/apache/doris/datasource/CatalogMgr.java    |   2 +
 .../apache/doris/datasource/ExternalCatalog.java   |   1 -
 .../doris/datasource/RefreshCatalogTest.java       |   2 +-
 .../test_hive_metadata_refresh_interval.groovy     | 101 +++++++++++++++++++++
 4 files changed, 104 insertions(+), 2 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/CatalogMgr.java 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/CatalogMgr.java
index 1564c89ce53..57029ec5cc1 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/datasource/CatalogMgr.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/CatalogMgr.java
@@ -131,6 +131,8 @@ public class CatalogMgr implements Writable, 
GsonPostProcessable {
         CatalogIf catalog = idToCatalog.remove(catalogId);
         LOG.info("Removed catalog with id {}, name {}", catalogId, catalog == 
null ? "N/A" : catalog.getName());
         if (catalog != null) {
+            // Remove from refresh map before calling onClose()
+            
Env.getCurrentEnv().getRefreshManager().removeFromRefreshMap(catalogId);
             catalog.onClose();
             nameToCatalog.remove(catalog.getName());
             if (ConnectContext.get() != null) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java
index 0677a12050a..a0a5b9a42de 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java
@@ -815,7 +815,6 @@ public abstract class ExternalCatalog
         if (threadPoolWithPreAuth != null) {
             ThreadPoolManager.shutdownExecutorService(threadPoolWithPreAuth);
         }
-        CatalogIf.super.onClose();
     }
 
     private void removeAccessController() {
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/datasource/RefreshCatalogTest.java 
b/fe/fe-core/src/test/java/org/apache/doris/datasource/RefreshCatalogTest.java
index 4e80a971f1a..56068c210fe 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/datasource/RefreshCatalogTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/datasource/RefreshCatalogTest.java
@@ -102,7 +102,7 @@ public class RefreshCatalogTest extends TestWithFeService {
         Thread.sleep(5000);
         // there are test1.db1 , test1.db2 , test1.db3, information_schema, 
mysql
         List<String> dbNames2 = test1.getDbNames();
-        Assertions.assertEquals(4, dbNames2.size());
+        Assertions.assertEquals(5, dbNames2.size());
         ExternalInfoSchemaDatabase infoDb = (ExternalInfoSchemaDatabase) 
test1.getDb(InfoSchemaDb.DATABASE_NAME).get();
         Assertions.assertEquals(SchemaTable.TABLE_MAP.size(), 
infoDb.getTables().size());
         TestExternalDatabase testDb = (TestExternalDatabase) 
test1.getDb("db1").get();
diff --git 
a/regression-test/suites/external_table_p0/hive/test_hive_metadata_refresh_interval.groovy
 
b/regression-test/suites/external_table_p0/hive/test_hive_metadata_refresh_interval.groovy
new file mode 100644
index 00000000000..1b5c6d5dc70
--- /dev/null
+++ 
b/regression-test/suites/external_table_p0/hive/test_hive_metadata_refresh_interval.groovy
@@ -0,0 +1,101 @@
+// 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.
+
+suite("test_hive_metadata_refresh_interval", 
"p0,external,hive,external_docker,external_docker_hive") {
+
+    String enabled = context.config.otherConfigs.get("enableHiveTest")
+    if (enabled == null || !enabled.equalsIgnoreCase("true")) {
+        logger.info("disable Hive test.")
+        return
+    }
+
+    for (String hivePrefix : ["hive2", "hive3"]) {
+        setHivePrefix(hivePrefix)
+        try {
+            String hms_port = context.config.otherConfigs.get(hivePrefix + 
"HmsPort")
+            String hdfs_port = context.config.otherConfigs.get(hivePrefix + 
"HdfsPort")
+            String externalEnvIp = 
context.config.otherConfigs.get("externalEnvIp")
+
+            String catalog_name = "test_${hivePrefix}_refresh_interval"
+            String test_db = "test_refresh_interval_db"
+            String table1 = "test_refresh_table_1"
+            String table2 = "test_refresh_table_2"
+
+            sql """drop catalog if exists ${catalog_name}"""
+            hive_docker "drop database if exists ${test_db} cascade"
+            hive_docker "create database ${test_db}"
+
+            // Create catalog with 10s refresh interval
+            sql """create catalog if not exists ${catalog_name} properties (
+                'type'='hms',
+                'hive.metastore.uris' = 
'thrift://${externalEnvIp}:${hms_port}',
+                'fs.defaultFS' = 'hdfs://${externalEnvIp}:${hdfs_port}',
+                'use_meta_cache' = 'true',
+                'metadata_refresh_interval_sec' = '10'
+            )"""
+
+            sql "switch ${catalog_name}"
+            sql "use ${test_db}"
+
+            // Show tables - should be empty
+            def result1 = sql "show tables from ${test_db}"
+            assertEquals(0, result1.size())
+
+            // Create table1 via hive_docker
+            hive_docker "create table ${test_db}.${table1} (id int, name 
string)"
+
+            // Wait 10s for automatic refresh
+            sleep(10000)
+
+            // Show tables - should have table1
+            def result2 = sql "show tables from ${test_db}"
+            assertEquals(1, result2.size())
+            assertTrue(result2.toString().contains(table1))
+
+            // ALTER catalog to 60s refresh interval
+            sql """alter catalog ${catalog_name} set properties (
+                'metadata_refresh_interval_sec' = '60'
+            )"""
+
+            // Show tables - should still have only table1
+            def result3 = sql "show tables from ${test_db}"
+            assertEquals(1, result3.size())
+            assertTrue(result3.toString().contains(table1))
+            assertFalse(result3.toString().contains(table2))
+
+            // Create table2 via hive_docker
+            hive_docker "create table ${test_db}.${table2} (id int, value 
string)"
+
+            // Wait 60s for automatic refresh
+            sleep(60000)
+
+            // Show tables - should have both table1 and table2
+            def result4 = sql "show tables from ${test_db}"
+            assertEquals(2, result4.size())
+            assertTrue(result4.toString().contains(table1))
+            assertTrue(result4.toString().contains(table2))
+
+            // Cleanup
+            hive_docker "drop database ${test_db} cascade"
+            sql """drop catalog ${catalog_name}"""
+
+        } finally {
+            sql """drop catalog if exists 
test_${hivePrefix}_refresh_interval"""
+            hive_docker "drop database if exists test_refresh_interval_db 
cascade"
+        }
+    }
+}


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

Reply via email to