#ifdef FCB_INCLUDED #error fcb.h already included #endif /* FCB_INCLUDED */ #define FCB_INCLUDED /* unique sequential key /**/ typedef ULONG DBK; #define FFCBDeletePending( pfcb ) ( (pfcb)->fFCBDeletePending ) #define FCBSetDeletePending( pfcb ) ( (pfcb)->fFCBDeletePending = 1 ) #define FCBResetDeletePending( pfcb ) ( (pfcb)->fFCBDeletePending = 0 ) #define FFCBOLCStatsAvail( pfcb ) ( (pfcb)->fFCBOLCStatsAvail ) #define FCBSetOLCStatsAvail( pfcb ) ( (pfcb)->fFCBOLCStatsAvail = 1 ) #define FCBResetOLCStatsAvail( pfcb ) ( (pfcb)->fFCBOLCStatsAvail = 0 ) #define FFCBOLCStatsChange( pfcb ) ( (pfcb)->fFCBOLCStatsChange ) #define FCBSetOLCStatsChange( pfcb ) ( (pfcb)->fFCBOLCStatsChange = 1 ) #define FCBResetOLCStatsChange( pfcb ) ( (pfcb)->fFCBOLCStatsChange = 0 ) #define FFCBTemporaryTable( pfcb ) ( (pfcb)->fFCBTemporaryTable ) #define FCBSetTemporaryTable( pfcb ) ( (pfcb)->fFCBTemporaryTable = 1 ) #define FCBResetTemporaryTable( pfcb ) ( (pfcb)->fFCBTemporaryTable = 0 ) #define FFCBSystemTable( pfcb ) \ ( UtilCmpName( (pfcb)->szFileName, szScTable ) == 0 || \ UtilCmpName( (pfcb)->szFileName, szSiTable ) == 0 || \ UtilCmpName( (pfcb)->szFileName, szSoTable ) == 0 ) #define FFCBClusteredIndex( pfcb ) ( (pfcb)->fFCBClusteredIndex ) #define FCBSetClusteredIndex( pfcb ) ( (pfcb)->fFCBClusteredIndex = 1 ) #define FCBResetClusteredIndex( pfcb ) ( (pfcb)->fFCBClusteredIndex = 0 ) #define FFCBDomainDenyWrite( pfcb ) ( (pfcb)->crefDomainDenyWrite > 0 ) #define FCBSetDomainDenyWrite( pfcb ) ( (pfcb)->crefDomainDenyWrite++ ) #define FCBResetDomainDenyWrite( pfcb ) \ { \ Assert( (pfcb)->crefDomainDenyWrite > 0 ); \ --(pfcb)->crefDomainDenyWrite; \ } #define FFCBDomainDenyRead( pfcb, ppib ) ( (pfcb)->fFCBDomainDenyRead && (ppib) != (pfcb)->ppibDomainDenyRead ) #define FCBSetDomainDenyRead( pfcb, ppib ) \ { \ if ( (pfcb)->crefDomainDenyRead++ == 0 ) \ { \ Assert( (pfcb)->ppibDomainDenyRead == ppibNil ); \ (pfcb)->ppibDomainDenyRead = (ppib); \ (pfcb)->fFCBDomainDenyRead = 1; \ } \ else \ { \ Assert( (pfcb)->ppibDomainDenyRead == (ppib) ); \ Assert( (pfcb)->fFCBDomainDenyRead ); \ } \ } #define FCBResetDomainDenyRead( pfcb ) \ { \ Assert( (pfcb)->crefDomainDenyRead > 0 ); \ Assert( (pfcb)->ppibDomainDenyRead != ppibNil ); \ Assert( (pfcb)->fFCBDomainDenyRead ); \ if ( --(pfcb)->crefDomainDenyRead == 0 ) \ { \ (pfcb)->fFCBDomainDenyRead = 0; \ (pfcb)->ppibDomainDenyRead = ppibNil; \ } \ } #define FFCBDomainDenyReadByUs( pfcb, ppib ) ( (pfcb)->fFCBDomainDenyRead && (ppib) == (pfcb)->ppibDomainDenyRead ) // Don't have an explicit fSort flag, but we can tell if it's a sort FCB by // examining certain fields. #define FFCBSort( pfcb ) ( (pfcb)->pgnoFDP > pgnoSystemRoot && \ (pfcb)->pfdb == pfdbNil && \ (pfcb)->pfcbNextIndex == pfcbNil && \ (pfcb)->pfcbTable == pfcbNil && \ (pfcb)->pidb == pidbNil && \ (pfcb)->dbid == dbidTemp && \ !FFCBTemporaryTable( pfcb ) && \ !FFCBClusteredIndex( pfcb ) ) #define FFCBReadLatch( pfcb ) ( (pfcb)->crefReadLatch > 0 ) #define FCBSetReadLatch( pfcb ) \ { \ Assert( FFCBClusteredIndex( pfcb ) || \ ( (pfcb)->pgnoFDP == pgnoSystemRoot ) || \ FFCBSort( pfcb ) ); \ (pfcb)->crefReadLatch++; \ } #define FCBResetReadLatch( pfcb ) \ { \ Assert( (pfcb)->crefReadLatch > 0 ); \ --(pfcb)->crefReadLatch; \ } #define FFCBSentinel( pfcb ) ( (pfcb)->fFCBSentinel ) #define FCBSetSentinel( pfcb ) ( (pfcb)->fFCBSentinel = 1 ) #define FCBResetSentinel( pfcb ) ( (pfcb)->fFCBSentinel = 0 ) #define FFCBWriteLatch( pfcb, ppib ) ( (pfcb)->crefWriteLatch > 0 && (ppib) != (pfcb)->ppibWriteLatch ) #define FFCBWriteLatchByUs( pfcb, ppib ) ( (pfcb)->crefWriteLatch > 0 && (ppib) == (pfcb)->ppibWriteLatch ) #define FCBSetWriteLatch( pfcb, ppib ) \ { \ Assert( FFCBClusteredIndex( pfcb ) || \ FFCBSentinel( pfcb ) ); \ if ( (pfcb)->crefWriteLatch++ == 0 ) \ { \ Assert( (pfcb)->ppibWriteLatch == ppibNil ); \ (pfcb)->ppibWriteLatch = (ppib); \ } \ else \ { \ Assert( (pfcb)->ppibWriteLatch == ppib ); \ } \ } #define FCBResetWriteLatch( pfcb, ppib ) \ { \ Assert( FFCBWriteLatchByUs( pfcb, ppib ) ); \ Assert( (pfcb)->crefWriteLatch > 0 ); \ Assert( (pfcb)->ppibWriteLatch != ppibNil ); \ if ( --(pfcb)->crefWriteLatch == 0 ) \ { \ (pfcb)->ppibWriteLatch = ppibNil; \ } \ } #define FFCBWait( pfcb ) ( (pfcb)->fFCBWait ) #define FCBSetWait( pfcb ) \ { \ Assert( !FFCBWait( pfcb ) ); \ (pfcb)->fFCBWait = 1; \ } #define FCBResetWait( pfcb ) \ { \ Assert( FFCBWait( pfcb ) ); \ (pfcb)->fFCBWait = 0; \ } #define FFCBInLRU( pfcb ) ( (pfcb)->fFCBInLRU ) #define FCBSetInLRU( pfcb ) \ { \ Assert( !FFCBInLRU( pfcb ) ); \ (pfcb)->fFCBInLRU = 1; \ } #define FCBResetInLRU( pfcb ) \ { \ Assert( FFCBInLRU( pfcb ) ); \ (pfcb)->fFCBInLRU = 0; \ } #define CVersionFCB( pfcb ) (pfcb)->cVersion #define FCBVersionIncrement( pfcb ) (pfcb)->cVersion++; #define FCBVersionDecrement( pfcb ) \ { \ if ( (pfcb) != pfcbNil ) \ { \ Assert( cVersion-- > 0 ); \ Assert( (pfcb)->cVersion > 0 ); \ (pfcb)->cVersion--; \ (pfcb) = pfcbNil; \ } \ } // File Control Block // typedef struct _fcb { //--------------------USED BY DATA & INDEX FCB--------------------- struct _fdb volatile *pfdb; // field descriptors struct _fcb *pfcbNextIndex; // chain of indexes for this file struct _fcb *pfcbLRU; // next LRU FCB in global LRU list struct _fcb *pfcbMRU; // previous LRU FCB in global LRU list INT fFCBInLRU : 1; // in LRU list struct _fcb *pfcbNextInHashBucket; struct _fcb *pfcbTable; // points to FCB of table for an index FCB struct _idb *pidb; // index info (NULL if "seq." file) FUCB *pfucb; // chain of FUCBs open on this file PGNO pgnoFDP; // FDP of this file/index DBID dbid; // which database SHORT cbDensityFree; // loading density parameter: // # of bytes free w/o using new page INT wRefCnt; // # of FUCBs for this file/index INT volatile cVersion; // # of RCEs for this file/index INT crefDomainDenyRead; // # of FUCBs with deny read flag INT crefDomainDenyWrite;// # of FUCBs with deny write flag INT crefReadLatch; // # of read latch on this FCB. INT crefWriteLatch; // # of FUCB ( of the same ppib ) with write // latch on this FCB. PIB *ppibWriteLatch; // ppib of process updating index/adding column PIB *ppibDomainDenyRead;// ppib of process holding exclusive lock /* flags for FCB /**/ union { ULONG ulFlags; struct { INT fFCBTemporaryTable : 1; // This is a temporary file INT fFCBClusteredIndex : 1; // This FCB is for data records. INT fFCBDomainDenyRead : 1; // no other session can read domain INT fFCBSentinel : 1; // FCB is only flag holder INT fFCBWait : 1; // wait flag INT fFCBOLCStatsAvail : 1; // are OLC Stats available? INT fFCBOLCStatsChange : 1; // have OLC Stats changed since last open? INT fFCBDeletePending : 1; // is a delete pending on this table/index? }; }; //--------------------USED ONLY BY FCB OF DATA--------------------- CHAR *szFileName; // name of file (for GetTableInfo) DBK dbkMost; // greatest DBK in use ULONG ulLongIdMax; // max long field id BYTE rgbitAllIndex[32]; // used for clustered index FCB only //-------------------------INSTRUMENTATION---------------------------- ULONG cpgCompactFreed; P_OLC_DATA olc_data; /* PCACHE_OPTIMIZATION pads to multiple of 32 bytes. /* We're currently 4 bytes short, so even if COSTLY_PERF is disabled, add /* lClass anyways to pad to our requisite 32-byte boundary. /**/ #if defined( COSTLY_PERF ) || defined( PCACHE_OPTIMIZATION ) ULONG lClass; // table stats class (for BF performance) #endif BYTE rgbFiller[20]; } FCB; /* hash table for FCB /**/ #define cFCBBuckets 256 FCB* pfcbHash[cFCBBuckets]; #define FCBHashInit() \ { \ Assert( pfcbNil == (FCB *) 0 ); \ memset( pfcbHash, '\0', sizeof( pfcbHash ) ); \ } #define FCBInitFCB( pfcb ) \ { \ memset( pfcb, '\0', sizeof(FCB) ); \ } #define PfcbMEMAlloc() ( (FCB *)PbMEMAlloc( iresFCB ) ) #define PfcbMEMPreferredThreshold() ( (FCB *)PbMEMPreferredThreshold( iresFCB ) ) #define PfcbMEMMax() ( (FCB *)PbMEMMax( iresFCB ) ) #ifdef DEBUG /* Debug check for illegal use of freed fcb */ #define MEMReleasePfcb(pfcb) \ { \ Assert( PfcbFCBGet( (pfcb)->dbid, (pfcb)->pgnoFDP ) != pfcb ); \ Assert( (pfcb)->pfdb == pfdbNil ); \ MEMRelease( iresFCB, (BYTE*)(pfcb) ); \ (pfcb) = pfcbNil; \ } #else #define MEMReleasePfcb(pfcb) \ { \ MEMRelease( iresFCB, (BYTE*)(pfcb) ); \ } #endif ERR ErrFCBISetMode( PIB *ppib, FCB *pfcb, JET_GRBIT grbit ); /* if opening domain for read, write or read write, and not with /* deny read or deny write, and domain does not have deny read or /* deny write set, then return JET_errSuccess, else call /* ErrFCBISetMode to determine if lock is by other session or to /* put lock on domain. /**/ INLINE LOCAL ERR ErrFCBSetMode( PIB *ppib, FCB *pfcb, ULONG grbit ) { if ( ( grbit & ( JET_bitTableDenyRead | JET_bitTableDenyWrite ) ) == 0 ) { // No read/write restrictions. Ensure no other session has any locks. if ( !( FFCBWriteLatch( pfcb, ppib ) || FFCBDomainDenyRead( pfcb, ppib ) || FFCBDomainDenyWrite( pfcb ) || FFCBDeletePending( pfcb ) ) ) return JET_errSuccess; } return ErrFCBISetMode( ppib, pfcb, grbit ); } /* reset DDL is same as reset Delete. Both use deny read flags /* or sentinel. /**/ #define FCBResetRenameTable FCBResetDeleteTable extern BYTE * rgfcb; extern FCB * pfcbGlobalMRU; extern CRIT critGlobalFCBList; /* outstanding versions may be on non-clustered index and not on /* table FCB, so must check all non-clustered indexes before /* freeing table FCBs. /**/ STATIC INLINE BOOL FFCBINoVersion( FCB *pfcbTable ) { FCB *pfcbT; for ( pfcbT = pfcbTable; pfcbT != pfcbNil; pfcbT = pfcbT->pfcbNextIndex ) { if ( pfcbT->cVersion > 0 ) { return fFalse; } } return fTrue; } #define FFCBAvail( pfcb, ppib ) \ ( pfcb->wRefCnt == 0 && \ pfcb->pgnoFDP != 1 && \ !FFCBReadLatch( pfcb ) && \ !FFCBSentinel( pfcb ) && \ !FFCBDomainDenyRead( pfcb, ppib ) && \ !FFCBWait( pfcb ) && \ FFCBINoVersion( pfcb ) ) VOID FCBTerm( VOID ); VOID FCBInsert( FCB *pfcb ); VOID FCBLink( FUCB *pfucb, FCB *pfcb ); VOID FCBInsertHashTable( FCB *pfcb ); VOID FCBDeleteHashTable( FCB *pfcb ); VOID FCBUnlink( FUCB *pfucb ); FCB *PfcbFCBGet( DBID dbid, PGNO pgnoFDP ); ERR ErrFCBAlloc( PIB *ppib, FCB **ppfcb ); VOID FCBPurgeDatabase( DBID dbid ); VOID FCBPurgeTable( DBID dbid, PGNO pgnoFDP ); ERR ErrFCBNew( PIB *ppib, DBID dbid, PGNO pgno, FCB **ppfcb ); VOID FCBResetMode( PIB *ppib, FCB *pfcb, JET_GRBIT grbit ); ERR ErrFCBSetDeleteTable( PIB *ppib, DBID dbid, PGNO pgnoFDP ); VOID FCBResetDeleteTable( FCB *pfcb ); ERR ErrFCBSetRenameTable( PIB *ppib, DBID dbid, PGNO pgno ); FCB *FCBResetAfterRedo( void ); BOOL FFCBTableOpen ( DBID dbid, PGNO pgno ); VOID FCBLinkIndex( FCB *pfcbTable, FCB *pfcbIndex ); VOID FCBUnlinkIndex( FCB *pfcbTable, FCB *pfcbIndex ); BOOL FFCBUnlinkIndexIfFound( FCB *pfcbTable, FCB *pfcbIndex ); FCB *PfcbFCBUnlinkIndexByName( FCB *pfcb, CHAR *szIndex ); ERR ErrFCBSetDeleteIndex( PIB *ppib, FCB *pfcbTable, CHAR *szIndex ); VOID FCBResetDeleteIndex( FCB *pfcbIndex ); INLINE STATIC VOID FCBLinkClusteredIdx( FCB *pfcbClustered ) { FCB *pfcbIdx; for ( pfcbIdx = pfcbClustered->pfcbNextIndex; pfcbIdx != pfcbNil; pfcbIdx = pfcbIdx->pfcbNextIndex ) { pfcbIdx->pfcbTable = pfcbClustered; } }