Virtuoso Data Access Clients Connection Fail over and Load Balancing Support

As of Release 6.1, all Virtuoso Data Access Clients (ODBC, JDBC, ADO.Net, OLE DB, Sesame, Jena, and Redland) enable server failover, load-balanced, and fault-tolerant connections. Full fault tolerance is only delivered against shared-nothing Cluster Edition configurations.

In each case, where the "Host" or "Server" connect string attribute would previously have held a single hostname and port (e.g., demo.openlinksw.com:1111), a comma-delimited list is now specified.

In the most basic fail-over configuration, an attempt is made against each instance in the list, always starting with the first listed, until a successful connection is achieved.

A round-robin, load-balanced connection, where the server targeted by the initial connection attempt is chosen at random from the comma-delimited list as provided for a failover connection, can be configured by adding a new connect string attribute --


RoundRobin = [True | Yes | False | No]

If the listed instances are all member nodes in a Cluster Edition deployment, the connections can become fault-tolerant, but this the client application must be written to take advantage of this functionality.

Example connect strings for Virtuoso ODBC, JDBC, ADO.Net and OLE DB drivers/providers are provided below. The Sesame and Jena providers make use of the JDBC driver, and the Redland Provider makes use of the ODBC driver, so these do not require their own special connect strings.

ODBC driver

Failover Connect String format


Driver={OpenLink Virtuoso};Host=server1:port1,server2:port2,server3:port3;UID=dba;PWD=dba;

Round Robin Connect String format


Driver={OpenLink Virtuoso};Host=server1:port1,server2:port2,server3:port3;UID=dba;PWD=dba;RoundRobin=Yes"

Or alternatively ensure the "use Round Robin for failover connection" check box in the setup dialog.


JDBC Driver

Failover Connect String format


jdbc:virtuoso://server1:port1,server2:port2,server3:port3/UID=dba/PWD=dba/;

Round Robin Connect String format


 jdbc:virtuoso://server1:port1,server2:port2,server3:port3/UID=dba/PWD=dba/ROUNDROBIN=yes;

OLE DB Provider

Failover Connect String format


Provider=VIRTOLEDB;Data Source=server1:port1,server2:port2,server3:port3;User Id=dba;Password=dba;Initial Catalog=Demo;Prompt=NoPrompt;

Round Robin Connect String format


 Provider=VIRTOLEDB;Data Source=server1:port1,server2:port2,server3:port3;User Id=dba;Password=dba;Initial Catalog=Demo;Prompt=NoPrompt;Round Robin=true

ADO.NET Provider

Failover Connect String format


Server=server1:port1,server2:port2,server3:port3;UserId=dba;Password=dba;

Round Robin Connect String format


Server=server1:port1,server2:port2,server3:port3;UserId=dba;Password=dba;Round Robin=true;Pooling=false;

Sesame

Failover Connect String format


VirtuosoRepository("server1:port1,server2:port2,server3:port3", "uid", "pwd");

Round Robin Connect String format


VirtuosoRepository("server1:port1,server2:port2,server3:port3", "uid", "pwd");
((VirtuosoRepository)repository).setRoundrobin(true);

Sample program


/*
 *  $Id:$
 *
 *  This file is part of the OpenLink Software Virtuoso Open-Source (VOS)
 *  project.
 *
 *  Copyright (C) 1998-2009 OpenLink Software
 *
 *  This project is free software; you can redistribute it and/or modify it
 *  under the terms of the GNU General Public License as published by the
 *  Free Software Foundation; only version 2 of the License, dated June 1991.
 *
 *  This program is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 *  General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

import java.sql.*;
import java.util.*;
import java.lang.*;

import org.openrdf.model.*;
import org.openrdf.query.*;
import org.openrdf.repository.*;
import org.openrdf.rio.*;
import virtuoso.jdbc4.*;

import virtuoso.sesame2.driver.*;

public class TestSesame2 {

  public static void main(String[] args) {

      Repository repository = new
	VirtuosoRepository("localhost:1111,localhost:1311,localhost:1312,localhost:1313", "dba", "dba");
      ((VirtuosoRepository)repository).setRoundrobin(true);

      RepositoryConnection con = null;
      Random rnd = new Random();
      for (int i = 0; i < 1000000; ) {
	  try {
	      if (null == con) {
		  System.out.println("New connection");
		  con = repository.getConnection();
	      }

	      TupleQuery query = con.prepareTupleQuery(
		      QueryLanguage.SPARQL, "INSERT INTO <test_g> { <sub" + i + "> <pred> <obj" + i+ "> . " + 
		      " <r" + Math.abs (rnd.nextInt()) + "> <rndpred> <r" + Math.abs (rnd.nextInt ()) + "> . }");
	      TupleQueryResult queryResult = query.evaluate();
	      /*long count = 0;
	      while (queryResult.hasNext()) 
	      {
		  queryResult.next();
		  count++;
		  if (count % 1000 == 0) 
		  {
		      System.out.println("Passed " + count + " results...");
		  }
	      }
	      */
	      queryResult.close();
	      i++;
	      try { Thread.sleep(100); } catch (InterruptedException ie) { }

	  } catch (Exception e) {
	      String state = "";
	      if (e.getCause() instanceof SQLException) {
		  state = ((SQLException)e.getCause()).getSQLState();
	      }
	      System.out.println("ERROR:" + state + " " + e.getCause()); 
	      try { Thread.sleep(2000); } catch (InterruptedException ie) { }
	      System.out.println("ERROR:" + e.toString ());
	      if (state == "")
	        e.printStackTrace();
	      try {
		  if (con != null /*&& (state == "08U01" || state == "S2801")*/) {  
		      System.out.println("Closing Connection.");
		      con.close();
		      con = null;
		  }
	      } catch (RepositoryException re) {
		  System.out.println("Test Failed.");
		  re.printStackTrace();
		  System.exit (1);
	      }
	  } finally {
	  }
      }
  }
}