1997-06-16 13:01:08 +00:00
/* o4opt.c (c)Copyright Sequiter Software Inc., 1988-1996. All rights reserved. */
# include "d4all.h"
# ifdef __TURBOC__
# pragma hdrstop
# endif
# ifndef S4OPTIMIZE_OFF
static int opt4blockAdd ( OPT4BLOCK * , FILE4 * , unsigned , long , long ) ;
static OPT4BLOCK * opt4fileChooseBlock ( FILE4 * ) ;
/* puts block onto bottom of lru-list and assigns the optlist to the block */
# define opt4listLruBottomPlace( o4, b4 ) ( l4add( &((o4)->list), &((b4)->lruLink) ), ( (b4)->optList = (o4) ) )
static void opt4listLruBottomShift ( OPT4BLOCK * ) ;
static void opt4fileReadSpBuffer ( FILE4 * , const unsigned long , int , int ) ;
static void opt4timeReset ( OPT4 * , int , int ) ;
# ifdef S4ADVANCE_TEST
S4EXPORT unsigned S4FUNCTION opt4fileReadFile ( FILE4 S4PTR * , const long , char S4PTR * ) ;
# else
static unsigned opt4fileReadFile ( FILE4 * , const long , char * ) ;
# endif
/* moves the block from the current position to the lru position (l4last)
of the lru - list it is currently on . Also updates the accessCount */
static void opt4listLruBottomShift ( OPT4BLOCK * block )
{
OPT4 * opt ;
LINK4 * link ;
LIST4 * list ;
opt = & block - > file - > codeBase - > opt ;
list = & block - > optList - > list ;
link = ( LINK4 * ) & block - > lruLink ;
if ( link ! = list - > lastNode )
{
if ( list - > selected = = link )
list - > selected = ( LINK4 * ) l4prev ( list , link ) ;
l4remove ( list , link ) ;
l4add ( list , link ) ;
}
if ( ( unsigned int ) ( opt - > accessTimeCount - block - > accessTime ) > opt - > minAccessTimeVariation )
block - > accessTime = opt - > accessTimeCount + + ;
if ( opt - > accessTimeCount = = 0 ) /* time count got reset, so reset for everyone */
opt4timeReset ( opt , 0 , 1 ) ;
block - > hitCount + = block - > file - > hitCountAdd ;
}
static int opt4blockAdd ( OPT4BLOCK * block , FILE4 * file , unsigned blockLen , long hashVal , long position )
{
# ifdef E4PARM_LOW
if ( file = = 0 | | block = = 0 | | hashVal < 0 | | position < 0 )
return error4 ( 0 , e4parm , E92508 ) ;
if ( ( unsigned long ) hashVal > = file - > codeBase - > opt . numLists )
return error4 ( 0 , e4parm , E92508 ) ;
# endif
# ifdef E4ANALYZE
if ( block - > changed ! = 0 )
return error4 ( file - > codeBase , e4struct , E92508 ) ;
# endif
l4add ( & file - > codeBase - > opt . lists [ hashVal ] , block ) ;
block - > len = blockLen ;
block - > pos = position ;
block - > file = file ;
return 0 ;
}
int opt4blockClear ( OPT4BLOCK * block )
{
# ifdef E4PARM_LOW
if ( block = = 0 )
return error4 ( 0 , e4parm_null , E92508 ) ;
# endif
block - > changed = 0 ;
block - > len = 0 ;
block - > pos = 0 ;
block - > file = 0 ;
return 0 ;
}
# ifdef S4WRITE_DELAY
void S4CALL opt4writeCompletionRoutine ( void * inDelay )
{
FILE4WRITE_DELAY * delay ;
delay = ( FILE4WRITE_DELAY * ) inDelay ;
EnterCriticalSection ( & delay - > file - > codeBase - > opt . critical4optWrite ) ;
l4add ( & delay - > file - > codeBase - > opt . delayAvail , ( LINK4 * ) delay - > completionData ) ;
LeaveCriticalSection ( & delay - > file - > codeBase - > opt . critical4optWrite ) ;
}
# endif
# ifndef _MSC_VER
# ifdef P4ARGS_USED
# pragma argsused
# endif
# endif
static int opt4blockFlush ( OPT4 * opt , OPT4BLOCK * block , char buffer , int doDelay )
{
int rc , flushBuffer ;
# ifdef S4WRITE_DELAY
OPT4BLOCK * delayBlock ;
LINK4 * delayLink ;
# endif
# ifdef __SC__ /* compiler bug - cpp */
unsigned long long_val ;
# endif
# ifdef E4PARM_LOW
if ( block = = 0 )
return error4 ( 0 , e4parm_null , E92508 ) ;
# endif
# ifdef E4ANALYZE_ALL
if ( block - > file - > hasDup = = 1 )
if ( file4cmpPart ( block - > file - > codeBase , block - > data , block - > file , block - > pos , block - > len ) ! = 0 )
return error4 ( block - > file - > codeBase , e4opt , E82503 ) ;
# endif
if ( opt - > readFile = = block - > file ) /* check to see if block has been temporarily read-buffered */
if ( ( ( unsigned long ) block - > pos < opt - > readStartPos + opt - > bufferSize ) & & ( ( unsigned long ) block - > pos > = opt - > readStartPos ) )
memcpy ( opt - > readBuffer + block - > pos - opt - > readStartPos , block - > data , block - > len ) ;
if ( buffer & & block - > file - > type = = OPT4DBF )
{
if ( opt - > writeFile ! = block - > file )
flushBuffer = 1 ;
else
{
if ( opt - > writeBlockCount = = opt - > maxBlocks )
flushBuffer = 1 ;
else
{
if ( opt - > writeCurPos ! = ( unsigned long ) block - > pos ) /* not a consecutive write, so check out possibilities */
{
if ( opt - > writeCurPos < ( unsigned long ) block - > pos )
{
if ( ( unsigned long ) block - > pos - opt - > writeCurPos < opt - > blockSize ) /* partially filled block, can just extend */
{
opt - > writeCurPos = ( unsigned long ) block - > pos ;
flushBuffer = 0 ;
}
else
flushBuffer = 1 ;
}
else
flushBuffer = 1 ;
}
else /* just want to write at current spot, so go ahead */
flushBuffer = 0 ;
}
}
# ifdef E4ANALYZE
if ( flushBuffer < 0 | | flushBuffer > 1 )
return error4 ( block - > file - > codeBase , e4info , E92508 ) ;
# endif
if ( flushBuffer = = 1 )
{
if ( ( rc = opt4flushWriteBuffer ( opt ) ) ! = 0 )
return rc ;
opt - > writeFile = block - > file ;
opt - > writeStartPos = opt - > writeCurPos = ( unsigned long ) block - > pos ;
}
memcpy ( opt - > writeBuffer + ( opt - > writeCurPos - opt - > writeStartPos ) , block - > data , block - > len ) ;
opt - > writeCurPos + = block - > len ;
opt - > writeBlockCount + + ;
# ifdef E4ANALYZE_ALL
if ( block - > file - > hasDup = = 1 )
if ( file4cmpPart ( opt - > writeFile - > codeBase , opt - > writeBuffer , opt - > writeFile , opt - > writeStartPos , ( unsigned ) ( opt - > writeCurPos - opt - > writeStartPos ) ) ! = 0 )
return error4 ( block - > file - > codeBase , e4opt , E82503 ) ;
# endif
}
else
{
# ifdef __SC__ /* compiler bug - cpp */
if ( opt - > writeFile = = block - > file )
{
long_val = opt - > writeBlockCount ;
long_val * = opt - > blockSize ;
if ( opt - > writeCurPos > = ( unsigned long ) block - > pos & &
( opt - > writeCurPos - long_val ) < = ( unsigned long ) block - > pos )
if ( ( rc = opt4flushWriteBuffer ( opt ) ) ! = 0 )
return rc ;
}
# else
if ( opt - > writeFile = = block - > file )
if ( opt - > writeCurPos > = ( unsigned long ) block - > pos & &
( opt - > writeCurPos - opt - > writeBlockCount * opt - > blockSize ) < = ( unsigned long ) block - > pos )
if ( ( rc = opt4flushWriteBuffer ( opt ) ) ! = 0 )
return rc ;
# endif
block - > file - > doBuffer = 0 ;
# ifdef S4WRITE_DELAY
if ( doDelay = = 1 & & opt - > delayWriteBuffer ! = 0 )
{
for ( ; ; ) /* wait until a block is available */
{
delayLink = ( LINK4 * ) l4first ( & opt - > delayAvail ) ;
if ( delayLink = = 0 )
Sleep ( 0 ) ;
else
break ;
}
delayBlock = ( OPT4BLOCK * ) ( delayLink - 1 ) ;
EnterCriticalSection ( & opt - > critical4optWrite ) ;
l4remove ( & opt - > delayAvail , delayLink ) ;
LeaveCriticalSection ( & opt - > critical4optWrite ) ;
memcpy ( delayBlock - > data , block - > data , block - > len ) ;
file4writeOpt ( block - > file , block - > pos , delayBlock - > data , block - > len , 1 , opt4writeCompletionRoutine , & delayBlock - > lruLink ) ;
}
else
# endif
{
if ( ( rc = file4writeOpt ( block - > file , block - > pos , block - > data , block - > len , 0 , 0 , 0 ) ) ! = 0 )
return rc ;
}
block - > file - > doBuffer = 1 ;
}
block - > changed = 0 ;
return 0 ;
}
/* esp. in delay-write, may return a different block back to user for
use , instead of the current one */
/*OPT4BLOCK *opt4blockRemove( OPT4 *opt, OPT4BLOCK *block, int doFlush )*/
int opt4blockRemove ( OPT4 * opt , OPT4BLOCK * block , int doFlush )
{
# ifdef E4PARM_LOW
if ( block = = 0 )
{
error4 ( 0 , e4parm_null , E92508 ) ;
return 0 ;
}
# endif
if ( doFlush & & block - > changed )
{
block - > file - > doBuffer = 0 ;
opt4blockFlush ( opt , block , 1 , 1 ) ;
block - > file - > doBuffer = 1 ;
}
if ( block - > file ! = 0 )
{
l4remove ( & opt - > lists [ opt4fileHash ( opt , block - > file , ( unsigned long ) block - > pos ) ] , block ) ;
block - > file = 0 ;
}
opt4blockClear ( block ) ;
/* return block ; */
return 0 ;
}
/* function to remove, without saving, parts of an optimized file */
int opt4fileDelete ( FILE4 * file , long lowPos , long hiPos )
{
long onPos , endDeletePos , hashVal ;
OPT4BLOCK * blockOn ;
OPT4 * opt ;
# ifdef E4PARM_LOW
if ( file = = 0 | | lowPos < 0 | | hiPos < 0 )
return error4 ( 0 , e4parm , E92508 ) ;
# endif
opt = & file - > codeBase - > opt ;
hashVal = opt4fileHash ( opt , file , ( unsigned long ) lowPos ) ;
if ( hashVal ! = opt4fileHash ( opt , file , lowPos + file - > codeBase - > opt . blockSize - 1L ) ) /* not on a block boundary, so delete partial */
{
/* lowPos / blockSize because position must be on a block boundary */
blockOn = opt4fileReturnBlock ( file , lowPos / file - > codeBase - > opt . blockSize , hashVal ) ;
if ( blockOn ) /* block in memory, so partially delete */
{
if ( file - > len < = hiPos ) /* just removing all file, so merely delete */
blockOn - > len = ( unsigned ) ( lowPos - blockOn - > pos ) ;
else /* read the old data into the block - ignore errors since could be eof, else catch later */
file4read ( file , lowPos , ( char * ) blockOn - > data + blockOn - > pos - lowPos , ( unsigned ) ( opt - > blockSize - ( lowPos - blockOn - > pos ) ) ) ;
}
onPos = ( ( lowPos + opt - > blockSize ) > > opt - > blockPower ) < < opt - > blockPower ;
}
else
onPos = lowPos ;
endDeletePos = hiPos + opt - > blockSize - 1 ;
while ( onPos < endDeletePos )
{
/* onPos / blockSize because position must be on a block boundary */
blockOn = opt4fileReturnBlock ( file , onPos / file - > codeBase - > opt . blockSize , opt4fileHash ( opt , file , ( unsigned long ) onPos ) ) ;
if ( blockOn ) /* block in memory, so delete */
{
opt4blockRemove ( opt , blockOn , 0 ) ;
opt4blockLruTop ( blockOn ) ;
l4addBefore ( & opt - > avail , l4first ( & opt - > avail ) , & blockOn - > lruLink ) ;
}
onPos + = opt - > blockSize ;
}
onPos - = opt - > blockSize ;
if ( onPos < hiPos )
{
blockOn = opt4fileReturnBlock ( file , ( unsigned long ) onPos , opt4fileHash ( opt , file , ( unsigned long ) onPos ) ) ;
if ( blockOn )
{
if ( file - > len < = hiPos )
{
opt4blockRemove ( opt , blockOn , 0 ) ;
opt4blockLruTop ( blockOn ) ;
l4addBefore ( & opt - > avail , l4first ( & opt - > avail ) , & blockOn - > lruLink ) ;
}
else
file4read ( file , onPos , blockOn - > data , ( unsigned ) ( hiPos - blockOn - > pos ) ) ;
}
}
return 0 ;
}
int opt4flushAll ( OPT4 * opt , char doFree )
{
OPT4BLOCK * blockOn ;
LINK4 * linkOn , * nextLink ;
LIST4 * flushList ;
2003-05-01 15:14:58 +00:00
int i ;
1997-06-16 13:01:08 +00:00
int rc , saveRc ;
# ifdef E4PARM_LOW
if ( opt = = 0 )
return error4 ( 0 , e4parm_null , E92508 ) ;
# endif
saveRc = opt4flushWriteBuffer ( opt ) ;
for ( i = 0 ; i < OPT4NUM_LISTS ; i + + )
{
flushList = & opt - > prio [ i ] - > list ;
for ( linkOn = ( LINK4 * ) l4first ( flushList ) ; linkOn ! = 0 ; )
{
blockOn = ( OPT4BLOCK * ) ( linkOn - 1 ) ;
if ( blockOn - > changed )
{
rc = opt4blockFlush ( opt , blockOn , 1 , 0 ) ;
if ( rc ! = 0 )
saveRc = rc ;
}
if ( doFree )
{
nextLink = ( LINK4 * ) l4next ( flushList , linkOn ) ;
l4remove ( & opt - > lists [ opt4fileHash ( opt , blockOn - > file , ( unsigned long ) blockOn - > pos ) ] , blockOn ) ;
opt4blockLruTop ( blockOn ) ;
l4add ( & opt - > avail , linkOn ) ;
linkOn = nextLink ;
opt4blockClear ( blockOn ) ;
}
else
linkOn = ( LINK4 * ) l4next ( flushList , linkOn ) ;
}
}
return saveRc ;
}
int opt4fileFlushList ( OPT4 * opt , FILE4 * file , LIST4 * flushList , int doFree )
{
OPT4BLOCK * blockOn ;
LINK4 * linkOn , * nextLink ;
# ifdef E4PARM_LOW
if ( file = = 0 | | flushList = = 0 )
return error4 ( 0 , e4parm , E92508 ) ;
# endif
for ( linkOn = ( LINK4 * ) l4first ( flushList ) ; linkOn ! = 0 ; )
{
blockOn = ( OPT4BLOCK * ) ( linkOn - 1 ) ;
if ( blockOn - > file = = file )
{
if ( blockOn - > changed )
if ( opt4blockFlush ( opt , blockOn , 1 , 0 ) < 0 )
return - 1 ;
if ( doFree )
{
nextLink = ( LINK4 * ) l4next ( flushList , linkOn ) ;
l4remove ( & opt - > lists [ opt4fileHash ( opt , file , ( unsigned long ) blockOn - > pos ) ] , blockOn ) ;
opt4blockLruTop ( blockOn ) ;
l4add ( & opt - > avail , linkOn ) ;
linkOn = nextLink ;
opt4blockClear ( blockOn ) ;
}
else
linkOn = ( LINK4 * ) l4next ( flushList , linkOn ) ;
}
else
linkOn = ( LINK4 * ) l4next ( flushList , linkOn ) ;
}
return 0 ;
}
# ifdef S4WRITE_DELAY
void S4CALL opt4largeWriteCompletionRoutine ( void * delay )
{
/* just resets the avail flag */
* ( ( int * ) ( ( ( FILE4WRITE_DELAY * ) ( delay ) ) - > completionData ) ) = 1 ;
}
# endif
int opt4flushWriteBuffer ( OPT4 * opt )
{
int rc , oldDoBuffer , oldBufferWrites ;
FILE4 * file ;
# ifdef E4PARM_LOW
if ( opt = = 0 )
return error4 ( 0 , e4parm_null , E92508 ) ;
# endif
if ( opt - > writeBlockCount ! = 0 )
{
file = opt - > writeFile ;
# ifdef E4ANALYZE_ALL
if ( file - > hasDup = = 1 )
if ( file4cmpPart ( file - > codeBase , opt - > writeBuffer , file , opt - > writeStartPos , ( unsigned ) ( opt - > writeCurPos - opt - > writeStartPos ) ) ! = 0 )
return error4 ( file - > codeBase , e4opt , E80602 ) ;
# endif
oldDoBuffer = file - > doBuffer ;
oldBufferWrites = file - > bufferWrites ;
file - > doBuffer = 0 ;
file - > bufferWrites = 0 ;
# ifdef S4WRITE_DELAY
if ( opt - > writeBuffer = = opt - > writeBufferActual )
{
opt - > writeBufferActualAvail = 0 ;
rc = file4writeDelay ( file , opt - > writeStartPos , opt - > writeBuffer ,
( unsigned ) ( opt - > writeCurPos - opt - > writeStartPos ) , opt4largeWriteCompletionRoutine , & opt - > writeBufferActualAvail ) ;
while ( opt - > delayLargeBufferAvail ! = 1 ) /* wait so we can use this buffer */
Sleep ( 0 ) ;
opt - > writeBuffer = opt - > delayLargeBuffer ;
}
else
{
# ifdef E4ANALYZE
if ( opt - > writeBuffer ! = opt - > delayLargeBuffer )
return error4 ( 0 , e4struct , E92508 ) ;
# endif
opt - > delayLargeBufferAvail = 0 ;
rc = file4writeDelay ( file , opt - > writeStartPos , opt - > writeBuffer , ( unsigned ) ( opt - > writeCurPos - opt - > writeStartPos ) , opt4largeWriteCompletionRoutine , & opt - > delayLargeBufferAvail ) ;
while ( opt - > writeBufferActualAvail ! = 1 ) /* wait so we can use this buffer */
Sleep ( 0 ) ;
opt - > writeBuffer = opt - > writeBufferActual ;
}
# else
rc = file4write ( file , opt - > writeStartPos , opt - > writeBuffer , ( unsigned ) ( opt - > writeCurPos - opt - > writeStartPos ) ) ;
# endif
file - > doBuffer = oldDoBuffer ;
file - > bufferWrites = oldBufferWrites ;
if ( rc ! = 0 )
return rc ;
opt - > writeStartPos = opt - > writeCurPos = opt - > writeBlockCount = 0 ;
}
return 0 ;
}
/* this function sets the 'selected' member of the lru-list to show which
links are considered available . */
static void opt4fileMarkAvailable ( OPT4 * opt , int useCount )
{
OPT4LIST * optList ;
OPT4BLOCK * block ;
LINK4 * link ;
LIST4 * list ;
int i ;
unsigned short int linksLeft ;
unsigned long elapsedTime ;
for ( i = 0 ; i < OPT4NUM_LISTS ; i + + )
{
optList = opt - > prio [ i ] ;
if ( useCount )
{
optList - > currentPrioCount - - ;
if ( optList - > currentPrioCount > 0 )
continue ;
optList - > currentPrioCount = i ; /* reset priority */
}
list = & optList - > list ;
for ( linksLeft = l4numNodes ( list ) , link = ( LINK4 * ) l4first ( list ) ; ; linksLeft - - , link = ( LINK4 * ) l4next ( list , link ) )
{
if ( link = = 0 )
break ;
block = ( OPT4BLOCK * ) ( link - 1 ) ;
elapsedTime = opt - > accessTimeCount - block - > accessTime ;
if ( elapsedTime < optList - > minTime ) /* all blocks this new must remain on list */
break ;
/* other wise determine based on minimum links */
elapsedTime = opt - > readTimeCount - block - > readTime ;
if ( elapsedTime > optList - > maxTime ) /* candidate for removal */
{
list - > selected = link ;
continue ;
}
/* else use maximum link information */
if ( linksLeft > optList - > minLink )
{
list - > selected = link ;
continue ;
}
/* else at or below the minimum allowed links, so stop */
break ;
}
if ( list - > selected = = 0 ) /* there were none available, so increase the time before a re-scan */
optList - > currentPrioCount + + ;
}
}
/* also sets the priority scheme */
static OPT4BLOCK * opt4fileChooseBlock ( FILE4 * file )
{
LINK4 * lruLink ;
LIST4 * chooseList ;
OPT4 * opt ;
int i , listAvg , l1 , l2 , l3 ;
OPT4BLOCK * block ;
# ifdef E4PARM_LOW
if ( file = = 0 )
{
error4 ( 0 , e4parm_null , E92508 ) ;
return 0 ;
}
# endif
opt = & file - > codeBase - > opt ;
if ( opt - > avail . nLink )
chooseList = & opt - > avail ;
else
{
for ( i = 0 ; i < OPT4NUM_LISTS ; i + + )
{
chooseList = & opt - > prio [ i ] - > list ;
if ( chooseList - > selected ! = 0 ) /* we have the desired link */
break ;
}
if ( i > = OPT4NUM_LISTS )
{
/* no candidate lists were found, so try finding something available */
opt4fileMarkAvailable ( opt , 1 ) ;
for ( i = 0 ; i < OPT4NUM_LISTS ; i + + )
{
chooseList = & opt - > prio [ i ] - > list ;
if ( chooseList - > selected ! = 0 ) /* we have the desired link */
break ;
}
if ( i > = OPT4NUM_LISTS )
{
/* no candidate lists were found, mark available for ALL lists */
opt4fileMarkAvailable ( opt , 0 ) ;
for ( i = 0 ; i < OPT4NUM_LISTS ; i + + )
{
chooseList = & opt - > prio [ i ] - > list ;
if ( chooseList - > selected ! = 0 ) /* we have the desired link */
break ;
}
if ( i > = OPT4NUM_LISTS )
{
/* no candidate lists were found, so try list normalization */
l1 = l4numNodes ( & opt - > prio [ 0 ] - > list ) ;
l2 = l4numNodes ( & opt - > prio [ 1 ] - > list ) ;
l3 = l4numNodes ( & opt - > prio [ 2 ] - > list ) ;
listAvg = ( l1 + l2 + l3 ) / 3 ;
chooseList = 0 ;
if ( listAvg > 0 )
{
if ( l1 > listAvg )
chooseList = & opt - > prio [ 0 ] - > list ;
else
{
if ( l2 > listAvg )
chooseList = & opt - > prio [ 1 ] - > list ;
else
chooseList = & opt - > prio [ 2 ] - > list ;
}
}
else
{
/* just try to get a link */
chooseList = & opt - > prio [ 3 ] - > list ;
if ( l4numNodes ( chooseList ) = = 0 )
{
chooseList = & opt - > prio [ 4 ] - > list ;
if ( l4numNodes ( chooseList ) = = 0 )
chooseList = & opt - > prio [ 5 ] - > list ;
}
}
}
}
}
}
lruLink = ( LINK4 * ) l4first ( chooseList ) ;
if ( lruLink = = 0 ) /* none were available, this is an error */
{
error4 ( 0 , e4struct , E92508 ) ;
return 0 ;
}
if ( lruLink = = chooseList - > selected ) /* lru link is selected, set selected to null */
chooseList - > selected = ( LINK4 * ) 0 ;
l4remove ( chooseList , lruLink ) ;
block = ( OPT4BLOCK * ) ( lruLink - 1 ) ;
return block ;
}
static void opt4blockUpgradePriorityCheck ( OPT4BLOCK * block , OPT4 * opt )
{
# ifndef S4OFF_INDEX
# ifdef N4OTHER
TAG4FILE * t4file ;
# else
INDEX4FILE * i4file ;
# endif
# endif
DATA4FILE * d4file ;
if ( block - > optList = = & opt - > dbfLo ) /* maybe move to hi */
{
d4file = ( ( DATA4FILE * ) block - > file - > ownerPtr ) ;
/* NOT moved to hi-priority if record size > 4k, to avoid memory congestion (except header pos 0 block) */
if ( d4file ! = 0 )
if ( block - > pos = = 0 | | ( d4file - > hiPrio = = 1 & & dfile4recWidth ( d4file ) > 4096 ) )
{
l4remove ( & block - > optList - > list , & block - > lruLink ) ;
opt4listLruBottomPlace ( & opt - > dbfHi , block ) ;
}
return ;
}
# ifndef S4OFF_INDEX
if ( block - > optList = = & opt - > indexLo ) /* maybe move to hi */
{
# ifdef N4OTHER
t4file = ( ( TAG4FILE * ) block - > file - > ownerPtr ) ;
if ( t4file ! = 0 )
{
if ( t4file - > readBlockTag = = 0 | | block - > len ! = opt - > blockSize ) /* not reading a block, so leave at low priority */
return ;
/* first ensure that it is on a real index boundary, and that we read the whole block */
if ( opt - > blockSize / 2 = = B4BLOCK_SIZE ) /* must check both blocks */
{
if ( b4dataLeaf ( block - > data , t4file - > readBlockTag ) = = 0 )
{
l4remove ( & block - > optList - > list , & block - > lruLink ) ;
opt4listLruBottomPlace ( & opt - > indexHi , block ) ;
return ;
}
if ( b4dataLeaf ( ( char * ) block - > data + B4BLOCK_SIZE , t4file - > readBlockTag ) = = 0 )
{
l4remove ( & block - > optList - > list , & block - > lruLink ) ;
opt4listLruBottomPlace ( & opt - > indexHi , block ) ;
}
}
if ( opt - > blockSize = = B4BLOCK_SIZE )
if ( b4dataLeaf ( block - > data , t4file - > readBlockTag ) = = 0 )
{
l4remove ( & block - > optList - > list , & block - > lruLink ) ;
opt4listLruBottomPlace ( & opt - > indexHi , block ) ;
}
}
# else
i4file = ( ( INDEX4FILE * ) block - > file - > ownerPtr ) ;
if ( i4file ! = 0 )
{
if ( i4file - > readBlockTag = = 0 | | block - > len ! = opt - > blockSize ) /* not reading a block, so leave at low priority */
return ;
/* first ensure that it is on a real index boundary, and that we read the whole block */
# ifdef S4MDX
if ( ( unsigned long ) i4file - > header . blockRw ! = opt - > blockSize )
return ;
/* if it is a branch block, then upgrade it's priority */
if ( b4dataLeaf ( block - > data , i4file - > readBlockTag ) = = 0 )
{
l4remove ( & block - > optList - > list , & block - > lruLink ) ;
opt4listLruBottomPlace ( & opt - > indexHi , block ) ;
}
# else
if ( opt - > blockSize / 2 = = B4BLOCK_SIZE ) /* must check both blocks */
{
if ( b4dataLeaf ( block - > data , i4file - > readBlockTag ) = = 0 )
{
l4remove ( & block - > optList - > list , & block - > lruLink ) ;
opt4listLruBottomPlace ( & opt - > indexHi , block ) ;
return ;
}
if ( b4dataLeaf ( ( char * ) block - > data + B4BLOCK_SIZE , i4file - > readBlockTag ) = = 0 )
{
l4remove ( & block - > optList - > list , & block - > lruLink ) ;
opt4listLruBottomPlace ( & opt - > indexHi , block ) ;
}
}
if ( opt - > blockSize = = B4BLOCK_SIZE )
if ( b4dataLeaf ( block - > data , i4file - > readBlockTag ) = = 0 )
{
l4remove ( & block - > optList - > list , & block - > lruLink ) ;
opt4listLruBottomPlace ( & opt - > indexHi , block ) ;
}
# endif
}
# endif
}
# endif /* S4OFF_INDEX */
}
static OPT4LIST * opt4listDetermine ( OPT4 * opt , FILE4 * file , int hiPrio )
{
switch ( file - > type )
{
case OPT4DBF :
if ( hiPrio = = 1 )
return & opt - > dbfHi ;
else
return & opt - > dbfLo ;
case OPT4INDEX :
if ( hiPrio = = 1 )
return & opt - > indexHi ;
else
return & opt - > indexLo ;
default :
return & opt - > other ;
}
}
/* gets an available block, and places it on the appropriate lru-list */
/* also sets the readTime and accessTime for the block */
static OPT4BLOCK * opt4fileGetBlock ( OPT4 * opt , FILE4 * file , int hiPrio )
{
OPT4BLOCK * block ;
OPT4LIST * optList ;
# ifdef E4PARM_LOW
if ( file = = 0 )
{
error4 ( 0 , e4parm_null , E92508 ) ;
return 0 ;
}
# endif
block = opt4fileChooseBlock ( file ) ;
opt4blockRemove ( opt , block , 1 ) ;
optList = opt4listDetermine ( opt , file , hiPrio ) ;
opt4listLruBottomPlace ( optList , block ) ;
block - > readTime = opt - > readTimeCount + + ;
if ( opt - > readTimeCount = = 0 ) /* time count got reset, so reset for everyone */
opt4timeReset ( opt , 1 , 0 ) ;
block - > accessTime = + + opt - > accessTimeCount ;
return block ;
}
static void opt4timeReset ( OPT4 * opt , int doReadTime , int doAccessTime )
{
OPT4BLOCK * blockOn ;
LIST4 * listOn ;
int i ;
/* for simplicity, just reset all blocks read-time to 0 (i.e. just read) */
/* in general this function will rarely be called, thus the impact should be minor */
for ( i = 0 ; i < OPT4NUM_LISTS ; i + + )
{
listOn = & opt - > prio [ i ] - > list ;
blockOn = ( OPT4BLOCK * ) l4first ( listOn ) ;
for ( ; ; )
{
if ( blockOn = = 0 )
break ;
if ( doReadTime )
blockOn - > readTime = 0 ;
if ( doAccessTime )
blockOn - > accessTime = 0 ;
blockOn = ( OPT4BLOCK * ) l4next ( listOn , blockOn ) ;
}
}
}
/* inlined now
long opt4fileHash ( OPT4 * opt , FILE4 * file , unsigned long pos )
{
return ( ( ( file - > hashInit + pos ) > > opt - > blockPower ) & opt - > mask ) ;
}
*/
int opt4fileWrite ( FILE4 * file , long pos , unsigned len , const void * data , char changed )
{
long hashVal , adjustedPos , lenWritten ;
unsigned readLen , lenRead , extraRead ;
OPT4BLOCK * blockOn ;
OPT4 * opt ;
2003-05-01 15:14:58 +00:00
int doUpgradeCheck = 0 ;
1997-06-16 13:01:08 +00:00
# ifdef E4PARM_LOW
if ( file = = 0 | | pos < 0 | | data = = 0 )
return error4 ( 0 , e4parm , E92508 ) ;
# endif
# ifdef S4ADVANCE_READ
/* ensure that the information to be written replaces any advanced-read
information in order to ensure that the advance - read data is up to
date */
if ( changed = = 1 )
file4advanceReadWriteOver ( file , pos , len , data , 1 ) ;
# endif
opt = & file - > codeBase - > opt ;
lenWritten = 0 ;
extraRead = ( unsigned ) ( ( unsigned long ) ( ( unsigned long ) pos < < opt - > numShift ) > > opt - > numShift ) ;
adjustedPos = pos - extraRead ;
if ( ( long ) len > ( long ) ( ( long ) opt - > numBlocks * ( long ) opt - > blockSize ) )
{
/* case where amount to write > total bufferred length - do a piece at a time */
adjustedPos = ( long ) ( ( ( long ) opt - > numBlocks - 1 ) * ( long ) opt - > blockSize ) ;
for ( lenWritten = 0L ; ( long ) len > lenWritten ; lenWritten + = adjustedPos )
{
if ( ( ( long ) len - lenWritten ) < adjustedPos )
adjustedPos = len - lenWritten ;
if ( opt4fileWrite ( file , pos + lenWritten , ( unsigned ) adjustedPos , ( char * ) data + lenWritten , changed ) ! = adjustedPos )
return ( int ) lenWritten ;
}
return ( int ) lenWritten ;
}
len + = extraRead ;
do
{
hashVal = opt4fileHash ( opt , file , ( unsigned long ) adjustedPos ) ;
readLen = ( unsigned ) ( ( len / ( unsigned ) opt - > blockSize ) ? opt - > blockSize : len ) ;
blockOn = opt4fileReturnBlock ( file , adjustedPos , hashVal ) ;
if ( blockOn = = 0 )
{
blockOn = opt4fileGetBlock ( opt , file , 0 ) ;
# ifdef E4ANALYZE
if ( blockOn = = 0 )
return error4 ( 0 , e4info , E92508 ) ;
# endif
if ( ( unsigned long ) ( readLen - extraRead ) < opt - > blockSize & & adjustedPos < file4len ( file ) )
lenRead = opt4fileReadFile ( file , adjustedPos , ( char * ) blockOn - > data ) ;
else
{
if ( file4len ( file ) > = ( long ) ( pos + lenWritten + opt - > blockSize ) ) /* mark block as full to avoid file len set below... */
lenRead = ( unsigned ) opt - > blockSize ;
else
lenRead = 0 ;
}
opt4blockAdd ( blockOn , file , lenRead , hashVal , adjustedPos ) ;
doUpgradeCheck = 1 ;
}
if ( readLen < ( unsigned ) extraRead )
readLen = ( unsigned ) extraRead ;
memcpy ( ( char * ) blockOn - > data + extraRead , ( char * ) data + lenWritten , ( unsigned ) ( readLen - extraRead ) ) ;
if ( doUpgradeCheck = = 1 )
opt4blockUpgradePriorityCheck ( blockOn , opt ) ;
opt4listLruBottomShift ( blockOn ) ;
blockOn - > changed | = changed ;
len - = readLen ;
lenWritten + = readLen - extraRead ;
extraRead = 0 ;
adjustedPos + = opt - > blockSize ;
if ( pos + lenWritten > blockOn - > pos + ( long ) blockOn - > len )
{
if ( file - > len < ( pos + lenWritten ) ) /* file size has grown */
{
if ( blockOn - > pos + ( long ) blockOn - > len < pos )
memset ( ( ( char * ) blockOn - > data ) + blockOn - > len , 0 , ( unsigned ) ( pos - ( blockOn - > pos + blockOn - > len ) ) ) ;
blockOn - > len = ( unsigned ) ( pos - blockOn - > pos + lenWritten ) ;
if ( file - > bufferWrites = = 1 )
{
file - > len = pos + lenWritten ;
# ifdef E4ANALYZE
/* make sure the file length really has grown */
if ( file - > fileCreated )
if ( u4filelength ( file - > hand ) > file - > len )
return error4 ( file - > codeBase , e4info , E92508 ) ;
# endif
}
}
else /* we have written past our end of block, but not our block, update our block len, dummy info */
blockOn - > len = ( unsigned ) opt - > blockSize ;
}
} while ( len & & blockOn - > len = = ( unsigned ) opt - > blockSize ) ;
return ( unsigned ) lenWritten ;
}
unsigned opt4fileRead ( FILE4 * f4 , long pos , void * data , unsigned len )
{
long hashVal , adjustedPos , lenRead ;
unsigned readLen , extraRead ;
int blocksNeeded ;
OPT4BLOCK * blockOn ;
OPT4 * opt ;
DATA4FILE * d4file ;
# ifdef E4PARM_LOW
if ( f4 = = 0 | | pos < 0 | | data = = 0 )
{
error4 ( 0 , e4parm , E92508 ) ;
return 0 ;
}
# endif
opt = & f4 - > codeBase - > opt ;
lenRead = 0 ;
extraRead = ( unsigned ) ( ( unsigned long ) ( ( unsigned long ) pos < < opt - > numShift ) > > opt - > numShift ) ;
adjustedPos = pos - extraRead ;
if ( ( unsigned long ) len > ( opt - > numBlocks * opt - > blockSize ) )
{
/* case where amount to read > total bufferred length - do a piece at a time */
adjustedPos = ( long ) ( ( ( long ) opt - > numBlocks - 1 ) * ( long ) opt - > blockSize ) ;
for ( lenRead = 0 ; ( long ) len > lenRead ; lenRead + = adjustedPos )
{
if ( ( ( long ) len - lenRead ) < adjustedPos )
adjustedPos = len - lenRead ;
if ( opt4fileRead ( f4 , pos + lenRead , ( char * ) data + lenRead , ( unsigned ) adjustedPos ) ! = ( unsigned ) adjustedPos )
return ( unsigned ) lenRead ;
}
# ifdef E4ANALYZE_ALL
if ( f4 - > hasDup = = 1 )
if ( file4cmpPart ( f4 - > codeBase , data , f4 , pos , ( unsigned ) lenRead ) ! = 0 )
{
error4 ( f4 - > codeBase , e4opt , E80602 ) ;
return 0 ;
}
# endif
return ( unsigned ) lenRead ;
}
len + = extraRead ;
do
{
hashVal = opt4fileHash ( opt , f4 , ( unsigned long ) adjustedPos ) ;
readLen = ( unsigned ) ( ( len / opt - > blockSize ) ? opt - > blockSize : len ) ;
blockOn = opt4fileReturnBlock ( f4 , adjustedPos , hashVal ) ;
if ( blockOn = = 0 ) /* read from disk */
{
/* first ensure that the file is not a temporary file that is empty */
if ( f4 - > fileCreated = = 0 ) /* not created, so if not in memory then empty */
return ( unsigned ) 0 ;
/* if force current is on, then pre-reading will be wasted, so just skip */
if ( opt - > forceCurrent ! = 1 )
{
if ( f4 - > type = = OPT4DBF )
{
d4file = ( DATA4FILE * ) f4 - > ownerPtr ;
if ( d4file ! = 0 )
if ( d4file - > hiPrio = = - 1 )
{
opt4fileReadSpBuffer ( f4 , ( unsigned long ) adjustedPos , - 1 , - 1 ) ;
blockOn = opt4fileReturnBlock ( f4 , adjustedPos , hashVal ) ;
}
}
if ( blockOn = = 0 )
{
/* depending on the amount to read, it may still make sense to
do advance reading - - quicker to read 2 blocks now than to
read 1 block twice */
if ( len - readLen > 0 ) /* need to read more than 1 block */
{
/* if the 2nd block is already in memory, don't bother */
blockOn = opt4fileReturnBlock ( f4 , adjustedPos + opt - > blockSize , opt4fileHash ( opt , f4 , ( unsigned long ) adjustedPos + opt - > blockSize ) ) ;
if ( blockOn = = 0 ) /* not there, so get */
{
/* check to see how many blocks we need */
blocksNeeded = 1 + len / readLen ; /* 1st block, plus any extras */
opt4fileReadSpBuffer ( f4 , ( unsigned long ) adjustedPos , blocksNeeded , 1 ) ;
blockOn = opt4fileReturnBlock ( f4 , adjustedPos , hashVal ) ;
}
else /* the 2nd block is there, so reset blockOn and read the first one */
blockOn = 0 ;
}
}
}
if ( blockOn = = 0 )
{
blockOn = opt4fileGetBlock ( opt , f4 , 0 ) ;
opt4blockAdd ( blockOn , f4 , opt4fileReadFile ( f4 , adjustedPos , ( char * ) blockOn - > data ) , hashVal , adjustedPos ) ;
opt4blockUpgradePriorityCheck ( blockOn , opt ) ;
}
}
else
if ( opt - > forceCurrent = = 1 )
{
if ( blockOn - > changed = = 0 & & f4 - > bufferWrites = = 0
# ifndef S4OFF_MULTI
& & f4 - > lowAccessMode = = OPEN4DENY_NONE
# endif
)
opt4fileReadFile ( f4 , adjustedPos , ( char * ) blockOn - > data ) ;
}
opt4listLruBottomShift ( blockOn ) ;
if ( blockOn - > len < readLen )
readLen = blockOn - > len ;
if ( readLen < ( unsigned ) extraRead )
readLen = ( unsigned ) extraRead ;
memcpy ( ( char * ) data + lenRead , ( char * ) blockOn - > data + extraRead , ( unsigned ) ( readLen - extraRead ) ) ;
len - = readLen ;
lenRead + = readLen - extraRead ;
extraRead = 0 ;
adjustedPos + = opt - > blockSize ;
} while ( len & & blockOn - > len = = ( unsigned ) opt - > blockSize ) ;
# ifdef E4ANALYZE_ALL
if ( f4 - > hasDup = = 1 )
if ( file4cmpPart ( f4 - > codeBase , data , f4 , pos , ( unsigned ) lenRead ) ! = 0 )
{
error4 ( f4 - > codeBase , e4opt , E80602 ) ;
return 0 ;
}
# endif
return ( unsigned ) lenRead ;
}
void opt4blockLruTop ( OPT4BLOCK * block )
{
LIST4 * list ;
LINK4 * l4link ;
# ifdef E4PARM_LOW
if ( block = = 0 )
{
error4 ( 0 , e4parm_null , E92508 ) ;
return ;
}
# endif
list = & block - > optList - > list ;
l4link = & block - > lruLink ;
if ( list - > selected = = l4link )
list - > selected = ( LINK4 * ) l4prev ( list , l4link ) ;
l4remove ( list , l4link ) ;
}
# ifdef S4ADVANCE_TEST
unsigned S4FUNCTION opt4fileReadFile ( FILE4 * file , const long posIn , char * buf )
# else
static unsigned opt4fileReadFile ( FILE4 * file , const long posIn , char * buf )
# endif
{
unsigned int len ;
OPT4 * opt ;
long pos ;
# ifdef S4ADVANCE_READ
unsigned int compareLen , copyOffset ;
# endif
# ifdef E4PARM_LOW
if ( file = = 0 | | posIn < 0 | | buf = = 0 )
{
error4 ( 0 , e4parm , E92508 ) ;
return 0 ;
}
# endif
pos = posIn ;
opt = & file - > codeBase - > opt ;
# ifdef S4ADVANCE_READ
/* first check the advance-read buffer. If the data is available there,
then copy it out . Can ' t do more than that here because this function
is reading into a block already ( don ' t want to overwrite that one by
mistake */
/* only copy if can get the entire block from advance-read (in theory
must always be able to get none or all since on block boundaries */
if ( opt - > advanceLargeBufferAvail ! = AR4EMPTY )
if ( file = = opt - > advanceReadFile )
{
len = ( unsigned ) ( opt - > blockSize ) ;
/* if an overlap of any type occurs, then copy that part out first,
and then take care of the remaining pieces */
if ( pos > = opt - > advanceLargePos & & pos < opt - > advanceLargePos + ( long ) opt - > advanceLargeLen )
{
if ( pos = = opt - > advanceLargePos ) /* easy case */
{
if ( opt - > advanceLargeLen > = len )
{
while ( opt - > advanceLargeBufferAvail = = AR4SET ) /* wait for the buffer to complete read, if reqd. */
Sleep ( 0 ) ;
if ( opt - > advanceLargeBufferAvail = = AR4FULL ) /* successful read */
{
memcpy ( buf , opt - > advanceLargeBuffer , len ) ;
/* reset the position of the data for easier handling later */
opt - > advanceLargePos + = len ;
opt - > advanceLargeLen - = len ;
memcpy ( opt - > advanceLargeBuffer , opt - > advanceLargeBuffer + len , opt - > advanceLargeLen ) ;
if ( opt - > advanceLargeLen = = 0 ) /* just remove */
{
opt - > advanceLargeBufferAvail = AR4EMPTY ;
opt - > advanceReadFile = 0 ;
}
return len ;
}
}
}
else
if ( pos > opt - > advanceLargePos ) /* full copy only */
{
copyOffset = pos - opt - > advanceLargePos ;
compareLen = opt - > advanceLargeLen - copyOffset ;
if ( compareLen > = len ) /* then ok */
{
while ( opt - > advanceLargeBufferAvail = = AR4SET ) /* wait for the buffer to complete read, if reqd. */
Sleep ( 0 ) ;
if ( opt - > advanceLargeBufferAvail = = AR4FULL ) /* successful read */
{
if ( compareLen = = len )
opt - > advanceLargeLen - = compareLen ; /* remove trailer, since will get copied into buffers anyway */
memcpy ( buf , opt - > advanceLargeBuffer + copyOffset , len ) ;
return len ;
}
}
}
}
}
# endif
if ( opt - > writeFile = = file )
if ( ( unsigned long ) pos + opt - > blockSize > = opt - > writeStartPos & & ( unsigned long ) pos < opt - > writeCurPos )
opt4flushWriteBuffer ( opt ) ;
len = file4readLow ( file , pos , buf , ( unsigned ) ( opt - > blockSize ) ) ;
return len ;
}
/* this function performs larger reads into the given buffer with the
desired length to read . This is used for advance reads and when
larger amounts of information are required
returned is the length read */
static unsigned long opt4fileReadToBuffer ( FILE4 * file , char * buf , unsigned long pos , unsigned int readLen )
{
unsigned long len , saveBlockSize ;
OPT4 * opt ;
opt = & file - > codeBase - > opt ;
saveBlockSize = opt - > blockSize ;
opt - > blockSize = readLen ;
len = opt4fileReadFile ( file , pos , buf ) ;
opt - > blockSize = saveBlockSize ;
return len ;
}
# ifdef S4ADVANCE_READ
void S4CALL opt4readCompletionRoutine ( void * advance )
{
FILE4ADVANCE_READ * advanceRead ;
int * arFlag ;
/* to verify safety, use critical section on the arFlag (from CODE4) */
advanceRead = ( FILE4ADVANCE_READ * ) advance ;
arFlag = ( int * ) ( advanceRead - > completionData ) ;
if ( advanceRead - > usageFlag = = r4canceled )
* arFlag = AR4EMPTY ;
else
if ( * arFlag = = AR4SET ) /* if reset to empty it means the read was cancelled by the main thread, so leave as empty */
{
/* verify that all was read */
if ( advanceRead - > file - > codeBase - > opt . advanceLargeLen = = advanceRead - > status )
* arFlag = AR4FULL ;
else
* arFlag = AR4EMPTY ;
}
}
static void opt4fileReadAdvanceBuffer ( OPT4 * opt , FILE4 * f4 , void * buffer , long pos , unsigned int len )
{
long hashVal ;
hashVal = opt4fileHash ( opt , f4 , ( unsigned long ) pos ) ;
if ( opt4fileReturnBlock ( f4 , pos , hashVal ) ! = 0 ) /* in memory, so don't perform the advance-read */
return ;
opt - > advanceLargeBufferAvail = AR4SET ;
opt - > advanceReadFile = f4 ;
file4advanceRead ( f4 , pos , buffer , len , opt4readCompletionRoutine , & opt - > advanceLargeBufferAvail ) ;
}
# endif
/* this function does advance reads by reading in a whole buffer at
a time , instead of just one block worth
will advance - read numBlocks blocks . If numBlocks = = - 1 , then will advance
read the whole read buffer , if direction = = - 1 , then it self - detects it
if either direction or numBlocks is - 1 , both must be - 1 */
static void opt4fileReadSpBuffer ( FILE4 * file , const unsigned long posIn , int numBlocks , int direction )
{
unsigned long len , curPos , saveBlockSize , endPos , pos ;
unsigned short copyPos ;
OPT4BLOCK * blockOn ;
OPT4 * opt ;
long hashVal ;
int readBlocks ;
unsigned int curBlocks ;
# ifdef S4ADVANCE_READ
int posInAdvance ; /* position to read was within the advance-read area */
int blocksWithin ; /* the number of blocks within the advance read once position-adjusted (i.e. the length relevanet to quantity reqd. - if numBlocks not -1 */
int advanceNextRead ;
long advPos ;
# endif
# ifdef E4PARM_LOW
if ( file = = 0 )
{
error4 ( 0 , e4parm_null , E92508 ) ;
return ;
}
if ( ( direction = = - 1 & & numBlocks ! = - 1 ) | | ( direction ! = - 1 & & numBlocks = = - 1 ) )
{
error4 ( file - > codeBase , e4parm , E92508 ) ;
return ;
}
# endif
pos = posIn ;
opt = & file - > codeBase - > opt ;
saveBlockSize = opt - > blockSize ;
# ifdef S4ADVANCE_READ
advanceNextRead = 0 ;
/* first check the advance read-buffer, and see if it matches the
information we want . Even if it doesn ' t , if numBlocks is - 1 , then
it gets copied out ( to perform more advance - reading */
if ( opt - > advanceLargeBufferAvail = = AR4SET ) /* wait on read if file matches */
if ( file = = opt - > advanceReadFile )
while ( opt - > advanceLargeBufferAvail = = AR4SET )
Sleep ( 0 ) ;
if ( opt - > advanceLargeBufferAvail = = AR4FULL )
{
if ( opt - > advanceLargeLen = = 0 )
{
opt - > advanceLargeBufferAvail = AR4EMPTY ;
opt - > advanceReadFile = 0 ;
}
else
{
blocksWithin = 0 ;
posInAdvance = 0 ;
if ( file = = opt - > advanceReadFile )
{
if ( pos > = ( unsigned long ) opt - > advanceLargePos & & pos < = opt - > advanceLargePos + opt - > advanceLargeLen - saveBlockSize )
{
posInAdvance = 1 ;
if ( numBlocks ! = - 1 )
blocksWithin = ( opt - > advanceLargeLen + opt - > advanceLargePos - pos ) / saveBlockSize ;
}
else
posInAdvance = 0 ;
}
if ( file = = opt - > advanceReadFile | | numBlocks = = - 1 ) /* extract the blocks from the advance-read buffer */
{
advPos = curPos = opt - > advanceLargePos ;
hashVal = opt4fileHash ( opt , file , curPos ) ;
opt - > advanceLargeBufferAvail = AR4EMPTY ;
opt - > advanceReadFile = 0 ;
for ( ; ; )
{
blockOn = opt4fileReturnBlock ( file , curPos , hashVal ) ;
if ( blockOn = = 0 )
{
blockOn = opt4fileGetBlock ( opt , file , 0 ) ;
memcpy ( blockOn - > data , opt - > advanceLargeBuffer + ( curPos - advPos ) , ( unsigned ) ( saveBlockSize ) ) ;
opt4blockAdd ( blockOn , file , ( unsigned ) ( saveBlockSize ) , hashVal , curPos ) ;
opt4blockUpgradePriorityCheck ( blockOn , opt ) ;
}
else /* update the lru status */
opt4listLruBottomShift ( blockOn ) ;
curPos + = saveBlockSize ;
# ifdef E4DEBUG
if ( curPos > opt - > advanceLargePos + opt - > advanceLargeLen )
{
error4 ( file - > codeBase , e4struct , E92508 ) ;
return ;
}
# endif
if ( curPos = = opt - > advanceLargePos + opt - > advanceLargeLen )
break ;
hashVal + + ;
if ( ( unsigned long ) hashVal > = opt - > numLists )
hashVal = opt4fileHash ( opt , file , curPos ) ;
}
if ( file = = opt - > advanceReadFile )
{
if ( numBlocks = = - 1 )
{
if ( posInAdvance = = 1 )
return ;
}
else
if ( blocksWithin > = numBlocks )
return ;
}
}
}
}
# endif
if ( direction = = - 1 )
{
/* first do a sample to see which way to read */
blockOn = opt4fileReturnBlock ( file , pos + saveBlockSize , opt4fileHash ( opt , file , pos + saveBlockSize ) ) ;
if ( blockOn ! = 0 ) /* read previous blocks, not next blocks */
{
if ( pos > ( opt - > bufferSize - saveBlockSize ) )
pos - = ( opt - > bufferSize - saveBlockSize ) ;
else
pos = 0 ;
}
}
readBlocks = 0 ;
curBlocks = opt - > maxBlocks ;
for ( ; ; ) /* may need to read more than the read-buffer worth if a large read */
{
if ( numBlocks ! = - 1 )
{
if ( curBlocks > ( unsigned int ) ( numBlocks - readBlocks ) ) /* don't over-read */
{
curBlocks = numBlocks - readBlocks ;
numBlocks = - 1 ; /* will be done */
}
}
len = opt4fileReadToBuffer ( file , opt - > readBuffer , pos , ( unsigned int ) ( curBlocks * saveBlockSize ) ) ;
if ( len = = 0 )
return ;
opt - > readStartPos = pos ;
opt - > readFile = file ;
/* first do the last block, in case there is a length issue */
curPos = pos + saveBlockSize * ( ( len - 1 ) > > opt - > blockPower ) ;
hashVal = opt4fileHash ( opt , file , curPos ) ;
blockOn = opt4fileReturnBlock ( file , curPos , hashVal ) ;
if ( blockOn = = 0 )
{
blockOn = opt4fileGetBlock ( opt , file , 0 ) ;
endPos = curPos - pos ;
copyPos = ( unsigned short ) ( len - endPos ) ;
memcpy ( blockOn - > data , opt - > readBuffer + endPos , copyPos ) ;
opt4blockAdd ( blockOn , file , copyPos , hashVal , curPos ) ;
opt4blockUpgradePriorityCheck ( blockOn , opt ) ;
}
if ( curPos ! = pos )
{
curPos - = saveBlockSize ;
/* can just subtract one from hash value since it goes in order */
for ( ; ; curPos - = saveBlockSize )
{
hashVal - - ;
if ( hashVal < 0 )
hashVal = opt4fileHash ( opt , file , curPos ) ;
blockOn = opt4fileReturnBlock ( file , curPos , hashVal ) ;
if ( blockOn = = 0 )
{
blockOn = opt4fileGetBlock ( opt , file , 0 ) ;
memcpy ( blockOn - > data , opt - > readBuffer + ( curPos - pos ) , ( unsigned ) ( saveBlockSize ) ) ;
opt4blockAdd ( blockOn , file , ( unsigned ) ( saveBlockSize ) , hashVal , curPos ) ;
opt4blockUpgradePriorityCheck ( blockOn , opt ) ;
}
else /* update the lru status */
opt4listLruBottomShift ( blockOn ) ;
if ( curPos = = pos )
{
# ifdef S4ADVANCE_READ
advanceNextRead = 1 ;
# endif
break ;
}
}
}
opt - > readFile = 0 ;
if ( numBlocks = = - 1 )
break ;
if ( len < opt - > bufferSize )
break ;
readBlocks + = curBlocks ;
pos + = opt - > bufferSize ;
}
# ifdef S4ADVANCE_READ
if ( opt - > advanceLargeBufferAvail = = AR4EMPTY & & advanceNextRead = = 1 & & numBlocks = = - 1 ) /* request an advance read for the next section */
{
if ( direction = = 1 )
advPos = ( ( unsigned long ) ( posIn > > opt - > blockPower ) > > opt - > blockPower ) + opt - > bufferSize ;
else
advPos = ( ( unsigned long ) ( posIn < < opt - > blockPower ) > > opt - > blockPower ) - 2 * opt - > bufferSize ;
if ( advPos > 0 )
{
opt - > advanceLargePos = advPos ;
opt - > advanceLargeLen = opt - > bufferSize ;
opt4fileReadAdvanceBuffer ( opt , file , opt - > advanceLargeBuffer , advPos , opt - > bufferSize ) ;
}
}
# endif
return ;
}
OPT4BLOCK * opt4fileReturnBlock ( FILE4 * file , long pos , long hashVal )
{
OPT4CMP compare ;
OPT4BLOCK * blockOn ;
LIST4 * list ;
# ifdef E4PARM_LOW
if ( file - > codeBase - > opt . numBuffers = = 0 | | file = = 0 | | hashVal < 0 | | pos < 0 )
{
error4 ( 0 , e4parm , E92508 ) ;
return 0 ;
}
if ( ( unsigned long ) hashVal > = file - > codeBase - > opt . numLists )
{
error4 ( 0 , e4parm , E92508 ) ;
return 0 ;
}
# endif
if ( file - > doBuffer = = 0 )
return 0 ;
list = & file - > codeBase - > opt . lists [ hashVal ] ;
blockOn = ( OPT4BLOCK * ) l4first ( list ) ;
if ( blockOn ! = 0 )
{
compare . file = file ;
memcpy ( ( void * ) & compare . pos , ( void * ) & pos , sizeof ( compare . pos ) ) ;
for ( ; ; )
{
if ( ! c4memcmp ( ( void * ) & blockOn - > file , ( void * ) & compare , sizeof ( compare ) ) )
return blockOn ;
blockOn = ( OPT4BLOCK * ) l4next ( list , blockOn ) ;
if ( blockOn = = 0 )
return 0 ;
}
}
return 0 ;
}
# endif /* not S4OPTIMIZE_OFF */