Skip to content

6. Using Failover#

This chapter describes how to perform Failover-related tasks using the Altibase C interface.

Overview#

The failover features is provided so that a fault that occurs while a database is providing service can continue to be provided as though no fault had occurred. For example, failover is the capability to switch over automatically to a standby server upon abnormal termination of the previously active server where you execute queries. This feature allows you to retry task which you wanted to do before abnormal termination without establishing a connection again in application. For more detailed information, refer to Replication Manual.

How to Use Failover#

This section describes the data structures provided for writing Failover-related tasks in the application and how to use them.

To support writing Failover-related tasks in the application, Altibase provides the following Failover event values and function pointers for callback functions.

enum ALTIBASE_FAILOVER_EVENT#

An enumeration that contains a Failover event.

If the user has registered a Failover callback function, it will receive one of the following event values through the event argument of the registered function.

The user can also use this value when returning to the client library whether the Failover callback function should continue with the next step of the Failover.

Enumerated Value Description
ALTIBASE_FO_BEGIN Indicates that failover has detected a lost connection and that failover is starting.
ALTIBASE_FO_END Indicates successful completion of failover.
ALTIBASE_FO_ABORT Indicates thata failover was unsuccessful, and there is no option of retrying.
ALTIBASE_FO_GO FailOverCallback sends this so that STF (Service Time Failover) can advance to the next step.
ALTIBASE_FO_QUIT FailOverCallback sends this to prevent STF from advancing to the next step.

Callback Function Pointer (altibase_failover_callback_func)#

The following is a function pointer provided by Altibase for creating a Failover callback function.

typedef ALTIBASE_FAILOVER_EVENT (*altibase_failover_callback_func)
(
    ALTIBASE                     altibase,
    void                         *app_context,
    ALTIBASE_FAILOVER_EVENT      event
);

app_context argument is used to receive data for failover callback function. If the user passes a pointer of data type used for registering callback to the function, the result is returned by app_context argument for callback function.

The event argument notifies the callback function which callback event occurred. For more information about events, refer to "enum ALTIBASE_FAILOVER_EVENT".

How to register a Failover Callback#

This section describes how to register a callback function to be used when a failover occurs and a pointer to the data to be referred to by the callback function. The user must register the callback function after successfully connecting to the server.

The following is an example of source code for registering a callback function.

#define CONNSTR "DSN=127.0.0.1;PORT_NO=20300;UID=sys;PWD=manager;" \
                "AlternateServers=(192.168.3.54:20300,192.168.3.53:20300);" \
                "ConnectionRetryCount=3;ConnectionRetryDelay=5;" \
                "LoadBalance=on;SessionFailOver=on;"

/* ... omit ... */

if ((altibase = altibase_init()) == NULL)
{
    /* ... error handling ... */
}

rc = altibase_connect(altibase, CONNSTR);
/* ... check return value ... */

rc = altibase_set_failover_callback(altibase, my_callback_func, &my_context);
/* ... check return value ... */

/* ... omit ... */

rc = altibase_set_failover_callback(altibase, NULL, NULL);
/* ... check return value ... */

Failover sets up a connection rather than a statement, so the connection handle is used to register the callback function. The failover operation also affects all statements belonging to that connection handle. If the user wants to apply failover to only one statement, the user must create a separate connection handle that belongs only to that statement.

Task upon a Failover#

This refers to restoring prepare and bind operations perviously performed by the user when a failover occurs.

To achieve a successful failover due to an error in the database session where database was executing a command, database can implement logic that chathces the errors during failover, and then retry and failed work. If there were no errors, database returns ALTIBASE_FAILOVER_SUCCESS. If database fails to achieve a failover or cannot complete the work even after a failover, database also retruns an error code depending on this case. While you use altibase_stmt_execute() or altibase_stmt_fetch(), an error message can be returned by the failure of work such as preparing a SQL statement or binding data. At this time, you must check if how you set the failover and server works normally because database can achieve a successful failover but fails to complete its actual work.

Example#

The following is an example of source code related to Failover operation.

Upon a failover due to an error in the database session where database was executing a prepared statement, database can immediately re-execute the work that was attempted but not completed because database automatically prepares a SQL statement and binds data again.

rc = altibase_stmt_prepare(stmt, qstr);
/* ... check return value ... */

/* ... omit ... */

:retry

rc = altibase_stmt_execute(stmt);
if (ALTIBASE_NOT_SUCCEEDED(rc))
{
    if (altibase_stmt_errno(stmt) == ALTIBASE_FAILOVER_SUCCESS)
    {
        /* Database re-executes a statement because it is automatically prepared.  */
        goto retry;
    }
    else
    {
        /* ... error handling ... */
    }
}

/* altibase_stmt_store_result() is optional */
rc = altibase_stmt_store_result(stmt);
if (ALTIBASE_NOT_SUCCEEDED(rc))
{
    if (altibase_stmt_errno(stmt) == ALTIBASE_FAILOVER_SUCCESS)
    {
        /* Database re-executes a statement because it is automatically prepared. */
        goto retry;
    }
    else
    {
        /* ... error handling ... */
    }
}

while (1)
{
    rc = altibase_stmt_fetch(stmt)
    if (ALTIBASE_NOT_SUCCEEDED(rc))
    {
        if (altibase_stmt_errno(stmt) == ALTIBASE_FAILOVER_SUCCESS)
        {
            /*  re-execute. */
            goto retry;
        }
        else
        {
            /* ... error handling ... */
            break;
        }
    }

    /* TODO something */
}