/*!***************************************************************************

  module      : LVCSim_OIDAllocator.hpp

  -------------------------------------------------------------------------

  responsible : IvanS

  special area: liveCache Simulator
  description : allocator for memory and OIDs

  -------------------------------------------------------------------------





    ========== licence begin  GPL
    Copyright (c) 2000-2005 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end




*****************************************************************************/


#ifndef LVCSIM_OIDALLOCATOR_HPP
#define LVCSIM_OIDALLOCATOR_HPP

#include "LVCSimulator/LVCSim_CheckpointIO.hpp"

#define	LVCSIM_ALLOC_MAX_MAP	4096	// allocate max. 2GB/allocator


/*!*****************************************************************************

   class:        LVCSim_OIDObject
   description:  Base class for objects allocated by LVCSim_OIDAllocator

*******************************************************************************/

class LVCSim_OIDObject 
{
private:
	// WARNING: This must have the same structure as OmsTypeOid
	teo00_Uint4		pagenr;			// page number
	teo00_Uint2		pagepos;		// page position
	teo00_Uint2		generation;		// object generation

public:
	/*!
		function: getOid
		description: fill in OID structure
		arguments:
			lpoid	[out]	space where to write OID
	*/
	void getOid(OmsTypeOid *lpoid) const;

	/*!
		function: getRef
		description: fill in PageRef structure
		arguments:
			ref		[out]	space where to write PageRef
	*/
	void getRef(tgg91_PageRef *ref) const;


	inline unsigned int hash() const
	{
		return pagenr ^ (pagepos << 8);
	}

	inline void setOid(unsigned int container, unsigned int oid, unsigned int _generation)
	{
		pagenr = oid | ((container >> 16) << LVCSIM_OADDR_BITS);
		pagepos = container & 0xffff;
		generation = _generation;
	}

	inline unsigned int getContainer() const
	{
		return pagepos | ((pagenr >> LVCSIM_OADDR_BITS) << 16);
	}

  /// Check if the object is still valid.
  inline bool isValid() const
  {
    if ((pagepos | ((pagenr >> LVCSIM_OADDR_BITS) << 16)) == 0) {
      return false;
    }
    return pagenr != (teo00_Uint4) -1;
  }

  /// Get index in container from OID.
	inline unsigned int getOid() const
	{
		return pagenr & ((1 << LVCSIM_OADDR_BITS) - 1);
	}

	inline unsigned int getPageNr() const
	{
		return pagenr;
	}

	inline unsigned int getPagePos() const
	{
		return pagepos;
	}

	inline unsigned int getGeneration() const
	{
		return generation;
	}

  /// Set object generation.   // PTS 1125361
	inline void setGeneration(unsigned int generation)
	{
		this->generation = generation;
	}


  /// Increase generation.
  /*! Increase generation.
  ** \attention As only one byte is used for the generation (there is no more
  **    space left in the kernel) it must be assured, that the generation value
  **    stay within this corresponding interval. Furthermore 0 is no valid 
  **    generation so that the interval [1..0xff] remains as valid generations
  **    (PTS 1125361)
  */
	inline void nextGeneration()
	{
    if (generation == 0xff)    
      generation = 1;
    else
		  ++generation;
    pagepos = 0;
    pagenr = 0;
	}

  /// Deactivate current object (make it invalid).
	inline void deactivateObject()
	{
    pagepos = 0;
    pagenr = 0;
	}
};

/*! endclass: LVCSim_OIDObject */



/*!*****************************************************************************

   class:        LVCSim_OIDAllocator
   description:  This class allocates memory and physical references for objects

*******************************************************************************/

class LVCSim_OIDAllocator  
{
private:
	size_t	idx;				// allocator index (container ID)
	size_t	size;				// aligned object size
	size_t	objpage;			// objects per page

	int		freeptr;			// free pointer
	size_t	endptr;				// end pointer

	size_t	mapcnt;				// alocated page ranges count
	char*	maps[LVCSIM_ALLOC_MAX_MAP];		// page ranges pointers

	RTESync_Spinlock	lock;

public:
	LVCSim_OIDAllocator(LVCSim_CheckpointReader &i, size_t size);
	LVCSim_OIDAllocator(unsigned int idx, size_t sz);
	~LVCSim_OIDAllocator();

	/*!
		function: allocate

		description: allocate memory for an object and fill in physical address
			(the object must be derived from LVCSim_OIDObject - it is filled in).
			Generation's highest bit in allocated object is set to 1, application
			MUST set this bit to 0.

		arguments:
			ret	[out]	returns physical reference of the object

		returns: pointer to allocated memory
	*/
	void *allocate();

	/*!
		function: deallocate

		description: deallocate an object

		arguments:
			oid	[in]	physical reference of the object
	*/
	void deallocate(unsigned int oid);

	/*!
		function: map

		description: map physical reference to a memory address

		arguments:
			oid	[in]	physical reference of the object

		returns: pointer to object
	*/
	void *map(unsigned int oid) const;

	/*!
		function: getNextOid

		description: get next allocated OID in allocator

		arguments:
			oid [in]	last returned OID or 0 for first call

		returns: next OID or 0 if no more objects
	 */
	unsigned int getNextOid(unsigned int oid) const;

	void writeToStream(LVCSim_CheckpointWriter &o, size_t size) const;
};

/*! endclass: LVCSim_OIDAllocator */

#endif
