head     1.5;
branch   ;
access   ;
symbols  Version_2_1:1.5 C_Demo_1:1.3;
locks    ; strict;
comment  @ * @;


1.5
date     90.01.30.16.56.50;  author jamesb;  state Exp;
branches ;
next     1.4;

1.4
date     89.09.20.16.43.41;  author hirohama;  state Exp;
branches ;
next     1.3;

1.3
date     89.09.05.17.30.19;  author mao;  state C_Demo_1;
branches ;
next     1.2;

1.2
date     89.02.02.16.36.00;  author dillon;  state Stab;
branches ;
next     1.1;

1.1
date     89.01.17.05.59.05;  author cimarron;  state Exp;
branches ;
next     ;


desc
@@


1.5
log
@Added small routine to 'kick' up the command counter, for recursive
command iterations.
@
text
@/*
 * xstate.c --
 *	POSTGRES transaction state code.
 *
 * Uses a Finite State Atomata  (FsaMachine)
 *
 */

#include <signal.h>

#include "c.h"

#include "log.h"
#include "tim.h"
#include "xid.h"
#include "xlog.h"

#include "xstate.h"

#define static /* static */

RcsId("$Header: RCS/xstate.c,v 1.4 89/09/20 16:43:41 hirohama Exp $");

/* #define XSTATEDEBUG		/* watch state changes... */

#ifdef XSTATEDEBUG
# define DO_DB(A)	A
#else
# define DO_DB(A)	/* A */
#endif

bool CommandIdCounterOverflowFlag;

static void
ClearCommandIdCounterOverflowFlag()
{
	CommandIdCounterOverflowFlag = false;
}

static void
UserErrorEndWithoutBegin() {
	elog(WARN,"User Error: END without BEGIN");
}

static void
UserErrorBeginAfterBegin() {
	elog(WARN,"User Error: BEGIN after a BEGIN");
}

static void
UserErrorAbortWithoutBegin() {
	elog(WARN,"User Error: ABORT without BEGIN");
}

/* redefine these things to make them fit in the table (below) */

#define d_init	NULL	/* InitializeTransactionSystem */
#define d_e		InternalErrorIllegalStateTransition
#define d_bor	NULL	/* TransactionSystemBeginOverrid */
#define d_eor	NULL	/* TransactionSystemEndOverride */
#define d_uerE		UserErrorEndWithoutBegin
#define d_uerB		UserErrorBeginAfterBegin
#define d_uerA		UserErrorAbortWithoutBegin
#define d_newT		ClearCommandIdCounterOverflowFlag
#define	d_endT	NULL	/* TransactionSystemEndTransaction */
#define d_abtT	NULL	/* TransactionSystemAbortTransaction */

#define code_B 0 /* user BEGIN */
#define code_E 1 /* user END */
#define code_A 2 /* user ABORT  XXX this is unused currently */
#define code_s 3 /* start */
#define code_c 4 /* commit */
#define code_a 5 /* exception abort */
#define code_I 6 /* initialize */
#define code_O 7 /* OVERRIDE */

static String codenames[] = { "user_BEGIN", "user_END", "user_ABORT", "start", 
	"commit", "exception_abort", "initialize", "override", NULL };

#define MAX_CODES 8

#define s_r  	 0 /* ready state */
#define s_ready  s_r
#define s_over   1 /* override state */
#define s_work   2 /* not in trans block, recieved start */
#define s_begin  3 /* recieved BEGIN, no commit yet */
#define s_Twait  4 /* inside transaction block, waiting for start */
#define s_Twork  5 /* inside transaction block, recieved start, want A,E,c */
#define s_Tend   6 /* inside transaction block, recieved END, want commit */
#define s_Tabrt  7 /* inside transaction block, recieved ABORT, want commit */
#define s_init   8 /* uninitialized */
#define s_Iover	 9 /* override from uninitialized */

static char	*statenames[] = { "ready", "override", "work", "begin",
	"ready_in_block", "work_in_block", "end", "abort", "uninitilized", 
	"uninitialized_override", NULL };

static void
InternalErrorIllegalStateTransition(old, code, New)
{
	elog(WARN,"Illegal Transaction State Change: %s:%d to %s:%d on %s:%d",
		statenames[old], old, statenames[New], New, 
		codenames[code], code);
}

#define MAX_STATES 10

