diff --git a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVPartitionUtil.java b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVPartitionUtil.java index dd42e14b824157..3c884a311b4109 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVPartitionUtil.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVPartitionUtil.java @@ -487,11 +487,34 @@ private static boolean isSyncWithBaseTable(MTMVRefreshContext context, String mt if (!baseTable.needAutoRefresh()) { return true; } - MTMVSnapshotIf baseTableCurrentSnapshot = baseTable.getTableSnapshot(context, Optional.empty()); + MTMVSnapshotIf baseTableCurrentSnapshot = getTableSnapshotFromContext(baseTable, context); return mtmv.getRefreshSnapshot() .equalsWithBaseTable(mtmvPartitionName, new BaseTableInfo(baseTable), baseTableCurrentSnapshot); } + /** + * Try context first, then load via getTableSnapshot and cache + * + * @param mtmvRelatedTableIf Base table of materialized views + * @param context The context data persists for the duration of either a refresh task + * or a transparent rewrite operation + * @return The snapshot information of the MTMV + * @throws AnalysisException + */ + public static MTMVSnapshotIf getTableSnapshotFromContext(MTMVRelatedTableIf mtmvRelatedTableIf, + MTMVRefreshContext context) + throws AnalysisException { + BaseTableInfo baseTableInfo = new BaseTableInfo(mtmvRelatedTableIf); + Map baseTableSnapshotCache = context.getBaseTableSnapshotCache(); + if (baseTableSnapshotCache.containsKey(baseTableInfo)) { + return baseTableSnapshotCache.get(baseTableInfo); + } + MTMVSnapshotIf baseTableCurrentSnapshot = mtmvRelatedTableIf.getTableSnapshot(context, + Optional.empty()); + baseTableSnapshotCache.put(baseTableInfo, baseTableCurrentSnapshot); + return baseTableCurrentSnapshot; + } + /** * Generate updated snapshots of partitions to determine if they are synchronized * @@ -538,7 +561,7 @@ private static MTMVRefreshPartitionSnapshot generatePartitionSnapshot(MTMVRefres continue; } refreshPartitionSnapshot.addTableSnapshot(baseTableInfo, - ((MTMVRelatedTableIf) table).getTableSnapshot(context, Optional.empty())); + getTableSnapshotFromContext((MTMVRelatedTableIf) table, context)); } return refreshPartitionSnapshot; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVRefreshContext.java b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVRefreshContext.java index 3d611b5e8527e6..c59abd9ebdcda7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVRefreshContext.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVRefreshContext.java @@ -20,6 +20,8 @@ import org.apache.doris.catalog.MTMV; import org.apache.doris.common.AnalysisException; +import com.google.common.collect.Maps; + import java.util.Map; import java.util.Set; @@ -27,6 +29,10 @@ public class MTMVRefreshContext { private MTMV mtmv; private Map> partitionMappings; private MTMVBaseVersions baseVersions; + // Within the same context, repeated fetches of the same table's snapshot must return consistent values. + // Hence, the results are cached at this stage. + // The value is loaded/cached on the first fetch + private Map baseTableSnapshotCache = Maps.newHashMap(); public MTMVRefreshContext(MTMV mtmv) { this.mtmv = mtmv; @@ -44,6 +50,10 @@ public MTMVBaseVersions getBaseVersions() { return baseVersions; } + public Map getBaseTableSnapshotCache() { + return baseTableSnapshotCache; + } + public static MTMVRefreshContext buildContext(MTMV mtmv) throws AnalysisException { MTMVRefreshContext context = new MTMVRefreshContext(mtmv); context.partitionMappings = mtmv.calculatePartitionMappings(); diff --git a/fe/fe-core/src/test/java/org/apache/doris/mtmv/MTMVPartitionUtilTest.java b/fe/fe-core/src/test/java/org/apache/doris/mtmv/MTMVPartitionUtilTest.java index c2e1777f796c33..d90b43482eba1a 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/mtmv/MTMVPartitionUtilTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/mtmv/MTMVPartitionUtilTest.java @@ -38,6 +38,7 @@ import org.junit.Test; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; @@ -92,6 +93,10 @@ public void setUp() throws NoSuchMethodException, SecurityException, AnalysisExc minTimes = 0; result = versions; + context.getBaseTableSnapshotCache(); + minTimes = 0; + result = Maps.newHashMap(); + mtmv.getPartitions(); minTimes = 0; result = Lists.newArrayList(p1); @@ -296,4 +301,20 @@ public void testIsTableNamelike() { Assert.assertFalse(MTMVPartitionUtil.isTableNamelike(new TableName("db1"), tableNameToCheck)); Assert.assertFalse(MTMVPartitionUtil.isTableNamelike(new TableName("ctl1"), tableNameToCheck)); } + + @Test + public void testGetTableSnapshotFromContext() throws AnalysisException { + Map cache = Maps.newHashMap(); + new Expectations() { + { + context.getBaseTableSnapshotCache(); + minTimes = 0; + result = cache; + } + }; + Assert.assertTrue(cache.isEmpty()); + MTMVPartitionUtil.getTableSnapshotFromContext(baseOlapTable, context); + Assert.assertEquals(1, cache.size()); + Assert.assertEquals(baseSnapshotIf, cache.values().iterator().next()); + } }