251 lines
7.4 KiB
C
251 lines
7.4 KiB
C
//
|
|
//------ Page Structure ---------------------------------------------------
|
|
//
|
|
|
|
#define cbPage 4096 // database logical page size
|
|
|
|
#define ctagMax 256 // default limit on number of tags
|
|
|
|
typedef BYTE PGTYP;
|
|
|
|
// the pragma is bad for efficiency, but we need it here so that the
|
|
// THREEBYTES will not be aligned on 4-byte boundary
|
|
#pragma pack(1)
|
|
|
|
|
|
typedef struct _pghdr
|
|
{
|
|
ULONG ulChecksum; // checksum of page, always 1st byte
|
|
ULONG ulDBTimeLow; // database time page dirtied
|
|
PGNO pgnoFDP; // pgno of FDP which owns this page
|
|
SHORT cbFree; // count free bytes
|
|
SHORT ibMic; // minimum used byte
|
|
SHORT ctagMac; // count tags used
|
|
SHORT itagFree; // itag of first free tag
|
|
SHORT cbUncommittedFreed; // bytes freed from this page, but *possibly*
|
|
// uncommitted (this number will always be
|
|
// a subset of cbFree)
|
|
THREEBYTES pgnoPrev; // pgno of previous page
|
|
THREEBYTES pgnoNext; // pgno of next page
|
|
} PGHDR;
|
|
|
|
typedef struct _pgtrlr
|
|
{
|
|
PGTYP pgtyp:3;
|
|
BYTE bDBTimeHigh:4;
|
|
BYTE bitModified:1;
|
|
THREEBYTES pgnoThisPage;
|
|
} PGTRLR;
|
|
|
|
typedef struct _tag
|
|
{
|
|
SHORT cb;
|
|
SHORT ib;
|
|
} TAG;
|
|
|
|
/* tag status
|
|
/**/
|
|
typedef enum { tsLine, tsVacant, tsLink } TS;
|
|
|
|
typedef struct _page
|
|
{
|
|
PGHDR;
|
|
TAG rgtag[1];
|
|
BYTE rgbFiller[ cbPage -
|
|
sizeof(PGHDR) - // pghdr
|
|
sizeof(TAG) - // rgtag[1]
|
|
sizeof(BYTE) - // rgbData[1]
|
|
sizeof(PGTRLR) ]; // pgtyp and pgnoThisPage
|
|
BYTE rgbData[1];
|
|
|
|
PGTRLR;
|
|
} PAGE;
|
|
|
|
#pragma pack()
|
|
|
|
STATIC INLINE VOID PMSetDBTime( PAGE *ppage, QWORD qwDBTime )
|
|
{
|
|
QWORDX qwx;
|
|
qwx.qw = qwDBTime;
|
|
ppage->bDBTimeHigh = (BYTE) qwx.h;
|
|
ppage->ulDBTimeLow = qwx.l;
|
|
}
|
|
|
|
STATIC INLINE QWORD QwPMDBTime( PAGE *ppage )
|
|
{
|
|
QWORDX qwx;
|
|
qwx.l = ppage->ulDBTimeLow;
|
|
qwx.h = (ULONG) ppage->bDBTimeHigh;
|
|
return qwx.qw;
|
|
}
|
|
|
|
STATIC INLINE VOID PMIncDBTime( PAGE *ppage )
|
|
{
|
|
QWORDX qwx;
|
|
qwx.qw = QwPMDBTime( ppage );
|
|
qwx.qw++;
|
|
PMSetDBTime( ppage, qwx.qw );
|
|
}
|
|
|
|
#define bitLink (1L<<31)
|
|
|
|
#define pgtypFDP ((PGTYP) 0)
|
|
#define pgtypRecord ((PGTYP) 1)
|
|
#define pgtypIndexNC ((PGTYP) 2)
|
|
#define pgtypSort ((PGTYP) 4)
|
|
|
|
#define PMSetPageType( ppage, pgtypT ) ( (ppage)->pgtyp = pgtypT )
|
|
#define PMPageTypeOfPage( ppage ) ( (PGTYP)( (ppage)->pgtyp) )
|
|
|
|
#ifdef DEBUG
|
|
VOID PMSetModified( SSIB *ssib );
|
|
VOID PMResetModified( SSIB *pssib );
|
|
VOID CheckPgno( PAGE *ppage, PN pn );
|
|
#else
|
|
#define CheckPgno( ppage, pn )
|
|
#define PMSetModified( pssib ) ( (pssib)->pbf->ppage->bitModified = 1 )
|
|
#define PMResetModified( pssib ) ( (pssib)->pbf->ppage->bitModified = 0 )
|
|
#endif
|
|
|
|
#define PMPageSetModified( ppage ) ( (ppage)->bitModified = 1 )
|
|
#define PMPageResetModified( ppage ) ( (ppage)->bitModified = 0 )
|
|
#define FPMPageModified( ppage ) ( (ppage)->bitModified )
|
|
|
|
#define PMSetPgnoFDP( ppage, pgnoT ) ( (ppage)->pgnoFDP = pgnoT )
|
|
#define PgnoPMPgnoFDPOfPage( ppage ) ( (ppage)->pgnoFDP )
|
|
|
|
#define SetPgno( ppage, pgno ) \
|
|
ThreeBytesFromL( &(ppage)->pgnoThisPage, (pgno) )
|
|
#define SetPgnoNext( ppage, pgno ) \
|
|
ThreeBytesFromL( &(ppage)->pgnoNext, (pgno) )
|
|
#define SetPgnoPrev( ppage, pgno ) \
|
|
ThreeBytesFromL( &(ppage)->pgnoPrev, (pgno) )
|
|
|
|
#define PgnoFromPage( ppage, ppgno ) \
|
|
LFromThreeBytes( ppgno, &(ppage)->pgnoThisPage )
|
|
|
|
#ifdef DEBUG
|
|
#define PgnoNextFromPage( pssib, ppgno ) \
|
|
{ CheckSSIB( pssib ); LFromThreeBytes( ppgno, &(pssib)->pbf->ppage->pgnoNext ); }
|
|
#define PgnoPrevFromPage( pssib, ppgno ) \
|
|
{ CheckSSIB( (pssib) ); LFromThreeBytes( ppgno, &(pssib)->pbf->ppage->pgnoPrev ); }
|
|
#else
|
|
#define PgnoNextFromPage( pssib, ppgno ) \
|
|
LFromThreeBytes( ppgno, &(pssib)->pbf->ppage->pgnoNext )
|
|
#define PgnoPrevFromPage( pssib, ppgno ) \
|
|
LFromThreeBytes( ppgno, &(pssib)->pbf->ppage->pgnoPrev )
|
|
#endif
|
|
|
|
#define absdiff( x, y ) ( (x) > (y) ? (x)-(y) : (y)-(x) )
|
|
#define pgdiscont( pgno1, pgno2 ) \
|
|
( ( (pgno1) == 0 ) || ( (pgno2) == 0 ) ? 0 \
|
|
: absdiff( (pgno1), (pgno2) ) / cpgDiscont )
|
|
|
|
#define ibPgnoPrevPage ( (INT) (ULONG_PTR)&((PAGE *)0)->pgnoPrev )
|
|
#define ibPgnoNextPage ( (INT) (ULONG_PTR)&((PAGE *)0)->pgnoNext )
|
|
#define ibCbFreeTotal ( (INT) (ULONG_PTR)&((PAGE *)0)->cbFree )
|
|
#define ibCtagMac ( (INT) (ULONG_PTR)&((PAGE *)0)->ctagMac )
|
|
#define ibPgtyp ( (INT) (ULONG_PTR)&((PAGE *)0)->pgtyp )
|
|
|
|
#define CbLastFreeSpace(ppage) \
|
|
( (ppage)->ibMic \
|
|
- sizeof(PGHDR) \
|
|
- ( sizeof(TAG) * (ppage)->ctagMac ) )
|
|
|
|
#define IbCbFromPtag( ibP, cbP, ptagP ) \
|
|
{ TAG *_ptagT = ptagP; \
|
|
(ibP) = _ptagT->ib; \
|
|
(cbP) = _ptagT->cb; \
|
|
}
|
|
|
|
#define PtagFromIbCb( ptagP, ibP, cbP ) \
|
|
{ TAG *_ptagT = ptagP; \
|
|
_ptagT->ib = (SHORT)(ibP); \
|
|
_ptagT->cb = (SHORT)(cbP); \
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
#define PMGet( pssib, itagT ) CallS( ErrPMGet( pssib, itagT ) )
|
|
#else
|
|
#define PMGet( pssib, itagT ) \
|
|
{ \
|
|
PAGE *ppageT_ = (pssib)->pbf->ppage; \
|
|
TAG *ptagT_ = &(ppageT_->rgtag[itagT]); \
|
|
Assert( itagT >= 0 ); \
|
|
Assert( itagT < (pssib)->pbf->ppage->ctagMac ); \
|
|
(pssib)->line.pb = (BYTE *)ppageT_ + ptagT_->ib; \
|
|
(pssib)->line.cb = ptagT_->cb; \
|
|
}
|
|
#endif
|
|
|
|
#define ItagPMMost( ppage ) ((ppage)->ctagMac - 1)
|
|
|
|
BOOL FPMFreeTag( SSIB *pssib, INT citagReq );
|
|
|
|
|
|
#ifdef DEBUG
|
|
// This call does not guarantee the accuracy of cbUncommittedFree.
|
|
// If accuracy is needed, call CbNDFreePageSpace() instead.
|
|
#define CbPMFreeSpace( pssib ) ( CheckSSIB(pssib), \
|
|
((INT)( (pssib)->pbf->ppage->cbFree - (pssib)->pbf->ppage->cbUncommittedFreed ) ) )
|
|
#else
|
|
#define CbPMFreeSpace( pssib ) \
|
|
((INT)( (pssib)->pbf->ppage->cbFree - (pssib)->pbf->ppage->cbUncommittedFreed ) )
|
|
#endif
|
|
|
|
|
|
#if 0 // No longer needed with uncommitted freed page space count
|
|
#define PMAllocFreeSpace( pssib, cb ) \
|
|
{ \
|
|
Assert( (INT)(pssib)->pbf->ppage->cbFree >= cb ); \
|
|
(pssib)->pbf->ppage->cbFree -= cb; \
|
|
}
|
|
|
|
#define PMFreeFreeSpace( pssib, cb ) \
|
|
{ \
|
|
Assert( (INT)(pssib)->pbf->ppage->cbFree >= 0 ); \
|
|
(pssib)->pbf->ppage->cbFree += cb; \
|
|
Assert( (INT)(pssib)->pbf->ppage->cbFree < cbPage ); \
|
|
}
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
#define AssertBTFOP(pssib) \
|
|
Assert( PMPageTypeOfPage((pssib)->pbf->ppage) == pgtypSort || \
|
|
PMPageTypeOfPage((pssib)->pbf->ppage) == pgtypFDP || \
|
|
(pssib)->itag != 0 || \
|
|
( CbNDKey( (pssib)->line.pb ) == 0 && \
|
|
!FNDBackLink( *(pssib)->line.pb ) ) \
|
|
)
|
|
#else
|
|
#define AssertBTFOP( pssib )
|
|
#endif
|
|
|
|
#define PbPMGetChunk(pssib, ib) &(((BYTE *)((pssib)->pbf->ppage))[ib])
|
|
|
|
INT CbPMLinkSpace( SSIB *pssib );
|
|
TS TsPMTagstatus( PAGE *ppage, INT itag );
|
|
VOID PMInitPage( PAGE *ppage, PGNO pgno, PGTYP pgtyp, PGNO pgnoFDP );
|
|
INT ItagPMQueryNextItag( SSIB *pssib );
|
|
ERR ErrPMInsert( SSIB *pssib, LINE *rgline, INT cline );
|
|
VOID PMDelete( SSIB *ssib );
|
|
ERR ErrPMReplace( SSIB *pssib, LINE *rgline, INT cline );
|
|
ERR ErrPMGet( SSIB *pssib, INT itag );
|
|
VOID PMGetLink( SSIB *pssib, INT itag, LINK *plink );
|
|
VOID PMExpungeLink( SSIB *pssib );
|
|
VOID PMReplaceWithLink( SSIB *pssib, SRID srid );
|
|
VOID PMReplaceLink( SSIB *pssib, SRID srid );
|
|
INT CPMIFreeTag( PAGE *ppage );
|
|
BOOL FPMEmptyPage( SSIB *pssib );
|
|
BOOL FPMLastNode( SSIB *pssib );
|
|
BOOL FPMLastNodeWithLinks( SSIB *pssib );
|
|
|
|
VOID PMDirty( SSIB *pssib );
|
|
VOID PMReadAsync( PIB *ppib, PN pn );
|
|
ERR ErrPMAccessPage( FUCB *pfucb, PGNO pgno );
|
|
|
|
#ifdef DEBUG
|
|
VOID PageConsistent( PAGE *ppage );
|
|
#endif
|
|
|