778 lines
20 KiB
C
778 lines
20 KiB
C
|
#ifndef _STAPI_H
|
||
|
#define _STAPI_H
|
||
|
|
||
|
|
||
|
// Redirect Asserts in inline code to seem to fire from this file
|
||
|
|
||
|
#define szAssertFilename __FILE__
|
||
|
|
||
|
|
||
|
//---- externs -------------------------------------------------------------
|
||
|
|
||
|
extern CRIT critBuf;
|
||
|
extern TRX trxOldest;
|
||
|
extern TRX trxNewest;
|
||
|
extern CRIT critCommit0;
|
||
|
|
||
|
extern SIG sigBFCleanProc;
|
||
|
|
||
|
//---- IO (io.c) ----------------------------------------------------------
|
||
|
|
||
|
ERR ErrIOInit( VOID );
|
||
|
ERR ErrIOTerm( BOOL fNormal );
|
||
|
|
||
|
/* Reserve first 2 pages of a database.
|
||
|
*/
|
||
|
#define cpageDBReserved 2
|
||
|
STATIC INLINE LONG LOffsetOfPgnoLow( PGNO pgno ) { return ( pgno -1 + cpageDBReserved ) << 12; }
|
||
|
STATIC INLINE LONG LOffsetOfPgnoHigh( PGNO pgno ) { return ( pgno -1 + cpageDBReserved ) >> 20; }
|
||
|
|
||
|
VOID IOCloseFile( HANDLE hf );
|
||
|
ERR ErrIONewSize( DBID dbid, CPG cpg );
|
||
|
|
||
|
BOOL FIOFileExists( CHAR *szFileName );
|
||
|
ERR ErrIOLockDbidByNameSz( CHAR *szFileName, DBID *pdbid );
|
||
|
ERR ErrIOLockDbidByDbid( DBID dbid );
|
||
|
ERR ErrIOLockNewDbid( DBID *pdbid, CHAR *szDatabaseName );
|
||
|
ERR ErrIOSetDbid( DBID dbid, CHAR *szDatabaseName );
|
||
|
VOID IOFreeDbid( DBID dbid );
|
||
|
void BFOldestLgpos( LGPOS *plgposCheckPoint );
|
||
|
VOID BFPurge( DBID dbid );
|
||
|
|
||
|
STATIC INLINE BOOL FIODatabaseOpen ( DBID dbid )
|
||
|
{
|
||
|
AssertCriticalSection( critJet );
|
||
|
return rgfmp[dbid].hf != handleNil;
|
||
|
}
|
||
|
|
||
|
ERR ErrIOOpenDatabase( DBID dbid, CHAR *szDatabaseName, CPG cpg );
|
||
|
VOID IOCloseDatabase( DBID dbid );
|
||
|
ERR ErrIODeleteDatabase( DBID dbid );
|
||
|
BOOL FIODatabaseInUse( DBID dbid );
|
||
|
BOOL FIODatabaseAvailable( DBID dbid );
|
||
|
|
||
|
STATIC INLINE VOID IOUnlockDbid( DBID dbid )
|
||
|
{
|
||
|
SgEnterCriticalSection( critBuf );
|
||
|
Assert( FDBIDWait( dbid ) );
|
||
|
DBIDResetWait( dbid );
|
||
|
SgLeaveCriticalSection( critBuf );
|
||
|
}
|
||
|
|
||
|
STATIC INLINE BOOL FIOExclusiveByAnotherSession( DBID dbid, PIB *ppib )
|
||
|
{
|
||
|
Assert( FDBIDWait( dbid ) );
|
||
|
return FDBIDExclusiveByAnotherSession( dbid, ppib );
|
||
|
}
|
||
|
|
||
|
STATIC INLINE VOID IOSetExclusive( DBID dbid, PIB *ppib )
|
||
|
{
|
||
|
Assert( FDBIDWait( dbid ) );
|
||
|
Assert( !( FDBIDExclusive( dbid ) ) );
|
||
|
DBIDSetExclusive( dbid, ppib );
|
||
|
}
|
||
|
|
||
|
STATIC INLINE VOID IOResetExclusive( DBID dbid )
|
||
|
{
|
||
|
Assert( FDBIDWait( dbid ) );
|
||
|
DBIDResetExclusive( dbid );
|
||
|
}
|
||
|
|
||
|
STATIC INLINE BOOL FIOReadOnly( DBID dbid )
|
||
|
{
|
||
|
Assert( FDBIDWait( dbid ) );
|
||
|
return FDBIDReadOnly( dbid );
|
||
|
}
|
||
|
|
||
|
STATIC INLINE VOID IOSetReadOnly( DBID dbid )
|
||
|
{
|
||
|
Assert( FDBIDWait( dbid ) );
|
||
|
DBIDSetReadOnly( dbid );
|
||
|
}
|
||
|
|
||
|
STATIC INLINE VOID IOResetReadOnly( DBID dbid )
|
||
|
{
|
||
|
Assert( FDBIDWait( dbid ) );
|
||
|
DBIDResetReadOnly( dbid );
|
||
|
}
|
||
|
|
||
|
STATIC INLINE BOOL FIOAttached( DBID dbid )
|
||
|
{
|
||
|
Assert( FDBIDWait( dbid ) );
|
||
|
return FDBIDAttached( dbid );
|
||
|
}
|
||
|
|
||
|
STATIC INLINE VOID IOSetAttached( DBID dbid )
|
||
|
{
|
||
|
Assert( FDBIDWait( dbid ) );
|
||
|
Assert( !( FDBIDAttached( dbid ) ) );
|
||
|
DBIDSetAttached( dbid );
|
||
|
}
|
||
|
|
||
|
STATIC INLINE VOID IOResetAttached( DBID dbid )
|
||
|
{
|
||
|
Assert( FDBIDWait( dbid ) );
|
||
|
Assert( FDBIDAttached( dbid ) );
|
||
|
DBIDResetAttached( dbid );
|
||
|
}
|
||
|
|
||
|
|
||
|
//---- BUF (buf.c) ----------------------------------------------------------
|
||
|
|
||
|
typedef struct _lru // LRU List
|
||
|
{
|
||
|
LONG cbfAvail; // clean available buffers in LRU list
|
||
|
struct _bf *pbfLRU; // Least Recently Used buffer
|
||
|
struct _bf *pbfMRU; // Most Recently Used buffer
|
||
|
} LRULIST;
|
||
|
|
||
|
typedef struct _bgcb // Buffer Group Control Block
|
||
|
{
|
||
|
struct _bgcb *pbgcbNext; // pointer to the next BCGB
|
||
|
struct _bf *rgbf; // buffer control blocks for group
|
||
|
struct _page *rgpage; // buffer control blocks for group
|
||
|
LONG cbfGroup; // number of bfs in this group
|
||
|
LONG cbfThresholdLow; // threshold to start cleaning buffers
|
||
|
LONG cbfThresholdHigh; // threshold to stop cleaning buffers
|
||
|
|
||
|
LRULIST lrulist;
|
||
|
} BGCB;
|
||
|
|
||
|
#define pbgcbNil ((BGCB*)0)
|
||
|
|
||
|
#define PbgcbMEMAlloc() (BGCB*)PbMEMAlloc(iresBGCB)
|
||
|
|
||
|
#ifdef DEBUG /* Debug check for illegal use of freed bgcb */
|
||
|
#define MEMReleasePbgcb(pbgcb) { MEMRelease(iresBGCB, (BYTE*)(pbgcb)); pbgcb = pbgcbNil; }
|
||
|
#else
|
||
|
#define MEMReleasePbgcb(pbgcb) { MEMRelease(iresBGCB, (BYTE*)(pbgcb)); }
|
||
|
#endif
|
||
|
|
||
|
#define BUT INT
|
||
|
#define butBuffer 0
|
||
|
#define butHistory 1
|
||
|
|
||
|
#define ibfNotUsed -1
|
||
|
|
||
|
typedef struct _he
|
||
|
{
|
||
|
BUT but:2; // must use 2 bits to avoid sign extension when converting to int
|
||
|
INT ibfHashNext:30; // hash table overflow
|
||
|
} HE;
|
||
|
|
||
|
typedef struct _hist
|
||
|
{
|
||
|
ULONG ulBFTime;
|
||
|
PN pn;
|
||
|
INT ipbfHISTHeap;
|
||
|
} HIST;
|
||
|
|
||
|
typedef struct _bf
|
||
|
{
|
||
|
struct _page *ppage; // pointer to page buffer
|
||
|
|
||
|
#if defined( _X86_ ) && defined( X86_USE_SEM )
|
||
|
LONG volatile lLock; // num of locks being asked
|
||
|
LONG cSemWait; // num of user waiting for on semaphore
|
||
|
SEM sem;
|
||
|
#endif // defined( _X86_ ) && defined( X86_USE_SEM )
|
||
|
|
||
|
PN pn; // physical pn of cached page
|
||
|
ULONG fDirty:1; // indicates page needs to be flushed
|
||
|
// the following flags are mutual exclusive:
|
||
|
ULONG fDirectRead:1; // buffer is being direct read
|
||
|
ULONG fAsyncRead:1; // buffer is being async read
|
||
|
ULONG fSyncRead:1; // buffer is being sync read
|
||
|
ULONG fAsyncWrite:1; // buffer is being async written
|
||
|
ULONG fSyncWrite:1; // buffer is being sync written
|
||
|
ULONG fHold:1; // buffer is in transient state
|
||
|
ULONG fIOError:1; // indicates read/write error
|
||
|
#ifdef DEBUG
|
||
|
ULONG fInHash:1; // BF is currently in hash table
|
||
|
#endif // DEBUG
|
||
|
ULONG fInLRUK:1; // BF is in LRUK heap or LRUK list
|
||
|
ULONG fVeryOld:1; // BF is very old relative to last check point
|
||
|
ULONG fPatch:1; // BF is being written to the patch file
|
||
|
ULONG fNeedPatch:1; // BF need to write patch file after regular write.
|
||
|
LONG ipbfHeap; // index in heap
|
||
|
LONG cWriteLatch; // if cWriteLatch > 0, page cannot be updated by other
|
||
|
LONG cWaitLatch;
|
||
|
LONG cPin; // if cPin > 0 then buf cannot be overlayed
|
||
|
|
||
|
#ifdef READ_LATCH
|
||
|
LONG cReadLatch; // if cReadLatch > 0, page cannot be updated
|
||
|
#endif // READ_LATCH
|
||
|
PIB *ppibWriteLatch; // thread with write latch
|
||
|
PIB *ppibWaitLatch; // thread with wait latch
|
||
|
|
||
|
struct _bf *pbfLRU; // pointer to less recently used buffer
|
||
|
struct _bf *pbfMRU; // pointer to more recently used buffer
|
||
|
|
||
|
TRX trxLastRef; // last transaction that referenced us
|
||
|
ULONG ulBFTime1; // last reference time
|
||
|
ULONG ulBFTime2; // previous to last reference time
|
||
|
|
||
|
struct _bf *pbfNextBatchIO; // next BF in BatchIO list
|
||
|
LONG ipageBatchIO;
|
||
|
|
||
|
ERR err; // error code for err occurs during the IO
|
||
|
SIG sigIOComplete; // set (if valid) when IO on BF is completed
|
||
|
SIG sigSyncIOComplete; // set (if valid) when sync IO on BF is completed
|
||
|
|
||
|
union
|
||
|
{
|
||
|
ULONG cpageDirectRead; // count of prior BFs to be flushed
|
||
|
ULONG cDepend; // count of prior BFs to be flushed
|
||
|
};
|
||
|
union
|
||
|
{
|
||
|
PAGE *ppageDirectRead;
|
||
|
struct _bf *pbfDepend; // BF to be flushed after this one
|
||
|
};
|
||
|
LGPOS lgposRC; // log ptr to BeginT of oldest modifying xact
|
||
|
LGPOS lgposModify; // log ptr of entry for last page modify
|
||
|
|
||
|
struct _rce *prceDeferredBINext; // dbl link list for deferred before image.
|
||
|
|
||
|
#ifdef COSTLY_PERF
|
||
|
LONG lClass; // Table Class of which this BF is a member
|
||
|
#endif // COSTLY_PERF
|
||
|
|
||
|
HE rghe[2]; // 0 for buffer, 1 for history.
|
||
|
HIST hist; // borrow the space in bf structure to keep HIST.
|
||
|
|
||
|
#ifdef PCACHE_OPTIMIZATION
|
||
|
//#if !defined( _X86_ ) || !defined( X86_USE_SEM )
|
||
|
// BYTE rgbFiller[32];
|
||
|
//#endif
|
||
|
#ifndef COSTLY_PERF
|
||
|
BYTE rgbFiller2[4]; // pad BF to 32 byte boundary
|
||
|
#endif // !COSTLY_PERF
|
||
|
#endif // PCACHE_OPTIMIZATION
|
||
|
} BF;
|
||
|
#define pbfNil ((BF *) 0)
|
||
|
|
||
|
ERR ErrBFInit( VOID );
|
||
|
VOID BFTerm( BOOL fNormal );
|
||
|
|
||
|
#if defined( _X86_ ) && defined( X86_USE_SEM )
|
||
|
|
||
|
VOID BFIEnterCriticalSection( BF *pbf );
|
||
|
VOID BFILeaveCriticalSection( BF *pbf );
|
||
|
|
||
|
STATIC INLINE VOID BFEnterCriticalSection( BF *pbf )
|
||
|
{
|
||
|
LONG volatile *plLock = &pbf->lLock;
|
||
|
|
||
|
// use bit test and set instruction
|
||
|
_asm
|
||
|
{
|
||
|
mov eax, plLock
|
||
|
lock inc [eax]
|
||
|
// If already set go to busy, otherwise return TRUE
|
||
|
jnz busy
|
||
|
} ;
|
||
|
return;
|
||
|
busy:
|
||
|
BFIEnterCriticalSection( pbf );
|
||
|
}
|
||
|
|
||
|
|
||
|
STATIC INLINE VOID BFLeaveCriticalSection( BF *pbf )
|
||
|
{
|
||
|
LONG volatile *plLock = &pbf->lLock;
|
||
|
|
||
|
_asm
|
||
|
{
|
||
|
mov eax, plLock
|
||
|
lock dec [eax]
|
||
|
jge wake
|
||
|
}
|
||
|
return;
|
||
|
wake:
|
||
|
BFILeaveCriticalSection( pbf );
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
|
||
|
extern int ccritBF;
|
||
|
extern int critBFHashConst;
|
||
|
extern CRIT *rgcritBF;
|
||
|
#define IcritHash( ibf ) ((ibf) & critBFHashConst )
|
||
|
#define BFEnterCriticalSection( pbf ) UtilEnterCriticalSection( rgcritBF[ IcritHash((ULONG)((ULONG_PTR)pbf) / sizeof(BF) ) ])
|
||
|
#define BFLeaveCriticalSection( pbf ) UtilLeaveCriticalSection( rgcritBF[ IcritHash((ULONG)((ULONG_PTR)pbf) / sizeof(BF) ) ])
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
ERR ErrBFAccessPage( PIB *ppib, BF **ppbf, PN pn );
|
||
|
ERR ErrBFReadAccessPage( FUCB *pfucb, PGNO pgno );
|
||
|
ERR ErrBFWriteAccessPage( FUCB *pfucb, PGNO pgno );
|
||
|
VOID BFAbandon( PIB *ppib, BF *pbf );
|
||
|
VOID BFTossImmediate( PIB *ppib, BF *pbf );
|
||
|
ERR ErrBFAllocPageBuffer( PIB *ppib, BF **ppbf, PN pn, LGPOS lgposRC, BYTE pgtyp );
|
||
|
ERR ErrBFAllocTempBuffer( BF **ppbf );
|
||
|
VOID BFFree( BF *pbf );
|
||
|
VOID BFPreread( PN pn, CPG cpg, CPG *pcpgActual );
|
||
|
VOID BFPrereadList( PN * rgpnPages, CPG *pcpgActual );
|
||
|
ERR ErrBFDirectRead( DBID dbid, PGNO pgnoStart, PAGE *ppage, INT cpage );
|
||
|
VOID BFDeferRemoveDependence( BF *pbf );
|
||
|
#define fBFWait fFalse
|
||
|
#define fBFNoWait fTrue
|
||
|
ERR ErrBFRemoveDependence( PIB *ppib, BF *pbf, BOOL fNoWait );
|
||
|
BOOL FBFCheckDependencyChain( BF *pbf );
|
||
|
|
||
|
/* buffer flush prototype and flags
|
||
|
/**/
|
||
|
#define fBFFlushSome 0
|
||
|
#define fBFFlushAll 1
|
||
|
ERR ErrBFFlushBuffers( DBID dbid, LONG fBFFlush );
|
||
|
|
||
|
STATIC INLINE VOID BFSFree( BF *pbf )
|
||
|
{
|
||
|
SgEnterCriticalSection( critBuf );
|
||
|
BFFree( pbf );
|
||
|
SgLeaveCriticalSection( critBuf );
|
||
|
}
|
||
|
|
||
|
/* the following small functions are called too often, */
|
||
|
/* make it as a macros
|
||
|
/**/
|
||
|
DBID DbidOfPn( PN pn );
|
||
|
PGNO PgnoOfPn( PN pn );
|
||
|
|
||
|
#ifdef COSTLY_PERF
|
||
|
extern unsigned long cBFClean[];
|
||
|
extern unsigned long cBFNewDirties[];
|
||
|
#else // !COSTLY_PERF
|
||
|
extern unsigned long cBFClean;
|
||
|
extern unsigned long cBFNewDirties;
|
||
|
#endif // COSTLY_PERF
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
VOID BFSetDirtyBit( BF *pbf );
|
||
|
#else
|
||
|
STATIC INLINE VOID BFSetDirtyBit( BF *pbf )
|
||
|
{
|
||
|
QWORD qwDBTime = QwPMDBTime( pbf->ppage );
|
||
|
BFEnterCriticalSection( pbf );
|
||
|
if ( !fRecovering && qwDBTime > QwDBHDRDBTime( rgfmp[ DbidOfPn(pbf->pn) ].pdbfilehdr ) )
|
||
|
DBHDRSetDBTime( rgfmp[ DbidOfPn(pbf->pn) ].pdbfilehdr, qwDBTime );
|
||
|
if ( !pbf->fDirty )
|
||
|
{
|
||
|
#ifdef COSTLY_PERF
|
||
|
cBFClean[pbf->lClass]--;
|
||
|
cBFNewDirties[pbf->lClass]++;
|
||
|
#else // !COSTLY_PERF
|
||
|
cBFClean--;
|
||
|
cBFNewDirties++;
|
||
|
#endif // COSTLY_PERF
|
||
|
pbf->fDirty = fTrue;
|
||
|
}
|
||
|
BFLeaveCriticalSection( pbf );
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/* resets a BFs dirty flag
|
||
|
/**/
|
||
|
|
||
|
extern BOOL fLogDisabled;
|
||
|
|
||
|
STATIC INLINE VOID BFResetDirtyBit( BF *pbf )
|
||
|
{
|
||
|
BFEnterCriticalSection( pbf );
|
||
|
Assert( fRecovering ||
|
||
|
pbf->fSyncWrite ||
|
||
|
pbf->cWriteLatch == 0 );
|
||
|
pbf->fVeryOld = fFalse;
|
||
|
|
||
|
Assert( fLogDisabled || fRecovering || !rgfmp[DbidOfPn( pbf->pn )].fLogOn ||
|
||
|
memcmp( &pbf->lgposRC, &lgposMax, sizeof( LGPOS ) ) != 0 );
|
||
|
|
||
|
pbf->lgposRC = lgposMax;
|
||
|
if ( pbf->fDirty )
|
||
|
{
|
||
|
#ifdef COSTLY_PERF
|
||
|
cBFClean[pbf->lClass]++;
|
||
|
#else // !COSTLY_PERF
|
||
|
cBFClean++;
|
||
|
#endif // COSTLY_PERF
|
||
|
pbf->fDirty = fFalse;
|
||
|
}
|
||
|
BFLeaveCriticalSection( pbf );
|
||
|
}
|
||
|
|
||
|
|
||
|
STATIC INLINE VOID BFDirty( BF *pbf )
|
||
|
{
|
||
|
DBID dbid = DbidOfPn( pbf->pn );
|
||
|
|
||
|
Assert( !pbf->fHold );
|
||
|
|
||
|
BFSetDirtyBit( pbf );
|
||
|
|
||
|
/* set ulDBTime for logging and also for multiple cursor
|
||
|
/* maintenance, so that cursors can detect a change.
|
||
|
/**/
|
||
|
Assert( fRecovering ||
|
||
|
dbid == dbidTemp ||
|
||
|
QwPMDBTime( pbf->ppage ) <= QwDBHDRDBTime( rgfmp[dbid].pdbfilehdr ) );
|
||
|
|
||
|
DBHDRIncDBTime( rgfmp[dbid].pdbfilehdr );
|
||
|
PMSetDBTime( pbf->ppage, QwDBHDRDBTime( rgfmp[dbid].pdbfilehdr ) );
|
||
|
}
|
||
|
|
||
|
|
||
|
/* check if a page is dirty. If it is allocated for temp buffer, whose
|
||
|
* pn must be Null, then no need to check if it is dirty since it will
|
||
|
* not be written out.
|
||
|
*/
|
||
|
#define AssertBFDirty( pbf ) \
|
||
|
Assert( (pbf)->pn == pnNull || \
|
||
|
(pbf) != pbfNil && (pbf)->fDirty == fTrue )
|
||
|
|
||
|
#define AssertBFPin( pbf ) Assert( (pbf)->cPin > 0 )
|
||
|
|
||
|
#define AssertBFWaitLatched( pbf, ppib ) \
|
||
|
Assert( (pbf)->cWaitLatch > 0 \
|
||
|
&& (pbf)->cPin > 0 \
|
||
|
&& (pbf)->ppibWaitLatch == (ppib) );
|
||
|
|
||
|
STATIC INLINE VOID BFPin( BF *pbf )
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
BFEnterCriticalSection( pbf );
|
||
|
Assert( pbf != pbfNil );
|
||
|
Assert( !pbf->fSyncRead );
|
||
|
Assert( !pbf->fAsyncRead );
|
||
|
Assert( pbf->cPin >= 0 );
|
||
|
pbf->cPin++;
|
||
|
BFLeaveCriticalSection( pbf );
|
||
|
#else // !DEBUG
|
||
|
UtilInterlockedIncrement( &pbf->cPin );
|
||
|
#endif // DEBUG
|
||
|
}
|
||
|
|
||
|
STATIC INLINE VOID BFUnpin( BF *pbf )
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
BFEnterCriticalSection( pbf );
|
||
|
Assert( pbf != pbfNil );
|
||
|
Assert( !pbf->fSyncRead );
|
||
|
Assert( !pbf->fAsyncRead );
|
||
|
Assert( pbf->cPin > 0 );
|
||
|
pbf->cPin--;
|
||
|
BFLeaveCriticalSection( pbf );
|
||
|
#else // !DEBUG
|
||
|
UtilInterlockedDecrement( &pbf->cPin );
|
||
|
#endif // DEBUG
|
||
|
}
|
||
|
|
||
|
|
||
|
STATIC INLINE VOID BFSetReadLatch( BF *pbf, PIB *ppib )
|
||
|
{
|
||
|
#ifdef READ_LATCH
|
||
|
BFPin( pbf );
|
||
|
Assert( pbf->cWriteLatch == 0 || pbf->ppibWriteLatch == ppib );
|
||
|
pbf->cReadLatch++;
|
||
|
#endif // READ_LATCH
|
||
|
}
|
||
|
|
||
|
STATIC INLINE VOID BFResetReadLatch( BF *pbf, PIB *ppib )
|
||
|
{
|
||
|
#ifdef READ_LATCH
|
||
|
Assert( pbf->cReadLatch > 0 );
|
||
|
Assert( pbf->cWriteLatch == 0 || pbf->ppibWriteLatch == ppib );
|
||
|
pbf->cReadLatch--;
|
||
|
BFUnpin( pbf );
|
||
|
#endif // READ_LATCH
|
||
|
}
|
||
|
|
||
|
STATIC INLINE BOOL FBFReadLatchConflict( PIB *ppib, BF *pbf )
|
||
|
{
|
||
|
#ifdef READ_LATCH
|
||
|
return pbf->cWriteLatch > 0 && pbf->ppibWriteLatch != ppib;
|
||
|
#else // !READ_LATCH
|
||
|
return fFalse;
|
||
|
#endif // READ_LATCH
|
||
|
}
|
||
|
|
||
|
|
||
|
STATIC INLINE VOID BFSetWriteLatch( BF *pbf, PIB *ppib )
|
||
|
{
|
||
|
BFPin( pbf );
|
||
|
#ifdef READ_LATCH
|
||
|
Assert( pbf->cReadLatch == 0 );
|
||
|
#endif // READ_LATCH
|
||
|
Assert( pbf->cWriteLatch == 0 || pbf->ppibWriteLatch == ppib );
|
||
|
pbf->cWriteLatch++;
|
||
|
pbf->ppibWriteLatch = ppib;
|
||
|
}
|
||
|
|
||
|
STATIC INLINE VOID BFResetWriteLatch( BF *pbf, PIB *ppib )
|
||
|
{
|
||
|
#ifdef READ_LATCH
|
||
|
Assert( pbf->cReadLatch == 0 );
|
||
|
#endif // READ_LATCH
|
||
|
Assert( pbf->cWriteLatch > 0 );
|
||
|
Assert( pbf->ppibWriteLatch == ppib );
|
||
|
pbf->cWriteLatch--;
|
||
|
BFUnpin( pbf );
|
||
|
}
|
||
|
|
||
|
STATIC INLINE BOOL FBFWriteLatchConflict( PIB *ppib, BF *pbf )
|
||
|
{
|
||
|
return
|
||
|
#ifdef READ_LATCH
|
||
|
pbf->cReadLatch > 0 ||
|
||
|
#endif // READ_LATCH
|
||
|
( pbf->cWriteLatch > 0 && pbf->ppibWriteLatch != ppib );
|
||
|
}
|
||
|
|
||
|
STATIC INLINE BOOL FBFWriteLatch( PIB *ppib, BF *pbf )
|
||
|
{
|
||
|
return pbf->cWriteLatch > 0 && pbf->ppibWriteLatch == ppib;
|
||
|
}
|
||
|
|
||
|
|
||
|
STATIC INLINE VOID BFSetWaitLatch( BF *pbf, PIB *ppib )
|
||
|
{
|
||
|
AssertCriticalSection( critJet );
|
||
|
BFSetWriteLatch( pbf, ppib );
|
||
|
Assert( pbf->cWaitLatch == 0 ||
|
||
|
pbf->ppibWaitLatch == ppib );
|
||
|
pbf->cWaitLatch++;
|
||
|
pbf->ppibWaitLatch = ppib;
|
||
|
}
|
||
|
|
||
|
STATIC INLINE VOID BFResetWaitLatch( BF *pbf, PIB *ppib )
|
||
|
{
|
||
|
AssertCriticalSection( critJet );
|
||
|
Assert( pbf->cWaitLatch > 0 );
|
||
|
Assert( pbf->ppibWaitLatch == ppib );
|
||
|
pbf->cWaitLatch--;
|
||
|
BFResetWriteLatch( pbf, ppib );
|
||
|
}
|
||
|
|
||
|
ERR ErrBFDepend( BF *pbf, BF *pbfD );
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
extern ERR ErrLGTrace( PIB *ppib, CHAR *sz );
|
||
|
extern BOOL fDBGTraceBR;
|
||
|
#endif
|
||
|
|
||
|
STATIC INLINE VOID BFUndepend( BF *pbf )
|
||
|
{
|
||
|
if ( pbf->pbfDepend != pbfNil )
|
||
|
{
|
||
|
BF *pbfD = pbf->pbfDepend;
|
||
|
#ifdef DEBUG
|
||
|
if ( fDBGTraceBR )
|
||
|
{
|
||
|
char sz[256];
|
||
|
sprintf( sz, "UD %ld:%ld->%ld:%ld(%lu)",
|
||
|
DbidOfPn( pbf->pn ), PgnoOfPn( pbf->pn ),
|
||
|
DbidOfPn( pbf->pbfDepend->pn), PgnoOfPn( pbf->pbfDepend->pn ),
|
||
|
pbf->pbfDepend->cDepend );
|
||
|
CallS( ErrLGTrace( ppibNil, sz ) );
|
||
|
}
|
||
|
#endif
|
||
|
Assert( pbfD->cDepend > 0 );
|
||
|
BFEnterCriticalSection( pbfD );
|
||
|
pbfD->cDepend--;
|
||
|
pbf->pbfDepend = pbfNil;
|
||
|
BFLeaveCriticalSection( pbfD );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* When ppib is not Nil and check if a page is in use by checking if it is
|
||
|
* Accessible to this PIB. Note that a page is accessible even it is overlay
|
||
|
* latched (cPin != 0). This checking accessible is mainly used by BFAccess.
|
||
|
* If ppib is nil, basically it is used for freeing a buffer. This is used
|
||
|
* by BFClean and BFIAlloc.
|
||
|
*/
|
||
|
|
||
|
STATIC INLINE BOOL FBFNotAccessible( PIB *ppib, BF *pbf )
|
||
|
{
|
||
|
return pbf->fAsyncRead ||
|
||
|
pbf->fSyncRead ||
|
||
|
pbf->fAsyncWrite ||
|
||
|
pbf->fSyncWrite ||
|
||
|
pbf->fHold ||
|
||
|
( pbf->cWaitLatch != 0 && ppib != pbf->ppibWaitLatch );
|
||
|
}
|
||
|
|
||
|
STATIC INLINE BOOL FBFNotAvail( BF *pbf )
|
||
|
{
|
||
|
return pbf->fAsyncRead ||
|
||
|
pbf->fSyncRead ||
|
||
|
pbf->fAsyncWrite ||
|
||
|
pbf->fSyncWrite ||
|
||
|
pbf->fHold ||
|
||
|
pbf->cPin != 0;
|
||
|
}
|
||
|
|
||
|
STATIC INLINE BOOL FBFInUse( PIB *ppib, BF *pbf )
|
||
|
{
|
||
|
return ppib != ppibNil ? FBFNotAccessible( ppib, pbf ) : FBFNotAvail( pbf );
|
||
|
}
|
||
|
|
||
|
STATIC INLINE BOOL FBFInUseByOthers( PIB *ppib, BF *pbf )
|
||
|
{
|
||
|
return pbf->fAsyncRead ||
|
||
|
pbf->fSyncRead ||
|
||
|
pbf->fAsyncWrite ||
|
||
|
pbf->fSyncWrite ||
|
||
|
pbf->fHold ||
|
||
|
pbf->cPin > 1 ||
|
||
|
( pbf->cWaitLatch != 0 && ppib != pbf->ppibWaitLatch ) ||
|
||
|
( pbf->cWriteLatch != 0 && ppib != pbf->ppibWriteLatch );
|
||
|
}
|
||
|
|
||
|
//---- STORAGE (storage.c) -------------------------------------------------
|
||
|
|
||
|
ERR ErrFMPSetDatabases( PIB *ppib );
|
||
|
extern BOOL fGlobalFMPLoaded;
|
||
|
ERR ErrFMPInit( VOID );
|
||
|
VOID FMPTerm( );
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
VOID ITDBGSetConstants();
|
||
|
#endif
|
||
|
ERR ErrITSetConstants( VOID );
|
||
|
ERR ErrITInit( VOID );
|
||
|
|
||
|
#define fTermCleanUp 0x00000001 /* Termination with OLC, Version clean up etc */
|
||
|
#define fTermNoCleanUp 0x00000002 /* Termination without any clean up */
|
||
|
|
||
|
#define fTermError 0x00000004 /* Terminate with error, no OLC clean up, */
|
||
|
/* no flush buffers, db header */
|
||
|
|
||
|
ERR ErrITTerm( INT fTerm );
|
||
|
|
||
|
ERR ErrBFNewPage( FUCB *pfucb, PGNO pgno, PGTYP pgtyp, PGNO pgnoFDP );
|
||
|
VOID BFSleep( unsigned long ulMSecs );
|
||
|
|
||
|
STATIC INLINE PN PnOfDbidPgno( DBID dbid, PGNO pgno )
|
||
|
{
|
||
|
return (PN) ( ( (PN) dbid << 24 ) | (PN) pgno );
|
||
|
}
|
||
|
|
||
|
STATIC INLINE DBID DbidOfPn( PN pn )
|
||
|
{
|
||
|
return (DBID) ( ( (BYTE *) &pn )[3] );
|
||
|
}
|
||
|
|
||
|
STATIC INLINE PGNO PgnoOfPn( PN pn )
|
||
|
{
|
||
|
return (PGNO) ( pn & 0x00FFFFFF );
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID BFReference( BF *pbf, PIB *ppib );
|
||
|
|
||
|
#define FBFReadAccessPage FBFAccessPage
|
||
|
#define FBFWriteAccessPage FBFAccessPage
|
||
|
|
||
|
STATIC INLINE BOOL FBFAccessPage( FUCB *pfucb, PGNO pgno )
|
||
|
{
|
||
|
BOOL fAccessible;
|
||
|
BF *pbf = pfucb->ssib.pbf;
|
||
|
|
||
|
AssertCriticalSection( critJet );
|
||
|
Assert( pfucb->ppib != ppibNil );
|
||
|
|
||
|
if ( pbf == pbfNil )
|
||
|
return fFalse;
|
||
|
|
||
|
/* if the cached BF's PN is the same and it is accessible and it is in
|
||
|
/* the LRUK heap or list, we can access the page
|
||
|
/**/
|
||
|
BFEnterCriticalSection( pbf );
|
||
|
fAccessible = ( pbf->pn == PnOfDbidPgno( pfucb->dbid, pgno ) &&
|
||
|
!FBFNotAccessible( pfucb->ppib, pbf ) &&
|
||
|
pbf->fInLRUK );
|
||
|
BFLeaveCriticalSection( pbf );
|
||
|
|
||
|
#ifdef LRU1
|
||
|
BFReference( pbf, pfucb->ppib );
|
||
|
#else // !LRU1
|
||
|
/* if this is not a correlated access, this counts as a BF reference
|
||
|
/**/
|
||
|
if ( fAccessible && pbf->trxLastRef != pfucb->ppib->trxBegin0 )
|
||
|
BFReference( pbf, pfucb->ppib );
|
||
|
#endif // LRU1
|
||
|
|
||
|
return fAccessible;
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
|
||
|
#define AssertFBFReadAccessPage AssertFBFAccessPage
|
||
|
#define AssertFBFWriteAccessPage AssertFBFAccessPage
|
||
|
|
||
|
STATIC VOID AssertFBFAccessPage( FUCB *pfucb, PGNO pgno )
|
||
|
{
|
||
|
BF *pbf = pfucb->ssib.pbf;
|
||
|
|
||
|
AssertCriticalSection( critJet );
|
||
|
Assert( pfucb->ppib != ppibNil );
|
||
|
|
||
|
Assert( pbf != pbfNil );
|
||
|
|
||
|
/* if the cached BF's PN is the same and it is accessible and it is in
|
||
|
/* the LRUK heap or list, we can access the page
|
||
|
/**/
|
||
|
BFEnterCriticalSection( pbf );
|
||
|
|
||
|
Assert( pbf->pn == PnOfDbidPgno( pfucb->dbid, pgno ) );
|
||
|
Assert( !FBFNotAccessible( pfucb->ppib, pbf ) );
|
||
|
Assert( pbf->fInLRUK );
|
||
|
|
||
|
BFLeaveCriticalSection( pbf );
|
||
|
}
|
||
|
|
||
|
#else // !DEBUG
|
||
|
|
||
|
#define AssertFBFReadAccessPage( pfucbX, pgnoX )
|
||
|
#define AssertFBFWriteAccessPage( pfucbX, pgnoX )
|
||
|
|
||
|
#endif // DEBUG
|
||
|
|
||
|
//---- PAGE (page.c) --------------------------------------------------------
|
||
|
|
||
|
STATIC INLINE QWORD QwSTDBTimePssib( SSIB *pssib )
|
||
|
{
|
||
|
return QwPMDBTime( pssib->pbf->ppage );
|
||
|
}
|
||
|
|
||
|
STATIC INLINE VOID PMSetQwDBTime( SSIB *pssib, QWORD qw )
|
||
|
{
|
||
|
Assert( qw <= QwDBHDRDBTime( rgfmp[DbidOfPn( pssib->pbf->pn )].pdbfilehdr ) );
|
||
|
PMSetDBTime( pssib->pbf->ppage, qw );
|
||
|
}
|
||
|
|
||
|
STATIC INLINE VOID BFSetQwDBTime( BF *pbf, QWORD qw )
|
||
|
{
|
||
|
Assert( qw <= QwDBHDRDBTime( rgfmp[DbidOfPn( pbf->pn )].pdbfilehdr ) );
|
||
|
PMSetDBTime( pbf->ppage, qw );
|
||
|
}
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
VOID AssertPMGet( SSIB *pssib, LONG itag );
|
||
|
#else
|
||
|
#define AssertPMGet( pssib, itag )
|
||
|
#endif
|
||
|
|
||
|
|
||
|
// End Assert redirection
|
||
|
|
||
|
#undef szAssertFilename
|
||
|
|
||
|
#endif // _STAPI_H
|
||
|
|
||
|
|