452 lines
14 KiB
C
452 lines
14 KiB
C
//============== DAE: OS/2 Database Access Engine =====================
|
||
//============== stapi.h: Storage System API =====================
|
||
|
||
//---- externs -------------------------------------------------------------
|
||
|
||
extern SEM __near semST;
|
||
extern RES __near rgres[];
|
||
extern TRX __near trxOldest;
|
||
extern TRX __near trxNewest;
|
||
|
||
extern SIG __near sigBFCleanProc;
|
||
|
||
//---- IO (io.c) ----------------------------------------------------------
|
||
|
||
#define LOffsetOfPgnoLow( pgno ) ( ((pgno) - 1) << 12 )
|
||
#define LOffsetOfPgnoHigh( pgno ) ( ((pgno) - 1) >> 20 )
|
||
|
||
#define fioqeOpenFile 1 /* for Opening File */
|
||
#define fioqeCloseFile 2 /* for Closing File */
|
||
#define fioqeDeleteFile 3 /* for deleting file */
|
||
#define fioqeNewSize 4 /* for resize file */
|
||
|
||
typedef struct _ioqe /* IO queue element */
|
||
{
|
||
struct _ioqe *pioqePrev; /* double linked IO queue list */
|
||
struct _ioqe *pioqeNext;
|
||
SIG sigIO; /* signal to wait for IO completion */
|
||
ERR err; /* error code for err occurs during the IO */
|
||
INT fioqe; /* use up to 16 bits only */
|
||
} IOQE;
|
||
|
||
#define fioqefileReadOnly fTrue
|
||
#define fioqefileReadWrite fFalse
|
||
typedef struct _ioqefile
|
||
{
|
||
IOQE;
|
||
struct {
|
||
BOOL fioqefile; /* open file for read only or not */
|
||
HANDLE hf; /* file handle */
|
||
char *sz; /* fioqe = fioqeOpenFile, CloseFile, ExtFile */
|
||
struct {
|
||
ULONG cb; /* how long the file is */
|
||
ULONG cbHigh;
|
||
};
|
||
};
|
||
} IOQEFILE;
|
||
|
||
VOID IOInitFMP();
|
||
ERR ErrInitFileMap( PIB *ppib );
|
||
BOOL FFileExists( CHAR *szFileName );
|
||
ERR ErrIOOpenFile( HANDLE *phf, CHAR *szDatabaseName, ULONG cb, BOOL fioqefile );
|
||
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, PGNO pgnoFDP );
|
||
|
||
#define FIODatabaseOpen( dbid ) ( rgfmp[dbid].hf != handleNil )
|
||
ERR ErrIOOpenDatabase( DBID dbid, CHAR *szDatabaseName, CPG cpg );
|
||
VOID IOCloseDatabase( DBID dbid );
|
||
VOID IODeleteDatabase( DBID dbid );
|
||
BOOL FIODatabaseInUse( DBID dbid );
|
||
BOOL FIODatabaseAvailable( DBID dbid );
|
||
|
||
#define FDatabaseLocked( dbid ) (rgfmp[dbid].fXOpen)
|
||
|
||
#define IOUnlockDbid( dbid ) \
|
||
{ \
|
||
SgSemRequest( semST ); \
|
||
Assert( FDBIDWait( dbid ) ); \
|
||
DBIDResetWait( dbid ); \
|
||
SgSemRelease( semST ); \
|
||
}
|
||
|
||
#ifdef DEBUG
|
||
#define IOSetDatabaseVersion( dbid, ulVersion ) \
|
||
{ \
|
||
Assert( ulVersion == ulDAEPrevVersion || \
|
||
ulVersion == ulDAEVersion ); \
|
||
rgfmp[dbid].fPrevVersion = ( ulVersion == ulDAEPrevVersion );\
|
||
}
|
||
#else /* !DEBUG */
|
||
#define IOSetDatabaseVersion( dbid, ulVersion )
|
||
#endif /* !DEBUG */
|
||
|
||
#define FIOExclusiveByAnotherSession( dbid, ppib ) \
|
||
( Assert( FDBIDWait( dbid ) ), FDBIDExclusiveByAnotherSession( dbid, ppib ) )
|
||
|
||
#define IOSetExclusive( dbid, ppib ) \
|
||
{ \
|
||
Assert( FDBIDWait( dbid ) ); \
|
||
Assert( !( FDBIDExclusive( dbid ) ) ); \
|
||
DBIDSetExclusive( dbid, ppib ); \
|
||
}
|
||
|
||
#define IOResetExclusive( dbid ) \
|
||
{ \
|
||
Assert( FDBIDWait( dbid ) ); \
|
||
DBIDResetExclusive( dbid ); \
|
||
}
|
||
|
||
#define FIOReadOnly( dbid ) \
|
||
( Assert( FDBIDWait( dbid ) ), FDBIDReadOnly( dbid ) )
|
||
|
||
#define IOSetReadOnly( dbid ) \
|
||
{ \
|
||
Assert( FDBIDWait( dbid ) ); \
|
||
DBIDSetReadOnly( dbid ); \
|
||
}
|
||
|
||
#define IOResetReadOnly( dbid ) \
|
||
{ \
|
||
Assert( FDBIDWait( dbid ) ); \
|
||
DBIDResetReadOnly( dbid ); \
|
||
}
|
||
|
||
#define FIOAttached( dbid ) \
|
||
( Assert( FDBIDWait( dbid ) ), FDBIDAttached( dbid ) )
|
||
|
||
#define IOSetAttached( dbid ) \
|
||
{ \
|
||
Assert( FDBIDWait( dbid ) ); \
|
||
Assert( !( FDBIDAttached( dbid ) ) ); \
|
||
DBIDSetAttached( dbid ); \
|
||
}
|
||
|
||
#define IOResetAttached( dbid ) \
|
||
{ \
|
||
Assert( FDBIDWait( dbid ) ); \
|
||
Assert( FDBIDAttached( dbid ) ); \
|
||
DBIDResetAttached( dbid ); \
|
||
}
|
||
|
||
//---- PAGE (page.c) --------------------------------------------------------
|
||
|
||
// Max # of lines to update at once with ErrSTReplace
|
||
#define clineMax 6
|
||
|
||
#define UlSTDBTimePssib( pssib ) ( (pssib)->pbf->ppage->pghdr.ulDBTime )
|
||
#define PMSetUlDBTime( pssib, ul ) \
|
||
( Assert( (ul) <= rgfmp[DbidOfPn((pssib)->pbf->pn)].ulDBTime ), \
|
||
(pssib)->pbf->ppage->pghdr.ulDBTime = (ul) ) \
|
||
|
||
#define BFSetUlDBTime( pbf, ul ) \
|
||
( Assert( (ul) <= rgfmp[DbidOfPn((pbf)->pn)].ulDBTime ), \
|
||
(pbf)->ppage->pghdr.ulDBTime = (ul) ) \
|
||
|
||
#ifdef DEBUG
|
||
VOID AssertPMGet( SSIB *pssib, INT itag );
|
||
#else
|
||
#define AssertPMGet( pssib, itag )
|
||
#endif
|
||
|
||
|
||
//---- BUF (buf.c) ----------------------------------------------------------
|
||
|
||
#define LRU_K 1
|
||
|
||
CRIT __near critLRU;
|
||
|
||
typedef struct _lru
|
||
{
|
||
INT 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
|
||
INT cbfGroup; // number of bfs in this group
|
||
INT cbfThresholdLow; // threshold to start cleaning buffers
|
||
INT 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
|
||
|
||
typedef struct _bf
|
||
{
|
||
struct _page *ppage; // pointer to page buffer
|
||
struct _bf *pbfNext; // hash table overflow
|
||
struct _bf *pbfLRU; // pointer to Less Recently Used Buffer
|
||
struct _bf *pbfMRU; // pointer to More Recently Used Buffer
|
||
|
||
PIB *ppibWriteLatch; /* thread with Wait Latch */
|
||
PIB *ppibWaitLatch; /* thread with Wait Latch */
|
||
CRIT critBF; /* for setting fPreread/fRead/fWrite/fHold */
|
||
|
||
OLP olp; /* for ssync IO, to wait for IO completion */
|
||
HANDLE hf; /* for assync IO */
|
||
|
||
struct _bf *pbfNextBatchIO; /* next BF in BatchIO list */
|
||
INT ipageBatchIOFirst;
|
||
|
||
ERR err; /* error code for err occurs during the IO */
|
||
|
||
PN pn; // physical pn of cached page
|
||
UINT cPin; // if cPin > 0 then buf cannot be overlayed
|
||
UINT cReadLatch; // if cReadLatch > 0, page cannot be updated
|
||
UINT cWriteLatch; // if cWriteLatch > 0, page cannot be updated by other
|
||
UINT cWaitLatch;
|
||
UINT fDirty:1; // indicates page needs to be flushed
|
||
|
||
// the following flags are mutual exclusive:
|
||
UINT fPreread:1; // indicates page is being prefetched
|
||
UINT fRead:1; // indicates page is being read/written
|
||
UINT fWrite:1; //
|
||
UINT fHold:1; // indicates buf is in transient state.
|
||
|
||
UINT fIOError:1; // indicates read/write error
|
||
UINT fInHash:1; // BF is currently in hash table
|
||
|
||
ULONG ulBFTime1;
|
||
ULONG ulBFTime2;
|
||
INT ipbfHeap; // index in heap
|
||
|
||
UINT cDepend; // count of prior BF's to be flushed
|
||
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
|
||
#ifdef WIN16
|
||
HANDLE hpage; // handle to the page buffer
|
||
#endif
|
||
|
||
// UINT fWaiting:1; // someone is waiting to reference page
|
||
// INT wNumberPages; // number of contiguous pages to read
|
||
} BF;
|
||
#define pbfNil ((BF *) 0)
|
||
|
||
|
||
ERR ErrBFAccessPage( PIB *ppib, BF **ppbf, PN pn );
|
||
BF* PbfBFMostUsed( void );
|
||
VOID BFAbandon( 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 BFReadAsync( PN pn, INT cpage );
|
||
BF * PbfBFdMostUsed( void );
|
||
VOID BFRemoveDependence( PIB *ppib, BF *pbf );
|
||
|
||
/* buffer flush prototype and flags
|
||
/**/
|
||
#define fBFFlushSome 0
|
||
#define fBFFlushAll 1
|
||
ERR ErrBFFlushBuffers( DBID dbid, INT fBFFlush );
|
||
|
||
#define BFSFree( pbf ) \
|
||
{ \
|
||
SgSemRequest( semST ); \
|
||
BFFree( pbf ); \
|
||
SgSemRelease( semST ); \
|
||
}
|
||
|
||
#define FBFDirty( pbf ) ((pbf)->fDirty)
|
||
|
||
/* the following small functions are called too often, */
|
||
/* make it as a macros */
|
||
#ifdef DEBUG
|
||
VOID BFSetDirtyBit( BF *pbf );
|
||
#else
|
||
#define BFSetDirtyBit( pbf ) (pbf)->fDirty = fTrue
|
||
#endif
|
||
|
||
VOID BFDirty( BF *pbf );
|
||
|
||
/* 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) );
|
||
|
||
#define BFPin( pbf ) \
|
||
{ \
|
||
EnterCriticalSection( (pbf)->critBF ); \
|
||
Assert( (pbf) != pbfNil ); \
|
||
Assert( !(pbf)->fWrite ); \
|
||
Assert( !(pbf)->fRead ); \
|
||
(pbf)->cPin++; \
|
||
LeaveCriticalSection( (pbf)->critBF ); \
|
||
}
|
||
|
||
#define BFUnpin( pbf ) \
|
||
{ \
|
||
EnterCriticalSection( (pbf)->critBF ); \
|
||
Assert( (pbf) != pbfNil ); \
|
||
Assert( !(pbf)->fWrite ); \
|
||
Assert( !(pbf)->fRead ); \
|
||
Assert( (pbf)->cPin > 0 ); \
|
||
(pbf)->cPin--; \
|
||
LeaveCriticalSection( (pbf)->critBF ); \
|
||
}
|
||
|
||
#define BFSetReadLatch( pbf, ppibT ) \
|
||
{ \
|
||
Assert( (pbf)->cPin > 0 ); \
|
||
Assert( (pbf)->cWriteLatch == 0 || \
|
||
(pbf)->ppibWriteLatch == (ppibT) ); \
|
||
(pbf)->cReadLatch++; \
|
||
}
|
||
|
||
#define BFResetReadLatch( pbf, ppibT ) \
|
||
{ \
|
||
Assert( (pbf)->cPin > 0 ); \
|
||
Assert( (pbf)->cReadLatch > 0 ); \
|
||
Assert( (pbf)->cWriteLatch == 0 || \
|
||
(pbf)->ppibWriteLatch == (ppibT) ); \
|
||
(pbf)->cReadLatch--; \
|
||
}
|
||
|
||
#define FBFReadLatchConflict( ppibT, pbf ) \
|
||
( (pbf)->cWriteLatch > 0 && \
|
||
(pbf)->ppibWriteLatch != (ppibT) )
|
||
|
||
#define BFSetWriteLatch( pbf, ppibT ) \
|
||
{ \
|
||
Assert( (pbf)->cPin > 0 ); \
|
||
Assert( (pbf)->cReadLatch == 0 ); \
|
||
Assert( (pbf)->cWriteLatch == 0 || \
|
||
(pbf)->ppibWriteLatch == (ppibT) ); \
|
||
(pbf)->cWriteLatch++; \
|
||
(pbf)->ppibWriteLatch = (ppibT); \
|
||
}
|
||
|
||
#define BFResetWriteLatch( pbf, ppibT ) \
|
||
{ \
|
||
Assert( (pbf)->cPin > 0 ); \
|
||
Assert( (pbf)->cReadLatch == 0 ); \
|
||
Assert( (pbf)->cWriteLatch > 0 ); \
|
||
Assert( (pbf)->ppibWriteLatch == (ppibT) ); \
|
||
if ( --(pbf)->cWriteLatch == 0 ) \
|
||
{ \
|
||
(pbf)->ppibWriteLatch = ppibNil; \
|
||
Assert( (pbf)->cWaitLatch == 0 ); \
|
||
} \
|
||
}
|
||
|
||
#define FBFWriteLatch( ppibT, pbf ) \
|
||
((pbf)->cPin > 0 && \
|
||
(pbf)->cWriteLatch > 0 && \
|
||
(pbf)->ppibWriteLatch == (ppibT))
|
||
|
||
#define FBFWriteLatchConflict( ppibT, pbf ) \
|
||
( (pbf)->cReadLatch > 0 || \
|
||
( (pbf)->cWriteLatch > 0 && \
|
||
(pbf)->ppibWriteLatch != (ppibT) ) )
|
||
|
||
#define BFSetWaitLatch( pbf, ppib ) \
|
||
{ \
|
||
Assert( ( pbf )->cPin > 0 ); \
|
||
Assert( ( pbf )->cWriteLatch > 0 ); \
|
||
Assert( (pbf)->ppibWriteLatch == (ppib) ); \
|
||
if ( pbf->cWaitLatch++ > 0 ) \
|
||
Assert( (pbf)->ppibWaitLatch == (ppib) ); \
|
||
(pbf)->ppibWaitLatch = ppib; \
|
||
}
|
||
|
||
#define BFResetWaitLatch( pbf, ppibT ) \
|
||
{ \
|
||
Assert( (pbf)->cPin > 0 ); \
|
||
Assert( ( pbf )->cWriteLatch > 0 ); \
|
||
Assert( (pbf)->cWaitLatch > 0 ); \
|
||
Assert( (pbf)->ppibWaitLatch == (ppibT) ); \
|
||
if ( --(pbf)->cWaitLatch == 0 ) \
|
||
{ \
|
||
(pbf)->ppibWaitLatch = ppibNil; \
|
||
SignalSend( (pbf)->olp.sigIO ); \
|
||
} \
|
||
}
|
||
|
||
ERR ErrBFDepend( BF *pbf, BF *pbfD );
|
||
|
||
#define BFUndepend( pbf ) \
|
||
{ \
|
||
if ( (pbf)->pbfDepend != pbfNil ) \
|
||
{ \
|
||
BF *pbfD = (pbf)->pbfDepend; \
|
||
Assert( pbfD->cDepend > 0 ); \
|
||
EnterCriticalSection( pbfD->critBF ); \
|
||
pbfD->cDepend--; \
|
||
(pbf)->pbfDepend = pbfNil; \
|
||
LeaveCriticalSection( pbfD->critBF ); \
|
||
} \
|
||
}
|
||
|
||
//---- STORAGE (storage.c) -------------------------------------------------
|
||
|
||
ERR ErrFMPSetDatabases( PIB *ppib );
|
||
ERR ErrFMPInit( VOID );
|
||
VOID FMPTerm( );
|
||
|
||
ERR ErrSTSetIntrinsicConstants( VOID );
|
||
ERR ErrSTInit( VOID );
|
||
ERR ErrSTTerm( VOID );
|
||
|
||
// Transaction support
|
||
ERR ErrSTBeginTransaction( PIB *ppib );
|
||
ERR ErrSTRollback( PIB *ppib );
|
||
ERR ErrSTCommitTransaction( PIB *ppib );
|
||
ERR ErrSTInitOpenSysDB();
|
||
|
||
ERR ErrBFNewPage( FUCB *pfucb, PGNO pgno, PGTYP pgtyp, PGNO pgnoFDP );
|
||
VOID BFSleep( unsigned long ulMSecs );
|
||
|
||
// Modes for Storage System
|
||
#define modeRead 0
|
||
#define modeWrite 1
|
||
#define modeRIW 2
|
||
|
||
#define PnOfDbidPgno( dbid, pgno ) ( ( (LONG) (dbid) )<<24 | (pgno) )
|
||
#define DbidOfPn( pn ) ( (DBID)( (pn)>>24 ) )
|
||
#define PgnoOfPn( pn ) ( (pn) & 0x00ffffff )
|
||
|
||
#define ErrSTReadAccessPage ErrSTAccessPage
|
||
#define ErrSTWriteAccessPage ErrSTAccessPage
|
||
#define FReadAccessPage FAccessPage
|
||
#define FWriteAccessPage FAccessPage
|
||
|
||
BOOL FBFAccessPage( FUCB *pfucb, PGNO pgno );
|
||
#define FAccessPage( pfucb, pgno ) FBFAccessPage( pfucb, pgno )
|
||
|
||
// UNDONE: this should be in SgSemRequest( semST )
|
||
#define ErrSTAccessPage( pfucb, pgnoT ) \
|
||
( ErrBFAccessPage( pfucb->ppib, &(pfucb)->ssib.pbf, PnOfDbidPgno( (pfucb)->dbid, pgnoT ) ) )
|
||
|