Using Sequoia with GlassFish
Sequoia is a open source database clustering middleware that allows any Java application to transparentlyaccess a cluster of databases through JDBC.No code change is required to enable an application to
have failover, replication capabilities.
This demo will have the modified sample application from Netbeans, deployed in GlassFish,
interacting with Sequoia controller for database operations. The only change needed in the sample is to
configure the properties of jdbc-connection-pool to interact with Sequoia controller.
Bundles used :
GlassFish v2 build 38Sequoia 2.10.6
Netbeans 5.5.1 beta
Setup :
Install GlassFish & NetbeansGlassFish server can be registered through Netbeans > Runtime > Servers > Sun Java System Application Server
![]() |
Installation of Sequoia :
Extract the downloaded bundle and set the environment variable SEQUOIA_HOME to the installation (extracted) directory.Sequoia has sample configurations for various modes. This demo will modify and use the "hsqldb-raidb1-distribution-1.xml"
available in SEQUOIA_HOME/config/virtualdatabases to work with JavaDB bundled with GlassFish.
Sequoia Controller :
Controller is responsible for delegating the requests to underlying databases that are transparent to the application.Behind the scenes, sequoia will log the requests in a recovery table that will be used during recovery of a failed node
(database). The entire setup can be distributed ie., Application, Sequoia controller, databases to store the application data,
database to store the recovery log can all be distribued. Controller will load balance the read operations (queries) to one
of the database nodes and will replicate the write operations (create, drop, insert, delete, update) to all the database nodes.
Configuration of virtual database:
Virtual database represents the configuration of individual database nodes, recovery db node and has credentials for applicationto connect to controller.
copy "hsqldb-raidb1-distribution-1.xml" as "hetero-raidb1-distribution-1.xml"
Change VirtualDatabase name to "heterodb"
Set the "admin" password of AuthenticationManager to "adminadmin" [To do controller operations]
Set the virtualuser login of AuthenticationManager to "jdbc" and password to "jdbc" [For applications to interact with Sequoia]
For this demo, Derby is used in embedded mode.
Configuring individual database nodes for data replication :
|
<DatabaseBackend name="localhost1"
driver="org.apache.derby.jdbc.EmbeddedDriver"
url="jdbc:derby:heterodb1;Password=APP;User=APP;databaseName=heterodb1;create=true;"
connectionTestStatement="select count(*) from sys.systables"> <ConnectionManager vLogin="jdbc" rLogin="APP" rPassword="APP"> <VariablePoolConnectionManager initPoolSize="10" minPoolSize="5" maxPoolSize="50" idleTimeout="30" waitTimeout="10"/> </ConnectionManager> </DatabaseBackend> <DatabaseBackend name="localhost2" driver="org.apache.derby.jdbc.EmbeddedDriver" url="jdbc:derby:heterodb2;Password=APP;User=APP;databaseName=heterodb2;create=true;" connectionTestStatement="select count(*) from sys.systables"> <ConnectionManager vLogin="jdbc" rLogin="APP" rPassword="APP"> <VariablePoolConnectionManager initPoolSize="10" minPoolSize="5" maxPoolSize="50" idleTimeout="30" waitTimeout="10"/> </ConnectionManager> </DatabaseBackend> |
Configuring recovery log table :
|
<RecoveryLog driver="org.apache.derby.jdbc.EmbeddedDriver" url="jdbc:derby:recoverydb1;Password=APP;User=APP;databaseName=recoverydb1;create=true;" login="APP" password="APP"> <RecoveryLogTable tableName="RECOVERY" logIdColumnType="BIGINT" vloginColumnType="VARCHAR (500) " sqlColumnType="VARCHAR(500)" extraStatementDefinition=",PRIMARY KEY (log_id)"/> <CheckpointTable tableName="CHECKPOINT" checkpointNameColumnType="VARCHAR(500) "/> <BackendTable tableName="BACKEND" databaseNameColumnType="VARCHAR(500) " backendNameColumnType="VARCHAR(500) " checkpointNameColumnType="VARCHAR(500) "/> <DumpTable tableName="DUMP" dumpNameColumnType="VARCHAR(500) " dumpDateColumnType="TIMESTAMP" dumpPathColumnType="VARCHAR(500) " dumpFormatColumnType="VARCHAR(500) " checkpointNameColumnType="VARCHAR(500) " backendNameColumnType="VARCHAR(500) " tablesColumnType="VARCHAR(500) "/> </RecoveryLog> |
Configuring the Backuper :
Backuper is used to take complete backup of a node (backend) and can be used to create a new backend ortransfer the backup to another controller to bring back the controller from failure.
Above sample configration uses Derby's Embedded driver and hence setting Derby Embedded backuper.
|
<Backup> <Backuper backuperName="DerbyEmbeddedBackuper" className="org.continuent.sequoia.controller.backup.backupers.DerbyEmbeddedBackuper" options="zip=true"/> </Backup> |
Complete virtual database configuration file can be downloaded from here and copied to SEQUOIA_HOME/config/virtualdatbases
Copy the JavaDB driver (derby.jar available in GlassFish_Install_Dir/javadb/lib) to $SEQUOIA_HOME/drivers so that they
are available for Sequoia controller.
Controller configuration :
Configuration file sample is available at SEQUOIA_HOME/config/controllercopy "controller-distributed-1.xml" to "hetero-distributed-1.xml" and set the virtual database to use.
| <VirtualDatabase configFile="hetero-raidb1-distribution-1.xml" virtualDatabaseName="heterodb" autoEnableBackends="true"/> |
Complete controller configuration file can be downloaded from here and copied to SEQUOIA_HOME/config/controller
Starting the Sequoia controller :
SEQUOIA_HOME/bin/controller.sh -f config/controller/hetero-distributed-1.xml
20:31:21,629 INFO controller.core.Controller Sequoia controller (2.10.6) |
Initializing the nodes using the Sequoia console:
SEQUOIA_HOME/bin/console.sh
Launching the Sequoia controller console |
Now both the nodes are initialized and can serve for replication.
Sample application :
Start Netbeans, Create a new project > Samples > Enterprise > CustomerCMP

