af15e0698b
git-svn-id: svn://10.65.10.50/trunk@4679 c028cbd2-c16b-5b4b-a496-9718f37d4682
2901 lines
74 KiB
C
Executable File
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 ;
|
|
}
|