Bug #19993 ReplicationDriver always connects to a same slave server.

Submitted: 22 May 2006 8:35 Modified: 26 Jul 2006 18:17
Reporter: 俊夫 大矢 Email Updates:
Status: Closed Impact on me:
None 
Category:Connector / J Severity:S2 (Serious)
Version:3.1.12 OS:Any(Java)
Assigned to: CPU Architecture:Any

[22 May 2006 8:35] 俊夫 大矢
Description:
Using the ReplicationDriver in Connector/J 3.1.12, it seems to send sqlqueries to a same slave server for setReadOnly(true).

Referring to the MYSQL 5.0 reference Manual: "23.3.3.6. UsingMaster/Slave Replication with ReplicationConnection", we tested this feature.  Using jdbc:mysql://master,slave1,slave2,slave3/db" with options "autoReconnect = true" and "roundRobinLoadBalance = true", this driver sent all read-only queries to ONLY slave2.

How to repeat:
Sample code:

// JDBC URL:
// Master: localhost:3306
// Slave1: localhost:3307
// Slave2: localhost:3307
// Slave3: localhost:3307
String jdbcUrl = "jdbc:mysql://localhost:3306,"
		+ "localhost:3307,localhost:3308,localhost:3309/db";
// Properties:
Properties props = new Properties();
props.put("roundRobinLoadBalance", "true");
props.put("autoReconnect", "true");
// other options...

for (int i = 0; i < 4; i ++)
    try {
        Connection conn = new ReplicationDriver().connect(jdbcUrl, props);
        conn.setReadOnly(false);
        ResultSet rs = conn.createStatement().executeQuery(
             "SHOW VARIABLES LIKE "PORT");
        if (rs.next())
           System.out.println("Connection[" + i + "]: " + rs.getString(2));
        conn.close();
    } catch (Exception e) (
        e.printStackTrace();
    }

Result:

Connection[0]: 3308
Connection[1]: 3308
Connection[2]: 3308
Connection[3]: 3308

Suggested fix:
I've looked into the Connector/J source code with a debugger, and found the following points.

ReplicationConnection has two - master and slave connections for queries.  These connections are created with a same jdbc url - "jdbc:mysql:///".  This url is used for a key of "roundRobinStateMap" HashMap in com.mysql.jdbc.Connection#getNextRoundRobinHostIndex().
This HashMap keeps indexes for selecting a next host from its connection's hostlist.

Because a master connection has only one host in its hostlist, "roundRobinStateMap" is always set "0" for "jdbc:mysql:///". And then, a slave connection gets always "1" from "roundRobinStateMap".

I think ReplicationConnection should set different jdbc urls for these two connections.  For example, one is "jdbc:mysql://master/db", the other is "jdbc:mysq://slave1,salve2,slave3/db".

Sample fix:
   public ReplicationConnection(Properties masterProperties,
            Properties slaveProperties) throws SQLException {
        Driver driver = new Driver();

        // Create JDBC URLs for Master Connection and Slave Connection.
        StringBuffer masterUrl = new StringBuffer("jdbc:mysql://");
        StringBuffer slaveUrl = new StringBuffer("jdbc:mysql://");

        masterUrl.append((String)masterProperties
             .getProperty(NonRegisteringDriver.HOST_PROPERTY_KEY));
        slaveUrl.append((String)slaveProperties
             .getProperty(NonRegisteringDriver.HOST_PROPERTY_KEY));
        
        masterUrl.append("/").append((String)masterProperties
                     .getProperty(NonRegisteringDriver.DBNAME_PROPERTY_KEY));
        slaveUrl.append("/").append((String)slaveProperties
                     .getProperty(NonRegisteringDriver.DBNAME_PROPERTY_KEY));
        
        this.masterConnection = (com.mysql.jdbc.Connection) driver.connect(
                masterUrl.toString(), masterProperties);
        this.slavesConnection = (com.mysql.jdbc.Connection) driver.connect(
                slaveUrl.toString(), slaveProperties);
        this.currentConnection = this.masterConnection;
    }
[3 Jul 2006 7:45] Sveta Smirnova
Thank you for the report.

Verified as reporter described using Connector/J 3.1.13. You can turn off last 2 slaves to be convinced what connection to first slave happens never.
[7 Jul 2006 4:50] 俊夫 大矢
Thank you for verifing this bug.

I want to realize below behavior with MySQL Connector/J.
--------
1. Setting
URL: jdbc:mysql://master,slave1,slave2,slave3/db
Driver: com.mysql.jdbc.ReplicationDriver
Props: roundRobinLoadBalance=true, autoReconnect=true

2. Expect Behavior
First ReadOnly connection:  connecting to 'slave1'.
Second ReadOnly conncetion: connecting to 'slave2'.
Third ReadOnly connection: connecting to 'slave3'.
Forth ReadOnly connection: connecting to 'slave1'.
...
------------

This behavior is explained in MySQL Ref. Manual-'23.3.3.6. Using Master/Slave Replication with ReplicationConnection'.

If that manual is correct, this bug should be fixed.
If not, the manual should be fixed.

Do you have any plan for this bug?
[19 Jul 2006 2:18] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/9316

Portions of this website are copyright © 2001, 2002 The PHP Group

Page generated in 0.052 sec. using MySQL 8.4.7-u6-cloud

Timestamp references displayed by the system are UTC.
Content reproduced on this site is the property of the respective copyright holders.
It is not reviewed in advance by Oracle and does not necessarily represent the opinion of Oracle or any other party.