char	fsaNewState[MAX_STATES][MAX_CODES] = {
/*	     BEGIN   END     ABORT   start   commit  abort   init    OVERRIDE */
/* ready */ {s_r    ,s_r    ,s_r    ,s_work ,s_r    ,s_r    ,s_r    ,s_over },
/* over  */ {s_over ,s_over ,s_over ,s_over ,s_over ,s_over ,s_over ,s_r    },
/* work  */ {s_begin,s_r    ,s_r    ,s_work ,s_r    ,s_r    ,s_r    ,s_over },
/* begin */ {s_r    ,s_r    ,s_r    ,s_r    ,s_Twait,s_r    ,s_r    ,s_over },
/* Twait */ {s_r    ,s_r    ,s_r    ,s_Twork,s_r    ,s_r    ,s_r    ,s_over },
/* Twork */ {s_r    ,s_Tend ,s_Tabrt,s_r    ,s_Twait,s_r    ,s_r    ,s_over },
/* Tend  */ {s_r    ,s_r    ,s_r    ,s_r    ,s_r    ,s_r    ,s_r    ,s_over },
/* Tabrt */ {s_r    ,s_r    ,s_r    ,s_r    ,s_r    ,s_r    ,s_r    ,s_over },
/* init  */ {s_init ,s_init ,s_init ,s_init ,s_init ,s_init ,s_r    ,s_Iover},
/* Iover */ {s_Iover,s_Iover,s_Iover,s_Iover,s_Iover,s_Iover,s_Iover,s_init }};

void	(*fsaActions[MAX_STATES][MAX_CODES])() = {
/*	     BEGIN   END     ABORT   start   commit  abort   init    OVERRIDE */
/* ready */ {d_e,    d_e,    d_e,    d_newT, d_e,    d_e,    d_e,    d_bor  },
/* over  */ {NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   d_e,    d_eor  },
/* work  */ {NULL,   d_uerE, d_uerA, d_e,    d_endT, d_abtT, d_e,    d_bor  },
/* begin */ {d_e,    d_e,    d_e,    d_e,    NULL,   d_abtT, d_e,    d_bor  },
/* Twait */ {d_e,    d_e,    d_e,    NULL,   d_e,    d_abtT, d_e,    d_bor  },
/* Twork */ {d_uerB, NULL,   NULL,   d_e,    NULL,   d_abtT, d_e,    d_bor  },
/* Tend  */ {d_e,    d_e,    d_e,    d_e,    d_endT, d_abtT, d_e,    d_bor  },
/* Tabrt */ {d_e,    d_e,    d_e,    d_e,    d_abtT, d_abtT, d_e,    d_bor  },
/* init  */ {d_e,    d_e,    d_e,    d_e,    d_e,    d_e,    d_init, d_bor  },
/* Iover */ {d_e,    d_e,    d_e,    d_e,    d_e,    d_e,    d_e,    d_eor  }};

static int	currentState = s_init;

void static
FsaMachine(code) 
	uint32	code;
{
	int		oldState = currentState;

	currentState = fsaNewState[currentState][code];

	DO_DB(elog(DEBUG,"XState: %s to %s on %s",
		statenames[oldState], statenames[currentState], 
		codenames[code]));

	if ((char *)fsaActions[oldState][code] != NULL) 
		(*fsaActions[oldState][code])(oldState,code,currentState);
}


typedef struct TransactionStateData {
	TransactionIdData	transactionIdData;
	CommandId		commandId;
	Time			startTime;
/*
	UserId			userId;
*/
} TransactionStateData;

static TransactionStateData	CurrentTransactionStateData = {
	{ 0 }, FirstCommandId, 0x0
};

static TransactionIdData	DisabledTransactionIdData =
	{ '\177', '\177', '\177', '\177', '\177' };


bool	AMI_OVERRIDE = false;	/* catalog creation transaction bootstrapping */

void
InitializeTransactionState()
{
	FsaMachine(code_I);
}

void
OverrideTransactionState(override)
	bool	override;
{
	if (currentState == s_over || currentState == s_Iover) {
		if (!override) FsaMachine(code_O);
	} else {
		if (override) FsaMachine(code_O);
	}
}

bool
IsBlockTransactionState()
{
	switch(currentState) {
	default:
		elog(WARN,"Transaction State is erronious (%d) 4",currentState);
	case s_init:
		elog(WARN,"Checking for block state before initialize");
	case s_over:
	case s_Iover:
	case s_ready:
	case s_work:
	case s_Tend:
	case s_Tabrt:
		return(false);
	case s_begin:
	case s_Twait:
	case s_Twork:
		return(true);
	}
}


