/*
 * @doc
 *
 * @module LOGSTATE.H |
 * 		CLogState is the class that contains the current state of the log.
 *   	It is initialized from the last restart area written to the log.
 *   	It is updated when log records are written.  The methods of this
 *   	class determine the way a log record is laid down in the log.
 *   	It provides the log storage with a write or read map to be used to
 *   	write or read log records.
 *	 	
 *   	CWriteMap defines the mapping of a log record given its length and
 *   	starting position on the log to the log storage pages.  The map
 *   	is then used to get the memory buffers from the log storage and to
 *   	copy the user data into the log buffers.
 *	 	
 *   	CReadMap defines a mapping of a log record given its length and
 *   	starting position on the log to the log storage pages where that
 *   	record is written.
 *
 * @rev 0 | 16-Jan-95 | robertba | Created from Vincentf OFS code
 * @rev 1 | 29-Mar-95 | wilfr | Removed transaction stuff
 * @rev 2 | 03-Apr-95 | wilfr | seqno to gennum changes
 *
 */

#ifndef __LOGSTATE_H__
#define __LOGSTATE_H__

class CLogMgr; //forward class declaration
/*
 * @class  CWriteMap |
 *		Provides a mapping between user supplied write records and the log storage.
 *
 * hungarian crm
 */

class CWriteMap
{
//@access Public Members
public:
	//@cmember  Constructor
    CWriteMap(IN CLogStorage *pclgsto,IN ULONG ulEntryCount,IN LOGREC *algr,IN WRITELISTELEMENT *pwle);

    //@cmember  Default Constructor
    CWriteMap();

    //@cmember  Destructor
    ~CWriteMap();

    //@cmember  Init after default constructor
    VOID 	Init(IN CLogStorage *pclgsto,IN ULONG ulEntryCount,IN LOGREC *algr,IN WRITELISTELEMENT *pwle);

    //@cmember  Returns the computed client data plus header length.
    ULONG   GetRecordLength();

    //@cmember  sets the next range record in the write map.
    VOID    AddRange(IN RANGEENTRY &re);

    //@cmember  copy of the client data into the log storage buffers.
    VOID    CopyRecord(IN LOGRECHEADER &lrh);

    //@cmember	Sets the number of bytes that need to be allocated to align
    //          the next record on a ulALIGN boundary.
    VOID    SetAlign(IN ULONG ulAlign);

    //@cmember  Compute alignment bytes
    ULONG   GetAlign();


//@access Private Members
private:
    //
    //  Initial Parameters
    //
    //@cmember  Number of buffers in array 0 => linked list.
    ULONG                   _ulEntryCount;

    //@cmember 	Array of user buffers.
    LOGREC       *_algr;

    //@cmember  Linked list of buffers.
    WRITELISTELEMENT        *_pwle;

    //@cmember 	Number of date bytes in the message.
    ULONG                   _ulByteLength;

    //@cmember 	Log storage reference.
    CLogStorage             *_pclgstr;

    //@cmember 	Cursor variables into client buffers during copy
    ULONG                   _ulCurrentIndex;

    //@cmember 	The current write element
    WRITELISTELEMENT        *_pwleCurrentElement;

    //@cmember 	The current length
    ULONG                   _ulCurrentLength;

    //@cmember 	The current address
    CHAR                    *_pchCurrentAddress;

    //@cmember 	Alignment bytes needed.
    ULONG                   _ulAlign;

    //@cmember 	Number of bytes allocated for alignment by CLogState::AttemptWrite
    ULONG                   _ulAlignAlloc;

    //
    //  Buffer structures for the client log record.
    //
    //@cmember 	Number of ranges where buffers must be allocated.
    ULONG                   _ulRangeCount;

    //@cmember 	The ranges.
    RANGEENTRY              _arre[4];

	//
    //  Internal Support Routines.
    //
    //@cmember 	Returns the address and length of the next buffer to be copied.
    BOOL 	_GetNextClientBuffer();

    //@cmember 	Copy the client record or part of it into the buffer.
    VOID 		_CopyBuffer(IN ULONG ulRangeIndex);
};



/*
 * @class CReadMap |
 *      Provides a mapping between log storage records and user buffers log storage.
 *
 * hungarian crm
 *
 */

class CReadMap
{
friend class CILogRead;

//@access Public Members
public:
	//@cmember 	Constructor
    CReadMap(IN CLogStorage *pclgs,IN ULONG ulPageSize);

	//@cmember 	Destructor
    ~CReadMap();

