campo-sirio/cb/source/c4trans.c
alex af15e0698b Codebase
git-svn-id: svn://10.65.10.50/trunk@4679 c028cbd2-c16b-5b4b-a496-9718f37d4682
1997-06-16 13:01:08 +00:00

2901 lines
74 KiB
C
Executable File

/* c4trans.c (c)Copyright Sequiter Software Inc., 1988-1996. All rights reserved. */
#include "d4all.h"
#ifndef UNIX
#ifdef __TURBOC__
#pragma hdrstop
#endif
#endif
/* TRANSACTION FILE FORMAT
-----------------------
Every entry in the transaction file has the following format:
[unisgned short int] - transaction entry length (including this length entry)
[transaction data]
[transaction header]
The transaction file can be read either forwards or backwards in this
fashion. It is usually read backwards when performing rollbacks, but
it is useful to read forwards for database history review purposes or
in case the transaction file itself is corrupt at some point.
*/
#ifndef S4OFF_TRAN
#ifndef S4OFF_WRITE
static void tran4lowCloseDelayed( TRAN4 *trans )
{
DATA4 *data ;
for ( ;; )
{
data = (DATA4 *)l4pop( &trans->closedDataFiles ) ;
if ( data == 0 )
break ;
l4add( tran4dataList( data->trans ), data ) ;
d4close( data ) ;
}
}
#ifndef S4CLIENT
static DATA4 *tran4dataFull( TRAN4 *, const long, const long ) ;
#endif
#ifdef E4ANALYZE
static int code4transVerify( CODE4TRANS *, int ) ;
#endif /* E4ANALYZE */
#ifndef S4SERVER
static void code4invalidate( CODE4 * ) ;
#endif
#ifndef S4CLIENT
#ifdef E4ANALYZE
static int tran4fileVerify( TRAN4FILE *t4, int subs )
{
int rc ;
if ( t4 == 0 )
return error4( 0, e4parm_null, E93801 ) ;
if ( t4->c4trans == 0 )
return error4( 0, e4parm, E93801 ) ;
if ( subs == 1 )
if ( ( rc = code4transVerify( t4->c4trans, 1 ) ) < 0 )
return rc ;
return 0 ;
}
#endif /* E4ANALYZE */
static int tran4fileInit( TRAN4FILE *t4, CODE4TRANS *c4trans )
{
t4->c4trans = c4trans ;
memset( &t4->file, 0, sizeof( FILE4 ) ) ;
t4->file.hand = -1 ;
t4->transId = -1 ;
#ifdef E4ANALYZE
return tran4fileVerify( t4, 0 ) ;
#else
return 0 ;
#endif
}
int S4FUNCTION tran4fileAppend( TRAN4FILE *t4, LOG4HEADER *header, void *dta )
{
long filePos ;
int rc ;
TRAN4ENTRY_LEN len ;
#ifdef E4PARM_LOW
if ( header == 0 )
return error4( t4->c4trans->c4, e4parm_null, E93801 ) ;
#endif
#ifdef E4ANALYZE
if ( ( rc = tran4fileVerify( t4, 1 ) ) < 0 )
return rc ;
if ( t4->file.hand < 0 )
return error4( t4->c4trans->c4, e4struct, E93801 ) ;
#endif
filePos = file4len( &t4->file ) ;
if ( filePos < 0 )
return (int)filePos ;
len = tran4entryLen( header ) ;
rc = file4write( &t4->file, filePos, &len, sizeof( TRAN4ENTRY_LEN ) ) ;
if ( rc < 0 )
return rc ;
filePos += sizeof( len ) ;
if ( header->dataLen != 0 )
{
#ifdef E4PARM_LOW
if ( dta == 0 )
return error4( t4->c4trans->c4, e4parm_null, E93801 ) ;
#endif
rc = file4write( &t4->file, filePos, dta, (unsigned int)header->dataLen ) ;
if ( rc < 0 )
return rc ;
filePos += header->dataLen ;
}
rc = file4write( &t4->file, filePos, header, sizeof( LOG4HEADER ) ) ;
if ( rc < 0 )
return rc ;
return file4flush( &t4->file ) ;
}
int S4FUNCTION tran4lowAppend( TRAN4 *t4, void *dta )
{
int rc ;
#ifdef E4ANALYZE
if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
return rc ;
#endif
if ( t4->dataPos != 0 )
{
dta = t4->c4trans->c4->tranData ;
t4->dataPos = 0 ;
}
t4->pos = -1 ;
rc = tran4fileAppend( t4->c4trans->transFile, &t4->header, dta ) ;
memset( &t4->header, 0, sizeof( LOG4HEADER ) ) ;
return rc ;
}
static int tran4fileClose( TRAN4FILE *t4 )
{
int rc, saveRc, saveErr ;
#ifdef S4SERVER
SERVER4CLIENT *client ;
#endif
/* must close files no matter what */
/* #ifdef E4ANALYZE*/
/* if ( ( rc = tran4fileVerify( t4, 1 ) ) < 0 )*/
/* return rc ;*/
/* #endif*/
if ( t4->file.hand < 0 )
return 0 ;
saveRc = 0 ;
#ifdef S4SERVER
/* ensure there are no active transactions */
client = (SERVER4CLIENT *)l4first( &t4->c4trans->c4->server->clients ) ;
for ( ;; )
{
if ( client == 0 )
break ;
if ( client->trans.currentTranStatus == r4active )
{
if ( error4code( t4->c4trans->c4 ) == 0 )
saveRc = error4( t4->c4trans->c4, e4trans, E93801 ) ;
t4->validState = 0 ;
}
}
#endif
saveErr = error4code( t4->c4trans->c4 ) ;
error4set( t4->c4trans->c4, 0 ) ;
rc = file4close( &t4->file ) ;
if ( rc < 0 && saveRc == 0 )
saveRc = rc ;
t4->c4trans->c4->errorCode = saveErr ;
return saveRc ;
}
int tran4fileCreate( TRAN4FILE *t4, const char *name )
{
char buf[258] ;
int rc ;
LOG4HEADER header ;
CODE4 *c4 ;
#ifndef S4OFF_MULTI
int oldExcl ;
#endif
#ifdef E4ANALYZE
if ( ( rc = tran4fileVerify( t4, 1 ) ) < 0 )
return rc ;
#endif
c4 = t4->c4trans->c4 ;
#ifdef E4PARM_LOW
if ( name == 0 )
return error4( c4, e4parm_null, E93801 ) ;
#endif
memcpy( buf, name, strlen( name ) + 1 ) ;
u4nameExt( buf, sizeof( buf ), "log", 0 ) ;
#ifndef S4OFF_MULTI
oldExcl = c4->accessMode ;
c4->accessMode = OPEN4DENY_NONE ;
#endif
rc = file4create( &t4->file, c4, buf, 1 ) ;
#ifndef S4OFF_MULTI
c4->accessMode = oldExcl ;
#endif
if ( rc < 0 )
return rc ;
t4->validState = 1;
memset( &header, 0, sizeof( header ) ) ;
header.type = TRAN4SHUTDOWN ;
header.serverDataId = TRAN4VERSION_NUM ;
rc = tran4fileAppend( t4, &header, "\0" ) ;
if (rc < 0)
return(rc);
#ifdef E4ANALYZE
return tran4fileVerify( t4, 1 ) ;
#else
return 0 ;
#endif
}
#ifndef S4UTILS
static int tran4fileStatusFile( TRAN4FILE *t4 )
{
CODE4 *c4 ;
long filePos ;
int rc ;
LOG4HEADER header ;
TRAN4ENTRY_LEN entryLen;
#ifdef S4STAND_ALONE
#ifndef S4OFF_MULTI
long loop ;
int oldNumAttempts ;
#endif
#endif
#ifdef E4ANALYZE
if ( ( rc = tran4fileVerify( t4, 1 ) ) < 0 )
return rc ;
if ( t4->file.hand < 0 )
return error4( t4->c4trans->c4, e4struct, E93801 ) ;
#endif
c4 = t4->c4trans->c4 ;
#ifdef S4STAND_ALONE
/* first see if the only user, in which case can verify */
#ifndef S4OFF_MULTI
oldNumAttempts = c4->lockAttempts ;
/* can't do overlay locking due to Novell inconsistencies... */
/* reserve a byte so only one attempt to set up at a time */
c4->lockAttempts = -1 ;
rc = file4lock( &t4->file, TRAN4LOCK_USERS + TRAN4MAX_USERS + 1, 1 ) ;
c4->lockAttempts = 1 ;
for ( loop = 0 ; loop <= TRAN4MAX_USERS ; loop++ )
{
rc = file4lock( &t4->file, TRAN4LOCK_USERS+loop, 1 ) ;
if ( rc < 0 || rc == r4locked )
break ;
file4unlock( &t4->file, TRAN4LOCK_USERS+loop, 1 ) ;
}
c4->lockAttempts = oldNumAttempts ;
if ( rc != 0 )
{
file4unlock( &t4->file, TRAN4LOCK_USERS + TRAN4MAX_USERS + 1, 1 ) ;
if ( rc == r4locked )
return 0 ;
return rc ;
}
#endif
#endif
for( ;; )
{
filePos = file4len( &t4->file ) - sizeof( LOG4HEADER ) - sizeof(TRAN4ENTRY_LEN);
if ( filePos < 0 )
{
rc = error4( c4, e4trans, E83801 ) ;
break ;
}
rc = file4readAll( &t4->file, 0L, &entryLen, sizeof( TRAN4ENTRY_LEN ) ) ;
if ( rc < 0 )
break ;
if (entryLen != sizeof(LOG4HEADER) + sizeof(TRAN4ENTRY_LEN))
{
rc = error4( c4, e4read, E93801 ) ;
break ;
}
rc = file4readAll( &t4->file, (long)sizeof(TRAN4ENTRY_LEN), &header, sizeof( LOG4HEADER ) ) ;
if ( rc < 0 )
break ;
if ( header.type == TRAN4BACKEDUP )
{
rc = error4( c4, e4trans, E83815 ) ;
break ;
}
rc = file4readAll( &t4->file, filePos, &entryLen, sizeof( TRAN4ENTRY_LEN ) ) ;
if ( rc < 0 )
break ;
if (entryLen != sizeof(LOG4HEADER) + sizeof(TRAN4ENTRY_LEN))
{
rc = error4( c4, e4trans, E83801 ) ;
break ;
}
rc = file4readAll( &t4->file, filePos + sizeof(TRAN4ENTRY_LEN), &header, sizeof( LOG4HEADER ) ) ;
if ( rc < 0 )
break ;
break ;
}
#ifdef S4STAND_ALONE
file4unlock( &t4->file, TRAN4LOCK_USERS + TRAN4MAX_USERS + 1, 1 ) ;
#endif
if ( rc < 0 )
return rc ;
if ( header.type == TRAN4SHUTDOWN )
return 0 ;
return error4( c4, e4trans, E83801 ) ;
}
#endif /* S4UTILS */
static int tran4fileOpen( TRAN4FILE *t4, char *name )
{
int rc, oldOpenError, oldReadOnly ;
char buf[258] ;
CODE4 *c4 ;
#ifndef S4OFF_MULTI
int oldExcl ;
#endif
#ifdef E4PARM_LOW
if ( name == 0 )
return error4( t4->c4trans->c4, e4parm_null, E93801 ) ;
#endif
c4 = t4->c4trans->c4 ;
#ifdef E4ANALYZE
if ( ( rc = tran4fileVerify( t4, 1 ) ) < 0 )
return rc ;
if ( t4->file.hand != -1 ) /* already open */
return error4( c4, e4struct, E93801 ) ;
#endif
memcpy( buf, name, strlen( name ) + 1 ) ;
u4nameExt( buf, sizeof( buf ), "log", 0 ) ;
#ifndef S4OFF_MULTI
oldExcl = c4->accessMode ;
#ifdef S4UTILS
c4->accessMode = OPEN4DENY_RW ;
#else
c4->accessMode = OPEN4DENY_NONE ;
#endif
#endif
oldReadOnly = c4->readOnly ;
c4->readOnly = 0 ;
oldOpenError = c4->errOpen ;
c4->errOpen = 0 ;
rc = file4open( &t4->file, c4, buf, 1 ) ;
c4->errOpen = oldOpenError ;
c4->readOnly = oldReadOnly ;
#ifndef S4OFF_MULTI
c4->accessMode = oldExcl ;
#endif
#ifndef S4UTILS
if ( rc != r4noOpen && rc >= 0 )
{
if ( tran4fileStatusFile( t4 ) != 0 )
{
t4->validState = 0 ;
return -1 ;
}
else
t4->validState = 1 ;
}
#endif /* S4UTILS */
if ( rc != 0 )
return rc ;
#ifdef E4ANALYZE
return tran4fileVerify( t4, 1 ) ;
#else
return 0 ;
#endif
}
/* server just increments and checks trans file for last entry */
/* stand-alone uses the userIdNo as an offset to avoid requiring
continual reads to get next id no. */
static long tran4fileGetNextTransId( TRAN4FILE *t4, TRAN4 *trans )
{
#ifdef E4ANALYZE
int rc ;
if ( ( rc = tran4fileVerify( t4, 1 ) ) < 0 )
return rc ;
#endif
#ifdef S4SERVER
if ( t4->transId > 0 )
{
if ( t4->transId == LONG_MAX )
t4->transId = 0 ;
++t4->transId ;
}
else
{
if ( tran4bottom( trans ) < 0 ) /* no entries */
return 0 ;
while ( trans->header.transId == 0 )
if ( tran4skip( trans, TRAN4BACKWARDS ) != 0 )
break ;
if ( trans->header.transId < 0 )
return e4trans ;
if ( trans->header.transId == LONG_MAX )
t4->transId = 0 ;
else
t4->transId = trans->header.transId + 1 ;
}
#endif
#ifdef S4STAND_ALONE
if ( t4->transId > 0 )
{
if ( t4->transId == LONG_MAX )
t4->transId = t4->c4trans->trans.userIdNo ;
t4->transId += TRAN4MAX_USERS ;
}
else
{
if ( tran4bottom( trans ) < 0 ) /* no entries */
return 0 ;
for ( ;; )
{
if ( trans->header.transId % TRAN4MAX_USERS == trans->userIdNo )
break ;
if ( tran4skip( trans, TRAN4BACKWARDS ) != 0 )
break ;
}
if ( trans->header.transId < 0 )
return e4trans ;
if ( trans->header.transId == LONG_MAX || ( trans->header.transId % TRAN4MAX_USERS != t4->c4trans->trans.userIdNo ) )
t4->transId = t4->c4trans->trans.userIdNo ;
else
t4->transId = trans->header.transId + TRAN4MAX_USERS ;
}
#endif
return t4->transId ;
}
static long tran4getTransId( TRAN4 *t4 )
{
#ifdef E4ANALYZE
int rc ;
if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
return rc ;
#endif
if ( t4->transId > 0 )
return t4->transId ;
#ifdef E4ANALYZE
if ( t4->c4trans->transFile == 0 )
return error4( t4->c4trans->c4, e4struct, E93801 ) ;
#endif
t4->transId = tran4fileGetNextTransId( t4->c4trans->transFile, t4 ) ;
return t4->transId ;
}
/*
int S4FUNCTION tran4fileStatus( TRAN4FILE *t4, long transactionId )
{
long filePos ;
int rc ;
LOG4HEADER header ;
#ifdef E4ANALYZE
if ( ( rc = tran4fileVerify( t4, 1 ) ) < 0 )
return rc ;
if ( t4->file.hand < 0 )
return error4( t4->c4trans->c4, e4struct, E93801 ) ;
#endif
rc = -1 ;
filePos = file4len( &t4->file ) - sizeof( LOG4HEADER ) ;
for( ; filePos > 0 ; )
{
rc = file4readAll( &t4->file, filePos, &header, sizeof( LOG4HEADER ) ) ;
if ( rc < 0 )
return rc ;
if ( header.transId == transactionId )
return header.type ;
filePos -= ( header.dataLen + sizeof( LOG4HEADER ) ) ;
}
return rc ;
}
*/
static int tran4fileRead( TRAN4FILE *t4, long pos, LOG4HEADER *header, char **data, unsigned int *dataLen )
{
int rc ;
#ifdef E4ANALYZE
if ( ( rc = tran4fileVerify( t4, 1 ) ) < 0 )
return rc ;
if ( t4->file.hand < 0 )
return error4( t4->c4trans->c4, e4struct, E93801 ) ;
#endif
rc = file4readAll( &t4->file, pos, header, sizeof( LOG4HEADER ) ) ;
if ( rc < 0 )
return rc ;
if ( *dataLen < header->dataLen + 1 )
if ( u4allocAgain( t4->c4trans->c4, data, dataLen, (unsigned int)header->dataLen + 1 ) != 0 )
return e4memory ;
if ( header->dataLen > 0L )
{
rc = file4readAll( &t4->file, pos - header->dataLen, *data, (unsigned int)header->dataLen ) ;
if ( rc < 0 )
return rc ;
}
else
(*data)[0] = '\0' ;
return 0 ;
}
static int tran4read( TRAN4 *t4 )
{
#ifdef E4ANALYZE
int rc ;
if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
return rc ;
if ( t4->pos < 0 )
return error4( t4->c4trans->c4, e4info, E83802 ) ;
if ( t4->c4trans->transFile == 0 )
return error4( t4->c4trans->c4, e4info, E93801 ) ;
#endif
return tran4fileRead( t4->c4trans->transFile, t4->pos, &t4->header, &t4->c4trans->c4->tranData, &t4->c4trans->c4->tranDataLen ) ;
}
int S4FUNCTION tran4fileTop( TRAN4FILE *t4, TRAN4 *trans )
{
int rc ;
unsigned lenRead ;
TRAN4ENTRY_LEN len ;
#ifdef E4ANALYZE
if ( ( rc = tran4fileVerify( t4, 1 ) ) < 0 )
return rc ;
#endif
lenRead = file4read( &t4->file, 0L, &len, sizeof( len ) ) ;
if ( lenRead != sizeof( len ) )
return r4bof ;
trans->pos = len - sizeof( LOG4HEADER ) ;
rc = tran4read( trans ) ;
if ( rc < 0 )
{
trans->pos = -1 ;
return rc ;
}
return 0 ;
}
int S4FUNCTION tran4fileBottom( TRAN4FILE *t4, TRAN4 *trans )
{
int rc ;
#ifdef E4ANALYZE
if ( ( rc = tran4fileVerify( t4, 1 ) ) < 0 )
return rc ;
#endif
trans->pos = file4len( &t4->file ) - sizeof( LOG4HEADER ) ;
if ( trans->pos < 0 )
return r4eof ;
rc = tran4read( trans ) ;
if ( rc < 0 )
{
trans->pos = -1 ;
return rc ;
}
return 0 ;
}
int S4FUNCTION tran4fileSkip( TRAN4FILE *t4, TRAN4 *trans, const int direction )
{
int rc ;
TRAN4ENTRY_LEN len ;
#ifdef E4PARM_LOW
if ( t4 == 0 || trans == 0 || ( direction != TRAN4FORWARDS && direction != TRAN4BACKWARDS ) )
return error4( 0, e4parm, E93801 ) ;
#endif
if ( trans->pos < 0L ) /* empty file ... */
{
if ( direction == TRAN4BACKWARDS )
return r4eof ;
else
return r4bof ;
}
#ifdef E4ANALYZE
if ( ( rc = tran4fileVerify( t4, 1 ) ) < 0 )
return rc ;
#endif
if ( direction == TRAN4BACKWARDS )
{
trans->pos -= tran4entryLen( &trans->header ) ;
if ( trans->pos < 0L )
return r4bof ;
rc = tran4read( trans ) ;
if ( rc< 0 )
{
trans->pos = -1 ;
return rc ;
}
}
else
{
trans->pos += sizeof( LOG4HEADER ) ;
if ( (long)trans->pos + (long)sizeof( TRAN4ENTRY_LEN ) >= file4len( &t4->file ) )
return r4eof ;
rc = file4readAll( &t4->file, trans->pos, &len, sizeof( TRAN4ENTRY_LEN ) ) ;
if ( rc < 0 )
return rc ;
trans->pos += len - sizeof( LOG4HEADER ) ;
if ( trans->pos >= file4len( &t4->file ) )
return r4eof ;
rc = tran4read( trans ) ;
if ( rc< 0 )
{
trans->pos = -1 ;
return rc ;
}
}
return 0 ;
}
/*
int S4FUNCTION tran4fileSeek( TRAN4FILE *t4, TRAN4 *trans, long transIdno )
{
int rc ;
#ifdef E4ANALYZE
if ( ( rc = tran4fileVerify( t4, 1 ) ) < 0 )
return rc ;
#endif
for ( trans->pos = file4len( &t4->file ) - sizeof( LOG4HEADER ) ; trans->pos > 0L ; trans->pos -= tran4entryLen( &trans->header ) )
{
rc = file4readAll( &t4->file, trans->pos, &trans->header, sizeof( LOG4HEADER ) ) ;
if ( rc < 0 )
{
trans->pos = -1L ;
return rc ;
}
if ( trans->header.transId == transIdno )
return tran4read( trans ) ;
}
trans->pos = -1L ;
return error4( t4->c4trans->c4, e4trans, E83803 ) ;
}
*/
#ifndef S4INLINE
long S4FUNCTION tran4id( TRAN4 *t4 )
{
#ifdef E4ANALYZE
int rc ;
if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
return rc ;
#endif
return t4->header.transId ;
}
long S4FUNCTION tran4clientId( TRAN4 *t4 )
{
int rc ;
#ifdef E4ANALYZE
if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
return rc ;
#endif
return t4->header.clientId ;
}
unsigned long S4FUNCTION tran4clientDataId( TRAN4 *t4 )
{
int rc ;
#ifdef E4ANALYZE
if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
return rc ;
#endif
return t4->header.clientDataId ;
}
unsigned long S4FUNCTION tran4serverDataId( TRAN4 *t4 )
{
int rc ;
#ifdef E4ANALYZE
if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
return rc ;
#endif
return t4->header.serverDataId ;
}
int S4FUNCTION tran4type( TRAN4 *t4 )
{
int rc ;
#ifdef E4ANALYZE
if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
return rc ;
#endif
return t4->header.type ;
}
unsigned S4FUNCTION tran4len( TRAN4 *t4 )
{
int rc ;
#ifdef E4ANALYZE
if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
return rc ;
#endif
return t4->header.dataLen ;
}
#endif /* S4INLINE */
/* data may be larger than can be contained in memory... new coding reqd */
void *S4FUNCTION tran4getData( TRAN4 *t4, const long pos )
{
CODE4 *c4 ;
#ifdef E4ANALYZE
if ( tran4verify( t4, 1 ) < 0 )
return 0 ;
if ( t4->c4trans->transFile == 0 )
{
error4( t4->c4trans->c4, e4struct, E93801 ) ;
return 0 ;
}
#endif
c4 = t4->c4trans->c4 ;
if ( c4->tranData != 0 )
{
if ( c4->tranDataLen < t4->header.dataLen + 1 )
{
error4( c4, e4trans, E93801 ) ;
return 0 ;
}
c4->tranData[ t4->header.dataLen ] = 0 ;
}
return c4->tranData + pos ;
}
int S4FUNCTION tran4set( TRAN4 *t4, const int status, const long id1, const long id2, const int typ,
const unsigned int dLen, const long clientId, const long serverId )
{
#ifdef E4ANALYZE
int rc ;
if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
return rc ;
#endif
if ( status == r4active || typ == TRAN4START || typ == TRAN4ROLLBACK )
{
if ( id1 == -1 )
t4->header.transId = tran4getTransId( t4 ) ;
else
t4->header.transId = id1 ;
}
else
t4->header.transId = 0 ;
#ifdef E4ANALYZE
if ( t4->c4trans->transFile == 0 )
return error4( t4->c4trans->c4, e4struct, E93801 ) ;
#endif
if ( t4->header.transId < 0 )
return error4( t4->c4trans->c4, e4trans, E93801 ) ;
t4->header.clientId = id2 ;
t4->header.type = typ ;
t4->header.dataLen = dLen ;
t4->header.clientDataId = clientId ;
t4->header.serverDataId = serverId ;
time( &t4->header.time ) ;
return 0 ;
}
int S4FUNCTION tran4putData( TRAN4 *t4, void *dta, unsigned dLen )
{
CODE4 *c4 ;
#ifdef E4ANALYZE
int rc ;
if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
return rc ;
if ( t4->c4trans->transFile == 0 || dLen <= 0 )
return error4( t4->c4trans->c4, e4info, E93801 ) ;
#endif
c4 = t4->c4trans->c4 ;
if ( t4->dataPos + dLen + 1 > c4->tranDataLen )
if ( u4allocAgain( c4, &c4->tranData, &c4->tranDataLen, dLen + t4->dataPos + 1 ) != 0 )
return e4memory ;
memcpy( c4->tranData + t4->dataPos, dta, dLen ) ;
t4->dataPos += dLen ;
return 0 ;
}
#ifndef S4INLINE
int S4FUNCTION tran4bottom( TRAN4 *t4 )
{
#ifdef E4ANALYZE
int rc ;
if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
return rc ;
if ( t4->c4trans->transFile == 0 )
return error4( t4->c4trans->c4, e4struct, E93801 ) ;
#endif
return tran4fileBottom( t4->c4trans->transFile, t4 ) ;
}
int S4FUNCTION tran4top( TRAN4 *t4 )
{
#ifdef E4ANALYZE
int rc ;
if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
return rc ;
if ( t4->c4trans->transFile == 0 )
return error4( t4->c4trans->c4, e4info, E93801 ) ;
#endif
return tran4fileTop( t4->c4trans->transFile, t4 ) ;
}
int S4FUNCTION tran4skip( TRAN4 *t4, int direction )
{
#ifdef E4ANALYZE
int rc ;
#endif
#ifdef E4PARM_LOW
if ( direction != TRAN4FORWARDS && direction != TRAN4BACKWARDS )
return error4( 0, e4parm, E93801 ) ;
#endif
#ifdef E4ANALYZE
if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
return rc ;
if ( t4->c4trans->transFile == 0 )
return error4( t4->c4trans->c4, e4struct, E93801 ) ;
#endif
return tran4fileSkip( t4->c4trans->transFile, t4, direction ) ;
}
#endif /* S4INLINE */
int tran4lowUnappend( TRAN4 *trans )
{
DATA4 *data ;
int rc ;
long recNo ;
#ifdef E4PARM_LOW
if ( trans == 0 )
return error4( 0, e4parm_null, E93801 ) ;
#endif
recNo = *((long *)(tran4getData( trans, 0L ) ) ) ;
data = tran4dataFull( trans, tran4serverDataId( trans ), tran4clientDataId( trans ) ) ;
if ( data == 0 )
return error4( trans->c4trans->c4, e4name, E93801 ) ;
#ifndef S4OFF_MULTI
if ( dfile4lockTestAppend( data->dataFile, tran4clientDataId( trans ), tran4serverDataId( trans ) ) == 0 )
return error4( trans->c4trans->c4, e4lock, E83804 ) ;
#endif
if ( d4recCount( data ) != recNo )
{
if ( d4recCount( data ) == recNo - 1 ) /* already unappended */
return 0 ;
else
return error4( trans->c4trans->c4, e4rollback, E83805 ) ;
}
memcpy( data->record, tran4getData( trans, sizeof( long ) ), dfile4recWidth( data->dataFile ) ) ;
rc = d4unappend( data ) ;
memset( data->record, 0, dfile4recWidth( data->dataFile ) ) ;
if ( rc < 0 )
return error4stack( trans->c4trans->c4, rc, E93801 ) ;
return d4update( data ) ;
}
int tran4lowUnwrite( TRAN4 *trans )
{
DATA4 *data ;
int rc, doSpecial ;
long recNo ;
char *rec, *saveRec = 0;
CODE4 *c4 ;
#ifndef S4MEMO_OFF
int i ;
unsigned long ptrLen, pos ;
#endif
#ifdef E4PARM_LOW
if ( trans == 0 )
return error4( 0, e4parm_null, E93801 ) ;
#endif
c4 = trans->c4trans->c4 ;
recNo = *((long *)(tran4getData( trans, 0L ) ) ) ;
rec = (char *)tran4getData( trans, (long)sizeof( long ) ) ;
data = tran4dataFull( trans, tran4serverDataId( trans ), tran4clientDataId( trans ) ) ;
if ( data == 0 )
return error4( c4, e4name, E93801 ) ;
doSpecial = 0 ;
if ( data->recordChanged == 1 ) /* override flush */
{
if ( d4recNo( data ) == recNo )
{
/* special, case (automatic rollback) -- save record for user */
doSpecial = 1 ;
saveRec = data->record ;
data->record =(char*) u4allocFree( c4, dfile4recWidth( data->dataFile ) + 1 ) ;
if ( data->record == 0 )
{
/* user will lose changes, due to low memory, but can at least rollback */
data->record = saveRec ;
doSpecial = 0 ;
}
else
memcpy( data->record, saveRec, dfile4recWidth( data->dataFile ) ) ;
}
data->recordChanged = 0 ;
}
rc = 0 ;
if ( doSpecial == 0 )
rc = d4go( data, recNo ) ;
if ( rc == 0 )
#ifndef S4OFF_MULTI
if ( dfile4lockTest( data->dataFile, tran4clientDataId( trans ), tran4serverDataId( trans ), recNo ) == 0 )
rc = error4( c4, e4lock, E83804 ) ;
#endif
if ( rc == 0 )
{
memcpy( d4record( data ), rec, (size_t)dfile4recWidth( data->dataFile ) ) ;
#ifndef S4MEMO_OFF
pos = (long)sizeof( long ) + 2L * dfile4recWidth( data->dataFile ) ;
for ( i = 0; i < data->dataFile->nFieldsMemo; i++ )
{
ptrLen = *( (unsigned int *)tran4getData( trans, pos ) ) ;
pos += sizeof( ptrLen ) ;
if ( ptrLen != 0 )
f4memoAssignN( data->fieldsMemo[i].field, (char *)tran4getData( trans, pos ), (unsigned int)ptrLen ) ;
pos += ptrLen ;
#ifdef S4DATA_ALIGN
memcpy(&ptrLen, tran4getData(trans, pos), sizeof(ptrLen));
#else
ptrLen = *( (unsigned long *)tran4getData( trans, pos ) ) ;
#endif
pos += sizeof( ptrLen ) + ptrLen ;
}
#endif
}
if ( rc == 0 )
rc = d4writeLow( data, recNo, 0 ) ;
if ( rc == 0 )
rc = d4update( data ) ;
if ( doSpecial )
{
u4free( data->record ) ;
data->record = saveRec ;
data->recordChanged = 1 ;
}
return rc ;
}
#ifdef P4ARGS_USED
#pragma argsused
#endif
/* clientId is a unique id for the transactee. In the single user case, there is only one */
int S4FUNCTION tran4lowStart( TRAN4 *trans, long clientId, int doUnlock )
{
int rc ;
#ifdef S4STAND_ALONE_TRANS
int oldLockAttempts ;
#endif
CODE4 *c4 ;
#ifdef E4PARM_HIGH
if ( trans == 0 )
return error4( 0, e4parm_null, E93801 ) ;
#endif
c4 = trans->c4trans->c4 ;
if ( trans->c4trans->enabled == 0 )
{
#ifdef S4STAND_ALONE
if ( c4->logOpen == 0 )
return error4( c4, e4trans, E83814 ) ;
#endif
#ifdef S4STAND_ALONE
rc = code4logOpen( c4, 0, 0 ) ;
#else
rc = code4transFileEnable( trans->c4trans, 0, 0 ) ;
#endif
if ( rc < 0 )
return rc ;
}
if ( trans->c4trans->enabled != 1 )
return error4( c4, e4trans, E83807 ) ;
#ifdef S4STAND_ALONE
if ( trans->currentTranStatus == r4active ) /* already in a transactional state */
return error4( c4, e4trans, E93801 ) ;
#endif
if ( trans->c4trans->transFile->status != 0 )
return error4( c4, e4trans, E83801 ) ;
#ifndef S4OFF_MULTI
if ( doUnlock == 1 )
{
rc = code4unlock( c4 ) ;
if ( rc < 0 )
return rc ;
}
#endif
#ifdef S4STAND_ALONE_TRANS
oldLockAttempts = c4->lockAttempts ;
c4->lockAttempts = WAIT4EVER ;
rc = code4tranLockTransactions( c4->c4trans, TRAN4LOCK_MULTIPLE ) ;
c4->lockAttempts = oldLockAttempts ;
if ( rc < 0 )
rc = error4( c4, rc, E93801 ) ;
tran4bottom( trans ) ;
switch( tran4type( trans ) )
{
case TRAN4COMPLETE:
case TRAN4ROLLBACK:
case TRAN4OPEN:
case TRAN4CLOSE:
}
#endif
rc = tran4set( trans, trans->currentTranStatus, -1L, clientId, TRAN4START, 0, 0L, 0L ) ;
if ( rc < 0 )
return rc ;
if ( tran4lowAppend( trans, "\0" ) != 0 )
return e4transAppend ;
trans->currentTranStatus = r4active ;
#ifndef S4OFF_MULTI
trans->savedUnlockAuto = trans->unlockAuto ;
trans->unlockAuto = 0 ;
#endif
return 0 ;
}
/*int S4FUNCTION tran4lowRollback( TRAN4 *trans, long id, int doUnlock )*/
int S4FUNCTION tran4lowRollback( TRAN4 *trans, long id, const int doInvalidate )
{
int done, saveErr, rc ;
long transId ;
CODE4 *c4 ;
#ifdef E4PARM_HIGH
if ( trans == 0 )
return error4( 0, e4parm, E93801 ) ;
#endif
c4 = trans->c4trans->c4 ;
saveErr = error4set( c4, 0 ) ;
transId = tran4getTransId( trans ) ;
#ifdef E4ANALYZE
if ( transId <= 0 )
return error4( 0, e4info, E93801 ) ;
#endif
#ifdef E4ANALYZE
if ( trans->c4trans->enabled != 1 )
return error4( c4, e4rollback, E83807 ) ;
#endif
if ( trans->currentTranStatus != r4active )
return error4( c4, e4trans, E83808 ) ;
if ( trans->c4trans->transFile->status != 0 )
return error4( c4, e4trans, E83801 ) ;
trans->c4trans->transFile->status = 1 ;
trans->currentTranStatus = r4rollback ;
/* first rollback all the transactions, then mark a rollback as having occurred */
rc = tran4bottom( trans ) ;
if ( rc != 0 )
return error4stack( c4, rc, E93801 ) ;
for( done = 0, rc = 0; !done && !rc ; )
{
if ( tran4id( trans ) == transId )
{
switch( tran4type( trans ) )
{
case TRAN4START:
done = 1 ;
break ;
case TRAN4WRITE:
rc = tran4lowUnwrite( trans ) ;
break ;
case TRAN4APPEND:
rc = tran4lowUnappend( trans ) ;
break ;
case TRAN4VOID: /* transaction connectioning to next was voided, so skip... */
case TRAN4OPEN:
case TRAN4OPEN_TEMP:
case TRAN4CLOSE:
break ;
default:
rc = error4( c4, e4rollback, E83809 ) ;
}
}
if ( !done && !rc )
rc = tran4skip( trans, TRAN4BACKWARDS ) ;
}
if ( rc > 0 )
rc = 0 ;
if ( rc == 0 )
{
tran4set( trans, trans->currentTranStatus, transId, id, TRAN4ROLLBACK, 0, 0L, 0L ) ;
if ( tran4lowAppend( trans, "\0" ) != 0 )
return e4transAppend ;
}
trans->currentTranStatus = r4inactive ;
trans->transId = 0;
#ifndef S4OFF_MULTI
trans->unlockAuto = trans->savedUnlockAuto ;
#endif
#ifdef S4STAND_ALONE_TRANS
#ifndef S4UTILS
rc = code4tranUnlockTransactions( c4->c4trans, TRAN4LOCK_MULTIPLE ) ;
#endif
#endif
if ( saveErr != 0 )
error4set( c4, saveErr ) ;
if ( rc == 0 )
trans->c4trans->transFile->status = 0 ;
tran4lowCloseDelayed( trans ) ;
#ifndef S4SERVER
if ( doInvalidate )
code4invalidate( c4 ) ;
#endif
return rc ;
}
static int tran4lowRemoveKeys( TRAN4 *trans )
{
DATA4 *data ;
#ifndef S4OFF_INDEX
int rc, saveRc ;
TAG4 *tag ;
TAG4KEY_REMOVED *removed ;
saveRc = 0 ;
#endif
for ( data = 0 ;; ) /* first do open files */
{
data =(DATA4 *) l4next( tran4dataList( trans ), data ) ;
if ( data == 0 )
break ;
#ifndef S4OFF_INDEX
for ( tag = 0 ;; )
{
tag = d4tagNext( data, tag ) ;
if ( tag == 0 )
break ;
for ( removed = 0 ;; )
{
removed = (TAG4KEY_REMOVED *)l4first( &tag->removedKeys ) ;
if ( removed == 0 )
break ;
rc = tfile4remove( tag->tagFile, removed->key, removed->recno ) ;
if ( rc < 0 )
saveRc = rc ;
l4remove( &tag->removedKeys, removed ) ;
u4free( removed ) ;
}
}
#endif
}
for ( data = 0 ;; ) /* now do closed files */
{
data =(DATA4 *) l4next( &trans->closedDataFiles, data ) ;
if ( data == 0 )
break ;
#ifndef S4OFF_INDEX
for ( tag = 0 ;; )
{
tag = d4tagNext( data, tag ) ;
if ( tag == 0 )
break ;
for ( removed = 0 ;; )
{
removed = (TAG4KEY_REMOVED *)l4first( &tag->removedKeys ) ;
if ( removed == 0 )
break ;
rc = tfile4remove( tag->tagFile, removed->key, removed->recno ) ;
if ( rc < 0 )
saveRc = rc ;
l4remove( &tag->removedKeys, removed ) ;
u4free( removed ) ;
}
}
#endif
}
#ifndef S4OFF_INDEX
return saveRc ;
#else
return 0 ;
#endif
}
static int tran4updateData( TRAN4 *trans )
{
DATA4 *data ;
int rc, saveRc, oldTransStatus ;
/* changes trans status to force an update */
oldTransStatus = trans->currentTranStatus ;
trans->currentTranStatus = r4off ;
for ( data = 0, saveRc = 0 ;; )
{
data = (DATA4 *)l4next( trans->dataList, data ) ;
if ( data == 0 )
break ;
if ( data->dataFile->fileChanged == 1 )
{
#ifndef S4OFF_MULTI
if ( d4lockTestAppend( data ) == 1 )
#endif
{
rc = dfile4updateHeader( data->dataFile, 1, 1 ) ;
if ( rc < 0 )
saveRc = rc ;
}
}
}
trans->currentTranStatus = oldTransStatus ;
return saveRc ;
}
static int tran4lowFlush( TRAN4 *trans )
{
DATA4 *dataOn ;
int rc ;
for ( dataOn = 0 ;; )
{
dataOn = (DATA4 *)l4next( tran4dataList( trans ), dataOn ) ;
if ( dataOn == 0 )
break ;
#ifndef S4OFF_MULTI
if ( d4lockTestAppend( dataOn ) )
#endif
dfile4updateHeader( dataOn->dataFile, 1, 1 ) ;
rc = d4flush( dataOn ) ;
if ( rc != 0 )
return rc ;
}
return 0 ;
}
#ifdef P4ARGS_USED
#pragma argsused
#endif
int S4FUNCTION tran4lowCommit( TRAN4 *trans, long id, unsigned short int numServers, int doUnlock )
{
int rc ;
CODE4 *c4 ;
#ifdef E4PARM_LOW
if ( trans == 0 )
return error4( 0, e4parm_null, E93801 ) ;
#endif
c4 = trans->c4trans->c4 ;
if ( trans->c4trans->enabled != 1 )
return error4( c4, e4parm, E83807 ) ;
if ( trans->currentTranStatus == r4inactive )
return 0 ;
#ifdef S4DISTRIBUTED
if ( trans->currentTranStatus == S4PARTIAL )
return error4( c4, e4commit, E93801 ) ;
#endif
if ( trans->c4trans->transFile->status != 0 )
return error4( c4, e4trans, E83801 ) ;
rc = tran4lowFlush( trans ) ;
if ( rc != 0 )
return rc ;
trans->c4trans->transFile->status = 1 ;
rc = tran4set( trans, trans->currentTranStatus, -1L, id, TRAN4COMPLETE, 0, 0L, 0L ) ;
if ( rc < 0 )
return rc ;
#ifdef S4DISTRIBUTED
rc = tran4putData( trans, &numServers, sizeof( numServers ) ) ;
if ( rc < 0 )
return rc ;
#endif
if ( tran4lowAppend( trans, "\0" ) != 0 )
return e4transAppend ;
#ifdef S4DISTRIBUTED
trans->currentTranStatus = r4partial ;
if ( numServers == 1 ) /* simple commit, perform completion as well */
rc = tran4complete( trans, id ) ;
else
rc = 0 ;
#else
rc = tran4lowRemoveKeys( trans ) ;
if ( rc < 0 )
return error4stack( c4, rc, E93801 ) ;
trans->currentTranStatus = r4inactive ;
trans->transId = 0;
#ifdef S4STAND_ALONE_TRANS
#ifndef S4UTILS
rc = code4tranUnlockTransactions( c4->c4trans, TRAN4LOCK_MULTIPLE ) ;
if ( rc == 0 )
{
#endif
#endif
#ifdef S4OFF_MULTI
rc = 0 ;
#else
trans->unlockAuto = trans->savedUnlockAuto ;
rc = tran4updateData( trans ) ;
if ( rc == 0 && doUnlock )
{
if ( code4unlockAuto( c4 ) == 1 )
rc = code4unlock( c4 ) ;
}
#endif
#ifdef S4STAND_ALONE_TRANS
#ifndef S4UTILS
}
#endif
#endif
#endif
if ( rc == 0 )
trans->c4trans->transFile->status = 0 ;
tran4lowCloseDelayed( trans ) ;
return rc ;
}
#ifdef S4DISTRIBUTED
int tran4lowComplete( TRAN4 *trans, long id )
{
int rc ;
#ifdef E4PARM_LOW
if ( trans == 0 )
return error4( 0, e4parm_null, E93801 ) ;
#endif
if ( trans->currentTranStatus != S4PARTIAL )
return error4( trans->c4trans->c4, e4commit, E83811 ) ;
rc = tran4set( trans, trans->currentTranStatus, -1, id, TRAN4COMMIT, 0, 0L, 0L ) ;
if ( rc < 0 )
return rc ;
if ( tran4lowAppend( trans, "\0" ) != 0 )
return e4transAppend ;
trans->currentTranStatus = TRAN4INACTIVE ;
trans->unlockAuto = trans->savedUnlockAuto ;
return 0 ;
}
#endif /* S4DISTRIBUTED */
#endif /* not S4CLIENT */
#ifdef S4SERVER
#ifndef S4INLINE
int S4FUNCTION code4tranStart( CODE4 *c4 )
{
return tran4lowStart( &c4->currentClient->trans, connection4id( c4->currentClient->connection ), 0 ) ;
}
int S4FUNCTION code4tranStartSingle( CODE4 *c4 )
{
return tran4lowStart( &c4->currentClient->trans, connection4id( c4->currentClient->connection ), 0 ) ;
}
int S4FUNCTION code4tranCommit( CODE4 *c4 )
{
int rc ;
rc = code4flush( c4 ) ;
if ( rc != 0 )
return rc ;
return tran4lowCommit( &c4->currentClient->trans, connection4id( c4->currentClient->connection ), 1 ) ;
}
int S4FUNCTION code4tranRollback( CODE4 *c4 )
{
return tran4lowRollback( &c4->currentClient->trans, connection4id( c4->currentClient->connection ), 1 ) ;
}
#endif /* S4INLINE */
#endif /* S4SERVER */
#ifndef S4SERVER
/* places all DATA4's into an invalid state */
static void code4invalidate( CODE4 *c4 )
{
DATA4 *dataOn ;
#ifdef E4PARM_LOW
if ( c4 == 0 )
{
error4( 0, e4parm_null, E93827 ) ;
return ;
}
#endif
for ( dataOn = 0 ;; )
{
dataOn = (DATA4 *)l4next( c4->c4trans.trans.dataList, dataOn ) ;
if ( dataOn == 0 )
break ;
/* 04/24/96 --> d4blank() replacing memset due to S4FOX binary
fields having non-blank contents to represent blank */
/* memset( dataOn->record, ' ', dfile4recWidth( dataOn->dataFile ) ) ; */
dataOn->recNum = dataOn->recNumOld = -1 ; /* ensure that d4blank works with lock-enforce on, plus reset record # */
d4blank( dataOn ) ;
d4changed( dataOn, 0 ) ;
}
}
#ifndef S4CLIENT
S4EXPORT int S4FUNCTION code4tranCommit( CODE4 *c4 )
{
int saveErr, rc ;
#ifdef E4PARM_HIGH
if ( c4 == 0 )
return error4( 0, e4parm_null, E93828 ) ;
#endif
if ( code4transEnabled( c4 ) != 1 )
return error4( c4, e4trans, E83807 ) ;
rc = code4flush( c4 ) ;
if ( rc != 0 )
return rc ;
saveErr = error4code( c4 ) ;
if ( saveErr < 0 )
error4set( c4, 0 ) ;
rc = tran4lowCommit( &c4->c4trans.trans, 0, 1, 1 ) ;
#ifndef S4OFF_MULTI
if ( code4unlockAuto( c4 ) == 1 )
if ( code4unlock( c4 ) != 0 )
return error4( c4, e4unlock, E93828 ) ;
#endif
if ( saveErr == 0 )
saveErr = rc ;
if ( saveErr != 0 )
error4set( c4, saveErr ) ;
return rc ;
}
S4EXPORT int S4FUNCTION code4tranStart( CODE4 *c4 )
{
#ifdef E4PARM_HIGH
if ( c4 == 0 )
return error4( 0, e4parm_null, E93829 ) ;
#endif
return tran4lowStart( &c4->c4trans.trans, 0, 0 ) ;
}
int S4FUNCTION code4tranStartSingle( CODE4 *c4 )
{
#ifdef E4PARM_HIGH
if ( c4 == 0 )
return error4( 0, e4parm_null, E93829 ) ;
#endif
return tran4lowStart( &c4->c4trans.trans, 0, 0 ) ;
}
int S4FUNCTION code4tranRollback( CODE4 *c4 )
{
int rc ;
#ifdef E4PARM_HIGH
if ( c4 == 0 )
return error4( 0, e4parm_null, E93830 ) ;
#endif
if ( code4transEnabled( c4 ) != 1 )
return error4( c4, e4trans, E83807 ) ;
rc = tran4lowRollback( &c4->c4trans.trans, 0, 1 ) ;
if ( rc < 0 )
return rc ;
/* rc = code4invalidate( c4 ) ; --> moved to low rollback.*/
/* if ( rc < 0 )*/
/* return rc ;*/
#ifdef S4OFF_MULTI
return 0 ;
#else
return code4unlock( c4 ) ;
#endif
}
#endif
#endif
#ifdef S4CLIENT
int S4FUNCTION code4tranCommit( CODE4 *c4 )
{
int saveRc, saveErr ;
SOCKET4 *socket4 ;
CONNECTION4 *connection ;
CONNECTION4COMMIT_INFO_IN info ;
#ifdef S4DISTRIBUTED
unsigned int dataLen ;
char *data ;
int numServers, rc ;
#endif
#ifdef E4ANALYZE
socket4 = 0 ;
connection = 0 ;
memset( &info, 0, sizeof( CONNECTION4COMMIT_INFO_IN ) ) ;
#endif
#ifdef E4PARM_HIGH
if ( c4 == 0 )
return error4( 0, e4parm_null, E93828 ) ;
#endif
if ( code4transEnabled( c4 ) != 1 )
return error4( c4, e4trans, E83807 ) ;
if ( c4->c4trans.trans.currentTranStatus == r4inactive )
return error4( c4, e4trans, E83812 ) ;
saveRc = code4flush( c4 ) ;
if ( saveRc != 0 )
return saveRc ;
#ifdef S4DISTRIBUTED
if ( c4->servers.nLink == 0 )
#else
if ( c4->defaultServer == 0 )
#endif
if ( c4->defaultServer == 0 )
return error4( c4, e4connection, E80304 ) ;
if ( error4code( c4 ) < 0 )
{
saveErr = error4code( c4 ) ;
error4set( c4, 0 ) ;
}
else
saveErr = 0 ;
saveRc = 0 ;
#ifdef S4DISTRIBUTED
if ( c4->servers.nLink == 1 ) /* simple commit only required */
{
#endif
info.numServers = 1 ;
#ifdef S4DISTRIBUTED
socket4 = (SOCKET4 *)l4first( &c4->servers ) ;
#else
socket4 = c4->defaultServer ;
#endif
connection = socket4->connect ;
connection4assign( connection, CON4COMMIT, 0, 0 ) ;
connection4addData( connection, &info, sizeof( CONNECTION4COMMIT_INFO_IN ), 0 ) ;
connection4send( connection ) ;
saveRc = connection4receive( connection ) ;
if ( saveRc >= 0 )
saveRc = connection4status( connection ) ;
#ifdef S4DISTRIBUTED
}
else
{
info.numServers = c4->servers.nLink ;
dataLen = sizeof( CONNECTION4COMMIT_INFO_IN ) + info.numServers * S4STAND_ALONE_ALIAS_LEN ;
data = (char *)u4allocFree( c4, dataLen ) ;
if ( data == 0 )
return error4stack( c4, e4memory, E93828 ) ;
memcpy( data, &info, sizeof( CONNECTION4COMMIT_INFO_IN ) ) ;
rc = 0 ;
socket4 = 0 ;
for( numServers = 0 ;; numServers++ ) /* prepare the info packets */
{
socket4 = (SOCKET4 *)l4next( &c4->servers, socket4 ) ;
if ( socket4 == 0 )
break ;
connection = socket4->connect ;
if ( connection == 0 )
return error4( c4, e4info, E93828 ) ;
memcpy( data + sizeof( CONNECTION4COMMIT_INFO_IN ) + numServers * S4STAND_ALONE_ALIAS_LEN, socket4->serverName, NEED A LOCAL FOR SERVER NAME, SET TO SIZE AND S4MAX_SERVER_NAME_SI
}
rc = 0 ;
socket4 = 0 ;
for( ;; ) /* set commit message to all connected servers */
{
socket4 = (SOCKET4 *)l4next( &c4->servers, socket4 ) ;
if ( socket4 == 0 )
break ;
connection = socket4->connect ;
connection4assign( connection, CON4COMMIT, 0, 0 ) ;
connection4addData( connection, data, dataLen, 0 ) ;
connection4send( connection ) ;
rc = connection4receive( connection ) ;
if ( rc < 0 )
break ;
rc = connection4status( connection ) ;
if ( rc != 0 )
break ;
}
if ( rc != 0 ) /* rollback everybody */
{
for( ;; )
{
socket4 = (SOCKET4 *)l4prev( &c4->servers, socket4 ) ;
if ( socket4 == 0 )
break ;
connection = socket4->connect ;
connection4assign( connection, S4CANCEL_TRANSACTION, 0, 0 ) ;
connection4send( connection ) ;
connection4receive( connection, rc ) ;
}
return rc ;
}
socket4 = 0 ;
for( ;; ) /* complete the commits */
{
socket4 = (SOCKET4 *)l4next( &c4->servers, socket4 ) ;
if ( socket4 == 0 )
break ;
connection = socket4->connect ;
connection4assign( connection, S4COMPLETE, 0, 0 ) ;
connection4send( connection ) ;
rc = connection4receive( connection ) ;
if ( rc < 0 )
{
saveRc = rc ;
error4set( c4, 0 ) ;
continue ;
}
rc = connection4status( connection ) ;
if ( rc < 0 )
{
saveRc = rc ;
error4set( c4, 0 ) ;
continue ;
}
}
}
#endif
if ( saveErr == 0 )
saveErr = saveRc ;
if ( saveErr != 0 )
error4set( c4, saveErr ) ;
c4->c4trans.trans.currentTranStatus = r4inactive ;
tran4lowCloseDelayed( &c4->c4trans.trans ) ;
return 0 ;
}
int S4FUNCTION code4tranStart( CODE4 *c4 )
{
CONNECTION4 *connection ;
int rc ;
#ifdef S4DISTRIBUTED
SOCKET4 *socket4 ;
#endif
#ifdef E4PARM_HIGH
if ( c4 == 0 )
return error4( 0, e4parm_null, E93829 ) ;
#endif
if ( code4transEnabled( c4 ) != 1 )
return error4( c4, e4trans, E83807 ) ;
if ( c4->c4trans.trans.currentTranStatus == r4active )
return error4( c4, e4trans, E93829 ) ;
rc = 0 ;
#ifdef S4DISTRIBUTED
socket4 = 0 ;
for( ;; ) /* set start message to all connected servers */
{
socket4 = (SOCKET4 *)l4next( &c4->servers, socket4 ) ;
if ( socket4 == 0 )
break ;
connection = socket4->connect ;
connection4assign( connection, CON4START, 0, 0 ) ;
connection4send( connection ) ;
rc = connection4receive( connection ) ;
if ( rc < 0 )
break ;
rc = connection4status( connection ) ;
if ( rc != 0 )
{
if ( rc < 0 )
connection4error( connection, c4, rc, E93829 ) ;
break ;
}
}
#else
if ( c4->defaultServer == 0 )
return error4( c4, e4connection, E80304 ) ;
if ( c4->defaultServer != 0 )
{
connection = c4->defaultServer->connect ;
connection4assign( connection, CON4START, 0, 0 ) ;
connection4send( connection ) ;
rc = connection4receive( connection ) ;
if ( rc >= 0 )
rc = connection4status( connection ) ;
}
if ( rc < 0 )
return error4stack( c4, rc, E93829 ) ;
#endif
c4->c4trans.trans.currentTranStatus = r4active ;
return rc ;
/* code4save()*/
}
int S4FUNCTION code4tranRollback( CODE4 *c4 )
{
CONNECTION4 *connection ;
int rc ;
#ifdef S4DISTRIBUTED
SOCKET4 *socket4 ;
#endif
#ifdef E4PARM_HIGH
if ( c4 == 0 )
return error4( 0, e4parm_null, E93830 ) ;
#endif
if ( code4transEnabled( c4 ) != 1 )
return error4( c4, e4trans, E83807 ) ;
if ( c4->c4trans.trans.currentTranStatus == r4inactive )
return error4( c4, e4trans, E83808 ) ;
#ifdef S4DISTRIBUTED
socket4 = 0 ;
for( ;; ) /* set start message to all connected servers */
{
socket4 = (SOCKET4 *)l4next( &c4->servers, socket4 ) ;
if ( socket4 == 0 )
break ;
connection = socket4->connect ;
connection4assign( connection, TRAN4ROLLBACK, 0, 0 ) ;
connection4send( connection ) ;
rc = connection4receive( connection ) ;
if ( rc < 0 )
return error4( c4, rc, E93830 ) ;
rc = connection4status( connection ) ;
if ( rc < 0 )
return connection4error( connection, c4, rc, E93830 ) ;
}
#else
if ( c4->defaultServer == 0 )
return error4( c4, e4connection, E80304 ) ;
if ( c4->defaultServer != 0 )
{
connection = c4->defaultServer->connect ;
connection4assign( connection, CON4ROLLBACK, 0, 0 ) ;
connection4send( connection ) ;
rc = connection4receive( connection ) ;
if ( rc >= 0 )
rc = connection4status( connection ) ;
if ( rc != 0 )
return error4stack( c4, rc, E93830 ) ;
}
#endif
c4->c4trans.trans.currentTranStatus = r4inactive ;
/* 04/24/96 AS --> moved code4invalidate before unlock call, so that any
changes left to records won't be flushed as a result of the unlock
call */
code4invalidate( c4 ) ;
rc = code4unlock( c4 ) ;
if ( rc < 0 )
return rc ;
tran4lowCloseDelayed( &c4->c4trans.trans ) ;
return 0 ;
/* code4restore( c4 ) ;*/
}
#endif
#ifdef S4STAND_ALONE
int S4FUNCTION code4transFileEnable( CODE4TRANS *c4trans, const char *logName, const int doCreate )
#else
int code4transFileEnable( CODE4TRANS *c4trans, const char *logName, const int doCreate )
#endif
{
#ifdef E4ANALYZE
int rc ;
#else
#ifndef S4CLIENT
int rc ;
#endif
#endif
#ifndef S4CLIENT
CODE4 *c4 ;
#endif
if ( c4trans->enabled == 1 )
return 0 ;
#ifdef S4STAND_ALONE
rc = code4tranInitLow( &c4trans->trans, c4trans ) ;
if ( rc < 0 )
return rc ;
#endif
#ifdef E4ANALYZE
if ( ( rc = code4transVerify( c4trans, 1 ) ) < 0 )
return rc ;
#endif
#ifndef S4CLIENT
rc = 0 ;
c4 = c4trans->c4 ;
if ( c4trans->enabled == 0 )
{
if ( logName != 0 )
{
if ( c4->transFileName != 0 )
u4free( c4->transFileName ) ;
c4->transFileName = (char *)u4allocFree( c4, (long)strlen( logName ) + 1L ) ;
if ( c4->transFileName == 0 )
rc = e4memory ;
else
strcpy( c4->transFileName, logName ) ;
}
if( c4->transFileName != 0 )
{
#ifdef S4SERVER
rc = tran4fileInit( &c4->server->transFile, c4trans ) ;
#else
rc = tran4fileInit( &c4->transFile, c4trans ) ;
#endif
if ( rc == 0 )
{
if ( doCreate == 0 )
{
#ifdef S4SERVER
rc = tran4fileOpen( &c4->server->transFile, c4->transFileName ) ;
#else
rc = tran4fileOpen( &c4->transFile, c4->transFileName ) ;
#endif
}
else
{
#ifdef S4SERVER
rc = tran4fileCreate( &c4->server->transFile, c4->transFileName ) ;
#else
rc = tran4fileCreate( &c4->transFile, c4->transFileName ) ;
#endif
}
if ( rc == 0 )
{
c4trans->enabled = 1 ;
#ifdef S4SERVER
c4trans->transFile = &c4->server->transFile ;
#else
c4trans->transFile = &c4->transFile ;
#endif
}
}
}
}
if ( rc != 0 )
{
u4free( c4->transFileName ) ;
c4->transFileName = 0 ;
}
return rc ;
#else
return 0 ;
#endif
}
#ifndef S4CLIENT
int tran4addUser( TRAN4 *trans, const long clientId, const char *charId, const unsigned short int lenIn )
{
int rc ;
short int netIdLen ;
unsigned short int len ;
char *netId ;
CODE4 *c4 ;
#ifdef S4STAND_ALONE
#ifndef S4OFF_MULTI
int i, oldNumAttempts ;
#endif
#endif
len = lenIn ;
c4 = trans->c4trans->c4 ;
if ( trans->c4trans->enabled == 1 && code4tranStatus( c4 ) != r4off )
{
#ifdef S4STAND_ALONE
#ifdef S4OFF_MULTI
trans->userIdNo = 1 ; /* only one user */
#else
if ( clientId == 0L ) /* need to manually get the id */
{
for ( i = 0 ;; i++ )
{
if ( i >= TRAN4MAX_USERS )
return error4( c4, e4max, E83816 ) ;
oldNumAttempts = c4->lockAttempts ;
c4->lockAttempts = 1 ;
rc = file4lock( &trans->c4trans->transFile->file, TRAN4LOCK_USERS+i+1, 1 ) ;
c4->lockAttempts = oldNumAttempts ;
if ( rc == 0 )
{
trans->userIdNo = i + 1 ;
break ;
}
}
}
#endif
#endif
if ( len > sizeof( trans->userId ) )
len = sizeof( trans->userId ) - 1 ;
memcpy( trans->userId, charId, len ) ;
trans->userId[len] = 0 ;
#ifdef S4SERVER
netId = connection4netUserId( c4->currentClient->connection->net ) ;
if ( netId == 0 )
netIdLen = 0 ;
else
netIdLen = strlen( netId ) ;
#else
netId = (char *)0 ;
netIdLen = 0 ;
#endif
rc = tran4set( trans, trans->currentTranStatus, -1L, clientId, TRAN4INIT, len + netIdLen + sizeof( len ) + sizeof( netIdLen), 0L, 0L ) ;
if ( rc < 0 )
return rc ;
if ( tran4putData( trans, (void *)&netIdLen, sizeof( netIdLen ) ) == e4memory )
return e4memory ;
if ( netIdLen != 0 )
if ( tran4putData( trans, (void *)netId, (unsigned int)netIdLen ) == e4memory )
return e4memory ;
if ( tran4putData( trans, (void *)&len, sizeof( len ) ) == e4memory )
return e4memory ;
if ( tran4putData( trans, (void *)charId, len ) == e4memory )
return e4memory ;
if ( tran4lowAppend( trans, 0 ) != 0 )
return e4transAppend ;
}
else
return e4trans ; /* must return error to client so it is known that code4tranInit failed */
return 0 ;
}
#endif /* S4CLIENT */
#endif /* S4OFF_WRITE */
#endif /* S4OFF_TRAN */
#ifndef S4SERVER
#ifdef P4ARGS_USED
#pragma argsused
#endif
int S4FUNCTION code4lock( CODE4 *c4 )
{
#ifdef S4OFF_MULTI
return 0 ;
#else
LOCK4 *lock ;
#ifdef S4CLIENT
int numLocks, unlockData ;
int outRc = 0 ;
CONNECTION4 *connection ;
CONNECTION4LOCK_GROUP_INFO_IN info ;
#else
LOCK4 *lockNext ;
LIST4 locked ;
int saveErr, count, saveUnlockAuto ;
#endif
int rc = 0 ;
CODE4TRANS *c4trans ;
#ifdef E4ANALYZE
if ( ( rc = code4verify( c4, 1 ) ) < 0 )
return rc ;
#endif
c4trans = &c4->c4trans ;
#ifdef S4CLIENT
numLocks = c4trans->trans.locks.nLink ;
if ( numLocks > 0 )
{
lock = (LOCK4 *)l4first( &c4trans->trans.locks ) ; /* for next line */
connection = lock->data->dataFile->connection ;
info.numLocks = numLocks ;
connection4assign( connection, CON4LOCK_GROUP, 0L, 0L ) ;
connection4addData( connection, &info, sizeof( info ), 0 ) ;
lock = (LOCK4 *)l4first( &c4trans->trans.locks ) ; /* reset */
unlockData = ( code4unlockAuto( c4 ) == LOCK4DATA ) ; /* must perform and register data unlock */
for( numLocks = info.numLocks ; numLocks > 0 ; numLocks-- )
{
#ifdef E4ANALYZE
if ( lock == 0 )
return error4stack( c4, e4struct, E91008 ) ;
#endif
if ( unlockData )
d4unlockClientData( lock->data ) ;
connection4addData( connection, &lock->id, sizeof( LOCK4ID ), 0 ) ;
lock = (LOCK4 *)l4next( &c4trans->trans.locks, lock ) ;
}
outRc = connection4repeat( connection, -2, -1, -1, 0 ) ;
if ( outRc < 0 )
return connection4error( connection, c4, outRc, E91008 ) ;
if ( outRc == r4locked )
return outRc ;
for( ;; ) /* now free lock memory, and record locks if required */
{
lock = (LOCK4 *)l4first( &c4trans->trans.locks ) ;
if ( lock == 0 )
break ;
if ( outRc == 0 ) /* record lock */
{
switch( lock->id.type )
{
case LOCK4APPEND:
lock->data->dataFile->appendLock = lock->data ;
break ;
case LOCK4FILE:
lock->data->dataFile->fileLock = lock->data ;
break ;
case LOCK4ALL:
lock->data->dataFile->fileLock = lock->data ;
break ;
case LOCK4RECORD:
d4localLockSet( lock->data, lock->id.recNum ) ;
break ;
#ifdef E4ANALYZE
default:
return error4( c4, e4lock, E81505 ) ;
#endif
}
}
l4remove( &c4trans->trans.locks, lock ) ;
mem4free( c4->lockMemory, lock ) ;
}
}
return outRc ;
#else
saveUnlockAuto = code4unlockAuto( c4 ) ;
if ( saveUnlockAuto == 1 )
{
rc = code4unlockDo( tran4dataList( &c4->c4trans.trans ) ) ;
if ( rc < 0 )
return error4stack( c4, rc, E91008 ) ;
}
code4unlockAutoSet( c4, 0 ) ;
memset( &locked, 0, sizeof( locked ) ) ;
for ( lock = 0, count = -1 ;; )
{
if ( lock == 0 )
{
lock = (LOCK4 *)l4first( &c4trans->trans.locks ) ;
count++ ;
if ( c4->lockAttemptsSingle != WAIT4EVER )
if ( count >= c4->lockAttemptsSingle ) /* timed out */
for ( ;; )
{
lock = (LOCK4 *)l4first( &locked ) ;
if ( lock == 0 )
{
code4unlockAutoSet( c4, saveUnlockAuto ) ;
return r4locked ;
}
lockNext = (LOCK4 *)l4next( &locked, lock ) ;
l4remove( &locked, lock ) ;
l4add( &c4trans->trans.locks, lock ) ;
lock = lockNext ;
}
}
if ( lock == 0 )
{
code4unlockAutoSet( c4, saveUnlockAuto ) ;
return 0 ;
}
switch( lock4lock( lock ) )
{
case r4success:
lockNext = (LOCK4 *)l4next( &c4trans->trans.locks, lock ) ;
l4remove( &c4trans->trans.locks, lock ) ;
l4add( &locked, lock ) ;
lock = lockNext ;
if ( lock == 0 )
{
for ( ;; )
{
lock = (LOCK4 *)l4first( &locked ) ;
if ( lock == 0 )
break ;
l4remove( &locked, lock ) ;
mem4free( c4->lockMemory, lock ) ;
}
code4unlockAutoSet( c4, saveUnlockAuto ) ;
return 0 ;
}
break ;
case r4locked:
lock = (LOCK4 *)l4next( &c4trans->trans.locks, lock ) ;
break ;
default:
saveErr = error4set( c4trans->c4, 0 ) ;
for ( ;; )
{
lock = (LOCK4 *)l4first( &locked ) ;
if ( lock == 0 )
{
error4set( c4trans->c4, saveErr ) ;
code4unlockAutoSet( c4, saveUnlockAuto ) ;
return -1 ;
}
l4remove( &locked, lock ) ;
l4add( &c4trans->trans.locks, lock ) ;
lock4unlock( lock ) ;
}
}
}
#endif /* S4CLIENT */
#endif /* S4OFF_MULTI */
}
#endif /* not S4SERVER */
#ifdef S4SERVER
int tran4closeAll( TRAN4 *trans )
{
DATA4 *dataOn, *dataNext ;
int rc ;
LIST4 *list ;
#ifdef E4PARM_LOW
if ( trans == 0 )
return error4( 0, e4parm_null, E93801 ) ;
#endif
rc = 0 ;
list = tran4dataList( trans ) ;
#ifdef E4ANALYZE
if ( list == 0 )
return error4( trans->c4trans->c4, e4struct, E93801 ) ;
#endif
for ( dataNext = (DATA4 *)l4first( list ) ;; )
{
dataOn = dataNext ;
if ( !dataOn )
break ;
dataNext = (DATA4 *)l4next( list, dataNext ) ;
if ( d4close( dataOn ) < 0 )
rc = -1 ;
}
if ( error4code( trans->c4trans->c4 ) < 0 )
return -1 ;
return rc ;
}
#endif /* S4SERVER */
#ifdef E4ANALYZE
static int code4transVerify( CODE4TRANS *c4trans, int subs )
{
int rc ;
if ( c4trans == 0 )
return error4( 0, e4parm_null, E93832 ) ;
if ( subs == 1 )
{
if ( ( rc = code4verify( c4trans->c4, 1 ) ) < 0 )
return rc ;
}
else
if ( c4trans->c4 == 0 )
return error4( 0, e4struct, E93832 ) ;
#ifndef S4OFF_TRAN
#ifndef S4OFF_WRITE
#ifndef S4CLIENT
if ( c4trans->enabled == 1 )
if ( c4trans->transFile == 0 )
return error4( c4trans->c4, e4struct, E93832 ) ;
#endif
#endif
#endif
return 0 ;
}
int tran4verify( TRAN4 *t4, int subs )
{
int rc ;
#ifndef S4OFF_TRAN
CODE4 *c4 ;
#endif
if ( t4 == 0 )
return error4( 0, e4parm_null, E93801 ) ;
if ( t4->c4trans == 0 )
return error4( 0, e4struct, E93801 ) ;
#ifndef S4OFF_TRAN
c4 = t4->c4trans->c4 ;
if ( ( c4->tranDataLen != 0 && c4->tranData == 0 ) || ( c4->tranDataLen == 0 && c4->tranData != 0 ) )
return error4( c4, e4struct, E93801 ) ;
if ( ( t4->dataPos != 0 && c4->tranDataLen == 0 ) )
return error4( c4, e4struct, E93801 ) ;
#endif
if ( subs == 1 )
if ( ( rc = code4transVerify( t4->c4trans, 1 ) ) < 0 )
return rc ;
return 0 ;
}
#endif /* E4ANALYZE */
int code4tranInitLow( TRAN4 *t4, CODE4TRANS *c4trans )
{
#ifdef E4PARM_LOW
if ( t4 == 0 || c4trans == 0 )
return error4( 0, e4parm_null, E93834 ) ;
#endif
t4->c4trans = c4trans ;
#ifndef S4OFF_WRITE
t4->transId = -1 ;
t4->dataPos = 0 ;
t4->pos = -1 ;
#endif
#ifdef S4CLIENT
t4->dataIdCount = 1 ;
#endif
#ifdef S4SERVER
t4->unlockAuto = 1 ;
#endif
#ifndef S4OFF_WRITE
t4->currentTranStatus = r4inactive ;
#endif
tran4dataListSet( t4, &(t4->localDataList) ) ;
#ifdef E4ANALYZE
return tran4verify( t4, 0 ) ;
#else
return 0 ;
#endif
}
#ifdef P4ARGS_USED
#pragma argsused
#endif
int S4FUNCTION code4transInitUndo( CODE4TRANS *c4trans )
{
#ifndef S4OFF_WRITE
#ifndef S4CLIENT
CODE4 *c4 ;
#ifndef S4OFF_TRAN
int rc, oldError ;
LOG4HEADER header ;
short int i ;
#ifdef S4STAND_ALONE
#ifndef S4OFF_MULTI
int oldNumAttempts ;
#endif
#endif
#endif
#endif
#endif
#ifdef E4PARM_LOW
if ( c4trans == 0 )
return error4( 0, e4parm_null, E93835 ) ;
#endif
#ifdef S4OFF_WRITE
return 0 ;
#else
#ifdef S4CLIENT
return 0 ;
#else
c4 = c4trans->c4 ;
if ( c4 != 0 )
if ( c4->transFileName != 0 )
{
u4free( c4->transFileName ) ;
c4->transFileName = 0 ;
}
#ifndef S4OFF_TRAN
oldError = error4set( c4trans->c4, 0 ) ;
rc = 0 ;
if ( c4trans->transFile != 0 )
{
#ifdef S4STAND_ALONE
#ifndef S4UTILS
code4tranInitUndoLow( &c4trans->trans, 0L ) ;
if (c4trans->trans.currentTranStatus == r4inactive)
{
#ifndef S4OFF_MULTI
file4unlock( &c4trans->transFile->file, TRAN4LOCK_USERS + c4trans->trans.userIdNo, 1 ) ;
oldNumAttempts = c4->lockAttempts ;
c4->lockAttempts = 1 ;
if ( file4lock( &c4trans->transFile->file, TRAN4LOCK_USERS, TRAN4MAX_USERS ) != r4locked ) /* last user, so shutdown */
#endif
{
#endif /* S4UTILS */
#endif /* S4STAND_ALONE */
#ifndef S4UTILS
if ( c4trans->transFile->status == 0 )
{
memset( &header, 0, sizeof( header ) ) ;
header.type = TRAN4SHUTDOWN ;
header.serverDataId = TRAN4VERSION_NUM ;
tran4fileAppend( c4trans->transFile, &header, "\0" ) ;
}
#endif
#ifdef S4STAND_ALONE
#ifndef S4UTILS
#ifndef S4OFF_MULTI
file4unlock( &c4trans->transFile->file, TRAN4LOCK_USERS, TRAN4MAX_USERS ) ;
#endif
}
#ifndef S4OFF_MULTI
c4->lockAttempts = oldNumAttempts ;
#endif
}
#endif /* S4UTILS */
#endif /* S4STAND_ALONE */
i = -1;
#ifndef S4OFF_MULTI
#ifndef S4UTILS
while ( (1UL << ++i ) <= c4trans->transFile->fileLocks )
if ( c4trans->transFile->fileLocks & ( 1UL << i ) )
code4tranUnlockTransactions( c4trans, TRAN4LOCK_BASE + i ) ;
#endif
#endif
rc = tran4fileClose( c4trans->transFile ) ;
c4trans->transFile = 0 ;
}
c4trans->enabled = 0 ;
error4set( c4trans->c4, oldError ) ;
return rc ;
#else
return 0 ;
#endif /* S4OFF_TRAN */
#endif /* S4CLIENT */
#endif
}
#ifdef S4SERVER
int code4transInit( CODE4TRANS *c4trans, CODE4 *c4 )
{
#ifndef S4SERVER
int rc ;
#endif
#ifdef E4PARM_LOW
if ( c4trans == 0 || c4 == 0 )
return error4( 0, e4parm_null, E93836 ) ;
#endif
#ifndef S4OFF_TRAN
#ifndef S4CLIENT
#ifdef E4ANALYZE
if ( c4trans->enabled != 0 )
return error4( 0, e4struct, E93836 ) ;
#endif
#endif
#endif
memset( c4trans, 0, sizeof( c4trans ) ) ;
#ifdef E4ANALYZE
if ( c4->debugInt != E4DEBUG_INT ) /* not initialized */
return error4( 0, e4struct, E81301 ) ;
#endif
c4trans->c4 = c4 ;
#ifndef S4SERVER
rc = code4tranInitLow( &c4trans->trans, c4trans ) ;
if ( rc < 0 )
return rc ;
#endif
#ifdef E4ANALYZE
return code4transVerify( c4trans, 0 ) ;
#else
return 0 ;
#endif
}
#endif
#ifndef S4CLIENT
#ifdef S4SERVER
/*
int d4tagUniqueSync( DATA4 *data )
{
TAG4 *tag ;
#ifdef E4PARM_LOW
if ( data == 0 )
return error4( 0, e4parm_null, E96501 ) ;
#endif
for ( tag = 0 ;; )
{
tag = d4tagNext( data, tag ) ;
if ( tag == 0 )
break ;
tag->tagFile->uniqueError = tag->uniqueError ;
}
return 0 ;
}
*/
#endif /* S4SERVER */
#ifndef S4OFF_MULTI
#ifndef S4OFF_TRAN
/* ensure only one process is accessing the transaction file */
int S4FUNCTION code4tranLockTransactions( CODE4TRANS *c4trans, long lockByte )
{
int rc, oldAttempts ;
#ifdef E4ANALYZE
if ( code4transVerify( c4trans, 1 ) < 0 )
return 0 ;
#endif
if ( lockByte < TRAN4LOCK_BASE )
return e4parm ;
if ( c4trans->transFile->fileLocks & ( 1UL << ( lockByte - TRAN4LOCK_BASE ) ) )
return 0 ;
oldAttempts = c4trans->c4->lockAttempts ;
c4trans->c4->lockAttempts = 1 ;
rc = file4lock( &c4trans->transFile->file, lockByte, 1L ) ;
c4trans->c4->lockAttempts = oldAttempts ;
if ( rc == 0 )
c4trans->transFile->fileLocks |= ( 1UL << ( lockByte - TRAN4LOCK_BASE ) ) ;
return rc ;
}
#ifndef S4UTILS
int S4FUNCTION code4tranUnlockTransactions( CODE4TRANS *c4trans, long lockByte )
{
#ifdef E4ANALYZE
if ( code4transVerify( c4trans, 1 ) < 0 )
return 0 ;
#endif
if ( lockByte < TRAN4LOCK_BASE )
return e4parm ;
if ( !(c4trans->transFile->fileLocks & ( 1UL << ( lockByte - TRAN4LOCK_BASE ) ) ) )
return e4unlock ;
return file4unlock( &c4trans->transFile->file, lockByte, 1L ) ;
}
#endif /* S4UTILS */
#endif /* S4OFF_TRAN */
int tran4lock( TRAN4 *trans )
{
LOCK4 *lock, *lockNext ;
LIST4 locked ;
int saveErr, rc, saveUnlockAuto ;
CODE4 *c4 ;
#ifdef E4ANALYZE
if ( ( rc = tran4verify( trans, 1 ) ) < 0 )
return rc ;
#endif
c4 = trans->c4trans->c4 ;
saveUnlockAuto = code4unlockAuto( c4 ) ;
if ( saveUnlockAuto == 1 )
{
rc = code4unlockDo( tran4dataList( trans ) ) ;
if ( rc < 0 )
return error4stack( c4, rc, 0L ) ;
}
code4unlockAutoSet( c4, 0 ) ;
#ifndef S4CLIENT
memset( &locked, 0, sizeof( locked ) ) ;
#endif
lock = (LOCK4 *)l4first( &trans->locks ) ;
for ( ;; )
{
if ( lock == 0 )
{
for ( ;; )
{
lock = (LOCK4 *)l4first( &locked ) ;
if ( lock == 0 )
{
code4unlockAutoSet( c4, saveUnlockAuto ) ;
#ifdef S4CLIENT
return saveRc ;
#else
return 0 ;
#endif
}
lockNext = (LOCK4 *)l4next( &locked, lock ) ;
l4remove( &locked, lock ) ;
mem4free( c4->lockMemory, lock ) ;
lock = lockNext ;
}
}
switch( lock4lock( lock ) )
{
case r4success:
lockNext = (LOCK4 *)l4next( &trans->locks, lock ) ;
l4remove( &trans->locks, lock ) ;
l4add( &locked, lock ) ;
lock = lockNext ;
break ;
case r4locked:
lock = (LOCK4 *)l4next( &trans->locks, lock ) ;
#ifdef S4SERVER
for ( ;; )
{
lock = (LOCK4 *)l4first( &locked ) ;
if ( lock == 0 )
return r4locked ;
l4remove( &locked, lock ) ;
l4add( &trans->locks, lock ) ;
lock4unlock( lock ) ;
}
#else
break ;
#endif
default:
saveErr = error4set( trans->c4trans->c4, 0 ) ;
for ( ;; )
{
lock = (LOCK4 *)l4first( &locked ) ;
if ( lock == 0 )
{
code4unlockAutoSet( c4, saveUnlockAuto ) ;
error4set( trans->c4trans->c4, saveErr ) ;
return -1 ;
}
l4remove( &locked, lock ) ;
l4add( &trans->locks, lock ) ;
lock4unlock( lock ) ;
}
}
}
}
#endif /* S4OFF_MULTI */
#endif /* S4SERVER */
#ifndef S4CLIENT
static DATA4 *tran4dataFull( TRAN4 *trans, const long serverId, const long clientId )
{
DATA4 *data ;
LIST4 *oldList ;
data = tran4data( trans, serverId, clientId ) ;
if ( data != 0 )
return data ;
oldList = tran4dataList( trans ) ;
tran4dataListSet( trans, &trans->closedDataFiles ) ;
data = tran4data( trans, serverId, clientId ) ;
tran4dataListSet( trans, oldList ) ;
return data ;
}
#endif
#ifdef S4SERVER
/* to get a DATA4 based on id instead of TRAN4 */
DATA4 *code4idData( CODE4 *c4, const long serverId, const long clientId )
{
SERVER4CLIENT *client ;
DATA4 *data ;
for( client = 0 ;; )
{
client = (SERVER4CLIENT *)l4next( &c4->server->clients, client ) ;
if ( client == 0 )
break ;
data = tran4data( &client->trans, serverId, clientId ) ;
if ( data != 0 )
return data ;
}
return 0 ;
}
#endif
#ifndef S4CLIENT
#ifdef P4ARGS_USED
#pragma argsused
#endif
/* are there any active transactions which conflict with the data4? */
int tran4active( CODE4 *c4, DATA4 *data )
{
#ifndef S4OFF_TRAN
#ifndef S4STAND_ALONE
SERVER4CLIENT *client ;
DATA4 *dataLoop ;
#endif
#endif
#ifndef S4OFF_TRAN
if ( code4transEnabled( c4 ) )
if ( code4trans( c4 )->currentTranStatus == r4active )
return e4transViolation ;
#ifdef S4STAND_ALONE
if ( data->logVal == LOG4TRANS ) /* not logging this datafile, and not a transaction in progress... */
return 0 ;
#endif
#ifdef S4SERVER
if ( data->accessMode != OPEN4DENY_NONE ) /* if denying others write access, then can proceed */
return 0 ;
#endif
#ifdef S4OFF_MULTI
return 0 ;
#else
#ifdef S4STAND_ALONE
if ( d4lockTestFile( data ) == 1 )
return 0 ;
if ( data->dataFile->file.lowAccessMode != OPEN4DENY_NONE )
return 0 ;
/* in stand-alone, can't check active transactions, so just deny */
return error4( c4, e4transViolation, E81504 ) ;
#else
if ( dfile4lockTestFile( data->dataFile, data4clientId( data ), data4serverId( data ) ) == 1 )
return 0 ;
/* if file not ultimately opened exclusively, may be problems */
if ( data->dataFile->file.lowAccessMode == OPEN4DENY_NONE )
return error4( c4, e4transViolation, E81504 ) ;
for ( client = 0 ;; )
{
client = (SERVER4CLIENT *)l4next( &c4->server->clients, client ) ;
if ( client == 0 )
break ;
if ( client->trans.c4trans->enabled )
if ( client->trans.currentTranStatus == r4active )
{
/* check if that user has a data4 using the same datafile */
for( dataLoop = 0 ;; )
{
dataLoop = (DATA4 *)l4next( client->trans.dataList, dataLoop ) ;
if ( dataLoop == 0 )
break ;
if ( dataLoop->readOnly == 0 )
if ( dataLoop->dataFile == data->dataFile )
return error4( c4, e4transViolation, E81504 ) ;
}
}
}
return 0 ;
#endif
#endif
#else
return 0 ;
#endif /* S4OFF_TRAN */
}
#endif
#ifdef P4ARGS_USED
#pragma argsused
#endif
void S4FUNCTION code4lockClear( CODE4 *c4 )
{
#ifndef S4OFF_MULTI
LOCK4 *lock ;
TRAN4 *trans ;
#ifdef E4PARM_HIGH
if ( c4 == 0 )
{
error4( 0, e4parm_null, E91018 ) ;
return ;
}
#endif
#ifdef S4SERVER
trans = &c4->currentClient->trans ;
#else
trans = &c4->c4trans.trans ;
#endif
for ( ;; )
{
lock = (LOCK4 *)l4first( &trans->locks ) ;
if ( lock == 0 )
break ;
l4remove( &trans->locks, lock ) ;
mem4free( c4->lockMemory, lock ) ;
}
#endif /* S4OFF_MULTI */
return ;
}