#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