	//@cmember 	Initialize the read map
  	VOID    InitReadMap(IN ULONG ulGeneration, IN ULONG ulOffset);

	//@cmember 	Returns start & size of the record to be read
    VOID    GetBounds(OUT ULONG *pulOffset,OUT ULONG *pulLength);
			
	//@cmember 	Get the number of buffers
    ULONG   GetBufCount();

	//@cmember 	Adds a range of buffer to the map.
    VOID    AddRange(IN RANGEENTRY &re);

	//@cmember 	Reads the next record and returns the buffer.
    BOOL ReadRecord(
			IN ULONG ulGeneration,
			IN ULONG ulBufCount,
			OUT ULONG *pulBufUsed,
			OUT LOGRECHEADER **pplrh,
			OUT LOGREC *algr, 
			IN BOOL fFree, 
			IN OUT ULONG *pulGenNum);

	//@cmember 	Release the buffers and get the header for the next record
 	BOOL ReleaseAndSet(
			IN ULONG ulGeneration,
			IN ULONG ulNextOffset);

    
//@access Private Members
private:
	//
    //  Private member functions
    //
	//@cmember 	For each page in the buffer the operation sets the address and
	//  		length of the write array element.
    VOID 	_SetRangeBuffers(LOGREC **pplgrNext,RANGEENTRY *preNext,ULONG *pulBufUsed,BOOL fFree);

	//@cmember 	obtain the log storage page that contains the log header of the
	//  		next record to be read.
    VOID    _SetUpResidue(IN ULONG ulGeneration);

	//@cmember 	Get the next page
    RECORDPAGE* _GetNextPage(RANGEENTRY *pre);

    //
    //  Next record parameters.
    //
	//@cmember 	Offset of next record to be read.
    ULONG			_ulOffset;

	//@cmember 	Length of next record to be read.
    ULONG           _ulLength;

    //
    //  Range structures.
    //
	//@cmember 	The count of ranges
	ULONG            _ulRangeCount;

	//@cmember 	The residue
    RANGEENTRY       _reResidue;

	//@cmember  Is this a residue
    BOOL          _fIsResidue;

	//@cmember 	The ranges
    RANGEENTRY       _arre[4];

	//@cmember 	The current log storage
    CLogStorage      *_pclgs;

	//@cmember 	The current page size
    ULONG            _ulPageSize;
};



/*
 * @class CLogState |
 *  	Maintains the current state of the file.  Is used to determine
 *  	how log records can be written and provides the information to
 *  	construct restart area buffers.
 *
 * hungarian clgs
 *
 */

class CLogState          // clgs
{
friend class CLogMgr;
friend class CILogStorage;
friend class CILogWrite;
friend DWORD _FlushThread(LPDWORD lpdwParam);

//@access Public Members
public:
	//@cmember	Constructor
 	CLogState(IN RESTARTLOG &rslCurrentRestartArea,IN ULONG ulSysPageSize);

 	//@cmember 	Returns a number that signifies the fraction of the log storage that is unused.
 	ULONG  	WhatFractionFree();

 	//@cmember 	Sees if a caller's log record can be fit into the
 	//         	log storage.  If possible, returns the physical
 	//         	layout of the record.
	ULONG   AttemptWrite(IN OUT LOGRECHEADER *plrh,IN CWriteMap &cwm,IN BOOL fFlush,IN BOOL fMarkAsOldest,IN ULONG ulBytesNeeded,IN ULONG ulChkptLen,IN OUT LRP *plrpWritten,OUT ULONG *pulStartGenNum);

	//@cmember 	Sets up a restart area buffer.
	VOID    GetRestartArea(OUT RESTARTLOG *prsl,OUT ULONG *pulAvailableSpace,IN BOOL fIsInit);

	//@cmember 	Determines if a given offset and sequence number are within the current range
	BOOL IsRecordInRange(IN ULONG ulGenNum,IN ULONG ulOffset,IN BOOL fChkBackEdge);

	//@cmember 	Sets up the physical record layout for a record whose bounds are specified.
	VOID    AttemptRead(IN CReadMap &crm, IN BOOL fRecovery);

	//@cmember 	Sets the oldest dirty seq no and offset     in the restart area.
	VOID    SetOldestDirtyRecord(ULONG ulGenNum, ULONG ulOffset,RECORDPAGE *prcpg);


	//@cmember 	Sets the position for the next record to be written and the position
	//         	of the last record completely written.  This is only called during recovery.
 	VOID    SetLeadingEdge(ULONG ulGenNum,ULONG ulOffset,ULONG ulNextOffset,ULONG *pulLastPageOffset,ULONG *pulLastRecOffset,ULONG *pulLastPageSpace);

