Skip to content

Commit dec53c4

Browse files
authored
[fix](metaCache)fix bug that names cache can not invalidate. (#46287)
### What problem does this PR solve? Related PR: #41510 Problem Summary: In this pr#41510, namesCache changed from `LoadingCache<String, List<String>>` to `LoadingCache<String, List<Pair<String, String>>>`, but the `remove` method of this cache did not change, causing the hms event case to fail.
1 parent 073fd68 commit dec53c4

File tree

5 files changed

+238
-22
lines changed

5 files changed

+238
-22
lines changed

fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java

+1-5
Original file line numberDiff line numberDiff line change
@@ -628,7 +628,7 @@ public ExternalDatabase<? extends ExternalTable> getDbNullable(String dbName) {
628628
if (useMetaCache.get()) {
629629
// must use full qualified name to generate id.
630630
// otherwise, if 2 catalogs have the same db name, the id will be the same.
631-
return metaCache.getMetaObj(realDbName, Util.genIdByName(getQualifiedName(realDbName))).orElse(null);
631+
return metaCache.getMetaObj(realDbName, Util.genIdByName(name, realDbName)).orElse(null);
632632
} else {
633633
if (dbNameToId.containsKey(realDbName)) {
634634
return idToDb.get(dbNameToId.get(realDbName));
@@ -1081,10 +1081,6 @@ public void truncateTable(TruncateTableStmt stmt) throws DdlException {
10811081
}
10821082
}
10831083

1084-
public String getQualifiedName(String dbName) {
1085-
return String.join(".", name, dbName);
1086-
}
1087-
10881084
public void setAutoAnalyzePolicy(String dbName, String tableName, String policy) {
10891085
Pair<String, String> key = Pair.of(dbName, tableName);
10901086
if (policy == null) {

fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalDatabase.java

+6-7
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,8 @@ public T getTableNullable(String tableName) {
569569
if (extCatalog.getUseMetaCache().get()) {
570570
// must use full qualified name to generate id.
571571
// otherwise, if 2 databases have the same table name, the id will be the same.
572-
return metaCache.getMetaObj(tableName, Util.genIdByName(getQualifiedName(tableName))).orElse(null);
572+
return metaCache.getMetaObj(tableName,
573+
Util.genIdByName(extCatalog.getName(), name, tableName)).orElse(null);
573574
} else {
574575
if (!tableNameToId.containsKey(tableName)) {
575576
return null;
@@ -655,7 +656,7 @@ public void unregisterTable(String tableName) {
655656

656657
if (extCatalog.getUseMetaCache().get()) {
657658
if (isInitialized()) {
658-
metaCache.invalidate(tableName, Util.genIdByName(getQualifiedName(tableName)));
659+
metaCache.invalidate(tableName, Util.genIdByName(extCatalog.getName(), name, tableName));
659660
lowerCaseToTableName.remove(tableName.toLowerCase());
660661
}
661662
} else {
@@ -688,7 +689,9 @@ public boolean registerTable(TableIf tableIf) {
688689
}
689690
if (extCatalog.getUseMetaCache().get()) {
690691
if (isInitialized()) {
691-
metaCache.updateCache(tableName, (T) tableIf, Util.genIdByName(getQualifiedName(tableName)));
692+
String localName = extCatalog.fromRemoteTableName(this.remoteName, tableName);
693+
metaCache.updateCache(tableName, localName, (T) tableIf,
694+
Util.genIdByName(extCatalog.getName(), name, localName));
692695
lowerCaseToTableName.put(tableName.toLowerCase(), tableName);
693696
}
694697
} else {
@@ -704,10 +707,6 @@ public boolean registerTable(TableIf tableIf) {
704707
return true;
705708
}
706709

707-
public String getQualifiedName(String tblName) {
708-
return String.join(".", extCatalog.getName(), name, tblName);
709-
}
710-
711710
private boolean isStoredTableNamesLowerCase() {
712711
// Because we have added a test configuration item,
713712
// it needs to be judged together with Env.isStoredTableNamesLowerCase()

fe/fe-core/src/main/java/org/apache/doris/datasource/hive/HMSExternalCatalog.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ public void unregisterDatabase(String dbName) {
244244
}
245245
if (useMetaCache.get()) {
246246
if (isInitialized()) {
247-
metaCache.invalidate(dbName, Util.genIdByName(getQualifiedName(dbName)));
247+
metaCache.invalidate(dbName, Util.genIdByName(name, dbName));
248248
}
249249
} else {
250250
Long dbId = dbNameToId.remove(dbName);
@@ -265,7 +265,8 @@ public void registerDatabase(long dbId, String dbName) {
265265
ExternalDatabase<? extends ExternalTable> db = buildDbForInit(dbName, null, dbId, logType, false);
266266
if (useMetaCache.get()) {
267267
if (isInitialized()) {
268-
metaCache.updateCache(dbName, db, Util.genIdByName(getQualifiedName(dbName)));
268+
metaCache.updateCache(db.getRemoteName(), db.getFullName(), db,
269+
Util.genIdByName(name, db.getFullName()));
269270
}
270271
} else {
271272
dbNameToId.put(dbName, dbId);

fe/fe-core/src/main/java/org/apache/doris/datasource/metacache/MetaCache.java

+9-8
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636

3737
public class MetaCache<T> {
3838
private LoadingCache<String, List<Pair<String, String>>> namesCache;
39+
//Pair<String, String> : <Remote name, Local name>
3940
private Map<Long, String> idToName = Maps.newConcurrentMap();
4041
private LoadingCache<String, Optional<T>> metaObjCache;
4142

@@ -101,29 +102,29 @@ public Optional<T> getMetaObjById(long id) {
101102
return name == null ? Optional.empty() : getMetaObj(name, id);
102103
}
103104

104-
public void updateCache(String objName, T obj, long id) {
105-
metaObjCache.put(objName, Optional.of(obj));
105+
public void updateCache(String remoteName, String localName, T obj, long id) {
106+
metaObjCache.put(localName, Optional.of(obj));
106107
namesCache.asMap().compute("", (k, v) -> {
107108
if (v == null) {
108-
return Lists.newArrayList(Pair.of(objName, objName));
109+
return Lists.newArrayList(Pair.of(remoteName, localName));
109110
} else {
110-
v.add(Pair.of(objName, objName));
111+
v.add(Pair.of(remoteName, localName));
111112
return v;
112113
}
113114
});
114-
idToName.put(id, objName);
115+
idToName.put(id, localName);
115116
}
116117

117-
public void invalidate(String objName, long id) {
118+
public void invalidate(String localName, long id) {
118119
namesCache.asMap().compute("", (k, v) -> {
119120
if (v == null) {
120121
return Lists.newArrayList();
121122
} else {
122-
v.remove(objName);
123+
v.removeIf(pair -> pair.value().equals(localName));
123124
return v;
124125
}
125126
});
126-
metaObjCache.invalidate(objName);
127+
metaObjCache.invalidate(localName);
127128
idToName.remove(id);
128129
}
129130

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.apache.doris.datasource;
19+
20+
import org.apache.doris.common.Pair;
21+
import org.apache.doris.datasource.metacache.MetaCache;
22+
23+
import com.github.benmanes.caffeine.cache.CacheLoader;
24+
import com.github.benmanes.caffeine.cache.RemovalListener;
25+
import com.google.common.collect.Lists;
26+
import org.junit.Assert;
27+
import org.junit.Before;
28+
import org.junit.Test;
29+
30+
import java.util.List;
31+
import java.util.Optional;
32+
import java.util.OptionalLong;
33+
import java.util.concurrent.CountDownLatch;
34+
import java.util.concurrent.ExecutorService;
35+
import java.util.concurrent.Executors;
36+
import java.util.concurrent.TimeUnit;
37+
38+
public class MetaCacheTest {
39+
40+
private MetaCache<String> metaCache;
41+
42+
@Before
43+
public void setUp() {
44+
CacheLoader<String, List<Pair<String, String>>> namesCacheLoader = key -> Lists.newArrayList();
45+
CacheLoader<String, Optional<String>> metaObjCacheLoader = key -> Optional.empty();
46+
RemovalListener<String, Optional<String>> removalListener = (key, value, cause) -> {};
47+
48+
metaCache = new MetaCache<>(
49+
"testCache",
50+
Executors.newCachedThreadPool(),
51+
OptionalLong.of(1),
52+
OptionalLong.of(1),
53+
100, // max size
54+
namesCacheLoader,
55+
metaObjCacheLoader,
56+
removalListener
57+
);
58+
}
59+
60+
@Test
61+
public void testListNames() {
62+
metaCache.updateCache("remote1", "local1", "meta1", 1L);
63+
metaCache.updateCache("remote2", "local2", "meta2", 2L);
64+
65+
List<String> names = metaCache.listNames();
66+
Assert.assertEquals(2, names.size());
67+
Assert.assertTrue(names.contains("local1"));
68+
Assert.assertTrue(names.contains("local2"));
69+
}
70+
71+
@Test
72+
public void testGetRemoteName() {
73+
metaCache.updateCache("remote1", "local1", "meta1", 1L);
74+
75+
String remoteName = metaCache.getRemoteName("local1");
76+
Assert.assertEquals("remote1", remoteName);
77+
78+
Assert.assertNull(metaCache.getRemoteName("nonexistent"));
79+
}
80+
81+
@Test
82+
public void testGetMetaObj() {
83+
metaCache.updateCache("remote1", "local1", "meta1", 1L);
84+
metaCache.updateCache("remote2", "local2", "meta2", 2L);
85+
86+
Optional<String> metaObj = metaCache.getMetaObj("local1", 1L);
87+
Assert.assertTrue(metaObj.isPresent());
88+
Assert.assertEquals("meta1", metaObj.get());
89+
90+
Assert.assertFalse(metaCache.getMetaObj("xxx", 2L).isPresent());
91+
92+
}
93+
94+
@Test
95+
public void testGetMetaObjById() {
96+
metaCache.updateCache("remote1", "local1", "meta1", 1L);
97+
metaCache.updateCache("remote2", "local2", "meta2", 2L);
98+
metaCache.updateCache("remote3", "local3", "meta3", 1L);
99+
100+
Optional<String> metaObj = metaCache.getMetaObjById(1L);
101+
Assert.assertTrue(metaObj.isPresent());
102+
Assert.assertEquals("meta3", metaObj.get());
103+
104+
Assert.assertFalse(metaCache.getMetaObjById(99L).isPresent());
105+
}
106+
107+
@Test
108+
public void testUpdateCache() {
109+
metaCache.updateCache("remote1", "local1", "meta1", 1L);
110+
metaCache.updateCache("remote2", "local2", "meta2", 2L);
111+
112+
List<String> names = metaCache.listNames();
113+
Assert.assertEquals(2, names.size());
114+
Assert.assertTrue(names.contains("local1"));
115+
Assert.assertTrue(names.contains("local2"));
116+
117+
Optional<String> metaObj1 = metaCache.getMetaObj("local1", 1L);
118+
Assert.assertTrue(metaObj1.isPresent());
119+
Assert.assertEquals("meta1", metaObj1.get());
120+
121+
Optional<String> metaObj2 = metaCache.getMetaObj("local2", 2L);
122+
Assert.assertTrue(metaObj2.isPresent());
123+
Assert.assertEquals("meta2", metaObj2.get());
124+
}
125+
126+
@Test
127+
public void testInvalidate() {
128+
metaCache.updateCache("remote1", "local1", "meta1", 1L);
129+
metaCache.updateCache("remote2", "local2", "meta2", 2L);
130+
131+
// Invalidate local1 cache
132+
metaCache.invalidate("local1", 1L);
133+
134+
List<String> names = metaCache.listNames();
135+
Assert.assertEquals(1, names.size());
136+
Assert.assertTrue(names.contains("local2"));
137+
138+
Optional<String> metaObj1 = metaCache.getMetaObj("local1", 1L);
139+
Assert.assertFalse(metaObj1.isPresent());
140+
141+
Optional<String> metaObj2 = metaCache.getMetaObj("local2", 2L);
142+
Assert.assertTrue(metaObj2.isPresent());
143+
Assert.assertEquals("meta2", metaObj2.get());
144+
}
145+
146+
@Test
147+
public void testInvalidateAll() {
148+
metaCache.updateCache("remote1", "local1", "meta1", 1L);
149+
metaCache.updateCache("remote2", "local2", "meta2", 2L);
150+
151+
metaCache.invalidateAll();
152+
153+
List<String> names = metaCache.listNames();
154+
Assert.assertTrue(names.isEmpty());
155+
156+
Assert.assertFalse(metaCache.getMetaObj("local1", 1L).isPresent());
157+
Assert.assertFalse(metaCache.getMetaObj("local2", 2L).isPresent());
158+
}
159+
160+
@Test
161+
public void testCacheExpiration() throws InterruptedException {
162+
metaCache.updateCache("remote1", "local1", "meta1", 1L);
163+
Thread.sleep(2000);
164+
Optional<String> metaObj = metaCache.getMetaObj("local1", 1L);
165+
Assert.assertFalse(metaObj.isPresent());
166+
}
167+
168+
@Test
169+
public void testConcurrency() throws InterruptedException {
170+
ExecutorService executorService = Executors.newFixedThreadPool(10);
171+
172+
for (int i = 0; i < 10; i++) {
173+
final int id = i;
174+
executorService.submit(() -> {
175+
metaCache.updateCache("remote" + id, "local" + id, "meta" + id, id);
176+
});
177+
}
178+
179+
executorService.shutdown();
180+
executorService.awaitTermination(1, TimeUnit.MINUTES);
181+
182+
for (int i = 0; i < 10; i++) {
183+
Optional<String> metaObj = metaCache.getMetaObj("local" + i, i);
184+
Assert.assertTrue(metaObj.isPresent());
185+
Assert.assertEquals("meta" + i, metaObj.get());
186+
}
187+
}
188+
189+
@Test
190+
public void testMetaObjCacheLoader() throws InterruptedException {
191+
192+
CacheLoader<String, List<Pair<String, String>>> namesCacheLoader = key -> Lists.newArrayList();
193+
CountDownLatch latch = new CountDownLatch(2);
194+
CacheLoader<String, Optional<String>> metaObjCacheLoader = key -> {
195+
latch.countDown();
196+
return Optional.of("meta" + key);
197+
};
198+
199+
RemovalListener<String, Optional<String>> removalListener = (key, value, cause) -> {};
200+
201+
MetaCache<String> testCache = new MetaCache<>(
202+
"testCache",
203+
Executors.newCachedThreadPool(),
204+
OptionalLong.of(1),
205+
OptionalLong.of(1),
206+
100,
207+
namesCacheLoader,
208+
metaObjCacheLoader,
209+
removalListener
210+
);
211+
testCache.getMetaObj("local2", 1L);
212+
213+
Optional<String> metaObj = testCache.getMetaObj("local1", 1L);
214+
Assert.assertTrue(metaObj.isPresent());
215+
Assert.assertEquals("metalocal1", metaObj.get());
216+
latch.await();
217+
218+
}
219+
}

0 commit comments

Comments
 (0)