bool
IsOverrideTransactionState()
{
	switch(currentState) {
	default:
		elog(WARN,"Transaction State is erronious (%d) 5",currentState);
	case s_Iover:
	case s_over:
		return(true);
	case s_init:
	case s_ready:
	case s_work:
	case s_Tend:
	case s_Tabrt:
	case s_begin:
	case s_Twait:
	case s_Twork:
		return(false);
	}
}

/* XXX the sematics of IsTransactionState are not completely set, yet */
bool
IsTransactionState()
{
	switch(currentState) {
	default:
		elog(WARN,"Transaction State is erronious (%d) 6",currentState);
	case s_over:
	case s_Iover:
	case s_ready:
	case s_init:
		return(false);
	case s_work:
	case s_Tend:
	case s_Tabrt:
	case s_begin:
	case s_Twait:
	case s_Twork:
		return(true);
	}
}

TransactionId
GetCurrentTransactionId()
{
	switch(currentState) {
	default:
		elog(WARN,"Transaction State is erronious (%d) 7",currentState);
	case s_init:
		elog(WARN,"Premature query on transaction state 2"); /* XXX */
	case s_over:
	case s_Iover:
		return (&DisabledTransactionIdData);
	case s_ready:		/* XXXXXXXXXXXX */
		elog(WARN,"Inappropriate query due to state 3");
	case s_work:
	case s_Tend:
	case s_Tabrt:
	case s_begin:
	case s_Twait:
	case s_Twork:
		return (&CurrentTransactionStateData.transactionIdData);
	}
}

CommandId
GetCurrentCommandId()
{
	switch(currentState) {
	default:
		elog(WARN,"Transaction State is erronious (%d) 8",currentState);
	case s_init:
		elog(WARN,"Premature query on transaction state 4"); /* XXX */
	case s_over:
	case s_Iover:
		return ('\177');
	case s_ready:
	case s_Twait:
		elog(WARN,"Inappropriate query due to state 5");
	case s_Tabrt:
	case s_work:
	case s_Tend:
	case s_begin:
	case s_Twork:
		return (CurrentTransactionStateData.commandId);
	}
}

Time
GetCurrentTransactionStartTime()
{
	switch(currentState) {
	default:
		elog(WARN,"Transaction State is erronious (%d) 9",currentState);
	case s_init:
		elog(WARN,"Premature query on transaction state 5"); /* XXX */
	case s_Iover:
	case s_over:
		return (1073741823);
	case s_ready:
		elog(WARN,"Inappropriate query due to state 6");
	case s_Twait:
	case s_Tabrt:
	case s_work:
	case s_Tend:
	case s_begin:
	case s_Twork:
		return (CurrentTransactionStateData.startTime);
	}
}

bool
TransactionIdIsCurrentTransactionId(transactionId)
	TransactionId	transactionId;
{
	switch(currentState) {
	default:
		elog(WARN,"Transaction State is erronious (%d) a",currentState);
	case s_init:
		elog(WARN,"Premature query on transaction state 7"); /* XXX */
	case s_Iover:
	case s_over:
		return (false);
	case s_ready:
		elog(WARN,"Inappropriate querry due to state 8");
	case s_Tabrt:
	case s_Twait:
	case s_work:
	case s_Tend:
	case s_begin:
	case s_Twork:
		if (AMI_OVERRIDE)
			return false;
		return ((bool)(TransactionIdEquals(transactionId,
			&CurrentTransactionStateData.transactionIdData)));
	}
}

bool
CommandIdIsCurrentCommandId(commandId)
	CommandId	commandId;
{
	switch(currentState) {
	default:
		elog(WARN,"Transaction State is erronious (%d) 1",currentState);
	case s_init:
		elog(WARN,"Premature query on transaction state 9"); /* XXX */
	case s_Iover:
	case s_over:
		return (false);
	case s_ready:
	case s_Twait:
		elog(WARN,"Inappropriate querry due to state 10");
	case s_work:
	case s_Tend:
	case s_Tabrt:
	case s_begin:
	case s_Twork:
		if (AMI_OVERRIDE)
			return false;

		return ((bool)(AsUint8(commandId) ==
			AsUint8(CurrentTransactionStateData.commandId)));
	}
}

