All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.microsoft.sqlserver.jdbc.FailOverInfo Maven / Gradle / Ivy

/*
 * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made
 * available under the terms of the MIT License. See the LICENSE file in the project root for more information.
 */

package com.microsoft.sqlserver.jdbc;

import java.text.MessageFormat;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;


/**
 * This class keeps the failover server info and if the mirror has become the primary. For synchronizing better and not
 * to keep a lock in the class through a connection open a placeholder class is used to get the failover info in one
 * shot. This class should never directly expose its members.
 */
final class FailoverInfo {
    private String failoverPartner;
    private int portNumber;
    private String failoverInstance;
    private boolean setUpInfocalled;
    private final Lock lock = new ReentrantLock();

    // This member is exposed outside for reading, we need to know in advance if the
    // failover partner is the currently active server before making a DNS resolution and a connect attempt.
    private boolean useFailoverPartner;

    boolean getUseFailoverPartner() {
        return useFailoverPartner;
    }

    FailoverInfo(String failover, boolean actualFailoverPartner) {
        failoverPartner = failover;
        useFailoverPartner = actualFailoverPartner;
        portNumber = -1; // init to -1 to make sure that the user of this class calls the failover check before getting
                         // the port number.
    }

    // the members of this class are not exposed so inorder to log we call this function.
    void log(SQLServerConnection con) {
        if (con.getConnectionLogger().isLoggable(Level.FINE))
            con.getConnectionLogger().fine(con.toString() + " Failover server :" + failoverPartner
                    + " Failover partner is primary : " + useFailoverPartner);
    }

    // this function gets the failover server port and sets up the security manager
    // note calls to these should be synchronized or guaranteed to happen from only one thread.
    private void setupInfo(SQLServerConnection con) throws SQLServerException {
        if (setUpInfocalled)
            return;

        if (0 == failoverPartner.length()) {
            portNumber = SQLServerConnection.DEFAULTPORT;
        } else {
            // 3.3006 get the instance name
            int px = failoverPartner.indexOf('\\');
            String instancePort;
            String instanceValue;

            // found the instance name with the severname
            if (px >= 0) {
                if (con.getConnectionLogger().isLoggable(Level.FINE))
                    con.getConnectionLogger().fine(con.toString() + " Failover server :" + failoverPartner);
                instanceValue = failoverPartner.substring(px + 1, failoverPartner.length());
                failoverPartner = failoverPartner.substring(0, px);
                con.validateMaxSQLLoginName(SQLServerDriverStringProperty.INSTANCE_NAME.toString(), instanceValue);
                failoverInstance = instanceValue;
                instancePort = con.getInstancePort(failoverPartner, instanceValue);

                try {
                    portNumber = Integer.parseInt(instancePort);
                } catch (NumberFormatException e) {
                    // Should not get here as the server should give a proper port number anyway.
                    MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidPortNumber"));
                    Object[] msgArgs = {instancePort};
                    SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, false);
                }
            } else
                portNumber = SQLServerConnection.DEFAULTPORT;
        }
        setUpInfocalled = true;
    }

    ServerPortPlaceHolder failoverPermissionCheck(SQLServerConnection con, boolean link) throws SQLServerException {
        lock.lock();
        try {
            setupInfo(con);
            return new ServerPortPlaceHolder(failoverPartner, portNumber, failoverInstance, link);
        } finally {
            lock.unlock();
        }
    }

    // Add/replace the failover server,
    void failoverAdd(SQLServerConnection connection, boolean actualUseFailoverPartner, String actualFailoverPartner) {
        lock.lock();
        try {
            if (useFailoverPartner != actualUseFailoverPartner) {
                if (connection.getConnectionLogger().isLoggable(Level.FINE))
                    connection.getConnectionLogger()
                            .fine(connection.toString() + " Failover detected. failover partner=" + actualFailoverPartner);
                useFailoverPartner = actualUseFailoverPartner;
            }
            // The checking for actualUseFailoverPartner may look weird but this is required
            // We only change the failoverpartner info when we connect to the primary
            // if we connect to the secondary and it sends a failover partner
            // we wont store that information.
            if (!actualUseFailoverPartner && !failoverPartner.equals(actualFailoverPartner)) {
                failoverPartner = actualFailoverPartner;
                // new FO partner need to setup again.
                setUpInfocalled = false;
            }
        } finally {
            lock.unlock();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy