8 Labeling connections

This chapter provides information on how to label connections to increase performance:

What is Connection Labeling?

Applications often initialize connections retrieved from a connection pool before using the connection. The initialization varies and could include simple state re-initialization that requires method calls within the application code or database operations that require round trips over the network. The cost of such initialization may be significant.

Labeling connections allows an application to attach arbitrary name/value pairs to a connection. The application can request a connection with the desired label from the connection pool. By associating particular labels with particular connection states, an application can retrieve an already initialized connection from the pool and avoid the time and cost of re-initialization. The connection labeling feature does not impose any meaning on user-defined keys or values; the meaning of user-defined keys and values is defined solely by the application.

Some of the examples for connection labeling include role, NLS language settings, transaction isolation levels, stored procedure calls, or any other state initialization that is expensive and necessary on the connection before work can be executed by the resource.

Connection labeling is application-driven and requires the following:

Implementing Labeling Callbacks

A labeling callback is used to define how the connection pool selects labeled connections and allows the selected connection to be configured before returning it to an application. Applications that use the connection labeling feature must provide a callback implementation.

A labeling callback is used when a labeled connection is requested but there are no connections in the pool that match the requested labels. The callback determines which connection requires the least amount of work in order to be re-configured to match the requested label and then allows the connection's labels to be updated before returning the connection to the application.

Note:

Connection Labeling is not supported from client applications that use RMI. See "Using the WebLogic RMI Driver (Deprecated)" in Developing JDBC Applications for Oracle WebLogic Server.

Creating a Labeling Callback

To create a labeling callback, an application implements the oracle.ucp.ConnectionLabelingCallback interface. One callback is created per connection pool. The interface provides two methods as shown below:

public int cost(Properties requestedLabels, Properties currentLabels);

public boolean configure(Properties requestedLabels, Connection conn);

The connection pool iterates over each connection available in the pool. For each connection, it calls the cost method. The result of the cost method is an integer which represents an estimate of the cost required to reconfigure the connection to the required state. The larger the value, the costlier it is to reconfigure the connection. The connection pool always returns connections with the lowest cost value. The algorithm is as follows:

  • If the cost method returns 0 for a connection, the connection is a match (note that this does not guarantee that requestedLabels equals currentLabels). The connection pool does not call configure on the connection found and simply returns the connection.

  • If the cost method returns a value that is not 0 (a negative or positive integer), then the connection pool iterates until it finds a connection with a cost value of 0 or runs out of available connections.

  • If the pool has iterated through all available connections and the lowest cost of a connection is Integer.MAX_VALUE (2147483647 by default), then no connection in the pool is able to satisfy the connection request. The pool creates a new connection, calls the configure method on it, and then returns this new connection. If the pool has reached the maximum pool size (it cannot create a new connection), then the pool either throws an SQL exception or waits if the connection wait timeout attribute is specified.

  • If the pool has iterated through all available connections and the lowest cost of a connection is less than Integer.MAX_VALUE, then the configure method is called on the connection and the connection is returned. If multiple connections are less than Integer.MAX_VALUE, the connection with the lowest cost is returned.

There is also an extended callback interface oracle.ucp.jdbc.ConnectionLabelingCallback that has an additional getRequestedLabels() method. getRequestedLabels is invoked at getConnection() time when no requested labels are provided and there is an instance registered. This occurs when the standard java.sql.Datasource getConnection() methods are used that do not provide the label information on the getConnection() call.

Example Labeling Callback

The following code example demonstrates a simple labeling callback implementation that implements both the cost and configure methods. The callback is used to find a labeled connection that is initialized with a specific transaction isolation level.

Example 8-1 Labeling Callback

import oracle.ucp.jdbc.ConnectionLabelingCallback;  
import oracle.ucp.jdbc.LabelableConnection; 
import java.util.Properties; 
import java.util.Map; 
import java.util.Set;
import weblogic.jdbc.extensions.WLDataSource;
class MyConnectionLabelingCallback implements ConnectionLabelingCallback {
 
  public MyConnectionLabelingCallback()  { 
  }
  public int cost(Properties reqLabels, Properties currentLabels)  { 
    // Case 1: exact match 
    if (reqLabels.equals(currentLabels)) { 
      System.out.println("## Exact match found!! ##"); 
      return 0; 
    }
 
   // Case 2: some labels match with no unmatched labels 
    String iso1 = (String) reqLabels.get("TRANSACTION_ISOLATION");
    String iso2 = (String) currentLabels.get("TRANSACTION_ISOLATION"); 
    boolean match = 
      (iso1 != null && iso2 != null && iso1.equalsIgnoreCase(iso2)); 
    Set rKeys = reqLabels.keySet(); 
    Set cKeys = currentLabels.keySet(); 
    if (match && rKeys.containsAll(cKeys)) { 
      System.out.println("## Partial match found!! ##"); 
      return 10;
 
    } 
    // No label matches to application's preference. 
    // Do not choose this connection. 
    System.out.println("## No match found!! ##"); 
    return Integer.MAX_VALUE; 
  }
 
