1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
|
<?xml version="1.0" encoding="UTF-8"?>
<!--
-
- This file is part of the OpenLink Software Virtuoso Open-Source (VOS)
- project.
-
- Copyright (C) 1998-2018 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
-
-
-->
<chapter label="xa.xml" id="xa">
<title>Using Virtuoso with Tuxedo</title>
<abstract>
<para>
BEA Tuxedo provides the framework, or middleware, for building scalable multi-tier client/server
applications in heterogeneous (dissimilar), distributed environments that extend from the Web to
the Enterprise. Using BEA Tuxedo, users can develop, manage, and deploy distributed applications
independently of the underlying hardware, operating system, network, and database environment.
</para>
<para>
The current document covers linkage between Virtuoso server and Tuxedo by ATMI (Application-to-Transaction
Monitor Interface) only.
</para>
<para>
In contrast to classic 2-tier client/server configuration of SQL servers, the Tuxedo brings 3-tier paradigm
(clients, services, resource managers).
</para>
<para>
At the foundation of BEA Tuxedo ATMI is a proven, reliable transaction processor, also known as
a transaction processing (TP) monitor. A transaction processor is an example of a 3-tier client/server
architecture, where the transaction processor supports the application logic (represented by "services"
between the GUI front-end and the back-end resource managers. Examples of resource managers are SQL
databases, message queues, legacy applications, and other back-end services.
</para>
<para>
This document explains how to build support binaries for Tuxedo and Virtuoso and how to write services which
use the Virtuoso as resource manager.
</para>
</abstract>
<sect1 id="xaBuildTMS">
<title>Building the Transaction Manager Server</title>
<para>
First of all, the administrator needs to build Virtuoso Transaction Manager Server application in order
to use Virtuoso server as Resource Manager of global transactions operated by Tuxedo.
</para>
<para>
Then, the following line needs to be put in the $TUXDIR/udataobj/RM file:
<programlisting>
Virtuoso:virt_xa_switch: libvirtxa.a -L${HOME}/lib -lwic -ldk1t -lthrp -lutil2 -L${SSLDIR}/lib -lssl -lcrypto
</programlisting>
The libvirtxa.a library could be found in tuxedo/lib directory.
</para>
<para>
This allows to build TP monitor with Virtuoso support (VirtTMS) and services which could use Virtuoso as resource manager.
libvirtxa.a and other libraries must be accessible by the compiler. The following command builds the VirtTMS:
<programlisting>
buildtms -o ${TUXDIR}/bin/VirtTMS -r Virtuoso
</programlisting>
</para>
</sect1>
<sect1 id="xaUBBconf">
<title>Configuration</title>
<para>
In order to use Virtuoso as resource manager the UBB config file (Tuxedo main configuration file) must contain reference
to VirtTMS. The following example of UBB config file configures two services and two virtuoso servers (resource managers)
behind them.
</para>
<programlisting><![CDATA[*RESOURCES
IPCKEY 52617
DOMAINID qsample
MASTER NODE
MODEL SHM
#
*MACHINES
#
NODE
LMID = NODE
TUXDIR = "TUXEDODIR"
TUXCONFIG = "SERVDIR/tuxconfig"
TLOGDEVICE ="SERVDIR/tuxconfig"
TLOGSIZE=10
APPDIR = "SERVDIR"
ULOGPFX = "SERVDIR/ULOG"
*GROUPS
DEFAULT: TMSNAME=VirtTMS TMSCOUNT=2 LMID=NODE
GROUP1 GRPNO=1 OPENINFO = "Virtuoso:dba:dba@NODE:1111"
GROUP2 GRPNO=2 OPENINFO = "Virtuoso:dba@NODE:1112"
*SERVERS
#
DEFAULT: CLOPT="-A"
VirtRMtest SRVGRP=GROUP1 SRVID=1
# VirtRMtest SRVGRP=GROUP2 SRVID=1
# VirtRMtest2 SRVGRP=GROUP1 SRVID=2
VirtRMtest2 SRVGRP=GROUP2 SRVID=2
#server SRVGRP=GROUP1 SRVID=1
*SERVICES
DEFAULT: LOAD=50
VRMTEST PRIO=50
VRMTEST2 PRIO=50
]]></programlisting>
</sect1>
<sect1 id="xaServices">
<title>Services</title>
<sect2 id="xaServicesAbstract">
<title>Introduction</title>
<para>
The services (in the Tuxedo's term) are special programs which implement business logic. The services could
be in the context of a global XA transaction, in this case 2PC control will be set in motion.
Each service which uses Virtuoso as resource manager has hdbc connection to
the Virtuoso server. This connection is automatically opened when service activated. The connection string (OPENINFO)
to the Virtuoso server is the connection string of the group of the service (see GROUPS section
in the sample config file). The OPENINFO has the following format: "Virtuoso:user:password@NODENAME:port".
The user,password and port are optional.
</para>
</sect2>
<sect2 id="xaServicesVQL">
<title>VQL functions</title>
<para>
VQL functions are used to receive access to hdbc for further work with the Virtuoso server.
Only HDBCs received by the VQL functions are operated in
the context of the distributed transactions.
</para>
<para>
<programlisting>
int vql_get_connection (HDBC * hdbc, int type);
</programlisting>
returns result of setting hdbc to current hdbc connection. "type" argument indicates
which hdbc is to select, currently only VQL_CTX_TYPE is supported, other values are
reserved.
</para>
<para>
<programlisting>
int vql_get_env (HENV * env);
</programlisting>
returns result of setting current ODBC environment.
</para>
<para>Header: vql_client.h</para>
<para>Library: libvirtxa.a</para>
</sect2>
<sect2 id="xaServCon">
<title>Services concept</title>
<para>
Each service has an entry point (some function), which is supposed to perform the application task. The result of
whole transaction depends on result of the service's entry function. The scenario of typical workflow is as
follows:
<itemizedlist mark="bullet" spacing="compact">
<listitem>client begins global transaction by ATMI tpbegin() call,</listitem>
<listitem>client calls the service N1 to update some tables on the first Virtuoso server (resource manager),</listitem>
<listitem>client calls the service N2 to update some tables on the second Virtuoso server (resource manager),</listitem>
<listitem>client finishes global transaction by either tpcommit() or tpabort() call of ATMI.</listitem>
</itemizedlist>
</para>
<para>
The tx_* functions also could be used, See TUXEDO TxRPC related or ORACLE XA documentation.
<itemizedlist mark="bullet" spacing="compact">
<listitem>tx_begin()</listitem>
<listitem>tx_commit()</listitem>
<listitem>tx_open()</listitem>
</itemizedlist>
</para>
<para>
Services can be built with the following command:
<programlisting>buildserver -v -f virt_service1.o -o VirtService1 -r Virtuoso -s VService1</programlisting>
where "virt_service1.o" is the service object file which contains VService1 entry function.
"-r Virtuoso" indicates that service must be assembled with Virtuoso XA support library.
</para>
</sect2>
<sect2 id="xaServOpeninfo">
<title>OPENINFO</title>
<para>
OPENINFO is necessary for services to connect to the certain Virtuoso server.
OPENINFO for the services (see GROUPS section in the example) consists of 2 parts:
"Virtuoso" term and connection string. Connection string provides the service name,
password, server and port of Virtuoso server. Common format of connection string is
[USER[:PASSWORD]]@SERVER[:PORT].
Only the SERVER name is required, the others are optional.
</para>
</sect2>
</sect1>
<sect1 id="xaClients">
<title>Clients</title>
<para>
There are no special requirements for the clients of services which use Virtuoso as resource manager.
See Tuxedo 8.x documentation
</para>
</sect1>
<sect1 id="xaServExample">
<title>Service example</title>
<programlisting><![CDATA[#include <stdio.h>
#include <time.h>
#include <xa.h>
#include <atmi.h>
#include <userlog.h>
#include "vql_client.h"
#include <libudbc.h>
#ifndef SQL_SUCCEEDED
#define SQL_SUCCEEDED(rc) (((rc)&(~1))==0)
#endif
#define MAXNAME SQL_MAX_DSN_LENGTH
int sql_exec (HDBC hdbc, char* text);
/* VirtRM test service */
int
tpsvrinit(int argc, char *argv[])
{
if (tpopen () == -1)
{
userlog ("tpsrvinit: could not open RM, %s\n", tpstrerror (tperrno));
return -1;
}
/* userlog writes to the central TUXEDO message log */
userlog("Welcome to the VirtRMtest server");
return 0;
}
int
tpsrvdone()
{
if (tpclose () == -1)
{
userlog ("tpsrvinit: could not close RM, %s\n", tpstrerror (tperrno));
return -1;
}
/* userlog writes to the central TUXEDO message log */
userlog("By!! the VirtRMtest server");
return 0;
}
static void
DoSQLError (HDBC hdbc, HSTMT hstmt);
#define CHECK_RC(rc) \
if (!SQL_SUCCEEDED (rc)) { DoSQLError (hdbc, stmt); return -1; };
int sql_exec (HDBC hdbc, char* text)
{
RETCODE rc;
HSTMT stmt;
rc = SQLAllocStmt (hdbc, &stmt);
CHECK_RC(rc);
rc = SQLExecDirect (stmt, text, SQL_NTS);
CHECK_RC(rc);
SQLFreeStmt (stmt, SQL_DROP);
return 0;
}
void
VRMTEST(TPSVCINFO *rqst)
{
HDBC hdbc;
int rc;
rc = vql_get_connection (&hdbc, VQL_CTX_TYPE);
if (rc != VQL_SUCCESS)
{
#ifdef TMS_TRACE
userlog ("AP[%d]: vql_get_connection error %d\n", getpid(), rc);
#endif
goto _fail;
}
rc = sql_exec (hdbc, "UPDATE sal set amount = amount + 10 where name = 'jfk'");
if (rc == -1)
{
#ifdef TMS_TRACE
userlog ("AP[%d]: vql_get_connection error %d\n", getpid(), rc);
#endif
goto _fail;
}
userlog ("AP[%d]: exec sql succ.\n", getpid());
tpreturn(TPSUCCESS, 0, rqst->data, 0L, 0);
return;
_fail:
userlog ("FAILED: exec sql.\n");
tpreturn(TPFAIL, 0, rqst->data, 0L, 0);
return;
}
void
VRMTEST2(TPSVCINFO *rqst)
{
HDBC hdbc;
int rc;
rc = vql_get_connection (&hdbc, VQL_CTX_TYPE);
if (rc != VQL_SUCCESS)
goto _fail;
rc = sql_exec (hdbc, "UPDATE sal set amount = amount - 10 where name = 'jfk'");
if (rc == -1)
goto _fail;
userlog ("AP[%d]: exec sql succ.\n", getpid());
tpreturn(TPSUCCESS, 0, rqst->data, 0L, 0);
return;
_fail:
userlog ("AP[%d]: service #2 error %d\n", getpid(), rc);
tpreturn(TPFAIL, 0, rqst->data, 0L, 0);
return;
tpreturn(TPSUCCESS, 0, rqst->data, 0L, 0);
}
#define MSG_BUF_SIZE 300
static void
DoSQLError (HDBC hdbc, HSTMT hstmt)
{
UCHAR szSqlState[MSG_BUF_SIZE];
UCHAR szErrorMsg[MSG_BUF_SIZE];
SQLINTEGER fNativeError = 0;
SWORD cbErrorMsg = MSG_BUF_SIZE;
RETCODE rc;
HENV env;
#ifndef TMS_TRACE
return;
#else
vql_get_env (&env);
rc = SQLError (env,
hdbc,
hstmt,
szSqlState, &fNativeError, szErrorMsg, MSG_BUF_SIZE, &cbErrorMsg);
if (rc != SQL_NO_DATA_FOUND || rc != SQL_ERROR)
{
if (fNativeError != 0x1645) // ignore change database to master context message
{
userlog ("SqlState: %s, fNativeError: %x m=%s\n", szSqlState,
fNativeError, szErrorMsg);
}
}
else
{
userlog ("SQLError() failed: %x, NO_DATA_FOUND OR SQL_ERROR\n", rc);
}
return;
#endif
}]]>
</programlisting>
</sect1>
</chapter>
|