Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief XA tracking switch may produce different output results for different
0003  *  configuration, with purpose of diagnostics of the state machines.
0004  *
0005  * @file xatracesw.c
0006  */
0007 /* -----------------------------------------------------------------------------
0008  * Enduro/X Middleware Platform for Distributed Transaction Processing
0009  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0010  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0011  * This software is released under one of the following licenses:
0012  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0013  * See LICENSE file for full text.
0014  * -----------------------------------------------------------------------------
0015  * AGPL license:
0016  *
0017  * This program is free software; you can redistribute it and/or modify it under
0018  * the terms of the GNU Affero General Public License, version 3 as published
0019  * by the Free Software Foundation;
0020  *
0021  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0022  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0023  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0024  * for more details.
0025  *
0026  * You should have received a copy of the GNU Affero General Public License along 
0027  * with this program; if not, write to the Free Software Foundation, Inc.,
0028  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0029  *
0030  * -----------------------------------------------------------------------------
0031  * A commercial use license is available from Mavimax, Ltd
0032  * contact@mavimax.com
0033  * -----------------------------------------------------------------------------
0034  */
0035 #include <string.h>
0036 #include <stdio.h>
0037 #include <stdlib.h>
0038 #include <errno.h>
0039 #include <ndrstandard.h>
0040 #include <xa.h>
0041 #include <userlog.h>
0042 #include <tmenv.h>
0043 #include <thlock.h>
0044 #include <sys_unix.h>
0045 
0046 #include "ndebug.h"
0047 /*---------------------------Externs------------------------------------*/
0048 /*---------------------------Macros-------------------------------------*/
0049 #ifdef TEST_RM1
0050 
0051 #define TEST_LOGFILE    "lib1.log"
0052 #define TEST_RETS       "lib1.rets"
0053 #define TRM             "RM1"
0054 
0055 #else
0056 
0057 #define TEST_LOGFILE    "lib2.log"
0058 #define TEST_RETS       "lib2.rets"
0059 #define TRM             "RM2"
0060 
0061 #endif
0062 
0063 #define MAX_LEN     1024    /**< Max command len                        */
0064 #define NR_SETTINGS 5       /**< Number of settings used                */
0065 
0066 #define SETTING_FUNC        0
0067 #define SETTING_RET1        1
0068 #define SETTING_CNT         2
0069 #define SETTING_RET2        3
0070 #define SETTING_PROC        4   /**< To which process this setting applies? */
0071 
0072 /*---------------------------Enums--------------------------------------*/
0073 /*---------------------------Typedefs-----------------------------------*/
0074 /*---------------------------Globals------------------------------------*/
0075 /*---------------------------Statics------------------------------------*/
0076 exprivate MUTEX_LOCKDECL(M_init);
0077 __thread int M_is_open = 0;
0078 __thread int M_rmid = -1;
0079 __thread int M_is_reg = 0; /* Dynamic registration done? */
0080 /*---------------------------Prototypes---------------------------------*/
0081 
0082 static int xa_open_entry(char *xa_info, int rmid, long flags);
0083 static int xa_close_entry(char *xa_info, int rmid, long flags);
0084 static int xa_start_entry(XID *xid, int rmid, long flags);
0085 static int xa_end_entry(XID *xid, int rmid, long flags);
0086 static int xa_rollback_entry(XID *xid, int rmid, long flags);
0087 static int xa_prepare_entry(XID *xid, int rmid, long flags);
0088 static int xa_commit_entry(XID *xid, int rmid, long flags);
0089 static int xa_recover_entry(XID *xid, long count, int rmid, long flags);
0090 static int xa_forget_entry(XID *xid, int rmid, long flags);
0091 static int xa_complete_entry(int *handle, int *retval, int rmid, long flags);
0092 
0093 /* Also needs to configure the flags
0094  * we might want to perform testing when JOIN is available
0095  * and we might want check the cases when JOIN is disabled.
0096  */
0097 struct xa_switch_t exxaswitch = 
0098 { 
0099     .name = "exxaswitch",
0100     .flags = TMNOFLAGS,
0101     .version = 0,
0102     .xa_open_entry = xa_open_entry,
0103     .xa_close_entry = xa_close_entry,
0104     .xa_start_entry = xa_start_entry,
0105     .xa_end_entry = xa_end_entry,
0106     .xa_rollback_entry = xa_rollback_entry,
0107     .xa_prepare_entry = xa_prepare_entry,
0108     .xa_commit_entry = xa_commit_entry,
0109     .xa_recover_entry = xa_recover_entry,
0110     .xa_forget_entry = xa_forget_entry,
0111     .xa_complete_entry = xa_complete_entry
0112 };
0113 
0114 /**
0115  * Get command code
0116  * @param func function that asks for return code
0117  * @param cntr counter of try
0118  * @return XA return code
0119  */
0120 static int get_return_code(const char *func, int *cntr)
0121 {
0122     FILE* fp;
0123     char buffer[MAX_LEN];
0124     int matched = 0;
0125     char *setting, *saveptr1;
0126     char *all_settings[NR_SETTINGS];
0127     int i, line=0, ret;
0128     static __thread char progname[PATH_MAX+1];
0129     static __thread int first = EXTRUE;
0130     
0131     if (first)
0132     {
0133         NDRX_STRCPY_SAFE(progname, EX_PROGNAME);
0134         first = EXFALSE;
0135     }
0136 
0137     fp = fopen(TEST_RETS, "r");
0138     
0139     if (fp == NULL)
0140     {
0141       perror("Failed to open return file: " TEST_RETS);
0142       exit(1);
0143     }
0144 
0145     while (fgets(buffer, MAX_LEN - 1, fp))
0146     {
0147         
0148         memset(all_settings, 0, sizeof(all_settings));
0149         
0150         /* Remove trailing newline */
0151         buffer[strcspn(buffer, "\n")] = 0;
0152         buffer[strcspn(buffer, "\r")] = 0;
0153     
0154         /* format  is
0155          * func_name;ret1;attempts;ret2
0156          * where func_name is matched by func
0157          * ret1 is returned while cntr < attempts
0158          * ret2 if returned if cntr>= attempts
0159          */
0160         for (i=0, setting=strtok_r(buffer, ":", &saveptr1); 
0161                 NULL!=setting && i<NR_SETTINGS; 
0162                 i++, setting=strtok_r(NULL, ":", &saveptr1))
0163         {
0164             NDRX_LOG(log_error, "LOADING: [%s]", setting);
0165             all_settings[i] = setting;
0166         }
0167         
0168         if (i<NR_SETTINGS-1)
0169         {
0170             userlog( TRM ": Invalid settings, line %d expect args %d got %d", 
0171                     line, NR_SETTINGS, i);
0172             exit(-1);
0173         }
0174         
0175         if (0==strcmp(all_settings[SETTING_FUNC], func) && 
0176                 ((NULL==all_settings[SETTING_PROC]) ||
0177                     (NULL!=all_settings[SETTING_PROC] && NULL!=strstr(progname, all_settings[SETTING_PROC]))
0178                 ))
0179         {
0180             NDRX_LOG(log_error, TRM ": Matched [%s]", func);
0181             matched=1;
0182             break;
0183         }
0184         
0185         line++;
0186     }
0187     
0188     fclose(fp);
0189     
0190     if (!matched)
0191     {
0192         userlog(TRM ": func not found [%s]", func);
0193         NDRX_LOG(log_error, TRM ": func not found [%s]", func);
0194         exit(-1);
0195     }
0196     
0197     /* start to process the command */
0198     
0199     if (*cntr < atoi(all_settings[SETTING_CNT]))
0200     {
0201         *cntr = *cntr + 1;
0202         ret=atoi(all_settings[SETTING_RET1]);
0203         NDRX_LOG(log_error, "%s counter: %d ret [%d]", func, *cntr, ret);
0204         
0205     }
0206     else
0207     {
0208         ret=atoi(all_settings[SETTING_RET2]);
0209         NDRX_LOG(log_error, "%s counter: %d ret [%d]", func, *cntr, ret);
0210     }
0211     
0212     userlog(TRM ": FUNC [%s] return %d", func, ret);
0213     
0214     return ret;
0215 }
0216 
0217 
0218 #define ATTEMPT(closed_OK) do {\
0219         static int attempt = 0;\
0220         if (!closed_OK && !M_is_open) \
0221         {\
0222             return XAER_RMERR;\
0223         }\
0224         userlog(TRM ": %s attempt=%d rmid=%d flags=%ld (TMASYNC=%d TMONEPHASE=%d "\
0225         "TMFAIL=%d TMNOWAIT=%d TMRESUME=%d TMSUCCESS=%d TMSUSPEND=%d TMSTARTRSCAN=%d TMENDRSCAN=%d TMMULTIPLE=%d TMJOIN=%d TMMIGRATE=%d)",\
0226             __func__, attempt, rmid, flags,\
0227             !!(flags & TMASYNC),\
0228             !!(flags & TMONEPHASE),\
0229             !!(flags & TMFAIL),\
0230             !!(flags & TMNOWAIT),\
0231             !!(flags & TMRESUME),\
0232             !!(flags & TMSUCCESS),\
0233             !!(flags & TMSUSPEND),\
0234             !!(flags & TMSTARTRSCAN),\
0235             !!(flags & TMENDRSCAN),\
0236             !!(flags & TMMULTIPLE),\
0237             !!(flags & TMJOIN),\
0238             !!(flags & TMMIGRATE));\
0239         return get_return_code(__func__, &attempt);\
0240     } while (0)
0241 
0242 static int xa_open_entry(char *xa_info, int rmid, long flags)
0243 {
0244     static int first=EXTRUE;
0245 
0246 #ifdef TEST_NOJOIN
0247     /* mark that suspend no required by this resource... */
0248     if (first)
0249     {
0250         MUTEX_LOCK_V(M_init);
0251         if (first)
0252         {
0253             ndrx_xa_nojoin(EXTRUE);
0254             first=EXFALSE;
0255         }
0256         MUTEX_UNLOCK_V(M_init);
0257     }
0258 #endif
0259     
0260     if (M_is_open)
0261     {
0262         return XAER_RMERR;
0263     }
0264 
0265     M_is_open = 1;
0266     M_rmid = rmid;
0267              
0268     /* return XA_OK; */
0269     
0270     ATTEMPT(EXFALSE);
0271 }
0272 
0273 static int xa_close_entry(char *xa_info, int rmid, long flags)
0274 {   
0275     if (!M_is_open)
0276     {
0277         return XAER_RMERR;
0278     }
0279     
0280     M_is_open = 0;
0281     /* return XA_OK; */
0282     
0283     ATTEMPT(EXTRUE);
0284 }
0285 
0286 static int xa_start_entry(XID *xid, int rmid, long flags)
0287 {    
0288     ATTEMPT(EXFALSE);
0289 }
0290 
0291 static int xa_end_entry(XID *xid, int rmid, long flags)
0292 {
0293     ATTEMPT(EXFALSE);
0294 }
0295 
0296 static int xa_rollback_entry(XID *xid, int rmid, long flags)
0297 {
0298     ATTEMPT(EXFALSE);
0299 }
0300 
0301 static int xa_prepare_entry(XID *xid, int rmid, long flags)
0302 {
0303     ATTEMPT(EXFALSE);
0304 }
0305 
0306 static int xa_commit_entry(XID *xid, int rmid, long flags)
0307 {
0308     ATTEMPT(EXFALSE);
0309 }
0310 
0311 static int xa_recover_entry(XID *xid, long count, int rmid, long flags)
0312 {
0313     ATTEMPT(EXFALSE);
0314 }
0315 
0316 static int xa_forget_entry(XID *xid, int rmid, long flags)
0317 {
0318     ATTEMPT(EXFALSE);
0319 }
0320 
0321 static int xa_complete_entry(int *handle, int *retval, int rmid, long flags)
0322 {
0323     ATTEMPT(EXFALSE);
0324 }
0325 
0326 /* vim: set ts=4 sw=4 et smartindent: */