Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief `recoverlocal', `commitlocal' and `abortlocal' implementation
0003  *
0004  * @file cmd_tranlocal.c
0005  */
0006 /* -----------------------------------------------------------------------------
0007  * Enduro/X Middleware Platform for Distributed Transaction Processing
0008  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0009  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0010  * This software is released under one of the following licenses:
0011  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0012  * See LICENSE file for full text.
0013  * -----------------------------------------------------------------------------
0014  * AGPL license:
0015  *
0016  * This program is free software; you can redistribute it and/or modify it under
0017  * the terms of the GNU Affero General Public License, version 3 as published
0018  * by the Free Software Foundation;
0019  *
0020  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0021  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0022  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0023  * for more details.
0024  *
0025  * You should have received a copy of the GNU Affero General Public License along 
0026  * with this program; if not, write to the Free Software Foundation, Inc.,
0027  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0028  *
0029  * -----------------------------------------------------------------------------
0030  * A commercial use license is available from Mavimax, Ltd
0031  * contact@mavimax.com
0032  * -----------------------------------------------------------------------------
0033  */
0034 #include <string.h>
0035 #include <stdio.h>
0036 #include <stdlib.h>
0037 #include <memory.h>
0038 #include <sys/param.h>
0039 
0040 #include <ndrstandard.h>
0041 #include <ndebug.h>
0042 #include <nstdutil.h>
0043 
0044 #include <ndrxdcmn.h>
0045 #include <atmi_int.h>
0046 #include <gencall.h>
0047 #include <utlist.h>
0048 #include <Exfields.h>
0049 #include <xa.h>
0050 
0051 #include "xa_cmn.h"
0052 #include "exbase64.h"
0053 #include <ndrx.h>
0054 #include <nclopt.h>
0055 /*---------------------------Externs------------------------------------*/
0056 /*---------------------------Macros-------------------------------------*/
0057 /*---------------------------Enums--------------------------------------*/
0058 /*---------------------------Typedefs-----------------------------------*/
0059 /*---------------------------Globals------------------------------------*/
0060 /*---------------------------Statics------------------------------------*/
0061 exprivate int M_rcv_count;
0062 /*---------------------------Prototypes---------------------------------*/
0063 
0064 /**
0065  * List in-doubt transactions
0066  * @param[in] p_ub UBF buffer with TM response
0067  * @param[in] svcnm TM service name
0068  * @param[in] parse shall we parse the XID
0069  * @return SUCCEED/FAIL
0070  */
0071 exprivate int print_buffer(UBFH *p_ub, char *svcnm, short parse)
0072 {
0073     int ret = EXSUCCEED;
0074     char tmxid[1024];
0075     BFLDLEN len;
0076     
0077     /* the xid is binary XID recovered in hex */
0078     if (EXSUCCEED!=Bget(p_ub, TMXID, 0, (char *)tmxid, 0L))
0079     {
0080         fprintf(stderr, "Protocol error - TM did not return data, see logs!\n");
0081         NDRX_LOG(log_error, "Failed to read fields: [%s]", 
0082                 Bstrerror(Berror));
0083         EXFAIL_OUT(ret);
0084     }
0085     
0086     /* list in copy/past for commit/abort local format */
0087     printf("XID: -s %s -x %s\n", svcnm, tmxid);
0088     
0089     /* TODO: Print Enduro/X related data... (if have one) */
0090     
0091     if (parse)
0092     {
0093         XID xid;
0094         size_t sz;
0095         
0096         memset(&xid, 0, sizeof(xid));
0097 
0098         sz = sizeof(xid);
0099         if (NULL==ndrx_xa_base64_decode((unsigned char *)tmxid, strlen(tmxid),
0100                 &sz, (char *)&xid))
0101         {
0102             NDRX_LOG(log_warn, "Failed to parse XID -> Corrupted base64?");
0103         }
0104         else
0105         {
0106             /* print general info */
0107             printf("DATA: formatID: 0x%lx (%s) gtrid_length: %ld bqual_length: %ld\n",
0108                     xid.formatID, 
0109                     ((NDRX_XID_FORMAT_ID==xid.formatID ||
0110                         NDRX_XID_FORMAT_ID==(long)ntohll(xid.formatID))?
0111                         "fmt OK":"Not Enduro/X or different arch"),
0112                     xid.gtrid_length, xid.bqual_length);
0113             
0114             /* print raw xid */
0115             STDOUT_DUMP(log_info,"RAW XID", &xid, sizeof(xid));
0116             
0117             if (NDRX_XID_FORMAT_ID==xid.formatID ||
0118                     NDRX_XID_FORMAT_ID==(long)ntohll(xid.formatID))
0119             {
0120                 short nodeid;
0121                 short srvid;
0122                 unsigned char rmid_start;
0123                 unsigned char rmid_cur;
0124                 long btid;
0125                 char xid_str[NDRX_XID_SERIAL_BUFSIZE];
0126                 
0127                 NDRX_LOG(log_debug, "Format OK");
0128                 
0129                 /* Print Enduro/X related xid data */
0130                 
0131                 atmi_xa_xid_get_info(&xid, &nodeid, 
0132                     &srvid, &rmid_start, &rmid_cur, &btid);
0133                 
0134                 /* the generic xid would be with out branch & current rmid */
0135                 
0136                 /* reset xid trailer to have original xid_str */
0137                 memset(xid.data + xid.gtrid_length - 
0138                     sizeof(long) - sizeof(unsigned char), 
0139                         0, sizeof(long)+sizeof(unsigned char));
0140                 
0141                 atmi_xa_serialize_xid(&xid, xid_str);
0142                 
0143                 printf("DETAILS: tm_nodeid: %hd tm_srvid: %hd tm_rmid: %d cur_rmid: %d btid: %ld\n",
0144                         nodeid, srvid, (int)rmid_start, (int)rmid_cur, btid);
0145                 printf("XID_STR: [%s]\n", xid_str);
0146             }
0147             
0148         }
0149     }
0150     
0151      /* Check do we have error fields? of so then print the status? */
0152     
0153     if (Bpres(p_ub, TMERR_CODE, 0))
0154     {
0155         char msg[MAX_TP_ERROR_LEN+1] = {EXEOS};
0156         short code;
0157         short reason = 0;
0158 
0159         Bget(p_ub, TMERR_CODE, 0, (char *)&code, 0L);
0160         Bget(p_ub, TMERR_REASON, 0, (char *)&reason, 0L);
0161         len = sizeof(msg);
0162         Bget(p_ub, TMERR_MSG, 0, msg, &len);
0163         
0164         if (0==code && EXEOS==msg[0])
0165         {
0166             NDRX_STRCPY_SAFE(msg, "SUCCEED");
0167         }
0168         
0169         printf("RESULT: tp code: %hd, xa reason: %hd, msg: %s\n", code, reason, msg);
0170         
0171     }
0172     
0173 out:
0174     return ret;
0175 }
0176 
0177 /**
0178  * This basically tests the normal case when all have been finished OK!
0179  * @return
0180  */
0181 exprivate int call_tm(UBFH *p_ub, char *svcnm, short parse)
0182 {
0183     int ret=EXSUCCEED;
0184     int cd;
0185     long revent;
0186     int recv_continue = 1;
0187     int tp_errno;
0188     
0189     /* Setup the call buffer... */
0190     if (NULL==p_ub)
0191     {
0192         NDRX_LOG(log_error, "Failed to alloc FB!");
0193         EXFAIL_OUT(ret);
0194     }
0195     
0196     /* reset the call buffer only to request fields... */
0197     if (EXSUCCEED!=atmi_xa_reset_tm_call(p_ub))
0198     {
0199         NDRX_LOG(log_error, "Failed to prepare UBF for TM call!");
0200         EXFAIL_OUT(ret);
0201     }
0202     
0203     if (EXFAIL == (cd = tpconnect(svcnm,
0204                                     (char *)p_ub,
0205                                     0,
0206                                     TPNOTRAN |
0207                                     TPRECVONLY)))
0208     {
0209         NDRX_LOG(log_error, "Connect error [%s]", tpstrerror(tperrno) );
0210         ret = EXFAIL;
0211         goto out;
0212     }
0213     NDRX_LOG(log_debug, "Connected OK, cd = %d", cd );
0214 
0215     while (recv_continue)
0216     {
0217         recv_continue=0;
0218         if (EXFAIL == tprecv(cd,
0219                             (char **)&p_ub,
0220                             0L,
0221                             0L,
0222                             &revent))
0223         {
0224             ret = EXFAIL;
0225             tp_errno = tperrno;
0226             if (TPEEVENT == tp_errno)
0227             {
0228                     if (TPEV_SVCSUCC == revent)
0229                             ret = EXSUCCEED;
0230                     else
0231                     {
0232                         NDRX_LOG(log_error,
0233                                  "Unexpected conv event %lx", revent );
0234                         EXFAIL_OUT(ret);
0235                     }
0236             }
0237             else
0238             {
0239                 NDRX_LOG(log_error, "recv error %d", tp_errno  );
0240                 EXFAIL_OUT(ret);
0241             }
0242         }
0243         else
0244         {
0245             /*fprintf(stderr, "Response: \n");
0246             Bfprint(p_ub, stderr);*/
0247             if (EXSUCCEED!=print_buffer(p_ub, svcnm, parse))
0248             {
0249                 EXFAIL_OUT(ret);
0250             }
0251             M_rcv_count++;
0252             recv_continue=1;
0253         }
0254     }
0255 
0256 out:
0257     
0258 /*
0259     tpdiscon(cd);
0260 */
0261     return ret;
0262 }
0263 
0264 /**
0265  * Print local transactions for all or particular TM
0266  * @param p_cmd_map
0267  * @param argc
0268  * @param argv
0269  * @return SUCCEED
0270  */
0271 expublic int cmd_recoverlocal(cmd_mapping_t *p_cmd_map, int argc, 
0272         char **argv, int *p_have_next)
0273 {
0274     int ret = EXSUCCEED;
0275     atmi_svc_list_t *el, *tmp, *list;
0276     char svcnm[MAXTIDENT+1]={EXEOS};
0277     UBFH *p_ub = atmi_xa_alloc_tm_call(ATMI_XA_RECOVERLOCAL);
0278     short parse = EXFALSE;
0279     
0280     ncloptmap_t clopt[] =
0281     {
0282         {'s', BFLD_STRING, (void *)svcnm, sizeof(svcnm), 
0283                                 NCLOPT_OPT|NCLOPT_HAVE_VALUE, "TM Service Name"},
0284         {'p', BFLD_SHORT, (void *)&parse, 0, 
0285                                 NCLOPT_OPT | NCLOPT_TRUEBOOL, "Parse xid"},
0286         {0}
0287     };
0288     
0289     if (NULL==p_ub)
0290     {
0291         NDRX_LOG(log_error, "Failed to alloc UBF!");
0292         EXFAIL_OUT(ret);
0293     }
0294     
0295     /* parse command line */
0296     if (nstd_parse_clopt(clopt, EXTRUE,  argc, argv, EXFALSE))
0297     {
0298         fprintf(stderr, XADMIN_INVALID_OPTIONS_MSG);
0299         EXFAIL_OUT(ret);
0300     }
0301     
0302     /* we need to init TP subsystem... */
0303     if (EXSUCCEED!=tpinit(NULL))
0304     {
0305         fprintf(stderr, "Failed to tpinit(): %s\n", tpstrerror(tperrno));
0306         EXFAIL_OUT(ret);
0307     }
0308     
0309     M_rcv_count = 0;
0310     
0311     if (EXEOS!=svcnm[0])
0312     {
0313         NDRX_LOG(log_debug, "TM Service name specified: [%s]", svcnm);
0314         ret = call_tm(p_ub, svcnm, parse);
0315     }
0316     else
0317     {
0318         NDRX_LOG(log_debug, "TM Service name not specified - query all");
0319         
0320         list = ndrx_get_svc_list(ndrx_tmfilter_common);
0321 
0322         LL_FOREACH_SAFE(list,el,tmp)
0323         {
0324 
0325             NDRX_LOG(log_info, "About to call service: [%s]\n", el->svcnm);
0326 
0327             ret = call_tm(p_ub, el->svcnm, parse);
0328             /* Have some housekeep. */
0329             LL_DELETE(list,el);
0330             NDRX_FREE(el);
0331         }
0332     }
0333     
0334     fprintf(stderr, "Recovered %d transactions\n", M_rcv_count);
0335     
0336 out:
0337     
0338     if (NULL!=p_ub)
0339     {
0340         tpfree((char *)p_ub);
0341     }
0342 
0343     return ret;
0344 }
0345 
0346 /**
0347  * Perform commit/abort/forget for particular xid.
0348  * @param msg message for confirm
0349  * @param tmcmd ATMI_XA_COMMITLOCAL /  ATMI_XA_ABORTLOCAL / ATMI_XA_FORGETLOCAL
0350  * @param p_cmd_map
0351  * @param argc
0352  * @param argv
0353  * @param p_have_next
0354  * @return 
0355  */
0356 exprivate int cmd_x_local(char *msg, char tmcmd, cmd_mapping_t *p_cmd_map, 
0357         int argc, char **argv, int *p_have_next)
0358 {
0359     int ret = EXSUCCEED;
0360     atmi_svc_list_t *el, *tmp, *list;
0361     char svcnm[MAXTIDENT+1]={EXEOS};
0362     char xid[sizeof(XID)*2] = {EXEOS};
0363     char msgfmt[128];
0364     short confirm = EXFALSE;
0365     short parse = EXFALSE;
0366     
0367     UBFH *p_ub = atmi_xa_alloc_tm_call(tmcmd);
0368     
0369     ncloptmap_t clopt[] =
0370     {
0371         {'s', BFLD_STRING, (void *)svcnm, sizeof(svcnm), 
0372                                 NCLOPT_OPT|NCLOPT_HAVE_VALUE, "TM Service Name"},
0373         {'x', BFLD_STRING, (void *)xid, sizeof(xid), 
0374                                 NCLOPT_OPT|NCLOPT_HAVE_VALUE, 
0375                                 "XID to process (for recoverlocal output)"},
0376         {'y', BFLD_SHORT, (void *)&confirm, 0, 
0377                                 NCLOPT_OPT | NCLOPT_TRUEBOOL, "Confirm"},
0378         {'p', BFLD_SHORT, (void *)&parse, 0, 
0379                                 NCLOPT_OPT | NCLOPT_TRUEBOOL, "Parse xid"},
0380                                 
0381         {0}
0382     };
0383     
0384     /* we need to init TP subsystem... */
0385     if (EXSUCCEED!=tpinit(NULL))
0386     {
0387         fprintf(stderr, "Failed to tpinit(): %s\n", tpstrerror(tperrno));
0388         EXFAIL_OUT(ret);
0389     }
0390     
0391     if (NULL==p_ub)
0392     {
0393         NDRX_LOG(log_error, "Failed to alloc UBF!");
0394         EXFAIL_OUT(ret);
0395     }
0396     
0397     /* parse command line */
0398     if (nstd_parse_clopt(clopt, EXTRUE,  argc, argv, EXFALSE))
0399     {
0400         fprintf(stderr, XADMIN_INVALID_OPTIONS_MSG);
0401         EXFAIL_OUT(ret);
0402     }
0403     
0404     
0405     if (EXEOS!=xid[0] && EXEOS==svcnm[0])
0406     {
0407         fprintf(stderr, "ERROR ! If -x is specified, the -s must be set too!\n");
0408     }
0409     
0410     snprintf(msgfmt, sizeof(msgfmt), "Are you sure you want to %s the transaction?", 
0411             msg);
0412     
0413     /* Check for confirmation */
0414     if (!ndrx_chk_confirm(msgfmt, confirm))
0415     {
0416         EXFAIL_OUT(ret);
0417     }
0418     
0419     /* load the settings to UBF */
0420     M_rcv_count = 0;
0421     
0422     if (EXEOS!=xid[0] && EXSUCCEED!=Bchg(p_ub, TMXID, 0, xid, 0))
0423     {
0424         NDRX_LOG(log_error, "Failed to set TMXID: %s", Bstrerror(Berror));
0425         EXFAIL_OUT(ret);
0426     }
0427     
0428     if (EXEOS!=svcnm[0])
0429     {
0430         NDRX_LOG(log_debug, "TM Service name specified: [%s]", svcnm);
0431         ret = call_tm(p_ub, svcnm, parse);
0432     }
0433     else
0434     {
0435         NDRX_LOG(log_debug, "TM Service name not specified - query all");
0436         
0437         list = ndrx_get_svc_list(ndrx_tmfilter_common);
0438 
0439         LL_FOREACH_SAFE(list,el,tmp)
0440         {
0441 
0442             NDRX_LOG(log_info, "About to call service: [%s]\n", el->svcnm);
0443 
0444             ret = call_tm(p_ub, el->svcnm, parse);
0445             /* Have some housekeep. */
0446             LL_DELETE(list,el);
0447             NDRX_FREE(el);
0448         }
0449     }
0450     
0451     fprintf(stderr, "Processed %d transactions\n", M_rcv_count);
0452     
0453 out:
0454     
0455     if (NULL!=p_ub)
0456     {
0457         tpfree((char *)p_ub);
0458     }
0459 
0460     return ret;
0461 }
0462 
0463 /**
0464  * Commit local transactions
0465  */
0466 expublic int cmd_commitlocal(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next)
0467 {
0468     return cmd_x_local("commit", ATMI_XA_COMMITLOCAL, p_cmd_map, argc, argv, p_have_next);
0469 }
0470 
0471 /**
0472  * Abort local transactions
0473  */
0474 expublic int cmd_abortlocal(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next)
0475 {
0476     return cmd_x_local("abort", ATMI_XA_ABORTLOCAL, p_cmd_map, argc, argv, p_have_next);
0477 }
0478 
0479 /**
0480  * Forget local transactions
0481  */
0482 expublic int cmd_forgetlocal(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next)
0483 {
0484     return cmd_x_local("forget", ATMI_XA_FORGETLOCAL, p_cmd_map, argc, argv, p_have_next);
0485 }
0486 
0487 
0488 /* vim: set ts=4 sw=4 et smartindent: */