This is an automated email from the ASF dual-hosted git repository.
yashmayya pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git
The following commit(s) were added to refs/heads/master by this push:
new 6950c850cd GET /logicalTables API to return database specific tables.
(#15944)
6950c850cd is described below
commit 6950c850cd7ce14af7cf667da8f09c4824bb96fd
Author: Abhishek Bafna <[email protected]>
AuthorDate: Fri May 30 20:07:39 2025 +0530
GET /logicalTables API to return database specific tables. (#15944)
---
.../api/resources/PinotLogicalTableResource.java | 3 +-
.../helix/core/PinotHelixResourceManager.java | 15 +++++
.../resources/PinotLogicalTableResourceTest.java | 66 +++++++++++++++++++---
3 files changed, 76 insertions(+), 8 deletions(-)
diff --git
a/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotLogicalTableResource.java
b/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotLogicalTableResource.java
index 73265bd832..56a9f02edd 100644
---
a/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotLogicalTableResource.java
+++
b/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotLogicalTableResource.java
@@ -93,7 +93,8 @@ public class PinotLogicalTableResource {
@Authorize(targetType = TargetType.CLUSTER, paramName = "tableName", action
= Actions.Cluster.GET_TABLE)
@ApiOperation(value = "List all logical table names", notes = "Lists all
logical table names")
public List<String> listLogicalTableNames(@Context HttpHeaders headers) {
- return _pinotHelixResourceManager.getAllLogicalTableNames();
+ String databaseName =
DatabaseUtils.extractDatabaseFromHttpHeaders(headers);
+ return _pinotHelixResourceManager.getAllLogicalTableNames(databaseName);
}
@GET
diff --git
a/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/PinotHelixResourceManager.java
b/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/PinotHelixResourceManager.java
index ef823d55bf..93ece7c42e 100644
---
a/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/PinotHelixResourceManager.java
+++
b/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/PinotHelixResourceManager.java
@@ -2378,6 +2378,10 @@ public class PinotHelixResourceManager {
return ZKMetadataProvider.getLogicalTableConfig(_propertyStore, tableName);
}
+ /**
+ * Returns all logical table names in the cluster regardless of their
database name.
+ * @return List of logical table names
+ */
public List<String> getAllLogicalTableNames() {
List<String> logicalTableNames = _propertyStore.getChildNames(
PinotHelixPropertyStoreZnRecordProvider.forLogicalTable(_propertyStore).getRelativePath(),
@@ -2385,6 +2389,17 @@ public class PinotHelixResourceManager {
return logicalTableNames != null ? logicalTableNames :
Collections.emptyList();
}
+ /**
+ * Returns all logical table names in the cluster that belong to the given
database.
+ * @param databaseName The name of the database
+ * @return List of logical table names that belong to the given database
+ */
+ public List<String> getAllLogicalTableNames(String databaseName) {
+ return getAllLogicalTableNames().stream()
+ .filter(tableName -> DatabaseUtils.isPartOfDatabase(tableName,
databaseName))
+ .collect(Collectors.toList());
+ }
+
/**
* Returns the ZK metdata for the given jobId and jobType
* @param jobId the id of the job
diff --git
a/pinot-controller/src/test/java/org/apache/pinot/controller/api/resources/PinotLogicalTableResourceTest.java
b/pinot-controller/src/test/java/org/apache/pinot/controller/api/resources/PinotLogicalTableResourceTest.java
index 3458777e8d..50a29e2e55 100644
---
a/pinot-controller/src/test/java/org/apache/pinot/controller/api/resources/PinotLogicalTableResourceTest.java
+++
b/pinot-controller/src/test/java/org/apache/pinot/controller/api/resources/PinotLogicalTableResourceTest.java
@@ -20,6 +20,7 @@ package org.apache.pinot.controller.api.resources;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -32,6 +33,7 @@ import org.apache.pinot.spi.config.table.TableConfig;
import org.apache.pinot.spi.config.table.TableType;
import org.apache.pinot.spi.data.LogicalTableConfig;
import org.apache.pinot.spi.data.TimeBoundaryConfig;
+import org.apache.pinot.spi.utils.CommonConstants;
import org.apache.pinot.spi.utils.builder.ControllerRequestURLBuilder;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
@@ -334,9 +336,11 @@ public class PinotLogicalTableResourceTest extends
ControllerTest {
throwable.getMessage());
}
+ @Test
public void testLogicalTableTimeBoundaryConfigValidation()
throws IOException {
// Test logical table time boundary strategy validation
+ addDummySchema(LOGICAL_TABLE_NAME);
List<String> physicalTableNamesWithType =
createHybridTables(List.of("test_table_8"));
LogicalTableConfig logicalTableConfig =
getDummyLogicalTableConfig(LOGICAL_TABLE_NAME,
physicalTableNamesWithType, BROKER_TENANT);
@@ -356,7 +360,7 @@ public class PinotLogicalTableResourceTest extends
ControllerTest {
ControllerTest.sendPostRequest(_addLogicalTableUrl,
logicalTableConfig.toSingleLineJsonString(), getHeaders());
});
assertTrue(throwable.getMessage()
- .contains("Reason: 'timeBoundaryConfig.strategy' should not be
null or empty for hybrid logical tables"),
+ .contains("Reason: 'timeBoundaryConfig.boundaryStrategy' should
not be null or empty"),
throwable.getMessage());
// Test logical table with time boundary config but empty strategy
@@ -365,7 +369,7 @@ public class PinotLogicalTableResourceTest extends
ControllerTest {
ControllerTest.sendPostRequest(_addLogicalTableUrl,
logicalTableConfig.toSingleLineJsonString(), getHeaders());
});
assertTrue(throwable.getMessage()
- .contains("Reason: 'timeBoundaryConfig.strategy' should not be
null or empty for hybrid logical tables"),
+ .contains("Reason: 'timeBoundaryConfig.boundaryStrategy' should
not be null or empty"),
throwable.getMessage());
// Test logical table with time boundary config but null parameters
@@ -374,7 +378,7 @@ public class PinotLogicalTableResourceTest extends
ControllerTest {
ControllerTest.sendPostRequest(_addLogicalTableUrl,
logicalTableConfig.toSingleLineJsonString(), getHeaders());
});
assertTrue(throwable.getMessage()
- .contains("Reason: 'timeBoundaryConfig.parameters' should not be
null or empty for hybrid logical tables"),
+ .contains("Reason: 'timeBoundaryConfig.parameters' should not be
null or empty"),
throwable.getMessage());
// Test logical table with time boundary config but empty parameters
@@ -383,7 +387,7 @@ public class PinotLogicalTableResourceTest extends
ControllerTest {
ControllerTest.sendPostRequest(_addLogicalTableUrl,
logicalTableConfig.toSingleLineJsonString(), getHeaders());
});
assertTrue(throwable.getMessage()
- .contains("Reason: 'timeBoundaryConfig.parameters' should not be
null or empty for hybrid logical tables"),
+ .contains("Reason: 'timeBoundaryConfig.parameters' should not be
null or empty"),
throwable.getMessage());
}
@@ -447,7 +451,8 @@ public class PinotLogicalTableResourceTest extends
ControllerTest {
assertEquals(response, objectMapper.writeValueAsString(List.of()));
// setup physical tables and logical tables
- List<String> logicalTableNames = List.of("db.test_logical_table_1",
"test_logical_table_2", "test_logical_table_3");
+ List<String> logicalTableNames =
+ List.of("db.test_logical_table_1", "default.test_logical_table_2",
"test_logical_table_3");
List<String> physicalTableNames = List.of("test_table_1", "test_table_2",
"db.test_table_3");
List<String> physicalTableNamesWithType =
createHybridTables(physicalTableNames);
@@ -459,9 +464,56 @@ public class PinotLogicalTableResourceTest extends
ControllerTest {
ControllerTest.sendPostRequest(_addLogicalTableUrl,
logicalTableConfig.toSingleLineJsonString(), getHeaders());
}
- // verify logical table names
+ // verify logical table names without headers, should return tables
without database prefix (or default database)
String getLogicalTableNamesResponse =
ControllerTest.sendGetRequest(getLogicalTableNamesUrl, getHeaders());
- assertEquals(getLogicalTableNamesResponse,
objectMapper.writeValueAsString(logicalTableNames));
+ assertEquals(getLogicalTableNamesResponse,
+ objectMapper.writeValueAsString(List.of("test_logical_table_2",
"test_logical_table_3")));
+
+ // verify logical table names with headers, should return tables with
database prefix
+ Map<String, String> headers = new HashMap<>(getHeaders());
+ headers.put(CommonConstants.DATABASE, "db");
+ getLogicalTableNamesResponse =
ControllerTest.sendGetRequest(getLogicalTableNamesUrl, headers);
+ assertEquals(getLogicalTableNamesResponse,
+ objectMapper.writeValueAsString(List.of("db.test_logical_table_1")));
+ }
+
+ @Test
+ public void testLogicalTableDatabaseHeaderMismatchValidation()
+ throws IOException {
+ Map<String, String> headers = new HashMap<>(getHeaders());
+ headers.put(CommonConstants.DATABASE, "db1");
+ String logicalTableName = "db2.test_logical_table";
+ LogicalTableConfig logicalTableConfig =
getDummyLogicalTableConfig(logicalTableName,
+ List.of("test_table_1_OFFLINE", "test_table_2_REALTIME"),
BROKER_TENANT);
+
+ // Test add logical table with database header mismatch
+ String msg = expectThrows(IOException.class,
+ () -> ControllerTest.sendPostRequest(_addLogicalTableUrl,
logicalTableConfig.toSingleLineJsonString(),
+ headers)).getMessage();
+ assertTrue(msg.contains("Database name 'db2' from table prefix does not
match database name 'db1' from header"),
+ msg);
+
+ // Test get logical table with database header mismatch
+ String getLogicalTableUrl =
_controllerRequestURLBuilder.forLogicalTableGet(logicalTableName);
+ msg = expectThrows(IOException.class,
+ () -> ControllerTest.sendGetRequest(getLogicalTableUrl,
headers)).getMessage();
+ assertTrue(msg.contains("Database name 'db2' from table prefix does not
match database name 'db1' from header"),
+ msg);
+
+ // Test update logical table with database header mismatch
+ String updateLogicalTableUrl =
_controllerRequestURLBuilder.forLogicalTableUpdate(logicalTableName);
+ msg = expectThrows(IOException.class,
+ () -> ControllerTest.sendPutRequest(updateLogicalTableUrl,
logicalTableConfig.toSingleLineJsonString(),
+ headers)).getMessage();
+ assertTrue(msg.contains("Database name 'db2' from table prefix does not
match database name 'db1' from header"),
+ msg);
+
+ // Test delete logical table with database header mismatch
+ String deleteLogicalTableUrl =
_controllerRequestURLBuilder.forLogicalTableDelete(logicalTableName);
+ msg = expectThrows(IOException.class,
+ () -> ControllerTest.sendDeleteRequest(deleteLogicalTableUrl,
headers)).getMessage();
+ assertTrue(msg.contains("Database name 'db2' from table prefix does not
match database name 'db1' from header"),
+ msg);
}
@Test
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]