This is an automated email from the ASF dual-hosted git repository.
diqiu50 pushed a commit to branch branch-1.3
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/branch-1.3 by this push:
new 81fa21ad27 [Cherry-pick to branch-1.3] [#13697]
improvement(trino-connector): Load catalogs with a single detailed listing on
refresh (#13698) (#13704)
81fa21ad27 is described below
commit 81fa21ad2751b8393581138085f50ccdd1df64a5
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Fri Oct 9 15:08:29 2026 +0800
[Cherry-pick to branch-1.3] [#13697] improvement(trino-connector): Load
catalogs with a single detailed listing on refresh (#13698) (#13704)
**Cherry-pick Information:**
- Original commit: 62240804b7c4a79da147b7f659b840ff50ce934a
- Target branch: `branch-1.3`
- Status: ⚠️ **Has conflicts - manual resolution required**
---------
Co-authored-by: Yuhui <[email protected]>
Co-authored-by: diqiu50 <[email protected]>
---
.../connector/catalog/CatalogConnectorManager.java | 21 +++----
.../catalog/TestCatalogConnectorManager.java | 72 +++++++++++++---------
2 files changed, 53 insertions(+), 40 deletions(-)
diff --git
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/CatalogConnectorManager.java
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/CatalogConnectorManager.java
index d7fed43f55..cdc4cac2ba 100644
---
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/CatalogConnectorManager.java
+++
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/CatalogConnectorManager.java
@@ -26,6 +26,7 @@ import io.trino.spi.TrinoException;
import io.trino.spi.connector.ConnectorContext;
import java.util.ArrayList;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
@@ -450,9 +451,13 @@ public class CatalogConnectorManager {
private void loadCatalogs(GravitinoMetalake metalake) {
String metalakeName = metalake.name();
- String[] allCatalogNames;
+ // Keyed by name in listing order. Read with their details in a single
request, so that a
+ // refresh costs the server one call instead of one per catalog.
+ Map<String, Catalog> allCatalogs = new LinkedHashMap<>();
try {
- allCatalogNames = metalake.listCatalogs();
+ for (Catalog catalog : metalake.listCatalogsInfo()) {
+ allCatalogs.put(catalog.name(), catalog);
+ }
} catch (Exception e) {
// Keep the existing catalog states untouched, a transient listing
failure must not turn
// healthy catalogs into failed ones. The load status system table
reports the cause.
@@ -465,7 +470,7 @@ public class CatalogConnectorManager {
// catalogs that are intentionally not registered.
Set<String> presentTrinoNames = new HashSet<>();
List<String> catalogNames = new ArrayList<>();
- for (String catalogName : allCatalogNames) {
+ for (String catalogName : allCatalogs.keySet()) {
String trinoCatalogName = getTrinoCatalogName(metalakeName, catalogName);
presentTrinoNames.add(trinoCatalogName);
if (skipCatalog(trinoCatalogName)) {
@@ -558,7 +563,7 @@ public class CatalogConnectorManager {
// Tracked outside the try so that a failure can still report the
provider it knows about.
String provider = null;
try {
- Catalog catalog = metalake.loadCatalog(catalogName);
+ Catalog catalog = allCatalogs.get(catalogName);
GravitinoCatalog gravitinoCatalog = new GravitinoCatalog(metalakeName,
catalog);
provider = gravitinoCatalog.getProvider();
// Checked before the already-registered path: a catalog can be
dropped and recreated
@@ -593,14 +598,6 @@ public class CatalogConnectorManager {
recordCatalogState(
CatalogRegistrationState.succeeded(gravitinoCatalog,
trinoCatalogName), null);
}
- } catch (UnsupportedOperationException e) {
- // The client library does not recognize this catalog's type, e.g.
DTOConverters.toCatalog
- // throws for a type it cannot map. This is the same "we know about
it, we just don't
- // support it" case as the type/provider checks above, not a
registration failure.
- recordCatalogState(
- CatalogRegistrationState.unsupported(
- metalakeName, catalogName, trinoCatalogName, provider,
toErrorMessage(e)),
- e);
} catch (Exception e) {
// reloadCatalog() unregisters the old connector before
re-registering; if the
// re-register then fails, the catalog is no longer in
catalogConnectors even though
diff --git
a/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/catalog/TestCatalogConnectorManager.java
b/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/catalog/TestCatalogConnectorManager.java
index 8bea849ee3..2e904d0a3a 100644
---
a/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/catalog/TestCatalogConnectorManager.java
+++
b/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/catalog/TestCatalogConnectorManager.java
@@ -258,15 +258,14 @@ public class TestCatalogConnectorManager {
@Test
public void testFailureBeforeProviderIsKnownKeepsPreviousProvider() throws
Exception {
LoadFixture fixture = new LoadFixture();
- fixture.withCatalogs(mockCatalog("memory", "memory",
Catalog.Type.RELATIONAL));
+ Catalog catalog = mockCatalog("memory", "memory", Catalog.Type.RELATIONAL);
+ fixture.withCatalogs(catalog);
CatalogConnectorManager manager = fixture.createManager(ImmutableMap.of());
manager.loadMetalakeSync();
assertEquals("memory", singleState(manager).getProvider());
// The next attempt fails before the provider can even be read off the
catalog.
- Mockito.doThrow(new RuntimeException("Connection reset"))
- .when(fixture.metalake)
- .loadCatalog("memory");
+ when(catalog.properties()).thenThrow(new RuntimeException("simulated:
invalid properties"));
manager.loadMetalakeSync();
CatalogRegistrationState state = singleState(manager);
@@ -319,7 +318,7 @@ public class TestCatalogConnectorManager {
Mockito.doThrow(new RuntimeException("Connection refused"))
.when(fixture.metalake)
- .listCatalogs();
+ .listCatalogsInfo();
manager.loadMetalakeSync();
Map<String, String> metalakeErrors = manager.getMetalakeErrors();
@@ -448,7 +447,7 @@ public class TestCatalogConnectorManager {
Mockito.doThrow(new RuntimeException("Connection refused"))
.when(fixture.metalake)
- .listCatalogs();
+ .listCatalogsInfo();
manager.loadMetalakeSync();
assertEquals(1, manager.getMetalakeErrors().size());
// A metalake that cannot be listed is not a healthy loop.
@@ -483,7 +482,7 @@ public class TestCatalogConnectorManager {
doThrow(new TrinoException(GravitinoErrorCode.GRAVITINO_RUNTIME_ERROR,
"Access Denied"))
.when(fixture.catalogRegister)
.unregisterCatalog(any());
- Mockito.doReturn(new String[0]).when(fixture.metalake).listCatalogs();
+ Mockito.doReturn(new Catalog[0]).when(fixture.metalake).listCatalogsInfo();
manager.loadMetalakeSync();
// The catalog is gone from Gravitino but still registered in Trino: the
state must say so
@@ -539,9 +538,7 @@ public class TestCatalogConnectorManager {
when(context.getCatalog())
.thenReturn(new GravitinoCatalog("test", "memory", "memory",
ImmutableMap.of(), 0L));
- Mockito.doThrow(new RESTException("simulated: the server rejected the
load"))
- .when(fixture.metalake)
- .loadCatalog("memory");
+ when(catalog.properties()).thenThrow(new RuntimeException("simulated:
invalid properties"));
manager.loadMetalakeSync();
// The catalog is still registered and queryable, so a failed refresh must
not flip it to
@@ -553,21 +550,19 @@ public class TestCatalogConnectorManager {
}
@Test
- public void testUnknownCatalogTypeIsRecordedAsUnsupported() throws Exception
{
+ public void testUnknownCatalogTypeFailsTheMetalakeListing() throws Exception
{
LoadFixture fixture = new LoadFixture();
- fixture.withCatalogs(mockCatalog("memory", "memory",
Catalog.Type.RELATIONAL));
CatalogConnectorManager manager = fixture.createManager(ImmutableMap.of());
- // The client library cannot map this catalog's type, e.g.
DTOConverters.toCatalog throwing
- // for a type it does not know. That is a "not supported", not a
registration failure.
+ // The client library cannot map a listed catalog's type, e.g.
DTOConverters.toCatalog throwing
+ // for a type it does not know, which fails the listing of the whole
metalake.
Mockito.doThrow(new UnsupportedOperationException("Unsupported catalog
type: UNKNOWN"))
.when(fixture.metalake)
- .loadCatalog("memory");
+ .listCatalogsInfo();
manager.loadMetalakeSync();
- CatalogRegistrationState state = singleState(manager);
- assertEquals(CatalogRegistrationState.Status.UNSUPPORTED,
state.getStatus());
- assertTrue(state.getLastError().contains("Unsupported catalog type"));
+ assertTrue(manager.getMetalakeErrors().get("test").contains("Unsupported
catalog type"));
+ assertTrue(manager.getCatalogRegistrationStates().isEmpty());
assertFalse(manager.catalogConnectorExist("memory"));
}
@@ -629,6 +624,28 @@ public class TestCatalogConnectorManager {
assertNull(state.getLastError());
}
+ @Test
+ public void testCatalogsAreLoadedWithOneDetailedListing() throws Exception {
+ LoadFixture fixture = new LoadFixture();
+ Catalog first = mockCatalog("a", "memory", Catalog.Type.RELATIONAL);
+ Catalog second = mockCatalog("b", "memory", Catalog.Type.RELATIONAL);
+ Mockito.doReturn(new Catalog[] {first,
second}).when(fixture.metalake).listCatalogsInfo();
+ CatalogConnectorManager manager = fixture.createManager(ImmutableMap.of());
+
+ manager.loadMetalakeSync();
+ manager.loadMetalakeSync();
+
+ // Every refresh reads all catalogs with one request instead of one
request per catalog.
+ verify(fixture.metalake, times(2)).listCatalogsInfo();
+ verify(fixture.metalake, never()).listCatalogs();
+ verify(fixture.metalake, never()).loadCatalog(any());
+ List<CatalogRegistrationState> states =
manager.getCatalogRegistrationStates();
+ assertEquals(2, states.size());
+ for (CatalogRegistrationState state : states) {
+ assertEquals(CatalogRegistrationState.Status.REGISTERED,
state.getStatus());
+ }
+ }
+
@Test
public void testDeletedCatalogWithConnectorIsRemoved() throws Exception {
LoadFixture fixture = new LoadFixture();
@@ -645,7 +662,7 @@ public class TestCatalogConnectorManager {
.thenReturn(new GravitinoCatalog("test", "memory", "memory",
ImmutableMap.of(), 0L));
// The catalog is deleted in Gravitino and unregisters cleanly from Trino.
- Mockito.doReturn(new String[0]).when(fixture.metalake).listCatalogs();
+ Mockito.doReturn(new Catalog[0]).when(fixture.metalake).listCatalogsInfo();
manager.loadMetalakeSync();
verify(fixture.catalogRegister, times(1)).unregisterCatalog("memory");
@@ -792,7 +809,7 @@ public class TestCatalogConnectorManager {
// The losing catalog is deleted in Gravitino. The winner still holds the
Trino name, which
// must not keep the loser's row alive.
- Mockito.doReturn(new String[0]).when(dev).listCatalogs();
+ Mockito.doReturn(new Catalog[0]).when(dev).listCatalogsInfo();
manager.loadMetalakeSync();
assertTrue(manager.getCatalogRegistrationStates("dev").isEmpty());
@@ -825,7 +842,7 @@ public class TestCatalogConnectorManager {
assertNull(manager.getCatalogConnector("dev", "memory"));
// The winning catalog is deleted in Gravitino, which frees the Trino name
for the loser.
- Mockito.doReturn(new String[0]).when(fixture.metalake).listCatalogs();
+ Mockito.doReturn(new Catalog[0]).when(fixture.metalake).listCatalogsInfo();
owner[0] = "dev";
manager.loadMetalakeSync();
@@ -872,8 +889,7 @@ public class TestCatalogConnectorManager {
GravitinoMetalake devMetalake = mock(GravitinoMetalake.class);
when(devMetalake.name()).thenReturn("dev");
Catalog devCatalog = mockCatalog("sandbox", "memory",
Catalog.Type.RELATIONAL);
- Mockito.doReturn(new String[]
{"sandbox"}).when(devMetalake).listCatalogs();
- Mockito.doReturn(devCatalog).when(devMetalake).loadCatalog("sandbox");
+ Mockito.doReturn(new Catalog[]
{devCatalog}).when(devMetalake).listCatalogsInfo();
Mockito.doReturn(new GravitinoMetalake[] {fixture.metalake, devMetalake})
.when(fixture.client)
.listMetalakes();
@@ -963,7 +979,7 @@ public class TestCatalogConnectorManager {
LoadFixture fixture = new LoadFixture();
Mockito.doThrow(new RESTException("simulated: listing failed"))
.when(fixture.metalake)
- .listCatalogs();
+ .listCatalogsInfo();
CatalogConnectorManager manager = fixture.createManager(ImmutableMap.of());
manager.loadMetalakeSync();
@@ -1145,7 +1161,7 @@ public class TestCatalogConnectorManager {
LoadFixture fixture = new LoadFixture();
Mockito.doThrow(new RESTException("simulated: listing failed"))
.when(fixture.metalake)
- .listCatalogs();
+ .listCatalogsInfo();
CatalogConnectorManager manager = fixture.createManager(ImmutableMap.of());
manager.loadMetalakeSync();
assertFalse(manager.getLoadOutcome().getMetalakeErrors().isEmpty());
@@ -1165,7 +1181,7 @@ public class TestCatalogConnectorManager {
LoadFixture fixture = new LoadFixture();
Mockito.doThrow(new RESTException("simulated: listing failed"))
.when(fixture.metalake)
- .listCatalogs();
+ .listCatalogsInfo();
CatalogConnectorManager manager = fixture.createManager(ImmutableMap.of());
manager.loadMetalakeSync();
assertTrue(manager.describeRegistrationFailure("test",
"memory").contains("listing failed"));
@@ -1560,7 +1576,7 @@ public class TestCatalogConnectorManager {
names[i] = catalogs[i].name();
Mockito.doReturn(catalogs[i]).when(metalake).loadCatalog(names[i]);
}
- Mockito.doReturn(names).when(metalake).listCatalogs();
+ Mockito.doReturn(catalogs).when(metalake).listCatalogsInfo();
}
CatalogConnectorManager createManager(Map<String, String> extraConfig) {
@@ -1597,7 +1613,7 @@ public class TestCatalogConnectorManager {
names[i] = catalogs[i].name();
Mockito.doReturn(catalogs[i]).when(second).loadCatalog(names[i]);
}
- Mockito.doReturn(names).when(second).listCatalogs();
+ Mockito.doReturn(catalogs).when(second).listCatalogsInfo();
Mockito.doReturn(second).when(client).loadMetalake(name);
Mockito.doReturn(new GravitinoMetalake[] {metalake,
second}).when(client).listMetalakes();
return second;