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

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


The following commit(s) were added to refs/heads/branch-2.0 by this push:
     new aaced7f3280 [fix](stats) Drop stats or update updated rows after 
truncate table (#27956)
aaced7f3280 is described below

commit aaced7f32808b91a21e031dd09b1298448e0be4f
Author: Jibing-Li <64681310+jibing...@users.noreply.github.com>
AuthorDate: Tue Dec 5 14:52:40 2023 +0800

    [fix](stats) Drop stats or update updated rows after truncate table (#27956)
    
    1. Also clear follower's stats cache when doing drop stats.
    2. Drop stats when truncate a table.
    
    backport https://github.com/apache/doris/pull/27931
---
 .../apache/doris/datasource/InternalCatalog.java   | 11 +++-
 .../apache/doris/service/FrontendServiceImpl.java  |  8 +++
 .../apache/doris/statistics/AnalysisManager.java   |  6 +-
 .../doris/statistics/StatisticsAutoCollector.java  | 30 ---------
 .../apache/doris/statistics/StatisticsCache.java   | 30 +++++++++
 .../doris/statistics/StatisticsRepository.java     |  3 +
 .../org/apache/doris/statistics/CacheTest.java     |  3 +-
 .../statistics/StatisticsAutoCollectorTest.java    | 74 ----------------------
 gensrc/thrift/FrontendService.thrift               |  6 ++
 .../suites/statistics/analyze_stats.groovy         | 12 +++-
 10 files changed, 74 insertions(+), 109 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java
index 0777f2c1edc..e6e9e52a4ea 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java
@@ -2867,6 +2867,8 @@ public class InternalCatalog implements 
CatalogIf<Database> {
         Database db = (Database) getDbOrDdlException(dbTbl.getDb());
         OlapTable olapTable = db.getOlapTableOrDdlException(dbTbl.getTbl());
 
+        long rowsToTruncate = 0;
+
         BinlogConfig binlogConfig;
         olapTable.readLock();
         try {
@@ -2879,6 +2881,7 @@ public class InternalCatalog implements 
CatalogIf<Database> {
                     }
                     origPartitions.put(partName, partition.getId());
                     partitionsDistributionInfo.put(partition.getId(), 
partition.getDistributionInfo());
+                    rowsToTruncate += partition.getBaseIndex().getRowCount();
                 }
             } else {
                 for (Partition partition : olapTable.getPartitions()) {
@@ -3013,7 +3016,13 @@ public class InternalCatalog implements 
CatalogIf<Database> {
         } finally {
             olapTable.writeUnlock();
         }
-
+        if (truncateEntireTable) {
+            // Drop the whole table stats after truncate the entire table
+            Env.getCurrentEnv().getAnalysisManager().dropStats(olapTable);
+        } else {
+            // Update the updated rows in table stats after truncate some 
partitions.
+            
Env.getCurrentEnv().getAnalysisManager().updateUpdatedRows(olapTable.getId(), 
rowsToTruncate);
+        }
         LOG.info("finished to truncate table {}, partitions: {}", 
tblRef.getName().toSql(), tblRef.getPartitionNames());
     }
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java 
b/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java
index ac1f941145f..11b42913650 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java
@@ -136,6 +136,7 @@ import 
org.apache.doris.thrift.TGetTabletReplicaInfosRequest;
 import org.apache.doris.thrift.TGetTabletReplicaInfosResult;
 import org.apache.doris.thrift.TInitExternalCtlMetaRequest;
 import org.apache.doris.thrift.TInitExternalCtlMetaResult;
+import org.apache.doris.thrift.TInvalidateFollowerStatsCacheRequest;
 import org.apache.doris.thrift.TListPrivilegesResult;
 import org.apache.doris.thrift.TListTableMetadataNameIdsResult;
 import org.apache.doris.thrift.TListTableStatusResult;
@@ -3085,6 +3086,13 @@ public class FrontendServiceImpl implements 
FrontendService.Iface {
         return new TStatus(TStatusCode.OK);
     }
 
+    @Override
+    public TStatus invalidateStatsCache(TInvalidateFollowerStatsCacheRequest 
request) throws TException {
+        StatisticsCacheKey k = GsonUtils.GSON.fromJson(request.key, 
StatisticsCacheKey.class);
+        Env.getCurrentEnv().getStatisticsCache().invalidate(k.tableId, 
k.idxId, k.colName);
+        return new TStatus(TStatusCode.OK);
+    }
+
     public TGetMetaResult getMeta(TGetMetaRequest request) throws TException {
         String clientAddr = getClientAddrAsString();
         LOG.debug("receive get meta request: {}", request);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisManager.java 
b/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisManager.java
index 01e48f422f9..4f62c3b875a 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisManager.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisManager.java
@@ -719,8 +719,9 @@ public class AnalysisManager implements Writable {
             tableStats.reset();
         } else {
             dropStatsStmt.getColumnNames().forEach(tableStats::removeColumn);
+            StatisticsCache statisticsCache = 
Env.getCurrentEnv().getStatisticsCache();
             for (String col : cols) {
-                Env.getCurrentEnv().getStatisticsCache().invalidate(tblId, 
-1L, col);
+                statisticsCache.syncInvalidate(tblId, -1L, col);
             }
             tableStats.updatedTime = 0;
         }
@@ -734,9 +735,10 @@ public class AnalysisManager implements Writable {
             return;
         }
         Set<String> cols = 
table.getBaseSchema().stream().map(Column::getName).collect(Collectors.toSet());
+        StatisticsCache statisticsCache = 
Env.getCurrentEnv().getStatisticsCache();
         for (String col : cols) {
             tableStats.removeColumn(col);
-            Env.getCurrentEnv().getStatisticsCache().invalidate(table.getId(), 
-1L, col);
+            statisticsCache.syncInvalidate(table.getId(), -1L, col);
         }
         tableStats.updatedTime = 0;
         logCreateTableStats(tableStats);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsAutoCollector.java
 
b/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsAutoCollector.java
index bcc7f53f4d1..044eeffcccf 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsAutoCollector.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsAutoCollector.java
@@ -93,10 +93,6 @@ public class StatisticsAutoCollector extends 
StatisticsCollector {
         List<AnalysisInfo> analysisInfos = constructAnalysisInfo(databaseIf);
         for (AnalysisInfo analysisInfo : analysisInfos) {
             try {
-                if (needDropStaleStats(analysisInfo)) {
-                    
Env.getCurrentEnv().getAnalysisManager().dropStats(databaseIf.getTable(analysisInfo.tblId).get());
-                    continue;
-                }
                 analysisInfo = getReAnalyzeRequiredPart(analysisInfo);
                 if (analysisInfo == null) {
                     continue;
@@ -201,30 +197,4 @@ public class StatisticsAutoCollector extends 
StatisticsCollector {
 
         return new 
AnalysisInfoBuilder(jobInfo).setColToPartitions(needRunPartitions).build();
     }
-
-    /**
-     * Check if the given table should drop stale stats. User may truncate 
table,
-     * in this case, we need to drop the stale stats.
-     * @param jobInfo
-     * @return True if you need to drop, false otherwise.
-     */
-    protected boolean needDropStaleStats(AnalysisInfo jobInfo) {
-        TableIf table = StatisticsUtil
-                .findTable(jobInfo.catalogId, jobInfo.dbId, jobInfo.tblId);
-        if (!(table instanceof OlapTable)) {
-            return false;
-        }
-        AnalysisManager analysisManager = 
Env.getServingEnv().getAnalysisManager();
-        TableStatsMeta tblStats = 
analysisManager.findTableStatsStatus(table.getId());
-        if (tblStats == null) {
-            return false;
-        }
-        if (tblStats.analyzeColumns().isEmpty()) {
-            return false;
-        }
-        if (table.getRowCount() == 0) {
-            return true;
-        }
-        return false;
-    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsCache.java 
b/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsCache.java
index 84110d5bda1..d4b91b07364 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsCache.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsCache.java
@@ -27,6 +27,7 @@ import org.apache.doris.qe.ConnectContext;
 import org.apache.doris.statistics.util.StatisticsUtil;
 import org.apache.doris.system.Frontend;
 import org.apache.doris.thrift.FrontendService;
+import org.apache.doris.thrift.TInvalidateFollowerStatsCacheRequest;
 import org.apache.doris.thrift.TNetworkAddress;
 import org.apache.doris.thrift.TUpdateFollowerStatsCacheRequest;
 
@@ -138,6 +139,19 @@ public class StatisticsCache {
         columnStatisticsCache.synchronous().invalidate(new 
StatisticsCacheKey(tblId, idxId, colName));
     }
 
+    public void syncInvalidate(long tblId, long idxId, String colName) {
+        StatisticsCacheKey cacheKey = new StatisticsCacheKey(tblId, idxId, 
colName);
+        columnStatisticsCache.synchronous().invalidate(cacheKey);
+        TInvalidateFollowerStatsCacheRequest request = new 
TInvalidateFollowerStatsCacheRequest();
+        request.key = GsonUtils.GSON.toJson(cacheKey);
+        for (Frontend frontend : 
Env.getCurrentEnv().getFrontends(FrontendNodeType.FOLLOWER)) {
+            if (StatisticsUtil.isMaster(frontend)) {
+                continue;
+            }
+            invalidateStats(frontend, request);
+        }
+    }
+
     public void updateColStatsCache(long tblId, long idxId, String colName, 
ColumnStatistic statistic) {
         columnStatisticsCache.synchronous().put(new StatisticsCacheKey(tblId, 
idxId, colName), Optional.of(statistic));
     }
@@ -250,6 +264,22 @@ public class StatisticsCache {
         }
     }
 
+    @VisibleForTesting
+    public void invalidateStats(Frontend frontend, 
TInvalidateFollowerStatsCacheRequest request) {
+        TNetworkAddress address = new TNetworkAddress(frontend.getHost(), 
frontend.getRpcPort());
+        FrontendService.Client client = null;
+        try {
+            client = ClientPool.frontendPool.borrowObject(address);
+            client.invalidateStatsCache(request);
+        } catch (Throwable t) {
+            LOG.warn("Failed to sync invalidate to follower: {}", address, t);
+        } finally {
+            if (client != null) {
+                ClientPool.frontendPool.returnObject(address, client);
+            }
+        }
+    }
+
     public void putCache(StatisticsCacheKey k, ColumnStatistic c) {
         CompletableFuture<Optional<ColumnStatistic>> f = new 
CompletableFuture<Optional<ColumnStatistic>>();
         f.obtrudeValue(Optional.of(c));
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsRepository.java
 
b/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsRepository.java
index 29e11ac75ad..4512bf1feff 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsRepository.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsRepository.java
@@ -184,6 +184,9 @@ public class StatisticsRepository {
     }
 
     public static void dropStatistics(long tblId, Set<String> colNames) throws 
DdlException {
+        if (colNames == null) {
+            return;
+        }
         dropStatisticsByColName(tblId, colNames, 
StatisticConstants.STATISTIC_TBL_NAME);
         dropStatisticsByColName(tblId, colNames, 
StatisticConstants.HISTOGRAM_TBL_NAME);
     }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/statistics/CacheTest.java 
b/fe/fe-core/src/test/java/org/apache/doris/statistics/CacheTest.java
index 587a5b859a1..b8e8e8df433 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/statistics/CacheTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/statistics/CacheTest.java
@@ -379,7 +379,7 @@ public class CacheTest extends TestWithFeService {
     }
 
     @Test
-    public void testEvict() {
+    public void testEvict() throws InterruptedException {
         ThreadPoolExecutor threadPool
                 = ThreadPoolManager.newDaemonFixedThreadPool(
                 1, Integer.MAX_VALUE, "STATS_FETCH", true);
@@ -400,6 +400,7 @@ public class CacheTest extends TestWithFeService {
         columnStatisticsCache.get(1);
         columnStatisticsCache.get(2);
         
Assertions.assertTrue(columnStatisticsCache.synchronous().asMap().containsKey(2));
+        Thread.sleep(100);
         Assertions.assertEquals(1, 
columnStatisticsCache.synchronous().asMap().size());
     }
 }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/statistics/StatisticsAutoCollectorTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/statistics/StatisticsAutoCollectorTest.java
index 56475201765..fd7eaeaad90 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/statistics/StatisticsAutoCollectorTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/statistics/StatisticsAutoCollectorTest.java
@@ -27,7 +27,6 @@ import org.apache.doris.catalog.Table;
 import org.apache.doris.catalog.TableIf;
 import org.apache.doris.catalog.Type;
 import org.apache.doris.catalog.View;
-import org.apache.doris.catalog.external.ExternalTable;
 import org.apache.doris.cluster.ClusterNamespace;
 import org.apache.doris.common.Config;
 import org.apache.doris.common.DdlException;
@@ -450,77 +449,4 @@ public class StatisticsAutoCollectorTest {
             Assertions.assertNotNull(task.getTableSample());
         }
     }
-
-    @Test
-    public void testNeedDropStaleStats() {
-
-        TableIf olapTable = new OlapTable();
-        TableIf otherTable = new ExternalTable();
-
-        new MockUp<StatisticsUtil>() {
-            @Mock
-            public TableIf findTable(long catalogId, long dbId, long tblId) {
-                if (tblId == 0) {
-                    return olapTable;
-                } else {
-                    return otherTable;
-                }
-            }
-        };
-
-        new MockUp<OlapTable>() {
-            int count = 0;
-
-            int[] rowCounts = {100, 100, 100, 0, 0, 0, 0};
-            @Mock
-            public long getRowCount() {
-                return rowCounts[count++];
-            }
-
-            @Mock
-            public List<Column> getBaseSchema() {
-                return Lists.newArrayList(new Column("col1", Type.INT), new 
Column("col2", Type.INT));
-            }
-        };
-
-        AnalysisInfo analysisInfoOlap = new 
AnalysisInfoBuilder().setAnalysisMethod(AnalysisMethod.FULL)
-                .setColToPartitions(new HashMap<>())
-                .setAnalysisType(AnalysisType.FUNDAMENTALS)
-                .setColName("col1")
-                .setTblId(0)
-                .setJobType(JobType.SYSTEM).build();
-
-        new MockUp<AnalysisManager>() {
-            int count = 0;
-
-            TableStatsMeta[] tableStatsArr =
-                    new TableStatsMeta[] {null,
-                        new TableStatsMeta(0, analysisInfoOlap, olapTable),
-                        new TableStatsMeta(0, analysisInfoOlap, olapTable)};
-
-            {
-                tableStatsArr[1].updatedRows.addAndGet(100);
-                tableStatsArr[2].updatedRows.addAndGet(0);
-            }
-
-
-            @Mock
-            public TableStatsMeta findTableStatsStatus(long tblId) {
-                return tableStatsArr[count++];
-            }
-        };
-
-        AnalysisInfo analysisInfoOtherTable = new 
AnalysisInfoBuilder().setAnalysisMethod(AnalysisMethod.FULL)
-                .setColToPartitions(new HashMap<>())
-                .setAnalysisType(AnalysisType.FUNDAMENTALS)
-                .setColName("col1")
-                .setTblId(1)
-                .setJobType(JobType.SYSTEM).build();
-
-        StatisticsAutoCollector statisticsAutoCollector = new 
StatisticsAutoCollector();
-        
Assertions.assertFalse(statisticsAutoCollector.needDropStaleStats(analysisInfoOtherTable));
-        
Assertions.assertFalse(statisticsAutoCollector.needDropStaleStats(analysisInfoOlap));
-        
Assertions.assertFalse(statisticsAutoCollector.needDropStaleStats(analysisInfoOlap));
-        
Assertions.assertTrue(statisticsAutoCollector.needDropStaleStats(analysisInfoOlap));
-    }
 }
diff --git a/gensrc/thrift/FrontendService.thrift 
b/gensrc/thrift/FrontendService.thrift
index 3d881099de7..248163ad110 100644
--- a/gensrc/thrift/FrontendService.thrift
+++ b/gensrc/thrift/FrontendService.thrift
@@ -1102,6 +1102,10 @@ struct TUpdateFollowerStatsCacheRequest {
     2: list<string> statsRows;
 }
 
+struct TInvalidateFollowerStatsCacheRequest {
+    1: optional string key;
+}
+
 struct TGetMetaReplica {
     1: optional i64 id
 }
@@ -1282,4 +1286,6 @@ service FrontendService {
     TGetMetaResult getMeta(1: TGetMetaRequest request)
 
     TGetBackendMetaResult getBackendMeta(1: TGetBackendMetaRequest request)
+
+    Status.TStatus invalidateStatsCache(1: 
TInvalidateFollowerStatsCacheRequest request)
 }
diff --git a/regression-test/suites/statistics/analyze_stats.groovy 
b/regression-test/suites/statistics/analyze_stats.groovy
index 3f0e5862ba0..21697bbec01 100644
--- a/regression-test/suites/statistics/analyze_stats.groovy
+++ b/regression-test/suites/statistics/analyze_stats.groovy
@@ -1248,7 +1248,6 @@ PARTITION `p599` VALUES IN (599)
 
     assert all_finished(show_result)
 
-
     // unique table update rows
     sql """
         CREATE TABLE unique_tbl_update_rows_test (col1 varchar(11451) not null,
@@ -1275,4 +1274,15 @@ PARTITION `p599` VALUES IN (599)
         return false
     }
     check_update_rows(unique_table_update_rows_result)
+
+    // Test truncate table will drop table stats too.
+    sql """ANALYZE TABLE ${tbl} WITH SYNC"""
+    def result_before_truncate = sql """show column stats ${tbl}"""
+    assertEquals(14, result_before_truncate.size())
+    sql """TRUNCATE TABLE ${tbl}"""
+    def result_after_truncate = sql """show column stats ${tbl}"""
+    assertEquals(0, result_after_truncate.size())
+    result_after_truncate = sql """show column cached stats ${tbl}"""
+    assertEquals(0, result_after_truncate.size())
+
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org

Reply via email to