diff --git a/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalDatabase.java b/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalDatabase.java index b716ce5366b690..34f38df5de6086 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalDatabase.java +++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalDatabase.java @@ -177,7 +177,7 @@ private void buildMetaCache() { } } - private List> listTableNames() { + private synchronized List> listTableNames() { List> tableNames; lowerCaseToTableName.clear(); if (name.equals(InfoSchemaDb.DATABASE_NAME)) { @@ -420,9 +420,17 @@ public boolean isTableExist(String tableName) { remoteTblName = lowerCaseToTableName.get(tableName.toLowerCase()); if (remoteTblName == null) { // Here we need to execute listTableNames() once to fill in lowerCaseToTableName - // to prevent lowerCaseToTableName from being empty in some cases - listTableNames(); - remoteTblName = lowerCaseToTableName.get(tableName.toLowerCase()); + // to prevent lowerCaseToTableName from being empty in some cases. + // Use double-checked locking against the same monitor used by listTableNames() + // so that we don't keep repeating a remote list call and don't race with + // a concurrent listTableNames() that is swapping the map. + synchronized (this) { + remoteTblName = lowerCaseToTableName.get(tableName.toLowerCase()); + if (remoteTblName == null) { + listTableNames(); + remoteTblName = lowerCaseToTableName.get(tableName.toLowerCase()); + } + } if (remoteTblName == null) { return false; } @@ -504,9 +512,17 @@ private String getLocalTableName(String tableName, boolean isReplay) { return null; } // Here we need to execute listTableNames() once to fill in lowerCaseToTableName - // to prevent lowerCaseToTableName from being empty in some cases - listTableNames(); - finalName = lowerCaseToTableName.get(tableName.toLowerCase()); + // to prevent lowerCaseToTableName from being empty in some cases. + // Use double-checked locking against the same monitor used by listTableNames() + // so that concurrent callers don't wipe each other's results and don't issue + // redundant remote list calls. + synchronized (this) { + finalName = lowerCaseToTableName.get(tableName.toLowerCase()); + if (finalName == null) { + listTableNames(); + finalName = lowerCaseToTableName.get(tableName.toLowerCase()); + } + } if (finalName == null) { if (LOG.isDebugEnabled()) { LOG.debug("failed to get final table name from: {}.{}.{}",