Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief State transition handling of XA transactions
0003  *
0004  * @file xastates.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 <stdint.h>
0037 #include <stdlib.h>
0038 #include <memory.h>
0039 #include <errno.h>
0040 #include <dlfcn.h>
0041 #include <limits.h>
0042 
0043 #include <atmi.h>
0044 #include <atmi_shm.h>
0045 #include <ndrstandard.h>
0046 #include <ndebug.h>
0047 #include <ndrxdcmn.h>
0048 #include <userlog.h>
0049 #include <xa_cmn.h>
0050 /*---------------------------Externs------------------------------------*/
0051 /*---------------------------Macros-------------------------------------*/
0052 /*---------------------------Enums--------------------------------------*/
0053 /*---------------------------Typedefs-----------------------------------*/
0054 /*---------------------------Globals------------------------------------*/
0055 /*---------------------------Statics------------------------------------*/
0056 
0057 /**
0058  * Static branch driver
0059  * We will have two drives of all of this:
0060  * 1. Get new RM status (driven by current stage, status, operation and outcome)
0061  * 2. Get new TX state (Driven by current TX stage, and RM new status)
0062  * And the for file TX outcome we should select the stage with lower number...
0063  */
0064 
0065 /* =========================================================================
0066  * Driving of the PREPARING: 
0067  * =========================================================================
0068  */
0069 exprivate rmstatus_driver_t M_rm_status_driver_preparing[] =
0070 {  
0071     /* ok: */
0072     {XA_TX_STAGE_PREPARING, XA_RM_STATUS_ACTIVE, XA_OP_PREPARE, XA_OK,     XA_OK,     XA_RM_STATUS_PREP,          XA_TX_STAGE_COMMITTING},
0073     /* read only assumed as committed: */
0074     {XA_TX_STAGE_PREPARING, XA_RM_STATUS_ACTIVE, XA_OP_PREPARE, XA_RDONLY, XA_RDONLY, XA_RM_STATUS_COMMITTED_RO,  XA_TX_STAGE_COMMITTING},
0075     /* If no transaction, then assume committed, read only: */
0076     {XA_TX_STAGE_PREPARING, XA_RM_STATUS_ACTIVE, XA_OP_PREPARE, XAER_NOTA, XAER_NOTA, XA_RM_STATUS_ABORTED,       XA_TX_STAGE_ABORTING},
0077     /* Shall we perform any action here? */
0078     {XA_TX_STAGE_PREPARING, XA_RM_STATUS_ACTIVE, XA_OP_PREPARE, XA_RBBASE, XA_RBEND,  XA_RM_STATUS_ABORTED,       XA_TX_STAGE_ABORTING},
0079     /* Any error out of the range (catched, we scan from the start) causes abort sequence to run */
0080     {XA_TX_STAGE_PREPARING, XA_RM_STATUS_ACTIVE, XA_OP_PREPARE, INT_MIN,INT_MAX,      XA_RM_STATUS_ACT_AB,        XA_TX_STAGE_ABORTING},
0081     /* for PostgreSQL we have strange situation, that only case to work in distributed way is to mark the transaction as
0082      * prepared once the processing thread disconnects. Thus even transaction is active, the resource is prepared.
0083      */
0084     {XA_TX_STAGE_PREPARING, XA_RM_STATUS_PREP,   XA_OP_NOP,     XA_OK,XA_OK,          XA_RM_STATUS_PREP,          XA_TX_STAGE_COMMITTING},
0085     /* If recovered from logs where decision is not yet logged, but was logged that this particular RM wants abort: */
0086     {XA_TX_STAGE_PREPARING, XA_RM_STATUS_ACT_AB, XA_OP_NOP,     XA_OK,XA_OK,          XA_RM_STATUS_ACT_AB,        XA_TX_STAGE_ABORTING},
0087     /* If restarted, vote for abort, thought after the restart we enter automatically in abort sequence */
0088     {XA_TX_STAGE_PREPARING, XA_RM_STATUS_ABORTED,XA_OP_NOP,     XA_OK,XA_OK,          XA_RM_STATUS_ABORTED,       XA_TX_STAGE_ABORTING},
0089     /* if restarted, vote for commit */
0090     {XA_TX_STAGE_PREPARING, XA_RM_STATUS_COMMITTED_RO,XA_OP_NOP,XA_OK,XA_OK,          XA_RM_STATUS_COMMITTED_RO,  XA_TX_STAGE_COMMITTING},
0091     
0092     {EXFAIL}
0093 };
0094 
0095 /* =========================================================================
0096  * Driving of the COMMITTING 
0097  * =========================================================================
0098  */
0099 exprivate rmstatus_driver_t M_rm_status_driver_committing[] =
0100 {  
0101     /* ok: */
0102     {XA_TX_STAGE_COMMITTING, XA_RM_STATUS_PREP,          XA_OP_COMMIT,  XA_OK,      XA_OK,      XA_RM_STATUS_COMMITTED,     XA_TX_STAGE_COMMITTED},
0103     /* In case of error: assuming heuristic results: */
0104     {XA_TX_STAGE_COMMITTING, XA_RM_STATUS_PREP,          XA_OP_COMMIT,  XAER_RMERR, XAER_RMERR, XA_RM_STATUS_COMMIT_HEURIS, XA_TX_STAGE_COMMITTED_HEURIS},
0105     /* If RM failed, retry (will be hazard error): */
0106     {XA_TX_STAGE_COMMITTING, XA_RM_STATUS_PREP,          XA_OP_COMMIT,  XAER_RMFAIL,XAER_RMFAIL,XA_RM_STATUS_PREP,          XA_TX_STAGE_COMMITTING},
0107     /* If RM failed, retry (will be hazard error): */
0108     {XA_TX_STAGE_COMMITTING, XA_RM_STATUS_PREP,          XA_OP_COMMIT,  XA_RETRY,   XA_RETRY,   XA_RM_STATUS_PREP,          XA_TX_STAGE_COMMITTING},
0109     /* TPEHAZARD + xa_forget */
0110     {XA_TX_STAGE_COMMITTING, XA_RM_STATUS_PREP,          XA_OP_COMMIT,  XA_HEURHAZ, XA_HEURHAZ, XA_RM_STATUS_COMFORGET_HAZ, XA_TX_STAGE_COMFORGETTING},
0111     /* TPEHEURISTIC + xa_forget */
0112     {XA_TX_STAGE_COMMITTING, XA_RM_STATUS_PREP,          XA_OP_COMMIT,  XA_HEURCOM, XA_HEURCOM, XA_RM_STATUS_COMFORGET_HEU, XA_TX_STAGE_COMFORGETTING},
0113     /* TPEHEURISTIC + xa_forget */
0114     {XA_TX_STAGE_COMMITTING, XA_RM_STATUS_PREP,          XA_OP_COMMIT,  XA_HEURRB,  XA_HEURRB,  XA_RM_STATUS_COMFORGET_HEU, XA_TX_STAGE_COMFORGETTING},
0115     /* TPEHEURISTIC + xa_forget */
0116     {XA_TX_STAGE_COMMITTING, XA_RM_STATUS_PREP,          XA_OP_COMMIT,  XA_HEURMIX, XA_HEURMIX, XA_RM_STATUS_COMFORGET_HEU, XA_TX_STAGE_COMFORGETTING},
0117     /* Rolled back: */
0118     {XA_TX_STAGE_COMMITTING, XA_RM_STATUS_PREP,          XA_OP_COMMIT,  XA_RBBASE,  XA_RBEND,   XA_RM_STATUS_ABORTED,       XA_TX_STAGE_COMMITTED_HEURIS},
0119     /* All unknown statuses will vote for committed: */
0120     {XA_TX_STAGE_COMMITTING, XA_RM_STATUS_PREP,          XA_OP_COMMIT,  INT_MIN,    INT_MAX,    XA_RM_STATUS_COMMITTED,     XA_TX_STAGE_COMMITTED},
0121     /* In case of restart - same results: */
0122     {XA_TX_STAGE_COMMITTING, XA_RM_STATUS_COMMIT_HEURIS, XA_OP_NOP,     XA_OK,  XA_OK,          XA_RM_STATUS_COMMIT_HEURIS, XA_TX_STAGE_COMMITTED_HEURIS},
0123     /* In case of restart - same results: */
0124     {XA_TX_STAGE_COMMITTING, XA_RM_STATUS_ABORTED,       XA_OP_NOP,     XA_OK,  XA_OK,          XA_RM_STATUS_ABORTED,       XA_TX_STAGE_COMMITTED_HEURIS},
0125     /* In case of restart - same results: */
0126     {XA_TX_STAGE_COMMITTING, XA_RM_STATUS_COMMIT_HAZARD, XA_OP_NOP,     XA_OK,  XA_OK,          XA_RM_STATUS_COMMIT_HAZARD, XA_TX_STAGE_COMMITTED_HAZARD},
0127     /* In case of restart - same results: */
0128     {XA_TX_STAGE_COMMITTING, XA_RM_STATUS_COMFORGET_HAZ, XA_OP_NOP,     XA_OK,  XA_OK,          XA_RM_STATUS_COMFORGET_HAZ, XA_TX_STAGE_COMFORGETTING},
0129     /* In case of restart - same results: */
0130     {XA_TX_STAGE_COMMITTING, XA_RM_STATUS_COMFORGET_HEU, XA_OP_NOP,     XA_OK,  XA_OK,          XA_RM_STATUS_COMFORGET_HEU, XA_TX_STAGE_COMFORGETTING},
0131     {EXFAIL}
0132 };
0133 
0134 /* =========================================================================
0135  * Driving of the COMMITTED, FORGETTGIN
0136  * =========================================================================
0137  */
0138 exprivate rmstatus_driver_t M_rm_status_driver_comforgetting[] =
0139 {  
0140     /* OK */
0141     {XA_TX_STAGE_COMFORGETTING, XA_RM_STATUS_COMFORGET_HAZ,   XA_OP_FORGET,  XA_OK,       XA_OK,       XA_RM_STATUS_COMMIT_HAZARD, XA_TX_STAGE_COMFORGOT_HAZ},
0142     {XA_TX_STAGE_COMFORGETTING, XA_RM_STATUS_COMFORGET_HEU,   XA_OP_FORGET,  XA_OK,       XA_OK,       XA_RM_STATUS_COMMIT_HEURIS, XA_TX_STAGE_COMFORGOT_HEU},
0143     /* retry on failure: */
0144     {XA_TX_STAGE_COMFORGETTING, XA_RM_STATUS_COMFORGET_HAZ,   XA_OP_FORGET,  XAER_RMFAIL, XAER_RMFAIL, XA_RM_STATUS_COMFORGET_HAZ, XA_TX_STAGE_COMFORGETTING},
0145     {XA_TX_STAGE_COMFORGETTING, XA_RM_STATUS_COMFORGET_HEU,   XA_OP_FORGET,  XAER_RMFAIL, XAER_RMFAIL, XA_RM_STATUS_COMFORGET_HEU, XA_TX_STAGE_COMFORGETTING},
0146     /* All other assume completed: */
0147     {XA_TX_STAGE_COMFORGETTING, XA_RM_STATUS_COMFORGET_HAZ,   XA_OP_FORGET,  INT_MIN,    INT_MAX,      XA_RM_STATUS_COMMIT_HAZARD, XA_TX_STAGE_COMFORGOT_HAZ},
0148     {XA_TX_STAGE_COMFORGETTING, XA_RM_STATUS_COMFORGET_HEU,   XA_OP_FORGET,  INT_MIN,    INT_MAX,      XA_RM_STATUS_COMMIT_HEURIS, XA_TX_STAGE_COMFORGOT_HEU},
0149     /* Status reporting in restart: */
0150     {XA_TX_STAGE_COMFORGETTING, XA_RM_STATUS_COMMIT_HAZARD,   XA_OP_NOP,     XA_OK,       XA_OK,       XA_RM_STATUS_COMMIT_HAZARD, XA_TX_STAGE_COMFORGOT_HAZ},
0151     {XA_TX_STAGE_COMFORGETTING, XA_RM_STATUS_COMMIT_HEURIS,   XA_OP_NOP,     XA_OK,       XA_OK,       XA_RM_STATUS_COMMIT_HEURIS, XA_TX_STAGE_COMFORGOT_HEU},
0152     
0153     {EXFAIL}
0154 };
0155 /* =========================================================================
0156  * Driving of ABORTING:  
0157  * =========================================================================
0158  */
0159 exprivate rmstatus_driver_t M_rm_status_driver_aborting[] =
0160 {  
0161     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_ACT_AB, XA_OP_ROLLBACK, XA_OK,      XA_OK,      XA_RM_STATUS_ABORTED,      XA_TX_STAGE_ABORTED},
0162     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_ACTIVE, XA_OP_ROLLBACK, XA_OK,      XA_OK,      XA_RM_STATUS_ABORTED,      XA_TX_STAGE_ABORTED},
0163     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_PREP,   XA_OP_ROLLBACK, XA_OK,      XA_OK,      XA_RM_STATUS_ABORTED,      XA_TX_STAGE_ABORTED},
0164     /* these are RO reported by end prep */
0165     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_COMMITTED_RO,XA_OP_NOP, XA_OK,      XA_OK,      XA_RM_STATUS_ABORTED,      XA_TX_STAGE_ABORTED},
0166     /* Really for active only, for other already it is a NOP: */
0167     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_ACT_AB, XA_OP_ROLLBACK, XA_RDONLY,  XA_RDONLY,  XA_RM_STATUS_ABORTED,      XA_TX_STAGE_ABORTED},
0168     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_ACTIVE, XA_OP_ROLLBACK, XA_RDONLY,  XA_RDONLY,  XA_RM_STATUS_ABORTED,      XA_TX_STAGE_ABORTED},
0169     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_PREP,   XA_OP_ROLLBACK, XA_RDONLY,  XA_RDONLY,  XA_RM_STATUS_ABORTED,      XA_TX_STAGE_ABORTED},
0170     
0171     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_ACT_AB, XA_OP_ROLLBACK, XA_HEURHAZ, XA_HEURHAZ, XA_RM_STATUS_ABFORGET_HAZ, XA_TX_STAGE_ABFORGETTING},
0172     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_ACTIVE, XA_OP_ROLLBACK, XA_HEURHAZ, XA_HEURHAZ, XA_RM_STATUS_ABFORGET_HAZ, XA_TX_STAGE_ABFORGETTING},
0173     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_PREP,   XA_OP_ROLLBACK, XA_HEURHAZ, XA_HEURHAZ, XA_RM_STATUS_ABFORGET_HAZ, XA_TX_STAGE_ABFORGETTING},
0174     
0175     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_ACT_AB, XA_OP_ROLLBACK, XA_HEURRB,  XA_HEURRB,  XA_RM_STATUS_ABFORGET_HEU, XA_TX_STAGE_ABFORGETTING},
0176     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_ACTIVE, XA_OP_ROLLBACK, XA_HEURRB,  XA_HEURRB,  XA_RM_STATUS_ABFORGET_HEU, XA_TX_STAGE_ABFORGETTING},
0177     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_PREP,   XA_OP_ROLLBACK, XA_HEURRB,  XA_HEURRB,  XA_RM_STATUS_ABFORGET_HEU, XA_TX_STAGE_ABFORGETTING},
0178     
0179     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_ACT_AB, XA_OP_ROLLBACK, XA_HEURCOM, XA_HEURCOM, XA_RM_STATUS_ABFORGET_HEU, XA_TX_STAGE_ABFORGETTING},
0180     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_ACTIVE, XA_OP_ROLLBACK, XA_HEURCOM, XA_HEURCOM, XA_RM_STATUS_ABFORGET_HEU, XA_TX_STAGE_ABFORGETTING},
0181     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_PREP,   XA_OP_ROLLBACK, XA_HEURCOM, XA_HEURCOM, XA_RM_STATUS_ABFORGET_HEU, XA_TX_STAGE_ABFORGETTING},
0182     
0183     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_ACT_AB, XA_OP_ROLLBACK, XA_HEURMIX, XA_HEURMIX, XA_RM_STATUS_ABFORGET_HEU, XA_TX_STAGE_ABFORGETTING},
0184     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_ACTIVE, XA_OP_ROLLBACK, XA_HEURMIX, XA_HEURMIX, XA_RM_STATUS_ABFORGET_HEU, XA_TX_STAGE_ABFORGETTING},
0185     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_PREP,   XA_OP_ROLLBACK, XA_HEURMIX, XA_HEURMIX, XA_RM_STATUS_ABFORGET_HEU, XA_TX_STAGE_ABFORGETTING},
0186     
0187     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_ACT_AB, XA_OP_ROLLBACK, XAER_RMFAIL,XAER_RMFAIL,XA_RM_STATUS_ACT_AB,       XA_TX_STAGE_ABORTING},
0188     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_ACTIVE, XA_OP_ROLLBACK, XAER_RMFAIL,XAER_RMFAIL,XA_RM_STATUS_ACTIVE,       XA_TX_STAGE_ABORTING},
0189     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_PREP,   XA_OP_ROLLBACK, XAER_RMFAIL,XAER_RMFAIL,XA_RM_STATUS_PREP,         XA_TX_STAGE_ABORTING},
0190 /*  well kind of not correct can retry via RECON flag
0191     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_ACT_AB, XA_OP_ROLLBACK, XAER_RMERR,XAER_RMERR,XA_RM_STATUS_ACT_AB,         XA_TX_STAGE_ABORTING},
0192     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_ACTIVE, XA_OP_ROLLBACK, XAER_RMERR,XAER_RMERR,XA_RM_STATUS_ACTIVE,         XA_TX_STAGE_ABORTING},
0193     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_PREP,   XA_OP_ROLLBACK, XAER_RMERR,XAER_RMERR,XA_RM_STATUS_PREP,           XA_TX_STAGE_ABORTING},
0194 */
0195     /* This is OK: */
0196     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_ACT_AB, XA_OP_ROLLBACK, XAER_NOTA,  XAER_NOTA,  XA_RM_STATUS_ABORTED,      XA_TX_STAGE_ABORTED},
0197     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_ACTIVE, XA_OP_ROLLBACK, XAER_NOTA,  XAER_NOTA,  XA_RM_STATUS_ABORTED,      XA_TX_STAGE_ABORTED},
0198     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_PREP,   XA_OP_ROLLBACK, XAER_NOTA,  XAER_NOTA,  XA_RM_STATUS_ABORTED,      XA_TX_STAGE_ABORTED},
0199     
0200     /* default all to aborted (reported to ulog error) */
0201     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_ACT_AB, XA_OP_ROLLBACK, INT_MIN,    INT_MAX,    XA_RM_STATUS_ABORTED,      XA_TX_STAGE_ABORTED},
0202     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_ACTIVE, XA_OP_ROLLBACK, INT_MIN,    INT_MAX,    XA_RM_STATUS_ABORTED,      XA_TX_STAGE_ABORTED},
0203     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_PREP,   XA_OP_ROLLBACK, INT_MIN,    INT_MAX,    XA_RM_STATUS_ABORTED,      XA_TX_STAGE_ABORTED},
0204     
0205     /* in case of restart keep the states to next */
0206     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_ABFORGET_HEU, XA_OP_NOP, XA_OK,     XA_OK,      XA_RM_STATUS_ABFORGET_HEU, XA_TX_STAGE_ABFORGETTING},
0207     {XA_TX_STAGE_ABORTING, XA_RM_STATUS_ABFORGET_HAZ, XA_OP_NOP, XA_OK,     XA_OK,      XA_RM_STATUS_ABFORGET_HAZ, XA_TX_STAGE_ABFORGETTING},
0208     
0209     {EXFAIL}
0210 };
0211 
0212 /* =========================================================================
0213  * Driving of the ABORTED, forgetting
0214  * =========================================================================
0215  */
0216 exprivate rmstatus_driver_t M_rm_status_driver_abforgetting[] =
0217 {  
0218     /* OK */
0219     {XA_TX_STAGE_ABFORGETTING, XA_RM_STATUS_ABFORGET_HAZ,   XA_OP_FORGET,  XA_OK,       XA_OK,       XA_RM_STATUS_ABORT_HAZARD, XA_TX_STAGE_ABFORGOT_HAZ},
0220     {XA_TX_STAGE_ABFORGETTING, XA_RM_STATUS_ABFORGET_HEU,   XA_OP_FORGET,  XA_OK,       XA_OK,       XA_RM_STATUS_ABORT_HEURIS, XA_TX_STAGE_ABFORGOT_HEU},
0221     /* retry on failure: */
0222     {XA_TX_STAGE_ABFORGETTING, XA_RM_STATUS_ABFORGET_HAZ,   XA_OP_FORGET,  XAER_RMFAIL, XAER_RMFAIL, XA_RM_STATUS_ABFORGET_HAZ, XA_TX_STAGE_ABFORGETTING},
0223     {XA_TX_STAGE_ABFORGETTING, XA_RM_STATUS_ABFORGET_HEU,   XA_OP_FORGET,  XAER_RMFAIL, XAER_RMFAIL, XA_RM_STATUS_ABFORGET_HEU, XA_TX_STAGE_ABFORGETTING},
0224     /* All other assume completed: */
0225     {XA_TX_STAGE_ABFORGETTING, XA_RM_STATUS_ABFORGET_HAZ,   XA_OP_FORGET,  INT_MIN,     INT_MAX,     XA_RM_STATUS_ABORT_HAZARD, XA_TX_STAGE_ABFORGOT_HAZ},
0226     {XA_TX_STAGE_ABFORGETTING, XA_RM_STATUS_ABFORGET_HEU,   XA_OP_FORGET,  INT_MIN,     INT_MAX,     XA_RM_STATUS_ABORT_HEURIS, XA_TX_STAGE_ABFORGOT_HEU},
0227     /* Status reporting in restart: */
0228     {XA_TX_STAGE_ABFORGETTING, XA_RM_STATUS_ABORT_HAZARD,   XA_OP_NOP,     XA_OK,       XA_OK,       XA_RM_STATUS_ABORT_HAZARD, XA_TX_STAGE_ABFORGOT_HAZ},
0229     {XA_TX_STAGE_ABFORGETTING, XA_RM_STATUS_ABORT_HEURIS,   XA_OP_NOP,     XA_OK,       XA_OK,       XA_RM_STATUS_ABORT_HEURIS, XA_TX_STAGE_ABFORGOT_HEU},
0230     
0231     {EXFAIL}
0232 };
0233 
0234 /**
0235  * If Stage/State not in list, then assume XA_OP_NOP
0236  */
0237 expublic txaction_driver_t G_txaction_driver[] =
0238 {  
0239     {XA_TX_STAGE_PREPARING,     XA_RM_STATUS_ACTIVE,        XA_OP_PREPARE},
0240     {XA_TX_STAGE_COMMITTING,    XA_RM_STATUS_PREP,          XA_OP_COMMIT},
0241     {XA_TX_STAGE_ABORTING,      XA_RM_STATUS_ACTIVE,        XA_OP_ROLLBACK},
0242     {XA_TX_STAGE_ABORTING,      XA_RM_STATUS_ACT_AB,        XA_OP_ROLLBACK},
0243     {XA_TX_STAGE_ABORTING,      XA_RM_STATUS_PREP,          XA_OP_ROLLBACK},
0244     /* drive the forget of committed: */
0245     {XA_TX_STAGE_COMFORGETTING, XA_RM_STATUS_COMFORGET_HAZ,     XA_OP_FORGET},
0246     {XA_TX_STAGE_COMFORGETTING, XA_RM_STATUS_COMFORGET_HEU,     XA_OP_FORGET},
0247     /* drive the  forget of aborted: */
0248     {XA_TX_STAGE_ABFORGETTING,  XA_RM_STATUS_ABFORGET_HAZ,      XA_OP_FORGET},
0249     {XA_TX_STAGE_ABFORGETTING,  XA_RM_STATUS_ABFORGET_HEU,      XA_OP_FORGET},
0250     {EXFAIL}
0251 };
0252 
0253 /**
0254  * State descriptors
0255  */
0256 expublic txstage_descriptor_t G_state_descriptor[] =
0257 {
0258 /* txstage                     txs_stage_min                 txs_min_complete             txs_max_complete  descr   allow_jump */
0259 {XA_TX_STAGE_NULL,             XA_TX_STAGE_NULL,             XA_TX_STAGE_NULL,            XA_TX_STAGE_NULL,             "NULL",                       EXFALSE},
0260 /* we get outside the ACTIVE state by API call or timeout */
0261 {XA_TX_STAGE_ACTIVE,           XA_TX_STAGE_NULL,             XA_TX_STAGE_NULL,            XA_TX_STAGE_NULL,             "ACTIVE",                     EXFALSE},
0262 {XA_TX_STAGE_ABORTING,         XA_TX_STAGE_ABORTING,         XA_TX_STAGE_ABORTED_HAZARD,  XA_TX_STAGE_ABORTED,          "ABORTING",                   EXFALSE},
0263 /* Left for compliance: */
0264 {XA_TX_STAGE_ABORTED_HAZARD,   XA_TX_STAGE_ABORTED_HAZARD,   XA_TX_STAGE_ABORTED_HAZARD,  XA_TX_STAGE_ABORTED_HAZARD,   "ABORTED_HAZARD",             EXFALSE},
0265 /* Left for compliance: */
0266 {XA_TX_STAGE_ABORTED_HEURIS,   XA_TX_STAGE_ABORTED_HEURIS,   XA_TX_STAGE_ABORTED_HEURIS,  XA_TX_STAGE_ABORTED_HEURIS,   "ABORTED_HEURIS",             EXFALSE},
0267 /* Left for compliance: */
0268 {XA_TX_STAGE_ABORTED,          XA_TX_STAGE_ABORTED,          XA_TX_STAGE_ABORTED,         XA_TX_STAGE_ABORTED,          "ABORTED",                    EXFALSE},
0269 /* Normally we jump out from PREPARING, in case if state not switched */
0270 {XA_TX_STAGE_PREPARING,        XA_TX_STAGE_PREPARING,        XA_TX_STAGE_PREPRO,          XA_TX_STAGE_PREPRO,           "PREPARING",                  EXTRUE},
0271 /* no participants: */
0272 {XA_TX_STAGE_PREPRO,           XA_TX_STAGE_PREPRO,           XA_TX_STAGE_PREPRO,          XA_TX_STAGE_PREPRO,           "NO_PARTICIPANTS",            EXFALSE},
0273 {XA_TX_STAGE_COMMITTING,       XA_TX_STAGE_COMMITTING,       XA_TX_STAGE_COMMITTED_HAZARD,XA_TX_STAGE_COMMITTED,        "COMMITTING",                 EXFALSE},
0274 /* Left for compliance: */
0275 {XA_TX_STAGE_COMMITTED_HAZARD, XA_TX_STAGE_COMMITTED_HAZARD, XA_TX_STAGE_COMMITTED_HAZARD,XA_TX_STAGE_COMMITTED_HAZARD, "COMMITTED_HAZARD",           EXFALSE},
0276 /* Left for compliance: */
0277 {XA_TX_STAGE_COMMITTED_HEURIS, XA_TX_STAGE_COMMITTED_HEURIS, XA_TX_STAGE_COMMITTED_HEURIS,XA_TX_STAGE_COMMITTED_HEURIS, "COMMITTED_HEURIS",           EXFALSE},
0278 /* Left for compliance: */
0279 {XA_TX_STAGE_COMMITTED,        XA_TX_STAGE_COMMITTED,        XA_TX_STAGE_COMMITTED,       XA_TX_STAGE_COMMITTED,        "COMMITTED",                  EXFALSE},
0280 /* Forgetting state of commit */
0281 {XA_TX_STAGE_COMFORGETTING,    XA_TX_STAGE_COMFORGETTING,    XA_TX_STAGE_COMFORGOT_HAZ,   XA_TX_STAGE_COMFORGOT_HEU,    "FORGETTING_COMMITTED",       EXFALSE},
0282 {XA_TX_STAGE_COMFORGOT_HAZ,    XA_TX_STAGE_COMFORGOT_HAZ,    XA_TX_STAGE_COMFORGOT_HAZ,   XA_TX_STAGE_COMFORGOT_HAZ,    "FORGOT_HAZARD_COMMITTED",    EXFALSE},
0283 {XA_TX_STAGE_COMFORGOT_HEU,    XA_TX_STAGE_COMFORGOT_HEU,    XA_TX_STAGE_COMFORGOT_HEU,   XA_TX_STAGE_COMFORGOT_HEU,    "FORGOT_HEURISTIC_COMMITTED", EXFALSE},
0284 
0285 /* Forgetting state of abort */
0286 {XA_TX_STAGE_ABFORGETTING,     XA_TX_STAGE_ABFORGETTING,     XA_TX_STAGE_ABFORGOT_HAZ,    XA_TX_STAGE_ABFORGOT_HEU,     "FORGETTING_ABORTED",         EXFALSE},
0287 {XA_TX_STAGE_ABFORGOT_HAZ,     XA_TX_STAGE_ABFORGOT_HAZ,     XA_TX_STAGE_ABFORGOT_HAZ,    XA_TX_STAGE_ABFORGOT_HAZ,     "FORGOT_HAZARD_ABORTED",      EXFALSE},
0288 {XA_TX_STAGE_ABFORGOT_HEU,     XA_TX_STAGE_ABFORGOT_HEU,     XA_TX_STAGE_ABFORGOT_HEU,    XA_TX_STAGE_ABFORGOT_HEU,     "FORGOT_HEURISTIC_ABORTED",   EXFALSE},
0289 
0290 
0291 {EXFAIL, 0, 0, 0, "FAIL"}
0292 };
0293 
0294 /**
0295  * Needs new table: state-to-tpreturn code mapper. 
0296  */
0297 expublic txstate2tperrno_t G_txstage2tperrno[] =
0298 {
0299 {XA_TX_STAGE_NULL,             XA_OP_COMMIT,    TPESYSTEM},
0300 {XA_TX_STAGE_ACTIVE,           XA_OP_COMMIT,    TPESYSTEM},
0301 /* If abort is logged, report error as TPEABORT */
0302 {XA_TX_STAGE_ABORTING,         XA_OP_COMMIT,    TPEABORT},
0303 {XA_TX_STAGE_ABORTED_HAZARD,   XA_OP_COMMIT,    TPEABORT},
0304 {XA_TX_STAGE_ABORTED_HEURIS,   XA_OP_COMMIT,    TPEABORT},
0305 {XA_TX_STAGE_ABORTED,          XA_OP_COMMIT,    TPEABORT},
0306 {XA_TX_STAGE_PREPARING,        XA_OP_COMMIT,    TPESYSTEM},
0307 {XA_TX_STAGE_PREPRO,           XA_OP_COMMIT,    EXSUCCEED},
0308 {XA_TX_STAGE_COMMITTING,       XA_OP_COMMIT,    TPEHAZARD},
0309 {XA_TX_STAGE_COMMITTED_HAZARD, XA_OP_COMMIT,    TPEHAZARD},
0310 {XA_TX_STAGE_COMMITTED_HEURIS, XA_OP_COMMIT,    TPEHEURISTIC},
0311 {XA_TX_STAGE_COMMITTED,        XA_OP_COMMIT,    EXSUCCEED},
0312 /* Heuristic completion, commit */
0313 {XA_TX_STAGE_COMFORGETTING,    XA_OP_COMMIT,    TPEHAZARD},
0314 {XA_TX_STAGE_COMFORGOT_HAZ,    XA_OP_COMMIT,    TPEHAZARD},
0315 {XA_TX_STAGE_COMFORGOT_HEU,    XA_OP_COMMIT,    TPEHEURISTIC},
0316 /* Heuristic completion, abort */
0317 {XA_TX_STAGE_ABFORGETTING,     XA_OP_COMMIT,    TPEHAZARD},
0318 /* Test the HEU/HAZ abort outcomes on commit... */
0319 {XA_TX_STAGE_ABFORGOT_HAZ,     XA_OP_COMMIT,    TPEABORT},
0320 {XA_TX_STAGE_ABFORGOT_HEU,     XA_OP_COMMIT,    TPEABORT},
0321 {XA_TX_STAGE_NULL,             XA_OP_ROLLBACK,  TPESYSTEM},
0322 {XA_TX_STAGE_ACTIVE,           XA_OP_ROLLBACK,  TPESYSTEM},
0323 {XA_TX_STAGE_ABORTING,         XA_OP_ROLLBACK,  TPEHAZARD},
0324 {XA_TX_STAGE_ABORTED_HAZARD,   XA_OP_ROLLBACK,  TPEHAZARD},
0325 {XA_TX_STAGE_ABORTED_HEURIS,   XA_OP_ROLLBACK,  TPEHEURISTIC},
0326 {XA_TX_STAGE_ABORTED,          XA_OP_ROLLBACK,  EXSUCCEED},
0327 {XA_TX_STAGE_PREPARING,        XA_OP_ROLLBACK,  TPESYSTEM},
0328 /* Not expected prepare completed with abort call:  */
0329 {XA_TX_STAGE_PREPRO,           XA_OP_ROLLBACK,  TPESYSTEM},
0330 {XA_TX_STAGE_COMMITTING,       XA_OP_ROLLBACK,  TPEHAZARD},
0331 {XA_TX_STAGE_COMMITTED_HAZARD, XA_OP_ROLLBACK,  TPEHAZARD},
0332 {XA_TX_STAGE_COMMITTED_HEURIS, XA_OP_ROLLBACK,  TPEHEURISTIC},
0333 {XA_TX_STAGE_COMMITTED,        XA_OP_ROLLBACK,  TPEHEURISTIC},
0334 /* Heuristic completion, commit */
0335 {XA_TX_STAGE_COMFORGETTING,    XA_OP_ROLLBACK,  TPEHAZARD},
0336 {XA_TX_STAGE_COMFORGOT_HAZ,    XA_OP_ROLLBACK,  TPEHAZARD},
0337 {XA_TX_STAGE_COMFORGOT_HEU,    XA_OP_ROLLBACK,  TPEHEURISTIC},
0338 /* Heuristic completion, abort */
0339 {XA_TX_STAGE_ABFORGETTING,     XA_OP_ROLLBACK,  TPEHAZARD},
0340 {XA_TX_STAGE_ABFORGOT_HAZ,     XA_OP_ROLLBACK,  TPEHAZARD},
0341 {XA_TX_STAGE_ABFORGOT_HEU,     XA_OP_ROLLBACK,  TPEHEURISTIC},
0342 
0343 
0344 {EXFAIL}
0345 };
0346 
0347 /**
0348  * Swtich the operations table
0349  */
0350 #define OP_TABLE_SWITCH     do { switch (txstage)\
0351     {\
0352         case XA_TX_STAGE_PREPARING:\
0353             ret = M_rm_status_driver_preparing;\
0354             break;\
0355         case XA_TX_STAGE_COMMITTING:\
0356             ret = M_rm_status_driver_committing;\
0357             break;    \
0358         case XA_TX_STAGE_ABORTING:\
0359             ret = M_rm_status_driver_aborting;\
0360             break;\
0361         case XA_TX_STAGE_COMFORGETTING:\
0362             ret = M_rm_status_driver_comforgetting;\
0363             break;\
0364         case XA_TX_STAGE_ABFORGETTING:\
0365             ret = M_rm_status_driver_abforgetting;\
0366             break;\
0367         default:\
0368             return NULL;\
0369     }} while (0)
0370 
0371 /*---------------------------Prototypes---------------------------------*/
0372 
0373 /**
0374  * Get next RM status/txstage by current operation.
0375  * @param txstage - current tx stage
0376  * @param rmstatus - current RM status
0377  * @param op - operation done
0378  * @param op_retcode - operation return code
0379  * @param p_xai transaction identifier (used for debug)
0380  * @param rmid resource manager id (for debug)
0381  * @param btid branch at RM (for debug)
0382  * @return NULL or transition descriptor
0383  */
0384 expublic rmstatus_driver_t* xa_status_get_next_by_op(short txstage, char rmstatus, 
0385                                                     int op, int op_retcode,
0386                                                     atmi_xa_tx_info_t *p_xai, 
0387                                                     short rmid, long btid)
0388 {
0389     rmstatus_driver_t *ret=NULL;
0390     
0391     OP_TABLE_SWITCH;
0392     
0393     while (EXFAIL!=ret->txstage)
0394     {
0395         if (ret->txstage == txstage &&
0396                 ret->rmstatus == rmstatus &&
0397                 ret->op == op &&
0398                 op_retcode>=ret->min_retcode && 
0399                 op_retcode<=ret->max_retcode
0400             )
0401         {
0402             break;
0403         }
0404         ret++;
0405     } 
0406     
0407     if (EXFAIL==ret->txstage)
0408     {
0409         ret=NULL;
0410     }
0411     
0412     return ret;
0413 }
0414 
0415 /**
0416  * If we got NOP on current stage action for RM, then we lookup
0417  * this table, to get it's wote for next txstage.
0418  * @param txstage - current tx stage
0419  * @param next_rmstatus - RM status (after NOP...)
0420  * @return NULL or transition descriptor
0421  */
0422 expublic rmstatus_driver_t* xa_status_get_next_by_new_status(short   txstage, 
0423                                                     char next_rmstatus)
0424 {
0425     rmstatus_driver_t *ret=NULL;
0426     
0427     OP_TABLE_SWITCH;
0428     
0429     while (EXFAIL!=ret->txstage)
0430     {
0431         if (ret->txstage == txstage &&
0432                 ret->next_rmstatus == next_rmstatus
0433             )
0434         {
0435             break;
0436         }
0437         ret++;
0438     }
0439     
0440     if (EXFAIL==ret->txstage)
0441     {
0442         ret=NULL;
0443     }
0444     
0445     return ret;
0446 }
0447 
0448 /**
0449  * Get operation to be done for current RM in given state
0450  * @param txstage current tx stage
0451  * @param rmstatus curren RM status
0452  * @return operation to be done or NOP
0453  */
0454 expublic int xa_status_get_op(short txstage, char rmstatus)
0455 {
0456     txaction_driver_t *ret = G_txaction_driver;
0457     
0458     while (EXFAIL!=ret->txstage)
0459     {
0460         if (ret->txstage == txstage &&
0461                 ret->rmstatus == rmstatus
0462             )
0463         {
0464             break;
0465         }
0466         ret++;
0467     }
0468     
0469     if (EXFAIL!=ret->txstage)
0470     {
0471         return ret->op;
0472     }
0473     else
0474     {
0475         return XA_OP_NOP;
0476     }
0477 }
0478 
0479 /**
0480  * Get stage descriptor
0481  * @param txstage
0482  * @return NULL or stage descriptor
0483  */
0484 expublic txstage_descriptor_t* xa_stage_get_descr(short txstage)
0485 {
0486     txstage_descriptor_t* ret = G_state_descriptor;
0487     
0488     while (EXFAIL!=ret->txstage)
0489     {
0490         if (ret->txstage == txstage)
0491         {
0492             break;
0493         }
0494         ret++;
0495     }
0496     
0497     if (EXFAIL==ret->txstage)
0498         ret = NULL;
0499     
0500     return ret;
0501 }
0502 
0503 /**
0504  * Translate stage to tperrno
0505  * @param txstage
0506  * @return 
0507  */
0508 expublic int xa_txstage2tperrno(short txstage, int master_op)
0509 {
0510     txstate2tperrno_t* ret = G_txstage2tperrno;
0511     
0512     while (EXFAIL!=ret->txstage)
0513     {
0514         if (ret->txstage == txstage &&
0515                 ret->master_op == master_op
0516                 )
0517         {
0518             break;
0519         }
0520         ret++;
0521     }
0522     
0523     if (EXFAIL==ret->txstage)
0524         return TPESYSTEM;
0525     
0526     return ret->tpe;
0527 }
0528 
0529 /* vim: set ts=4 sw=4 et smartindent: */