alex 3d6c8b3e2d Patch level : 2.0 464
Files correlati     : cb6.dll
Ricompilazione Demo : [ ]
Commento            :
Modifiche per la compilazione Linux


git-svn-id: svn://10.65.10.50/trunk@11080 c028cbd2-c16b-5b4b-a496-9718f37d4682
2003-05-01 15:14:58 +00:00

1527 lines
51 KiB
C
Executable File

/* 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 ;
int i ;
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 ;
int doUpgradeCheck = 0;
#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 */