	//@cmember 	Evaluates whether a checkpoint is necessary
	BOOL IsCheckpointUnnecessary();

	//@cmember 	The log storage was flushed up to the range specified
	BOOL AttemptFlush(IN ULONG ulGenNum,IN ULONG ulOffset,OUT ULONG *pulFlushOffset);

	//@cmember 	Evaluates whether a checkpoint is necessary.
	VOID 	EnsureCheckpointSpace(IN ULONG ulBytesNeeded,IN ULONG ulTabRecLen,IN BOOL fIsLogFull);



//@access Private Members
private:
	//@cmember 	Used to allocate a part of a log storage record page.
	BOOL	_MapOnePage(CReadMap &crm,RANGEENTRY *pre,ULONG *pulLength);

	//@cmember 	Using the state in the range parameter map as many pages
	//  		as possible for the record to be read.
	BOOL _MapPageRange(CReadMap &crm,RANGEENTRY *pre,ULONG *pulLength);

	//@cmember 	Used to allocate a part of a log storage record page.
	BOOL _AllocateFromCurrent(CWriteMap &cwm,ULONG *pulLength,RANGEENTRY *pre,BOOL fFlush);

	//@cmember 	Allocate as many pages as possible from the forward range.
	BOOL _AllocatePages(CWriteMap &cwm,ULONG *pulLength,RANGEENTRY *pre);

	//@cmember 	Handles the wrap around of a fixed size log during a write.
	VOID  	_DoWrapAround();

	//@cmember 	Adjusts the range variables if the allocation or map wrap around
	VOID  	_WrapRange(RANGEENTRY *pre);

	//@cmember 	Determines if the offset being freed is in the current range
	//     		being used by log records.  If it is the forward and backward
	VOID 	_FreeSpace(IN ULONG ulOffset);

	//@cmember 	Computes the state variables of the log.
	VOID  	_ComputeState(IN BOOL fInitCall);

	//@cmember 	Set the restart information for the oldest xaction
	VOID  	_ComputeNextRecord(ULONG *pulGenNum,ULONG *pulOffset);

	//
	//  Computed constants;
	//
	//@cmember 	Offset where first record page starts.
	ULONG   	_ulFirstRecordPage;

	//@cmember 	Number of record pages in the log.
	ULONG   	_ulPageCount;

	//
	//  Current storage State
	//		   	
	//@cmember 	Position where previous write occurred.
	ULONG   	_ulPreviousOffset;

	//@cmember 	There are two free areas; one in front of the buffer for log
	// 			records and the other behind it.
	BOOL 	_fFreeWrapped;

	//@cmember 	Size of the largest record in the log.
	ULONG   	_ulAvailableSpace;

	//@cmember 	Signals that records were not written between checkpoints.
	BOOL 	_fNoRecordWritten;

	//@cmember 	The restart area needed.
	RESTARTLOG 	_rsl;

	//
	//  Current Page State
	//
	//@cmember 	Offset of first byte of the current     page in log storage.
	ULONG   	_ulCurrentPageOffset;

	//@cmember 	Offset in current page for next record. Relative to the start
	//  		of the data area in the page.
	ULONG   	_ulCurrentRecOffset;

	//@cmember 	Space available in the current page.
	ULONG   	_ulCurrentPageSpace;

	//
	//  Forward Range State
	//
	//@cmember 	Offset of first byte of forward range in log storage.
	ULONG   	_ulForwardOffset;

	//@cmember 	Number of pages after current page to end of storage.
	ULONG   	_ulForwardPageCount;

	//
	//  Backward Range State
	//
	//@cmember 	Number of pages before first page of trailing edge.
	ULONG   	_ulBackwardPageCount;
	
	//
	//  State to support log full.
	//
	//@cmember 	Allowance for the fact that records may cause wastage up to
	//  		sizeof(LOGRECHEADER) on a page
	ULONG   	_ulRecOverflow;

	//@cmember 	Set to true when the log storage cannot
	// 			accomodate any more update records. Reset when the checkpoint after this
	// 			condition happens.
	BOOL 	_fLogFull;

	//@cmember 	State to remember last oldest dirty lrp passed in.
 	ULONG   	_ulLastOldestGenNum;

	//@cmember 	State to remember last oldest dirty lrp passed in.
	ULONG   	_ulLastOldestOffset;

	CLogMgr		*m_pCLogMgr;

};

#endif   //  __LOGSTATE_H__