This is an automated email from the ASF dual-hosted git repository.

DaanHoogland pushed a commit to branch ghi14172-lodBalancedDb
in repository https://gitbox.apache.org/repos/asf/cloudstack.git

commit 86dc7a4e7eca4c6f75b9663a7cc34f980da40718
Author: Daan Hoogland <[email protected]>
AuthorDate: Thu Oct 1 10:43:56 2026 +0200

    allow loadbalanced DB
---
 client/conf/db.properties.in                       | 20 ++++++++------
 .../java/com/cloud/utils/db/TransactionLegacy.java | 25 ++++++++---------
 .../com/cloud/utils/db/TransactionLegacyTest.java  | 31 +++++++++++-----------
 3 files changed, 40 insertions(+), 36 deletions(-)

diff --git a/client/conf/db.properties.in b/client/conf/db.properties.in
index 0f7d2706a42..4bf226b37d7 100644
--- a/client/conf/db.properties.in
+++ b/client/conf/db.properties.in
@@ -104,24 +104,28 @@ db.simulator.uri=
 
 
 # High Availability And Cluster Properties
+# When enabled, connections use MySQL Connector/J's load-balancing driver 
(jdbc:mysql:loadbalance)
+# with the first host in the list (db.<schema>.host) always preferred over the 
replicas, via
+# db.ha.loadBalanceStrategy. connectTimeout/socketTimeout bound how long a new 
connection can hang
+# against an unreachable host; loadBalanceBlocklistTimeout is how long a host 
that just failed is
+# skipped before being retried. This only fails read/write traffic over to a 
replica connection-wise:
+# promoting a replica to a writable primary after a real source outage is 
still a manual DBA step.
 db.ha.enabled=false
 db.ha.loadBalanceStrategy=com.cloud.utils.db.StaticStrategy
 # cloud stack Database
 db.cloud.replicas=localhost,localhost
 db.cloud.autoReconnect=true
-db.cloud.failOverReadOnly=false
 db.cloud.reconnectAtTxEnd=true
 db.cloud.autoReconnectForPools=true
-db.cloud.secondsBeforeRetrySource=3600
-db.cloud.queriesBeforeRetrySource=5000
-db.cloud.initialTimeout=3600
+db.cloud.connectTimeout=3000
+db.cloud.socketTimeout=30000
+db.cloud.loadBalanceBlocklistTimeout=30000
 
 #usage Database
 db.usage.replicas=localhost,localhost
 db.usage.autoReconnect=true
-db.usage.failOverReadOnly=false
 db.usage.reconnectAtTxEnd=true
 db.usage.autoReconnectForPools=true
-db.usage.secondsBeforeRetrySource=3600
-db.usage.queriesBeforeRetrySource=5000
-db.usage.initialTimeout=3600
+db.usage.connectTimeout=3000
+db.usage.socketTimeout=30000
+db.usage.loadBalanceBlocklistTimeout=30000
diff --git 
a/framework/db/src/main/java/com/cloud/utils/db/TransactionLegacy.java 
b/framework/db/src/main/java/com/cloud/utils/db/TransactionLegacy.java
index 18a90749e49..f27995a98e7 100644
--- a/framework/db/src/main/java/com/cloud/utils/db/TransactionLegacy.java
+++ b/framework/db/src/main/java/com/cloud/utils/db/TransactionLegacy.java
@@ -1191,8 +1191,8 @@ public class TransactionLegacy implements Closeable {
             connectionUri = getPropertiesAndBuildConnectionUri(dbProps, 
loadBalanceStrategy, driver, useSSL, schema);
         } else {
             LOGGER.warn(String.format("db.%s.uri was set, ignoring the 
following properties for schema %s of db.properties: [host, port, name, driver, 
autoReconnect, url.params,"
-                    + " replicas, ha.loadBalanceStrategy, ha.enable, 
failOverReadOnly, reconnectAtTxEnd, autoReconnectForPools, 
secondsBeforeRetrySource, queriesBeforeRetrySource, "
-                    + "initialTimeout].", schema, schema));
+                    + " replicas, ha.loadBalanceStrategy, ha.enable, 
reconnectAtTxEnd, autoReconnectForPools, connectTimeout, socketTimeout, "
+                    + "loadBalanceBlocklistTimeout].", schema, schema));
 
             String[] splitUri = propertyUri.split(":");
             driver = String.format("%s:%s", splitUri[0], splitUri[1]);
