/* d4lock.c (c)Copyright Sequiter Software Inc., 1988-1996. All rights reserved. */ #include "d4all.h" #ifndef S4UNIX #ifdef __TURBOC__ #pragma hdrstop #endif #endif #ifdef S4CLIENT int d4localLockSet( DATA4 *data, const long rec ) { LOCK4LINK *lock, *lockOn ; CODE4 *c4 ; DATA4FILE *dfile ; #ifdef E4MISC long recSave ; #endif #ifdef E4PARM_LOW if ( data == 0 || rec < 1L ) return error4( 0, e4parm_null, E92723 ) ; #endif if ( d4lockTest( data, rec ) == 1 ) return 0 ; c4 = data->codeBase ; dfile = data->dataFile ; #ifdef E4MISC /* verify the order of the list */ lock = (LOCK4LINK *)l4first( &dfile->lockedRecords ) ; if ( lock != 0 ) for ( ;; ) { recSave = lock->recNo ; lock = (LOCK4LINK *)l4next( &dfile->lockedRecords, lock ) ; if ( lock == 0 ) break ; if ( lock->recNo <= recSave ) return error4( c4, e4info, E91102 ) ; } #endif for ( lock = 0 ;; ) { lock = (LOCK4LINK *)l4next( &dfile->lockedRecords, lock ) ; if ( lock == 0 ) break ; if ( lock->data == data && lock->recNo == rec ) return 0 ; } if ( c4->lockLinkMemory == 0 ) { c4->lockLinkMemory = mem4create( c4, c4->memStartLock, sizeof(LOCK4LINK), c4->memExpandLock, 0 ) ; if ( c4->lockLinkMemory == 0 ) return e4memory ; } lock = (LOCK4LINK *)mem4alloc( c4->lockLinkMemory ) ; if ( lock == 0 ) return e4memory ; lock->data = data ; lock->recNo = rec ; for ( lockOn = 0 ;; ) { lockOn = (LOCK4LINK *)l4next( &dfile->lockedRecords, lockOn ) ; if ( lockOn == 0 ) { lockOn = (LOCK4LINK *)l4last( &dfile->lockedRecords ) ; if ( lockOn != 0 ) l4addAfter( &dfile->lockedRecords, lockOn, lock ) ; else { l4add( &dfile->lockedRecords, lock ) ; #ifdef E4MISC if ( l4numNodes( &dfile->lockedRecords ) != 1 ) return error4( c4, e4info, E92723 ) ; #endif } break ; } if ( lockOn->recNo > rec ) { l4addBefore( &dfile->lockedRecords, lockOn, lock ) ; break ; } } return 0 ; } #endif #ifdef S4CB51 int S4FUNCTION d4lock_group( DATA4 *data, const long *recs, const int n_recs ) { CODE4 *c4 ; #ifndef S4SINGLE int i, rc ; #endif #ifdef E4PARM_LOW if ( data == 0 || recs == 0 || n_recs < 0 ) return error4( 0, e4parm_null, E92724 ) ; #endif c4 = data->codeBase ; #ifndef S4SINGLE if ( c4->errorCode < 0 ) return e4codeBase ; if( d4lockTestFile( data ) ) return 0 ; #ifndef S4CLIENT switch( code4unlockAuto( c4 ) ) { case LOCK4ALL : code4lockClear( c4 ) ; rc = error4code( c4 ) ; break ; case LOCK4DATA : rc = d4unlock( data ) ; break ; } if( rc < 0 ) return error4stack( c4, rc, E92724 ) ; #endif for ( i = 0 ; i < n_recs ; i++ ) { rc = d4lockAdd( data, recs[i] ) ; if ( rc != 0 ) { code4lockClear( c4 ) ; return rc ; } } return code4lock( c4 ) ; #else return 0 ; #endif } #endif /* S4CB51 */ #ifdef P4ARGS_USED #pragma argsused #endif int S4FUNCTION d4lock( DATA4 *data, const long rec ) { #ifndef S4SINGLE int rc ; CODE4 *c4 ; #ifdef S4VBASIC if ( c4parm_check( data, 2, E92701 ) ) return -1 ; #endif #ifdef E4PARM_HIGH if ( data == 0 || rec < 1L ) return error4( 0, e4parm, E92701 ) ; #endif c4 = data->codeBase ; if ( error4code( c4 ) < 0 ) return e4codeBase ; if ( d4lockTest( data, rec ) > 0 ) /* if record or file already locked */ return 0 ; #ifdef S4CLIENT /* verify that this app doesn't have it locked elsewhere */ if ( data->dataFile->lockTest != 0 && code4unlockAuto( c4 ) != LOCK4ALL ) { if ( c4->lockAttempts == WAIT4EVER ) return error4( c4, e4lock, E81523 ) ; else return r4locked ; } #else rc = 0 ; switch( code4unlockAuto( c4 ) ) { case LOCK4ALL : rc = code4unlockDo( tran4dataList( data->trans ) ) ; break ; case LOCK4DATA : #ifndef S4INDEX_OFF rc = dfile4unlockIndex( data->dataFile, data4serverId( data ) ); if( rc < 0 ) break ; #endif rc = d4unlockRecords( data ) ; /* next 2 lines added Feb 08/96 AS --> t4mul, not unlocking append bytes */ if ( rc == 0 ) rc = d4unlockAppend( data ) ; break ; default: break ; } if( rc < 0 ) return error4stack( c4, rc, E92701 ) ; #endif #ifdef S4CLIENT rc = dfile4lock( data->dataFile, data4clientId( data ), data4serverId( data ), rec, data ) ; if ( rc == 0 ) rc = d4localLockSet( data, rec ) ; #else rc = dfile4lock( data->dataFile, data4clientId( data ), data4serverId( data ), rec ) ; #endif return rc ; #else return 0 ; #endif } #ifdef P4ARGS_USED #pragma argsused #endif int S4FUNCTION d4lockAddAppend( DATA4 *d4 ) { #ifndef S4SINGLE LOCK4 *lock ; CODE4 *c4 ; int rc ; #ifdef E4PARM_HIGH if ( d4 == 0 ) return error4( 0, e4parm, E92719 ) ; #endif if ( ( rc = d4verify( d4, 1 ) ) < 0 ) return rc ; c4 = d4->codeBase ; if ( c4->lockMemory == 0 ) { c4->lockMemory = mem4create( c4, c4->memStartLock, sizeof(LOCK4), c4->memExpandLock, 0 ) ; if ( c4->lockMemory == 0 ) return 0 ; } lock = (LOCK4 *)mem4alloc( c4->lockMemory ) ; if ( lock == 0 ) return error4stack( c4, e4memory, E92719 ) ; #ifdef S4CLIENT lock->data = d4 ; #else lock->data = d4->dataFile ; #endif lock->id.type = LOCK4APPEND ; lock->id.serverId = data4serverId( d4 ) ; lock->id.clientId = data4clientId( d4 ) ; l4add( &d4->trans->locks, lock ) ; #endif return 0 ; } #ifdef P4ARGS_USED #pragma argsused #endif int S4FUNCTION d4lockAddAll( DATA4 *d4 ) { #ifndef S4SINGLE LOCK4 *lock ; CODE4 *c4 ; int rc ; #ifdef E4PARM_HIGH if ( d4 == 0 ) return error4( 0, e4parm, E92725 ) ; #endif if ( ( rc = d4verify( d4, 1 ) ) < 0 ) return rc ; c4 = d4->codeBase ; if ( c4->lockMemory == 0 ) { c4->lockMemory = mem4create( c4, c4->memStartLock, sizeof(LOCK4), c4->memExpandLock, 0 ) ; if ( c4->lockMemory == 0 ) return 0 ; } lock = (LOCK4 *)mem4alloc( c4->lockMemory ) ; if ( lock == 0 ) return error4stack( c4, e4memory, E92725 ) ; #ifdef S4CLIENT lock->data = d4 ; #else lock->data = d4->dataFile ; #endif lock->id.type = LOCK4ALL ; lock->id.serverId = data4serverId( d4 ) ; lock->id.clientId = data4clientId( d4 ) ; l4add( &d4->trans->locks, lock ) ; #endif return 0 ; } #ifdef P4ARGS_USED #pragma argsused #endif int S4FUNCTION d4lockAddFile( DATA4 *d4 ) { #ifndef S4SINGLE LOCK4 *lock ; CODE4 *c4 ; int rc ; #ifdef E4PARM_HIGH if ( d4 == 0 ) return error4( 0, e4parm, E92720 ) ; #endif if ( ( rc = d4verify( d4, 1 ) ) < 0 ) return rc ; c4 = d4->codeBase ; if ( c4->lockMemory == 0 ) { c4->lockMemory = mem4create( c4, c4->memStartLock, sizeof(LOCK4), c4->memExpandLock, 0 ) ; if ( c4->lockMemory == 0 ) return 0 ; } lock = (LOCK4 *)mem4alloc( c4->lockMemory ) ; if ( lock == 0 ) return error4stack( c4, e4memory, E92720 ) ; #ifdef S4CLIENT lock->data = d4 ; #else lock->data = d4->dataFile ; #endif lock->id.type = LOCK4FILE ; lock->id.serverId = data4serverId( d4 ) ; lock->id.clientId = data4clientId( d4 ) ; l4add( &d4->trans->locks, lock ) ; #endif return 0 ; } #ifdef P4ARGS_USED #pragma argsused #endif int S4FUNCTION d4lockAdd( DATA4 *d4, long rec ) { #ifndef S4SINGLE LOCK4 *lock ; CODE4 *c4 ; int rc ; #ifdef E4PARM_HIGH if ( d4 == 0 || rec < 1L ) return error4( 0, e4parm, E92721 ) ; #endif if ( ( rc = d4verify( d4, 1 ) ) < 0 ) return rc ; c4 = d4->codeBase ; if ( c4->lockMemory == 0 ) { c4->lockMemory = mem4create( c4, c4->memStartLock, sizeof(LOCK4), c4->memExpandLock, 0 ) ; if ( c4->lockMemory == 0 ) return error4stack( c4, e4memory, E92721 ) ; } lock = (LOCK4 *)mem4alloc( c4->lockMemory ) ; if ( lock == 0 ) return error4stack( c4, e4memory, E92721 ) ; #ifdef S4CLIENT lock->data = d4 ; #else lock->data = d4->dataFile ; #endif lock->id.type = LOCK4RECORD ; lock->id.recNum = rec ; lock->id.serverId = data4serverId( d4 ) ; lock->id.clientId = data4clientId( d4 ) ; l4add( &d4->trans->locks, lock ) ; #endif return 0 ; } #ifdef S4CLIENT int S4FUNCTION d4lockAll( DATA4 *data ) { int rc ; #ifdef E4PARM_HIGH if ( data == 0 ) return error4( 0, e4parm, E92702 ) ; #endif if ( error4code( data->codeBase ) < 0 ) return e4codeBase ; if ( d4lockTestFile( data ) == 0 ) { rc = dfile4lockAll( data->dataFile, data4clientId( data ), data4serverId( data ), data ) ; if ( rc == 0 ) data->dataFile->fileLock = data ; return rc ; } return 0 ; } #else /* locks database, memo, and index files */ #ifdef P4ARGS_USED #pragma argsused #endif int S4FUNCTION d4lockAll( DATA4 *data ) { #ifndef S4SINGLE int rc, rc2 ; #ifdef E4PARM_HIGH if ( data == 0 ) return error4( 0, e4parm, E92702 ) ; #endif if ( error4code( data->codeBase ) < 0 ) return e4codeBase ; /* d4lockFile will perform an auto unlock if required */ rc = d4lockFile( data ) ; #ifndef N4OTHER #ifndef S4MEMO_OFF if ( !rc ) if ( data->dataFile->nFieldsMemo > 0 ) rc = dfile4lockMemo( data->dataFile ) ; #endif #endif #ifndef S4INDEX_OFF if ( !rc ) rc = d4lockIndex( data ) ; #endif if( rc ) { switch( code4unlockAuto( data->codeBase ) ) { case LOCK4ALL : rc2 = code4unlockDo( tran4dataList( data->trans ) ) ; break ; case LOCK4DATA : rc2 = d4unlock( data ) ; break ; default: rc2 = 0 ; break ; } if( rc2 < 0 ) return rc2 ; } return rc ; #else return 0 ; #endif } #endif #ifdef P4ARGS_USED #pragma argsused #endif int S4FUNCTION d4lockAppend( DATA4 *data ) { #ifdef S4SINGLE return 0 ; #else CODE4 *c4 ; #ifdef S4CLIENT int rc ; #endif #ifdef S4VBASIC if ( c4parm_check( data, 2, E92708 ) ) return -1 ; #endif #ifdef E4PARM_HIGH if ( data == 0 ) return error4( 0, e4parm, E92708 ) ; #endif c4 = data->codeBase ; if ( error4code( c4 ) < 0 ) return e4codeBase ; if ( d4lockTestAppend( data ) == 0 ) { #ifdef S4CLIENT rc = dfile4lockAppend( data->dataFile, data4clientId( data ), data4serverId( data ), data ) ; if ( rc == 0 ) data->dataFile->appendLock = data ; #ifdef E4LOCK return request4lockTest( d4, LOCK4APPEND, 0L, rc ) ; #else return rc ; #endif #else /* in append case, unlock records only with unlock auto in order to avoid memo reset */ /* changed 06/16 because is failing on lock due to not unlocking */ switch( code4unlockAuto( c4 ) ) { case LOCK4ALL : if ( code4unlockDo( tran4dataList( data->trans ) ) != 0 ) return error4stack( c4, e4unlock, E92709 ) ; break ; case LOCK4DATA : #ifndef S4INDEX_OFF if ( dfile4unlockIndex( data->dataFile, data4serverId( data ) )!= 0 ) return error4stack( c4, e4unlock, E92709 ) ; #endif if ( d4unlockRecords( data ) != 0 ) return error4stack( c4, e4unlock, E92709 ) ; break; default: break ; } return dfile4lockAppend( data->dataFile, data4clientId( data ), data4serverId( data ) ) ; #endif } else return 0 ; #endif } #ifdef P4ARGS_USED #pragma argsused #endif int S4FUNCTION d4lockFile( DATA4 *data ) { #ifdef S4SINGLE return 0 ; #else CODE4 *c4 ; #ifndef S4CLIENT int rc ; #endif #ifdef S4VBASIC if ( c4parm_check( data, 2, E92709 ) ) return -1 ; #endif #ifdef E4PARM_HIGH if ( data == 0 ) return error4( 0, e4parm, E92709 ) ; #endif c4 = data->codeBase ; if ( error4code( c4 ) < 0 ) return e4codeBase ; if ( d4lockTestFile( data ) ) return 0 ; #ifdef S4CLIENT return dfile4lockFile( data->dataFile, data4clientId( data ), data4serverId( data ), data ) ; #else switch( code4unlockAuto( c4 ) ) { case LOCK4ALL : rc = code4unlockDo( tran4dataList( data->trans ) ) ; break ; case LOCK4DATA : rc = d4unlock( data ) ; break ; default: rc = 0 ; break ; } if( rc < 0 ) return error4stack( c4, e4unlock, E92709 ) ; return dfile4lockFile( data->dataFile, data4clientId( data ), data4serverId( data ) ) ; #endif #endif } #ifndef S4SINGLE #ifdef S4CLIENT #ifdef E4LOCK /* this function does a compare of a lock with the server. client and server should always return the same result (input value) */ static int request4lockTest( DATA4 *data, short int lockType, long rec, int clientVal ) { CONNECTION4 *connection ; CONNECTION4LOCK_INFO_IN info ; int rc ; if ( error4code( data->codeBase ) return -1 ; memset( &info, 0, sizeof( CONNECTION4LOCK_INFO_IN ) ) ; connection = data->dataFile->connection ; if ( connection == 0 ) rc = e4connection ; else { connection4assign( connection, CON4LOCK, data4clientId( data ), data4serverId( data ) ) ; info.type = lockType ; info.test = 1 ; connection4addData( connection, &info, sizeof( CONNECTION4LOCK_INFO_IN ), 0 ) ; if ( lockType == LOCK4RECORD ) connection4addData( connection, &rec, sizeof( rec ), 0 ) ; connection4send( connection ) ; rc = connection4receive( connection ) ; if ( rc == 0 ) { rc = connection4status( connection ) ; if ( rc < 0 ) return connection4error( connection, data->codeBase, rc, E92722 ) ; } } if ( rc != clientVal ) return error4( data->codeBase, e4info, E92722 ) ; return rc ; } #endif #endif #endif /* for client, this function also checks the data's CODE4 to see if another access point for the DATA4 has the desired lock. If it does, data->dataFile->lockTest is set to the offending DATA4 */ #ifdef P4ARGS_USED #pragma argsused #endif int S4FUNCTION d4lockTest( DATA4 *data, const long rec ) { #ifndef S4SINGLE int rc ; #ifdef E4PARM_HIGH if ( data == 0 ) return error4( 0, e4parm, E92703 ) ; #endif rc = dfile4lockTest( data->dataFile, data4clientId( data ), data4serverId( data ), rec ) ; #ifdef S4CLIENT if ( rc < 0 ) return rc ; #ifdef E4LOCK return request4lockTest( data, LOCK4RECORD, rec, rc ) ; #endif #endif return rc ; #else return 1 ; #endif } #ifndef S4STAND_ALONE int S4FUNCTION d4lockTestAppendLow( DATA4 *data ) { #ifndef S4SINGLE int rc ; #ifdef E4PARM_HIGH if ( data == 0 ) return error4( 0, e4parm, E92704 ) ; #endif #ifndef S4CLIENT if ( data->accessMode == OPEN4DENY_RW ) return 1 ; #endif rc = dfile4lockTestAppend( data->dataFile, data4clientId( data ), data4serverId( data ) ) ; #ifdef S4CLIENT #ifdef E4LOCK return request4lockTest( data, LOCK4APPEND, 0L, rc ) ; #endif #endif return rc ; #else return 1 ; #endif } #endif #ifdef S4CLIENT int S4FUNCTION d4lockTestFileLow( DATA4 *data ) { #ifndef S4SINGLE int rc ; #ifdef E4PARM_HIGH if ( data == 0 ) return error4( 0, e4parm_null, E92705 ) ; #endif #ifndef S4CLIENT if ( data->accessMode != OPEN4DENY_NONE ) return 1 ; #endif rc = dfile4lockTestFile( data->dataFile, data4clientId( data ), data4serverId( data ) ) ; #ifdef S4CLIENT #ifdef E4LOCK return request4lockTest( data, LOCK4FILE, 0L, rc ) ; #endif #endif return rc ; #else return 1 ; #endif } #endif /* S4CLIENT */