select the jdbc-connection-pool

and change the configuration (DataSource Classname, Properties) to point to sequoia controller

For GlassFish to talk to Sequoia controller, copy the Sequoia jdbc-driver from $SEQUOIA_HOME/drivers/sequoia-driver.jar to
GLASSFISH_HOME/domains/domain/lib/ext
All the set up is done to build & deploy the application to GlassFish.
From Netbeans, build & deploy the sample application. This will build the project, generate .ear file, start GlassFish,
create connection pools, deploy the application to GlassFish
Once the deployment is successful, run project from Netbeans.
Netbeans will open the browser with the web-application's URL.

Customer CMP application :
Simple application where customer details can be captured.
Create a new customer and ensure that the entries are persisted, through the "search" option provided in the application.

Now, to check the fail-over functionality, disable one of the node (backend) through Sequoia console.
heterodb(admin) > disable localhost2 |
Sequoia Controller will have similar logs :
22:33:13,236 INFO controller.RequestManager.heterodb All activity is suspended for heterodb |
Create another customer and ensure that the entries are persisted. [Behind the scenes, localhost1 alone will have
the entries and localhost2 is disabled/down]

Now disable localhost1 and enable localhost2
heterodb(admin) > disable localhost1 |
Access the application, search for customers of last name "Prasath"

There will not be any change in behavior of the application.
Behind the scenes, when localhost2 is enabled, all the entries will be persisted into localhost2 from recovery log's last
known checkpoint and ensure transparent failover & replication.
Multiple controllers :
It is possible to have more than one controller for a virtual database. In such a case, URL for the application will be,for eg : jdbc:sequoia://127.0.0.1:25322,127.0.0.1:25323/heterodb
Controller-2, virtual database configured similar to as shown above. Backends can be localhost3, localhost4.
Complete controller-2, virtual database file , configuration file can be copied to SEQUOIA_HOME/config/virtualdatabase, SEQUOIA_HOME/config/controller respectively.
With 2 controllers available, it is possible to shutdown an controller as a whole for maintenance. In case one of the controller
fails (eg, controller-2), sequoia driver will use the other and ensures availability. Backup can be taken on controller-1,
transferred to controller-2 and nodes can be restored.
Steps in brief :
Disable the backends of controller-2Add new customers using the application.
Take database dump of localhost1.
localhost:1090 > admin
|
Bring back controller-2
heterodb(admin) > show controllers |
Transfer the backup from controller-1 to controller-2 :
heterodb(admin) > transfer dump localhost1.bkp 127.0.0.1:1091 nocopy |
heterodb(admin) > restore backend localhost3 localhost1.bkp.2 |
Disable controller-1
heterodb(admin) > disable localhost2
|
Access the application, customers added when controller-2 was disabled will be visible via controller-2.
References :
GlassFish
Sequoia - Tutorial
Sequoia - Installation Guide
Sequoia - Administration Guide
Netbeans
Technorati Tags: glassfish