@@ -1213,19 +1213,22 @@ public class TransactionLegacy implements Closeable {
         String replicas = null;
         String dbHaParams = null;
         if (s_dbHAEnabled) {
-            dbHaParams = getDBHAParams(schema, dbProps);
+            dbHaParams = getDBHAParams(schema, dbProps, loadBalanceStrategy);
             replicas = dbProps.getProperty(String.format("db.%s.replicas", 
schema));
             LOGGER.info(String.format("The replicas configured for %s data 
base are %s.", schema, replicas));
         }
 
-        return buildConnectionUri(loadBalanceStrategy, driver, useSSL, host, 
replicas, port, dbName, autoReconnect, urlParams, dbHaParams);
+        return buildConnectionUri(driver, useSSL, host, replicas, port, 
dbName, autoReconnect, urlParams, dbHaParams);
     }
 
-    protected static String buildConnectionUri(String loadBalanceStrategy, 
String driver, boolean useSSL, String host, String replicas, int port, String 
dbName, boolean autoReconnect,
+    protected static String buildConnectionUri(String driver, boolean useSSL, 
String host, String replicas, int port, String dbName, boolean autoReconnect,
             String urlParams, String dbHaParams) {
 
         StringBuilder connectionUri = new StringBuilder();
         connectionUri.append(driver);
+        if (s_dbHAEnabled) {
+            connectionUri.append(":loadbalance");
+        }
         connectionUri.append("://");
         connectionUri.append(host);
 
@@ -1253,8 +1256,6 @@ public class TransactionLegacy implements Closeable {
         if (s_dbHAEnabled) {
             connectionUri.append("&");
             connectionUri.append(dbHaParams);
-            connectionUri.append("&loadBalanceStrategy=");
-            connectionUri.append(loadBalanceStrategy);
         }
 
         connectionUri.append("&");
@@ -1409,14 +1410,14 @@ public class TransactionLegacy implements Closeable {
         return new PoolingDataSource(connectionPool);
     }
 
-    private static String getDBHAParams(String dbName, Properties dbProps) {
+    private static String getDBHAParams(String dbName, Properties dbProps, 
String loadBalanceStrategy) {
         StringBuilder sb = new StringBuilder();
-        sb.append("failOverReadOnly=" + dbProps.getProperty("db." + dbName + 
".failOverReadOnly"));
+        sb.append("ha.loadBalanceStrategy=").append(loadBalanceStrategy);
         sb.append("&").append("reconnectAtTxEnd=" + dbProps.getProperty("db." 
+ dbName + ".reconnectAtTxEnd"));
         sb.append("&").append("autoReconnectForPools=" + 
dbProps.getProperty("db." + dbName + ".autoReconnectForPools"));
-        sb.append("&").append("secondsBeforeRetrySource=" + 
dbProps.getProperty("db." + dbName + ".secondsBeforeRetrySource"));
-        sb.append("&").append("queriesBeforeRetrySource=" + 
dbProps.getProperty("db." + dbName + ".queriesBeforeRetrySource"));
-        sb.append("&").append("initialTimeout=" + dbProps.getProperty("db." + 
dbName + ".initialTimeout"));
+        sb.append("&").append("connectTimeout=" + dbProps.getProperty("db." + 
dbName + ".connectTimeout"));
+        sb.append("&").append("socketTimeout=" + dbProps.getProperty("db." + 
dbName + ".socketTimeout"));
+        sb.append("&").append("loadBalanceBlocklistTimeout=" + 
dbProps.getProperty("db." + dbName + ".loadBalanceBlocklistTimeout"));
         return sb.toString();
     }
 
diff --git 
a/framework/db/src/test/java/com/cloud/utils/db/TransactionLegacyTest.java 
b/framework/db/src/test/java/com/cloud/utils/db/TransactionLegacyTest.java
index 2e0af6fa186..91cec2753d1 100644
--- a/framework/db/src/test/java/com/cloud/utils/db/TransactionLegacyTest.java
+++ b/framework/db/src/test/java/com/cloud/utils/db/TransactionLegacyTest.java
@@ -47,7 +47,7 @@ public class TransactionLegacyTest {
 
         Pair<String, String> result = 
TransactionLegacy.getConnectionUriAndDriver(properties, null, false, "cloud");
 
-        
Assert.assertEquals("driver://host:5555/name?autoReconnect=false&someParams", 
result.first());
+        
Assert.assertEquals("driver://host:5555/name?autoReconnect=false&someParams&scrollTolerantForwardOnly=true",
 result.first());
         Assert.assertEquals("driver", result.second());
     }
 
@@ -65,53 +65,52 @@ public class TransactionLegacyTest {
     public void getPropertiesAndBuildConnectionUriTestDbHaDisabled() {
         String result = 
TransactionLegacy.getPropertiesAndBuildConnectionUri(properties, "strat", 
"driver", true, "cloud");
 
-        
Assert.assertEquals("driver://host:5555/name?autoReconnect=false&someParams&useSSL=true",
 result);
+        
Assert.assertEquals("driver://host:5555/name?autoReconnect=false&someParams&useSSL=true&scrollTolerantForwardOnly=true",
 result);
     }
 
     @Test
     public void getPropertiesAndBuildConnectionUriTestDbHaEnabled() {
         TransactionLegacy.s_dbHAEnabled = true;
-        properties.setProperty("db.cloud.failOverReadOnly", "true");
         properties.setProperty("db.cloud.reconnectAtTxEnd", "false");
         properties.setProperty("db.cloud.autoReconnectForPools", "true");
-        properties.setProperty("db.cloud.secondsBeforeRetrySource", "25");
-        properties.setProperty("db.cloud.queriesBeforeRetrySource", "105");
-        properties.setProperty("db.cloud.initialTimeout", "1000");
+        properties.setProperty("db.cloud.connectTimeout", "3000");
+        properties.setProperty("db.cloud.socketTimeout", "15000");
+        properties.setProperty("db.cloud.loadBalanceBlocklistTimeout", 
"30000");
         properties.setProperty("db.cloud.replicas", "second_host");
 
         String result = 
TransactionLegacy.getPropertiesAndBuildConnectionUri(properties, "strat", 
"driver", true, "cloud");
 
-        
Assert.assertEquals("driver://host,second_host:5555/name?autoReconnect=false&someParams&useSSL=true&failOverReadOnly=true&reconnectAtTxEnd=false&autoReconnectFor"
-                + 
"Pools=true&secondsBeforeRetrySource=25&queriesBeforeRetrySource=105&initialTimeout=1000&loadBalanceStrategy=strat",
 result);
+        
Assert.assertEquals("driver:loadbalance://host,second_host:5555/name?autoReconnect=false&someParams&useSSL=true&ha.loadBalanceStrategy=strat&reconnectAtTxEnd=false&autoReconnectFor"
+                + 
"Pools=true&connectTimeout=3000&socketTimeout=15000&loadBalanceBlocklistTimeout=30000&scrollTolerantForwardOnly=true",
 result);
     }
 
     @Test
     public void buildConnectionUriTestDbHaDisabled() {
-        String result = TransactionLegacy.buildConnectionUri(null, "driver", 
false, "host", null, 5555, "cloud", false, null, null);
+        String result = TransactionLegacy.buildConnectionUri("driver", false, 
"host", null, 5555, "cloud", false, null, null);
 
-        Assert.assertEquals("driver://host:5555/cloud?autoReconnect=false", 
result);
+        
Assert.assertEquals("driver://host:5555/cloud?autoReconnect=false&scrollTolerantForwardOnly=true",
 result);
     }
 
     @Test
     public void buildConnectionUriTestDbHaEnabled() {
         TransactionLegacy.s_dbHAEnabled = true;
 
-        String result = TransactionLegacy.buildConnectionUri("strat", 
"driver", false, "host", "second_host", 5555, "cloud", false, null, 
"dbHaParams");
+        String result = TransactionLegacy.buildConnectionUri("driver", false, 
"host", "second_host", 5555, "cloud", false, null, "dbHaParams");
 
-        
Assert.assertEquals("driver://host,second_host:5555/cloud?autoReconnect=false&dbHaParams&loadBalanceStrategy=strat",
 result);
+        
Assert.assertEquals("driver:loadbalance://host,second_host:5555/cloud?autoReconnect=false&dbHaParams&scrollTolerantForwardOnly=true",
 result);
     }
 
     @Test
     public void buildConnectionUriTestUrlParamsNotNull() {
-        String result = TransactionLegacy.buildConnectionUri(null, "driver", 
false, "host", null, 5555, "cloud", false, "urlParams", null);
+        String result = TransactionLegacy.buildConnectionUri("driver", false, 
"host", null, 5555, "cloud", false, "urlParams", null);
 
-        
Assert.assertEquals("driver://host:5555/cloud?autoReconnect=false&urlParams", 
result);
+        
Assert.assertEquals("driver://host:5555/cloud?autoReconnect=false&urlParams&scrollTolerantForwardOnly=true",
 result);
     }
 
     @Test
     public void buildConnectionUriTestUseSslTrue() {
-        String result = TransactionLegacy.buildConnectionUri(null, "driver", 
true, "host", null, 5555, "cloud", false, null, null);
+        String result = TransactionLegacy.buildConnectionUri("driver", true, 
"host", null, 5555, "cloud", false, null, null);
 
-        
Assert.assertEquals("driver://host:5555/cloud?autoReconnect=false&useSSL=true", 
result);
+        
Assert.assertEquals("driver://host:5555/cloud?autoReconnect=false&useSSL=true&scrollTolerantForwardOnly=true",
 result);
     }
 }

Reply via email to