void
StartTransactionStateBlock()
{
	FsaMachine(code_B);

	if (currentState == s_over) return;

	CurrentTransactionStateData.transactionIdData =
		*GetNewTransactionId();
	CurrentTransactionStateData.commandId = FirstCommandId;
	CurrentTransactionStateData.startTime = GetCurrentTime();
}

void
StartTransactionStateCommand()
{
	FsaMachine(code_s);

	switch(currentState) {
	default:
	case s_Tend:
	case s_Tabrt:
	case s_begin:
	case s_Twait:
	case s_ready:
		elog(WARN,"Transaction State is erronious (%d) 2",currentState);
	case s_init:
		elog(WARN,"Premature start on transaction state"); /* XXX */
	case s_Iover:
	case s_over:
		return;
	case s_work:
		CurrentTransactionStateData.transactionIdData =
			*GetNewTransactionId();
		CurrentTransactionStateData.commandId = FirstCommandId;
		CurrentTransactionStateData.startTime = GetCurrentTime();
		return;
	case s_Twork:
		if (CommandIdCounterOverflowFlag != false) {
			elog(WARN, "StartTransactionCommand: cid overflow");
		}
		return;
	}
}

/*
 * JRB - Cim and I couldn't find correct Start/Commit sequence to use
 *	for executing multiple commands for the recursive node. 
 *	When it is figured out, we need to know when we are in a
 *	transaction already.
 */

void			/* increment's command counter; may set overflow */
CommandCounterIncrement()
{
    CurrentTransactionStateData.commandId += 1;
    if (CurrentTransactionStateData.commandId == FirstCommandId) {
	CommandIdCounterOverflowFlag = true;
    }
}

void
CommitTransactionStateCommand()
{
	FsaMachine(code_c);

	switch(currentState) {
	default:
	case s_work:
	case s_Tend:
	case s_Tabrt:
	case s_begin:
	case s_Twork:
		elog(WARN,"Transaction State is erronious (%d) 3",currentState);
	case s_init:
		elog(WARN,"Premature commit on transaction state"); /* XXX */
	case s_Iover:
	case s_over:
		return;
	case s_Twait:
		CurrentTransactionStateData.commandId += 1;
		if (CurrentTransactionStateData.commandId == FirstCommandId) {
			CommandIdCounterOverflowFlag = true;
		}
	case s_ready:
		return;
	}
}

void
CommitTransactionStateBlock()
{
	FsaMachine(code_E);
}

void
AbortCurrentTransactionState()
{
	FsaMachine(code_a);
}

void
AbortTransactionStateBlock()
{
	FsaMachine(code_A);
}
@


1.4
log
@codenames is now static
@
text
@d22 1
a22 1
RcsId("$Header: RCS/xstate.c,v 1.3 89/09/05 17:30:19 mao C_Demo_1 Locker: hirohama $");
d422 16
@


1.3
log
@Working version of C-only demo
@
text
@d22 1
a22 1
RcsId("$Header: /usr6/postgres/mao/postgres/src/utils/xact/RCS/xstate.c,v 1.2 89/02/02 16:36:00 dillon Stab $");
d77 1
a77 1
char	*codenames[] = { "user_BEGIN", "user_END", "user_ABORT", "start", 
@


1.2
log
@Txfer from old tree
@
text
@d22 1
a22 1
RcsId("$Header: xstate.c,v 1.5 88/08/16 23:43:07 dillon Locked $");
@


1.1
log
@Initial revision
@
text
@a0 1

a1 26
 * 
 * POSTGRES Data Base Management System
 * 
 * Copyright (c) 1988 Regents of the University of California
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for educational, research, and non-profit purposes and
 * without fee is hereby granted, provided that the above copyright
 * notice appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation, and that
 * the name of the University of California not be used in advertising
 * or publicity pertaining to distribution of the software without
 * specific, written prior permission.  Permission to incorporate this
 * software into commercial products can be obtained from the Campus
 * Software Office, 295 Evans Hall, University of California, Berkeley,
 * Ca., 94720 provided only that the the requestor give the University
 * of California a free licence to any derived software for educational
 * and research purposes.  The University of California makes no
 * representations about the suitability of this software for any
 * purpose.  It is provided "as is" without express or implied warranty.
 * 
 */



/*
d22 1
a22 1
RcsId("$Header: xstate.c,v 1.1 88/11/11 16:35:38 postgres Exp $");
@