Posted by Shreyas on August 02, 2007 at 02:50 PM IST #
Though I didnt understand much as this is out of syllabus for me(!), this is a nicely prepared article/demo.
Lata
Posted by lata on August 23, 2007 at 10:48 AM IST #
Thanks Jagadish for your tutorial.
I'm trying to use Sequoia for my own project, however during runtime I'm running into problems. The problem is that I get an java.lang.UnsupportedClassVersionError. Not sure why as I am running JRE v 1.5. The stack trace is as follows:
Exception in thread "main" java.lang.UnsupportedClassVersionError: Bad version number in .class file
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:620)
at java.lang.ClassLoader.defineClass(ClassLoader.java:465)
at org.continuent.sequoia.controller.connection.DriverClassLoader.findClass(DriverClassLoader.java:119)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at org.continuent.sequoia.controller.connection.DriverClassLoader.loadClass(DriverClassLoader.java:78)
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:242)
at org.continuent.sequoia.controller.connection.DriverManager.loadDriver(DriverManager.java:283)
at org.continuent.sequoia.controller.connection.DriverManager.getConnection(DriverManager.java:146)
at org.continuent.sequoia.controller.recoverylog.RecoveryLog.getDatabaseConnection(RecoveryLog.java:343)
at org.continuent.sequoia.controller.recoverylog.RecoveryLog.<init>(RecoveryLog.java:298)
at org.continuent.sequoia.controller.xml.DatabasesParser.newRecoveryLog(DatabasesParser.java:2845)
at org.continuent.sequoia.controller.xml.DatabasesParser.startElement(DatabasesParser.java:606)
at org.apache.crimson.parser.Parser2.maybeElement(Parser2.java:1488)
at org.apache.crimson.parser.Parser2.content(Parser2.java:1779)
at org.apache.crimson.parser.Parser2.maybeElement(Parser2.java:1507)
at org.apache.crimson.parser.Parser2.content(Parser2.java:1779)
at org.apache.crimson.parser.Parser2.maybeElement(Parser2.java:1507)
at org.apache.crimson.parser.Parser2.content(Parser2.java:1779)
at org.apache.crimson.parser.Parser2.maybeElement(Parser2.java:1507)
at org.apache.crimson.parser.Parser2.parseInternal(Parser2.java:500)
at org.apache.crimson.parser.Parser2.parse(Parser2.java:305)
at org.apache.crimson.parser.XMLReaderImpl.parse(XMLReaderImpl.java:442)
at org.continuent.sequoia.controller.xml.DatabasesParser.readXML(DatabasesParser.java:294)
at org.continuent.sequoia.controller.xml.DatabasesParser.readXML(DatabasesParser.java:343)
at org.continuent.sequoia.controller.core.Controller.addVirtualDatabases(Controller.java:222)
at org.continuent.sequoia.controller.core.Controller.loadXmlConfiguration(Controller.java:555)
at org.continuent.sequoia.controller.core.ControllerConfiguration.setUpVirtualDatabase(ControllerConfiguration.java:446)
at org.continuent.sequoia.controller.xml.ControllerParser.configureVirtualDatabase(ControllerParser.java:645)
at org.continuent.sequoia.controller.xml.ControllerParser.startElement(ControllerParser.java:325)
at org.apache.crimson.parser.Parser2.maybeElement(Parser2.java:1488)
at org.apache.crimson.parser.Parser2.content(Parser2.java:1779)
at org.apache.crimson.parser.Parser2.maybeElement(Parser2.java:1507)
at org.apache.crimson.parser.Parser2.content(Parser2.java:1779)
at org.apache.crimson.parser.Parser2.maybeElement(Parser2.java:1507)
at org.apache.crimson.parser.Parser2.parseInternal(Parser2.java:500)
at org.apache.crimson.parser.Parser2.parse(Parser2.java:305)
at org.apache.crimson.parser.XMLReaderImpl.parse(XMLReaderImpl.java:442)
at org.continuent.sequoia.controller.xml.ControllerParser.readXML(ControllerParser.java:127)
at org.continuent.sequoia.controller.xml.ControllerParser.readXML(ControllerParser.java:177)
at org.continuent.sequoia.controller.xml.ControllerParser.readXML(ControllerParser.java:206)
at org.continuent.sequoia.controller.core.ControllerConfiguration.setUpByXml(ControllerConfiguration.java:277)
at org.continuent.sequoia.controller.core.ControllerConfiguration.setup(ControllerConfiguration.java:327)
at org.continuent.sequoia.controller.core.ControllerConfiguration.getController(ControllerConfiguration.java:353)
at org.continuent.sequoia.controller.core.Controller.main(Controller.java:745)
Any ideas? Thanks in advance.
Posted by SAF on November 12, 2007 at 12:27 PM IST #
Hi,
When I am going to run this example, I got errors with the controller. It is showing unknown resource.
When I run the console, it is showing the "heterodb" is a not a virtual database file.
It is showing the jdbc error in the controller.
Please clarify my doubts.
Thank you,
srinivas
Posted by srinivasraopala on May 15, 2008 at 12:07 PM IST #
Hi , My name is sudheer,i am using 1 controller with 2 backends ,when i am running the controller,i am getting like below......................
15:18:34,473 INFO controller.core.Controller Sequoia controller (3.0-beta2)
15:18:34,629 INFO controller.core.Controller Loading configuration file: ../config/controller/controller-dis.xml
15:18:34,801 INFO controller.core.Controller JMX is enabled
15:18:34,831 INFO controller.core.Controller Starting JMX server on host: 0.0.0.0:1190
15:18:35,347 INFO controller.backup.BackupManager Registering backuper postgresql to handle format PostgreSQL Binary Dump
15:18:35,369 INFO backend.DatabaseBackend.back1 Adding connection manager for virtual user "user"
15:18:35,376 INFO backend.DatabaseBackend.back2 Adding connection manager for virtual user "user"
15:18:36,049 INFO sequoia.controller.recoverylog Creating recovery log table: RECOVERY
15:18:36,121 INFO sequoia.controller.recoverylog Creating checkpoint table: CHECKPOINT
15:18:36,144 INFO sequoia.controller.recoverylog Creating backend table: BACKEND
15:18:36,145 INFO sequoia.controller.recoverylog Creating dump table: DUMP
15:18:36,207 INFO controller.RequestManager.vDB Request manager will parse requests with the following granularity: TABLE
15:18:36,242 INFO controller.virtualdatabase.vDB Using Hedera properties file: /hedera_appia.properties
15:18:36,447 INFO appia.xml.AppiaXML Loading XML configuration from file: /usr/local/sequoia/config/appia.xml
15:18:37,603 INFO continuent.hedera.appia AppiaThread: Starting Appia.
15:18:39,675 INFO controller.virtualdatabase.vDB Group vDB connected to Member(address=/192.168.1.10:60370, uid=192.168.1.10:60370)
15:18:39,675 INFO controller.virtualdatabase.vDB First controller in group vDB
15:18:39,691 INFO sequoia.controller.recoverylog Checking recovery log consistency
15:18:39,710 WARN controller.virtualdatabase.vDB Cannot enable backend back1 from a known state. Resynchronize this backend by restoring a dump.
15:18:39,716 WARN controller.virtualdatabase.vDB Cannot enable backend back2 from a known state. Resynchronize this backend by restoring a dump.
15:18:39,716 INFO controller.core.Controller Adding VirtualDatabase vDB
15:18:39,743 INFO controller.core.Controller Waiting for connections on 127.0.0.1:25323
15:18:39,766 INFO controller.core.Controller Controller started on 2008.07.24 30 at 03:18:39 PM IST
15:18:39,766 INFO controller.core.Controller Controller c1 ready, listening to requests ...
My Controller Configuration :
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE SEQUOIA-CONTROLLER PUBLIC "-//Continuent//DTD SEQUOIA-CONTROLLER @VERSION@//EN"
"http://sequoia.continuent.org/dtds/sequoia-controller-@VERSION@.dtd">
<SEQUOIA-CONTROLLER>
<Controller name="c1" jdbcIpAddress="127.0.0.1" jdbcPort="25323">
<JmxSettings jmxIpAddress="0.0.0.0" jmxPort="1190"/>
<!-- <Report hideSensitiveData="true" generateOnShutdown="true" generateOnFatal="true" enableFileLogging="true"/> -->
<VirtualDatabaseAutoLoad configFile="post-distribution-1.xml" virtualDatabaseName="vDB" autoEnableBackends="true"/>
</Controller>
</SEQUOIA-CONTROLLER>
My Virtual Database Configuration :
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE SEQUOIA PUBLIC "-//Continuent//DTD SEQUOIA @VERSION@//EN"
"http://sequoia.continuent.org/dtds/sequoia-@VERSION@.dtd">
<SEQUOIA>
<VirtualDatabase name="vDB">
<Distribution>
<MessageTimeouts/>
</Distribution>
<Backup>
<Backuper backuperName="postgresql"
className="org.continuent.sequoia.controller.backup.backupers.PostgreSQLBinaryBackuper"/>
</Backup>
<AuthenticationManager>
<AdminUser username="admin" password=""/>
<VirtualUser vLogin="user" vPassword=""/>
</AuthenticationManager>
<!-- Example of a PostgreSQL backend attached to this controller -->
<DatabaseBackend name="back1" driver="org.postgresql.Driver"
url="jdbc:postgresql://192.168.1.10:5433/test" connectionTestStatement="select now()">
<!-- A connection pool must be defined for each user -->
<ConnectionManager vLogin="user" rLogin="postgres" rPassword="dn68qr7">
<VariablePoolConnectionManager initPoolSize="10" maxPoolSize="50"/>
</ConnectionManager>
</DatabaseBackend>
<DatabaseBackend name="back2" driver="org.postgresql.Driver"
url="jdbc:postgresql://192.168.1.10:5434/test" connectionTestStatement="select now()">
<!-- A connection pool must be defined for each user -->
<ConnectionManager vLogin="user" rLogin="postgres" rPassword="dn68qr7">
<VariablePoolConnectionManager initPoolSize="10" maxPoolSize="50"/>
</ConnectionManager>
</DatabaseBackend>
<DatabaseSchema/>
<RequestManager>
<RequestScheduler>
<RAIDb-1Scheduler level="passThrough"/>
</RequestScheduler>
<LoadBalancer>
<RAIDb-1>
<WaitForCompletion policy="first"/>
<MacroHandling>
<RandomMacro macroName="rand()"/>
<DateMacro macroName="now()" dateFormat="timestamp"/>
<DateMacro macroName="current_date" dateFormat="date"/>
<DateMacro macroName="timeofday()" dateFormat="time"/>
<DateMacro macroName="current_timestamp" dateFormat="timestamp"/>
<DateMacro macroName="current_time" dateFormat="time"/>
</MacroHandling>
<RAIDb-1-LeastPendingRequestsFirst/>
</RAIDb-1>
</LoadBalancer>
<EmbeddedRecoveryLog dataPath="../config/vDB/recoverylog"/>
</RequestManager>
</VirtualDatabase>
</SEQUOIA>
i am using postgresql 8.1 , jdbc driver is pg73jdbc2.jar , sequoia2.9 ,
plzzz any one give the soluiton.................
Thnx in Advance.........................
Posted by Sudheer on July 24, 2008 at 04:08 PM IST #
These r the errors
15:18:39,710 WARN controller.virtualdatabase.vDB Cannot enable backend back1 from a known state. Resynchronize this backend by restoring a dump.
15:18:39,716 WARN controller.virtualdatabase.vDB Cannot enable backend back2 from a known state. Resynchronize this backend by restoring a dump.
Posted by Sudheer on July 24, 2008 at 04:10 PM IST #