 public boolean configure(Properties reqLabels, Object conn)  { 
    try { 
      String isoStr = (String) reqLabels.get("TRANSACTION_ISOLATION"); 
      ((Connection)conn).setTransactionIsolation(Integer.valueOf(isoStr)); 
      LabelableConnection lconn = (LabelableConnection) conn;
 
     // Find the unmatched labels on this connection 
      Properties unmatchedLabels = 
           lconn.getUnmatchedConnectionLabels(reqLabels); 
      // Apply each label <key,value> in unmatchedLabels to conn
 
     for (Map.Entry<Object, Object> label : unmatchedLabels.entrySet())  { 
        String key = (String) label.getKey(); 
        String value = (String) label.getValue();
 
        lconn.applyConnectionLabel(key, value);
 
      } 
    } catch (Exception exc) { 
      return false; 
    } 
    return true; 
  }
  
public java.util.Properties getRequestedLabels() {
    Properties props = new Properties();
  
 // Set based on some application state that might be on a thread-local, http session info, etc.
    String value = "value"; 
 
  
  props.put("TRANSACTION_ISOLATION", value);
  
  return props;
  } 
}

Registering a Labeling Callback

A WLS data source provides the registerConnectionLabelingCallback(ConnectionLabelingCallback callback) method for registering labeling callbacks. Only one callback may be registered on a connection pool. The following code example demonstrates registering a labeling callback that is implemented in the MyConnectionLabelingCallback class:

. . .
import weblogic.jdbc.extensions.WLDataSource;
. . . 
MyConnectionLabelingCallback callback = new MyConnectionLabelingCallback(); 
((WLDataSource)ds).registerConnectionLabelingCallback( callback );
. . .

You can also register the callback using the Administration Console, see "Configure a connection labeling callback class" in Oracle WebLogic Server Administration Console Online Help.

Removing a Labeling Callback

You can remove a labeling callback by using one of the following methods:

  • If you have programmatically set a callback, use the removeConnectionLabelingCallback() method as shown in the following example:

    . . .
    import weblogic.jdbc.extensions.WLDataSource; 
    . . .
    ((WLDataSource)ds).removeConnectionLabelingCallback( callback );
    . . .
    
  • If you have administratively configured the callback, remove the callback from the data source configuration. See "Configure a connection labeling callback class" in Oracle WebLogic Server Administration Console Online Help

Note:

An application must use one of the methods to register and remove callbacks but not both. For example, if you register the callback on a connection using registerConnectionLabelingCallback(callback), you must use removeConnectionLabelingCallback() to remove it.

Applying Connection Labels

Labels are applied on a reserved connection using the applyConnectionLabel method from the LabelableConnection interface. Any number of connection labels may be cumulatively applied on a reserved connection. Each time a label is applied to a connection, the supplied key/value pair is added to the existing collection of labels. Only the last applied value is retained for any given key.

Note:

A labeling callback must be registered on the connection pool before a label can be applied on a reserved connection; otherwise, labeling is ignored. See Chapter 8, "Creating a Labeling Callback."

The following example demonstrates initializing a connection with a transaction isolation level and then applying a label to the connection:

. . .
String pname = "property1"; 
String pvalue = "value"; 
Connection conn = ds.getConnection(); 
// initialize the connection as required. 
conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE); 
((LabelableConnection) conn).applyConnectionLabel(pname, pvalue);
. . .

Reserving Labeled Connections

A WLS data source provides two getConnection methods that are used to reserve a labeled connection from the pool. The methods are shown below:

public Connection getConnection(java.util.Properties labels) throws SQLException;

public Connection getConnection(String user, String password, java.util.Properties labels) throws SQLException;

The methods require that the label be passed to the getConnection method as a Properties object. The following example demonstrates getting a connection with the label property1 value.

. . .
import weblogic.jdbc.extensions.WLDataSource;
. . . 
String pname = "property1"; 
String pvalue = "value"; 
Properties label = new Properties(); 
label.setProperty(pname, pvalue);
. . . 
Connection conn = ((WLDataSource)ds).getConnection(label);
. . .

It is also possible to use the standard java.sql.Datasource getConnection() methods. In this case, the label information is not provided on the getConnection() call. The interface oracle.ucp.jdbc.ConnectionLabelingCallback is used:

java.util.Properties getRequestedLabels();

getRequestedLabels is invoked at getConnection() time when no requested labels are provided and there is an instance registered.

Checking Unmatched labels

A connection may have multiple labels that each uniquely identifies the connection based on some desired criteria. The getUnmatchedConnectionLabels method is used to verify which connection labels matched from the requested labels and which did not. The method is used after a connection with multiple labels is reserved from the connection pool and is typically used by a labeling callback. The following code example demonstrates checking for unmatched labels:

. . .
String pname = "property1"; 
String pvalue = "value"; 
Properties label = new Properties(); 
label.setProperty(pname, pvalue);
. . . 
Connecion conn = ((WLDataSource)ds).getConnection(label); 
Properties unmatched =  
   ((LabelableConnection)connection).getUnmatchedConnectionLabels (label); 
. . .

Removing a Connection Label

The removeConnectionLabel method is used to remove a label from a connection. This method is used after a labeled connection is reserved from the connection pool. The following code example demonstrates removing a connection label:

. . .
String pname = "property1"; 
String pvalue = "value"; 
Properties label = new Properties(); 
label.setProperty(pname, pvalue); 
Connection conn = ((WLDataSource)ds).getConnection(label);
. . . 
((LabelableConnection) conn).removeConnectionLabel(pname);
. . .