/* 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 ; }