This is an automated email from the ASF dual-hosted git repository.
tkhurana pushed a commit to branch PHOENIX-7562-feature-new
in repository https://gitbox.apache.org/repos/asf/phoenix.git
The following commit(s) were added to refs/heads/PHOENIX-7562-feature-new by
this push:
new 95bc49ae23 PHOENIX-7763 :- Accept HAGroupName in Urls for HA
Connection to improve backward compatibility. (#2378)
95bc49ae23 is described below
commit 95bc49ae23ff31efae8b76f47931272dc149c467
Author: Lokesh Khurana <[email protected]>
AuthorDate: Thu Feb 26 15:39:27 2026 -0800
PHOENIX-7763 :- Accept HAGroupName in Urls for HA Connection to improve
backward compatibility. (#2378)
* Overriding connection properties with URL passed properties in HA
Connections
---
.../apache/phoenix/jdbc/HighAvailabilityGroup.java | 50 +++++---
.../apache/phoenix/jdbc/PhoenixEmbeddedDriver.java | 2 +-
.../phoenix/jdbc/FailoverPhoenixConnectionIT.java | 28 ++++-
.../jdbc/HighAvailabilityTestingUtility.java | 1 +
.../phoenix/jdbc/HighAvailabilityGroupTest.java | 126 +++++++++++++++++++++
5 files changed, 185 insertions(+), 22 deletions(-)
diff --git
a/phoenix-core-client/src/main/java/org/apache/phoenix/jdbc/HighAvailabilityGroup.java
b/phoenix-core-client/src/main/java/org/apache/phoenix/jdbc/HighAvailabilityGroup.java
index 87a6700eca..77c7e75c13 100644
---
a/phoenix-core-client/src/main/java/org/apache/phoenix/jdbc/HighAvailabilityGroup.java
+++
b/phoenix-core-client/src/main/java/org/apache/phoenix/jdbc/HighAvailabilityGroup.java
@@ -240,13 +240,6 @@ public class HighAvailabilityGroup {
* @throws SQLException if fails to get HA information and/or invalid
properties are seen
*/
public static HAURLInfo getUrlInfo(String url, Properties properties) throws
SQLException {
- // Check if HA group name is provided in the properties if not throw an
exception
- String name = properties.getProperty(PHOENIX_HA_GROUP_ATTR);
- if (StringUtils.isEmpty(name)) {
- throw new
SQLExceptionInfo.Builder(SQLExceptionCode.HA_INVALID_PROPERTIES)
- .setMessage(String.format("HA group name can not be empty for HA URL
%s", url)).build()
- .buildException();
- }
url = checkUrl(url);
String principal = null;
String additionalJDBCParams = null;
@@ -303,23 +296,45 @@ public class HighAvailabilityGroup {
: additionalJDBCParams)
: null;
- HAURLInfo haurlInfo = new HAURLInfo(name, principal, additionalJDBCParams);
- HAGroupInfo info = getHAGroupInfo(url, properties);
- URLS.computeIfAbsent(info, haGroupInfo -> new HashSet<>()).add(haurlInfo);
- return haurlInfo;
- }
+ // Here additionalJDBCParams can contain more than one properties
separated by ;
+ // Adding the properties from url to connection properties
+ if (additionalJDBCParams != null) {
+ String[] propsFromUrl = additionalJDBCParams.split(";");
+ for (String property : propsFromUrl) {
+ if (StringUtils.isEmpty(property)) {
+ continue;
+ }
+ String[] keyValue = property.split("=");
+ if (keyValue.length != 2) {
+ throw new
SQLExceptionInfo.Builder(SQLExceptionCode.MALFORMED_CONNECTION_URL)
+ .setMessage(String.format("URL %s has additional JDBC props in
wrong format", url))
+ .build().buildException();
+ }
+ properties.put(keyValue[0], keyValue[1]);
+ }
+ }
- private static HAGroupInfo getHAGroupInfo(String url, Properties properties)
throws SQLException {
+ // Check if HA group name is provided in the url if not then check in the
properties if not
+ // throw an exception.
String name = properties.getProperty(PHOENIX_HA_GROUP_ATTR);
if (StringUtils.isEmpty(name)) {
throw new
SQLExceptionInfo.Builder(SQLExceptionCode.HA_INVALID_PROPERTIES)
.setMessage(String.format("HA group name can not be empty for HA URL
%s", url)).build()
.buildException();
}
+
+ HAURLInfo haurlInfo = new HAURLInfo(name, principal, additionalJDBCParams);
+ HAGroupInfo info = getHAGroupInfo(url, properties, haurlInfo);
+ URLS.computeIfAbsent(info, haGroupInfo -> new HashSet<>()).add(haurlInfo);
+ return haurlInfo;
+ }
+
+ private static HAGroupInfo getHAGroupInfo(String url, Properties properties,
HAURLInfo haurlInfo)
+ throws SQLException {
url = checkUrl(url);
url = url.substring(url.indexOf("[") + 1, url.indexOf("]"));
String[] urls = url.split("\\|");
- return new HAGroupInfo(name, urls[0], urls[1]);
+ return new HAGroupInfo(haurlInfo.getName(), urls[0], urls[1]);
}
/**
@@ -371,7 +386,8 @@ public class HighAvailabilityGroup {
*/
public static Optional<HighAvailabilityGroup> get(String url, Properties
properties)
throws SQLException {
- HAGroupInfo info = getHAGroupInfo(url, properties);
+ HAURLInfo haurlInfo = getUrlInfo(url, properties);
+ HAGroupInfo info = getHAGroupInfo(url, properties, haurlInfo);
// create a cache for missing CRR to prevent unnecessary exceptions (cache
expires in 5 minutes)
if (MISSING_CRR_GROUPS_CACHE.getIfPresent(info) != null) {
return Optional.empty();
@@ -419,9 +435,9 @@ public class HighAvailabilityGroup {
* protocol
* @throws SQLException if fails to get HA information and/or invalid
properties are seen
*/
- static Optional<String> getFallbackCluster(String url, Properties properties)
+ static Optional<String> getFallbackCluster(String url, Properties
properties, HAURLInfo haurlInfo)
throws SQLException {
- HAGroupInfo haGroupInfo = getHAGroupInfo(url, properties);
+ HAGroupInfo haGroupInfo = getHAGroupInfo(url, properties, haurlInfo);
String fallback =
properties.getProperty(PHOENIX_HA_SHOULD_FALLBACK_WHEN_MISSING_CRR_KEY,
PHOENIX_HA_SHOULD_FALLBACK_WHEN_MISSING_CRR_DEFAULT);
diff --git
a/phoenix-core-client/src/main/java/org/apache/phoenix/jdbc/PhoenixEmbeddedDriver.java
b/phoenix-core-client/src/main/java/org/apache/phoenix/jdbc/PhoenixEmbeddedDriver.java
index b5bbe2ea55..5670bc3c33 100644
---
a/phoenix-core-client/src/main/java/org/apache/phoenix/jdbc/PhoenixEmbeddedDriver.java
+++
b/phoenix-core-client/src/main/java/org/apache/phoenix/jdbc/PhoenixEmbeddedDriver.java
@@ -138,7 +138,7 @@ public abstract class PhoenixEmbeddedDriver implements
Driver, SQLCloseable {
return haGroup.get().connect(augmentedInfo, haurlInfo);
} else {
// If empty HA group is returned, fall back to single cluster.
- url = HighAvailabilityGroup.getFallbackCluster(url, info).orElseThrow(
+ url = HighAvailabilityGroup.getFallbackCluster(url, info,
haurlInfo).orElseThrow(
() -> new SQLException("HA group can not be initialized, fallback to
single cluster"));
}
}
diff --git
a/phoenix-core/src/it/java/org/apache/phoenix/jdbc/FailoverPhoenixConnectionIT.java
b/phoenix-core/src/it/java/org/apache/phoenix/jdbc/FailoverPhoenixConnectionIT.java
index f74b91a57e..bc86689077 100644
---
a/phoenix-core/src/it/java/org/apache/phoenix/jdbc/FailoverPhoenixConnectionIT.java
+++
b/phoenix-core/src/it/java/org/apache/phoenix/jdbc/FailoverPhoenixConnectionIT.java
@@ -62,6 +62,7 @@ import org.apache.phoenix.jdbc.ClusterRoleRecord.ClusterRole;
import org.apache.phoenix.monitoring.MetricType;
import org.apache.phoenix.query.ConnectionQueryServices;
import org.apache.phoenix.query.ConnectionQueryServicesImpl;
+import org.apache.phoenix.schema.TypeMismatchException;
import org.apache.phoenix.util.PhoenixRuntime;
import org.junit.After;
import org.junit.AfterClass;
@@ -579,7 +580,7 @@ public class FailoverPhoenixConnectionIT extends HABaseIT {
tableName = tableName + "Tenant";
CLUSTERS.createTenantSpecificTable(haGroup, tableName);
- clientProperties.setProperty("TenantId", "mytenant");
+ clientProperties.setProperty(PhoenixRuntime.TENANT_ID_ATTRIB, "mytenant");
Connection tenantConn = createFailoverConnection();
doTestBasicOperationsWithConnection(tenantConn, tableName, haGroupName);
@@ -593,6 +594,24 @@ public class FailoverPhoenixConnectionIT extends HABaseIT {
try (Connection newTenantConn = createFailoverConnection()) {
doTestBasicOperationsWithConnection(newTenantConn, tableName,
haGroupName);
}
+
+ // Test creating new tenant connection with url with tenant id
+ clientProperties.remove(PhoenixRuntime.TENANT_ID_ATTRIB);
+ String jdbcUrl =
+ CLUSTERS.getJdbcHAUrl() + ":" + PhoenixRuntime.TENANT_ID_ATTRIB + "=" +
"mytenant";
+ Connection tenantConn2 = DriverManager.getConnection(jdbcUrl,
clientProperties);
+ doTestBasicOperationsWithConnection(tenantConn2, tableName, haGroupName);
+
+ // Normal Connection should fail
+ Connection conn3 = createFailoverConnection();
+ try {
+ doTestBasicOperationsWithConnection(conn3, tableName, haGroupName);
+ fail(
+ "Should have failed since normal connection should not be able to
connect to tenant specific table");
+ } catch (TypeMismatchException e) {
+ LOG.info("Got expected exception when creating normal connection to
tenant specific table",
+ e);
+ }
}
/**
@@ -809,9 +828,10 @@ public class FailoverPhoenixConnectionIT extends HABaseIT {
}
// For the given ha group of current test the value in URLS set for
current haGroupInfo
- // should be numThreads + 2 as all the connections created with same
principal should have
- // one entry in map and one extra for null principal
- Assert.assertEquals(numThreads + 2,
URLS.get(haGroup.getGroupInfo()).size());
+ // should be numThreads + 3 as all the connections created with same
principal should have
+ // one entry in map and one extra for null principal and one from the
setup() method for
+ // USER_FOO principal
+ Assert.assertEquals(numThreads + 3,
URLS.get(haGroup.getGroupInfo()).size());
}
/**
diff --git
a/phoenix-core/src/it/java/org/apache/phoenix/jdbc/HighAvailabilityTestingUtility.java
b/phoenix-core/src/it/java/org/apache/phoenix/jdbc/HighAvailabilityTestingUtility.java
index cf30d17ca8..4aa509ffdd 100644
---
a/phoenix-core/src/it/java/org/apache/phoenix/jdbc/HighAvailabilityTestingUtility.java
+++
b/phoenix-core/src/it/java/org/apache/phoenix/jdbc/HighAvailabilityTestingUtility.java
@@ -1155,6 +1155,7 @@ public class HighAvailabilityTestingUtility {
}
public static void sleepThreadFor(long sleepTime) {
+ LOG.info("Sleeping thread for {} milliseconds", sleepTime);
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < sleepTime) {
try {
diff --git
a/phoenix-core/src/test/java/org/apache/phoenix/jdbc/HighAvailabilityGroupTest.java
b/phoenix-core/src/test/java/org/apache/phoenix/jdbc/HighAvailabilityGroupTest.java
new file mode 100644
index 0000000000..8f52b5110c
--- /dev/null
+++
b/phoenix-core/src/test/java/org/apache/phoenix/jdbc/HighAvailabilityGroupTest.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.jdbc;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.sql.SQLException;
+import java.util.Properties;
+import org.apache.phoenix.exception.SQLExceptionCode;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class HighAvailabilityGroupTest {
+ private static final Logger LOG =
LoggerFactory.getLogger(FailoverPhoenixConnectionTest.class);
+ String quorum1 = "master1\\\\:60010,master2\\\\:60000,master3\\\\:60010";
+ String quorum2 =
"peer_master1\\\\:60010,peer_master2\\\\:60000,peer_master3\\\\:60010";
+
+ @Test
+ public void testGetUrlInfo() throws Exception {
+ String correctAdditionalParams =
"phoenix.ha.group.name=testGetUrlInfo;key2=value2;key3=value3";
+ String correctAdditionalParams2 =
+ "key1=val1;phoenix.ha.group.name=testGetUrlInfo;key2=value2;key3=value3";
+ String correctAdditionalParams3 =
"key1=val1;key2=val2;phoenix.ha.group.name=testGetUrlInfo";
+ String incorrectAdditionalParams = "key1;key2=val2";
+ String missingAdditionalParams = "key1=value1";
+ String principal = "principal";
+ String urlFormatWithPrincipal = "jdbc:phoenix+rpc:[%s|%s]:%s:%s";
+ String urlFormatWithoutPrincipal = "jdbc:phoenix+rpc:[%s|%s]::%s";
+
+ // Test correct additional params with principal
+ String url =
+ String.format(urlFormatWithPrincipal, quorum1, quorum2, principal,
correctAdditionalParams);
+ getAndAssertUrlInfo(url, correctAdditionalParams, principal);
+
+ // Test correct additional params without principal
+ url = String.format(urlFormatWithoutPrincipal, quorum1, quorum2,
correctAdditionalParams);
+ getAndAssertUrlInfo(url, correctAdditionalParams);
+
+ // Test another set of correct additional params with principal
+ url =
+ String.format(urlFormatWithPrincipal, quorum1, quorum2, principal,
correctAdditionalParams2);
+ getAndAssertUrlInfo(url, correctAdditionalParams2, principal);
+
+ // Test another set of correct additional params without principal
+ url = String.format(urlFormatWithoutPrincipal, quorum1, quorum2,
correctAdditionalParams2);
+ getAndAssertUrlInfo(url, correctAdditionalParams2);
+
+ // Test another set of correct additional params with principal
+ url =
+ String.format(urlFormatWithPrincipal, quorum1, quorum2, principal,
correctAdditionalParams3);
+ getAndAssertUrlInfo(url, correctAdditionalParams3, principal);
+
+ // Test another set of correct additional params without principal
+ url = String.format(urlFormatWithoutPrincipal, quorum1, quorum2,
correctAdditionalParams3);
+ getAndAssertUrlInfo(url, correctAdditionalParams3);
+
+ // Test incorrect additional params
+ url =
+ String.format(urlFormatWithPrincipal, quorum1, quorum2, principal,
incorrectAdditionalParams);
+ try {
+ getAndAssertUrlInfo(url, incorrectAdditionalParams, principal);
+ } catch (SQLException e) {
+ assertEquals(e.getErrorCode(),
SQLExceptionCode.MALFORMED_CONNECTION_URL.getErrorCode());
+ }
+
+ // Test incorrect additional params without principal
+ url = String.format(urlFormatWithoutPrincipal, quorum1, quorum2,
incorrectAdditionalParams);
+ try {
+ getAndAssertUrlInfo(url, incorrectAdditionalParams);
+ } catch (SQLException e) {
+ assertEquals(e.getErrorCode(),
SQLExceptionCode.MALFORMED_CONNECTION_URL.getErrorCode());
+ }
+
+ // Test missing additional params
+ url =
+ String.format(urlFormatWithPrincipal, quorum1, quorum2, principal,
missingAdditionalParams);
+ try {
+ getAndAssertUrlInfo(url, missingAdditionalParams, principal);
+ } catch (SQLException e) {
+ assertEquals(e.getErrorCode(),
SQLExceptionCode.HA_INVALID_PROPERTIES.getErrorCode());
+ }
+
+ // Test missing additional params without principal
+ url = String.format(urlFormatWithoutPrincipal, quorum1, quorum2,
missingAdditionalParams);
+ try {
+ getAndAssertUrlInfo(url, missingAdditionalParams);
+ } catch (SQLException e) {
+ assertEquals(e.getErrorCode(),
SQLExceptionCode.HA_INVALID_PROPERTIES.getErrorCode());
+ }
+
+ }
+
+ private void getAndAssertUrlInfo(String url, String additionalParams, String
principal)
+ throws Exception {
+ Properties properties = new Properties();
+ HAURLInfo haurlInfo = HighAvailabilityGroup.getUrlInfo(url, properties);
+ assertEquals(haurlInfo.getName(), "testGetUrlInfo");
+ if (principal != null) {
+ assertEquals(haurlInfo.getPrincipal(), principal);
+ } else {
+ assertNull(haurlInfo.getPrincipal());
+ }
+ assertEquals(haurlInfo.getAdditionalJDBCParams(), additionalParams);
+ }
+
+ private void getAndAssertUrlInfo(String url, String additionalParams) throws
Exception {
+ getAndAssertUrlInfo(url, additionalParams, null);
+ }
+}