Back to home page

Enduro/X

 
 

    


0001 LIBNDRXXAPQ(8)
0002 ==============
0003 :doctype: manpage
0004 
0005 
0006 NAME
0007 ----
0008 libndrxxapq - Enduro/X PostgreSQL PQ XA Driver
0009 
0010 
0011 SYNOPSIS
0012 --------
0013 libndrxxapq.so
0014 libndrxxapq.dylib
0015 
0016 --------------------------------------------------------------------------------
0017 NDRX_XA_RES_ID=1
0018 NDRX_XA_OPEN_STR={"url":"tcp:postgresql://${EX_PG_HOST}/${EX_PG_DB}"
0019         ,"user":"${EX_PG_USER}"
0020         ,"password":"${EX_PG_PASS}"
0021         ,"compat":"PGSQL|INFORMIX|INFORMIX_SE"
0022         }"
0023 NDRX_XA_CLOSE_STR=$NDRX_XA_OPEN_STR
0024 NDRX_XA_DRIVERLIB=libndrxxapq.so
0025 NDRX_XA_RMLIB=-
0026 NDRX_XA_LAZY_INIT=1
0027 --------------------------------------------------------------------------------
0028 
0029 DESCRIPTION
0030 -----------
0031 This is XA driver specifically written Enduro/X needs. It provides an XA switch
0032 emulation on top of PostgreSQL prepared transactions. PostgreSQL by default
0033 does not support XA switch. Also when transaction start, there is no possibility
0034 to identify the work unit performed. The identification of work done by some
0035 process on particular connection can be done by preparing the transaction. Thus
0036 there is no such thing as "active" transaction in terms of XA specification.
0037 Also there is no possibility for other processes to join the existing work and
0038 see work done by other session. Thus for example if one server process in same
0039 transaction performs some insert and other process tries insert on table which
0040 has foreign key to first insert, it will fail, as FK will not be seen. Thus
0041 Enduro/X needs to work on branch-transactions mode without join feature. The
0042 mode of PostgreSQL driver is the same as enabled by *NDRX_XA_FLAG* with value
0043 *NOJOIN*. 
0044 
0045 The emulation of XA protocol is done by following steps and assumptions:
0046 
0047 1. When process joins to global transaction, new branch-transaction-id is
0048 acquired. The TMSRV logs the branch with status 'u'-unknown.
0049 
0050 2. When process completes the work unit (server does tpreturn(3) or tpforward(3))
0051 or initiating process performs tpcommit(3), the xa_end() is called which in-turn
0052 runs PostgreSQL "PREPARE TRANSACTION <XID_STR>". "XID_STR" is based on PosgreSQL
0053 JDBC driver format. Thus JDBC version on PQ versions of tmsrv drivers can be mixed.
0054 When transaction is prepared OK, the TMSRV is reported with 'p'-prepared status.
0055 If prepare fails, this means that transaction is aborted by PosgreSQL, and in
0056 this case 'a'-aborted status is reported to TMSRV.
0057 
0058 3. When TMSRV tries to commit, and branch is in 'u'-unknown or 'a'-aborted status,
0059 the global transaction is aborted and tpcommit caller receives *TPEABORT* error.
0060 If transaction is in status 'p', the prepare phase of global transaction is
0061 skipped/no operation and then commit is executed.
0062 
0063 4. In case if work unit performs too long operation and tries to xa_end() after
0064 when TMSRV is already timed-out/rolled back the global transaction, the xa_end()
0065 status call to TMSRV fails with error *TPEMATCH*. In this case local process
0066 rolls back the prepared transaction.
0067 
0068 5. When tpabort is executed, the xa_end() within tpabort() process performs
0069 abort without executing prepare.
0070 
0071 The connection details are encoded in JSON based string which contains the
0072 database URL, user name and password.
0073 
0074 To get connection handler, used *tpgetconn(3)* function. Which is available
0075 for this driver.
0076 
0077 CONNECTION PARAMETERS
0078 ---------------------
0079 *url*::
0080     This is standard PostgreSQL connection URL. Typically it contains database
0081     host, port and database name. The Enduro/X standard environment variable
0082     substitution is used here.
0083     
0084 EXTERNAL SYMBOLS
0085 ----------------
0086 *ndrx_G_PG_conname*::
0087     This is connection name currently associated with thread. It is thread is
0088     stored in thread local storage (TLS). Definition is 
0089     *__thread char ndrx_G_PG_conname[65]*.
0090 
0091 CONFIGURATION EXAMPLE
0092 ---------------------
0093 When starting to use Enduro/X PQ XA Driver, ensure that PosgreSQL LIBPQ 
0094 is installed.
0095 
0096 The typical configuration is done as a standard Enduro/X XA resource configuration,
0097 which can be set directly in environment variables or in *[@global]* section in
0098 application configuration (e.g. app.ini). This gives example of app.ini configuration.
0099 
0100 Sample configuration *app.ini* for CCTAG *DB1_PQ*:
0101 
0102 --------------------------------------------------------------------------------
0103 
0104 [@global/DB1_PQ]
0105 NDRX_XA_RES_ID=1
0106 NDRX_XA_OPEN_STR={"url":"postgresql://testuser:testuser1@localhost:5432/testdb"}
0107 NDRX_XA_CLOSE_STR=${NDRX_XA_OPEN_STR}
0108 NDRX_XA_DRIVERLIB=libndrxxapq.so
0109 NDRX_XA_RMLIB=-
0110 NDRX_XA_LAZY_INIT=1
0111 
0112 --------------------------------------------------------------------------------
0113 
0114 Sample configuration of transaction manager in *ndrxconfig.xml* for CCTAG *DB1_PQ*:
0115 
0116 --------------------------------------------------------------------------------
0117     <servers>
0118         ...
0119         <server name="tmsrv">
0120             <max>1</max>
0121             <srvid>1650</srvid>
0122             <cctag>DB1_PQ</cctag>
0123             <sysopt>-e /tmp/tmsrv-dom1.log -r -- -t1 -l/tmp</sysopt>
0124         </server>
0125         ...
0126     </servers>
0127 --------------------------------------------------------------------------------
0128 
0129 LIBPQ C EXAMPLE
0130 ---------------
0131 
0132 This is example of programming database with libpq.
0133 
0134 File: test_expq.c
0135 --------------------------------------------------------------------------------
0136 #include <string.h>
0137 #include <stdio.h>
0138 #include <stdlib.h>
0139 #include <atmi.h>
0140 #include <libpq-fe.h>
0141 
0142 #define FAIL -1
0143 #define SUCCEED 0
0144 
0145 int main(int argc, char** argv)
0146 {
0147     PGconn * conn;
0148     PGresult *res = NULL;
0149     ExecStatusType estat;
0150     int ret = SUCCEED;
0151 
0152     /* open connection */
0153     if (EXSUCCEED!=tpopen())
0154     {
0155         fprintf(stderr, "Failed to open: %s\n", tpstrerror(tperrno));
0156         ret = FAIL;
0157         goto out;
0158     }
0159     
0160     /* get the connection which was open by tpopen() */
0161     conn = (PGconn *)tpgetconn();
0162 
0163     /* create some table... */
0164     
0165     res = PQexec(conn, "CREATE TABLE manextest(userid integer UNIQUE NOT NULL);");
0166     
0167     estat = PQresultStatus(res);
0168 
0169     if (PGRES_COMMAND_OK != estat) 
0170     {
0171         char *state = PQresultErrorField(res, PG_DIAG_SQLSTATE);
0172         char *msg = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY);
0173 
0174         fprintf(stderr, "Failed to create table: state: [%s]: %s\n", state, msg);
0175         
0176         if (0==strcmp(state, "42P07"))
0177         {
0178             fprintf(stderr, "Table already exist - ignore error\n");
0179         }
0180         else
0181         {
0182             ret = FAIL;
0183             goto out;
0184         }
0185     }
0186 
0187     /* start transaction */
0188     if (EXSUCCEED!=tpbegin(60, 0))
0189     {
0190         fprintf(stderr, "Failed to begin: %s\n", tpstrerror(tperrno));
0191         ret = FAIL;
0192         goto out;
0193     }
0194     
0195     
0196     /* insert data */
0197 
0198     PQclear(res);
0199 
0200     res = PQexec(conn, "insert into manextest(userid) values ((select COALESCE(max(userid), 1)+1 from manextest));");
0201         
0202     estat = PQresultStatus(res);
0203 
0204     if (PGRES_COMMAND_OK != estat) 
0205     {
0206         char *state = PQresultErrorField(res, PG_DIAG_SQLSTATE);
0207         char *msg = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY);
0208 
0209         fprintf(stderr, "Failed to create table: state: [%s]: %s\n", state, msg);
0210         ret = FAIL;
0211         goto out;
0212     }
0213 
0214     if (SUCCEED!=tpcommit(0))
0215     {
0216         fprintf(stderr, "TESTERROR: Commit OK, must fail!\n");
0217         ret = FAIL;
0218         goto out;
0219     }
0220 
0221 out:
0222     if (SUCCEED!=ret)
0223     {
0224         tpabort(0);
0225     }
0226 
0227     tpclose();
0228     tpterm();
0229 
0230 }
0231 
0232 --------------------------------------------------------------------------------
0233 
0234 Build the program with:
0235 
0236 --------------------------------------------------------------------------------
0237 
0238 $ cc test_expq.c -o expqtest -I/usr/include/postgresql -lpq -latmi -lnstd -lubf -lrt
0239 
0240 --------------------------------------------------------------------------------
0241 
0242 Run and test:
0243 
0244 --------------------------------------------------------------------------------
0245 
0246 $ ./expqtest 
0247 Failed to create table: state: [42P07]: relation "manextest" already exists
0248 Table already exist - ignore error
0249 
0250 $ psql -U testuser -d testdb -h localhost
0251 
0252 testdb=> select * from manextest;
0253  userid 
0254 ========
0255       2
0256 (1 row)
0257 
0258 --------------------------------------------------------------------------------
0259 
0260 For more unit tests please see 'atmitest/test067_postgres' unit test folder for
0261 PQ source examples and configuration.
0262 
0263 BUGS
0264 ----
0265 Report bugs to support@mavimax.com
0266 
0267 SEE ALSO
0268 --------
0269 *libndrxxaecpg(8)* *ndrxconfig.xml(5)* *tmsrv(8)* *libndrxxawsmqs(8)* *libndrxxaoras(8)*
0270 *tpgetconn(3)*
0271 
0272 COPYING
0273 -------
0274 (C) Mavimax, Ltd
0275