docs: @Override
    public void switchReadOnlyConnection(Boolean mustBeReadOnly) throws SQLException {
      checkWaitingConnection();
      if (currentReadOnlyAsked != mustBeReadOnly) {
        proxy.lock.lock();
        try {
          // another thread updated state
          if (currentReadOnlyAsked == mustBeReadOnly) {
            return;
          }
          currentReadOnlyAsked = mustBeReadOnly;
          if (currentReadOnlyAsked) {
            if (currentProtocol == null) {
              //switching to secondary connection
              currentProtocol = this.secondaryProtocol;
            } else if (currentProtocol.isMasterConnection()) {
              //must change to replica connection
              if (!isSecondaryHostFail()) {
                try {
                  //switching to secondary connection
                  syncConnection(this.masterProtocol, this.secondaryProtocol);
                  currentProtocol = this.secondaryProtocol;
                  //current connection is now secondary
                  return;
                } catch (SQLException e) {
                  //switching to secondary connection failed
                  if (setSecondaryHostFail()) {
                    addToBlacklist(secondaryProtocol.getHostAddress());
                  }
                }
              }
              //stay on master connection, since slave connection is fail
              FailoverLoop.addListener(this);
            }
          } else {
            if (currentProtocol == null) {
              //switching to master connection
              currentProtocol = this.masterProtocol;
            } else if (!currentProtocol.isMasterConnection()) {
              //must change to master connection
              if (!isMasterHostFail()) {
                try {
                  //switching to master connection
                  syncConnection(this.secondaryProtocol, this.masterProtocol);
                  currentProtocol = this.masterProtocol;
                  //current connection is now master
                  return;
                } catch (SQLException e) {
                  //switching to master connection failed
                  if (setMasterHostFail()) {
                    addToBlacklist(masterProtocol.getHostAddress());
                  }
                }
              } else if (urlParser.getOptions().allowMasterDownConnection) {
                currentProtocol = null;
                return;
              }
  
              try {
                reconnectFailedConnection(new SearchFilter(true, false));
                handleFailLoop();
  
              } catch (SQLException e) {
                //stop failover, since we will throw a connection exception that will close the connection.
                FailoverLoop.removeListener(this);
                HostAddress failHost =
                    (this.masterProtocol != null) ? this.masterProtocol.getHostAddress() : null;
                throwFailoverMessage(failHost, true, new SQLException("master connection failed"),
                    false);
              }
  
              if (!isMasterHostFail()) {
                //connection established, no need to send Exception !
                //switching to master connection
                try {
                  syncConnection(this.secondaryProtocol, this.masterProtocol);
                  currentProtocol = this.masterProtocol;
                } catch (SQLException e) {
                  //switching to master connection failed
                  if (setMasterHostFail()) {
                    addToBlacklist(masterProtocol.getHostAddress());
                  }
                }
              } else {
                currentReadOnlyAsked = !mustBeReadOnly;
                HostAddress failHost =
                    (this.masterProtocol != null) ? this.masterProtocol.getHostAddress() : null;
                throwFailoverMessage(failHost, true, new SQLException("master connection failed"),
                    false);
              }
  
            }
          }
        } finally {
          proxy.lock.unlock();
        }
      }
    }